Skip to content

Commit 12baebd

Browse files
Release v1.2.2 (#43)
* [FEATURE]: Add Support for Enumerable (#42) * Add support for enumerable block with yield return/break * Update nugets, documents and fix tests --------- Co-authored-by: Brenton Farmer <brent.farmer@wagglebee.net> Co-authored-by: MattEdwardsWaggleBee <MattEdwardsWaggleBee@users.noreply.github.com>
1 parent a121e82 commit 12baebd

20 files changed

+430
-68
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<MajorVersion>1</MajorVersion>
55
<MinorVersion>2</MinorVersion>
6-
<PatchVersion>1</PatchVersion>
6+
<PatchVersion>2</PatchVersion>
77
<RevisionVersion>0</RevisionVersion>
88
<VersionPrefix>$(MajorVersion).$(MinorVersion).$(PatchVersion)</VersionPrefix>
99
<FileVersion>$(MajorVersion).$(MinorVersion).$(PatchVersion).$(RevisionVersion)</FileVersion>

docs/docs.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<None Include="$(MSBuildThisFileDirectory)language\using-directive.md" />
3939
<None Include="$(MSBuildThisFileDirectory)language\using-statement.md" />
4040
<None Include="$(MSBuildThisFileDirectory)language\variables.md" />
41+
<None Include="$(MSBuildThisFileDirectory)language\yield.md" />
4142
<None Include="$(MSBuildThisFileDirectory)language\while.md" />
4243
<None Include="$(MSBuildThisFileDirectory)_config.yml" />
4344
</ItemGroup>

docs/language/yield.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
layout: default
3+
title: Yield
4+
parent: Language
5+
nav_order: 22
6+
---
7+
8+
# Yield
9+
10+
The `yield` within an `enumerable` block allows you to return a value from a function and then continue execution. The `break` keyword can be used to exit the block early.
11+
12+
This construct requires the `Hyperbee.XS.Extensions` package.
13+
14+
## Usage
15+
16+
```
17+
enumerable {
18+
yield 1;
19+
yield 2;
20+
break;
21+
yield 3;
22+
}
23+
```

src/Hyperbee.XS.Cli/Hyperbee.Xs.Cli.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
@@ -29,7 +29,7 @@
2929
</PropertyGroup>
3030

3131
<ItemGroup>
32-
<PackageReference Include="FastExpressionCompiler" Version="5.0.2" />
32+
<PackageReference Include="FastExpressionCompiler" Version="5.1.0" />
3333
<PackageReference Include="Spectre.Console" Version="0.49.1" />
3434
<PackageReference Include="Spectre.Console.Cli" Version="0.49.1" />
3535
<PackageReference Include="System.Reflection.Metadata" Version="9.0.3" />
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System.Linq.Expressions;
2+
using Hyperbee.Collections;
3+
using Hyperbee.Expressions;
4+
using Hyperbee.XS;
5+
using Hyperbee.XS.Core;
6+
using Hyperbee.XS.Core.Parsers;
7+
using Hyperbee.XS.Core.Writer;
8+
using Parlot.Fluent;
9+
using static Parlot.Fluent.Parsers;
10+
11+
namespace Hyperbee.Xs.Extensions;
12+
13+
public class EnumerableParseExtension : IParseExtension, IExpressionWriter, IXsWriter
14+
{
15+
public ExtensionType Type => ExtensionType.Expression;
16+
public string Key => "enumerable";
17+
18+
public Parser<Expression> CreateParser( ExtensionBinder binder )
19+
{
20+
var (_, statement) = binder;
21+
22+
return XsParsers.Bounded(
23+
static ctx =>
24+
{
25+
ctx.EnterScope( FrameType.Block );
26+
},
27+
Between(
28+
// This is basically a block, but we need the parts
29+
Terms.Char( '{' ),
30+
ZeroOrMany( statement ),
31+
Terms.Char( '}' )
32+
).Named( "enumerable block" )
33+
.Then<Expression>( static ( ctx, parts ) =>
34+
ExpressionExtensions.BlockEnumerable(
35+
[.. ctx.Scope().Variables.EnumerateValues( LinkedNode.Current )],
36+
[.. parts]
37+
)
38+
),
39+
static ctx =>
40+
{
41+
ctx.ExitScope();
42+
}
43+
).Named( "enumerable" );
44+
}
45+
46+
public bool CanWrite( Expression node )
47+
{
48+
return node is EnumerableBlockExpression;
49+
}
50+
51+
public void WriteExpression( Expression node, ExpressionWriterContext context )
52+
{
53+
if ( node is not EnumerableBlockExpression enumerableBlockExpression )
54+
return;
55+
56+
using var writer = context.EnterExpression( "Hyperbee.Expressions.ExpressionExtensions.BlockEnumerable", true, false );
57+
58+
var variableCount = enumerableBlockExpression.Variables.Count;
59+
60+
if ( variableCount > 0 )
61+
{
62+
writer.WriteParamExpressions( enumerableBlockExpression.Variables, true );
63+
}
64+
65+
var expressionCount = enumerableBlockExpression.Expressions.Count;
66+
67+
if ( expressionCount != 0 )
68+
{
69+
if ( variableCount > 0 )
70+
{
71+
writer.Write( ",\n" );
72+
}
73+
74+
for ( var i = 0; i < expressionCount; i++ )
75+
{
76+
writer.WriteExpression( enumerableBlockExpression.Expressions[i] );
77+
if ( i < expressionCount - 1 )
78+
{
79+
writer.Write( "," );
80+
}
81+
writer.Write( "\n" );
82+
}
83+
}
84+
}
85+
86+
public void WriteExpression( Expression node, XsWriterContext context )
87+
{
88+
if ( node is not EnumerableBlockExpression enumerableBlockExpression )
89+
return;
90+
91+
using var writer = context.GetWriter();
92+
93+
var expressionCount = enumerableBlockExpression.Expressions.Count;
94+
95+
writer.Write( "enumerable {\n" );
96+
writer.Indent();
97+
98+
for ( var i = 0; i < expressionCount; i++ )
99+
{
100+
writer.WriteExpression( enumerableBlockExpression.Expressions[i] );
101+
writer.WriteTerminated();
102+
}
103+
104+
writer.Outdent();
105+
writer.Write( "}\n" );
106+
context.SkipTerminated = true;
107+
}
108+
}

src/Hyperbee.XS.Extensions/Hyperbee.Xs.Extensions.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<None Include="..\..\NOTICES" Pack="true" Visible="false" PackagePath="/" />
4343
<None Include="README.md" Pack="true" PackagePath="\" />
4444
<PackageReference Include="Hyperbee.Collections" Version="2.4.0" />
45-
<PackageReference Include="Hyperbee.Expressions" Version="1.1.3" />
45+
<PackageReference Include="Hyperbee.Expressions" Version="1.1.4" />
4646
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
4747
<PackageReference Include="Parlot" Version="1.3.5" />
4848
<ProjectReference Include="..\Hyperbee.XS\Hyperbee.XS.csproj" />

src/Hyperbee.XS.Extensions/UsingParseExtension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public Parser<Expression> CreateParser( ExtensionBinder binder )
4040
return (variable, disposable);
4141
} )
4242
.And( statement )
43-
.Then<Expression>( static ( ctx, parts ) =>
43+
.Then<Expression>( static ( _, parts ) =>
4444
{
4545
var ((disposeVariable, disposable), body) = parts;
4646

src/Hyperbee.XS.Extensions/XsExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ public static IReadOnlyCollection<IParseExtension> Extensions()
1515
new AsyncParseExtension(),
1616
new AwaitParseExtension(),
1717
new DebugParseExtension(),
18-
new PackageParseExtension()
18+
new PackageParseExtension(),
19+
new EnumerableParseExtension(),
20+
new YieldBreakParseExtension(),
21+
new YieldReturnParseExtension()
1922
];
2023
}
2124
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.Linq.Expressions;
2+
using Hyperbee.Expressions;
3+
using Hyperbee.XS.Core;
4+
using Hyperbee.XS.Core.Writer;
5+
using Parlot.Fluent;
6+
using static Parlot.Fluent.Parsers;
7+
namespace Hyperbee.Xs.Extensions;
8+
9+
public class YieldBreakParseExtension : IParseExtension, IExpressionWriter, IXsWriter
10+
{
11+
public ExtensionType Type => ExtensionType.Terminated;
12+
public string Key => "break";
13+
14+
public Parser<Expression> CreateParser( ExtensionBinder binder )
15+
{
16+
return Terms.Char( ';' )
17+
.Then<Expression>( static _ => ExpressionExtensions.YieldBreak() )
18+
.Named( "break" );
19+
}
20+
21+
public bool CanWrite( Expression node )
22+
{
23+
return node is YieldExpression { IsReturn: false };
24+
}
25+
26+
public void WriteExpression( Expression node, ExpressionWriterContext context )
27+
{
28+
if ( node is not YieldExpression { IsReturn: false } )
29+
return;
30+
31+
using var writer = context.EnterExpression( "Hyperbee.Expressions.ExpressionExtensions.YieldBreak", false, false );
32+
}
33+
34+
public void WriteExpression( Expression node, XsWriterContext context )
35+
{
36+
if ( node is not YieldExpression )
37+
return;
38+
39+
using var writer = context.GetWriter();
40+
writer.Write( "break" );
41+
}
42+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System.Linq.Expressions;
2+
using Hyperbee.Expressions;
3+
using Hyperbee.XS.Core;
4+
using Hyperbee.XS.Core.Writer;
5+
using Parlot.Fluent;
6+
7+
namespace Hyperbee.Xs.Extensions;
8+
9+
public class YieldReturnParseExtension : IParseExtension, IExpressionWriter, IXsWriter
10+
{
11+
public ExtensionType Type => ExtensionType.Expression;
12+
public string Key => "yield";
13+
14+
public Parser<Expression> CreateParser( ExtensionBinder binder )
15+
{
16+
var (expression, _) = binder;
17+
18+
return expression
19+
.Then<Expression>( static parts => ExpressionExtensions.YieldReturn( parts ) )
20+
.Named( "yield" );
21+
}
22+
23+
public bool CanWrite( Expression node )
24+
{
25+
return node is YieldExpression { IsReturn: true };
26+
}
27+
28+
public void WriteExpression( Expression node, ExpressionWriterContext context )
29+
{
30+
if ( node is not YieldExpression { IsReturn: true } yieldExpression )
31+
return;
32+
33+
using var writer = context.EnterExpression( "Hyperbee.Expressions.ExpressionExtensions.YieldReturn", true, false );
34+
35+
writer.WriteExpression( yieldExpression.Value );
36+
}
37+
38+
public void WriteExpression( Expression node, XsWriterContext context )
39+
{
40+
if ( node is not YieldExpression yieldExpression )
41+
return;
42+
43+
using var writer = context.GetWriter();
44+
45+
writer.Write( "yield " );
46+
writer.WriteExpression( yieldExpression.Value );
47+
}
48+
}

0 commit comments

Comments
 (0)