Parser now uses enumerator
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
.globl _start
|
||||
_start:
|
||||
mov rdi, rsp
|
||||
call default_main
|
||||
call main
|
||||
mov rdi, rax
|
||||
mov rax, 60
|
||||
syscall
|
||||
|
||||
Reference in New Issue
Block a user