This commit is contained in:
nub31
2025-09-09 17:44:57 +02:00
parent ce999e4c1b
commit 16b86ea1c7
9 changed files with 143 additions and 126 deletions

View File

@@ -23,11 +23,12 @@ func main(args: []cstring): i64
age = "23" age = "23"
} }
puts(x.name.last) test(x&)
return 0 return 0
} }
func test(test: u32) func test(human: ^Human)
{ {
puts(human^.name.last)
} }

View File

@@ -7,7 +7,7 @@ public static class GCC
public static async Task<bool> Assemble(string asmPath, string outPath) public static async Task<bool> Assemble(string asmPath, string outPath)
{ {
using var process = new Process(); 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, UseShellExecute = false,
RedirectStandardOutput = true, RedirectStandardOutput = true,

View File

@@ -99,7 +99,7 @@ for (var i = 0; i < typedSyntaxTrees.Count; i++)
Directory.CreateDirectory(outFileDir); Directory.CreateDirectory(outFileDir);
} }
var generator = new QBEGenerator(syntaxTree, typedDefinitionTable); var generator = new QBEGenerator(syntaxTree, typedDefinitionTable, options.Files[i].Path);
var ssa = generator.Emit(); var ssa = generator.Emit();
var ssaFilePath = Path.ChangeExtension(outFileName, "ssa"); var ssaFilePath = Path.ChangeExtension(outFileName, "ssa");

View File

