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

@@ -2,7 +2,6 @@
using CLI;
using Generation.QBE;
using Syntax;
using Syntax.Binding;
using Syntax.Diagnostics;
using Syntax.Node;
using Syntax.Parsing;
@@ -83,13 +82,11 @@ foreach (var file in options.Files)
var tokenizeResult = Tokenizer.Tokenize(sourceText, out var tokenizerDiagnostics);
diagnostics.AddRange(tokenizerDiagnostics);
var syntaxTree = Parser.ParseFile(tokenizeResult, out var parseDiagnostics);
diagnostics.AddRange(parseDiagnostics);
var parser = new Parser(tokenizeResult);
var syntaxTree = parser.Parse();
diagnostics.AddRange(syntaxTree.Diagnostics);
if (syntaxTree != null)
{
syntaxTrees[file] = syntaxTree;
}
}
var definitionTable = new DefinitionTable(syntaxTrees.Values);
@@ -98,13 +95,12 @@ var boundSyntaxTrees = new Dictionary<string, BoundSyntaxTree>();
foreach (var (file, syntaxTree) in syntaxTrees)
{
var boundSyntaxTree = Binder.Bind(syntaxTree, definitionTable, out var binderDiagnostics);
diagnostics.AddRange(binderDiagnostics);
var binder = new Binder(syntaxTree, definitionTable);
var boundSyntaxTree = binder.Bind();
diagnostics.AddRange(boundSyntaxTree.Diagnostics);
boundSyntaxTrees[file] = boundSyntaxTree;
}
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values);
foreach (var diagnostic in diagnostics)
{
Console.Error.WriteLine(diagnostic.FormatANSI());
@@ -115,6 +111,8 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
return 1;
}
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values);
var objectFiles = new List<string>();
foreach (var file in options.Files)

View File

@@ -2,20 +2,25 @@
namespace Common;
public readonly struct Optional
public static class Optional
{
public static Optional<TValue> Empty<TValue>() => new();
/// <summary>
/// Alias for creating an Optional&lt;TValue&gt; which allows for implicit types
/// Alias for creating an Optional which allows for implicit types
/// </summary>
/// <param name="value"></param>
/// <typeparam name="TValue"></typeparam>
/// <returns></returns>
public static Optional<TValue> OfNullable<TValue>(TValue? value)
{
return value ?? Optional<TValue>.Empty();
}
/// <summary>
/// Converts a nullable type to an Optional
/// </summary>
public static Optional<TValue> ToOptional<TValue>(this TValue? value)
{
return OfNullable(value);
}
}
public readonly struct Optional<TValue>

View File

