Basic parser
This commit is contained in:
@@ -5,8 +5,6 @@ let STD_ERR = 2;
|
||||
|
||||
func main() {
|
||||
write("test");
|
||||
syscall(SYS_WRITE, STD_OUT, msg);
|
||||
return 12;
|
||||
}
|
||||
|
||||
func write(msg: void) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Nub.Lang.Parsing;
|
||||
|
||||
public class BlockNode(IEnumerable<StatementNode> statements) : StatementNode
|
||||
public class BlockNode(IEnumerable<StatementNode> statements) : Node
|
||||
{
|
||||
public IEnumerable<StatementNode> Statements { get; } = statements;
|
||||
}
|
||||
7
Nub.Lang/Nub.Lang/Parsing/FuncCallNode.cs
Normal file
7
Nub.Lang/Nub.Lang/Parsing/FuncCallNode.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Nub.Lang.Parsing;
|
||||
|
||||
public class FuncCallNode(string name, IEnumerable<ExpressionNode> parameters) : StatementNode
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public IEnumerable<ExpressionNode> Parameters { get; } = parameters;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
namespace Nub.Lang.Parsing;
|
||||
|
||||
public class FuncDefinitionNode(string name, IEnumerable<FuncParameter> parameters) : DefinitionNode
|
||||
public class FuncDefinitionNode(string name, IEnumerable<FuncParameter> parameters, BlockNode body) : DefinitionNode
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
|
||||
public BlockNode Body { get; } = body;
|
||||
}
|
||||
6
Nub.Lang/Nub.Lang/Parsing/IdentifierNode.cs
Normal file
6
Nub.Lang/Nub.Lang/Parsing/IdentifierNode.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Nub.Lang.Parsing;
|
||||
|
||||
public class IdentifierNode(string identifier) : ExpressionNode
|
||||
{
|
||||
public string Identifier { get; } = identifier;
|
||||
}
|
||||
6
Nub.Lang/Nub.Lang/Parsing/LiteralNode.cs
Normal file
6
Nub.Lang/Nub.Lang/Parsing/LiteralNode.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Nub.Lang.Parsing;
|
||||
|
||||
public class LiteralNode(string value) : ExpressionNode
|
||||
{
|
||||
public string Value { get; } = value;
|
||||
}
|
||||
@@ -15,17 +15,130 @@ public class Parser
|
||||
|
||||
public IEnumerable<DefinitionNode> Parse()
|
||||
{
|
||||
_index = 0;
|
||||
List<DefinitionNode> definitions = [];
|
||||
while (Peek().HasValue)
|
||||
{
|
||||
definitions.Add(ParseDefinition());
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
private DefinitionNode ParseDefinition()
|
||||
{
|
||||
var keyword = ExpectSymbol();
|
||||
return keyword.Symbol switch
|
||||
{
|
||||
Symbol.Let => ParseGlobalVariableDefinition(),
|
||||
Symbol.Func => ParseFuncDefinition(),
|
||||
_ => throw new Exception("Unexpected symbol: " + keyword.Symbol)
|
||||
};
|
||||
}
|
||||
|
||||
private GlobalVariableDefinitionNode ParseGlobalVariableDefinition()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
ExpectSymbol(Symbol.Assign);
|
||||
var value = ParseExpression();
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
|
||||
return new GlobalVariableDefinitionNode(name.Value, value);
|
||||
}
|
||||
|
||||
private FuncDefinitionNode ParseFuncDefinition()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
List<FuncParameter> parameters = [];
|
||||
ExpectSymbol(Symbol.OpenParen);
|
||||
if (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
while (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
parameters.Add(ParseFuncParameter());
|
||||
}
|
||||
}
|
||||
|
||||
var body = ParseBlock();
|
||||
|
||||
return new FuncDefinitionNode(name.Value, parameters, body);
|
||||
}
|
||||
|
||||
private FuncParameter ParseFuncParameter()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
ExpectSymbol(Symbol.Colon);
|
||||
var type = ParseType();
|
||||
|
||||
return new FuncParameter(name.Value, type);
|
||||
}
|
||||
|
||||
private StatementNode ParseStatement()
|
||||
{
|
||||
var token = ExpectToken();
|
||||
switch (token)
|
||||
{
|
||||
case IdentifierToken identifier:
|
||||
{
|
||||
var symbol = ExpectSymbol();
|
||||
switch (symbol.Symbol)
|
||||
{
|
||||
case Symbol.OpenParen:
|
||||
{
|
||||
var parameters = new List<ExpressionNode>();
|
||||
while (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
parameters.Add(ParseExpression());
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
}
|
||||
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
|
||||
if (identifier.Value == "syscall")
|
||||
{
|
||||
return new SyscallNode(parameters);
|
||||
}
|
||||
|
||||
return new FuncCallNode(identifier.Value, parameters);
|
||||
}
|
||||
case Symbol.Assign:
|
||||
throw new NotImplementedException();
|
||||
default:
|
||||
throw new Exception($"Unexpected symbol {symbol.Symbol}");
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new Exception($"Unexpected token type {token.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
private ExpressionNode ParseExpression()
|
||||
{
|
||||
var token = ExpectToken();
|
||||
return token switch
|
||||
{
|
||||
LiteralToken literal => new LiteralNode(literal.Value),
|
||||
IdentifierToken identifier => new IdentifierNode(identifier.Value),
|
||||
_ => throw new Exception($"Unexpected token type {token.GetType().Name}")
|
||||
};
|
||||
}
|
||||
|
||||
private BlockNode ParseBlock()
|
||||
{
|
||||
ExpectSymbol(Symbol.OpenBrace);
|
||||
List<StatementNode> statements = [];
|
||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||
{
|
||||
statements.Add(ParseStatement());
|
||||
}
|
||||
|
||||
return new BlockNode(statements);
|
||||
}
|
||||
|
||||
private Type ParseType()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
return new Type(name.Value);
|
||||
}
|
||||
|
||||
private Token ExpectToken()
|
||||
@@ -36,6 +149,7 @@ public class Parser
|
||||
throw new Exception("Reached end of tokens");
|
||||
}
|
||||
|
||||
Next();
|
||||
return token.Value;
|
||||
}
|
||||
|
||||
@@ -46,6 +160,7 @@ public class Parser
|
||||
{
|
||||
throw new Exception($"Expected {nameof(SymbolToken)} but got {token.GetType().Name}");
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@@ -58,6 +173,13 @@ public class Parser
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryExpectSymbol(Symbol symbol)
|
||||
{
|
||||
var result = Peek() is { HasValue: true, Value: SymbolToken symbolToken } && symbolToken.Symbol == symbol;
|
||||
if (result) Next();
|
||||
return result;
|
||||
}
|
||||
|
||||
private IdentifierToken ExpectIdentifier()
|
||||
{
|
||||
var token = ExpectToken();
|
||||
@@ -65,6 +187,7 @@ public class Parser
|
||||
{
|
||||
throw new Exception($"Expected {nameof(IdentifierToken)} but got {token.GetType().Name}");
|
||||
}
|
||||
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@@ -75,11 +198,17 @@ public class Parser
|
||||
{
|
||||
throw new Exception($"Expected {nameof(LiteralToken)} but got {token.GetType().Name}");
|
||||
}
|
||||
|
||||
return literal;
|
||||
}
|
||||
|
||||
private Optional<Token> Peek()
|
||||
{
|
||||
while (_index < _tokens.Length && _tokens[_index] is SymbolToken { Symbol: Symbol.Whitespace })
|
||||
{
|
||||
Next();
|
||||
}
|
||||
|
||||
if (_index < _tokens.Length)
|
||||
{
|
||||
return _tokens[_index];
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
namespace Nub.Lang.Parsing;
|
||||
|
||||
public class ESyscallNode(IEnumerable<FuncParameter> parameters) : ExpressionNode
|
||||
public class SyscallNode(IEnumerable<ExpressionNode> parameters) : StatementNode
|
||||
{
|
||||
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
|
||||
}
|
||||
|
||||
public class SSyscallNode(IEnumerable<FuncParameter> parameters) : StatementNode
|
||||
{
|
||||
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
|
||||
public IEnumerable<ExpressionNode> Parameters { get; } = parameters;
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
using Nub.Lang.Lexing;
|
||||
using Nub.Lang.Parsing;
|
||||
|
||||
var src = File.ReadAllText(args[0]);
|
||||
|
||||
var lexer = new Lexer(src);
|
||||
var tokens = lexer.Lex();
|
||||
|
||||
var parser = new Parser(tokens);
|
||||
var definitions = parser.Parse();
|
||||
|
||||
Console.Read();
|
||||
Reference in New Issue
Block a user