@@ -1,5 +1,4 @@
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using NubLang.Tokenization; using NubLang.Tokenization;
@@ -11,6 +10,7 @@ public class QBEGenerator
{ {
private readonly TypedSyntaxTree _syntaxTree; private readonly TypedSyntaxTree _syntaxTree;
private readonly TypedDefinitionTable _definitionTable; private readonly TypedDefinitionTable _definitionTable;
private readonly string _sourceFileName;
private readonly QBEWriter _writer; private readonly QBEWriter _writer;
private readonly List<CStringLiteral> _cStringLiterals = []; private readonly List<CStringLiteral> _cStringLiterals = [];
@@ -23,10 +23,11 @@ public class QBEGenerator
private int _stringLiteralIndex; private int _stringLiteralIndex;
private bool _codeIsReachable = true; private bool _codeIsReachable = true;
public QBEGenerator(TypedSyntaxTree syntaxTree, TypedDefinitionTable definitionTable) public QBEGenerator(TypedSyntaxTree syntaxTree, TypedDefinitionTable definitionTable, string sourceFileName)
{ {
_syntaxTree = syntaxTree; _syntaxTree = syntaxTree;
_definitionTable = definitionTable; _definitionTable = definitionTable;
_sourceFileName = sourceFileName;
_writer = new QBEWriter(); _writer = new QBEWriter();
} }
@@ -42,6 +43,8 @@ public class QBEGenerator
_stringLiteralIndex = 0; _stringLiteralIndex = 0;
_codeIsReachable = true; _codeIsReachable = true;
_writer.WriteLine($"dbgfile \"{_sourceFileName}\"");
foreach (var structDef in _definitionTable.GetStructs()) foreach (var structDef in _definitionTable.GetStructs())
{ {
EmitStructTypeDefinition(structDef); 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: return EmitExpression(source);
case StructInitializerNode:
case LiteralNode { Kind: LiteralKind.String }:
{
destination = EmitExpression(source);
return true;
}
} }
destination = null; // Simple types are passed in registers and therefore always copied
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);
if (source.Type.IsSimpleType(out _, out var complexType)) if (source.Type.IsSimpleType(out _, out var complexType))
{ {
// Simple types are passed in registers and are therefore always copied return EmitExpression(source);
return value;
} }
// For the rest, we figure out the size of the type and shallow copy them
var value = EmitExpression(source);
var size = complexType switch var size = complexType switch
{ {
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value), ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
@@ -474,6 +460,12 @@ public class QBEGenerator
private void EmitStatement(StatementNode statement) 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) switch (statement)
{ {
case AssignmentNode assignment: case AssignmentNode assignment:
@@ -589,6 +581,12 @@ public class QBEGenerator
private string EmitExpression(ExpressionNode expression) 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 return expression switch
{ {
ArrayInitializerNode arrayInitializer => EmitArrayInitializer(arrayInitializer), ArrayInitializerNode arrayInitializer => EmitArrayInitializer(arrayInitializer),
@@ -616,7 +614,13 @@ public class QBEGenerator
private string EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess) 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) private void EmitArrayBoundsCheck(string array, string index)
@@ -666,7 +670,13 @@ public class QBEGenerator
private string EmitDereference(DereferenceNode dereference) 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) private string EmitAddressOf(AddressOfNode addressOf)
@@ -901,10 +911,12 @@ public class QBEGenerator
private string EmitVariableIdent(VariableIdentNode variableIdent) private string EmitVariableIdent(VariableIdentNode variableIdent)
{ {
var address = EmitAddressOfVariableIdent(variableIdent); var address = EmitAddressOfVariableIdent(variableIdent);
if (variableIdent.Type is StructTypeNode)
{
return address;
}
return variableIdent.Type.IsSimpleType(out _, out _) return EmitLoad(variableIdent.Type, address);
? EmitLoad(variableIdent.Type, address)
: address;
} }
private string EmitFuncParameterIdent(FuncParameterIdentNode funcParameterIdent) private string EmitFuncParameterIdent(FuncParameterIdentNode funcParameterIdent)
@@ -1075,13 +1087,11 @@ public class QBEGenerator
private string EmitStructFieldAccess(StructFieldAccessNode structFieldAccess) private string EmitStructFieldAccess(StructFieldAccessNode structFieldAccess)
{ {
var address = EmitAddressOfStructFieldAccess(structFieldAccess); var address = EmitAddressOfStructFieldAccess(structFieldAccess);
// Inline structs should not be loaded
if (structFieldAccess.Type is StructTypeNode) if (structFieldAccess.Type is StructTypeNode)
{ {
return address; return address;
} }
return EmitLoad(structFieldAccess.Type, address); return EmitLoad(structFieldAccess.Type, address);
} }
@@ -1096,7 +1106,7 @@ public class QBEGenerator
foreach (var parameter in structFuncCall.Parameters) foreach (var parameter in structFuncCall.Parameters)
{ {
var copy = EmitCreateCopyOrInitialize(parameter); var copy = EmitCreateCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
} }
@@ -1138,7 +1148,7 @@ public class QBEGenerator
foreach (var parameter in interfaceFuncCall.Parameters) foreach (var parameter in interfaceFuncCall.Parameters)
{ {
var copy = EmitCreateCopyOrInitialize(parameter); var copy = EmitCreateCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
} }
@@ -1248,7 +1258,7 @@ public class QBEGenerator
foreach (var parameter in funcCall.Parameters) foreach (var parameter in funcCall.Parameters)
{ {
var copy = EmitCreateCopyOrInitialize(parameter); var copy = EmitCreateCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
} }

View File

@@ -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<Token> Tokens) : Node(Tokens);
public record FuncSignatureNode(IReadOnlyList<FuncParameterNode> Parameters, TypeNode ReturnType) : Node; public record FuncParameterNode(string Name, TypeNode Type, IEnumerable<Token> Tokens) : Node(Tokens);
public record LocalFuncNode(string Name, FuncSignatureNode Signature, BlockNode Body) : DefinitionNode; public record FuncSignatureNode(IReadOnlyList<FuncParameterNode> Parameters, TypeNode ReturnType, IEnumerable<Token> Tokens) : Node(Tokens);
public record ExternFuncNode(string Name, string CallName, FuncSignatureNode Signature) : DefinitionNode; public record LocalFuncNode(string Name, FuncSignatureNode Signature, BlockNode Body, IEnumerable<Token> Tokens) : DefinitionNode(Tokens);
public record StructFieldNode(int Index, string Name, TypeNode Type, Optional<ExpressionNode> Value) : Node; public record ExternFuncNode(string Name, string CallName, FuncSignatureNode Signature, IEnumerable<Token> Tokens) : DefinitionNode(Tokens);
public record StructFuncNode(string Name, FuncSignatureNode Signature, BlockNode Body) : Node; public record StructFieldNode(int Index, string Name, TypeNode Type, Optional<ExpressionNode> Value, IEnumerable<Token> Tokens) : Node(Tokens);
public record StructNode(string Name, StructTypeNode Type, IReadOnlyList<StructFieldNode> Fields, IReadOnlyList<StructFuncNode> Functions, IReadOnlyList<InterfaceTypeNode> InterfaceImplementations) : DefinitionNode; public record StructFuncNode(string Name, FuncSignatureNode Signature, BlockNode Body, IEnumerable<Token> Tokens) : Node(Tokens);
public record InterfaceFuncNode(string Name, FuncSignatureNode Signature) : Node; public record StructNode(string Name, StructTypeNode Type, IReadOnlyList<StructFieldNode> Fields, IReadOnlyList<StructFuncNode> Functions, IReadOnlyList<InterfaceTypeNode> InterfaceImplementations, IEnumerable<Token> Tokens) : DefinitionNode(Tokens);
public record InterfaceNode(string Name, IReadOnlyList<InterfaceFuncNode> Functions) : DefinitionNode; public record InterfaceFuncNode(string Name, FuncSignatureNode Signature, IEnumerable<Token> Tokens) : Node(Tokens);
public record InterfaceNode(string Name, IReadOnlyList<InterfaceFuncNode> Functions, IEnumerable<Token> Tokens) : DefinitionNode(Tokens);

View File

@@ -30,45 +30,45 @@ public enum BinaryOperator
BitwiseOr BitwiseOr
} }
public abstract record ExpressionNode(TypeNode Type) : Node; public abstract record ExpressionNode(TypeNode Type, IEnumerable<Token> Tokens) : Node(Tokens);
public abstract record LValueExpressionNode(TypeNode Type) : RValueExpressionNode(Type); public abstract record LValueExpressionNode(TypeNode Type, IEnumerable<Token> Tokens) : RValueExpressionNode(Type, Tokens);
public abstract record RValueExpressionNode(TypeNode Type) : ExpressionNode(Type); public abstract record RValueExpressionNode(TypeNode Type, IEnumerable<Token> 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<Token> 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<Token> Tokens) : RValueExpressionNode(Type, Tokens);
public record FuncCallNode(TypeNode Type, ExpressionNode Expression, IReadOnlyList<ExpressionNode> Parameters) : RValueExpressionNode(Type); public record FuncCallNode(TypeNode Type, ExpressionNode Expression, IReadOnlyList<ExpressionNode> Parameters, IEnumerable<Token> Tokens) : RValueExpressionNode(Type, Tokens);
public record StructFuncCallNode(TypeNode Type, string Name, StructTypeNode StructType, ExpressionNode StructExpression, IReadOnlyList<ExpressionNode> Parameters) : RValueExpressionNode(Type); public record StructFuncCallNode(TypeNode Type, string Name, StructTypeNode StructType, ExpressionNode StructExpression, IReadOnlyList<ExpressionNode> Parameters, IEnumerable<Token> Tokens) : RValueExpressionNode(Type, Tokens);
public record InterfaceFuncCallNode(TypeNode Type, string Name, InterfaceTypeNode InterfaceType, ExpressionNode InterfaceExpression, IReadOnlyList<ExpressionNode> Parameters) : RValueExpressionNode(Type); public record InterfaceFuncCallNode(TypeNode Type, string Name, InterfaceTypeNode InterfaceType, ExpressionNode InterfaceExpression, IReadOnlyList<ExpressionNode> Parameters, IEnumerable<Token> Tokens) : RValueExpressionNode(Type, Tokens);
public record VariableIdentNode(TypeNode Type, string Name) : LValueExpressionNode(Type); public record VariableIdentNode(TypeNode Type, string Name, IEnumerable<Token> Tokens) : LValueExpressionNode(Type, Tokens);
public record FuncParameterIdentNode(TypeNode Type, string Name) : RValueExpressionNode(Type); public record FuncParameterIdentNode(TypeNode Type, string Name, IEnumerable<Token> Tokens) : RValueExpressionNode(Type, Tokens);
public record LocalFuncIdentNode(TypeNode Type, string Name) : RValueExpressionNode(Type); public record LocalFuncIdentNode(TypeNode Type, string Name, IEnumerable<Token> Tokens) : RValueExpressionNode(Type, Tokens);
public record ExternFuncIdentNode(TypeNode Type, string Name) : RValueExpressionNode(Type); public record ExternFuncIdentNode(TypeNode Type, string Name, IEnumerable<Token> 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<Token> 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<Token> Tokens) : LValueExpressionNode(Type, Tokens);
public record AddressOfNode(TypeNode Type, LValueExpressionNode LValue) : RValueExpressionNode(Type); public record AddressOfNode(TypeNode Type, LValueExpressionNode LValue, IEnumerable<Token> 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<Token> 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<Token> Tokens) : LValueExpressionNode(Type, Tokens);
public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(StructType); public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers, IEnumerable<Token> Tokens) : RValueExpressionNode(StructType, Tokens);
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : RValueExpressionNode(Type); public record DereferenceNode(TypeNode Type, ExpressionNode Expression, IEnumerable<Token> 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<Token> 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<Token> 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<Token> Tokens) : RValueExpressionNode(Type, Tokens);