@@ -53,21 +53,21 @@ public static class QBEGenerator
_implFuncNameIndex = 0;
_codeIsReachable = true;
foreach (var structDef in _definitionTable.GetStructs())
{
EmitStructDefinition(structDef);
_writer.NewLine();
}
foreach (var trait in _definitionTable.GetTraits())
{
EmitTraitVTable(trait);
_writer.NewLine();
}
// foreach (var structDef in _definitionTable.GetStructs())
// {
// EmitStructDefinition(structDef);
// _writer.NewLine();
// }
//
// foreach (var trait in _definitionTable.GetTraits())
// {
// EmitTraitVTable(trait);
// _writer.NewLine();
// }
foreach (var funcDef in _syntaxTree.TopLevelNodes.OfType<BoundLocalFuncNode>())
{
EmitFuncDefinition(funcDef, FuncName(funcDef), funcDef.Parameters, funcDef.ReturnType, funcDef.Body, funcDef.Exported);
EmitFuncDefinition(funcDef, LocalFuncName(funcDef), funcDef.Parameters, funcDef.ReturnType, funcDef.Body, funcDef.Exported);
_writer.NewLine();
}
@@ -117,16 +117,14 @@ public static class QBEGenerator
return $"$string{++_stringLiteralIndex}";
}
private static string FuncName(BoundFuncDefinition funcDef)
private static string LocalFuncName(BoundLocalFuncNode funcDef)
{
return funcDef switch
return funcDef.Exported ? $"${funcDef.Name}" : $"${funcDef.Namespace}_{funcDef.Name}";
}
private static string ExternFuncName(BoundExternFuncNode funcDef)
{
BoundExternFuncNode externFuncDefinition => $"${externFuncDefinition.CallName}",
BoundLocalFuncNode localFuncDefinition => localFuncDefinition.Exported
? $"${localFuncDefinition.Name}"
: $"${localFuncDefinition.Namespace}_{localFuncDefinition.Name}",
_ => throw new ArgumentOutOfRangeException(nameof(funcDef))
};
return $"${funcDef.CallName}";
}
private static string ImplFuncName(BoundTraitImplNode implDef, string funcName)
@@ -586,65 +584,65 @@ public static class QBEGenerator
_writer.EndFunction();
}
private static void EmitStructDefinition(BoundStructNode structDef)
{
var structType = new NubCustomType(structDef.Namespace, structDef.Name);
_writer.WriteLine($"type {CustomTypeName(structType)} = {{ ");
var types = new Dictionary<string, string>();
foreach (var field in structDef.Fields)
{
types.Add(field.Name, StructDefQBEType(field));
}
var longest = types.Values.Max(x => x.Length);
foreach (var (name, type) in types)
{
var padding = longest - type.Length;
_writer.Indented($"{type},{new string(' ', padding)} # {name}");
}
_writer.WriteLine("}");
return;
string StructDefQBEType(BoundStructFieldNode field)
{
return field.Type switch
{
NubCustomType customType => CustomTypeName(customType),
NubComplexType => "l",
NubSimpleType simpleType => simpleType switch
{
NubPointerType or NubFuncType => "l",
NubPrimitiveType primitiveType => primitiveType.Kind switch
{
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "l",
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "w",
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => "h",
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => "b",
PrimitiveTypeKind.F64 => "d",
PrimitiveTypeKind.F32 => "s",
_ => throw new ArgumentOutOfRangeException()
},
_ => throw new NotSupportedException($"'{field.Type}' type cannot be used in structs")
},
_ => throw new UnreachableException()
};
}
}
private static void EmitTraitVTable(BoundTraitNode traitDef)
{
_writer.WriteLine($"type {CustomTypeName(new NubCustomType(traitDef.Namespace, traitDef.Name))} = {{");
foreach (var func in traitDef.Functions)
{
_writer.Indented($"l, # func {func.Name}({string.Join(", ", func.Parameters.Select(x => $"{x.Name}: {x.Type}"))}): {func.ReturnType}");
}
_writer.WriteLine("}");
}
// private static void EmitStructDefinition(BoundStructNode structDef)
// {
// var structType = new NubCustomType(structDef.Namespace, structDef.Name);
// _writer.WriteLine($"type {CustomTypeName(structType)} = {{ ");
//
// var types = new Dictionary<string, string>();
//
// foreach (var field in structDef.Fields)
// {
// types.Add(field.Name, StructDefQBEType(field));
// }
//
// var longest = types.Values.Max(x => x.Length);
// foreach (var (name, type) in types)
// {
// var padding = longest - type.Length;
// _writer.Indented($"{type},{new string(' ', padding)} # {name}");
// }
//
// _writer.WriteLine("}");
// return;
//
// string StructDefQBEType(BoundStructFieldNode field)
// {
// return field.Type switch
// {
// NubCustomType customType => CustomTypeName(customType),
// NubComplexType => "l",
// NubSimpleType simpleType => simpleType switch
// {
// NubPointerType or NubFuncType => "l",
// NubPrimitiveType primitiveType => primitiveType.Kind switch
// {
// PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "l",
// PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "w",
// PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => "h",
// PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => "b",
// PrimitiveTypeKind.F64 => "d",
// PrimitiveTypeKind.F32 => "s",
// _ => throw new ArgumentOutOfRangeException()
// },
// _ => throw new NotSupportedException($"'{field.Type}' type cannot be used in structs")
// },
// _ => throw new UnreachableException()
// };
// }
// }
//
// private static void EmitTraitVTable(BoundTraitNode traitDef)
// {
// _writer.WriteLine($"type {CustomTypeName(new NubCustomType(traitDef.Namespace, traitDef.Name))} = {{");
//
// foreach (var func in traitDef.Functions)
// {
// _writer.Indented($"l, # func {func.Name}({string.Join(", ", func.Parameters.Select(x => $"{x.Name}: {x.Type}"))}): {func.ReturnType}");
// }
//
// _writer.WriteLine("}");
// }
private static void EmitStatement(BoundStatementNode statement)
{
@@ -683,7 +681,7 @@ public static class QBEGenerator
private static void EmitAssignment(BoundAssignmentNode assignment)
{
var destination = EmitExpression(assignment.Expression);
var destination = EmitExpression(assignment.Target);
Debug.Assert(destination.Kind == ValKind.Pointer);
EmitCopyIntoOrInitialize(assignment.Value, destination.Name);
}

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)
public BoundSyntaxTree Bind()
{
definitions.Add(BindTopLevel(topLevel));
_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);
}
}
diagnostics = [];
return new BoundSyntaxTree(syntaxTree.Namespace, definitions);
return new BoundSyntaxTree(_syntaxTree.Namespace, topLevelNodes, diagnostics);
}
private static BoundTopLevelNode BindTopLevel(TopLevelNode node)
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(field.Value.Value, field.Type);
}
value = BindExpression(structField.Value.Value, definitionField.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());
}
if (type == null && !expression.Namespace.HasValue)
{
type = _variables[expression.Name];
}
if (type == null)
{
throw new NotImplementedException("Diagnostics not implemented");
}
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);
}
private static BoundLiteralNode BindLiteral(LiteralNode expression, NubType? expectedType = null)
var externFuncs = _definitionTable.LookupExternFunc(expression.Namespace.Or(_syntaxTree.Namespace), expression.Name).ToArray();
if (externFuncs.Length > 0)
{
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 (!expression.Namespace.HasValue)
{
return new BoundIdentifierNode(expression.Tokens, _variables[expression.Name], 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 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());
if (traits.Length > 1)
{
throw new BindException(Diagnostic.Error($"Trait {customType.Namespace}::{customType.Name} has multiple definitions").Build());
}
var trait = traits[0];
var traitFuncs = _definitionTable.LookupTraitFunc(trait, expression.Member).ToArray();
if (traits.Length > 0)
{
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 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)
{
throw new NotImplementedException("Diagnostics not implemented");
}
if (matchingFields.Count == 1)
var structs = _definitionTable.LookupStruct(customType.Namespace, customType.Name).ToArray();
if (structs.Length > 0)
{
return new BoundMemberAccessNode(expression.Tokens, matchingFields[0].Type, boundExpression, expression.Member);
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);
@@ -470,3 +532,13 @@ 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;
}
}

