This commit is contained in:
nub31
2025-05-04 16:02:48 +02:00
parent 248f95fa6e
commit 5f2d1ff3f9
25 changed files with 264 additions and 539 deletions

View File

@@ -86,7 +86,7 @@ public class Lexer
if (buffer is "true" or "false")
{
return new LiteralToken(new PrimitiveType(PrimitiveTypeKind.Bool), buffer);
return new LiteralToken(NubType.Bool, buffer);
}
return new IdentifierToken(buffer);
@@ -103,7 +103,7 @@ public class Lexer
current = Peek();
}
return new LiteralToken(new PrimitiveType(PrimitiveTypeKind.Int64), buffer);
return new LiteralToken(NubType.Int64, buffer);
}
// TODO: Revisit this
@@ -148,7 +148,7 @@ public class Lexer
buffer += current.Value;
}
return new LiteralToken(new StringType(), buffer);
return new LiteralToken(NubType.String, buffer);
}
if (char.IsWhiteSpace(current.Value))

View File

@@ -1,7 +1,7 @@
namespace Nub.Lang.Frontend.Lexing;
public class LiteralToken(Type type, string value) : Token
public class LiteralToken(NubType type, string value) : Token
{
public Type Type { get; } = type;
public NubType Type { get; } = type;
public string Value { get; } = value;
}

View File

@@ -1,9 +0,0 @@
namespace Nub.Lang.Frontend.Parsing;
public class ArrayIndexAccessNode(IdentifierNode identifier, ExpressionNode index) : ExpressionNode
{
public IdentifierNode Identifier { get; } = identifier;
public ExpressionNode Index { get; } = index;
public override string ToString() => $"{Identifier}[{Index}]";
}

View File

@@ -1,8 +0,0 @@
namespace Nub.Lang.Frontend.Parsing;
public class ArrayIndexAssignmentNode(IdentifierNode identifier, ExpressionNode index, ExpressionNode value) : StatementNode
{
public IdentifierNode Identifier { get; } = identifier;
public ExpressionNode Index { get; } = index;
public ExpressionNode Value { get; } = value;
}

View File

@@ -1,7 +0,0 @@
namespace Nub.Lang.Frontend.Parsing;
public class ArrayInitializerNode(long length, Type innerType) : ExpressionNode
{
public long Length { get; } = length;
public Type InnerType { get; } = innerType;
}

View File