View File

@@ -1,7 +1,9 @@
namespace NubLang.TypeChecking.Node; using NubLang.Tokenization;
public abstract record Node; namespace NubLang.TypeChecking.Node;
public record TypedSyntaxTree(IReadOnlyList<DefinitionNode> Definitions) : Node; public abstract record Node(IEnumerable<Token> Tokens);
public record BlockNode(IReadOnlyList<StatementNode> Statements) : Node; public record TypedSyntaxTree(IReadOnlyList<DefinitionNode> Definitions);
public record BlockNode(IReadOnlyList<StatementNode> Statements, IEnumerable<Token> Tokens) : Node(Tokens);

View File

@@ -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<Token> Tokens) : Node(Tokens);
public record ReturnNode(Optional<ExpressionNode> Value) : StatementNode; public record StatementExpressionNode(ExpressionNode Expression, IEnumerable<Token> Tokens) : StatementNode(Tokens);
public record AssignmentNode(LValueExpressionNode Target, ExpressionNode Value) : StatementNode; public record ReturnNode(Optional<ExpressionNode> Value, IEnumerable<Token> Tokens) : StatementNode(Tokens);
public record IfNode(ExpressionNode Condition, BlockNode Body, Optional<Variant<IfNode, BlockNode>> Else) : StatementNode; public record AssignmentNode(LValueExpressionNode Target, ExpressionNode Value, IEnumerable<Token> Tokens) : StatementNode(Tokens);
public record VariableDeclarationNode(string Name, Optional<ExpressionNode> Assignment, TypeNode Type) : StatementNode; public record IfNode(ExpressionNode Condition, BlockNode Body, Optional<Variant<IfNode, BlockNode>> Else, IEnumerable<Token> Tokens) : StatementNode(Tokens);
public record ContinueNode : StatementNode; public record VariableDeclarationNode(string Name, Optional<ExpressionNode> Assignment, TypeNode Type, IEnumerable<Token> Tokens) : StatementNode(Tokens);
public record BreakNode : StatementNode; public record ContinueNode(IEnumerable<Token> Tokens) : StatementNode(Tokens);
public record WhileNode(ExpressionNode Condition, BlockNode Body) : StatementNode; public record BreakNode(IEnumerable<Token> Tokens) : StatementNode(Tokens);
public record WhileNode(ExpressionNode Condition, BlockNode Body, IEnumerable<Token> Tokens) : StatementNode(Tokens);

