...
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
using CLI;
|
using CLI;
|
||||||
using Generation.QBE;
|
using Generation.QBE;
|
||||||
using Syntax;
|
using Syntax;
|
||||||
using Syntax.Binding;
|
|
||||||
using Syntax.Diagnostics;
|
using Syntax.Diagnostics;
|
||||||
using Syntax.Node;
|
using Syntax.Node;
|
||||||
using Syntax.Parsing;
|
using Syntax.Parsing;
|
||||||
@@ -83,13 +82,11 @@ foreach (var file in options.Files)
|
|||||||
var tokenizeResult = Tokenizer.Tokenize(sourceText, out var tokenizerDiagnostics);
|
var tokenizeResult = Tokenizer.Tokenize(sourceText, out var tokenizerDiagnostics);
|
||||||
diagnostics.AddRange(tokenizerDiagnostics);
|
diagnostics.AddRange(tokenizerDiagnostics);
|
||||||
|
|
||||||
var syntaxTree = Parser.ParseFile(tokenizeResult, out var parseDiagnostics);
|
var parser = new Parser(tokenizeResult);
|
||||||
diagnostics.AddRange(parseDiagnostics);
|
var syntaxTree = parser.Parse();
|
||||||
|
diagnostics.AddRange(syntaxTree.Diagnostics);
|
||||||
|
|
||||||
if (syntaxTree != null)
|
syntaxTrees[file] = syntaxTree;
|
||||||
{
|
|
||||||
syntaxTrees[file] = syntaxTree;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var definitionTable = new DefinitionTable(syntaxTrees.Values);
|
var definitionTable = new DefinitionTable(syntaxTrees.Values);
|
||||||
@@ -98,13 +95,12 @@ var boundSyntaxTrees = new Dictionary<string, BoundSyntaxTree>();
|
|||||||
|
|
||||||
foreach (var (file, syntaxTree) in syntaxTrees)
|
foreach (var (file, syntaxTree) in syntaxTrees)
|
||||||
{
|
{
|
||||||
var boundSyntaxTree = Binder.Bind(syntaxTree, definitionTable, out var binderDiagnostics);
|
var binder = new Binder(syntaxTree, definitionTable);
|
||||||
diagnostics.AddRange(binderDiagnostics);
|
var boundSyntaxTree = binder.Bind();
|
||||||
|
diagnostics.AddRange(boundSyntaxTree.Diagnostics);
|
||||||
boundSyntaxTrees[file] = boundSyntaxTree;
|
boundSyntaxTrees[file] = boundSyntaxTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values);
|
|
||||||
|
|
||||||
foreach (var diagnostic in diagnostics)
|
foreach (var diagnostic in diagnostics)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(diagnostic.FormatANSI());
|
Console.Error.WriteLine(diagnostic.FormatANSI());
|
||||||
@@ -115,6 +111,8 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values);
|
||||||
|
|
||||||
var objectFiles = new List<string>();
|
var objectFiles = new List<string>();
|
||||||
|
|
||||||
foreach (var file in options.Files)
|
foreach (var file in options.Files)
|
||||||
@@ -124,7 +122,7 @@ foreach (var file in options.Files)
|
|||||||
var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable, file);
|
var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable, file);
|
||||||
// File.WriteAllText(Path.Join(INT_DEBUG_DIR, $"{outFileName}.ssa"), ssa);
|
// File.WriteAllText(Path.Join(INT_DEBUG_DIR, $"{outFileName}.ssa"), ssa);
|
||||||
File.WriteAllText(Path.Join(INT_DEBUG_DIR, $"{Path.GetFileNameWithoutExtension(file)}.ssa"), ssa);
|
File.WriteAllText(Path.Join(INT_DEBUG_DIR, $"{Path.GetFileNameWithoutExtension(file)}.ssa"), ssa);
|
||||||
|
|
||||||
var asm = await QBE.Invoke(ssa);
|
var asm = await QBE.Invoke(ssa);
|
||||||
if (asm == null)
|
if (asm == null)
|
||||||
{
|
{
|
||||||
@@ -162,7 +160,7 @@ else
|
|||||||
Console.Error.WriteLine($"file '{options.CustomRuntime}' does not exist'");
|
Console.Error.WriteLine($"file '{options.CustomRuntime}' does not exist'");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
objectFiles.Add(options.CustomRuntime);
|
objectFiles.Add(options.CustomRuntime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +193,7 @@ async Task<string> CreateBuiltinRuntime()
|
|||||||
var runtime = resources.First(r => r.EndsWith(RUNTIME_NAME));
|
var runtime = resources.First(r => r.EndsWith(RUNTIME_NAME));
|
||||||
|
|
||||||
await using var reader = Assembly.GetExecutingAssembly().GetManifestResourceStream(runtime);
|
await using var reader = Assembly.GetExecutingAssembly().GetManifestResourceStream(runtime);
|
||||||
|
|
||||||
if (reader == null)
|
if (reader == null)
|
||||||
{
|
{
|
||||||
throw new RuntimeCreationException($"Cannot open stream to '{RUNTIME_NAME}'");
|
throw new RuntimeCreationException($"Cannot open stream to '{RUNTIME_NAME}'");
|
||||||
@@ -205,7 +203,7 @@ async Task<string> CreateBuiltinRuntime()
|
|||||||
await using var writer = new FileStream(runtimePath, FileMode.Create);
|
await using var writer = new FileStream(runtimePath, FileMode.Create);
|
||||||
|
|
||||||
reader.CopyTo(writer);
|
reader.CopyTo(writer);
|
||||||
|
|
||||||
return runtimePath;
|
return runtimePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,20 +2,25 @@
|
|||||||
|
|
||||||
namespace Common;
|
namespace Common;
|
||||||
|
|
||||||
public readonly struct Optional
|
public static class Optional
|
||||||
{
|
{
|
||||||
public static Optional<TValue> Empty<TValue>() => new();
|
public static Optional<TValue> Empty<TValue>() => new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Alias for creating an Optional<TValue> which allows for implicit types
|
/// Alias for creating an Optional which allows for implicit types
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <typeparam name="TValue"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Optional<TValue> OfNullable<TValue>(TValue? value)
|
public static Optional<TValue> OfNullable<TValue>(TValue? value)
|
||||||
{
|
{
|
||||||
return value ?? Optional<TValue>.Empty();
|
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>
|
public readonly struct Optional<TValue>
|
||||||
|
|||||||
@@ -53,21 +53,21 @@ public static class QBEGenerator
|
|||||||
_implFuncNameIndex = 0;
|
_implFuncNameIndex = 0;
|
||||||
_codeIsReachable = true;
|
_codeIsReachable = true;
|
||||||
|
|
||||||
foreach (var structDef in _definitionTable.GetStructs())
|
// foreach (var structDef in _definitionTable.GetStructs())
|
||||||
{
|
// {
|
||||||
EmitStructDefinition(structDef);
|
// EmitStructDefinition(structDef);
|
||||||
_writer.NewLine();
|
// _writer.NewLine();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
foreach (var trait in _definitionTable.GetTraits())
|
// foreach (var trait in _definitionTable.GetTraits())
|
||||||
{
|
// {
|
||||||
EmitTraitVTable(trait);
|
// EmitTraitVTable(trait);
|
||||||
_writer.NewLine();
|
// _writer.NewLine();
|
||||||
}
|
// }
|
||||||
|
|
||||||
foreach (var funcDef in _syntaxTree.TopLevelNodes.OfType<BoundLocalFuncNode>())
|
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();
|
_writer.NewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,16 +117,14 @@ public static class QBEGenerator
|
|||||||
return $"$string{++_stringLiteralIndex}";
|
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}";
|
||||||
{
|
}
|
||||||
BoundExternFuncNode externFuncDefinition => $"${externFuncDefinition.CallName}",
|
|
||||||
BoundLocalFuncNode localFuncDefinition => localFuncDefinition.Exported
|
private static string ExternFuncName(BoundExternFuncNode funcDef)
|
||||||
? $"${localFuncDefinition.Name}"
|
{
|
||||||
: $"${localFuncDefinition.Namespace}_{localFuncDefinition.Name}",
|
return $"${funcDef.CallName}";
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(funcDef))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ImplFuncName(BoundTraitImplNode implDef, string funcName)
|
private static string ImplFuncName(BoundTraitImplNode implDef, string funcName)
|
||||||
@@ -586,65 +584,65 @@ public static class QBEGenerator
|
|||||||
_writer.EndFunction();
|
_writer.EndFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitStructDefinition(BoundStructNode structDef)
|
// private static void EmitStructDefinition(BoundStructNode structDef)
|
||||||
{
|
// {
|
||||||
var structType = new NubCustomType(structDef.Namespace, structDef.Name);
|
// var structType = new NubCustomType(structDef.Namespace, structDef.Name);
|
||||||
_writer.WriteLine($"type {CustomTypeName(structType)} = {{ ");
|
// _writer.WriteLine($"type {CustomTypeName(structType)} = {{ ");
|
||||||
|
//
|
||||||
var types = new Dictionary<string, string>();
|
// var types = new Dictionary<string, string>();
|
||||||
|
//
|
||||||
foreach (var field in structDef.Fields)
|
// foreach (var field in structDef.Fields)
|
||||||
{
|
// {
|
||||||
types.Add(field.Name, StructDefQBEType(field));
|
// types.Add(field.Name, StructDefQBEType(field));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
var longest = types.Values.Max(x => x.Length);
|
// var longest = types.Values.Max(x => x.Length);
|
||||||
foreach (var (name, type) in types)
|
// foreach (var (name, type) in types)
|
||||||
{
|
// {
|
||||||
var padding = longest - type.Length;
|
// var padding = longest - type.Length;
|
||||||
_writer.Indented($"{type},{new string(' ', padding)} # {name}");
|
// _writer.Indented($"{type},{new string(' ', padding)} # {name}");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
_writer.WriteLine("}");
|
// _writer.WriteLine("}");
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
string StructDefQBEType(BoundStructFieldNode field)
|
// string StructDefQBEType(BoundStructFieldNode field)
|
||||||
{
|
// {
|
||||||
return field.Type switch
|
// return field.Type switch
|
||||||
{
|
// {
|
||||||
NubCustomType customType => CustomTypeName(customType),
|
// NubCustomType customType => CustomTypeName(customType),
|
||||||
NubComplexType => "l",
|
// NubComplexType => "l",
|
||||||
NubSimpleType simpleType => simpleType switch
|
// NubSimpleType simpleType => simpleType switch
|
||||||
{
|
// {
|
||||||
NubPointerType or NubFuncType => "l",
|
// NubPointerType or NubFuncType => "l",
|
||||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
// NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||||
{
|
// {
|
||||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "l",
|
// PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "l",
|
||||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "w",
|
// PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "w",
|
||||||
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => "h",
|
// PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => "h",
|
||||||
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => "b",
|
// PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => "b",
|
||||||
PrimitiveTypeKind.F64 => "d",
|
// PrimitiveTypeKind.F64 => "d",
|
||||||
PrimitiveTypeKind.F32 => "s",
|
// PrimitiveTypeKind.F32 => "s",
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
// _ => throw new ArgumentOutOfRangeException()
|
||||||
},
|
// },
|
||||||
_ => throw new NotSupportedException($"'{field.Type}' type cannot be used in structs")
|
// _ => throw new NotSupportedException($"'{field.Type}' type cannot be used in structs")
|
||||||
},
|
// },
|
||||||
_ => throw new UnreachableException()
|
// _ => throw new UnreachableException()
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static void EmitTraitVTable(BoundTraitNode traitDef)
|
// private static void EmitTraitVTable(BoundTraitNode traitDef)
|
||||||
{
|
// {
|
||||||
_writer.WriteLine($"type {CustomTypeName(new NubCustomType(traitDef.Namespace, traitDef.Name))} = {{");
|
// _writer.WriteLine($"type {CustomTypeName(new NubCustomType(traitDef.Namespace, traitDef.Name))} = {{");
|
||||||
|
//
|
||||||
foreach (var func in traitDef.Functions)
|
// 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.Indented($"l, # func {func.Name}({string.Join(", ", func.Parameters.Select(x => $"{x.Name}: {x.Type}"))}): {func.ReturnType}");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
_writer.WriteLine("}");
|
// _writer.WriteLine("}");
|
||||||
}
|
// }
|
||||||
|
|
||||||
private static void EmitStatement(BoundStatementNode statement)
|
private static void EmitStatement(BoundStatementNode statement)
|
||||||
{
|
{
|
||||||
@@ -683,7 +681,7 @@ public static class QBEGenerator
|
|||||||
|
|
||||||
private static void EmitAssignment(BoundAssignmentNode assignment)
|
private static void EmitAssignment(BoundAssignmentNode assignment)
|
||||||
{
|
{
|
||||||
var destination = EmitExpression(assignment.Expression);
|
var destination = EmitExpression(assignment.Target);
|
||||||
Debug.Assert(destination.Kind == ValKind.Pointer);
|
Debug.Assert(destination.Kind == ValKind.Pointer);
|
||||||
EmitCopyIntoOrInitialize(assignment.Value, destination.Name);
|
EmitCopyIntoOrInitialize(assignment.Value, destination.Name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,34 +7,45 @@ using UnaryExpressionNode = Syntax.Node.UnaryExpressionNode;
|
|||||||
namespace Syntax.Binding;
|
namespace Syntax.Binding;
|
||||||
|
|
||||||
// TODO: Currently anonymous function does not get a new scope
|
// TODO: Currently anonymous function does not get a new scope
|
||||||
public static class Binder
|
public sealed class Binder
|
||||||
{
|
{
|
||||||
private static SyntaxTree _syntaxTree = null!;
|
private readonly SyntaxTree _syntaxTree;
|
||||||
private static DefinitionTable _definitionTable = null!;
|
private readonly DefinitionTable _definitionTable;
|
||||||
|
|
||||||
private static Dictionary<string, NubType> _variables = new();
|
// TODO: Implement proper variable tracking and scoping
|
||||||
private static NubType? _funcReturnType;
|
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;
|
_syntaxTree = syntaxTree;
|
||||||
_definitionTable = definitionTable;
|
_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
|
return node switch
|
||||||
{
|
{
|
||||||
@@ -47,7 +58,7 @@ public static class Binder
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundTraitImplNode BindTraitImplementation(TraitImplNode node)
|
private BoundTraitImplNode BindTraitImplementation(TraitImplNode node)
|
||||||
{
|
{
|
||||||
_variables.Clear();
|
_variables.Clear();
|
||||||
var functions = new List<BoundTraitFuncImplNode>();
|
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);
|
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>();
|
var functions = new List<BoundTraitFuncNode>();
|
||||||
|
|
||||||
@@ -77,46 +88,34 @@ public static class Binder
|
|||||||
return new BoundTraitNode(node.Tokens, node.Namespace, node.Name, functions);
|
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>();
|
var structFields = new List<BoundStructFieldNode>();
|
||||||
|
|
||||||
foreach (var structField in node.Fields)
|
foreach (var field in node.Fields)
|
||||||
{
|
{
|
||||||
var value = Optional.Empty<BoundExpressionNode>();
|
var value = Optional.Empty<BoundExpressionNode>();
|
||||||
|
|
||||||
if (structField.Value.HasValue)
|
if (field.Value.HasValue)
|
||||||
{
|
{
|
||||||
var definitionField = definition.Fields.FirstOrDefault(f => f.Name == structField.Name);
|
value = BindExpression(field.Value.Value, field.Type);
|
||||||
if (definitionField == null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("Diagnostics not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
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);
|
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();
|
_variables.Clear();
|
||||||
_funcReturnType = node.ReturnType;
|
_functionReturnType = node.ReturnType;
|
||||||
|
|
||||||
foreach (var parameter in node.Parameters)
|
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);
|
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>();
|
var statements = new List<BoundStatementNode>();
|
||||||
|
|
||||||
@@ -140,7 +139,7 @@ public static class Binder
|
|||||||
return new BoundBlock(node.Tokens, statements);
|
return new BoundBlock(node.Tokens, statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundStatementNode BindStatement(StatementNode node)
|
private BoundStatementNode BindStatement(StatementNode node)
|
||||||
{
|
{
|
||||||
return node switch
|
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);
|
var value = BindExpression(statement.Value, expression.Type);
|
||||||
return new BoundAssignmentNode(statement.Tokens, expression, value);
|
return new BoundAssignmentNode(statement.Tokens, expression, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundBreakNode BindBreak(BreakNode statement)
|
private BoundBreakNode BindBreak(BreakNode statement)
|
||||||
{
|
{
|
||||||
return new BoundBreakNode(statement.Tokens);
|
return new BoundBreakNode(statement.Tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundContinueNode BindContinue(ContinueNode statement)
|
private BoundContinueNode BindContinue(ContinueNode statement)
|
||||||
{
|
{
|
||||||
return new BoundContinueNode(statement.Tokens);
|
return new BoundContinueNode(statement.Tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundIfNode BindIf(IfNode statement)
|
private BoundIfNode BindIf(IfNode statement)
|
||||||
{
|
{
|
||||||
var elseStatement = Optional.Empty<Variant<BoundIfNode, BoundBlock>>();
|
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);
|
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>();
|
var value = Optional.Empty<BoundExpressionNode>();
|
||||||
|
|
||||||
if (statement.Value.HasValue)
|
if (statement.Value.HasValue)
|
||||||
{
|
{
|
||||||
value = BindExpression(statement.Value.Value, _funcReturnType);
|
value = BindExpression(statement.Value.Value, _functionReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoundReturnNode(statement.Tokens, value);
|
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));
|
return new BoundStatementExpressionNode(statement.Tokens, BindExpression(statement.Expression));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundVariableDeclarationNode BindVariableDeclaration(VariableDeclarationNode statement)
|
private BoundVariableDeclarationNode BindVariableDeclaration(VariableDeclarationNode statement)
|
||||||
{
|
{
|
||||||
NubType? type = null;
|
NubType? type = null;
|
||||||
|
|
||||||
@@ -233,12 +232,12 @@ public static class Binder
|
|||||||
return new BoundVariableDeclarationNode(statement.Tokens, statement.Name, statement.ExplicitType, assignment, type);
|
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));
|
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
|
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);
|
var inner = BindExpression(expression.Expression);
|
||||||
return new BoundAddressOfNode(expression.Tokens, new NubPointerType(inner.Type), inner);
|
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();
|
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);
|
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 boundArray = BindExpression(expression.Array);
|
||||||
var elementType = ((NubArrayType)boundArray.Type).ElementType;
|
var elementType = ((NubArrayType)boundArray.Type).ElementType;
|
||||||
return new BoundArrayIndexAccessNode(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, NubPrimitiveType.U64));
|
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);
|
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 boundLeft = BindExpression(expression.Left);
|
||||||
var boundRight = BindExpression(expression.Right, boundLeft.Type);
|
var boundRight = BindExpression(expression.Right, boundLeft.Type);
|
||||||
return new BoundBinaryExpressionNode(expression.Tokens, boundLeft.Type, boundLeft, expression.Operator, boundRight);
|
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 boundExpression = BindExpression(expression.Expression);
|
||||||
var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType;
|
var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType;
|
||||||
return new BoundDereferenceNode(expression.Tokens, dereferencedType, boundExpression);
|
return new BoundDereferenceNode(expression.Tokens, dereferencedType, boundExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundFuncCallNode BindFuncCall(FuncCallNode expression)
|
private BoundFuncCallNode BindFuncCall(FuncCallNode expression)
|
||||||
{
|
{
|
||||||
var boundExpression = BindExpression(expression.Expression);
|
var boundExpression = BindExpression(expression.Expression);
|
||||||
|
|
||||||
@@ -323,30 +322,45 @@ public static class Binder
|
|||||||
return new BoundFuncCallNode(expression.Tokens, returnType, boundExpression, parameters);
|
return new BoundFuncCallNode(expression.Tokens, returnType, boundExpression, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundIdentifierNode BindIdentifier(IdentifierNode expression)
|
private BoundIdentifierNode BindIdentifier(IdentifierNode expression)
|
||||||
{
|
{
|
||||||
NubType? type = null;
|
var localFuncs = _definitionTable.LookupLocalFunc(expression.Namespace.Or(_syntaxTree.Namespace), expression.Name).ToArray();
|
||||||
|
if (localFuncs.Length > 0)
|
||||||
var definition = _definitionTable.LookupFunction(expression.Namespace.Or(_syntaxTree.Namespace), expression.Name);
|
|
||||||
if (definition.HasValue)
|
|
||||||
{
|
{
|
||||||
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
|
var type = expectedType ?? expression.Kind switch
|
||||||
{
|
{
|
||||||
@@ -360,81 +374,129 @@ public static class Binder
|
|||||||
return new BoundLiteralNode(expression.Tokens, type, expression.Literal, expression.Kind);
|
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 boundExpression = BindExpression(expression.Expression);
|
||||||
|
|
||||||
var implementation = _definitionTable.LookupTraitImplementationForType(boundExpression.Type, expression.Member);
|
var traitFuncImpls = _definitionTable.LookupTraitImpl(boundExpression.Type).SelectMany(x => _definitionTable.LookupTraitFuncImpl(x, expression.Member)).ToArray();
|
||||||
if (implementation.HasValue)
|
|
||||||
|
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);
|
return new BoundMemberAccessNode(expression.Tokens, type, boundExpression, expression.Member);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boundExpression.Type is NubCustomType customType)
|
if (boundExpression.Type is NubCustomType customType)
|
||||||
{
|
{
|
||||||
var function = _definitionTable.LookupFunctionOnTrait(customType.Namespace, customType.Name, expression.Member);
|
var traits = _definitionTable.LookupTrait(customType.Namespace, customType.Name).ToArray();
|
||||||
if (function.HasValue)
|
if (traits.Length > 0)
|
||||||
{
|
{
|
||||||
var type = new NubFuncType(function.Value.ReturnType, function.Value.Parameters.Select(p => p.Type).ToList());
|
if (traits.Length > 1)
|
||||||
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");
|
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")
|
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)
|
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);
|
var structs = _definitionTable.LookupStruct(structType.Namespace, structType.Name).ToArray();
|
||||||
if (!defOpt.TryGetValue(out var definition))
|
|
||||||
|
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>();
|
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);
|
var fields = _definitionTable.LookupStructField(@struct, field).ToArray();
|
||||||
if (definitionField == null)
|
|
||||||
|
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);
|
return new BoundStructInitializerNode(expression.Tokens, structType, structType, initializers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundUnaryExpressionNode BindUnaryExpression(UnaryExpressionNode expression)
|
private BoundUnaryExpressionNode BindUnaryExpression(UnaryExpressionNode expression)
|
||||||
{
|
{
|
||||||
var boundOperand = BindExpression(expression.Operand);
|
var boundOperand = BindExpression(expression.Operand);
|
||||||
|
|
||||||
@@ -469,4 +531,14 @@ public static class Binder
|
|||||||
|
|
||||||
return new BoundUnaryExpressionNode(expression.Tokens, type, expression.Operator, boundOperand);
|
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;
|
namespace Syntax;
|
||||||
|
|
||||||
public class DefinitionTable
|
public sealed class DefinitionTable
|
||||||
{
|
{
|
||||||
private readonly List<TopLevelNode> _topLevelNodes;
|
private readonly List<TopLevelNode> _topLevelNodes;
|
||||||
|
|
||||||
@@ -10,14 +10,54 @@ public class DefinitionTable
|
|||||||
{
|
{
|
||||||
_topLevelNodes = syntaxTrees.SelectMany(x => x.TopLevelNodes).ToList();
|
_topLevelNodes = syntaxTrees.SelectMany(x => x.TopLevelNodes).ToList();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public class BoundDefinitionTable
|
public IEnumerable<LocalFuncNode> LookupLocalFunc(string @namespace, string name)
|
||||||
{
|
|
||||||
private readonly List<BoundTopLevelNode> _topLevelNodes;
|
|
||||||
|
|
||||||
public BoundDefinitionTable(IEnumerable<BoundSyntaxTree> syntaxTrees)
|
|
||||||
{
|
{
|
||||||
_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 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 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 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 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);
|
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 ReturnNode(IEnumerable<Token> Tokens, Optional<ExpressionNode> Value) : StatementNode(Tokens);
|
||||||
public record BoundReturnNode(IEnumerable<Token> Tokens, Optional<BoundExpressionNode> Value) : BoundStatementNode(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 AssignmentNode(IEnumerable<Token> Tokens, ExpressionNode Target, ExpressionNode Value) : StatementNode(Tokens);
|
||||||
public record BoundAssignmentNode(IEnumerable<Token> Tokens, BoundExpressionNode Expression, BoundExpressionNode Value) : BoundStatementNode(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 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);
|
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);
|
namespace Syntax.Node;
|
||||||
public record BoundSyntaxTree(string Namespace, List<BoundTopLevelNode> TopLevelNodes);
|
|
||||||
|
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;
|
namespace Syntax.Parsing;
|
||||||
|
|
||||||
public static class Parser
|
public sealed class Parser
|
||||||
{
|
{
|
||||||
private static string _namespace = null!;
|
private string _namespace;
|
||||||
private static NubType? _functionReturnType;
|
private readonly IEnumerable<Token> _tokens;
|
||||||
private static List<Diagnostic> _diagnostics = [];
|
|
||||||
private static IEnumerable<Token> _tokens = [];
|
|
||||||
private static int _index;
|
|
||||||
|
|
||||||
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";
|
_namespace = "global";
|
||||||
_diagnostics = [];
|
_tokens = tokens;
|
||||||
_index = 0;
|
}
|
||||||
|
|
||||||
|
public SyntaxTree Parse()
|
||||||
|
{
|
||||||
|
_diagnostics.Clear();
|
||||||
_functionReturnType = null;
|
_functionReturnType = null;
|
||||||
|
_tokenIndex = 0;
|
||||||
|
|
||||||
if (TryExpectSymbol(Symbol.Namespace))
|
if (TryExpectSymbol(Symbol.Namespace))
|
||||||
{
|
{
|
||||||
_namespace = ExpectIdentifier().Value;
|
_namespace = ExpectIdentifier().Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
List<TopLevelNode> topLevelNodes = [];
|
||||||
{
|
|
||||||
List<TopLevelNode> definitions = [];
|
|
||||||
|
|
||||||
while (Peek().HasValue)
|
while (Peek().HasValue)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var definition = ParseDefinition();
|
topLevelNodes.Add(ParseTopLevel());
|
||||||
definitions.Add(definition);
|
}
|
||||||
|
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 new SyntaxTree(_namespace, topLevelNodes, _diagnostics);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TopLevelNode ParseDefinition()
|
private TopLevelNode ParseTopLevel()
|
||||||
{
|
{
|
||||||
var startIndex = _index;
|
var startIndex = _tokenIndex;
|
||||||
List<ModifierToken> modifiers = [];
|
List<ModifierToken> modifiers = [];
|
||||||
|
|
||||||
while (TryExpectModifier(out var modifier))
|
while (TryExpectModifier(out var modifier))
|
||||||
@@ -86,7 +86,7 @@ public static class Parser
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TopLevelNode ParseFunc(int startIndex, List<ModifierToken> modifiers)
|
private TopLevelNode ParseFunc(int startIndex, List<ModifierToken> modifiers)
|
||||||
{
|
{
|
||||||
var name = ExpectIdentifier();
|
var name = ExpectIdentifier();
|
||||||
List<FuncParameter> parameters = [];
|
List<FuncParameter> parameters = [];
|
||||||
@@ -138,7 +138,7 @@ public static class Parser
|
|||||||
return new LocalFuncNode(GetTokensForNode(startIndex), _namespace, name.Value, parameters, body, returnType, exported);
|
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;
|
var name = ExpectIdentifier().Value;
|
||||||
|
|
||||||
@@ -146,10 +146,12 @@ public static class Parser
|
|||||||
|
|
||||||
List<StructFieldNode> variables = [];
|
List<StructFieldNode> variables = [];
|
||||||
|
|
||||||
|
var fieldIndex = 0;
|
||||||
|
|
||||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||||
{
|
{
|
||||||
var fieldStartIndex = _index;
|
var fieldStartIndex = _tokenIndex;
|
||||||
|
|
||||||
var variableName = ExpectIdentifier().Value;
|
var variableName = ExpectIdentifier().Value;
|
||||||
ExpectSymbol(Symbol.Colon);
|
ExpectSymbol(Symbol.Colon);
|
||||||
var variableType = ParseType();
|
var variableType = ParseType();
|
||||||
@@ -161,13 +163,13 @@ public static class Parser
|
|||||||
variableValue = ParseExpression();
|
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);
|
return new StructNode(GetTokensForNode(startIndex), _namespace, name, variables);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TraitNode ParseTrait(int startIndex)
|
private TraitNode ParseTrait(int startIndex)
|
||||||
{
|
{
|
||||||
var name = ExpectIdentifier().Value;
|
var name = ExpectIdentifier().Value;
|
||||||
|
|
||||||
@@ -177,7 +179,7 @@ public static class Parser
|
|||||||
|
|
||||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||||
{
|
{
|
||||||
var funcStartIndex = _index;
|
var funcStartIndex = _tokenIndex;
|
||||||
|
|
||||||
ExpectSymbol(Symbol.Func);
|
ExpectSymbol(Symbol.Func);
|
||||||
|
|
||||||
@@ -207,7 +209,7 @@ public static class Parser
|
|||||||
return new TraitNode(GetTokensForNode(startIndex), _namespace, name, functions);
|
return new TraitNode(GetTokensForNode(startIndex), _namespace, name, functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TraitImplNode ParseImplementation(int startIndex)
|
private TraitImplNode ParseImplementation(int startIndex)
|
||||||
{
|
{
|
||||||
var traitType = ParseType();
|
var traitType = ParseType();
|
||||||
ExpectSymbol(Symbol.For);
|
ExpectSymbol(Symbol.For);
|
||||||
@@ -218,7 +220,7 @@ public static class Parser
|
|||||||
ExpectSymbol(Symbol.OpenBrace);
|
ExpectSymbol(Symbol.OpenBrace);
|
||||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||||
{
|
{
|
||||||
var funcStartIndex = _index;
|
var funcStartIndex = _tokenIndex;
|
||||||
ExpectSymbol(Symbol.Func);
|
ExpectSymbol(Symbol.Func);
|
||||||
var functionName = ExpectIdentifier().Value;
|
var functionName = ExpectIdentifier().Value;
|
||||||
var parameters = new List<FuncParameter>
|
var parameters = new List<FuncParameter>
|
||||||
@@ -252,7 +254,7 @@ public static class Parser
|
|||||||
return new TraitImplNode(GetTokensForNode(startIndex), _namespace, traitType, forType, functions);
|
return new TraitImplNode(GetTokensForNode(startIndex), _namespace, traitType, forType, functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FuncParameter ParseFuncParameter()
|
private FuncParameter ParseFuncParameter()
|
||||||
{
|
{
|
||||||
var name = ExpectIdentifier();
|
var name = ExpectIdentifier();
|
||||||
ExpectSymbol(Symbol.Colon);
|
ExpectSymbol(Symbol.Colon);
|
||||||
@@ -261,9 +263,9 @@ public static class Parser
|
|||||||
return new FuncParameter(name.Value, type);
|
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))
|
if (!Peek().TryGetValue(out var token))
|
||||||
{
|
{
|
||||||
throw new ParseException(Diagnostic
|
throw new ParseException(Diagnostic
|
||||||
@@ -294,7 +296,7 @@ public static class Parser
|
|||||||
return ParseStatementExpression(startIndex);
|
return ParseStatementExpression(startIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StatementNode ParseStatementExpression(int startIndex)
|
private StatementNode ParseStatementExpression(int startIndex)
|
||||||
{
|
{
|
||||||
var expr = ParseExpression();
|
var expr = ParseExpression();
|
||||||
|
|
||||||
@@ -307,7 +309,7 @@ public static class Parser
|
|||||||
return new StatementExpressionNode(GetTokensForNode(startIndex), expr);
|
return new StatementExpressionNode(GetTokensForNode(startIndex), expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VariableDeclarationNode ParseVariableDeclaration(int startIndex)
|
private VariableDeclarationNode ParseVariableDeclaration(int startIndex)
|
||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.Let);
|
ExpectSymbol(Symbol.Let);
|
||||||
var name = ExpectIdentifier().Value;
|
var name = ExpectIdentifier().Value;
|
||||||
@@ -327,20 +329,20 @@ public static class Parser
|
|||||||
return new VariableDeclarationNode(GetTokensForNode(startIndex), name, explicitType, assignment);
|
return new VariableDeclarationNode(GetTokensForNode(startIndex), name, explicitType, assignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StatementNode ParseBreak(int startIndex)
|
private StatementNode ParseBreak(int startIndex)
|
||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.Break);
|
ExpectSymbol(Symbol.Break);
|
||||||
Next();
|
Next();
|
||||||
return new BreakNode(GetTokensForNode(startIndex));
|
return new BreakNode(GetTokensForNode(startIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StatementNode ParseContinue(int startIndex)
|
private StatementNode ParseContinue(int startIndex)
|
||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.Continue);
|
ExpectSymbol(Symbol.Continue);
|
||||||
return new ContinueNode(GetTokensForNode(startIndex));
|
return new ContinueNode(GetTokensForNode(startIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReturnNode ParseReturn(int startIndex)
|
private ReturnNode ParseReturn(int startIndex)
|
||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.Return);
|
ExpectSymbol(Symbol.Return);
|
||||||
|
|
||||||
@@ -353,7 +355,7 @@ public static class Parser
|
|||||||
return new ReturnNode(GetTokensForNode(startIndex), value);
|
return new ReturnNode(GetTokensForNode(startIndex), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IfNode ParseIf(int startIndex)
|
private IfNode ParseIf(int startIndex)
|
||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.If);
|
ExpectSymbol(Symbol.If);
|
||||||
var condition = ParseExpression();
|
var condition = ParseExpression();
|
||||||
@@ -362,7 +364,7 @@ public static class Parser
|
|||||||
var elseStatement = Optional<Variant<IfNode, BlockNode>>.Empty();
|
var elseStatement = Optional<Variant<IfNode, BlockNode>>.Empty();
|
||||||
if (TryExpectSymbol(Symbol.Else))
|
if (TryExpectSymbol(Symbol.Else))
|
||||||
{
|
{
|
||||||
var newStartIndex = _index;
|
var newStartIndex = _tokenIndex;
|
||||||
elseStatement = TryExpectSymbol(Symbol.If)
|
elseStatement = TryExpectSymbol(Symbol.If)
|
||||||
? (Variant<IfNode, BlockNode>)ParseIf(newStartIndex)
|
? (Variant<IfNode, BlockNode>)ParseIf(newStartIndex)
|
||||||
: (Variant<IfNode, BlockNode>)ParseBlock();
|
: (Variant<IfNode, BlockNode>)ParseBlock();
|
||||||
@@ -371,7 +373,7 @@ public static class Parser
|
|||||||
return new IfNode(GetTokensForNode(startIndex), condition, body, elseStatement);
|
return new IfNode(GetTokensForNode(startIndex), condition, body, elseStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WhileNode ParseWhile(int startIndex)
|
private WhileNode ParseWhile(int startIndex)
|
||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.While);
|
ExpectSymbol(Symbol.While);
|
||||||
var condition = ParseExpression();
|
var condition = ParseExpression();
|
||||||
@@ -379,9 +381,9 @@ public static class Parser
|
|||||||
return new WhileNode(GetTokensForNode(startIndex), condition, body);
|
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();
|
var left = ParsePrimaryExpression();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
@@ -402,7 +404,7 @@ public static class Parser
|
|||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetBinaryOperatorPrecedence(BinaryExpressionOperator binaryExpressionOperator)
|
private int GetBinaryOperatorPrecedence(BinaryExpressionOperator binaryExpressionOperator)
|
||||||
{
|
{
|
||||||
return binaryExpressionOperator switch
|
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)
|
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;
|
ExpressionNode expr;
|
||||||
|
|
||||||
var token = ExpectToken();
|
var token = ExpectToken();
|
||||||
@@ -583,7 +585,7 @@ public static class Parser
|
|||||||
return ParsePostfixOperators(startIndex, expr);
|
return ParsePostfixOperators(startIndex, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ExpressionNode ParsePostfixOperators(int startIndex, ExpressionNode expr)
|
private ExpressionNode ParsePostfixOperators(int startIndex, ExpressionNode expr)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -640,9 +642,9 @@ public static class Parser
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BlockNode ParseBlock()
|
private BlockNode ParseBlock()
|
||||||
{
|
{
|
||||||
var startIndex = _index;
|
var startIndex = _tokenIndex;
|
||||||
ExpectSymbol(Symbol.OpenBrace);
|
ExpectSymbol(Symbol.OpenBrace);
|
||||||
List<StatementNode> statements = [];
|
List<StatementNode> statements = [];
|
||||||
while (Peek().HasValue && !TryExpectSymbol(Symbol.CloseBrace))
|
while (Peek().HasValue && !TryExpectSymbol(Symbol.CloseBrace))
|
||||||
@@ -661,7 +663,7 @@ public static class Parser
|
|||||||
return new BlockNode(GetTokensForNode(startIndex), statements);
|
return new BlockNode(GetTokensForNode(startIndex), statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NubType ParseType()
|
private NubType ParseType()
|
||||||
{
|
{
|
||||||
if (TryExpectIdentifier(out var name))
|
if (TryExpectIdentifier(out var name))
|
||||||
{
|
{
|
||||||
@@ -746,7 +748,7 @@ public static class Parser
|
|||||||
.Build());
|
.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Token ExpectToken()
|
private Token ExpectToken()
|
||||||
{
|
{
|
||||||
if (!Peek().TryGetValue(out var token))
|
if (!Peek().TryGetValue(out var token))
|
||||||
{
|
{
|
||||||
@@ -761,7 +763,7 @@ public static class Parser
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SymbolToken ExpectSymbol()
|
private SymbolToken ExpectSymbol()
|
||||||
{
|
{
|
||||||
var token = ExpectToken();
|
var token = ExpectToken();
|
||||||
if (token is not SymbolToken symbol)
|
if (token is not SymbolToken symbol)
|
||||||
@@ -776,7 +778,7 @@ public static class Parser
|
|||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ExpectSymbol(Symbol expectedSymbol)
|
private void ExpectSymbol(Symbol expectedSymbol)
|
||||||
{
|
{
|
||||||
var token = ExpectSymbol();
|
var token = ExpectSymbol();
|
||||||
if (token.Symbol != expectedSymbol)
|
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)
|
if (Peek() is { Value: SymbolToken symbolToken } && symbolToken.Symbol == symbol)
|
||||||
{
|
{
|
||||||
@@ -800,7 +802,7 @@ public static class Parser
|
|||||||
return false;
|
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 })
|
if (Peek() is { Value: ModifierToken modifierToken })
|
||||||
{
|
{
|
||||||
@@ -813,7 +815,7 @@ public static class Parser
|
|||||||
return false;
|
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 })
|
if (Peek() is { Value: IdentifierToken identifierToken })
|
||||||
{
|
{
|
||||||
@@ -826,7 +828,7 @@ public static class Parser
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IdentifierToken ExpectIdentifier()
|
private IdentifierToken ExpectIdentifier()
|
||||||
{
|
{
|
||||||
var token = ExpectToken();
|
var token = ExpectToken();
|
||||||
if (token is not IdentifierToken identifier)
|
if (token is not IdentifierToken identifier)
|
||||||
@@ -841,12 +843,12 @@ public static class Parser
|
|||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RecoverToNextDefinition()
|
private void RecoverToNextDefinition()
|
||||||
{
|
{
|
||||||
while (Peek().HasValue)
|
while (Peek().HasValue)
|
||||||
{
|
{
|
||||||
var token = Peek().Value;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -855,7 +857,7 @@ public static class Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RecoverToNextStatement()
|
private void RecoverToNextStatement()
|
||||||
{
|
{
|
||||||
while (Peek().TryGetValue(out var token))
|
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())
|
if (peekIndex < _tokens.Count())
|
||||||
{
|
{
|
||||||
return _tokens.ElementAt(peekIndex);
|
return _tokens.ElementAt(peekIndex);
|
||||||
@@ -882,14 +884,14 @@ public static class Parser
|
|||||||
return Optional<Token>.Empty();
|
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