View File

@@ -2,7 +2,7 @@ using Syntax.Node;
namespace Syntax;
public class DefinitionTable
public sealed class DefinitionTable
{
private readonly List<TopLevelNode> _topLevelNodes;
@@ -10,14 +10,54 @@ public class DefinitionTable
{
_topLevelNodes = syntaxTrees.SelectMany(x => x.TopLevelNodes).ToList();
}
}
public class BoundDefinitionTable
{
private readonly List<BoundTopLevelNode> _topLevelNodes;
public BoundDefinitionTable(IEnumerable<BoundSyntaxTree> syntaxTrees)
public IEnumerable<LocalFuncNode> LookupLocalFunc(string @namespace, string name)
{
_topLevelNodes = syntaxTrees.SelectMany(x => x.TopLevelNodes).ToList();
return _topLevelNodes
.OfType<LocalFuncNode>()
.Where(x => x.Namespace == @namespace && x.Name == name);
}
public IEnumerable<ExternFuncNode> LookupExternFunc(string @namespace, string name)
{
return _topLevelNodes
.OfType<ExternFuncNode>()
.Where(x => x.Namespace == @namespace && x.Name == name);
}
public IEnumerable<StructNode> LookupStruct(string @namespace, string name)
{
return _topLevelNodes
.OfType<StructNode>()
.Where(x => x.Namespace == @namespace && x.Name == name);
}
public IEnumerable<StructFieldNode> LookupStructField(StructNode structNode, string field)
{
return structNode.Fields.Where(x => x.Name == field);
}
public IEnumerable<TraitImplNode> LookupTraitImpl(NubType itemType)
{
return _topLevelNodes
.OfType<TraitImplNode>()
.Where(x => x.TraitType == itemType);
}
public IEnumerable<TraitFuncImplNode> LookupTraitFuncImpl(TraitImplNode traitImpl, string name)
{
return traitImpl.Functions.Where(x => x.Name == name);
}
public IEnumerable<TraitNode> LookupTrait(string @namespace, string name)
{
return _topLevelNodes
.OfType<TraitNode>()
.Where(x => x.Namespace == @namespace && x.Name == name);
}
public IEnumerable<TraitFuncNode> LookupTraitFunc(TraitNode trait, string name)
{
return trait.Functions.Where(x => x.Name == name);
}
}