@@ -2,8 +2,8 @@
public abstract class ExpressionNode : Node
{
private Type? _type;
public Type Type
private NubType? _type;
public NubType Type
{
get => _type ?? throw new Exception("Tried to access expression type before type was populated");
set => _type = value;

View File

@@ -1,10 +1,10 @@
namespace Nub.Lang.Frontend.Parsing;
public class ExternFuncDefinitionNode(string name, List<FuncParameter> parameters, Optional<Type> returnType) : DefinitionNode
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<Type> ReturnType { get; } = returnType;
public Optional<NubType> ReturnType { get; } = returnType;
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
}

View File

@@ -1,7 +1,7 @@
namespace Nub.Lang.Frontend.Parsing;
public class LiteralNode(string literal, Type type) : ExpressionNode
public class LiteralNode(string literal, NubType type) : ExpressionNode
{
public string Literal { get; } = literal;
public Type LiteralType { get; } = type;
public NubType LiteralType { get; } = type;
}

View File

@@ -1,11 +1,11 @@
namespace Nub.Lang.Frontend.Parsing;
public class LocalFuncDefinitionNode(string name, List<FuncParameter> parameters, BlockNode body, Optional<Type> returnType) : DefinitionNode
public class LocalFuncDefinitionNode(string name, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType) : DefinitionNode
{
public string Name { get; } = name;
public List<FuncParameter> Parameters { get; } = parameters;
public BlockNode Body { get; } = body;
public Optional<Type> ReturnType { get; } = returnType;
public Optional<NubType> ReturnType { get; } = returnType;
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
}

View File

@@ -7,21 +7,21 @@ 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 is not StringType)
if (!name.Type.Equals(NubType.String))
{
throw new Exception("Import statements must have a string literal value");
}
@@ -75,10 +75,10 @@ public class Parser
}
}
var returnType = Optional<Type>.Empty();
var returnType = Optional<NubType>.Empty();
if (TryExpectSymbol(Symbol.Colon))
{
returnType = ParseType();
returnType = ParseTypeInstance();
}
var body = ParseBlock();
@@ -101,14 +101,14 @@ public class Parser
}
}
var returnType = Optional<Type>.Empty();
var returnType = Optional<NubType>.Empty();
if (TryExpectSymbol(Symbol.Colon))
{
returnType = ParseType();
returnType = ParseTypeInstance();
}
ExpectSymbol(Symbol.Semicolon);
return new ExternFuncDefinitionNode(name.Value, parameters, returnType);
}
@@ -117,28 +117,27 @@ public class Parser
var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.OpenBrace);
List<StructMember> variables = [];
while (!TryExpectSymbol(Symbol.CloseBrace))
{
ExpectSymbol(Symbol.Let);
var variableName = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Colon);
var variableType = ParseType();
var variableType = ParseTypeInstance();
var variableValue = Optional<ExpressionNode>.Empty();
if (TryExpectSymbol(Symbol.Assign))
{
variableValue = ParseExpression();
}
ExpectSymbol(Symbol.Semicolon);
variables.Add(new StructMember(variableName, variableType, variableValue));
}
return new StructDefinitionNode(name, variables);
}
@@ -146,7 +145,7 @@ public class Parser
{
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon);
var type = ParseType();
var type = ParseTypeInstance();
return new FuncParameter(name.Value, type);
}
@@ -179,15 +178,6 @@ public class Parser
return new FuncCallStatementNode(new FuncCall(identifier.Value, parameters));
}
case Symbol.OpenBracket:
{
var index = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
ExpectSymbol(Symbol.Semicolon);
return new ArrayIndexAssignmentNode(new IdentifierNode(identifier.Value), index, value);
}
case Symbol.Assign:
{
var value = ParseExpression();
@@ -238,7 +228,7 @@ public class Parser
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
ExpectSymbol(Symbol.Semicolon);
return new VariableAssignmentNode(name, value);
}
@@ -254,7 +244,7 @@ public class Parser
? (Variant<IfNode, BlockNode>)ParseIf()
: (Variant<IfNode, BlockNode>)ParseBlock();
}
return new IfNode(condition, body, elseStatement);
}
@@ -276,7 +266,7 @@ public class Parser
ExpectSymbol(Symbol.Semicolon);
return new ContinueNode();
}
private ExpressionNode ParseExpression(int precedence = 0)
{
var left = ParsePrimaryExpression();
@@ -284,15 +274,16 @@ public class Parser
while (true)
{
var token = Peek();
if (!token.HasValue || token.Value is not SymbolToken symbolToken || !TryGetBinaryOperator(symbolToken.Symbol, out var op) || GetBinaryOperatorPrecedence(op.Value) < precedence)
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;
}
@@ -360,9 +351,13 @@ public class Parser
switch (token)
{
case LiteralToken literal:
{
return new LiteralNode(literal.Value, literal.Type);
}
case IdentifierToken identifier:
{
return ParseExpressionIdentifier(identifier);
}
case SymbolToken symbolToken:
{
switch (symbolToken.Symbol)
@@ -375,45 +370,25 @@ public class Parser
}
case Symbol.New:
{
var type = ParseType();
switch (type)
var type = ParseTypeInstance();
Dictionary<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
case ArrayType:
{
ExpectSymbol(Symbol.OpenParen);
var size = ExpectLiteral();
if (size.Type is not PrimitiveType { Kind: PrimitiveTypeKind.Int64 })
{
throw new Exception($"Array initializer size must be an {PrimitiveTypeKind.Int64}");
}
ExpectSymbol(Symbol.CloseParen);
return new ArrayInitializerNode(long.Parse(size.Value), type);
}
case StructType structType:
{
Dictionary<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
TryExpectSymbol(Symbol.Comma);
initializers.Add(name, value);
}
return new StructInitializerNode(structType, initializers);
}
default:
throw new Exception($"Type {type} cannot be initialized with the new keyword");
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:
default:
throw new Exception($"Unexpected token type {token.GetType().Name}");
}
}
@@ -448,13 +423,6 @@ public class Parser
return new StructMemberAccessorNode(members);
}
case Symbol.OpenBracket:
{
Next();
var index = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
return new ArrayIndexAccessNode(new IdentifierNode(identifier.Value), index);
}
case Symbol.OpenParen:
{
Next();
@@ -473,10 +441,11 @@ public class Parser
return new FuncCallExpressionNode(new FuncCall(identifier.Value, parameters));
}
}
break;
}
}
return new IdentifierNode(identifier.Value);
}
@@ -492,36 +461,22 @@ public class Parser
return new BlockNode(statements);
}
private Type ParseType()
private NubType ParseTypeInstance()
{
var parameters = new List<NubType>();
var name = ExpectIdentifier().Value;
switch (name)
if (TryExpectSymbol(Symbol.LessThan))
{
case "String":
do
{
return new StringType();
}
case "Array":
{
ExpectSymbol(Symbol.LessThan);
var innerType = ParseType();
ExpectSymbol(Symbol.GreaterThan);
return new ArrayType(innerType);
}
case "Any":
{
return new AnyType();
}
default:
{
if (PrimitiveType.TryParse(name, out var primitiveType))
{
return primitiveType;
}
return new StructType(name);
}
parameters.Add(ParseTypeInstance());
} while (TryExpectSymbol(Symbol.Comma));
ExpectSymbol(Symbol.GreaterThan);
}
return new NubType(name, parameters.ToArray());
}
private Token ExpectToken()

View File

@@ -1,7 +1,7 @@
namespace Nub.Lang.Frontend.Parsing;
public class StructInitializerNode(StructType structType, Dictionary<string, ExpressionNode> initializers) : ExpressionNode
public class StructInitializerNode(NubType structType, Dictionary<string, ExpressionNode> initializers) : ExpressionNode
{
public StructType StructType { get; } = structType;
public NubType StructType { get; } = structType;
public Dictionary<string, ExpressionNode> Initializers { get; } = initializers;
}

