Parser now uses enumerator
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
func main(args: []cstring): i64
|
func main(args: []cstring): i64
|
||||||
{
|
{
|
||||||
c::puts("test")
|
puts("test")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user