From 9a22198e49444bda0b5c70cfbbcfc97a1c6feda9 Mon Sep 17 00:00:00 2001 From: nub31 Date: Wed, 9 Jul 2025 22:53:45 +0200 Subject: [PATCH] Templates are working, but the code is ugly af --- example/src/main.nub | 11 + src/compiler/NubLang.CLI/Program.cs | 11 + .../HexString.cs | 4 +- src/compiler/NubLang/Syntax/Binding/Binder.cs | 14 +- .../NubLang/Syntax/Binding/DefinitionTable.cs | 8 +- .../NubLang/Syntax/Parsing/Node/SyntaxTree.cs | 2 +- .../NubLang/Syntax/Parsing/Node/TypeSyntax.cs | 25 +- src/compiler/NubLang/Syntax/Parsing/Parser.cs | 24 +- .../Syntax/Templating/TemplateGenerator.cs | 50 +++- .../Syntax/Templating/TemplateTable.cs | 16 +- .../Syntax/Templating/TypeTransformer.cs | 280 ++++++++++++++++++ 11 files changed, 417 insertions(+), 28 deletions(-) rename src/compiler/{NubLang.CLI => NubLang.Common}/HexString.cs (92%) create mode 100644 src/compiler/NubLang/Syntax/Templating/TypeTransformer.cs diff --git a/example/src/main.nub b/example/src/main.nub index 289a030..d86e614 100644 --- a/example/src/main.nub +++ b/example/src/main.nub @@ -10,6 +10,17 @@ func main(args: []cstring): i64 value = "bob" } + let box2 = alloc Box + { + value = "bob" + } + + let box3 = alloc Box + { + value = 23 + } + + c::puts(box.value) return 0 diff --git a/src/compiler/NubLang.CLI/Program.cs b/src/compiler/NubLang.CLI/Program.cs index d9ab13e..fddb627 100644 --- a/src/compiler/NubLang.CLI/Program.cs +++ b/src/compiler/NubLang.CLI/Program.cs @@ -1,6 +1,7 @@ using System.Reflection; using NubLang.CLI; using NubLang; +using NubLang.Common; using NubLang.Diagnostics; using NubLang.Generation; using NubLang.Generation.QBE; @@ -8,6 +9,7 @@ using NubLang.Syntax.Binding; using NubLang.Syntax.Binding.Node; using NubLang.Syntax.Parsing; using NubLang.Syntax.Parsing.Node; +using NubLang.Syntax.Templating; using NubLang.Syntax.Tokenization; using Binder = NubLang.Syntax.Binding.Binder; @@ -93,6 +95,15 @@ foreach (var file in options.Files) syntaxTrees[file] = syntaxTree; } +var templateTable = new TemplateTable(syntaxTrees.Values); + +foreach (var (file, syntaxTree) in syntaxTrees) +{ + var templateGenerator = new TemplateGenerator(syntaxTree, templateTable); + var definitions = templateGenerator.Generate(); + syntaxTrees[file] = syntaxTree with { Definitions = syntaxTree.Definitions.Concat(definitions).ToList() }; +} + var definitionTable = new DefinitionTable(syntaxTrees.Values); var boundSyntaxTrees = new Dictionary(); diff --git a/src/compiler/NubLang.CLI/HexString.cs b/src/compiler/NubLang.Common/HexString.cs similarity index 92% rename from src/compiler/NubLang.CLI/HexString.cs rename to src/compiler/NubLang.Common/HexString.cs index 29ac2a9..e5c2640 100644 --- a/src/compiler/NubLang.CLI/HexString.cs +++ b/src/compiler/NubLang.Common/HexString.cs @@ -1,6 +1,6 @@ -namespace NubLang.CLI; +namespace NubLang.Common; -internal static class HexString +public static class HexString { private static readonly HashSet _used = []; diff --git a/src/compiler/NubLang/Syntax/Binding/Binder.cs b/src/compiler/NubLang/Syntax/Binding/Binder.cs index 3f4bcba..d8918dc 100644 --- a/src/compiler/NubLang/Syntax/Binding/Binder.cs +++ b/src/compiler/NubLang/Syntax/Binding/Binder.cs @@ -406,7 +406,7 @@ public sealed class Binder if (boundExpression.Type is NubCustomType customType) { - var traits = _definitionTable.LookupTrait(customType.Namespace, customType.Name).ToArray(); + var traits = _definitionTable.LookupTrait(customType).ToArray(); if (traits.Length > 0) { if (traits.Length > 1) @@ -433,7 +433,7 @@ public sealed class Binder } } - var structs = _definitionTable.LookupStruct(customType.Namespace, customType.Name).ToArray(); + var structs = _definitionTable.LookupStruct(customType).ToArray(); if (structs.Length > 0) { if (structs.Length > 1) @@ -463,12 +463,14 @@ public sealed class Binder private BoundStructInitializer BindStructInitializer(StructInitializerSyntax expression) { - if (expression.StructType is not CustomTypeSyntax structType) + var boundType = BindType(expression.StructType); + + if (boundType is not NubCustomType structType) { throw new BindException(Diagnostic.Error($"Cannot initialize non-struct type {expression.StructType}").Build()); } - var structs = _definitionTable.LookupStruct(structType.Namespace, structType.Name).ToArray(); + var structs = _definitionTable.LookupStruct(structType).ToArray(); if (structs.Length == 0) { @@ -501,7 +503,7 @@ public sealed class Binder initializers[field] = BindExpression(initializer, BindType(fields[0].Type)); } - return new BoundStructInitializer(expression.Tokens, (NubCustomType)BindType(structType), initializers); + return new BoundStructInitializer(expression.Tokens, structType, initializers); } private BoundUnaryExpression BindUnaryExpression(UnaryExpressionSyntax expression) @@ -636,7 +638,7 @@ public sealed class Binder _ => throw new ArgumentOutOfRangeException() }), StringTypeSyntax => new NubStringType(), - TemplateTypeSyntax templateTypeSyntax => throw new NotImplementedException(), + TemplatedCustomTypeSyntax type => new NubCustomType(type.Namespace, type.MangledName()), VoidTypeSyntax => new NubVoidType(), _ => throw new ArgumentOutOfRangeException(nameof(node)) }; diff --git a/src/compiler/NubLang/Syntax/Binding/DefinitionTable.cs b/src/compiler/NubLang/Syntax/Binding/DefinitionTable.cs index 5d14b03..9dfc865 100644 --- a/src/compiler/NubLang/Syntax/Binding/DefinitionTable.cs +++ b/src/compiler/NubLang/Syntax/Binding/DefinitionTable.cs @@ -25,11 +25,11 @@ public class DefinitionTable .Where(x => x.Namespace == @namespace && x.Name == name); } - public IEnumerable LookupStruct(string @namespace, string name) + public IEnumerable LookupStruct(NubCustomType type) { return _definitions .OfType() - .Where(x => x.Namespace == @namespace && x.Name == name); + .Where(x => x.Namespace == type.Namespace && x.Name == type.Name); } public IEnumerable LookupStructField(StructSyntax structNode, string field) @@ -46,11 +46,11 @@ public class DefinitionTable // .Where(x => x.Name == name); // } - public IEnumerable LookupTrait(string @namespace, string name) + public IEnumerable LookupTrait(NubCustomType type) { return _definitions .OfType() - .Where(x => x.Namespace == @namespace && x.Name == name); + .Where(x => x.Namespace == type.Namespace && x.Name == type.Name); } public IEnumerable LookupTraitFunc(TraitSyntax trait, string name) diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/SyntaxTree.cs b/src/compiler/NubLang/Syntax/Parsing/Node/SyntaxTree.cs index bae6008..797984c 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Node/SyntaxTree.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Node/SyntaxTree.cs @@ -3,7 +3,7 @@ using NubLang.Syntax.Tokenization; namespace NubLang.Syntax.Parsing.Node; -public record SyntaxTree(string Namespace, IReadOnlyList Definitions, IReadOnlyList Templates, IReadOnlyList Diagnostics); +public record SyntaxTree(string Namespace, IReadOnlyList Definitions, IReadOnlyList Templates, IReadOnlyList ReferencedTemplatedCustomTypes, IReadOnlyList Diagnostics); public abstract record SyntaxNode(IReadOnlyList Tokens); diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/TypeSyntax.cs b/src/compiler/NubLang/Syntax/Parsing/Node/TypeSyntax.cs index ef26f09..f695adb 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Node/TypeSyntax.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Node/TypeSyntax.cs @@ -17,7 +17,26 @@ public enum PrimitiveTypeSyntaxKind Bool } -public abstract record TypeSyntax(IReadOnlyList Tokens) : SyntaxNode(Tokens); +public abstract record TypeSyntax(IReadOnlyList Tokens) : SyntaxNode(Tokens) +{ + public string MangledName() + { + return this switch + { + PrimitiveTypeSyntax primitive => primitive.SyntaxKind.ToString().ToLower(), + VoidTypeSyntax => "void", + CStringTypeSyntax => "cstring", + StringTypeSyntax => "string", + PointerTypeSyntax ptr => $"ptr_{ptr.BaseType.MangledName()}", + ArrayTypeSyntax arr => $"arr_{arr.BaseType.MangledName()}", + CustomTypeSyntax custom => $"{custom.Namespace}_{custom.Name}", + TemplateTypeSyntax template => $"tmpl_{template.Name}", + TemplatedCustomTypeSyntax tmpl => $"{tmpl.Namespace}_{tmpl.Name}_{string.Join("_", tmpl.Arguments.Select(x => x.MangledName()))}", + FuncTypeSyntax func => $"func_{string.Join("_", func.Parameters.Select(x => x.MangledName()))}_to_{func.ReturnType.MangledName()}", + _ => throw new NotSupportedException($"Unknown type syntax: {GetType().Name}") + }; + } +} public record FuncTypeSyntax(IReadOnlyList Tokens, IReadOnlyList Parameters, TypeSyntax ReturnType) : TypeSyntax(Tokens); @@ -33,6 +52,8 @@ public record StringTypeSyntax(IReadOnlyList Tokens) : TypeSyntax(Tokens) public record CustomTypeSyntax(IReadOnlyList Tokens, string Name, string Namespace) : TypeSyntax(Tokens); -public record TemplateTypeSyntax(IReadOnlyList Tokens, string Name, string Namespace, IReadOnlyList Arguments) : TypeSyntax(Tokens); +public record TemplatedCustomTypeSyntax(IReadOnlyList Tokens, string Namespace, string Name, IReadOnlyList Arguments) : TypeSyntax(Tokens); + +public record TemplateTypeSyntax(IReadOnlyList Tokens, string Name) : TypeSyntax(Tokens); public record ArrayTypeSyntax(IReadOnlyList Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens); \ 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 ac83f8e..8070b7a 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Parser.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Parser.cs @@ -1,7 +1,6 @@ using System.Diagnostics.CodeAnalysis; using NubLang.Common; using NubLang.Diagnostics; -using NubLang.Syntax.Binding; using NubLang.Syntax.Parsing.Node; using NubLang.Syntax.Tokenization; @@ -13,6 +12,8 @@ public sealed class Parser private readonly IReadOnlyList _tokens; private readonly List _diagnostics = []; + private readonly List _referencedTemplates = []; + private List _templateParameters = []; private int _tokenIndex; public Parser(IReadOnlyList tokens) @@ -23,7 +24,9 @@ public sealed class Parser public SyntaxTree Parse() { + _referencedTemplates.Clear(); _diagnostics.Clear(); + _templateParameters = []; _tokenIndex = 0; if (TryExpectSymbol(Symbol.Namespace)) @@ -42,18 +45,16 @@ public sealed class Parser { if (TryExpectSymbol(Symbol.Template)) { - var templateArguments = new List(); - ExpectSymbol(Symbol.LessThan); while (!TryExpectSymbol(Symbol.GreaterThan)) { - templateArguments.Add(ExpectIdentifier().Value); + _templateParameters.Add(ExpectIdentifier().Value); } ExpectSymbol(Symbol.Struct); var definition = ParseStruct(_tokenIndex); - templates.Add(new StructTemplateSyntax(GetTokens(startIndex), _namespace, templateArguments, definition)); + templates.Add(new StructTemplateSyntax(GetTokens(startIndex), _namespace, _templateParameters, definition)); } else { @@ -68,7 +69,7 @@ public sealed class Parser } } - return new SyntaxTree(_namespace, definitions, templates, _diagnostics); + return new SyntaxTree(_namespace, definitions, templates, _referencedTemplates, _diagnostics); } private DefinitionSyntax ParseDefinition(int startIndex) @@ -656,6 +657,11 @@ public sealed class Parser if (TryExpectIdentifier(out var name)) { + if (_templateParameters.Contains(name.Value)) + { + return new TemplateTypeSyntax(GetTokens(startIndex), name.Value); + } + return name.Value switch { "void" => new VoidTypeSyntax(GetTokens(startIndex)), @@ -692,10 +698,12 @@ public sealed class Parser parameters.Add(ParseType()); } - return new TemplateTypeSyntax(GetTokens(startIndex), @namespace, name.Value, parameters); + var template = new TemplatedCustomTypeSyntax(GetTokens(startIndex), @namespace, name.Value, parameters); + _referencedTemplates.Add(template); + return template; } - return new CustomTypeSyntax(GetTokens(startIndex), @namespace, name.Value); + return new CustomTypeSyntax(GetTokens(startIndex), name.Value, @namespace); } } diff --git a/src/compiler/NubLang/Syntax/Templating/TemplateGenerator.cs b/src/compiler/NubLang/Syntax/Templating/TemplateGenerator.cs index 86d033e..85825d2 100644 --- a/src/compiler/NubLang/Syntax/Templating/TemplateGenerator.cs +++ b/src/compiler/NubLang/Syntax/Templating/TemplateGenerator.cs @@ -1,3 +1,4 @@ +using NubLang.Diagnostics; using NubLang.Syntax.Parsing.Node; namespace NubLang.Syntax.Templating; @@ -7,8 +8,6 @@ public class TemplateGenerator private readonly SyntaxTree _syntaxTree; private readonly TemplateTable _templateTable; - private List _definitions = []; - public TemplateGenerator(SyntaxTree syntaxTree, TemplateTable templateTable) { _syntaxTree = syntaxTree; @@ -17,7 +16,50 @@ public class TemplateGenerator public IReadOnlyList Generate() { - _definitions.Clear(); - return _definitions; + var definitions = new List(); + + foreach (var type in _syntaxTree.ReferencedTemplatedCustomTypes) + { + definitions.Add(CreateDefinition(type)); + } + + return definitions; + } + + private DefinitionSyntax CreateDefinition(TemplatedCustomTypeSyntax type) + { + var structTemplates = _templateTable.LookupStructTemplate(type.Namespace, type.Name).ToArray(); + if (structTemplates.Length > 0) + { + if (structTemplates.Length > 1) + { + throw new TemplateGeneratorException(Diagnostic.Error($"Struct template {type.Namespace}::{type.Name} has multiple definitions").Build()); + } + + var structTemplate = structTemplates[0]; + + var transformations = new Dictionary(); + + for (var i = 0; i < structTemplate.TemplateParameters.Count; i++) + { + transformations[structTemplate.TemplateParameters[i]] = type.Arguments[i]; + } + + var transformer = new TypeTransformer(transformations); + var transformed = transformer.TransformStruct(structTemplate.Struct); + return transformed with { Name = type.MangledName() }; + } + + throw new TemplateGeneratorException(Diagnostic.Error($"Template {type.Namespace}::{type.Name} is not defined").Build()); + } +} + +public class TemplateGeneratorException : Exception +{ + public Diagnostic Diagnostic { get; } + + public TemplateGeneratorException(Diagnostic diagnostic) : base(diagnostic.Message) + { + Diagnostic = diagnostic; } } \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Templating/TemplateTable.cs b/src/compiler/NubLang/Syntax/Templating/TemplateTable.cs index a01b8ca..d6eb587 100644 --- a/src/compiler/NubLang/Syntax/Templating/TemplateTable.cs +++ b/src/compiler/NubLang/Syntax/Templating/TemplateTable.cs @@ -1,6 +1,20 @@ +using NubLang.Syntax.Parsing.Node; + namespace NubLang.Syntax.Templating; public class TemplateTable { - + private readonly List _templates; + + public TemplateTable(IEnumerable syntaxTrees) + { + _templates = syntaxTrees.SelectMany(x => x.Templates).ToList(); + } + + public IEnumerable LookupStructTemplate(string @namespace, string name) + { + return _templates + .OfType() + .Where(x => x.Struct.Namespace == @namespace && x.Struct.Name == @name); + } } \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Templating/TypeTransformer.cs b/src/compiler/NubLang/Syntax/Templating/TypeTransformer.cs new file mode 100644 index 0000000..d97f782 --- /dev/null +++ b/src/compiler/NubLang/Syntax/Templating/TypeTransformer.cs @@ -0,0 +1,280 @@ +using NubLang.Common; +using NubLang.Syntax.Parsing.Node; + +namespace NubLang.Syntax.Templating; + +public class TypeTransformer +{ + private readonly Dictionary _transformations; + + public TypeTransformer(Dictionary transformations) + { + _transformations = transformations; + } + + public DefinitionSyntax TransformDefinition(DefinitionSyntax definition) + { + return definition switch + { + ExternFuncSyntax node => TransformExternFunc(node), + LocalFuncSyntax node => TransformLocalFunc(node), + StructSyntax node => TransformStruct(node), + TraitImplSyntax node => TransformTraitImpl(node), + TraitSyntax node => TransformTrait(node), + _ => throw new ArgumentOutOfRangeException(nameof(definition)) + }; + } + + public FuncSignatureSyntax TransformFuncSignature(FuncSignatureSyntax node) + { + var parameters = new List(); + + foreach (var parameter in node.Parameters) + { + parameters.Add(new FuncParameterSyntax(parameter.Tokens, parameter.Name, TransformType(parameter.Type))); + } + + return new FuncSignatureSyntax(node.Tokens, parameters, TransformType(node.ReturnType)); + } + + public ExternFuncSyntax TransformExternFunc(ExternFuncSyntax node) + { + return new ExternFuncSyntax(node.Tokens, node.Namespace, node.Name, node.CallName, TransformFuncSignature(node.Signature)); + } + + public LocalFuncSyntax TransformLocalFunc(LocalFuncSyntax node) + { + return new LocalFuncSyntax(node.Tokens, node.Namespace, node.Name, TransformFuncSignature(node.Signature), TransformBlock(node.Body)); + } + + public StructSyntax TransformStruct(StructSyntax node) + { + var fields = new List(); + + foreach (var field in node.Fields) + { + var value = Optional.Empty(); + if (field.Value.HasValue) + { + value = TransformExpression(field.Value.Value); + } + + fields.Add(new StructFieldSyntax(field.Tokens, field.Index, field.Name, TransformType(field.Type), value)); + } + + return new StructSyntax(node.Tokens, node.Namespace, node.Name, fields); + } + + public TraitImplSyntax TransformTraitImpl(TraitImplSyntax node) + { + var functions = new List(); + + foreach (var function in node.Functions) + { + functions.Add(new TraitFuncImplSyntax(function.Tokens, function.Name, TransformFuncSignature(function.Signature), TransformBlock(function.Body))); + } + + return new TraitImplSyntax(node.Tokens, node.Namespace, TransformType(node.TraitType), TransformType(node.ForType), functions); + } + + public TraitSyntax TransformTrait(TraitSyntax node) + { + var functions = new List(); + + foreach (var function in node.Functions) + { + functions.Add(new TraitFuncSyntax(function.Tokens, function.Name, TransformFuncSignature(function.Signature))); + } + + return new TraitSyntax(node.Tokens, node.Namespace, node.Name, functions); + } + + public BlockSyntax TransformBlock(BlockSyntax block) + { + var statements = new List(); + + foreach (var statement in block.Statements) + { + statements.Add(TransformStatement(statement)); + } + + return new BlockSyntax(block.Tokens, statements); + } + + public StatementSyntax TransformStatement(StatementSyntax statement) + { + return statement switch + { + AssignmentSyntax node => TransformAssignment(node), + BreakSyntax node => new BreakSyntax(node.Tokens), + ContinueSyntax node => new ContinueSyntax(node.Tokens), + IfSyntax node => TransformIf(node), + ReturnSyntax node => TransformReturn(node), + StatementExpressionSyntax node => new StatementExpressionSyntax(node.Tokens, TransformExpression(node.Expression)), + VariableDeclarationSyntax node => TransformVariableDeclaration(node), + WhileSyntax node => new WhileSyntax(node.Tokens, TransformExpression(node.Condition), TransformBlock(node.Body)), + _ => throw new ArgumentOutOfRangeException(nameof(statement)) + }; + } + + public AssignmentSyntax TransformAssignment(AssignmentSyntax node) + { + return new AssignmentSyntax(node.Tokens, TransformExpression(node.Target), TransformExpression(node.Value)); + } + + public IfSyntax TransformIf(IfSyntax node) + { + var elseStatement = Optional.Empty>(); + if (node.Else.HasValue) + { + elseStatement = node.Else.Value.Match>(x => TransformIf(x), x => TransformBlock(x)); + } + + return new IfSyntax(node.Tokens, TransformExpression(node.Condition), TransformBlock(node.Body), elseStatement); + } + + public ReturnSyntax TransformReturn(ReturnSyntax node) + { + var value = Optional.Empty(); + if (node.Value.HasValue) + { + value = TransformExpression(node.Value.Value); + } + + return new ReturnSyntax(node.Tokens, value); + } + + public VariableDeclarationSyntax TransformVariableDeclaration(VariableDeclarationSyntax node) + { + var explicitType = Optional.Empty(); + if (node.ExplicitType.HasValue) + { + throw new NotImplementedException(); + } + + var assignment = Optional.Empty(); + if (node.Assignment.HasValue) + { + assignment = TransformExpression(node.Assignment.Value); + } + + return new VariableDeclarationSyntax(node.Tokens, node.Name, explicitType, assignment); + } + + public ExpressionSyntax TransformExpression(ExpressionSyntax expression) + { + return expression switch + { + AddressOfSyntax node => TransformAddressOf(node), + ArrayIndexAccessSyntax node => TransformArrayIndexAccess(node), + ArrayInitializerSyntax node => TransformArrayInitializer(node), + ArrowFuncParameterSyntax node => TransformArrowFuncParameter(node), + ArrowFuncSyntax node => TransformArrowFunc(node), + BinaryExpressionSyntax node => TransformBinaryExpression(node), + DereferenceSyntax node => TransformDereference(node), + FuncCallSyntax node => TransformFuncCall(node), + IdentifierSyntax node => TransformIdentifier(node), + LiteralSyntax node => TransformLiteral(node), + MemberAccessSyntax node => TransformMemberAccess(node), + StructInitializerSyntax node => TransformStructInitializer(node), + UnaryExpressionSyntax node => TransformUnaryExpression(node), + _ => throw new ArgumentOutOfRangeException(nameof(expression)) + }; + } + + public AddressOfSyntax TransformAddressOf(AddressOfSyntax node) + { + return new AddressOfSyntax(node.Tokens, TransformExpression(node.Expression)); + } + + public ArrayIndexAccessSyntax TransformArrayIndexAccess(ArrayIndexAccessSyntax node) + { + return new ArrayIndexAccessSyntax(node.Tokens, TransformExpression(node.Target), TransformExpression(node.Index)); + } + + public ArrayInitializerSyntax TransformArrayInitializer(ArrayInitializerSyntax node) + { + return new ArrayInitializerSyntax(node.Tokens, TransformExpression(node.Capacity), TransformType(node.ElementType)); + } + + public ArrowFuncParameterSyntax TransformArrowFuncParameter(ArrowFuncParameterSyntax node) + { + return new ArrowFuncParameterSyntax(node.Tokens, node.Name); + } + + public ArrowFuncSyntax TransformArrowFunc(ArrowFuncSyntax node) + { + var parameters = new List(); + + foreach (var parameter in node.Parameters) + { + parameters.Add(TransformArrowFuncParameter(parameter)); + } + + return new ArrowFuncSyntax(node.Tokens, parameters, TransformBlock(node.Body)); + } + + public BinaryExpressionSyntax TransformBinaryExpression(BinaryExpressionSyntax node) + { + return new BinaryExpressionSyntax(node.Tokens, TransformExpression(node.Left), node.Operator, TransformExpression(node.Right)); + } + + public DereferenceSyntax TransformDereference(DereferenceSyntax node) + { + return new DereferenceSyntax(node.Tokens, TransformExpression(node.Expression)); + } + + public FuncCallSyntax TransformFuncCall(FuncCallSyntax node) + { + var parameters = new List(); + + foreach (var parameter in node.Parameters) + { + parameters.Add(TransformExpression(parameter)); + } + + return new FuncCallSyntax(node.Tokens, TransformExpression(node.Expression), parameters); + } + + public IdentifierSyntax TransformIdentifier(IdentifierSyntax node) + { + return new IdentifierSyntax(node.Tokens, node.Namespace, node.Name); + } + + public LiteralSyntax TransformLiteral(LiteralSyntax node) + { + return new LiteralSyntax(node.Tokens, node.Literal, node.Kind); + } + + public MemberAccessSyntax TransformMemberAccess(MemberAccessSyntax node) + { + return new MemberAccessSyntax(node.Tokens, TransformExpression(node.Target), node.Member); + } + + public StructInitializerSyntax TransformStructInitializer(StructInitializerSyntax node) + { + var initializers = new Dictionary(); + + foreach (var (field, value) in node.Initializers) + { + initializers.Add(field, TransformExpression(value)); + } + + return new StructInitializerSyntax(node.Tokens, TransformType(node.StructType), initializers); + } + + public UnaryExpressionSyntax TransformUnaryExpression(UnaryExpressionSyntax node) + { + return new UnaryExpressionSyntax(node.Tokens, node.Operator, TransformExpression(node.Operand)); + } + + public TypeSyntax TransformType(TypeSyntax node) + { + if (node is TemplateTypeSyntax templateType) + { + return _transformations[templateType.Name]; + } + + return node; + } +} \ No newline at end of file