more renaming
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class BinaryExpressionNode(ExpressionNode left, BinaryExpressionOperator @operator, ExpressionNode right) : ExpressionNode
|
||||
{
|
||||
public ExpressionNode Left { get; } = left;
|
||||
public BinaryExpressionOperator Operator { get; } = @operator;
|
||||
public ExpressionNode Right { get; } = right;
|
||||
}
|
||||
|
||||
public enum BinaryExpressionOperator
|
||||
{
|
||||
Equal,
|
||||
NotEqual,
|
||||
GreaterThan,
|
||||
GreaterThanOrEqual,
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
Plus,
|
||||
Minus,
|
||||
Multiply,
|
||||
Divide
|
||||
}
|
||||
6
src/compiler/Nub.Lang/Frontend/Parsing/BlockNode.cs
Normal file
6
src/compiler/Nub.Lang/Frontend/Parsing/BlockNode.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class BlockNode(List<StatementNode> statements) : Node
|
||||
{
|
||||
public List<StatementNode> Statements { get; } = statements;
|
||||
}
|
||||
3
src/compiler/Nub.Lang/Frontend/Parsing/BreakNode.cs
Normal file
3
src/compiler/Nub.Lang/Frontend/Parsing/BreakNode.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class BreakNode : StatementNode;
|
||||
3
src/compiler/Nub.Lang/Frontend/Parsing/ContinueNode.cs
Normal file
3
src/compiler/Nub.Lang/Frontend/Parsing/ContinueNode.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class ContinueNode : StatementNode;
|
||||
3
src/compiler/Nub.Lang/Frontend/Parsing/DefinitionNode.cs
Normal file
3
src/compiler/Nub.Lang/Frontend/Parsing/DefinitionNode.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public abstract class DefinitionNode : Node;
|
||||
11
src/compiler/Nub.Lang/Frontend/Parsing/ExpressionNode.cs
Normal file
11
src/compiler/Nub.Lang/Frontend/Parsing/ExpressionNode.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public abstract class ExpressionNode : Node
|
||||
{
|
||||
private NubType? _type;
|
||||
public NubType Type
|
||||
{
|
||||
get => _type ?? throw new Exception("Tried to access expression type before type was populated");
|
||||
set => _type = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class ExternFuncDefinitionNode(string name, List<FuncParameter> parameters, Optional<NubType> returnType) : DefinitionNode
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public List<FuncParameter> Parameters { get; } = parameters;
|
||||
public Optional<NubType> ReturnType { get; } = returnType;
|
||||
|
||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||
}
|
||||
9
src/compiler/Nub.Lang/Frontend/Parsing/FuncCall.cs
Normal file
9
src/compiler/Nub.Lang/Frontend/Parsing/FuncCall.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class FuncCall(string name, List<ExpressionNode> parameters)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public List<ExpressionNode> Parameters { get; } = parameters;
|
||||
|
||||
public override string ToString() => $"{Name}()";
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class FuncCallExpressionNode(FuncCall funcCall) : ExpressionNode
|
||||
{
|
||||
public FuncCall FuncCall { get; } = funcCall;
|
||||
|
||||
public override string ToString() => FuncCall.ToString();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class FuncCallStatementNode(FuncCall funcCall) : StatementNode
|
||||
{
|
||||
public FuncCall FuncCall { get; } = funcCall;
|
||||
|
||||
public override string ToString() => FuncCall.ToString();
|
||||
}
|
||||
8
src/compiler/Nub.Lang/Frontend/Parsing/IdentifierNode.cs
Normal file
8
src/compiler/Nub.Lang/Frontend/Parsing/IdentifierNode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class IdentifierNode(string identifier) : ExpressionNode
|
||||
{
|
||||
public string Identifier { get; } = identifier;
|
||||
|
||||
public override string ToString() => Identifier;
|
||||
}
|
||||
8
src/compiler/Nub.Lang/Frontend/Parsing/IfNode.cs
Normal file
8
src/compiler/Nub.Lang/Frontend/Parsing/IfNode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class IfNode(ExpressionNode condition, BlockNode body, Optional<Variant<IfNode, BlockNode>> @else) : StatementNode
|
||||
{
|
||||
public ExpressionNode Condition { get; } = condition;
|
||||
public BlockNode Body { get; } = body;
|
||||
public Optional<Variant<IfNode, BlockNode>> Else { get; } = @else;
|
||||
}
|
||||
7
src/compiler/Nub.Lang/Frontend/Parsing/LiteralNode.cs
Normal file
7
src/compiler/Nub.Lang/Frontend/Parsing/LiteralNode.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class LiteralNode(string literal, NubType type) : ExpressionNode
|
||||
{
|
||||
public string Literal { get; } = literal;
|
||||
public NubType LiteralType { get; } = type;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class LocalFuncDefinitionNode(string name, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType, bool global) : DefinitionNode
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public List<FuncParameter> Parameters { get; } = parameters;
|
||||
public BlockNode Body { get; } = body;
|
||||
public Optional<NubType> ReturnType { get; } = returnType;
|
||||
public bool Global { get; } = global;
|
||||
|
||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||
}
|
||||
8
src/compiler/Nub.Lang/Frontend/Parsing/ModuleNode.cs
Normal file
8
src/compiler/Nub.Lang/Frontend/Parsing/ModuleNode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class ModuleNode(string path, List<string> imports, List<DefinitionNode> definitions) : Node
|
||||
{
|
||||
public string Path { get; } = path;
|
||||
public List<string> Imports { get; } = imports;
|
||||
public List<DefinitionNode> Definitions { get; } = definitions;
|
||||
}
|
||||
3
src/compiler/Nub.Lang/Frontend/Parsing/Node.cs
Normal file
3
src/compiler/Nub.Lang/Frontend/Parsing/Node.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public abstract class Node;
|
||||
568
src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs
Normal file
568
src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs
Normal file
@@ -0,0 +1,568 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Nub.Lang.Frontend.Lexing;
|
||||
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class Parser
|
||||
{
|
||||
private List<Token> _tokens = [];
|
||||
private int _index;
|
||||
|
||||
public ModuleNode ParseModule(List<Token> tokens, string path)
|
||||
{
|
||||
_index = 0;
|
||||
_tokens = tokens;
|
||||
|
||||
List<DefinitionNode> definitions = [];
|
||||
List<string> imports = [];
|
||||
|
||||
while (Peek().HasValue)
|
||||
{
|
||||
if (TryExpectSymbol(Symbol.Import))
|
||||
{
|
||||
var name = ExpectLiteral();
|
||||
if (!name.Type.Equals(NubType.String))
|
||||
{
|
||||
throw new Exception("Import statements must have a string literal value");
|
||||
}
|
||||
|
||||
TryExpectSymbol(Symbol.Semicolon);
|
||||
imports.Add(name.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
definitions.Add(ParseDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
return new ModuleNode(path, imports, definitions);
|
||||
}
|
||||
|
||||
private DefinitionNode ParseDefinition()
|
||||
{
|
||||
var keyword = ExpectSymbol();
|
||||
return keyword.Symbol switch
|
||||
{
|
||||
Symbol.Func => ParseFuncDefinition(),
|
||||
Symbol.Global => ParseGlobalFuncDefinition(),
|
||||
Symbol.Extern => ParseExternFuncDefinition(),
|
||||
Symbol.Struct => ParseStruct(),
|
||||
_ => throw new Exception("Unexpected symbol: " + keyword.Symbol)
|
||||
};
|
||||
}
|
||||
|
||||
private LocalFuncDefinitionNode ParseFuncDefinition()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
List<FuncParameter> parameters = [];
|
||||
ExpectSymbol(Symbol.OpenParen);
|
||||
if (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
while (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
parameters.Add(ParseFuncParameter());
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
}
|
||||
}
|
||||
|
||||
var returnType = Optional<NubType>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Colon))
|
||||
{
|
||||
returnType = ParseTypeInstance();
|
||||
}
|
||||
|
||||
var body = ParseBlock();
|
||||
|
||||
return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, false);
|
||||
}
|
||||
|
||||
private LocalFuncDefinitionNode ParseGlobalFuncDefinition()
|
||||
{
|
||||
ExpectSymbol(Symbol.Func);
|
||||
var name = ExpectIdentifier();
|
||||
List<FuncParameter> parameters = [];
|
||||
ExpectSymbol(Symbol.OpenParen);
|
||||
if (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
while (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
parameters.Add(ParseFuncParameter());
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
}
|
||||
}
|
||||
|
||||
var returnType = Optional<NubType>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Colon))
|
||||
{
|
||||
returnType = ParseTypeInstance();
|
||||
}
|
||||
|
||||
var body = ParseBlock();
|
||||
|
||||
return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, true);
|
||||
}
|
||||
|
||||
private ExternFuncDefinitionNode ParseExternFuncDefinition()
|
||||
{
|
||||
ExpectSymbol(Symbol.Func);
|
||||
var name = ExpectIdentifier();
|
||||
List<FuncParameter> parameters = [];
|
||||
ExpectSymbol(Symbol.OpenParen);
|
||||
if (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
while (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
parameters.Add(ParseFuncParameter());
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
}
|
||||
}
|
||||
|
||||
var returnType = Optional<NubType>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Colon))
|
||||
{
|
||||
returnType = ParseTypeInstance();
|
||||
}
|
||||
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
|
||||
return new ExternFuncDefinitionNode(name.Value, parameters, returnType);
|
||||
}
|
||||
|
||||
private StructDefinitionNode ParseStruct()
|
||||
{
|
||||
var name = ExpectIdentifier().Value;
|
||||
|
||||
ExpectSymbol(Symbol.OpenBrace);
|
||||
|
||||
List<StructField> variables = [];
|
||||
|
||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||
{
|
||||
var variableName = ExpectIdentifier().Value;
|
||||
ExpectSymbol(Symbol.Colon);
|
||||
var variableType = ParseTypeInstance();
|
||||
|
||||
var variableValue = Optional<ExpressionNode>.Empty();
|
||||
|
||||
if (TryExpectSymbol(Symbol.Assign))
|
||||
{
|
||||
variableValue = ParseExpression();
|
||||
}
|
||||
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
|
||||
variables.Add(new StructField(variableName, variableType, variableValue));
|
||||
}
|
||||
|
||||
return new StructDefinitionNode(name, variables);
|
||||
}
|
||||
|
||||
private FuncParameter ParseFuncParameter()
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
ExpectSymbol(Symbol.Colon);
|
||||
var type = ParseTypeInstance();
|
||||
|
||||
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);
|
||||
|
||||
return new FuncCallStatementNode(new FuncCall(identifier.Value, parameters));
|
||||
}
|
||||
case Symbol.Assign:
|
||||
{
|
||||
var value = ParseExpression();
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
return new VariableReassignmentNode(identifier.Value, value);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new Exception($"Unexpected symbol {symbol.Symbol}");
|
||||
}
|
||||
}
|
||||
}
|
||||
case SymbolToken symbol:
|
||||
{
|
||||
return symbol.Symbol switch
|
||||
{
|
||||
Symbol.Return => ParseReturn(),
|
||||
Symbol.Let => ParseVariableAssignment(),
|
||||
Symbol.If => ParseIf(),
|
||||
Symbol.While => ParseWhile(),
|
||||
Symbol.Break => ParseBreak(),
|
||||
Symbol.Continue => ParseContinue(),
|
||||
_ => throw new Exception($"Unexpected symbol {symbol.Symbol}")
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new Exception($"Unexpected token type {token.GetType().Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ReturnNode ParseReturn()
|
||||
{
|
||||
var value = Optional<ExpressionNode>.Empty();
|
||||
if (!TryExpectSymbol(Symbol.Semicolon))
|
||||
{
|
||||
value = ParseExpression();
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
}
|
||||
|
||||
return new ReturnNode(value);
|
||||
}
|
||||
|
||||
private VariableAssignmentNode ParseVariableAssignment()
|
||||
{
|
||||
var name = ExpectIdentifier().Value;
|
||||
ExpectSymbol(Symbol.Assign);
|
||||
var value = ParseExpression();
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
|
||||
return new VariableAssignmentNode(name, value);
|
||||
}
|
||||
|
||||
private IfNode ParseIf()
|
||||
{
|
||||
var condition = ParseExpression();
|
||||
var body = ParseBlock();
|
||||
|
||||
var elseStatement = Optional<Variant<IfNode, BlockNode>>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Else))
|
||||
{
|
||||
elseStatement = TryExpectSymbol(Symbol.If)
|
||||
? (Variant<IfNode, BlockNode>)ParseIf()
|
||||
: (Variant<IfNode, BlockNode>)ParseBlock();
|
||||
}
|
||||
|
||||
return new IfNode(condition, body, elseStatement);
|
||||
}
|
||||
|
||||
private WhileNode ParseWhile()
|
||||
{
|
||||
var condition = ParseExpression();
|
||||
var body = ParseBlock();
|
||||
return new WhileNode(condition, body);
|
||||
}
|
||||
|
||||
private BreakNode ParseBreak()
|
||||
{
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
return new BreakNode();
|
||||
}
|
||||
|
||||
private ContinueNode ParseContinue()
|
||||
{
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
return new ContinueNode();
|
||||
}
|
||||
|
||||
private ExpressionNode ParseExpression(int precedence = 0)
|
||||
{
|
||||
var left = ParsePrimaryExpression();
|
||||
|
||||
while (true)
|
||||
{
|
||||
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 BinaryExpressionNode(left, op.Value, right);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
private static int GetBinaryOperatorPrecedence(BinaryExpressionOperator binaryExpressionOperator)
|
||||
{
|
||||
return binaryExpressionOperator switch
|
||||
{
|
||||
BinaryExpressionOperator.Multiply => 3,
|
||||
BinaryExpressionOperator.Divide => 3,
|
||||
BinaryExpressionOperator.Plus => 2,
|
||||
BinaryExpressionOperator.Minus => 2,
|
||||
BinaryExpressionOperator.GreaterThan => 1,
|
||||
BinaryExpressionOperator.GreaterThanOrEqual => 1,
|
||||
BinaryExpressionOperator.LessThan => 1,
|
||||
BinaryExpressionOperator.LessThanOrEqual => 1,
|
||||
BinaryExpressionOperator.Equal => 0,
|
||||
BinaryExpressionOperator.NotEqual => 0,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(binaryExpressionOperator), binaryExpressionOperator, null)
|
||||
};
|
||||
}
|
||||
|
||||
private static bool TryGetBinaryOperator(Symbol symbol, [NotNullWhen(true)] out BinaryExpressionOperator? binaryExpressionOperator)
|
||||
{
|
||||
switch (symbol)
|
||||
{
|
||||
case Symbol.Equal:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.Equal;
|
||||
return true;
|
||||
case Symbol.NotEqual:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.NotEqual;
|
||||
return true;
|
||||
case Symbol.LessThan:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.LessThan;
|
||||
return true;
|
||||
case Symbol.LessThanOrEqual:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.LessThanOrEqual;
|
||||
return true;
|
||||
case Symbol.GreaterThan:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.GreaterThan;
|
||||
return true;
|
||||
case Symbol.GreaterThanOrEqual:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.GreaterThanOrEqual;
|
||||
return true;
|
||||
case Symbol.Plus:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.Plus;
|
||||
return true;
|
||||
case Symbol.Minus:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.Minus;
|
||||
return true;
|
||||
case Symbol.Star:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.Multiply;
|
||||
return true;
|
||||
case Symbol.ForwardSlash:
|
||||
binaryExpressionOperator = BinaryExpressionOperator.Divide;
|
||||
return true;
|
||||
default:
|
||||
binaryExpressionOperator = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private ExpressionNode ParsePrimaryExpression()
|
||||
{
|
||||
var token = ExpectToken();
|
||||
switch (token)
|
||||
{
|
||||
case LiteralToken literal:
|
||||
{
|
||||
return new LiteralNode(literal.Value, literal.Type);
|
||||
}
|
||||
case IdentifierToken identifier:
|
||||
{
|
||||
return ParseExpressionIdentifier(identifier);
|
||||
}
|
||||
case SymbolToken symbolToken:
|
||||
{
|
||||
switch (symbolToken.Symbol)
|
||||
{
|
||||
case Symbol.OpenParen:
|
||||
{
|
||||
var expression = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseParen);
|
||||
return expression;
|
||||
}
|
||||
case Symbol.New:
|
||||
{
|
||||
var type = ParseTypeInstance();
|
||||
Dictionary<string, ExpressionNode> initializers = [];
|
||||
ExpectSymbol(Symbol.OpenBrace);
|
||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||
{
|
||||
var name = ExpectIdentifier().Value;
|
||||
ExpectSymbol(Symbol.Assign);
|
||||
var value = ParseExpression();
|
||||
TryExpectSymbol(Symbol.Semicolon);
|
||||
initializers.Add(name, value);
|
||||
}
|
||||
|
||||
return new StructInitializerNode(type, initializers);
|
||||
}
|
||||
default:
|
||||
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new Exception($"Unexpected token type {token.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
private ExpressionNode ParseExpressionIdentifier(IdentifierToken identifier)
|
||||
{
|
||||
var token = Peek();
|
||||
if (!token.HasValue)
|
||||
{
|
||||
return new IdentifierNode(identifier.Value);
|
||||
}
|
||||
|
||||
switch (token.Value)
|
||||
{
|
||||
case SymbolToken symbolToken:
|
||||
{
|
||||
switch (symbolToken.Symbol)
|
||||
{
|
||||
case Symbol.Period:
|
||||
{
|
||||
Next();
|
||||
List<string> members =
|
||||
[
|
||||
identifier.Value,
|
||||
ExpectIdentifier().Value
|
||||
];
|
||||
|
||||
while (TryExpectSymbol(Symbol.Period))
|
||||
{
|
||||
members.Add(ExpectIdentifier().Value);
|
||||
}
|
||||
|
||||
return new StructMemberAccessorNode(members);
|
||||
}
|
||||
case Symbol.OpenParen:
|
||||
{
|
||||
Next();
|
||||
List<ExpressionNode> parameters = [];
|
||||
while (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
parameters.Add(ParseExpression());
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
}
|
||||
|
||||
return new FuncCallExpressionNode(new FuncCall(identifier.Value, parameters));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new IdentifierNode(identifier.Value);
|
||||
}
|
||||
|
||||
private BlockNode ParseBlock()
|
||||
{
|
||||
ExpectSymbol(Symbol.OpenBrace);
|
||||
List<StatementNode> statements = [];
|
||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||
{
|
||||
statements.Add(ParseStatement());
|
||||
}
|
||||
|
||||
return new BlockNode(statements);
|
||||
}
|
||||
|
||||
private NubType ParseTypeInstance()
|
||||
{
|
||||
var parameters = new List<NubType>();
|
||||
var name = ExpectIdentifier().Value;
|
||||
|
||||
if (TryExpectSymbol(Symbol.LessThan))
|
||||
{
|
||||
do
|
||||
{
|
||||
parameters.Add(ParseTypeInstance());
|
||||
} while (TryExpectSymbol(Symbol.Comma));
|
||||
|
||||
ExpectSymbol(Symbol.GreaterThan);
|
||||
}
|
||||
|
||||
return new NubType(name, parameters.ToArray());
|
||||
}
|
||||
|
||||
private Token ExpectToken()
|
||||
{
|
||||
var token = Peek();
|
||||
if (!token.HasValue)
|
||||
{
|
||||
throw new Exception("Reached end of tokens");
|
||||
}
|
||||
|
||||
Next();
|
||||
return token.Value;
|
||||
}
|
||||
|
||||
private SymbolToken ExpectSymbol()
|
||||
{
|
||||
var token = ExpectToken();
|
||||
if (token is not SymbolToken symbol)
|
||||
{
|
||||
throw new Exception($"Expected {nameof(SymbolToken)} but got {token.GetType().Name}");
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
private void ExpectSymbol(Symbol symbol)
|
||||
{
|
||||
var token = ExpectSymbol();
|
||||
if (token.Symbol != symbol)
|
||||
{
|
||||
throw new Exception($"Expected symbol {symbol} but got {token.Symbol}");
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
if (token is not IdentifierToken identifier)
|
||||
{
|
||||
throw new Exception($"Expected {nameof(IdentifierToken)} but got {token.GetType().Name}");
|
||||
}
|
||||
|
||||
return identifier;
|
||||
}
|
||||
|
||||
private LiteralToken ExpectLiteral()
|
||||
{
|
||||
var token = ExpectToken();
|
||||
if (token is not LiteralToken literal)
|
||||
{
|
||||
throw new Exception($"Expected {nameof(LiteralToken)} but got {token.GetType().Name}");
|
||||
}
|
||||
|
||||
return literal;
|
||||
}
|
||||
|
||||
private Optional<Token> Peek()
|
||||
{
|
||||
while (_index < _tokens.Count && _tokens.ElementAt(_index) is SymbolToken { Symbol: Symbol.Whitespace })
|
||||
{
|
||||
Next();
|
||||
}
|
||||
|
||||
if (_index < _tokens.Count)
|
||||
{
|
||||
return _tokens.ElementAt(_index);
|
||||
}
|
||||
|
||||
return Optional<Token>.Empty();
|
||||
}
|
||||
|
||||
private void Next()
|
||||
{
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
6
src/compiler/Nub.Lang/Frontend/Parsing/ReturnNode.cs
Normal file
6
src/compiler/Nub.Lang/Frontend/Parsing/ReturnNode.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class ReturnNode(Optional<ExpressionNode> value) : StatementNode
|
||||
{
|
||||
public Optional<ExpressionNode> Value { get; } = value;
|
||||
}
|
||||
3
src/compiler/Nub.Lang/Frontend/Parsing/StatementNode.cs
Normal file
3
src/compiler/Nub.Lang/Frontend/Parsing/StatementNode.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public abstract class StatementNode : Node;
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class StructDefinitionNode(string name, List<StructField> members) : DefinitionNode
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public List<StructField> Members { get; } = members;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class StructInitializerNode(NubType structType, Dictionary<string, ExpressionNode> initializers) : ExpressionNode
|
||||
{
|
||||
public NubType StructType { get; } = structType;
|
||||
public Dictionary<string, ExpressionNode> Initializers { get; } = initializers;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class StructMemberAccessorNode(List<string> members) : ExpressionNode
|
||||
{
|
||||
public List<string> Members { get; } = members;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class VariableAssignmentNode(string name, ExpressionNode value) : StatementNode
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public ExpressionNode Value { get; } = value;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class VariableReassignmentNode(string name, ExpressionNode value) : StatementNode
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public ExpressionNode Value { get; } = value;
|
||||
}
|
||||
7
src/compiler/Nub.Lang/Frontend/Parsing/WhileNode.cs
Normal file
7
src/compiler/Nub.Lang/Frontend/Parsing/WhileNode.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class WhileNode(ExpressionNode condition, BlockNode body) : StatementNode
|
||||
{
|
||||
public ExpressionNode Condition { get; } = condition;
|
||||
public BlockNode Body { get; } = body;
|
||||
}
|
||||
Reference in New Issue
Block a user