Basic parser
This commit is contained in:
@@ -5,8 +5,6 @@ let STD_ERR = 2;
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
write("test");
|
write("test");
|
||||||
syscall(SYS_WRITE, STD_OUT, msg);
|
|
||||||
return 12;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func write(msg: void) {
|
func write(msg: void) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace Nub.Lang.Parsing;
|
namespace Nub.Lang.Parsing;
|
||||||
|
|
||||||
public class BlockNode(IEnumerable<StatementNode> statements) : StatementNode
|
public class BlockNode(IEnumerable<StatementNode> statements) : Node
|
||||||
{
|
{
|
||||||
public IEnumerable<StatementNode> Statements { get; } = statements;
|
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;
|
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 string Name { get; } = name;
|
||||||
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
|
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()
|
public IEnumerable<DefinitionNode> Parse()
|
||||||
{
|
{
|
||||||
|
_index = 0;
|
||||||
List<DefinitionNode> definitions = [];
|
List<DefinitionNode> definitions = [];
|
||||||
while (Peek().HasValue)
|
while (Peek().HasValue)
|
||||||
{
|
{
|
||||||
definitions.Add(ParseDefinition());
|
definitions.Add(ParseDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return definitions;
|
return definitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DefinitionNode ParseDefinition()
|
private DefinitionNode ParseDefinition()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
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()
|
private Token ExpectToken()
|
||||||
@@ -36,6 +149,7 @@ public class Parser
|
|||||||
throw new Exception("Reached end of tokens");
|
throw new Exception("Reached end of tokens");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Next();
|
||||||
return token.Value;
|
return token.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,9 +160,10 @@ public class Parser
|
|||||||
{
|
{
|
||||||
throw new Exception($"Expected {nameof(SymbolToken)} but got {token.GetType().Name}");
|
throw new Exception($"Expected {nameof(SymbolToken)} but got {token.GetType().Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExpectSymbol(Symbol symbol)
|
private void ExpectSymbol(Symbol symbol)
|
||||||
{
|
{
|
||||||
var token = ExpectSymbol();
|
var token = ExpectSymbol();
|
||||||
@@ -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()
|
private IdentifierToken ExpectIdentifier()
|
||||||
{
|
{
|
||||||
var token = ExpectToken();
|
var token = ExpectToken();
|
||||||
@@ -65,9 +187,10 @@ public class Parser
|
|||||||
{
|
{
|
||||||
throw new Exception($"Expected {nameof(IdentifierToken)} but got {token.GetType().Name}");
|
throw new Exception($"Expected {nameof(IdentifierToken)} but got {token.GetType().Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LiteralToken ExpectLiteral()
|
private LiteralToken ExpectLiteral()
|
||||||
{
|
{
|
||||||
var token = ExpectToken();
|
var token = ExpectToken();
|
||||||
@@ -75,19 +198,25 @@ public class Parser
|
|||||||
{
|
{
|
||||||
throw new Exception($"Expected {nameof(LiteralToken)} but got {token.GetType().Name}");
|
throw new Exception($"Expected {nameof(LiteralToken)} but got {token.GetType().Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return literal;
|
return literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Token> Peek()
|
private Optional<Token> Peek()
|
||||||
{
|
{
|
||||||
|
while (_index < _tokens.Length && _tokens[_index] is SymbolToken { Symbol: Symbol.Whitespace })
|
||||||
|
{
|
||||||
|
Next();
|
||||||
|
}
|
||||||
|
|
||||||
if (_index < _tokens.Length)
|
if (_index < _tokens.Length)
|
||||||
{
|
{
|
||||||
return _tokens[_index];
|
return _tokens[_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional<Token>.Empty();
|
return Optional<Token>.Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Next()
|
private void Next()
|
||||||
{
|
{
|
||||||
_index++;
|
_index++;
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
namespace Nub.Lang.Parsing;
|
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 IEnumerable<ExpressionNode> Parameters { get; } = parameters;
|
||||||
}
|
|
||||||
|
|
||||||
public class SSyscallNode(IEnumerable<FuncParameter> parameters) : StatementNode
|
|
||||||
{
|
|
||||||
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
using Nub.Lang.Lexing;
|
using Nub.Lang.Lexing;
|
||||||
|
using Nub.Lang.Parsing;
|
||||||
|
|
||||||
var src = File.ReadAllText(args[0]);
|
var src = File.ReadAllText(args[0]);
|
||||||
|
|
||||||
var lexer = new Lexer(src);
|
var lexer = new Lexer(src);
|
||||||
var tokens = lexer.Lex();
|
var tokens = lexer.Lex();
|
||||||
|
|
||||||
|
var parser = new Parser(tokens);
|
||||||
|
var definitions = parser.Parse();
|
||||||
|
|
||||||
|
Console.Read();
|
||||||
Reference in New Issue
Block a user