This commit is contained in:
nub31
2025-07-05 18:08:59 +02:00
parent 5246e54ac9
commit e195731b9e
9 changed files with 413 additions and 296 deletions

View File

@@ -7,34 +7,45 @@ using UnaryExpressionNode = Syntax.Node.UnaryExpressionNode;
namespace Syntax.Binding;
// TODO: Currently anonymous function does not get a new scope
public static class Binder
public sealed class Binder
{
private static SyntaxTree _syntaxTree = null!;
private static DefinitionTable _definitionTable = null!;
private readonly SyntaxTree _syntaxTree;
private readonly DefinitionTable _definitionTable;
private static Dictionary<string, NubType> _variables = new();
private static NubType? _funcReturnType;
// TODO: Implement proper variable tracking and scoping
private Dictionary<string, NubType> _variables = new();
private NubType? _functionReturnType;
public static BoundSyntaxTree Bind(SyntaxTree syntaxTree, DefinitionTable definitionTable, out IEnumerable<Diagnostic> diagnostics)
public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable)
{
_syntaxTree = syntaxTree;
_definitionTable = definitionTable;
_variables = [];
_funcReturnType = null;
var definitions = new List<BoundTopLevelNode>();
foreach (var topLevel in syntaxTree.TopLevelNodes)
{
definitions.Add(BindTopLevel(topLevel));
}
diagnostics = [];
return new BoundSyntaxTree(syntaxTree.Namespace, definitions);
}
private static BoundTopLevelNode BindTopLevel(TopLevelNode node)
public BoundSyntaxTree Bind()
{
_variables = [];
_functionReturnType = null;
var diagnostics = new List<Diagnostic>();
var topLevelNodes = new List<BoundTopLevelNode>();
foreach (var topLevel in _syntaxTree.TopLevelNodes)
{
try
{
topLevelNodes.Add(BindTopLevel(topLevel));
}
catch (BindException e)
{
diagnostics.Add(e.Diagnostic);
}
}
return new BoundSyntaxTree(_syntaxTree.Namespace, topLevelNodes, diagnostics);
}
private BoundTopLevelNode BindTopLevel(TopLevelNode node)
{
return node switch
{
@@ -47,7 +58,7 @@ public static class Binder
};
}
private static BoundTraitImplNode BindTraitImplementation(TraitImplNode node)
private BoundTraitImplNode BindTraitImplementation(TraitImplNode node)
{
_variables.Clear();
var functions = new List<BoundTraitFuncImplNode>();
@@ -65,7 +76,7 @@ public static class Binder
return new BoundTraitImplNode(node.Tokens, node.Namespace, node.TraitType, node.ForType, functions);
}
private static BoundTraitNode BindTraitDefinition(TraitNode node)
private BoundTraitNode BindTraitDefinition(TraitNode node)
{
var functions = new List<BoundTraitFuncNode>();
@@ -77,46 +88,34 @@ public static class Binder
return new BoundTraitNode(node.Tokens, node.Namespace, node.Name, functions);
}
private static BoundStructNode BindStruct(StructNode node)
private BoundStructNode BindStruct(StructNode node)
{
var defOpt = _definitionTable.LookupStruct(node.Namespace, node.Name);
if (!defOpt.TryGetValue(out var definition))
{
throw new NotImplementedException("Diagnostics not implemented");
}
var structFields = new List<BoundStructFieldNode>();
foreach (var structField in node.Fields)
foreach (var field in node.Fields)
{
var value = Optional.Empty<BoundExpressionNode>();
if (structField.Value.HasValue)
if (field.Value.HasValue)
{
var definitionField = definition.Fields.FirstOrDefault(f => f.Name == structField.Name);
if (definitionField == null)
{
throw new NotImplementedException("Diagnostics not implemented");
}
value = BindExpression(structField.Value.Value, definitionField.Type);
value = BindExpression(field.Value.Value, field.Type);
}
structFields.Add(new BoundStructFieldNode(structField.Tokens, structField.Name, structField.Type, value));
structFields.Add(new BoundStructFieldNode(field.Tokens, field.Index, field.Name, field.Type, value));
}
return new BoundStructNode(node.Tokens, node.Namespace, node.Name, structFields);
}
private static BoundExternFuncNode BindExternFuncDefinition(ExternFuncNode node)
private BoundExternFuncNode BindExternFuncDefinition(ExternFuncNode node)
{
return new BoundExternFuncNode(node.Tokens, node.Namespace, node.Name, node.CallName, node.Parameters, node.ReturnType);
}
private static BoundLocalFuncNode BindLocalFuncDefinition(LocalFuncNode node)
private BoundLocalFuncNode BindLocalFuncDefinition(LocalFuncNode node)
{
_variables.Clear();
_funcReturnType = node.ReturnType;
_functionReturnType = node.ReturnType;
foreach (var parameter in node.Parameters)
{
@@ -128,7 +127,7 @@ public static class Binder
return new BoundLocalFuncNode(node.Tokens, node.Namespace, node.Name, node.Parameters, body, node.ReturnType, node.Exported);
}
private static BoundBlock BindBlock(BlockNode node)
private BoundBlock BindBlock(BlockNode node)
{
var statements = new List<BoundStatementNode>();
@@ -140,7 +139,7 @@ public static class Binder
return new BoundBlock(node.Tokens, statements);
}
private static BoundStatementNode BindStatement(StatementNode node)
private BoundStatementNode BindStatement(StatementNode node)
{
return node switch
{
@@ -156,24 +155,24 @@ public static class Binder
};
}
private static BoundStatementNode BindAssignment(AssignmentNode statement)
private BoundStatementNode BindAssignment(AssignmentNode statement)
{
var expression = BindExpression(statement.Expression);
var expression = BindExpression(statement.Target);
var value = BindExpression(statement.Value, expression.Type);
return new BoundAssignmentNode(statement.Tokens, expression, value);
}
private static BoundBreakNode BindBreak(BreakNode statement)
private BoundBreakNode BindBreak(BreakNode statement)
{
return new BoundBreakNode(statement.Tokens);
}
private static BoundContinueNode BindContinue(ContinueNode statement)
private BoundContinueNode BindContinue(ContinueNode statement)
{
return new BoundContinueNode(statement.Tokens);
}
private static BoundIfNode BindIf(IfNode statement)
private BoundIfNode BindIf(IfNode statement)
{
var elseStatement = Optional.Empty<Variant<BoundIfNode, BoundBlock>>();
@@ -189,24 +188,24 @@ public static class Binder
return new BoundIfNode(statement.Tokens, BindExpression(statement.Condition, NubPrimitiveType.Bool), BindBlock(statement.Body), elseStatement);
}
private static BoundReturnNode BindReturn(ReturnNode statement)
private BoundReturnNode BindReturn(ReturnNode statement)
{
var value = Optional.Empty<BoundExpressionNode>();
if (statement.Value.HasValue)
{
value = BindExpression(statement.Value.Value, _funcReturnType);
value = BindExpression(statement.Value.Value, _functionReturnType);
}
return new BoundReturnNode(statement.Tokens, value);
}
private static BoundStatementExpressionNode BindStatementExpression(StatementExpressionNode statement)
private BoundStatementExpressionNode BindStatementExpression(StatementExpressionNode statement)
{
return new BoundStatementExpressionNode(statement.Tokens, BindExpression(statement.Expression));
}
private static BoundVariableDeclarationNode BindVariableDeclaration(VariableDeclarationNode statement)
private BoundVariableDeclarationNode BindVariableDeclaration(VariableDeclarationNode statement)
{
NubType? type = null;
@@ -233,12 +232,12 @@ public static class Binder
return new BoundVariableDeclarationNode(statement.Tokens, statement.Name, statement.ExplicitType, assignment, type);
}
private static BoundWhileNode BindWhile(WhileNode statement)
private BoundWhileNode BindWhile(WhileNode statement)
{
return new BoundWhileNode(statement.Tokens, BindExpression(statement.Condition, NubPrimitiveType.Bool), BindBlock(statement.Body));
}
private static BoundExpressionNode BindExpression(ExpressionNode node, NubType? expectedType = null)
private BoundExpressionNode BindExpression(ExpressionNode node, NubType? expectedType = null)
{
return node switch
{
@@ -258,13 +257,13 @@ public static class Binder
};
}
private static BoundAddressOfNode BindAddressOf(AddressOfNode expression)
private BoundAddressOfNode BindAddressOf(AddressOfNode expression)
{
var inner = BindExpression(expression.Expression);
return new BoundAddressOfNode(expression.Tokens, new NubPointerType(inner.Type), inner);
}
private static BoundAnonymousFuncNode BindAnonymousFunc(AnonymousFuncNode expression)
private BoundAnonymousFuncNode BindAnonymousFunc(AnonymousFuncNode expression)
{
var parameterTypes = expression.Parameters.Select(x => x.Type).ToList();
@@ -273,33 +272,33 @@ public static class Binder
return new BoundAnonymousFuncNode(expression.Tokens, new NubFuncType(expression.ReturnType, parameterTypes), expression.Parameters, body, expression.ReturnType);
}
private static BoundArrayIndexAccessNode BindArrayIndexAccess(ArrayIndexAccessNode expression)
private BoundArrayIndexAccessNode BindArrayIndexAccess(ArrayIndexAccessNode expression)
{
var boundArray = BindExpression(expression.Array);
var elementType = ((NubArrayType)boundArray.Type).ElementType;
return new BoundArrayIndexAccessNode(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, NubPrimitiveType.U64));
}
private static BoundArrayInitializerNode BindArrayInitializer(ArrayInitializerNode expression)
private BoundArrayInitializerNode BindArrayInitializer(ArrayInitializerNode expression)
{
return new BoundArrayInitializerNode(expression.Tokens, new NubArrayType(expression.ElementType), BindExpression(expression.Capacity, NubPrimitiveType.U64), expression.ElementType);
}
private static BoundBinaryExpressionNode BindBinaryExpression(BinaryExpressionNode expression)
private BoundBinaryExpressionNode BindBinaryExpression(BinaryExpressionNode expression)
{
var boundLeft = BindExpression(expression.Left);
var boundRight = BindExpression(expression.Right, boundLeft.Type);
return new BoundBinaryExpressionNode(expression.Tokens, boundLeft.Type, boundLeft, expression.Operator, boundRight);
}
private static BoundDereferenceNode BindDereference(DereferenceNode expression)
private BoundDereferenceNode BindDereference(DereferenceNode expression)
{
var boundExpression = BindExpression(expression.Expression);
var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType;
return new BoundDereferenceNode(expression.Tokens, dereferencedType, boundExpression);
}
private static BoundFuncCallNode BindFuncCall(FuncCallNode expression)
private BoundFuncCallNode BindFuncCall(FuncCallNode expression)
{
var boundExpression = BindExpression(expression.Expression);
@@ -323,30 +322,45 @@ public static class Binder
return new BoundFuncCallNode(expression.Tokens, returnType, boundExpression, parameters);
}
private static BoundIdentifierNode BindIdentifier(IdentifierNode expression)
private BoundIdentifierNode BindIdentifier(IdentifierNode expression)
{
NubType? type = null;
var definition = _definitionTable.LookupFunction(expression.Namespace.Or(_syntaxTree.Namespace), expression.Name);
if (definition.HasValue)
var localFuncs = _definitionTable.LookupLocalFunc(expression.Namespace.Or(_syntaxTree.Namespace), expression.Name).ToArray();
if (localFuncs.Length > 0)
{
type = new NubFuncType(definition.Value.ReturnType, definition.Value.Parameters.Select(p => p.Type).ToList());
if (localFuncs.Length > 1)
{
throw new BindException(Diagnostic.Error($"Extern func {expression.Namespace}::{expression.Name} has multiple definitions").Build());
}
var localFunc = localFuncs[0];
var type = new NubFuncType(localFunc.ReturnType, localFunc.Parameters.Select(p => p.Type).ToList());
return new BoundIdentifierNode(expression.Tokens, type, expression.Namespace, expression.Name);
}
if (type == null && !expression.Namespace.HasValue)
var externFuncs = _definitionTable.LookupExternFunc(expression.Namespace.Or(_syntaxTree.Namespace), expression.Name).ToArray();
if (externFuncs.Length > 0)
{
type = _variables[expression.Name];
if (externFuncs.Length > 1)
{
throw new BindException(Diagnostic.Error($"Extern func {expression.Namespace}::{expression.Name} has multiple definitions").Build());
}
var externFunc = externFuncs[0];
var type = new NubFuncType(externFunc.ReturnType, externFunc.Parameters.Select(p => p.Type).ToList());
return new BoundIdentifierNode(expression.Tokens, type, expression.Namespace, expression.Name);
}
if (type == null)
if (!expression.Namespace.HasValue)
{
throw new NotImplementedException("Diagnostics not implemented");
return new BoundIdentifierNode(expression.Tokens, _variables[expression.Name], expression.Namespace, expression.Name);
}
return new BoundIdentifierNode(expression.Tokens, type, expression.Namespace, expression.Name);
throw new BindException(Diagnostic.Error($"No identifier with then name {(expression.Namespace.HasValue ? $"{expression.Namespace.Value}::" : "")}{expression.Name} exists").Build());
}
private static BoundLiteralNode BindLiteral(LiteralNode expression, NubType? expectedType = null)
private BoundLiteralNode BindLiteral(LiteralNode expression, NubType? expectedType = null)
{
var type = expectedType ?? expression.Kind switch
{
@@ -360,81 +374,129 @@ public static class Binder
return new BoundLiteralNode(expression.Tokens, type, expression.Literal, expression.Kind);
}
private static BoundMemberAccessNode BindMemberAccess(MemberAccessNode expression)
private BoundMemberAccessNode BindMemberAccess(MemberAccessNode expression)
{
var boundExpression = BindExpression(expression.Expression);
var implementation = _definitionTable.LookupTraitImplementationForType(boundExpression.Type, expression.Member);
if (implementation.HasValue)
var traitFuncImpls = _definitionTable.LookupTraitImpl(boundExpression.Type).SelectMany(x => _definitionTable.LookupTraitFuncImpl(x, expression.Member)).ToArray();
if (traitFuncImpls.Length > 0)
{
var type = new NubFuncType(implementation.Value.Item2.ReturnType, implementation.Value.Item2.Parameters.Select(p => p.Type).ToList());
if (traitFuncImpls.Length > 1)
{
throw new BindException(Diagnostic.Error($"Type {boundExpression.Type} implements multiple traits with the function {expression.Member}").Build());
}
var impl = traitFuncImpls[0];
var type = new NubFuncType(impl.ReturnType, impl.Parameters.Select(p => p.Type).ToList());
return new BoundMemberAccessNode(expression.Tokens, type, boundExpression, expression.Member);
}
if (boundExpression.Type is NubCustomType customType)
{
var function = _definitionTable.LookupFunctionOnTrait(customType.Namespace, customType.Name, expression.Member);
if (function.HasValue)
var traits = _definitionTable.LookupTrait(customType.Namespace, customType.Name).ToArray();
if (traits.Length > 0)
{
var type = new NubFuncType(function.Value.ReturnType, function.Value.Parameters.Select(p => p.Type).ToList());
return new BoundMemberAccessNode(expression.Tokens, type, boundExpression, expression.Member);
}
var structDef = _definitionTable.LookupStruct(customType.Namespace, customType.Name);
if (structDef.HasValue)
{
var matchingFields = structDef.Value.Fields.Where(f => f.Name == expression.Member).ToList();
if (matchingFields.Count > 1)
if (traits.Length > 1)
{
throw new NotImplementedException("Diagnostics not implemented");
throw new BindException(Diagnostic.Error($"Trait {customType.Namespace}::{customType.Name} has multiple definitions").Build());
}
if (matchingFields.Count == 1)
var trait = traits[0];
var traitFuncs = _definitionTable.LookupTraitFunc(trait, expression.Member).ToArray();
if (traits.Length > 0)
{
return new BoundMemberAccessNode(expression.Tokens, matchingFields[0].Type, boundExpression, expression.Member);
if (traits.Length > 1)
{
throw new BindException(Diagnostic.Error($"Trait {trait.Namespace}::{trait.Name} has multiple functions with the name {expression.Member}").Build());
}
var traitFunc = traitFuncs[0];
var type = new NubFuncType(traitFunc.ReturnType, traitFunc.Parameters.Select(p => p.Type).ToList());
return new BoundMemberAccessNode(expression.Tokens, type, boundExpression, expression.Member);
}
}
var structs = _definitionTable.LookupStruct(customType.Namespace, customType.Name).ToArray();
if (structs.Length > 0)
{
if (structs.Length > 1)
{
throw new BindException(Diagnostic.Error($"Struct {customType.Namespace}::{customType.Name} has multiple definitions").Build());
}
var @struct = structs[0];
var fields = _definitionTable.LookupStructField(@struct, customType.Name).ToArray();
if (fields.Length > 0)
{
if (fields.Length > 1)
{
throw new BindException(Diagnostic.Error($"Struct {@struct.Namespace}::{@struct.Name} has multiple fields with the name {expression.Member}").Build());
}
var field = fields[0];
return new BoundMemberAccessNode(expression.Tokens, field.Type, boundExpression, expression.Member);
}
}
}
if (boundExpression.Type is NubStringType or NubCStringType or NubArrayType && expression.Member == "count")
{
return new BoundMemberAccessNode(expression.Tokens, NubPrimitiveType.I64, boundExpression, expression.Member);
return new BoundMemberAccessNode(expression.Tokens, NubPrimitiveType.U64, boundExpression, expression.Member);
}
throw new NotImplementedException("Diagnostics not implemented");
throw new BindException(Diagnostic.Error($"{boundExpression.Type} has not member with the name {expression.Member}").Build());
}
private static BoundStructInitializerNode BindStructInitializer(StructInitializerNode expression)
private BoundStructInitializerNode BindStructInitializer(StructInitializerNode expression)
{
if (expression.StructType is not NubCustomType structType)
{
throw new NotImplementedException("Diagnostics not implemented");
throw new BindException(Diagnostic.Error($"Cannot initialize non-struct type {expression.StructType}").Build());
}
var defOpt = _definitionTable.LookupStruct(structType.Namespace, structType.Name);
if (!defOpt.TryGetValue(out var definition))
var structs = _definitionTable.LookupStruct(structType.Namespace, structType.Name).ToArray();
if (structs.Length == 0)
{
throw new NotImplementedException("Diagnostics not implemented");
throw new BindException(Diagnostic.Error($"Struct {structType.Namespace}::{structType.Name} is not defined").Build());
}
if (structs.Length > 1)
{
throw new BindException(Diagnostic.Error($"Struct {structType.Namespace}::{structType.Name} has multiple definitions").Build());
}
var @struct = structs[0];
var initializers = new Dictionary<string, BoundExpressionNode>();
foreach (var (member, initializer) in expression.Initializers)
foreach (var (field, initializer) in expression.Initializers)
{
var definitionField = definition.Fields.FirstOrDefault(x => x.Name == member);
if (definitionField == null)
var fields = _definitionTable.LookupStructField(@struct, field).ToArray();
if (fields.Length == 0)
{
throw new NotImplementedException("Diagnostics not implemented");
throw new BindException(Diagnostic.Error($"Struct {@struct.Namespace}::{@struct.Name} does not have a field with the name {field}").Build());
}
initializers[member] = BindExpression(initializer, definitionField.Type);
if (fields.Length > 1)
{
throw new BindException(Diagnostic.Error($"Struct {@struct.Namespace}::{@struct.Name} has multiple fields with the name {field}").Build());
}
initializers[field] = BindExpression(initializer, fields[0].Type);
}
return new BoundStructInitializerNode(expression.Tokens, structType, structType, initializers);
}
private static BoundUnaryExpressionNode BindUnaryExpression(UnaryExpressionNode expression)
private BoundUnaryExpressionNode BindUnaryExpression(UnaryExpressionNode expression)
{
var boundOperand = BindExpression(expression.Operand);
@@ -469,4 +531,14 @@ public static class Binder
return new BoundUnaryExpressionNode(expression.Tokens, type, expression.Operator, boundOperand);
}
}
public class BindException : Exception
{
public Diagnostic Diagnostic { get; }
public BindException(Diagnostic diagnostic) : base(diagnostic.Message)
{
Diagnostic = diagnostic;
}
}