Parser now uses enumerator

This commit is contained in:
nub31
2025-07-22 23:01:29 +02:00
parent f6da9e9753
commit 62c9d86cda
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,26 +384,34 @@ 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()),
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);
} }
case IdentifierToken identifier:
{ private ExpressionSyntax ParseArrowFunction()
expr = new IdentifierSyntax(identifier.Value);
break;
}
case SymbolToken symbolToken:
{
switch (symbolToken.Symbol)
{
case Symbol.Func:
{ {
List<ArrowFuncParameterSyntax> parameters = []; List<ArrowFuncParameterSyntax> parameters = [];
ExpectSymbol(Symbol.OpenParen); ExpectSymbol(Symbol.OpenParen);
@@ -429,9 +421,10 @@ public sealed class Parser
parameters.Add(new ArrowFuncParameterSyntax(name.Value)); parameters.Add(new ArrowFuncParameterSyntax(name.Value));
} }
ExpectSymbol(Symbol.Arrow);
BlockSyntax body; BlockSyntax body;
if (TryExpectSymbol(Symbol.Arrow)) if (_currentToken is SymbolToken { Symbol: Symbol.OpenBrace })
{ {
var returnValue = ParseExpression(); var returnValue = ParseExpression();
var arrowExpression = new ReturnSyntax(returnValue); var arrowExpression = new ReturnSyntax(returnValue);
@@ -442,37 +435,25 @@ public sealed class Parser
body = ParseBlock(); body = ParseBlock();
} }
expr = new ArrowFuncSyntax(parameters, body); return new ArrowFuncSyntax(parameters, body);
break;
} }
case Symbol.OpenParen:
private ExpressionSyntax ParseParenthesizedExpression()
{ {
var expression = ParseExpression(); var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen); ExpectSymbol(Symbol.CloseParen);
expr = expression; return expression;
break;
} }
case Symbol.Minus:
{ private ExpressionSyntax ParseArrayInitializer()
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(); var capacity = ParseExpression();
ExpectSymbol(Symbol.CloseBracket); ExpectSymbol(Symbol.CloseBracket);
var type = ParseType(); var type = ParseType();
expr = new ArrayInitializerSyntax(capacity, type); return new ArrayInitializerSyntax(capacity, type);
break;
} }
case Symbol.Alloc:
private ExpressionSyntax ParseStructInitializer()
{ {
var type = ParseType(); var type = ParseType();
Dictionary<string, ExpressionSyntax> initializers = []; Dictionary<string, ExpressionSyntax> initializers = [];
@@ -485,40 +466,17 @@ public sealed class Parser
initializers.Add(name, value); initializers.Add(name, value);
} }
expr = new StructInitializerSyntax(type, initializers); return 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);
} }
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