...
This commit is contained in:
@@ -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;
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -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<TValue> 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>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
BoundExternFuncNode externFuncDefinition => $"${externFuncDefinition.CallName}",
|
||||
BoundLocalFuncNode localFuncDefinition => localFuncDefinition.Exported
|
||||
? $"${localFuncDefinition.Name}"
|
||||
: $"${localFuncDefinition.Namespace}_{localFuncDefinition.Name}",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(funcDef))
|
||||
};
|
||||
return funcDef.Exported ? $"${funcDef.Name}" : $"${funcDef.Namespace}_{funcDef.Name}";
|
||||
}
|
||||
|
||||
private static string ExternFuncName(BoundExternFuncNode 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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
while (Peek().HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var definition = ParseDefinition();
|
||||
definitions.Add(definition);
|
||||
topLevelNodes.Add(ParseTopLevel());
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
_diagnostics.Add(ex.Diagnostic);
|
||||
RecoverToNextDefinition();
|
||||
}
|
||||
|
||||
diagnostics = _diagnostics;
|
||||
return new SyntaxTree(_namespace, definitions);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
_diagnostics.Add(ex.Diagnostic);
|
||||
RecoverToNextDefinition();
|
||||
}
|
||||
|
||||
diagnostics = _diagnostics;
|
||||
return null;
|
||||
return new SyntaxTree(_namespace, topLevelNodes, _diagnostics);
|
||||
}
|
||||
|
||||
private static TopLevelNode ParseDefinition()
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user