From d9d08a4367745a05a77e86de2c97ca7995dbb532 Mon Sep 17 00:00:00 2001 From: nub31 Date: Tue, 22 Jul 2025 20:03:22 +0200 Subject: [PATCH] ... --- src/compiler/NubLang.CLI/Program.cs | 6 +- src/compiler/NubLang.Common/Variant.cs | 36 +++++- src/compiler/NubLang/Syntax/Binding/Binder.cs | 12 +- .../NubLang/Syntax/Binding/DefinitionTable.cs | 2 +- .../Syntax/Generics/GenericInstantiator.cs | 69 ++++++++-- .../Syntax/Generics/Node/DefinitionSyntax.cs | 26 ---- .../Syntax/Generics/Node/ExpressionSyntax.cs | 52 -------- .../Syntax/Generics/Node/StatementSyntax.cs | 22 ---- .../Syntax/Generics/Node/TypeSyntax.cs | 36 ------ .../Syntax/Generics/Node/UnboundTree.cs | 10 -- .../Syntax/Parsing/Node/DefinitionSyntax.cs | 119 ++++++++++++++++-- .../Syntax/Parsing/Node/ExpressionSyntax.cs | 111 ++++++++++++++-- .../NubLang/Syntax/Parsing/Node/ParseTree.cs | 10 -- .../Syntax/Parsing/Node/StatementSyntax.cs | 81 ++++++++++-- .../NubLang/Syntax/Parsing/Node/SyntaxNode.cs | 41 ++++++ .../NubLang/Syntax/Parsing/Node/TypeSyntax.cs | 65 ++++++++-- src/compiler/NubLang/Syntax/Parsing/Parser.cs | 34 ++--- 17 files changed, 494 insertions(+), 238 deletions(-) delete mode 100644 src/compiler/NubLang/Syntax/Generics/Node/DefinitionSyntax.cs delete mode 100644 src/compiler/NubLang/Syntax/Generics/Node/ExpressionSyntax.cs delete mode 100644 src/compiler/NubLang/Syntax/Generics/Node/StatementSyntax.cs delete mode 100644 src/compiler/NubLang/Syntax/Generics/Node/TypeSyntax.cs delete mode 100644 src/compiler/NubLang/Syntax/Generics/Node/UnboundTree.cs delete mode 100644 src/compiler/NubLang/Syntax/Parsing/Node/ParseTree.cs create mode 100644 src/compiler/NubLang/Syntax/Parsing/Node/SyntaxNode.cs diff --git a/src/compiler/NubLang.CLI/Program.cs b/src/compiler/NubLang.CLI/Program.cs index 688c9ac..67d6ee4 100644 --- a/src/compiler/NubLang.CLI/Program.cs +++ b/src/compiler/NubLang.CLI/Program.cs @@ -7,6 +7,7 @@ using NubLang.Generation; using NubLang.Generation.QBE; using NubLang.Syntax.Binding; using NubLang.Syntax.Binding.Node; +using NubLang.Syntax.Generics; using NubLang.Syntax.Parsing; using NubLang.Syntax.Parsing.Node; using NubLang.Syntax.Tokenization; @@ -67,7 +68,7 @@ for (var i = 0; i < args.Length; i++) } var diagnostics = new List(); -var syntaxTrees = new Dictionary(); +var syntaxTrees = new Dictionary(); foreach (var file in options.Files) { @@ -94,6 +95,9 @@ foreach (var file in options.Files) syntaxTrees[file] = syntaxTree; } +var genericInstantiator = new GenericInstantiator(syntaxTrees.Values); +genericInstantiator.Visit(); + var definitionTable = new DefinitionTable(syntaxTrees.Values); var boundSyntaxTrees = new Dictionary(); diff --git a/src/compiler/NubLang.Common/Variant.cs b/src/compiler/NubLang.Common/Variant.cs index dba2119..334515e 100644 --- a/src/compiler/NubLang.Common/Variant.cs +++ b/src/compiler/NubLang.Common/Variant.cs @@ -1,4 +1,6 @@ -namespace NubLang.Common; +using System.Diagnostics.CodeAnalysis; + +namespace NubLang.Common; public readonly struct Variant where T1 : notnull where T2 : notnull { @@ -6,12 +8,12 @@ public readonly struct Variant where T1 : notnull where T2 : notnull { throw new InvalidOperationException("Variant must be initialized with a value"); } - + public Variant(T1 value) { _value = value; } - + public Variant(T2 value) { _value = value; @@ -33,7 +35,7 @@ public readonly struct Variant where T1 : notnull where T2 : notnull throw new InvalidCastException(); } } - + public T Match(Func on1, Func on2) { return _value switch @@ -43,7 +45,31 @@ public readonly struct Variant where T1 : notnull where T2 : notnull _ => throw new InvalidCastException() }; } - + + public bool IsCase1([NotNullWhen(true)] out T1? value) + { + if (_value is T1 converted) + { + value = converted; + return true; + } + + value = default; + return false; + } + + public bool IsCase2([NotNullWhen(true)] out T2? value) + { + if (_value is T2 converted) + { + value = converted; + return true; + } + + value = default; + return false; + } + public static implicit operator Variant(T1 value) => new(value); public static implicit operator Variant(T2 value) => new(value); } \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Binding/Binder.cs b/src/compiler/NubLang/Syntax/Binding/Binder.cs index b517537..14379c5 100644 --- a/src/compiler/NubLang/Syntax/Binding/Binder.cs +++ b/src/compiler/NubLang/Syntax/Binding/Binder.cs @@ -8,7 +8,7 @@ namespace NubLang.Syntax.Binding; public sealed class Binder { - private readonly ParseTree _parseTree; + private readonly SyntaxTree _syntaxTree; private readonly DefinitionTable _definitionTable; private readonly Stack _scopes = []; @@ -16,9 +16,9 @@ public sealed class Binder private Scope Scope => _scopes.Peek(); - public Binder(ParseTree parseTree, DefinitionTable definitionTable) + public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable) { - _parseTree = parseTree; + _syntaxTree = syntaxTree; _definitionTable = definitionTable; } @@ -30,7 +30,7 @@ public sealed class Binder var diagnostics = new List(); var definitions = new List(); - foreach (var definition in _parseTree.Definitions) + foreach (var definition in _syntaxTree.Definitions) { try { @@ -42,7 +42,7 @@ public sealed class Binder } } - return new BoundSyntaxTree(_parseTree.Namespace, definitions, diagnostics); + return new BoundSyntaxTree(_syntaxTree.Namespace, definitions, diagnostics); } private BoundDefinition BindDefinition(DefinitionSyntax node) @@ -309,7 +309,7 @@ public sealed class Binder private BoundExpression BindIdentifier(IdentifierSyntax expression) { - var @namespace = expression.Namespace.Or(_parseTree.Namespace); + var @namespace = expression.Namespace.Or(_syntaxTree.Namespace); var localFuncs = _definitionTable.LookupLocalFunc(@namespace, expression.Name).ToArray(); if (localFuncs.Length > 0) { diff --git a/src/compiler/NubLang/Syntax/Binding/DefinitionTable.cs b/src/compiler/NubLang/Syntax/Binding/DefinitionTable.cs index 36fa1d3..7cddd36 100644 --- a/src/compiler/NubLang/Syntax/Binding/DefinitionTable.cs +++ b/src/compiler/NubLang/Syntax/Binding/DefinitionTable.cs @@ -6,7 +6,7 @@ public class DefinitionTable { private readonly List _definitions; - public DefinitionTable(IEnumerable syntaxTrees) + public DefinitionTable(IEnumerable syntaxTrees) { _definitions = syntaxTrees.SelectMany(x => x.Definitions).ToList(); } diff --git a/src/compiler/NubLang/Syntax/Generics/GenericInstantiator.cs b/src/compiler/NubLang/Syntax/Generics/GenericInstantiator.cs index 257ebec..0abd722 100644 --- a/src/compiler/NubLang/Syntax/Generics/GenericInstantiator.cs +++ b/src/compiler/NubLang/Syntax/Generics/GenericInstantiator.cs @@ -1,30 +1,77 @@ -using NubLang.Syntax.Generics.Node; using NubLang.Syntax.Parsing.Node; namespace NubLang.Syntax.Generics; public class GenericInstantiator { - private readonly ParseTree _parseTree; + private readonly IEnumerable _syntaxTrees; + private readonly Queue _structQueue = []; - public GenericInstantiator(ParseTree parseTree) + public GenericInstantiator(IEnumerable syntaxTrees) { - _parseTree = parseTree; + _syntaxTrees = syntaxTrees; } - public UnboundTree Visit() + public IEnumerable Visit() { - var unboundDefinitions = new List(); + _structQueue.Clear(); - foreach (var definition in _parseTree.Definitions) + var syntaxTrees = new List(); + + foreach (var syntaxTree in _syntaxTrees) { - switch (definition) + var definitions = new List(); + foreach (var definition in syntaxTree.Definitions) { - default: - throw new ArgumentOutOfRangeException(nameof(definition)); + if (definition.Parameters.Any()) + { + switch (definition) + { + case StructSyntax structSyntax: + { + var usages = _syntaxTrees + .SelectMany(x => x.GetDescendants()) + .OfType() + .Where(x => x.Namespace == structSyntax.Namespace) + .Where(x => x.Name == structSyntax.Name); + + foreach (var usage in usages) + { + if (!_structQueue.Any(x => x.Type.Namespace == usage.Namespace && x.Type.Name == usage.Name)) + { + _structQueue.Enqueue(new GenericStructQueue(structSyntax, usage, false)); + } + } + + break; + } + default: + { + throw new ArgumentOutOfRangeException(nameof(definition)); + } + } + } + else + { + definitions.Add(definition); + } } + + while (_structQueue.TryDequeue(out var item)) + { + definitions.Add(new StructSyntax(item.Type.Tokens, item.Struct.Namespace, [], item.Type.MangledName(), item.Struct.Fields, item.Struct.Functions)); + } + + syntaxTrees.Add(new SyntaxTree(syntaxTree.Tokens, syntaxTree.Namespace, definitions, syntaxTree.Diagnostics)); } - return new UnboundTree(_parseTree.Namespace, unboundDefinitions, _parseTree.Diagnostics); + return syntaxTrees; } +} + +public class GenericStructQueue(StructSyntax @struct, CustomTypeSyntax type, bool created) +{ + public StructSyntax Struct { get; init; } = @struct; + public CustomTypeSyntax Type { get; init; } = type; + public bool Created { get; set; } = created; } \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Generics/Node/DefinitionSyntax.cs b/src/compiler/NubLang/Syntax/Generics/Node/DefinitionSyntax.cs deleted file mode 100644 index 9cfa421..0000000 --- a/src/compiler/NubLang/Syntax/Generics/Node/DefinitionSyntax.cs +++ /dev/null @@ -1,26 +0,0 @@ -using NubLang.Common; -using NubLang.Syntax.Tokenization; - -namespace NubLang.Syntax.Generics.Node; - -public record UnboundGenericParameter(IReadOnlyList Tokens, string Name) : UnboundNode(Tokens); - -public abstract record UnboundDefinition(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters) : UnboundNode(Tokens); - -public record UnboundFuncParameter(IReadOnlyList Tokens, string Name, UnboundType Type) : UnboundNode(Tokens); - -public record UnboundFuncSignature(IReadOnlyList Tokens, IReadOnlyList Parameters, UnboundType ReturnType) : UnboundNode(Tokens); - -public record UnboundLocalFunc(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, UnboundFuncSignature Signature, UnboundBlock Body) : UnboundDefinition(Tokens, Namespace, Parameters); - -public record UnboundExternFunc(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, string CallName, UnboundFuncSignature Signature) : UnboundDefinition(Tokens, Namespace, Parameters); - -public record UnboundStructField(IReadOnlyList Tokens, int Index, string Name, UnboundType Type, Optional Value) : UnboundNode(Tokens); - -public record UnboundStructFunc(IReadOnlyList Tokens, string Name, UnboundFuncSignature Signature, UnboundBlock Body) : UnboundNode(Tokens); - -public record UnboundStruct(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, IReadOnlyList Fields, IReadOnlyList Funcs) : UnboundDefinition(Tokens, Namespace, Parameters); - -public record UnboundInterfaceFunc(IReadOnlyList Tokens, string Name, UnboundFuncSignature Signature) : UnboundNode(Tokens); - -public record UnboundInterface(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, IReadOnlyList Functions) : UnboundDefinition(Tokens, Namespace, Parameters); \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Generics/Node/ExpressionSyntax.cs b/src/compiler/NubLang/Syntax/Generics/Node/ExpressionSyntax.cs deleted file mode 100644 index 3451340..0000000 --- a/src/compiler/NubLang/Syntax/Generics/Node/ExpressionSyntax.cs +++ /dev/null @@ -1,52 +0,0 @@ -using NubLang.Common; -using NubLang.Syntax.Tokenization; - -namespace NubLang.Syntax.Generics.Node; - -public enum UnboundUnaryOperator -{ - Negate, - Invert -} - -public enum UnboundBinaryOperator -{ - Equal, - NotEqual, - GreaterThan, - GreaterThanOrEqual, - LessThan, - LessThanOrEqual, - Plus, - Minus, - Multiply, - Divide -} - -public abstract record UnboundExpression(IReadOnlyList Tokens) : UnboundNode(Tokens); - -public record UnboundBinaryExpression(IReadOnlyList Tokens, UnboundExpression Left, UnboundBinaryOperator Operator, UnboundExpression Right) : UnboundExpression(Tokens); - -public record UnboundUnaryExpression(IReadOnlyList Tokens, UnboundUnaryOperator Operator, UnboundExpression Operand) : UnboundExpression(Tokens); - -public record UnboundFuncCall(IReadOnlyList Tokens, UnboundExpression Expression, IReadOnlyList Parameters) : UnboundExpression(Tokens); - -public record UnboundIdentifier(IReadOnlyList Tokens, Optional Namespace, string Name) : UnboundExpression(Tokens); - -public record UnboundArrayInitializer(IReadOnlyList Tokens, UnboundExpression Capacity, UnboundType ElementType) : UnboundExpression(Tokens); - -public record UnboundArrayIndexAccess(IReadOnlyList Tokens, UnboundExpression Target, UnboundExpression Index) : UnboundExpression(Tokens); - -public record UnboundArrowFuncParameter(IReadOnlyList Tokens, string Name) : UnboundExpression(Tokens); - -public record UnboundArrowFunc(IReadOnlyList Tokens, IReadOnlyList Parameters, UnboundBlock Body) : UnboundExpression(Tokens); - -public record UnboundAddressOf(IReadOnlyList Tokens, UnboundExpression Expression) : UnboundExpression(Tokens); - -public record UnboundLiteral(IReadOnlyList Tokens, string Value, LiteralKind Kind) : UnboundExpression(Tokens); - -public record UnboundMemberAccess(IReadOnlyList Tokens, UnboundExpression Target, string Member) : UnboundExpression(Tokens); - -public record UnboundStructInitializer(IReadOnlyList Tokens, UnboundType StructType, Dictionary Initializers) : UnboundExpression(Tokens); - -public record UnboundDereference(IReadOnlyList Tokens, UnboundExpression Expression) : UnboundExpression(Tokens); \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Generics/Node/StatementSyntax.cs b/src/compiler/NubLang/Syntax/Generics/Node/StatementSyntax.cs deleted file mode 100644 index fa90c03..0000000 --- a/src/compiler/NubLang/Syntax/Generics/Node/StatementSyntax.cs +++ /dev/null @@ -1,22 +0,0 @@ -using NubLang.Common; -using NubLang.Syntax.Tokenization; - -namespace NubLang.Syntax.Generics.Node; - -public record UnboundStatement(IReadOnlyList Tokens) : UnboundNode(Tokens); - -public record UnboundStatementExpression(IReadOnlyList Tokens, UnboundExpression Expression) : UnboundStatement(Tokens); - -public record UnboundReturn(IReadOnlyList Tokens, Optional Value) : UnboundStatement(Tokens); - -public record UnboundAssignment(IReadOnlyList Tokens, UnboundExpression Target, UnboundExpression Value) : UnboundStatement(Tokens); - -public record UnboundIf(IReadOnlyList Tokens, UnboundExpression Condition, UnboundBlock Body, Optional> Else) : UnboundStatement(Tokens); - -public record UnboundVariableDeclaration(IReadOnlyList Tokens, string Name, Optional ExplicitType, Optional Assignment) : UnboundStatement(Tokens); - -public record UnboundContinue(IReadOnlyList Tokens) : UnboundStatement(Tokens); - -public record UnboundBreak(IReadOnlyList Tokens) : UnboundStatement(Tokens); - -public record UnboundWhile(IReadOnlyList Tokens, UnboundExpression Condition, UnboundBlock Body) : UnboundStatement(Tokens); \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Generics/Node/TypeSyntax.cs b/src/compiler/NubLang/Syntax/Generics/Node/TypeSyntax.cs deleted file mode 100644 index 07c0dd5..0000000 --- a/src/compiler/NubLang/Syntax/Generics/Node/TypeSyntax.cs +++ /dev/null @@ -1,36 +0,0 @@ -using NubLang.Syntax.Tokenization; - -namespace NubLang.Syntax.Generics.Node; - -public enum UnboundPrimitiveTypeKind -{ - I64, - I32, - I16, - I8, - U64, - U32, - U16, - U8, - F64, - F32, - Bool -} - -public abstract record UnboundType(IReadOnlyList Tokens) : UnboundNode(Tokens); - -public record UnboundFuncType(IReadOnlyList Tokens, IReadOnlyList Parameters, UnboundType ReturnType) : UnboundType(Tokens); - -public record UnboundPointerType(IReadOnlyList Tokens, UnboundType BaseType) : UnboundType(Tokens); - -public record UnboundVoidType(IReadOnlyList Tokens) : UnboundType(Tokens); - -public record UnboundPrimitiveType(IReadOnlyList Tokens, UnboundPrimitiveTypeKind SyntaxKind) : UnboundType(Tokens); - -public record UnboundCStringType(IReadOnlyList Tokens) : UnboundType(Tokens); - -public record UnboundStringType(IReadOnlyList Tokens) : UnboundType(Tokens); - -public record UnboundCustomType(IReadOnlyList Tokens, string Namespace, string Name, IReadOnlyList Arguments) : UnboundType(Tokens); - -public record UnboundArrayType(IReadOnlyList Tokens, UnboundType BaseType) : UnboundType(Tokens); \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Generics/Node/UnboundTree.cs b/src/compiler/NubLang/Syntax/Generics/Node/UnboundTree.cs deleted file mode 100644 index 0953e8f..0000000 --- a/src/compiler/NubLang/Syntax/Generics/Node/UnboundTree.cs +++ /dev/null @@ -1,10 +0,0 @@ -using NubLang.Diagnostics; -using NubLang.Syntax.Tokenization; - -namespace NubLang.Syntax.Generics.Node; - -public record UnboundTree(string Namespace, IReadOnlyList Definitions, IReadOnlyList Diagnostics); - -public abstract record UnboundNode(IReadOnlyList Tokens); - -public record UnboundBlock(IReadOnlyList Tokens, IReadOnlyList Statements) : UnboundNode(Tokens); \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/DefinitionSyntax.cs b/src/compiler/NubLang/Syntax/Parsing/Node/DefinitionSyntax.cs index 13efa0d..f07f51e 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Node/DefinitionSyntax.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Node/DefinitionSyntax.cs @@ -3,24 +3,123 @@ using NubLang.Syntax.Tokenization; namespace NubLang.Syntax.Parsing.Node; -public record GenericParameter(IReadOnlyList Tokens, string Name) : SyntaxNode(Tokens); +public record GenericParameter(IReadOnlyList Tokens, string Name) : SyntaxNode(Tokens) +{ + public override IEnumerable GetChildren() => []; +} public abstract record DefinitionSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters) : SyntaxNode(Tokens); -public record FuncParameterSyntax(IReadOnlyList Tokens, string Name, TypeSyntax Type) : SyntaxNode(Tokens); +public record FuncParameterSyntax(IReadOnlyList Tokens, string Name, TypeSyntax Type) : SyntaxNode(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Type; + } +} -public record FuncSignatureSyntax(IReadOnlyList Tokens, IReadOnlyList Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens); +public record FuncSignatureSyntax(IReadOnlyList Tokens, IReadOnlyList Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens) +{ + public override IEnumerable GetChildren() + { + foreach (var parameter in Parameters) + { + yield return parameter; + } -public record LocalFuncSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Tokens, Namespace, Parameters); + yield return ReturnType; + } +} -public record ExternFuncSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Tokens, Namespace, Parameters); +public record LocalFuncSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Tokens, Namespace, Parameters) +{ + public override IEnumerable GetChildren() + { + foreach (var parameter in Parameters) + { + yield return parameter; + } -public record StructFieldSyntax(IReadOnlyList Tokens, int Index, string Name, TypeSyntax Type, Optional Value) : SyntaxNode(Tokens); + yield return Signature; + yield return Body; + } +} -public record StructFuncSyntax(IReadOnlyList Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : SyntaxNode(Tokens); +public record ExternFuncSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Tokens, Namespace, Parameters) +{ + public override IEnumerable GetChildren() + { + foreach (var parameter in Parameters) + { + yield return parameter; + } -public record StructSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, IReadOnlyList Fields, IReadOnlyList Funcs) : DefinitionSyntax(Tokens, Namespace, Parameters); + yield return Signature; + } +} -public record InterfaceFuncSyntax(IReadOnlyList Tokens, string Name, FuncSignatureSyntax Signature) : SyntaxNode(Tokens); +public record StructFieldSyntax(IReadOnlyList Tokens, int Index, string Name, TypeSyntax Type, Optional Value) : SyntaxNode(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Type; + if (Value.HasValue) + { + yield return Value.Value; + } + } +} -public record InterfaceSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, IReadOnlyList Functions) : DefinitionSyntax(Tokens, Namespace, Parameters); \ No newline at end of file +public record StructFuncSyntax(IReadOnlyList Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : SyntaxNode(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Signature; + yield return Body; + } +} + +public record StructSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, IReadOnlyList Fields, IReadOnlyList Functions) : DefinitionSyntax(Tokens, Namespace, Parameters) +{ + public override IEnumerable GetChildren() + { + foreach (var parameter in Parameters) + { + yield return parameter; + } + + foreach (var field in Fields) + { + yield return field; + } + + foreach (var func in Functions) + { + yield return func; + } + } +} + +public record InterfaceFuncSyntax(IReadOnlyList Tokens, string Name, FuncSignatureSyntax Signature) : SyntaxNode(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Signature; + } +} + +public record InterfaceSyntax(IReadOnlyList Tokens, string Namespace, IReadOnlyList Parameters, string Name, IReadOnlyList Functions) : DefinitionSyntax(Tokens, Namespace, Parameters) +{ + public override IEnumerable GetChildren() + { + foreach (var parameter in Parameters) + { + yield return parameter; + } + + foreach (var func in Functions) + { + yield return func; + } + } +} \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/ExpressionSyntax.cs b/src/compiler/NubLang/Syntax/Parsing/Node/ExpressionSyntax.cs index 32702b2..44983f1 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Node/ExpressionSyntax.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Node/ExpressionSyntax.cs @@ -25,28 +25,113 @@ public enum BinaryOperator public abstract record ExpressionSyntax(IReadOnlyList Tokens) : SyntaxNode(Tokens); -public record BinaryExpressionSyntax(IReadOnlyList Tokens, ExpressionSyntax Left, BinaryOperator Operator, ExpressionSyntax Right) : ExpressionSyntax(Tokens); +public record BinaryExpressionSyntax(IReadOnlyList Tokens, ExpressionSyntax Left, BinaryOperator Operator, ExpressionSyntax Right) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Left; + yield return Right; + } +} -public record UnaryExpressionSyntax(IReadOnlyList Tokens, UnaryOperator Operator, ExpressionSyntax Operand) : ExpressionSyntax(Tokens); +public record UnaryExpressionSyntax(IReadOnlyList Tokens, UnaryOperator Operator, ExpressionSyntax Operand) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Operand; + } +} -public record FuncCallSyntax(IReadOnlyList Tokens, ExpressionSyntax Expression, IReadOnlyList Parameters) : ExpressionSyntax(Tokens); +public record FuncCallSyntax(IReadOnlyList Tokens, ExpressionSyntax Expression, IReadOnlyList Parameters) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Expression; + foreach (var parameter in Parameters) + { + yield return parameter; + } + } +} -public record IdentifierSyntax(IReadOnlyList Tokens, Optional Namespace, string Name) : ExpressionSyntax(Tokens); +public record IdentifierSyntax(IReadOnlyList Tokens, Optional Namespace, string Name) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} -public record ArrayInitializerSyntax(IReadOnlyList Tokens, ExpressionSyntax Capacity, TypeSyntax ElementType) : ExpressionSyntax(Tokens); +public record ArrayInitializerSyntax(IReadOnlyList Tokens, ExpressionSyntax Capacity, TypeSyntax ElementType) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Capacity; + yield return ElementType; + } +} -public record ArrayIndexAccessSyntax(IReadOnlyList Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens); +public record ArrayIndexAccessSyntax(IReadOnlyList Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Target; + yield return Index; + } +} -public record ArrowFuncParameterSyntax(IReadOnlyList Tokens, string Name) : ExpressionSyntax(Tokens); +public record ArrowFuncParameterSyntax(IReadOnlyList Tokens, string Name) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} -public record ArrowFuncSyntax(IReadOnlyList Tokens, IReadOnlyList Parameters, BlockSyntax Body) : ExpressionSyntax(Tokens); +public record ArrowFuncSyntax(IReadOnlyList Tokens, IReadOnlyList Parameters, BlockSyntax Body) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + foreach (var parameter in Parameters) + { + yield return parameter; + } -public record AddressOfSyntax(IReadOnlyList Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens); + yield return Body; + } +} -public record LiteralSyntax(IReadOnlyList Tokens, string Value, LiteralKind Kind) : ExpressionSyntax(Tokens); +public record AddressOfSyntax(IReadOnlyList Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Expression; + } +} -public record MemberAccessSyntax(IReadOnlyList Tokens, ExpressionSyntax Target, string Member) : ExpressionSyntax(Tokens); +public record LiteralSyntax(IReadOnlyList Tokens, string Value, LiteralKind Kind) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} -public record StructInitializerSyntax(IReadOnlyList Tokens, TypeSyntax StructType, Dictionary Initializers) : ExpressionSyntax(Tokens); +public record MemberAccessSyntax(IReadOnlyList Tokens, ExpressionSyntax Target, string Member) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Target; + } +} -public record DereferenceSyntax(IReadOnlyList Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens); \ No newline at end of file +public record StructInitializerSyntax(IReadOnlyList Tokens, TypeSyntax StructType, Dictionary Initializers) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return StructType; + foreach (var initializer in Initializers) + { + yield return initializer.Value; + } + } +} + +public record DereferenceSyntax(IReadOnlyList Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Expression; + } +} \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/ParseTree.cs b/src/compiler/NubLang/Syntax/Parsing/Node/ParseTree.cs deleted file mode 100644 index 2fe9f0f..0000000 --- a/src/compiler/NubLang/Syntax/Parsing/Node/ParseTree.cs +++ /dev/null @@ -1,10 +0,0 @@ -using NubLang.Diagnostics; -using NubLang.Syntax.Tokenization; - -namespace NubLang.Syntax.Parsing.Node; - -public record ParseTree(string Namespace, IReadOnlyList Definitions, IReadOnlyList Diagnostics); - -public abstract record SyntaxNode(IReadOnlyList Tokens); - -public record BlockSyntax(IReadOnlyList Tokens, IReadOnlyList Statements) : SyntaxNode(Tokens); \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/StatementSyntax.cs b/src/compiler/NubLang/Syntax/Parsing/Node/StatementSyntax.cs index 73fcb3e..e4a90dd 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Node/StatementSyntax.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Node/StatementSyntax.cs @@ -3,20 +3,83 @@ using NubLang.Syntax.Tokenization; namespace NubLang.Syntax.Parsing.Node; -public record StatementSyntax(IReadOnlyList Tokens) : SyntaxNode(Tokens); +public abstract record StatementSyntax(IReadOnlyList Tokens) : SyntaxNode(Tokens); -public record StatementExpressionSyntax(IReadOnlyList Tokens, ExpressionSyntax Expression) : StatementSyntax(Tokens); +public record StatementExpressionSyntax(IReadOnlyList Tokens, ExpressionSyntax Expression) : StatementSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Expression; + } +} -public record ReturnSyntax(IReadOnlyList Tokens, Optional Value) : StatementSyntax(Tokens); +public record ReturnSyntax(IReadOnlyList Tokens, Optional Value) : StatementSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + if (Value.HasValue) + { + yield return Value.Value; + } + } +} -public record AssignmentSyntax(IReadOnlyList Tokens, ExpressionSyntax Target, ExpressionSyntax Value) : StatementSyntax(Tokens); +public record AssignmentSyntax(IReadOnlyList Tokens, ExpressionSyntax Target, ExpressionSyntax Value) : StatementSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Target; + yield return Value; + } +} -public record IfSyntax(IReadOnlyList Tokens, ExpressionSyntax Condition, BlockSyntax Body, Optional> Else) : StatementSyntax(Tokens); +public record IfSyntax(IReadOnlyList Tokens, ExpressionSyntax Condition, BlockSyntax Body, Optional> Else) : StatementSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return Condition; + yield return Body; + if (Else.HasValue) + { + if (Else.Value.IsCase1(out var elseIf)) + { + yield return elseIf; + } + else if (Else.Value.IsCase2(out var @else)) + { + yield return @else; + } + } + } +} -public record VariableDeclarationSyntax(IReadOnlyList Tokens, string Name, Optional ExplicitType, Optional Assignment) : StatementSyntax(Tokens); +public record VariableDeclarationSyntax(IReadOnlyList Tokens, string Name, Optional ExplicitType, Optional Assignment) : StatementSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + if (ExplicitType.HasValue) + { + yield return ExplicitType.Value; + } -public record ContinueSyntax(IReadOnlyList Tokens) : StatementSyntax(Tokens); + if (Assignment.HasValue) + { + yield return Assignment.Value; + } + } +} -public record BreakSyntax(IReadOnlyList Tokens) : StatementSyntax(Tokens); +public record ContinueSyntax(IReadOnlyList Tokens) : StatementSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} -public record WhileSyntax(IReadOnlyList Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens); \ No newline at end of file +public record BreakSyntax(IReadOnlyList Tokens) : StatementSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} + +public record WhileSyntax(IReadOnlyList Tokens, ExpressionSyntax Condition, BlockSyntax Body) : StatementSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/SyntaxNode.cs b/src/compiler/NubLang/Syntax/Parsing/Node/SyntaxNode.cs new file mode 100644 index 0000000..4867206 --- /dev/null +++ b/src/compiler/NubLang/Syntax/Parsing/Node/SyntaxNode.cs @@ -0,0 +1,41 @@ +using NubLang.Diagnostics; +using NubLang.Syntax.Tokenization; + +namespace NubLang.Syntax.Parsing.Node; + +public abstract record SyntaxNode(IReadOnlyList Tokens) +{ + public abstract IEnumerable GetChildren(); + + public IEnumerable GetDescendants() + { + yield return this; + + foreach (var child in GetChildren()) + { + foreach (var desc in child.GetDescendants()) + { + yield return desc; + } + } + } +} + +public record SyntaxTree(IReadOnlyList Tokens, string Namespace, IReadOnlyList Definitions, IReadOnlyList Diagnostics) : SyntaxNode(Tokens) +{ + public override IEnumerable GetChildren() + { + foreach (var definition in Definitions) + { + yield return definition; + } + } +} + +public record BlockSyntax(IReadOnlyList Tokens, IReadOnlyList Statements) : SyntaxNode(Tokens) +{ + public override IEnumerable GetChildren() + { + return Statements; + } +} \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/TypeSyntax.cs b/src/compiler/NubLang/Syntax/Parsing/Node/TypeSyntax.cs index d8f1c5f..68482df 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Node/TypeSyntax.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Node/TypeSyntax.cs @@ -36,20 +36,67 @@ public abstract record TypeSyntax(IReadOnlyList Tokens) : SyntaxNode(Toke } } -public record FuncTypeSyntax(IReadOnlyList Tokens, IReadOnlyList Parameters, TypeSyntax ReturnType) : TypeSyntax(Tokens); +public record FuncTypeSyntax(IReadOnlyList Tokens, IReadOnlyList Parameters, TypeSyntax ReturnType) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + foreach (var parameter in Parameters) + { + yield return parameter; + } -public record PointerTypeSyntax(IReadOnlyList Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens); + yield return ReturnType; + } +} -public record VoidTypeSyntax(IReadOnlyList Tokens) : TypeSyntax(Tokens); +public record PointerTypeSyntax(IReadOnlyList Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return BaseType; + } +} -public record PrimitiveTypeSyntax(IReadOnlyList Tokens, PrimitiveTypeSyntaxKind SyntaxKind) : TypeSyntax(Tokens); +public record VoidTypeSyntax(IReadOnlyList Tokens) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} -public record CStringTypeSyntax(IReadOnlyList Tokens) : TypeSyntax(Tokens); +public record PrimitiveTypeSyntax(IReadOnlyList Tokens, PrimitiveTypeSyntaxKind SyntaxKind) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} -public record StringTypeSyntax(IReadOnlyList Tokens) : TypeSyntax(Tokens); +public record CStringTypeSyntax(IReadOnlyList Tokens) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} -public record CustomTypeSyntax(IReadOnlyList Tokens, string Namespace, string Name, IReadOnlyList Arguments) : TypeSyntax(Tokens); +public record StringTypeSyntax(IReadOnlyList Tokens) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} -public record GenericTypeSyntax(IReadOnlyList Tokens, string Name) : TypeSyntax(Tokens); +public record CustomTypeSyntax(IReadOnlyList Tokens, string Namespace, string Name, IReadOnlyList Arguments) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + foreach (var argument in Arguments) + { + yield return argument; + } + } +} -public record ArrayTypeSyntax(IReadOnlyList Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens); \ No newline at end of file +public record GenericTypeSyntax(IReadOnlyList Tokens, string Name) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() => []; +} + +public record ArrayTypeSyntax(IReadOnlyList Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens) +{ + public override IEnumerable GetChildren() + { + yield return BaseType; + } +} \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Parsing/Parser.cs b/src/compiler/NubLang/Syntax/Parsing/Parser.cs index 39eb1bd..8fc227b 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Parser.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Parser.cs @@ -12,7 +12,7 @@ public sealed class Parser private readonly IReadOnlyList _tokens; private readonly List _diagnostics = []; - private readonly List _genericParameters = []; + private List _genericParameters = []; private int _tokenIndex; public Parser(IReadOnlyList tokens) @@ -21,10 +21,10 @@ public sealed class Parser _tokens = tokens; } - public ParseTree Parse() + public SyntaxTree Parse() { _diagnostics.Clear(); - _genericParameters.Clear(); + _genericParameters = []; _tokenIndex = 0; if (TryExpectSymbol(Symbol.Namespace)) @@ -36,7 +36,7 @@ public sealed class Parser while (Peek().HasValue) { - _genericParameters.Clear(); + _genericParameters = []; var startIndex = _tokenIndex; try @@ -95,7 +95,7 @@ public sealed class Parser } } - return new ParseTree(_namespace, definitions, _diagnostics); + return new SyntaxTree(_tokens, _namespace, definitions, _diagnostics); } private FuncSignatureSyntax ParseFuncSignature(FuncParameterSyntax? thisArg = null) @@ -140,17 +140,17 @@ public sealed class Parser return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type); } - private DefinitionSyntax ParseExtern(int startIndex, IdentifierToken name, IReadOnlyList templateParameters) + private DefinitionSyntax ParseExtern(int startIndex, IdentifierToken name, IReadOnlyList genericParameters) { var keyword = ExpectSymbol(); return keyword.Symbol switch { - Symbol.Func => ParseExternFunc(startIndex, name, templateParameters), + Symbol.Func => ParseExternFunc(startIndex, name, genericParameters), _ => throw new ParseException(Diagnostic.Error($"Unexpected symbol {keyword.Symbol} after extern declaration").At(keyword).Build()) }; } - private ExternFuncSyntax ParseExternFunc(int startIndex, IdentifierToken name, IReadOnlyList templateParameters) + private ExternFuncSyntax ParseExternFunc(int startIndex, IdentifierToken name, IReadOnlyList genericParameters) { var callName = name.Value; @@ -161,18 +161,18 @@ public sealed class Parser var signature = ParseFuncSignature(); - return new ExternFuncSyntax(GetTokens(startIndex), _namespace, templateParameters, name.Value, callName, signature); + return new ExternFuncSyntax(GetTokens(startIndex), _namespace, genericParameters, name.Value, callName, signature); } - private LocalFuncSyntax ParseFunc(int startIndex, IdentifierToken name, IReadOnlyList templateParameters) + private LocalFuncSyntax ParseFunc(int startIndex, IdentifierToken name, IReadOnlyList genericParameters) { var signature = ParseFuncSignature(); var body = ParseBlock(); - return new LocalFuncSyntax(GetTokens(startIndex), _namespace, templateParameters, name.Value, signature, body); + return new LocalFuncSyntax(GetTokens(startIndex), _namespace, genericParameters, name.Value, signature, body); } - private DefinitionSyntax ParseStruct(int startIndex, IdentifierToken name, IReadOnlyList templateParameters) + private DefinitionSyntax ParseStruct(int startIndex, IdentifierToken name, IReadOnlyList genericParameters) { ExpectSymbol(Symbol.OpenBrace); @@ -188,7 +188,7 @@ public sealed class Parser if (TryExpectSymbol(Symbol.Func)) { var funcName = ExpectIdentifier().Value; - var thisArg = new FuncParameterSyntax([], "this", new CustomTypeSyntax([], _namespace, name.Value, templateParameters.Select(x => new GenericTypeSyntax(x.Tokens, x.Name)).ToList())); + var thisArg = new FuncParameterSyntax([], "this", new CustomTypeSyntax([], _namespace, name.Value, genericParameters.Select(x => new GenericTypeSyntax(x.Tokens, x.Name)).ToList())); var funcSignature = ParseFuncSignature(thisArg); var funcBody = ParseBlock(); @@ -211,10 +211,10 @@ public sealed class Parser } } - return new StructSyntax(GetTokens(startIndex), _namespace, templateParameters, name.Value, fields, funcs); + return new StructSyntax(GetTokens(startIndex), _namespace, genericParameters, name.Value, fields, funcs); } - private InterfaceSyntax ParseInterface(int startIndex, IdentifierToken name, IReadOnlyList templateParameters) + private InterfaceSyntax ParseInterface(int startIndex, IdentifierToken name, IReadOnlyList genericParameters) { ExpectSymbol(Symbol.OpenBrace); @@ -232,7 +232,7 @@ public sealed class Parser functions.Add(new InterfaceFuncSyntax(GetTokens(funcStartIndex), funcName, signature)); } - return new InterfaceSyntax(GetTokens(startIndex), _namespace, templateParameters, name.Value, functions); + return new InterfaceSyntax(GetTokens(startIndex), _namespace, genericParameters, name.Value, functions); } private StatementSyntax ParseStatement() @@ -689,7 +689,7 @@ public sealed class Parser } } - return new CustomTypeSyntax(GetTokens(startIndex), name.Value, @namespace, parameters); + return new CustomTypeSyntax(GetTokens(startIndex), @namespace, name.Value, parameters); } }