summaryrefslogtreecommitdiff
path: root/compiler/Methods/Print.cs
blob: 524ef8d87fcce323c317916af2288aa61eb1eb1c (plain)
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
using AtLangCompiler.ILEmitter;
using System.Reflection.Emit;

namespace AtLangCompiler.Methods;

internal class PrintToken : ILexerTokenConfig
{
    public IReadOnlyDictionary<string, TokenType> TokenStrings => new Dictionary<string, TokenType>
    {
        { "@print", TokenType.PRINT }
    };
}

internal class PrintStatement : ASTNode
{
    public ASTNode Expr { get; }
    public PrintStatement(ASTNode expr) { Expr = expr; }
}

[ParserFor(TokenType.PRINT, inputTokens: 1)]
internal class PrintStatementParser : IStatementParser
{
    public ASTNode ParseStatement(Parser parser)
    {
        parser.Eat(TokenType.PRINT);
        parser.Eat(TokenType.LPAREN);
        ASTNode expr = parser.ParseExpression();
        parser.Eat(TokenType.RPAREN);
        return new PrintStatement(expr);
    }
}

[EmitterFor(typeof(PrintStatement))]
internal class Print : IMethodEmitter<PrintStatement>
{
    private readonly ILGenerator il;
    private readonly LocalBuilder dictLocal;
    private readonly ILMethodEmitterManager emitter;

    public Print(ILGenerator il, LocalBuilder dictLocal, ILMethodEmitterManager emitter)
    {
        this.il = il ?? throw new ArgumentNullException(nameof(il));
        this.dictLocal = dictLocal ?? throw new ArgumentNullException(nameof(dictLocal));
        this.emitter = emitter ?? throw new ArgumentNullException(nameof(emitter));
    }

    public void EmitIL(PrintStatement node)
    {
        // Console.Out.WriteLine( Evaluate(ps.Expr) )
        il.Emit(OpCodes.Call, typeof(Console).GetMethod("get_Out")!);
        emitter.EmitStatement(node.Expr);
        il.Emit(OpCodes.Callvirt,
            typeof(TextWriter).GetMethod(nameof(TextWriter.WriteLine), [typeof(string)])!);
    }
}