View File

@@ -66,10 +66,10 @@ public sealed class TypeChecker
foreach (var function in node.Functions) 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) private StructNode CheckStructDefinition(StructSyntax node)
@@ -85,7 +85,7 @@ public sealed class TypeChecker
value = CheckExpression(field.Value.Value, CheckType(field.Type)); 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<StructFuncNode>(); var funcs = new List<StructFuncNode>();
@@ -104,7 +104,7 @@ public sealed class TypeChecker
var body = CheckBlock(func.Body, scope); var body = CheckBlock(func.Body, scope);
_funcReturnTypes.Pop(); _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<InterfaceTypeNode>(); var interfaceImplementations = new List<InterfaceTypeNode>();
@@ -135,12 +135,12 @@ public sealed class TypeChecker
interfaceImplementations.Add(interfaceType); 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) 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) private LocalFuncNode CheckLocalFuncDefinition(LocalFuncSyntax node)
@@ -157,7 +157,7 @@ public sealed class TypeChecker
var body = CheckBlock(node.Body, scope); var body = CheckBlock(node.Body, scope);
_funcReturnTypes.Pop(); _funcReturnTypes.Pop();
return new LocalFuncNode(node.Name, signature, body); return new LocalFuncNode(node.Name, signature, body, node.Tokens);
} }
private StatementNode CheckStatement(StatementSyntax node) private StatementNode CheckStatement(StatementSyntax node)
@@ -165,8 +165,8 @@ public sealed class TypeChecker
return node switch return node switch
{ {
AssignmentSyntax statement => CheckAssignment(statement), AssignmentSyntax statement => CheckAssignment(statement),
BreakSyntax => new BreakNode(), BreakSyntax => new BreakNode(node.Tokens),
ContinueSyntax => new ContinueNode(), ContinueSyntax => new ContinueNode(node.Tokens),
IfSyntax statement => CheckIf(statement), IfSyntax statement => CheckIf(statement),
ReturnSyntax statement => CheckReturn(statement), ReturnSyntax statement => CheckReturn(statement),
StatementExpressionSyntax statement => CheckStatementExpression(statement), StatementExpressionSyntax statement => CheckStatementExpression(statement),
@@ -185,7 +185,7 @@ public sealed class TypeChecker
} }
var value = CheckExpression(statement.Value, target.Type); var value = CheckExpression(statement.Value, target.Type);
return new AssignmentNode(targetLValue, value); return new AssignmentNode(targetLValue, value, statement.Tokens);
} }
private IfNode CheckIf(IfSyntax statement) 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) private ReturnNode CheckReturn(ReturnSyntax statement)
@@ -213,12 +213,12 @@ public sealed class TypeChecker
value = CheckExpression(statement.Value.Value, _funcReturnTypes.Peek()); value = CheckExpression(statement.Value.Value, _funcReturnTypes.Peek());
} }
return new ReturnNode(value); return new ReturnNode(value, statement.Tokens);
} }
private StatementExpressionNode CheckStatementExpression(StatementExpressionSyntax statement) private StatementExpressionNode CheckStatementExpression(StatementExpressionSyntax statement)
{ {
return new StatementExpressionNode(CheckExpression(statement.Expression)); return new StatementExpressionNode(CheckExpression(statement.Expression), statement.Tokens);
} }
private VariableDeclarationNode CheckVariableDeclaration(VariableDeclarationSyntax statement) private VariableDeclarationNode CheckVariableDeclaration(VariableDeclarationSyntax statement)
@@ -259,12 +259,12 @@ public sealed class TypeChecker
Scope.Declare(new Identifier(statement.Name, type, IdentifierKind.Variable)); 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) 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) 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) 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 (result.Type is IntTypeNode sourceIntType && expectedType is IntTypeNode targetIntType)
{ {
if (sourceIntType.Signed == targetIntType.Signed && sourceIntType.Width < targetIntType.Width) 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) 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()); 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) private ArrayIndexAccessNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression)
{ {
var boundArray = CheckExpression(expression.Target); var boundArray = CheckExpression(expression.Target);
var elementType = ((ArrayTypeNode)boundArray.Type).ElementType; 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) private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression)
{ {
var capacity = CheckExpression(expression.Capacity, new IntTypeNode(false, 64)); var capacity = CheckExpression(expression.Capacity, new IntTypeNode(false, 64));
var type = new ArrayTypeNode(CheckType(expression.ElementType)); 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) private BinaryExpressionNode CheckBinaryExpression(BinaryExpressionSyntax expression)
@@ -392,14 +392,14 @@ public sealed class TypeChecker
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}; };
return new BinaryExpressionNode(resultingType, boundLeft, op, boundRight); return new BinaryExpressionNode(resultingType, boundLeft, op, boundRight, expression.Tokens);
} }
private DereferenceNode CheckDereference(DereferenceSyntax expression) private DereferenceNode CheckDereference(DereferenceSyntax expression)
{ {
var boundExpression = CheckExpression(expression.Expression); var boundExpression = CheckExpression(expression.Expression);
var dereferencedType = ((PointerTypeNode)boundExpression.Type).BaseType; var dereferencedType = ((PointerTypeNode)boundExpression.Type).BaseType;
return new DereferenceNode(dereferencedType, boundExpression); return new DereferenceNode(dereferencedType, boundExpression, expression.Tokens);
} }
private FuncCallNode CheckFuncCall(FuncCallSyntax expression) private FuncCallNode CheckFuncCall(FuncCallSyntax expression)
@@ -425,7 +425,7 @@ public sealed class TypeChecker
parameters.Add(CheckExpression(parameter, expectedType)); 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) private ExpressionNode CheckDotFuncCall(DotFuncCallSyntax expression)
@@ -460,7 +460,7 @@ public sealed class TypeChecker
} }
var returnType = CheckType(function.Signature.ReturnType); 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) if (thisParameter.Type is StructTypeNode structType)
@@ -491,7 +491,7 @@ public sealed class TypeChecker
} }
var returnType = CheckType(function.Signature.ReturnType); 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()); 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 return identifier.Kind switch
{ {
IdentifierKind.Variable => new VariableIdentNode(identifier.Type, identifier.Name), IdentifierKind.Variable => new VariableIdentNode(identifier.Type, identifier.Name, expression.Tokens),
IdentifierKind.FunctionParameter => new FuncParameterIdentNode(identifier.Type, identifier.Name), IdentifierKind.FunctionParameter => new FuncParameterIdentNode(identifier.Type, identifier.Name, expression.Tokens),
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}; };
} }
@@ -523,7 +523,7 @@ public sealed class TypeChecker
var returnType = CheckType(localFunc.Signature.ReturnType); var returnType = CheckType(localFunc.Signature.ReturnType);
var parameterTypes = localFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList(); var parameterTypes = localFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList();
var type = new FuncTypeNode(parameterTypes, returnType); 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(); var externFuncs = _definitionTable.LookupExternFunc(expression.Name).ToArray();
@@ -539,7 +539,7 @@ public sealed class TypeChecker
var returnType = CheckType(externFunc.Signature.ReturnType); var returnType = CheckType(externFunc.Signature.ReturnType);
var parameterTypes = externFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList(); var parameterTypes = externFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList();
var type = new FuncTypeNode(parameterTypes, returnType); 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()); 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() _ => 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) private StructFieldAccessNode CheckStructFieldAccess(StructFieldAccessSyntax expression)
@@ -586,7 +586,7 @@ public sealed class TypeChecker
var field = fields[0]; 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)); 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) private UnaryExpressionNode CheckUnaryExpression(UnaryExpressionSyntax expression)
@@ -687,7 +687,7 @@ public sealed class TypeChecker
_ => throw new ArgumentOutOfRangeException(nameof(expression.Operator), expression.Operator, null) _ => 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) private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax node)
@@ -696,10 +696,10 @@ public sealed class TypeChecker
foreach (var parameter in node.Parameters) 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) private BlockNode CheckBlock(BlockSyntax node, Scope? scope = null)
@@ -715,7 +715,7 @@ public sealed class TypeChecker
_scopes.Pop(); _scopes.Pop();
return new BlockNode(statements); return new BlockNode(statements, node.Tokens);
} }
private TypeNode CheckType(TypeSyntax node) private TypeNode CheckType(TypeSyntax node)