View File

@@ -2,12 +2,12 @@
namespace Nub.Lang.Frontend.Typing;
public class Func(string name, List<FuncParameter> parameters, Optional<BlockNode> body, Optional<Type> returnType)
public class Func(string name, List<FuncParameter> parameters, Optional<BlockNode> body, Optional<NubType> returnType)
{
public string Name { get; } = name;
public List<FuncParameter> Parameters { get; } = parameters;
public Optional<BlockNode> Body { get; } = body;
public Optional<Type> ReturnType { get; } = returnType;
public Optional<NubType> ReturnType { get; } = returnType;
}
public class ExpressionTyper
@@ -96,9 +96,6 @@ public class ExpressionTyper
{
switch (statement)
{
case ArrayIndexAssignmentNode arrayIndexAssignment:
PopulateArrayIndexAssignment(arrayIndexAssignment);
break;
case BreakNode:
case ContinueNode:
break;
@@ -128,13 +125,6 @@ public class ExpressionTyper
}
}
private void PopulateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment)
{
PopulateIdentifier(arrayIndexAssignment.Identifier);
PopulateExpression(arrayIndexAssignment.Index);
PopulateExpression(arrayIndexAssignment.Value);
}
private void PopulateFuncCallStatement(FuncCallStatementNode funcCall)
{
foreach (var parameter in funcCall.FuncCall.Parameters)
@@ -194,12 +184,6 @@ public class ExpressionTyper
{
switch (expression)
{
case ArrayIndexAccessNode arrayIndexAccess:
PopulateArrayIndexAccess(arrayIndexAccess);
break;
case ArrayInitializerNode arrayInitializer:
PopulateArrayInitializer(arrayInitializer);
break;
case BinaryExpressionNode binaryExpression:
PopulateBinaryExpression(binaryExpression);
break;
@@ -226,30 +210,6 @@ public class ExpressionTyper
}
}
private void PopulateArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess)
{
PopulateExpression(arrayIndexAccess.Index);
PopulateIdentifier(arrayIndexAccess.Identifier);
var variable = _variables.FirstOrDefault(v => v.Name == arrayIndexAccess.Identifier.Identifier);
if (variable == null)
{
throw new Exception($"Variable {arrayIndexAccess.Identifier} is not defined");
}
if (variable.Type is not ArrayType arrayType)
{
throw new Exception($"Variable {arrayIndexAccess.Identifier} is not an array type");
}
arrayIndexAccess.Type = arrayType.InnerType;
}
private void PopulateArrayInitializer(ArrayInitializerNode arrayInitializer)
{
arrayInitializer.Type = arrayInitializer.InnerType;
}
private void PopulateBinaryExpression(BinaryExpressionNode binaryExpression)
{
PopulateExpression(binaryExpression.Left);
@@ -263,7 +223,7 @@ public class ExpressionTyper
case BinaryExpressionOperator.LessThan:
case BinaryExpressionOperator.LessThanOrEqual:
{
binaryExpression.Type = new PrimitiveType(PrimitiveTypeKind.Bool);
binaryExpression.Type = new NubType("bool", []);
break;
}
case BinaryExpressionOperator.Plus:
@@ -333,13 +293,8 @@ public class ExpressionTyper
{
throw new Exception($"Variable {structMemberAccessor.Members[0]} is not defined");
}
if (variable.Type is not StructType variableType)
{
throw new Exception("Variable " + structMemberAccessor.Members[0] + " is not a struct");
}
var definition = _structDefinitions.FirstOrDefault(sd => sd.Name == variableType.Name);
var definition = _structDefinitions.FirstOrDefault(sd => sd.Name == variable.Type.Name);
if (definition == null)
{
throw new Exception($"Struct {structMemberAccessor.Members[0]} is not defined");
@@ -352,13 +307,8 @@ public class ExpressionTyper
{
throw new Exception($"Member {structMemberAccessor.Members[i]} does not exist on struct {definition.Name}");
}
if (member.Type is not StructType memberType)
{
throw new Exception($"Member {structMemberAccessor.Members[i]} on struct {definition.Name} is not a struct");
}
definition = _structDefinitions.FirstOrDefault(sd => sd.Name == memberType.Name);
definition = _structDefinitions.FirstOrDefault(sd => sd.Name == member.Type.Name);
if (definition == null)
{
throw new Exception($"Struct {structMemberAccessor.Members[i]} is not defined");
@@ -381,12 +331,12 @@ public class ExpressionTyper
PopulateExpression(parameter);
}
syscall.Type = new PrimitiveType(PrimitiveTypeKind.Int64);
syscall.Type = new NubType("int64", []);
}
private class Variable(string name, Type type)
private class Variable(string name, NubType type)
{
public string Name { get; } = name;
public Type Type { get; } = type;
public NubType Type { get; } = type;
}
}