Parser now uses enumerator

This commit is contained in:
nub31
2025-07-22 23:01:29 +02:00
parent eb009b6ac0
commit d97e37fd34
4 changed files with 105 additions and 159 deletions

View File

@@ -1,4 +1,2 @@
namespace c
extern func printf(fmt: cstring, arg: i64): void extern func printf(fmt: cstring, arg: i64): void
extern func puts(fmt: cstring) extern func puts(fmt: cstring)

View File

@@ -1,6 +1,5 @@
func main(args: []cstring): i64 func main(args: []cstring): i64
{ {
c::puts("test") puts("test")
return 0 return 0
} }

View File

@@ -8,10 +8,10 @@ namespace NubLang.Syntax.Parsing;
public sealed class Parser public sealed class Parser
{ {
private IEnumerable<Token> _tokens = null!; private IEnumerator<Token> _tokenEnumerator = null!;
private readonly List<Diagnostic> _diagnostics = []; private readonly List<Diagnostic> _diagnostics = [];
private int _tokenIndex; private Token? _currentToken;
private bool _hasCurrentToken;
public IReadOnlyList<Diagnostic> GetDiagnostics() public IReadOnlyList<Diagnostic> GetDiagnostics()
{ {
@@ -21,12 +21,13 @@ public sealed class Parser
public SyntaxTree Parse(IEnumerable<Token> tokens) public SyntaxTree Parse(IEnumerable<Token> tokens)
{ {
_diagnostics.Clear(); _diagnostics.Clear();
_tokenIndex = 0; _tokenEnumerator = tokens.GetEnumerator();
_tokens = tokens; _hasCurrentToken = _tokenEnumerator.MoveNext();
_currentToken = _hasCurrentToken ? _tokenEnumerator.Current : null;
var definitions = new List<DefinitionSyntax>(); var definitions = new List<DefinitionSyntax>();
while (Peek().HasValue) while (_hasCurrentToken)
{ {
try try
{ {
@@ -49,10 +50,9 @@ public sealed class Parser
catch (ParseException ex) catch (ParseException ex)
{ {
_diagnostics.Add(ex.Diagnostic); _diagnostics.Add(ex.Diagnostic);
while (Peek().HasValue) while (_hasCurrentToken)
{ {
var token = Peek().Value; if (_currentToken is SymbolToken { Symbol: Symbol.Extern or Symbol.Func or Symbol.Struct or Symbol.Interface })
if (token is SymbolToken { Symbol: Symbol.Extern or Symbol.Func or Symbol.Struct or Symbol.Interface })
{ {
break; break;
} }
@@ -80,7 +80,7 @@ public sealed class Parser
{ {
parameters.Add(ParseFuncParameter()); parameters.Add(ParseFuncParameter());
if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen }) if (!TryExpectSymbol(Symbol.Comma) && _currentToken is not SymbolToken { Symbol: Symbol.CloseParen })
{ {
_diagnostics.Add(Diagnostic _diagnostics.Add(Diagnostic
.Warning("Missing comma between function parameters") .Warning("Missing comma between function parameters")
@@ -204,14 +204,7 @@ public sealed class Parser
private StatementSyntax ParseStatement() private StatementSyntax ParseStatement()
{ {
if (!Peek().TryGetValue(out var token)) if (_currentToken is SymbolToken symbol)
{
throw new ParseException(Diagnostic
.Error("Unexpected end of file while parsing statement")
.Build());
}
if (token is SymbolToken symbol)
{ {
switch (symbol.Symbol) switch (symbol.Symbol)
{ {
@@ -269,7 +262,6 @@ public sealed class Parser
private StatementSyntax ParseBreak() private StatementSyntax ParseBreak()
{ {
ExpectSymbol(Symbol.Break); ExpectSymbol(Symbol.Break);
Next();
return new BreakSyntax(); return new BreakSyntax();
} }
@@ -322,18 +314,10 @@ public sealed class Parser
{ {
var left = ParsePrimaryExpression(); var left = ParsePrimaryExpression();
while (true) while (_currentToken is SymbolToken symbolToken && TryGetBinaryOperator(symbolToken.Symbol, out var op) && GetBinaryOperatorPrecedence(op.Value) >= precedence)
{ {
var token = Peek();
if (!token.HasValue || token.Value is not SymbolToken symbolToken || !TryGetBinaryOperator(symbolToken.Symbol, out var op) ||
GetBinaryOperatorPrecedence(op.Value) < precedence)
{
break;
}
Next(); Next();
var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1); var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
left = new BinaryExpressionSyntax(left, op.Value, right); left = new BinaryExpressionSyntax(left, op.Value, right);
} }
@@ -400,125 +384,99 @@ public sealed class Parser
private ExpressionSyntax ParsePrimaryExpression() private ExpressionSyntax ParsePrimaryExpression()
{ {
ExpressionSyntax expr;
var token = ExpectToken(); var token = ExpectToken();
switch (token) var expr = token switch
{ {
case LiteralToken literal: LiteralToken literal => new LiteralSyntax(literal.Value, literal.Kind),
IdentifierToken identifier => new IdentifierSyntax(identifier.Value),
SymbolToken symbolToken => symbolToken.Symbol switch
{ {
expr = new LiteralSyntax(literal.Value, literal.Kind); Symbol.Func => ParseArrowFunction(),
break; Symbol.OpenParen => ParseParenthesizedExpression(),
} Symbol.Minus => new UnaryExpressionSyntax(UnaryOperator.Negate, ParsePrimaryExpression()),
case IdentifierToken identifier: Symbol.Bang => new UnaryExpressionSyntax(UnaryOperator.Invert, ParsePrimaryExpression()),
{ Symbol.OpenBracket => ParseArrayInitializer(),
expr = new IdentifierSyntax(identifier.Value); Symbol.Alloc => ParseStructInitializer(),
break; _ => throw new ParseException(Diagnostic
} .Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
case SymbolToken symbolToken: .WithHelp("Expected literal, identifier, or '(' to start expression")
{ .Build())
switch (symbolToken.Symbol) },
{ _ => throw new ParseException(Diagnostic
case Symbol.Func: .Error($"Unexpected token '{token.GetType().Name}' in expression")
{ .WithHelp("Expected literal, identifier, or parenthesized expression")
List<ArrowFuncParameterSyntax> parameters = []; .Build())
ExpectSymbol(Symbol.OpenParen); };
while (!TryExpectSymbol(Symbol.CloseParen))
{
var name = ExpectIdentifier();
parameters.Add(new ArrowFuncParameterSyntax(name.Value));
}
BlockSyntax body;
if (TryExpectSymbol(Symbol.Arrow))
{
var returnValue = ParseExpression();
var arrowExpression = new ReturnSyntax(returnValue);
body = new BlockSyntax([arrowExpression]);
}
else
{
body = ParseBlock();
}
expr = new ArrowFuncSyntax(parameters, body);
break;
}
case Symbol.OpenParen:
{
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
expr = expression;
break;
}
case Symbol.Minus:
{
var expression = ParsePrimaryExpression();
expr = new UnaryExpressionSyntax(UnaryOperator.Negate, expression);
break;
}
case Symbol.Bang:
{
var expression = ParsePrimaryExpression();
expr = new UnaryExpressionSyntax(UnaryOperator.Invert, expression);
break;
}
case Symbol.OpenBracket:
{
var capacity = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
var type = ParseType();
expr = new ArrayInitializerSyntax(capacity, type);
break;
}
case Symbol.Alloc:
{
var type = ParseType();
Dictionary<string, ExpressionSyntax> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
initializers.Add(name, value);
}
expr = new StructInitializerSyntax(type, initializers);
break;
}
default:
{
throw new ParseException(Diagnostic
.Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
.WithHelp("Expected literal, identifier, or '(' to start expression")
.Build());
}
}
break;
}
default:
{
throw new ParseException(Diagnostic
.Error($"Unexpected token '{token.GetType().Name}' in expression")
.WithHelp("Expected literal, identifier, or parenthesized expression")
.Build());
}
}
return ParsePostfixOperators(expr); return ParsePostfixOperators(expr);
} }
private ExpressionSyntax ParseArrowFunction()
{
List<ArrowFuncParameterSyntax> parameters = [];
ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen))
{
var name = ExpectIdentifier();
parameters.Add(new ArrowFuncParameterSyntax(name.Value));
}
ExpectSymbol(Symbol.Arrow);
BlockSyntax body;
if (_currentToken is SymbolToken { Symbol: Symbol.OpenBrace })
{
var returnValue = ParseExpression();
var arrowExpression = new ReturnSyntax(returnValue);
body = new BlockSyntax([arrowExpression]);
}
else
{
body = ParseBlock();
}
return new ArrowFuncSyntax(parameters, body);
}
private ExpressionSyntax ParseParenthesizedExpression()
{
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return expression;
}
private ExpressionSyntax ParseArrayInitializer()
{
var capacity = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
var type = ParseType();
return new ArrayInitializerSyntax(capacity, type);
}
private ExpressionSyntax ParseStructInitializer()
{
var type = ParseType();
Dictionary<string, ExpressionSyntax> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
initializers.Add(name, value);
}
return new StructInitializerSyntax(type, initializers);
}
private ExpressionSyntax ParsePostfixOperators(ExpressionSyntax expr) private ExpressionSyntax ParsePostfixOperators(ExpressionSyntax expr)
{ {
while (true) while (_hasCurrentToken)
{ {
if (TryExpectSymbol(Symbol.Ampersand)) if (TryExpectSymbol(Symbol.Ampersand))
{ {
expr = new AddressOfSyntax(expr); expr = new AddressOfSyntax(expr);
break; continue;
} }
if (TryExpectSymbol(Symbol.Caret)) if (TryExpectSymbol(Symbol.Caret))
@@ -548,7 +506,7 @@ public sealed class Parser
while (!TryExpectSymbol(Symbol.CloseParen)) while (!TryExpectSymbol(Symbol.CloseParen))
{ {
parameters.Add(ParseExpression()); parameters.Add(ParseExpression());
if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) if (!TryExpectSymbol(Symbol.Comma) && _currentToken is not SymbolToken { Symbol: Symbol.CloseParen })
{ {
_diagnostics.Add(Diagnostic _diagnostics.Add(Diagnostic
.Warning("Missing comma between function arguments") .Warning("Missing comma between function arguments")
@@ -571,7 +529,7 @@ public sealed class Parser
{ {
ExpectSymbol(Symbol.OpenBrace); ExpectSymbol(Symbol.OpenBrace);
List<StatementSyntax> statements = []; List<StatementSyntax> statements = [];
while (Peek().HasValue && !TryExpectSymbol(Symbol.CloseBrace)) while (!TryExpectSymbol(Symbol.CloseBrace))
{ {
try try
{ {
@@ -625,7 +583,7 @@ public sealed class Parser
{ {
var parameter = ParseType(); var parameter = ParseType();
parameters.Add(parameter); parameters.Add(parameter);
if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) if (!TryExpectSymbol(Symbol.Comma) && _currentToken is not SymbolToken { Symbol: Symbol.CloseParen })
{ {
_diagnostics.Add(Diagnostic _diagnostics.Add(Diagnostic
.Warning("Missing comma between func type arguments") .Warning("Missing comma between func type arguments")
@@ -647,21 +605,22 @@ public sealed class Parser
} }
throw new ParseException(Diagnostic throw new ParseException(Diagnostic
.Error("Invalid type Syntax") .Error("Invalid type syntax")
.WithHelp("Expected type name, '^' for pointer, or '[]' for array") .WithHelp("Expected type name, '^' for pointer, or '[]' for array")
.Build()); .Build());
} }
private Token ExpectToken() private Token ExpectToken()
{ {
if (!Peek().TryGetValue(out var token)) if (!_hasCurrentToken)
{ {
throw new ParseException(Diagnostic throw new ParseException(Diagnostic
.Error("Unexpected end of file") .Error("Unexpected end of file")
.WithHelp("Expected more tokens to complete the Syntax") .WithHelp("Expected more tokens to complete the syntax")
.Build()); .Build());
} }
var token = _currentToken!;
Next(); Next();
return token; return token;
} }
@@ -694,7 +653,7 @@ public sealed class Parser
private bool TryExpectSymbol(Symbol symbol) private bool TryExpectSymbol(Symbol symbol)
{ {
if (Peek() is { Value: SymbolToken symbolToken } && symbolToken.Symbol == symbol) if (_currentToken is SymbolToken symbolToken && symbolToken.Symbol == symbol)
{ {
Next(); Next();
return true; return true;
@@ -705,7 +664,7 @@ public sealed class Parser
private bool TryExpectIdentifier([NotNullWhen(true)] out IdentifierToken? identifier) private bool TryExpectIdentifier([NotNullWhen(true)] out IdentifierToken? identifier)
{ {
if (Peek() is { Value: IdentifierToken identifierToken }) if (_currentToken is IdentifierToken identifierToken)
{ {
identifier = identifierToken; identifier = identifierToken;
Next(); Next();
@@ -730,20 +689,10 @@ public sealed class Parser
return identifier; return identifier;
} }
private Optional<Token> Peek(int offset = 0)
{
var peekIndex = _tokenIndex + offset;
if (peekIndex < _tokens.Count())
{
return _tokens.ElementAt(peekIndex);
}
return Optional<Token>.Empty();
}
private void Next() private void Next()
{ {
_tokenIndex++; _hasCurrentToken = _tokenEnumerator.MoveNext();
_currentToken = _hasCurrentToken ? _tokenEnumerator.Current : null;
} }
} }

View File

@@ -4,7 +4,7 @@
.globl _start .globl _start
_start: _start:
mov rdi, rsp mov rdi, rsp
call default_main call main
mov rdi, rax mov rdi, rax
mov rax, 60 mov rax, 60
syscall syscall