using System.Diagnostics.CodeAnalysis; namespace Compiler; public sealed class Parser(List tokens) { public static List Parse(List tokens) { return new Parser(tokens).Parse(); } private int index; private List Parse() { var nodes = new List(); while (Peek() != null) nodes.Add(ParseDefinition()); return nodes; } private NodeDefinition ParseDefinition() { var startIndex = index; if (TryExpectKeyword(Keyword.Func)) { var name = ExpectIdent(); var parameters = new List(); ExpectSymbol(Symbol.OpenParen); while (!TryExpectSymbol(Symbol.CloseParen)) { var paramStartIndex = index; var parameterName = ExpectIdent(); ExpectSymbol(Symbol.Colon); var parameterType = ParseType(); parameters.Add(new NodeDefinitionFunc.Param(TokensFrom(paramStartIndex), parameterName, parameterType)); } ExpectSymbol(Symbol.Colon); var returnType = ParseType(); var body = ParseStatement(); return new NodeDefinitionFunc(TokensFrom(startIndex), name, parameters, body, returnType); } throw new Exception("Not a valid definition"); } private NodeStatement ParseStatement() { var startIndex = index; if (TryExpectSymbol(Symbol.OpenCurly)) { var statements = new List(); while (!TryExpectSymbol(Symbol.CloseCurly)) statements.Add(ParseStatement()); return new NodeStatementBlock(TokensFrom(startIndex), statements); } var expression = ParseExpression(); var parameters = new List(); ExpectSymbol(Symbol.OpenParen); while (!TryExpectSymbol(Symbol.CloseParen)) parameters.Add(ParseExpression()); return new NodeStatementFuncCall(TokensFrom(startIndex), expression, parameters); } private NodeExpression ParseExpression() { var startIndex = index; if (TryExpectIntLiteral(out var intLiteral)) { return new NodeExpressionIntLiteral(TokensFrom(startIndex), intLiteral); } if (TryExpectStringLiteral(out var stringLiteral)) { return new NodeExpressionStringLiteral(TokensFrom(startIndex), stringLiteral); } if (TryExpectBoolLiteral(out var boolLiteral)) { return new NodeExpressionBoolLiteral(TokensFrom(startIndex), boolLiteral); } if (TryExpectIdent(out var ident)) { return new NodeExpressionIdent(TokensFrom(startIndex), ident); } throw new Exception("Not a valid expression"); } private NodeType ParseType() { var startIndex = index; if (TryExpectSymbol(Symbol.Caret)) { var to = ParseType(); return new NodeTypePointer(TokensFrom(startIndex), to); } if (TryExpectIdent(out var ident)) { switch (ident.Ident) { case "void": return new NubTypeVoid(TokensFrom(startIndex)); case "string": return new NodeTypeString(TokensFrom(startIndex)); case "i8": return new NodeTypeSInt(TokensFrom(startIndex), 8); case "i16": return new NodeTypeSInt(TokensFrom(startIndex), 16); case "i32": return new NodeTypeSInt(TokensFrom(startIndex), 32); case "i64": return new NodeTypeSInt(TokensFrom(startIndex), 64); case "u8": return new NodeTypeUInt(TokensFrom(startIndex), 8); case "u16": return new NodeTypeUInt(TokensFrom(startIndex), 16); case "u32": return new NodeTypeUInt(TokensFrom(startIndex), 32); case "u64": return new NodeTypeUInt(TokensFrom(startIndex), 64); case "f32": return new NodeTypeFloat(TokensFrom(startIndex), 32); case "f64": return new NodeTypeFloat(TokensFrom(startIndex), 64); default: return new NodeTypeCustom(TokensFrom(startIndex), ident); } } throw new Exception("Not a valid type"); } private List TokensFrom(int startIndex) { return tokens.GetRange(startIndex, index - startIndex); } private bool TryExpectKeyword(Keyword keyword) { if (Peek() is TokenKeyword token && token.Keyword == keyword) { Consume(); return true; } return false; } private void ExpectSymbol(Symbol symbol) { if (Peek() is TokenSymbol token && token.Symbol == symbol) { Consume(); return; } throw new Exception($"Expected symbol '{symbol}'"); } private bool TryExpectSymbol(Symbol symbol) { if (Peek() is TokenSymbol token && token.Symbol == symbol) { Consume(); return true; } return false; } private TokenIdent ExpectIdent() { if (Peek() is TokenIdent token) { Consume(); return token; } throw new Exception("Expected ident"); } private bool TryExpectIdent([NotNullWhen(true)] out TokenIdent? ident) { if (Peek() is TokenIdent token) { Consume(); ident = token; return true; } ident = null; return false; } private bool TryExpectIntLiteral([NotNullWhen(true)] out TokenIntLiteral? intLiteral) { if (Peek() is TokenIntLiteral token) { Consume(); intLiteral = token; return true; } intLiteral = null; return false; } private bool TryExpectStringLiteral([NotNullWhen(true)] out TokenStringLiteral? stringLiteral) { if (Peek() is TokenStringLiteral token) { Consume(); stringLiteral = token; return true; } stringLiteral = null; return false; } private bool TryExpectBoolLiteral([NotNullWhen(true)] out TokenBoolLiteral? boolLiteral) { if (Peek() is TokenBoolLiteral token) { Consume(); boolLiteral = token; return true; } boolLiteral = null; return false; } private Token Consume() { if (index >= tokens.Count) throw new Exception("End of tokens"); return tokens[index++]; } private Token? Peek(int offset = 0) { if (index + offset >= tokens.Count) return null; return tokens[index + offset]; } } public abstract class Node(List tokens) { public List Tokens = tokens; } public abstract class NodeDefinition(List tokens) : Node(tokens); public sealed class NodeDefinitionFunc(List tokens, TokenIdent name, List parameters, NodeStatement body, NodeType returnType) : NodeDefinition(tokens) { public readonly TokenIdent Name = name; public readonly List Parameters = parameters; public readonly NodeStatement Body = body; public readonly NodeType ReturnType = returnType; public sealed class Param(List tokens, TokenIdent name, NodeType type) : Node(tokens) { public readonly TokenIdent Name = name; public readonly NodeType Type = type; } } public abstract class NodeStatement(List tokens) : Node(tokens); public sealed class NodeStatementBlock(List tokens, List statements) : NodeStatement(tokens) { public readonly List Statements = statements; } public sealed class NodeStatementFuncCall(List tokens, NodeExpression func, List parameters) : NodeStatement(tokens) { public readonly NodeExpression Func = func; public readonly List Parameters = parameters; } public abstract class NodeExpression(List tokens) : Node(tokens); public sealed class NodeExpressionIntLiteral(List tokens, TokenIntLiteral value) : NodeExpression(tokens) { public readonly TokenIntLiteral Value = value; } public sealed class NodeExpressionStringLiteral(List tokens, TokenStringLiteral value) : NodeExpression(tokens) { public readonly TokenStringLiteral Value = value; } public sealed class NodeExpressionBoolLiteral(List tokens, TokenBoolLiteral value) : NodeExpression(tokens) { public readonly TokenBoolLiteral Value = value; } public sealed class NodeExpressionIdent(List tokens, TokenIdent value) : NodeExpression(tokens) { public readonly TokenIdent Value = value; } public abstract class NodeType(List tokens) : Node(tokens); public sealed class NubTypeVoid(List tokens) : NodeType(tokens); public sealed class NodeTypeUInt(List tokens, int width) : NodeType(tokens) { public readonly int Width = width; } public sealed class NodeTypeSInt(List tokens, int width) : NodeType(tokens) { public readonly int Width = width; } public sealed class NodeTypeFloat(List tokens, int width) : NodeType(tokens) { public readonly int Width = width; } public sealed class NodeTypeString(List tokens) : NodeType(tokens); public sealed class NodeTypeCustom(List tokens, TokenIdent name) : NodeType(tokens) { public readonly TokenIdent Name = name; } public sealed class NodeTypePointer(List tokens, NodeType to) : NodeType(tokens) { public readonly NodeType To = to; }