View File

@@ -17,10 +17,10 @@ public record BoundLocalFuncNode(IEnumerable<Token> Tokens, string Namespace, st
public record ExternFuncNode(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<FuncParameter> Parameters, NubType ReturnType) : TopLevelNode(Tokens, Namespace);
public record BoundExternFuncNode(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<FuncParameter> Parameters, NubType ReturnType) : BoundTopLevelNode(Tokens, Namespace);
public record StructFieldNode(IEnumerable<Token> Tokens, string Name, NubType Type, Optional<ExpressionNode> Value) : DefinitionNode(Tokens);
public record StructFieldNode(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<ExpressionNode> Value) : DefinitionNode(Tokens);
public record StructNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<StructFieldNode> Fields) : TopLevelNode(Tokens, Namespace);
public record BoundStructFieldNode(IEnumerable<Token> Tokens, string Name, NubType Type, Optional<BoundExpressionNode> Value) : BoundDefinitionNode(Tokens);
public record BoundStructFieldNode(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<BoundExpressionNode> Value) : BoundDefinitionNode(Tokens);
public record BoundStructNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundStructFieldNode> Fields) : BoundTopLevelNode(Tokens, Namespace);
public record TraitFuncNode(IEnumerable<Token> Tokens, string Name, List<FuncParameter> Parameters, NubType ReturnType) : DefinitionNode(Tokens);

View File

