1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
using AtLangCompiler.ILEmitter;
using System.Reflection.Emit;
namespace AtLangCompiler.Methods;
internal class IfToken : ILexerTokenConfig
{
public IReadOnlyDictionary<string, TokenType> TokenStrings => new Dictionary<string, TokenType>
{
{ "@if", TokenType.IF },
{ "@else", TokenType.ELSE }
};
}
internal class IfStatement : ASTNode
{
public ASTNode LeftExpr { get; }
public ASTNode RightExpr { get; }
public List<ASTNode> IfBody { get; }
public List<ASTNode> ElseBody { get; }
public IfStatement(ASTNode left, ASTNode right, List<ASTNode> ifBody, List<ASTNode> elseBody)
{
LeftExpr = left; RightExpr = right;
IfBody = ifBody; ElseBody = elseBody;
}
}
[ParserFor(TokenType.IF, inputTokens: 2, inputSeparator: "==", hasBody: true)]
[ParserFor(TokenType.ELSE, hasBody: true, prerequisiteToken: TokenType.IF)]
internal class ConditionalStatementParser : IStatementParser
{
public ASTNode ParseStatement(Parser parser)
{
parser.Eat(TokenType.IF);
parser.Eat(TokenType.LPAREN);
ASTNode left = parser.ParseExpression();
if (parser.current.Type == TokenType.EQEQ)
{
parser.Eat(TokenType.EQEQ);
}
else
{
throw new Exception("Only == is supported.");
}
ASTNode right = parser.ParseExpression();
parser.Eat(TokenType.RPAREN);
parser.Eat(TokenType.LBRACE);
List<ASTNode> ifBody = new List<ASTNode>();
while (parser.current.Type != TokenType.RBRACE && parser.current.Type != TokenType.EOF)
{
ASTNode? s = parser.ParseStatement();
if (s != null) ifBody.Add(s);
}
parser.Eat(TokenType.RBRACE);
List<ASTNode> elseBody = new List<ASTNode>();
if (parser.current.Type == TokenType.ELSE)
{
parser.Eat(TokenType.ELSE);
parser.Eat(TokenType.LBRACE);
while (parser.current.Type != TokenType.RBRACE && parser.current.Type != TokenType.EOF)
{
ASTNode? s = parser.ParseStatement();
if (s != null) elseBody.Add(s);
}
parser.Eat(TokenType.RBRACE);
}
return new IfStatement(left, right, ifBody, elseBody);
}
}
[EmitterFor(typeof(IfStatement))]
internal class Conditional : IMethodEmitter<IfStatement>
{
private readonly ILGenerator il;
private readonly ILMethodEmitterManager emitter;
public Conditional(ILGenerator il, ILMethodEmitterManager emitter)
{
this.il = il ?? throw new ArgumentNullException(nameof(il));
this.emitter = emitter ?? throw new ArgumentNullException(nameof(emitter));
}
public void EmitIL(IfStatement node)
{
// if (EvalExpr(Left) == EvalExpr(Right)) { IfBody } else { ElseBody }
emitter.EmitStatement(node.LeftExpr);
emitter.EmitStatement(node.RightExpr);
// string.Equals(string, StringComparison.Ordinal)
System.Reflection.MethodInfo strEquals = typeof(string).GetMethod("Equals", [typeof(string), typeof(StringComparison)])!;
Label labelElse = il.DefineLabel();
Label labelEnd = il.DefineLabel();
il.Emit(OpCodes.Ldc_I4, (int)StringComparison.Ordinal);
il.Emit(OpCodes.Call, strEquals);
il.Emit(OpCodes.Brfalse, labelElse);
// If-body
foreach (ASTNode st in node.IfBody)
{
emitter.EmitStatement(st);
}
il.Emit(OpCodes.Br, labelEnd);
// Else-body
il.MarkLabel(labelElse);
foreach (ASTNode st in node.ElseBody)
{
emitter.EmitStatement(st);
}
il.MarkLabel(labelEnd);
}
}
|