diff --git a/example/src/main.nub b/example/src/main.nub index 1b0f580..e6f514b 100644 --- a/example/src/main.nub +++ b/example/src/main.nub @@ -23,11 +23,12 @@ func main(args: []cstring): i64 age = "23" } - puts(x.name.last) + test(x&) return 0 } -func test(test: u32) +func test(human: ^Human) { + puts(human^.name.last) } \ No newline at end of file diff --git a/src/compiler/NubLang.CLI/GCC.cs b/src/compiler/NubLang.CLI/GCC.cs index 941ce17..db54016 100644 --- a/src/compiler/NubLang.CLI/GCC.cs +++ b/src/compiler/NubLang.CLI/GCC.cs @@ -7,7 +7,7 @@ public static class GCC public static async Task Assemble(string asmPath, string outPath) { using var process = new Process(); - process.StartInfo = new ProcessStartInfo("gcc", ["-xassembler", "-c", "-o", outPath, asmPath]) + process.StartInfo = new ProcessStartInfo("gcc", ["-xassembler", "-g", "-c", "-o", outPath, asmPath]) { UseShellExecute = false, RedirectStandardOutput = true, diff --git a/src/compiler/NubLang.CLI/Program.cs b/src/compiler/NubLang.CLI/Program.cs index 3f4f122..86fea89 100644 --- a/src/compiler/NubLang.CLI/Program.cs +++ b/src/compiler/NubLang.CLI/Program.cs @@ -99,7 +99,7 @@ for (var i = 0; i < typedSyntaxTrees.Count; i++) Directory.CreateDirectory(outFileDir); } - var generator = new QBEGenerator(syntaxTree, typedDefinitionTable); + var generator = new QBEGenerator(syntaxTree, typedDefinitionTable, options.Files[i].Path); var ssa = generator.Emit(); var ssaFilePath = Path.ChangeExtension(outFileName, "ssa"); diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs index 96b56aa..f640f4e 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -1,5 +1,4 @@ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text; using NubLang.Tokenization; @@ -11,6 +10,7 @@ public class QBEGenerator { private readonly TypedSyntaxTree _syntaxTree; private readonly TypedDefinitionTable _definitionTable; + private readonly string _sourceFileName; private readonly QBEWriter _writer; private readonly List _cStringLiterals = []; @@ -23,10 +23,11 @@ public class QBEGenerator private int _stringLiteralIndex; private bool _codeIsReachable = true; - public QBEGenerator(TypedSyntaxTree syntaxTree, TypedDefinitionTable definitionTable) + public QBEGenerator(TypedSyntaxTree syntaxTree, TypedDefinitionTable definitionTable, string sourceFileName) { _syntaxTree = syntaxTree; _definitionTable = definitionTable; + _sourceFileName = sourceFileName; _writer = new QBEWriter(); } @@ -42,6 +43,8 @@ public class QBEGenerator _stringLiteralIndex = 0; _codeIsReachable = true; + _writer.WriteLine($"dbgfile \"{_sourceFileName}\""); + foreach (var structDef in _definitionTable.GetStructs()) { EmitStructTypeDefinition(structDef); @@ -260,39 +263,22 @@ public class QBEGenerator } } - private bool EmitTryCreateWithoutCopy(ExpressionNode source, [NotNullWhen(true)] out string? destination) + private string EmitCreateCopy(ExpressionNode source) { - switch (source) + // Allowlist for types which are safe to not copy + if (source is ArrayInitializerNode or StructInitializerNode or ConvertToInterfaceNode or LiteralNode) { - case ArrayInitializerNode: - case StructInitializerNode: - case LiteralNode { Kind: LiteralKind.String }: - { - destination = EmitExpression(source); - return true; - } + return EmitExpression(source); } - destination = null; - return false; - } - - private string EmitCreateCopyOrInitialize(ExpressionNode source) - { - // If the source is a value which is not used yet such as an array/struct/interface initializer or literal, we can skip copying - if (EmitTryCreateWithoutCopy(source, out var uncopiedValue)) - { - return uncopiedValue; - } - - var value = EmitExpression(source); - + // Simple types are passed in registers and therefore always copied if (source.Type.IsSimpleType(out _, out var complexType)) { - // Simple types are passed in registers and are therefore always copied - return value; + return EmitExpression(source); } + // For the rest, we figure out the size of the type and shallow copy them + var value = EmitExpression(source); var size = complexType switch { ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value), @@ -474,6 +460,12 @@ public class QBEGenerator private void EmitStatement(StatementNode statement) { + var tokens = statement.Tokens.ToArray(); + if (tokens.Length != 0) + { + _writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}"); + } + switch (statement) { case AssignmentNode assignment: @@ -589,6 +581,12 @@ public class QBEGenerator private string EmitExpression(ExpressionNode expression) { + var tokens = expression.Tokens.ToArray(); + if (tokens.Length != 0) + { + _writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}"); + } + return expression switch { ArrayInitializerNode arrayInitializer => EmitArrayInitializer(arrayInitializer), @@ -616,7 +614,13 @@ public class QBEGenerator private string EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess) { - return EmitLoad(arrayIndexAccess.Type, EmitAddressOfArrayIndexAccess(arrayIndexAccess)); + var address = EmitAddressOfArrayIndexAccess(arrayIndexAccess); + if (arrayIndexAccess.Type is StructTypeNode) + { + return address; + } + + return EmitLoad(arrayIndexAccess.Type, address); } private void EmitArrayBoundsCheck(string array, string index) @@ -666,7 +670,13 @@ public class QBEGenerator private string EmitDereference(DereferenceNode dereference) { - return EmitLoad(dereference.Type, EmitExpression(dereference.Expression)); + var address = EmitExpression(dereference.Expression); + if (dereference.Type is StructTypeNode) + { + return address; + } + + return EmitLoad(dereference.Type, address); } private string EmitAddressOf(AddressOfNode addressOf) @@ -901,10 +911,12 @@ public class QBEGenerator private string EmitVariableIdent(VariableIdentNode variableIdent) { var address = EmitAddressOfVariableIdent(variableIdent); + if (variableIdent.Type is StructTypeNode) + { + return address; + } - return variableIdent.Type.IsSimpleType(out _, out _) - ? EmitLoad(variableIdent.Type, address) - : address; + return EmitLoad(variableIdent.Type, address); } private string EmitFuncParameterIdent(FuncParameterIdentNode funcParameterIdent) @@ -1075,13 +1087,11 @@ public class QBEGenerator private string EmitStructFieldAccess(StructFieldAccessNode structFieldAccess) { var address = EmitAddressOfStructFieldAccess(structFieldAccess); - - // Inline structs should not be loaded if (structFieldAccess.Type is StructTypeNode) { return address; } - + return EmitLoad(structFieldAccess.Type, address); } @@ -1096,7 +1106,7 @@ public class QBEGenerator foreach (var parameter in structFuncCall.Parameters) { - var copy = EmitCreateCopyOrInitialize(parameter); + var copy = EmitCreateCopy(parameter); parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); } @@ -1138,7 +1148,7 @@ public class QBEGenerator foreach (var parameter in interfaceFuncCall.Parameters) { - var copy = EmitCreateCopyOrInitialize(parameter); + var copy = EmitCreateCopy(parameter); parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); } @@ -1248,7 +1258,7 @@ public class QBEGenerator foreach (var parameter in funcCall.Parameters) { - var copy = EmitCreateCopyOrInitialize(parameter); + var copy = EmitCreateCopy(parameter); parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); } diff --git a/src/compiler/NubLang/TypeChecking/Node/DefinitionNode.cs b/src/compiler/NubLang/TypeChecking/Node/DefinitionNode.cs index ffabf2a..1afa33d 100644 --- a/src/compiler/NubLang/TypeChecking/Node/DefinitionNode.cs +++ b/src/compiler/NubLang/TypeChecking/Node/DefinitionNode.cs @@ -1,21 +1,23 @@ -namespace NubLang.TypeChecking.Node; +using NubLang.Tokenization; -public abstract record DefinitionNode : Node; +namespace NubLang.TypeChecking.Node; -public record FuncParameterNode(string Name, TypeNode Type) : Node; +public abstract record DefinitionNode(IEnumerable Tokens) : Node(Tokens); -public record FuncSignatureNode(IReadOnlyList Parameters, TypeNode ReturnType) : Node; +public record FuncParameterNode(string Name, TypeNode Type, IEnumerable Tokens) : Node(Tokens); -public record LocalFuncNode(string Name, FuncSignatureNode Signature, BlockNode Body) : DefinitionNode; +public record FuncSignatureNode(IReadOnlyList Parameters, TypeNode ReturnType, IEnumerable Tokens) : Node(Tokens); -public record ExternFuncNode(string Name, string CallName, FuncSignatureNode Signature) : DefinitionNode; +public record LocalFuncNode(string Name, FuncSignatureNode Signature, BlockNode Body, IEnumerable Tokens) : DefinitionNode(Tokens); -public record StructFieldNode(int Index, string Name, TypeNode Type, Optional Value) : Node; +public record ExternFuncNode(string Name, string CallName, FuncSignatureNode Signature, IEnumerable Tokens) : DefinitionNode(Tokens); -public record StructFuncNode(string Name, FuncSignatureNode Signature, BlockNode Body) : Node; +public record StructFieldNode(int Index, string Name, TypeNode Type, Optional Value, IEnumerable Tokens) : Node(Tokens); -public record StructNode(string Name, StructTypeNode Type, IReadOnlyList Fields, IReadOnlyList Functions, IReadOnlyList InterfaceImplementations) : DefinitionNode; +public record StructFuncNode(string Name, FuncSignatureNode Signature, BlockNode Body, IEnumerable Tokens) : Node(Tokens); -public record InterfaceFuncNode(string Name, FuncSignatureNode Signature) : Node; +public record StructNode(string Name, StructTypeNode Type, IReadOnlyList Fields, IReadOnlyList Functions, IReadOnlyList InterfaceImplementations, IEnumerable Tokens) : DefinitionNode(Tokens); -public record InterfaceNode(string Name, IReadOnlyList Functions) : DefinitionNode; \ No newline at end of file +public record InterfaceFuncNode(string Name, FuncSignatureNode Signature, IEnumerable Tokens) : Node(Tokens); + +public record InterfaceNode(string Name, IReadOnlyList Functions, IEnumerable Tokens) : DefinitionNode(Tokens); \ No newline at end of file diff --git a/src/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs b/src/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs index 0928db6..4f11b26 100644 --- a/src/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs +++ b/src/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs @@ -30,45 +30,45 @@ public enum BinaryOperator BitwiseOr } -public abstract record ExpressionNode(TypeNode Type) : Node; +public abstract record ExpressionNode(TypeNode Type, IEnumerable Tokens) : Node(Tokens); -public abstract record LValueExpressionNode(TypeNode Type) : RValueExpressionNode(Type); -public abstract record RValueExpressionNode(TypeNode Type) : ExpressionNode(Type); +public abstract record LValueExpressionNode(TypeNode Type, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); +public abstract record RValueExpressionNode(TypeNode Type, IEnumerable Tokens) : ExpressionNode(Type, Tokens); -public record BinaryExpressionNode(TypeNode Type, ExpressionNode Left, BinaryOperator Operator, ExpressionNode Right) : RValueExpressionNode(Type); +public record BinaryExpressionNode(TypeNode Type, ExpressionNode Left, BinaryOperator Operator, ExpressionNode Right, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record UnaryExpressionNode(TypeNode Type, UnaryOperator Operator, ExpressionNode Operand) : RValueExpressionNode(Type); +public record UnaryExpressionNode(TypeNode Type, UnaryOperator Operator, ExpressionNode Operand, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record FuncCallNode(TypeNode Type, ExpressionNode Expression, IReadOnlyList Parameters) : RValueExpressionNode(Type); +public record FuncCallNode(TypeNode Type, ExpressionNode Expression, IReadOnlyList Parameters, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record StructFuncCallNode(TypeNode Type, string Name, StructTypeNode StructType, ExpressionNode StructExpression, IReadOnlyList Parameters) : RValueExpressionNode(Type); +public record StructFuncCallNode(TypeNode Type, string Name, StructTypeNode StructType, ExpressionNode StructExpression, IReadOnlyList Parameters, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record InterfaceFuncCallNode(TypeNode Type, string Name, InterfaceTypeNode InterfaceType, ExpressionNode InterfaceExpression, IReadOnlyList Parameters) : RValueExpressionNode(Type); +public record InterfaceFuncCallNode(TypeNode Type, string Name, InterfaceTypeNode InterfaceType, ExpressionNode InterfaceExpression, IReadOnlyList Parameters, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record VariableIdentNode(TypeNode Type, string Name) : LValueExpressionNode(Type); +public record VariableIdentNode(TypeNode Type, string Name, IEnumerable Tokens) : LValueExpressionNode(Type, Tokens); -public record FuncParameterIdentNode(TypeNode Type, string Name) : RValueExpressionNode(Type); +public record FuncParameterIdentNode(TypeNode Type, string Name, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record LocalFuncIdentNode(TypeNode Type, string Name) : RValueExpressionNode(Type); +public record LocalFuncIdentNode(TypeNode Type, string Name, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record ExternFuncIdentNode(TypeNode Type, string Name) : RValueExpressionNode(Type); +public record ExternFuncIdentNode(TypeNode Type, string Name, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record ArrayInitializerNode(TypeNode Type, ExpressionNode Capacity, TypeNode ElementType) : RValueExpressionNode(Type); +public record ArrayInitializerNode(TypeNode Type, ExpressionNode Capacity, TypeNode ElementType, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record ArrayIndexAccessNode(TypeNode Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Type); +public record ArrayIndexAccessNode(TypeNode Type, ExpressionNode Target, ExpressionNode Index, IEnumerable Tokens) : LValueExpressionNode(Type, Tokens); -public record AddressOfNode(TypeNode Type, LValueExpressionNode LValue) : RValueExpressionNode(Type); +public record AddressOfNode(TypeNode Type, LValueExpressionNode LValue, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record LiteralNode(TypeNode Type, string Value, LiteralKind Kind) : RValueExpressionNode(Type); +public record LiteralNode(TypeNode Type, string Value, LiteralKind Kind, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record StructFieldAccessNode(TypeNode Type, StructTypeNode StructType, ExpressionNode Target, string Field) : LValueExpressionNode(Type); +public record StructFieldAccessNode(TypeNode Type, StructTypeNode StructType, ExpressionNode Target, string Field, IEnumerable Tokens) : LValueExpressionNode(Type, Tokens); -public record StructInitializerNode(StructTypeNode StructType, Dictionary Initializers) : RValueExpressionNode(StructType); +public record StructInitializerNode(StructTypeNode StructType, Dictionary Initializers, IEnumerable Tokens) : RValueExpressionNode(StructType, Tokens); -public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : RValueExpressionNode(Type); +public record DereferenceNode(TypeNode Type, ExpressionNode Expression, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record ConvertToInterfaceNode(TypeNode Type, InterfaceTypeNode InterfaceType, StructTypeNode StructType, ExpressionNode Implementation) : RValueExpressionNode(Type); +public record ConvertToInterfaceNode(TypeNode Type, InterfaceTypeNode InterfaceType, StructTypeNode StructType, ExpressionNode Implementation, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record ConvertIntNode(TypeNode Type, ExpressionNode Value, IntTypeNode ValueType, IntTypeNode TargetType) : RValueExpressionNode(Type); +public record ConvertIntNode(TypeNode Type, ExpressionNode Value, IntTypeNode ValueType, IntTypeNode TargetType, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); -public record ConvertFloatNode(TypeNode Type, ExpressionNode Value, FloatTypeNode ValueType, FloatTypeNode TargetType) : RValueExpressionNode(Type); +public record ConvertFloatNode(TypeNode Type, ExpressionNode Value, FloatTypeNode ValueType, FloatTypeNode TargetType, IEnumerable Tokens) : RValueExpressionNode(Type, Tokens); diff --git a/src/compiler/NubLang/TypeChecking/Node/Node.cs b/src/compiler/NubLang/TypeChecking/Node/Node.cs index 1624372..b2ce1af 100644 --- a/src/compiler/NubLang/TypeChecking/Node/Node.cs +++ b/src/compiler/NubLang/TypeChecking/Node/Node.cs @@ -1,7 +1,9 @@ -namespace NubLang.TypeChecking.Node; +using NubLang.Tokenization; -public abstract record Node; +namespace NubLang.TypeChecking.Node; -public record TypedSyntaxTree(IReadOnlyList Definitions) : Node; +public abstract record Node(IEnumerable Tokens); -public record BlockNode(IReadOnlyList Statements) : Node; \ No newline at end of file +public record TypedSyntaxTree(IReadOnlyList Definitions); + +public record BlockNode(IReadOnlyList Statements, IEnumerable Tokens) : Node(Tokens); \ No newline at end of file diff --git a/src/compiler/NubLang/TypeChecking/Node/StatementNode.cs b/src/compiler/NubLang/TypeChecking/Node/StatementNode.cs index bd58462..69de9da 100644 --- a/src/compiler/NubLang/TypeChecking/Node/StatementNode.cs +++ b/src/compiler/NubLang/TypeChecking/Node/StatementNode.cs @@ -1,19 +1,21 @@ -namespace NubLang.TypeChecking.Node; +using NubLang.Tokenization; -public record StatementNode : Node; +namespace NubLang.TypeChecking.Node; -public record StatementExpressionNode(ExpressionNode Expression) : StatementNode; +public record StatementNode(IEnumerable Tokens) : Node(Tokens); -public record ReturnNode(Optional Value) : StatementNode; +public record StatementExpressionNode(ExpressionNode Expression, IEnumerable Tokens) : StatementNode(Tokens); -public record AssignmentNode(LValueExpressionNode Target, ExpressionNode Value) : StatementNode; +public record ReturnNode(Optional Value, IEnumerable Tokens) : StatementNode(Tokens); -public record IfNode(ExpressionNode Condition, BlockNode Body, Optional> Else) : StatementNode; +public record AssignmentNode(LValueExpressionNode Target, ExpressionNode Value, IEnumerable Tokens) : StatementNode(Tokens); -public record VariableDeclarationNode(string Name, Optional Assignment, TypeNode Type) : StatementNode; +public record IfNode(ExpressionNode Condition, BlockNode Body, Optional> Else, IEnumerable Tokens) : StatementNode(Tokens); -public record ContinueNode : StatementNode; +public record VariableDeclarationNode(string Name, Optional Assignment, TypeNode Type, IEnumerable Tokens) : StatementNode(Tokens); -public record BreakNode : StatementNode; +public record ContinueNode(IEnumerable Tokens) : StatementNode(Tokens); -public record WhileNode(ExpressionNode Condition, BlockNode Body) : StatementNode; \ No newline at end of file +public record BreakNode(IEnumerable Tokens) : StatementNode(Tokens); + +public record WhileNode(ExpressionNode Condition, BlockNode Body, IEnumerable Tokens) : StatementNode(Tokens); \ No newline at end of file diff --git a/src/compiler/NubLang/TypeChecking/TypeChecker.cs b/src/compiler/NubLang/TypeChecking/TypeChecker.cs index 6730360..388087d 100644 --- a/src/compiler/NubLang/TypeChecking/TypeChecker.cs +++ b/src/compiler/NubLang/TypeChecking/TypeChecker.cs @@ -66,10 +66,10 @@ public sealed class TypeChecker foreach (var function in node.Functions) { - functions.Add(new InterfaceFuncNode(function.Name, CheckFuncSignature(function.Signature))); + functions.Add(new InterfaceFuncNode(function.Name, CheckFuncSignature(function.Signature), function.Tokens)); } - return new InterfaceNode(node.Name, functions); + return new InterfaceNode(node.Name, functions, node.Tokens); } private StructNode CheckStructDefinition(StructSyntax node) @@ -85,7 +85,7 @@ public sealed class TypeChecker value = CheckExpression(field.Value.Value, CheckType(field.Type)); } - structFields.Add(new StructFieldNode(field.Index, field.Name, CheckType(field.Type), value)); + structFields.Add(new StructFieldNode(field.Index, field.Name, CheckType(field.Type), value, field.Tokens)); } var funcs = new List(); @@ -104,7 +104,7 @@ public sealed class TypeChecker var body = CheckBlock(func.Body, scope); _funcReturnTypes.Pop(); - funcs.Add(new StructFuncNode(func.Name, CheckFuncSignature(func.Signature), body)); + funcs.Add(new StructFuncNode(func.Name, CheckFuncSignature(func.Signature), body, func.Tokens)); } var interfaceImplementations = new List(); @@ -135,12 +135,12 @@ public sealed class TypeChecker interfaceImplementations.Add(interfaceType); } - return new StructNode(node.Name, GetStructType(node), structFields, funcs, interfaceImplementations); + return new StructNode(node.Name, GetStructType(node), structFields, funcs, interfaceImplementations, node.Tokens); } private ExternFuncNode CheckExternFuncDefinition(ExternFuncSyntax node) { - return new ExternFuncNode(node.Name, node.CallName, CheckFuncSignature(node.Signature)); + return new ExternFuncNode(node.Name, node.CallName, CheckFuncSignature(node.Signature), node.Tokens); } private LocalFuncNode CheckLocalFuncDefinition(LocalFuncSyntax node) @@ -157,7 +157,7 @@ public sealed class TypeChecker var body = CheckBlock(node.Body, scope); _funcReturnTypes.Pop(); - return new LocalFuncNode(node.Name, signature, body); + return new LocalFuncNode(node.Name, signature, body, node.Tokens); } private StatementNode CheckStatement(StatementSyntax node) @@ -165,8 +165,8 @@ public sealed class TypeChecker return node switch { AssignmentSyntax statement => CheckAssignment(statement), - BreakSyntax => new BreakNode(), - ContinueSyntax => new ContinueNode(), + BreakSyntax => new BreakNode(node.Tokens), + ContinueSyntax => new ContinueNode(node.Tokens), IfSyntax statement => CheckIf(statement), ReturnSyntax statement => CheckReturn(statement), StatementExpressionSyntax statement => CheckStatementExpression(statement), @@ -185,7 +185,7 @@ public sealed class TypeChecker } var value = CheckExpression(statement.Value, target.Type); - return new AssignmentNode(targetLValue, value); + return new AssignmentNode(targetLValue, value, statement.Tokens); } private IfNode CheckIf(IfSyntax statement) @@ -201,7 +201,7 @@ public sealed class TypeChecker ); } - return new IfNode(CheckExpression(statement.Condition, new BoolTypeNode()), CheckBlock(statement.Body), elseStatement); + return new IfNode(CheckExpression(statement.Condition, new BoolTypeNode()), CheckBlock(statement.Body), elseStatement, statement.Tokens); } private ReturnNode CheckReturn(ReturnSyntax statement) @@ -213,12 +213,12 @@ public sealed class TypeChecker value = CheckExpression(statement.Value.Value, _funcReturnTypes.Peek()); } - return new ReturnNode(value); + return new ReturnNode(value, statement.Tokens); } private StatementExpressionNode CheckStatementExpression(StatementExpressionSyntax statement) { - return new StatementExpressionNode(CheckExpression(statement.Expression)); + return new StatementExpressionNode(CheckExpression(statement.Expression), statement.Tokens); } private VariableDeclarationNode CheckVariableDeclaration(VariableDeclarationSyntax statement) @@ -259,12 +259,12 @@ public sealed class TypeChecker Scope.Declare(new Identifier(statement.Name, type, IdentifierKind.Variable)); - return new VariableDeclarationNode(statement.Name, assignment, type); + return new VariableDeclarationNode(statement.Name, assignment, type, statement.Tokens); } private WhileNode CheckWhile(WhileSyntax statement) { - return new WhileNode(CheckExpression(statement.Condition, new BoolTypeNode()), CheckBlock(statement.Body)); + return new WhileNode(CheckExpression(statement.Condition, new BoolTypeNode()), CheckBlock(statement.Body), statement.Tokens); } private ExpressionNode CheckExpression(ExpressionSyntax node, TypeNode? expectedType = null) @@ -293,14 +293,14 @@ public sealed class TypeChecker if (result.Type is StructTypeNode structType && expectedType is InterfaceTypeNode interfaceType) { - return new ConvertToInterfaceNode(interfaceType, interfaceType, structType, result); + return new ConvertToInterfaceNode(interfaceType, interfaceType, structType, result, node.Tokens); } if (result.Type is IntTypeNode sourceIntType && expectedType is IntTypeNode targetIntType) { if (sourceIntType.Signed == targetIntType.Signed && sourceIntType.Width < targetIntType.Width) { - return new ConvertIntNode(targetIntType, result, sourceIntType, targetIntType); + return new ConvertIntNode(targetIntType, result, sourceIntType, targetIntType, node.Tokens); } } @@ -308,7 +308,7 @@ public sealed class TypeChecker { if (sourceFloatType.Width < targetFloatType.Width) { - return new ConvertFloatNode(targetFloatType, result, sourceFloatType, targetFloatType); + return new ConvertFloatNode(targetFloatType, result, sourceFloatType, targetFloatType, node.Tokens); } } @@ -324,21 +324,21 @@ public sealed class TypeChecker throw new TypeCheckerException(Diagnostic.Error("Cannot take address of rvalue").Build()); } - return new AddressOfNode(new PointerTypeNode(inner.Type), lValueInner); + return new AddressOfNode(new PointerTypeNode(inner.Type), lValueInner, expression.Tokens); } private ArrayIndexAccessNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression) { var boundArray = CheckExpression(expression.Target); var elementType = ((ArrayTypeNode)boundArray.Type).ElementType; - return new ArrayIndexAccessNode(elementType, boundArray, CheckExpression(expression.Index, new IntTypeNode(false, 64))); + return new ArrayIndexAccessNode(elementType, boundArray, CheckExpression(expression.Index, new IntTypeNode(false, 64)), expression.Tokens); } private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression) { var capacity = CheckExpression(expression.Capacity, new IntTypeNode(false, 64)); var type = new ArrayTypeNode(CheckType(expression.ElementType)); - return new ArrayInitializerNode(type, capacity, CheckType(expression.ElementType)); + return new ArrayInitializerNode(type, capacity, CheckType(expression.ElementType), expression.Tokens); } private BinaryExpressionNode CheckBinaryExpression(BinaryExpressionSyntax expression) @@ -392,14 +392,14 @@ public sealed class TypeChecker _ => throw new ArgumentOutOfRangeException() }; - return new BinaryExpressionNode(resultingType, boundLeft, op, boundRight); + return new BinaryExpressionNode(resultingType, boundLeft, op, boundRight, expression.Tokens); } private DereferenceNode CheckDereference(DereferenceSyntax expression) { var boundExpression = CheckExpression(expression.Expression); var dereferencedType = ((PointerTypeNode)boundExpression.Type).BaseType; - return new DereferenceNode(dereferencedType, boundExpression); + return new DereferenceNode(dereferencedType, boundExpression, expression.Tokens); } private FuncCallNode CheckFuncCall(FuncCallSyntax expression) @@ -425,7 +425,7 @@ public sealed class TypeChecker parameters.Add(CheckExpression(parameter, expectedType)); } - return new FuncCallNode(funcType.ReturnType, boundExpression, parameters); + return new FuncCallNode(funcType.ReturnType, boundExpression, parameters, expression.Tokens); } private ExpressionNode CheckDotFuncCall(DotFuncCallSyntax expression) @@ -460,7 +460,7 @@ public sealed class TypeChecker } var returnType = CheckType(function.Signature.ReturnType); - return new InterfaceFuncCallNode(returnType, expression.Name, interfaceType, thisParameter, parameters); + return new InterfaceFuncCallNode(returnType, expression.Name, interfaceType, thisParameter, parameters, expression.Tokens); } if (thisParameter.Type is StructTypeNode structType) @@ -491,7 +491,7 @@ public sealed class TypeChecker } var returnType = CheckType(function.Signature.ReturnType); - return new StructFuncCallNode(returnType, expression.Name, structType, thisParameter, parameters); + return new StructFuncCallNode(returnType, expression.Name, structType, thisParameter, parameters, expression.Tokens); } throw new TypeCheckerException(Diagnostic.Error($"Cannot call dot function on type {thisParameter.Type}").Build()); @@ -504,8 +504,8 @@ public sealed class TypeChecker { return identifier.Kind switch { - IdentifierKind.Variable => new VariableIdentNode(identifier.Type, identifier.Name), - IdentifierKind.FunctionParameter => new FuncParameterIdentNode(identifier.Type, identifier.Name), + IdentifierKind.Variable => new VariableIdentNode(identifier.Type, identifier.Name, expression.Tokens), + IdentifierKind.FunctionParameter => new FuncParameterIdentNode(identifier.Type, identifier.Name, expression.Tokens), _ => throw new ArgumentOutOfRangeException() }; } @@ -523,7 +523,7 @@ public sealed class TypeChecker var returnType = CheckType(localFunc.Signature.ReturnType); var parameterTypes = localFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList(); var type = new FuncTypeNode(parameterTypes, returnType); - return new LocalFuncIdentNode(type, expression.Name); + return new LocalFuncIdentNode(type, expression.Name, expression.Tokens); } var externFuncs = _definitionTable.LookupExternFunc(expression.Name).ToArray(); @@ -539,7 +539,7 @@ public sealed class TypeChecker var returnType = CheckType(externFunc.Signature.ReturnType); var parameterTypes = externFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList(); var type = new FuncTypeNode(parameterTypes, returnType); - return new ExternFuncIdentNode(type, expression.Name); + return new ExternFuncIdentNode(type, expression.Name, expression.Tokens); } throw new TypeCheckerException(Diagnostic.Error($"No identifier with the name {expression.Name} exists").Build()); @@ -556,7 +556,7 @@ public sealed class TypeChecker _ => throw new ArgumentOutOfRangeException() }; - return new LiteralNode(type, expression.Value, expression.Kind); + return new LiteralNode(type, expression.Value, expression.Kind, expression.Tokens); } private StructFieldAccessNode CheckStructFieldAccess(StructFieldAccessSyntax expression) @@ -586,7 +586,7 @@ public sealed class TypeChecker var field = fields[0]; - return new StructFieldAccessNode(CheckType(field.Type), structType, boundExpression, expression.Member); + return new StructFieldAccessNode(CheckType(field.Type), structType, boundExpression, expression.Member, expression.Tokens); } } @@ -644,7 +644,7 @@ public sealed class TypeChecker initializers[field] = CheckExpression(initializer, CheckType(fields[0].Type)); } - return new StructInitializerNode(structType, initializers); + return new StructInitializerNode(structType, initializers, expression.Tokens); } private UnaryExpressionNode CheckUnaryExpression(UnaryExpressionSyntax expression) @@ -687,7 +687,7 @@ public sealed class TypeChecker _ => throw new ArgumentOutOfRangeException(nameof(expression.Operator), expression.Operator, null) }; - return new UnaryExpressionNode(type, op, boundOperand); + return new UnaryExpressionNode(type, op, boundOperand, expression.Tokens); } private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax node) @@ -696,10 +696,10 @@ public sealed class TypeChecker foreach (var parameter in node.Parameters) { - parameters.Add(new FuncParameterNode(parameter.Name, CheckType(parameter.Type))); + parameters.Add(new FuncParameterNode(parameter.Name, CheckType(parameter.Type), parameter.Tokens)); } - return new FuncSignatureNode(parameters, CheckType(node.ReturnType)); + return new FuncSignatureNode(parameters, CheckType(node.ReturnType), node.Tokens); } private BlockNode CheckBlock(BlockSyntax node, Scope? scope = null) @@ -715,7 +715,7 @@ public sealed class TypeChecker _scopes.Pop(); - return new BlockNode(statements); + return new BlockNode(statements, node.Tokens); } private TypeNode CheckType(TypeSyntax node)