@@ -13,8 +13,8 @@ public record BoundStatementExpressionNode(IEnumerable<Token> Tokens, BoundExpre
public record ReturnNode(IEnumerable<Token> Tokens, Optional<ExpressionNode> Value) : StatementNode(Tokens);
public record BoundReturnNode(IEnumerable<Token> Tokens, Optional<BoundExpressionNode> Value) : BoundStatementNode(Tokens);
public record AssignmentNode(IEnumerable<Token> Tokens, ExpressionNode Expression, ExpressionNode Value) : StatementNode(Tokens);
public record BoundAssignmentNode(IEnumerable<Token> Tokens, BoundExpressionNode Expression, BoundExpressionNode Value) : BoundStatementNode(Tokens);
public record AssignmentNode(IEnumerable<Token> Tokens, ExpressionNode Target, ExpressionNode Value) : StatementNode(Tokens);
public record BoundAssignmentNode(IEnumerable<Token> Tokens, BoundExpressionNode Target, BoundExpressionNode Value) : BoundStatementNode(Tokens);
public record IfNode(IEnumerable<Token> Tokens, ExpressionNode Condition, BlockNode Body, Optional<Variant<IfNode, BlockNode>> Else) : StatementNode(Tokens);
public record BoundIfNode(IEnumerable<Token> Tokens, BoundExpressionNode Condition, BoundBlock Body, Optional<Variant<BoundIfNode, BoundBlock>> Else) : BoundStatementNode(Tokens);

View File

@@ -1,4 +1,6 @@
namespace Syntax.Node;
using Syntax.Diagnostics;
public record SyntaxTree(string Namespace, List<TopLevelNode> TopLevelNodes);
public record BoundSyntaxTree(string Namespace, List<BoundTopLevelNode> TopLevelNodes);
namespace Syntax.Node;
public record SyntaxTree(string Namespace, IEnumerable<TopLevelNode> TopLevelNodes, IEnumerable<Diagnostic> Diagnostics);
public record BoundSyntaxTree(string Namespace, IEnumerable<BoundTopLevelNode> TopLevelNodes, IEnumerable<Diagnostic> Diagnostics);

View File

@@ -6,53 +6,53 @@ using Syntax.Tokenization;
namespace Syntax.Parsing;
public static class Parser
public sealed class Parser
{
private static string _namespace = null!;
private static NubType? _functionReturnType;
private static List<Diagnostic> _diagnostics = [];
private static IEnumerable<Token> _tokens = [];
private static int _index;
private string _namespace;
private readonly IEnumerable<Token> _tokens;
public static SyntaxTree? ParseFile(IEnumerable<Token> tokens, out IEnumerable<Diagnostic> diagnostics)
private readonly List<Diagnostic> _diagnostics = [];
private NubType? _functionReturnType;
private int _tokenIndex;
public Parser(IEnumerable<Token> tokens)
{
_tokens = tokens;
_namespace = "global";
_diagnostics = [];
_index = 0;
_tokens = tokens;
}
public SyntaxTree Parse()
{
_diagnostics.Clear();
_functionReturnType = null;
_tokenIndex = 0;
if (TryExpectSymbol(Symbol.Namespace))
{
_namespace = ExpectIdentifier().Value;
}
try
{
List<TopLevelNode> definitions = [];
List<TopLevelNode> topLevelNodes = [];
while (Peek().HasValue)
{
var definition = ParseDefinition();
definitions.Add(definition);
}
diagnostics = _diagnostics;
return new SyntaxTree(_namespace, definitions);
try
{
topLevelNodes.Add(ParseTopLevel());
}
catch (ParseException ex)
{
_diagnostics.Add(ex.Diagnostic);
RecoverToNextDefinition();
}
diagnostics = _diagnostics;
return null;
}
private static TopLevelNode ParseDefinition()
return new SyntaxTree(_namespace, topLevelNodes, _diagnostics);
}
private TopLevelNode ParseTopLevel()
{
var startIndex = _index;
var startIndex = _tokenIndex;
List<ModifierToken> modifiers = [];
while (TryExpectModifier(out var modifier))
@@ -86,7 +86,7 @@ public static class Parser
return node;
}
private static TopLevelNode ParseFunc(int startIndex, List<ModifierToken> modifiers)
private TopLevelNode ParseFunc(int startIndex, List<ModifierToken> modifiers)
{
var name = ExpectIdentifier();
List<FuncParameter> parameters = [];
@@ -138,7 +138,7 @@ public static class Parser
return new LocalFuncNode(GetTokensForNode(startIndex), _namespace, name.Value, parameters, body, returnType, exported);
}
private static StructNode ParseStruct(int startIndex)
private StructNode ParseStruct(int startIndex)
{
var name = ExpectIdentifier().Value;
@@ -146,9 +146,11 @@ public static class Parser
List<StructFieldNode> variables = [];
var fieldIndex = 0;
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var fieldStartIndex = _index;
var fieldStartIndex = _tokenIndex;
var variableName = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Colon);
@@ -161,13 +163,13 @@ public static class Parser
variableValue = ParseExpression();
}
variables.Add(new StructFieldNode(GetTokensForNode(fieldStartIndex), variableName, variableType, variableValue));
variables.Add(new StructFieldNode(GetTokensForNode(fieldStartIndex), fieldIndex++, variableName, variableType, variableValue));
}
return new StructNode(GetTokensForNode(startIndex), _namespace, name, variables);
}
private static TraitNode ParseTrait(int startIndex)
private TraitNode ParseTrait(int startIndex)
{
var name = ExpectIdentifier().Value;
@@ -177,7 +179,7 @@ public static class Parser
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var funcStartIndex = _index;
var funcStartIndex = _tokenIndex;
ExpectSymbol(Symbol.Func);
@@ -207,7 +209,7 @@ public static class Parser
return new TraitNode(GetTokensForNode(startIndex), _namespace, name, functions);
}
private static TraitImplNode ParseImplementation(int startIndex)
private TraitImplNode ParseImplementation(int startIndex)
{
var traitType = ParseType();
ExpectSymbol(Symbol.For);
@@ -218,7 +220,7 @@ public static class Parser
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var funcStartIndex = _index;
var funcStartIndex = _tokenIndex;
ExpectSymbol(Symbol.Func);
var functionName = ExpectIdentifier().Value;
var parameters = new List<FuncParameter>
@@ -252,7 +254,7 @@ public static class Parser
return new TraitImplNode(GetTokensForNode(startIndex), _namespace, traitType, forType, functions);
}
private static FuncParameter ParseFuncParameter()
private FuncParameter ParseFuncParameter()
{
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon);
@@ -261,9 +263,9 @@ public static class Parser
return new FuncParameter(name.Value, type);
}
private static StatementNode ParseStatement()
private StatementNode ParseStatement()
{
var startIndex = _index;
var startIndex = _tokenIndex;
if (!Peek().TryGetValue(out var token))
{
throw new ParseException(Diagnostic
@@ -294,7 +296,7 @@ public static class Parser
return ParseStatementExpression(startIndex);
}
private static StatementNode ParseStatementExpression(int startIndex)
private StatementNode ParseStatementExpression(int startIndex)
{
var expr = ParseExpression();
@@ -307,7 +309,7 @@ public static class Parser
return new StatementExpressionNode(GetTokensForNode(startIndex), expr);
}
private static VariableDeclarationNode ParseVariableDeclaration(int startIndex)
private VariableDeclarationNode ParseVariableDeclaration(int startIndex)
{
ExpectSymbol(Symbol.Let);
var name = ExpectIdentifier().Value;
@@ -327,20 +329,20 @@ public static class Parser
return new VariableDeclarationNode(GetTokensForNode(startIndex), name, explicitType, assignment);
}
private static StatementNode ParseBreak(int startIndex)
private StatementNode ParseBreak(int startIndex)
{
ExpectSymbol(Symbol.Break);
Next();
return new BreakNode(GetTokensForNode(startIndex));
}
private static StatementNode ParseContinue(int startIndex)
private StatementNode ParseContinue(int startIndex)
{
ExpectSymbol(Symbol.Continue);
return new ContinueNode(GetTokensForNode(startIndex));
}
private static ReturnNode ParseReturn(int startIndex)
private ReturnNode ParseReturn(int startIndex)
{
ExpectSymbol(Symbol.Return);
@@ -353,7 +355,7 @@ public static class Parser
return new ReturnNode(GetTokensForNode(startIndex), value);
}
private static IfNode ParseIf(int startIndex)
private IfNode ParseIf(int startIndex)
{
ExpectSymbol(Symbol.If);
var condition = ParseExpression();
@@ -362,7 +364,7 @@ public static class Parser
var elseStatement = Optional<Variant<IfNode, BlockNode>>.Empty();
if (TryExpectSymbol(Symbol.Else))
{
var newStartIndex = _index;
var newStartIndex = _tokenIndex;
elseStatement = TryExpectSymbol(Symbol.If)
? (Variant<IfNode, BlockNode>)ParseIf(newStartIndex)
: (Variant<IfNode, BlockNode>)ParseBlock();
@@ -371,7 +373,7 @@ public static class Parser
return new IfNode(GetTokensForNode(startIndex), condition, body, elseStatement);
}
private static WhileNode ParseWhile(int startIndex)
private WhileNode ParseWhile(int startIndex)
{
ExpectSymbol(Symbol.While);
var condition = ParseExpression();
@@ -379,9 +381,9 @@ public static class Parser
return new WhileNode(GetTokensForNode(startIndex), condition, body);
}
private static ExpressionNode ParseExpression(int precedence = 0)
private ExpressionNode ParseExpression(int precedence = 0)
{
var startIndex = _index;
var startIndex = _tokenIndex;
var left = ParsePrimaryExpression();
while (true)
@@ -402,7 +404,7 @@ public static class Parser
return left;
}
private static int GetBinaryOperatorPrecedence(BinaryExpressionOperator binaryExpressionOperator)
private int GetBinaryOperatorPrecedence(BinaryExpressionOperator binaryExpressionOperator)
{
return binaryExpressionOperator switch
{
@@ -420,7 +422,7 @@ public static class Parser
};
}
private static bool TryGetBinaryOperator(Symbol symbol, [NotNullWhen(true)] out BinaryExpressionOperator? binaryExpressionOperator)
private bool TryGetBinaryOperator(Symbol symbol, [NotNullWhen(true)] out BinaryExpressionOperator? binaryExpressionOperator)
{
switch (symbol)
{
@@ -460,9 +462,9 @@ public static class Parser
}
}
private static ExpressionNode ParsePrimaryExpression()
private ExpressionNode ParsePrimaryExpression()
{
var startIndex = _index;
var startIndex = _tokenIndex;
ExpressionNode expr;
var token = ExpectToken();
@@ -583,7 +585,7 @@ public static class Parser
return ParsePostfixOperators(startIndex, expr);
}
private static ExpressionNode ParsePostfixOperators(int startIndex, ExpressionNode expr)
private ExpressionNode ParsePostfixOperators(int startIndex, ExpressionNode expr)
{
while (true)
{
@@ -640,9 +642,9 @@ public static class Parser
return expr;
}
private static BlockNode ParseBlock()
private BlockNode ParseBlock()
{
var startIndex = _index;
var startIndex = _tokenIndex;
ExpectSymbol(Symbol.OpenBrace);
List<StatementNode> statements = [];
while (Peek().HasValue && !TryExpectSymbol(Symbol.CloseBrace))
@@ -661,7 +663,7 @@ public static class Parser
return new BlockNode(GetTokensForNode(startIndex), statements);
}
private static NubType ParseType()
private NubType ParseType()
{
if (TryExpectIdentifier(out var name))
{
@@ -746,7 +748,7 @@ public static class Parser
.Build());
}
private static Token ExpectToken()
private Token ExpectToken()
{
if (!Peek().TryGetValue(out var token))
{
@@ -761,7 +763,7 @@ public static class Parser
return token;
}
private static SymbolToken ExpectSymbol()
private SymbolToken ExpectSymbol()
{
var token = ExpectToken();
if (token is not SymbolToken symbol)
@@ -776,7 +778,7 @@ public static class Parser
return symbol;
}
private static void ExpectSymbol(Symbol expectedSymbol)
private void ExpectSymbol(Symbol expectedSymbol)
{
var token = ExpectSymbol();
if (token.Symbol != expectedSymbol)
@@ -789,7 +791,7 @@ public static class Parser
}
}
private static bool TryExpectSymbol(Symbol symbol)
private bool TryExpectSymbol(Symbol symbol)
{
if (Peek() is { Value: SymbolToken symbolToken } && symbolToken.Symbol == symbol)
{
@@ -800,7 +802,7 @@ public static class Parser
return false;
}
private static bool TryExpectModifier([NotNullWhen(true)] out ModifierToken? modifier)
private bool TryExpectModifier([NotNullWhen(true)] out ModifierToken? modifier)
{
if (Peek() is { Value: ModifierToken modifierToken })
{
@@ -813,7 +815,7 @@ public static class Parser
return false;
}
private static bool TryExpectIdentifier([NotNullWhen(true)] out IdentifierToken? identifier)
private bool TryExpectIdentifier([NotNullWhen(true)] out IdentifierToken? identifier)
{
if (Peek() is { Value: IdentifierToken identifierToken })
{
@@ -826,7 +828,7 @@ public static class Parser
return false;
}
private static IdentifierToken ExpectIdentifier()
private IdentifierToken ExpectIdentifier()
{
var token = ExpectToken();
if (token is not IdentifierToken identifier)
@@ -841,12 +843,12 @@ public static class Parser
return identifier;
}
private static void RecoverToNextDefinition()
private void RecoverToNextDefinition()
{
while (Peek().HasValue)
{
var token = Peek().Value;
if (token is SymbolToken { Symbol: Symbol.Func or Symbol.Struct } or ModifierToken)
if (token is SymbolToken { Symbol: Symbol.Func or Symbol.Struct or Symbol.Trait or Symbol.Impl } or ModifierToken)
{
break;
}
@@ -855,7 +857,7 @@ public static class Parser
}
}
private static void RecoverToNextStatement()
private void RecoverToNextStatement()
{
while (Peek().TryGetValue(out var token))
{
@@ -871,9 +873,9 @@ public static class Parser
}
}
private static Optional<Token> Peek(int offset = 0)
private Optional<Token> Peek(int offset = 0)
{
var peekIndex = _index + offset;
var peekIndex = _tokenIndex + offset;
if (peekIndex < _tokens.Count())
{
return _tokens.ElementAt(peekIndex);
@@ -882,14 +884,14 @@ public static class Parser
return Optional<Token>.Empty();
}
private static void Next()
private void Next()
{
_index++;
_tokenIndex++;
}
private static IEnumerable<Token> GetTokensForNode(int startIndex)
private IEnumerable<Token> GetTokensForNode(int startIndex)
{
return _tokens.Skip(startIndex).Take(Math.Min(_index, _tokens.Count() - 1) - startIndex);
return _tokens.Skip(startIndex).Take(Math.Min(_tokenIndex, _tokens.Count() - 1) - startIndex);
}
}