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
|
using AtLangCompiler.ILEmitter;
using System.Reflection;
using System.Reflection.Emit;
namespace AtLangCompiler.Methods;
internal class GetEnvToken : ILexerTokenConfig
{
public IReadOnlyDictionary<string, TokenType> TokenStrings => new Dictionary<string, TokenType>
{
{ "@getEnv", TokenType.GETENV }
};
}
internal class EnvVarAssignment : ASTNode
{
public string VarName { get; }
public string? EnvVarName { get; }
public string? StrValue { get; }
public EnvVarAssignment(string varName, string? envVarName, string? strValue)
{
VarName = varName;
EnvVarName = envVarName;
StrValue = strValue;
}
}
[ParserFor(TokenType.GETENV, inputTokens: 1)]
internal class EnvironmentStatementParser : IStatementParser
{
public ASTNode ParseStatement(Parser parser)
{
parser.Eat(TokenType.GETENV);
parser.Eat(TokenType.LPAREN);
parser.Eat(TokenType.AT);
string envName = parser.current.Text;
parser.Eat(TokenType.IDENT);
parser.Eat(TokenType.RPAREN);
return new EnvVarAssignment(parser.varName, envName, null);
}
}
[EmitterFor(typeof(EnvVarAssignment))]
internal class EnvVar : IMethodEmitter<EnvVarAssignment>
{
private readonly ILGenerator il;
private readonly LocalBuilder dictLocal;
public EnvVar(ILGenerator il, LocalBuilder dictLocal)
{
this.il = il ?? throw new ArgumentNullException(nameof(il));
this.dictLocal = dictLocal ?? throw new ArgumentNullException(nameof(dictLocal));
}
public void EmitIL(EnvVarAssignment node)
{
// dict[varName] = ...
il.Emit(OpCodes.Ldloc, dictLocal);
il.Emit(OpCodes.Ldstr, node.VarName);
if (node.EnvVarName != null)
{
// Environment.GetEnvironmentVariable(...) ?? ""
System.Reflection.MethodInfo getEnvMI = typeof(Environment).GetMethod(nameof(Environment.GetEnvironmentVariable), [typeof(string)])!;
il.Emit(OpCodes.Ldstr, node.EnvVarName);
il.Emit(OpCodes.Call, getEnvMI);
// if null => ""
il.Emit(OpCodes.Dup);
Label labelNotNull = il.DefineLabel();
Label labelEnd = il.DefineLabel();
il.Emit(OpCodes.Brtrue_S, labelNotNull);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldstr, string.Empty);
il.MarkLabel(labelNotNull);
il.MarkLabel(labelEnd);
}
else
{
il.Emit(OpCodes.Ldstr, node.StrValue ?? string.Empty);
}
MethodInfo dictSetItem = typeof(Dictionary<string, object>)
.GetProperty("Item")!
.GetSetMethod()!;
il.Emit(OpCodes.Isinst, typeof(string));
il.Emit(OpCodes.Callvirt, dictSetItem);
}
}
|