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 puts(fmt: cstring)

View File

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

View File

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

View File

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