Skip to content

Commit 0f50173

Browse files
WIP: Super messing copy/paste from async/await state machine
1 parent 131ec1b commit 0f50173

File tree

10 files changed

+1411
-2
lines changed

10 files changed

+1411
-2
lines changed

src/Hyperbee.Expressions/CompilerServices/StateMachineBuilder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ FieldInfo[] fields
271271
exitLabel,
272272
stateField,
273273
builderField,
274-
finalResultField
274+
finalResultField,
275+
null //TODO: current for yield?
275276
);
276277

277278
// Create final lambda with try-catch block

src/Hyperbee.Expressions/CompilerServices/StateMachineContext.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ internal record StateMachineInfo(
1616
LabelTarget ExitLabel,
1717
MemberExpression StateField,
1818
MemberExpression BuilderField,
19-
MemberExpression FinalResultField
19+
MemberExpression FinalResultField,
20+
MemberExpression CurrentField
2021
);
2122

2223
internal record LoweringInfo
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System.Linq.Expressions;
2+
using static System.Linq.Expressions.Expression;
3+
4+
namespace Hyperbee.Expressions.CompilerServices.Transitions;
5+
6+
internal class YieldTransition : Transition
7+
{
8+
public StateNode TargetNode { get; set; }
9+
public LabelTarget ResumeLabel { get; internal set; }
10+
public Expression? Value { get; internal set; }
11+
public int StateId { get; internal set; }
12+
13+
internal override StateNode FallThroughNode => TargetNode;
14+
15+
public override void AddExpressions( List<Expression> expressions, StateMachineContext context )
16+
{
17+
//base.AddExpressions( expressions, context );
18+
if ( Value == null )
19+
{
20+
expressions.Add(
21+
Block(
22+
Return( context.StateMachineInfo.ExitLabel, Constant( false ) )
23+
)
24+
);
25+
return;
26+
}
27+
expressions.Add(
28+
Block(
29+
Assign( context.StateMachineInfo.StateField, Constant( TargetNode.StateId ) ),
30+
Assign( context.StateMachineInfo.CurrentField, Value ),
31+
Return( context.StateMachineInfo.ExitLabel, Constant( true ) )
32+
)
33+
);
34+
}
35+
36+
internal override void Optimize( HashSet<LabelTarget> references )
37+
{
38+
TargetNode = OptimizeGotos( TargetNode );
39+
references.Add( TargetNode.NodeLabel );
40+
}
41+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using System.Collections.ObjectModel;
2+
using System.Linq.Expressions;
3+
using Hyperbee.Collections;
4+
5+
namespace Hyperbee.Expressions.CompilerServices.YieldSupport;
6+
7+
public class YieldBlockExpression : Expression
8+
{
9+
private Type _enumerableType;
10+
public ReadOnlyCollection<Expression> Expressions { get; }
11+
public ReadOnlyCollection<ParameterExpression> Variables { get; }
12+
13+
internal LinkedDictionary<ParameterExpression, ParameterExpression> ScopedVariables { get; set; }
14+
15+
public YieldBlockExpression(
16+
ReadOnlyCollection<ParameterExpression> variables,
17+
ReadOnlyCollection<Expression> expressions )
18+
{
19+
if ( expressions == null || expressions.Count == 0 )
20+
throw new ArgumentException( "YieldBlockExpression must contain at least one expression." );
21+
22+
Variables = variables;
23+
Expressions = expressions;
24+
}
25+
26+
public override ExpressionType NodeType => ExpressionType.Extension;
27+
public Type EnumerableType => _enumerableType ??= GetYieldType();
28+
public override Type Type => typeof( IEnumerable<> ).MakeGenericType( EnumerableType );
29+
public override bool CanReduce => true;
30+
31+
public override Expression Reduce()
32+
{
33+
return YieldStateMachineBuilder.Create( EnumerableType, LoweringTransformer );
34+
}
35+
36+
private LoweringInfo LoweringTransformer()
37+
{
38+
try
39+
{
40+
var visitor = new YieldLoweringVisitor();
41+
42+
return visitor.Transform(
43+
EnumerableType,
44+
[.. Variables],
45+
[.. Expressions],
46+
ScopedVariables ?? []
47+
);
48+
}
49+
catch ( LoweringException ex )
50+
{
51+
throw new InvalidOperationException( $"Unable to lower {nameof( AsyncBlockExpression )}.", ex );
52+
}
53+
}
54+
55+
private Type GetYieldType()
56+
{
57+
var stack = new Stack<Expression>(Expressions);
58+
while (stack.Count > 0)
59+
{
60+
var current = stack.Pop();
61+
switch (current)
62+
{
63+
case YieldExpression { IsReturn: true } yieldExpression:
64+
return yieldExpression.Type;
65+
66+
case BlockExpression blockExpression:
67+
foreach (var expr in blockExpression.Expressions)
68+
{
69+
stack.Push(expr);
70+
}
71+
break;
72+
case ConditionalExpression conditionalExpression:
73+
stack.Push(conditionalExpression.IfTrue);
74+
stack.Push(conditionalExpression.IfFalse);
75+
stack.Push(conditionalExpression.Test);
76+
break;
77+
case LoopExpression loopExpression:
78+
stack.Push(loopExpression.Body);
79+
break;
80+
case SwitchExpression switchExpression:
81+
foreach (var switchCase in switchExpression.Cases)
82+
{
83+
stack.Push( switchCase.Body );
84+
}
85+
stack.Push(switchExpression.SwitchValue);
86+
break;
87+
case TryExpression tryExpression:
88+
stack.Push(tryExpression.Body);
89+
if (tryExpression.Fault != null) stack.Push(tryExpression.Fault);
90+
if (tryExpression.Finally != null) stack.Push(tryExpression.Finally);
91+
foreach (var handler in tryExpression.Handlers)
92+
{
93+
stack.Push(handler.Body);
94+
}
95+
break;
96+
}
97+
}
98+
return typeof(void);
99+
}
100+
}
101+
102+
public static partial class ExpressionExtensions
103+
{
104+
public static YieldBlockExpression BlockYield( params Expression[] expressions )
105+
{
106+
return new YieldBlockExpression( ReadOnlyCollection<ParameterExpression>.Empty, new ReadOnlyCollection<Expression>( expressions ) );
107+
}
108+
109+
public static YieldBlockExpression BlockYield( ParameterExpression[] variables, params Expression[] expressions )
110+
{
111+
return new YieldBlockExpression( new ReadOnlyCollection<ParameterExpression>( variables ), new ReadOnlyCollection<Expression>( expressions ) );
112+
}
113+
114+
public static YieldBlockExpression BlockYield( ReadOnlyCollection<Expression> expressions )
115+
{
116+
return new YieldBlockExpression( ReadOnlyCollection<ParameterExpression>.Empty, expressions );
117+
}
118+
119+
public static YieldBlockExpression BlockYield( ReadOnlyCollection<ParameterExpression> variables, ReadOnlyCollection<Expression> expressions )
120+
{
121+
return new YieldBlockExpression( variables, expressions );
122+
}
123+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Collections.ObjectModel;
2+
using System.Linq.Expressions;
3+
using System.Transactions;
4+
5+
namespace Hyperbee.Expressions.CompilerServices.YieldSupport;
6+
7+
public class YieldExpression : Expression
8+
{
9+
public Expression? Value { get; }
10+
public bool IsReturn { get; }
11+
12+
public YieldExpression( Expression value ) : this( value, true )
13+
{
14+
}
15+
16+
public YieldExpression() : this( null, false )
17+
{
18+
}
19+
20+
private YieldExpression( Expression? value, bool isReturn )
21+
{
22+
if ( isReturn && value == null )
23+
throw new ArgumentNullException( nameof( value ), "Yield return must have a value." );
24+
25+
Value = value;
26+
IsReturn = isReturn;
27+
}
28+
29+
public override ExpressionType NodeType => ExpressionType.Extension;
30+
public override Type Type => IsReturn ? Value!.Type : typeof( void );
31+
public override bool CanReduce => true;
32+
33+
public override Expression Reduce()
34+
{
35+
//if ( IsReturn )
36+
//{
37+
// return Block(
38+
// Assign( State, Constant( -1 ) ),
39+
// Assign( Current, Value ),
40+
// Return( Constant( true ) )
41+
// );
42+
//}
43+
44+
45+
// TODO: Hack
46+
return Value ?? Default( Type );
47+
}
48+
49+
protected override Expression VisitChildren( ExpressionVisitor visitor )
50+
{
51+
var newTarget = visitor.Visit( Value );
52+
53+
return newTarget == Value
54+
? this
55+
: new YieldExpression( newTarget, IsReturn );
56+
}
57+
}
58+
59+
public static partial class ExpressionExtensions
60+
{
61+
public static YieldExpression YieldReturn( Expression value )
62+
{
63+
return new YieldExpression( value );
64+
}
65+
66+
public static YieldExpression YieldBreak()
67+
{
68+
return new YieldExpression();
69+
}
70+
71+
}

0 commit comments

Comments
 (0)