From fbc709c50dfd22b794ac0a2bba784b7c36105980 Mon Sep 17 00:00:00 2001 From: nub31 Date: Mon, 2 Jun 2025 15:27:19 +0200 Subject: [PATCH] Refactor statements --- example/main.nub | 2 +- src/lang/Nub.Lang/Backend/Generator.cs | 162 ++++++----- .../Frontend/Parsing/ArrayIndexNode.cs | 9 - .../{ => Definitions}/DefinitionNode.cs | 0 .../{ => Definitions}/FuncDefinitionNode.cs | 0 .../{ => Definitions}/StructDefinitionNode.cs | 0 .../{ => Expressions}/AddressOfNode.cs | 0 .../Expressions/ArrayIndexAccessNode.cs | 9 + .../{ => Expressions}/ArrayInitializerNode.cs | 0 .../{ => Expressions}/BinaryExpressionNode.cs | 0 .../Parsing/{ => Expressions}/CastNode.cs | 0 .../{ => Expressions}/DereferenceNode.cs | 0 .../{ => Expressions}/ExpressionNode.cs | 0 .../Parsing/Expressions/FuncCallNode.cs | 12 + .../{ => Expressions}/IdentifierNode.cs | 0 .../Parsing/{ => Expressions}/LiteralNode.cs | 0 .../{ => Expressions}/MemberAccessNode.cs | 0 .../StructInitializerNode.cs | 0 .../{ => Expressions}/UnaryExpressionNode.cs | 0 .../Nub.Lang/Frontend/Parsing/FuncCall.cs | 10 - .../Parsing/FuncCallExpressionNode.cs | 10 - .../Frontend/Parsing/FuncCallStatementNode.cs | 10 - src/lang/Nub.Lang/Frontend/Parsing/Parser.cs | 270 ++++++++++++------ .../Statements/ArrayIndexAssignmentNode.cs | 9 + .../Parsing/{ => Statements}/BlockNode.cs | 0 .../Parsing/{ => Statements}/BreakNode.cs | 0 .../Parsing/{ => Statements}/ContinueNode.cs | 0 .../Parsing/{ => Statements}/IfNode.cs | 0 .../Statements/MemberAssignmentNode.cs | 9 + .../Parsing/{ => Statements}/ReturnNode.cs | 0 .../Statements/StatementExpressionNode.cs | 8 + .../Parsing/{ => Statements}/StatementNode.cs | 0 .../VariableAssignmentNode.cs | 4 +- .../VariableDeclarationNode.cs | 0 .../Parsing/{ => Statements}/WhileNode.cs | 0 .../Nub.Lang/Frontend/Typing/TypeChecker.cs | 60 +++- 36 files changed, 354 insertions(+), 230 deletions(-) delete mode 100644 src/lang/Nub.Lang/Frontend/Parsing/ArrayIndexNode.cs rename src/lang/Nub.Lang/Frontend/Parsing/{ => Definitions}/DefinitionNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Definitions}/FuncDefinitionNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Definitions}/StructDefinitionNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/AddressOfNode.cs (100%) create mode 100644 src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayIndexAccessNode.cs rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/ArrayInitializerNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/BinaryExpressionNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/CastNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/DereferenceNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/ExpressionNode.cs (100%) create mode 100644 src/lang/Nub.Lang/Frontend/Parsing/Expressions/FuncCallNode.cs rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/IdentifierNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/LiteralNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/MemberAccessNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/StructInitializerNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Expressions}/UnaryExpressionNode.cs (100%) delete mode 100644 src/lang/Nub.Lang/Frontend/Parsing/FuncCall.cs delete mode 100644 src/lang/Nub.Lang/Frontend/Parsing/FuncCallExpressionNode.cs delete mode 100644 src/lang/Nub.Lang/Frontend/Parsing/FuncCallStatementNode.cs create mode 100644 src/lang/Nub.Lang/Frontend/Parsing/Statements/ArrayIndexAssignmentNode.cs rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/BlockNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/BreakNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/ContinueNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/IfNode.cs (100%) create mode 100644 src/lang/Nub.Lang/Frontend/Parsing/Statements/MemberAssignmentNode.cs rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/ReturnNode.cs (100%) create mode 100644 src/lang/Nub.Lang/Frontend/Parsing/Statements/StatementExpressionNode.cs rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/StatementNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/VariableAssignmentNode.cs (62%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/VariableDeclarationNode.cs (100%) rename src/lang/Nub.Lang/Frontend/Parsing/{ => Statements}/WhileNode.cs (100%) diff --git a/example/main.nub b/example/main.nub index 67cff6b..d589687 100644 --- a/example/main.nub +++ b/example/main.nub @@ -7,6 +7,6 @@ export func main(args: []^string) { while i < args.count { c::printf("%s\n", args[i]) - i += 1 + i = i + 1 } } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Backend/Generator.cs b/src/lang/Nub.Lang/Backend/Generator.cs index 31e6b61..6a721fb 100644 --- a/src/lang/Nub.Lang/Backend/Generator.cs +++ b/src/lang/Nub.Lang/Backend/Generator.cs @@ -8,7 +8,7 @@ namespace Nub.Lang.Backend; public class Generator { private const string OutOfBoundsMessage = "Index is out of bounds\\n"; - + private List _sourceFiles = []; private StringBuilder _builder = new(); private Dictionary _variables = []; @@ -34,13 +34,13 @@ public class Generator _funcIndex = 0; _labelIndex = 0; _codeIsReachable = true; - + foreach (var structDef in _sourceFiles.SelectMany(f => f.Definitions).OfType()) { GenerateStructDefinition(structDef); _builder.AppendLine(); } - + foreach (var funcSignature in _sourceFiles.SelectMany(f => f.Definitions).OfType()) { switch (funcSignature) @@ -58,6 +58,7 @@ public class Generator var funcName = GenFuncName(); _funcNames[funcSignature] = funcName; } + break; default: throw new ArgumentOutOfRangeException(nameof(funcSignature)); @@ -77,7 +78,7 @@ public class Generator var str = _strings[i]; _builder.AppendLine($"data $str{i + 1} = {{ b \"{str}\", b 0 }}"); } - + return _builder.ToString(); } @@ -367,21 +368,27 @@ public class Generator { switch (statement) { + case ArrayIndexAssignmentNode arrayIndexAssignment: + throw new NotImplementedException(); + break; case BreakNode: GenerateBreak(); break; case ContinueNode: GenerateContinue(); break; - case FuncCallStatementNode funcCallStatement: - GenerateStatementFuncCall(funcCallStatement); - break; case IfNode ifStatement: GenerateIf(ifStatement); break; + case MemberAssignmentNode memberAssignment: + throw new NotImplementedException(); + break; case ReturnNode @return: GenerateReturn(@return); break; + case StatementExpressionNode statementExpression: + GenerateExpression(statementExpression.Expression); + break; case VariableAssignmentNode variableAssignment: GenerateVariableAssignment(variableAssignment); break; @@ -396,49 +403,6 @@ public class Generator } } - private string GenerateFuncCall(FuncCall funcCall) - { - var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList()); - if (funcDefinition == null) - { - throw new Exception($"Unknown function {funcCall}"); - } - - var parameterStrings = new List(); - - for (var i = 0; i < funcCall.Parameters.Count; i++) - { - if (i < funcDefinition.Parameters.Count && funcDefinition.Parameters[i].Variadic) - { - parameterStrings.Add("..."); - } - - NubType expectedType; - if (i < funcDefinition.Parameters.Count) - { - expectedType = funcDefinition.Parameters[i].Type; - } - else if (funcDefinition.Parameters[^1].Variadic) - { - expectedType = funcDefinition.Parameters[^1].Type; - } - else - { - throw new Exception($"Parameters for func {funcCall} does not not match"); - } - - var parameter = funcCall.Parameters[i]; - var result = GenerateExpression(parameter); - - var qbeParameterType = SQT(expectedType.Equals(NubPrimitiveType.Any) ? parameter.Type : expectedType); - parameterStrings.Add($"{qbeParameterType} {result}"); - } - - var funcName = _funcNames[funcDefinition]; - - return $"call ${funcName}({string.Join(", ", parameterStrings)})"; - } - private void GenerateBlock(BlockNode block) { foreach (var statement in block.Statements.Where(_ => _codeIsReachable)) @@ -461,12 +425,6 @@ public class Generator _codeIsReachable = false; } - private void GenerateStatementFuncCall(FuncCallStatementNode funcCall) - { - var call = GenerateFuncCall(funcCall.FuncCall); - _builder.AppendLine($" {call}"); - } - private void GenerateIf(IfNode ifStatement) { var trueLabel = GenLabelName(); @@ -507,7 +465,7 @@ public class Generator private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment) { var result = GenerateExpression(variableAssignment.Value); - _builder.AppendLine($" storel {result}, {_variables[variableAssignment.Name].Pointer}"); + _builder.AppendLine($" storel {result}, {_variables[variableAssignment.Identifier.Identifier].Pointer}"); } private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration) @@ -515,7 +473,7 @@ public class Generator var pointerName = GenVarName(); var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!; - + _builder.AppendLine($" %{pointerName} ={SQT(type)} alloc8 {QbeTypeSize(type)}"); if (variableDeclaration.Value.HasValue) @@ -527,7 +485,7 @@ public class Generator { _builder.AppendLine($" storel 0, %{pointerName}"); } - + _variables[variableDeclaration.Name] = new Variable { Pointer = $"%{pointerName}", @@ -561,12 +519,12 @@ public class Generator return expression switch { AddressOfNode addressOf => GenerateAddressOf(addressOf), - ArrayIndexNode arrayIndex => GenerateArrayIndex(arrayIndex), + ArrayIndexAccessNode arrayIndex => GenerateArrayIndex(arrayIndex), ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer), BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression), CastNode cast => GenerateCast(cast), DereferenceNode dereference => GenerateDereference(dereference), - FuncCallExpressionNode funcCallExpression => GenerateExpressionFuncCall(funcCallExpression), + FuncCallNode funcCallExpression => GenerateFuncCall(funcCallExpression), IdentifierNode identifier => GenerateIdentifier(identifier), LiteralNode literal => GenerateLiteral(literal), StructInitializerNode structInitializer => GenerateStructInitializer(structInitializer), @@ -576,34 +534,34 @@ public class Generator }; } - private string GenerateArrayIndex(ArrayIndexNode arrayIndex) + private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess) { - var array = GenerateExpression(arrayIndex.Expression); - var index = GenerateExpression(arrayIndex.Index); + var array = GenerateExpression(arrayIndexAccess.Array); + var index = GenerateExpression(arrayIndexAccess.Index); + + var arrayBaseType = ((NubArrayType)arrayIndexAccess.Array.Type).BaseType; - var arrayBaseType = ((NubArrayType)arrayIndex.Expression.Type).BaseType; - var countName = GenVarName(); _builder.AppendLine($" %{countName} =l loadl {array}"); - + var isNegativeName = GenVarName(); _builder.AppendLine($" %{isNegativeName} =w csltl {index}, 0"); - + var isOobName = GenVarName(); _builder.AppendLine($" %{isOobName} =w csgel {index}, %{countName}"); - + var anyOobName = GenVarName(); _builder.AppendLine($" %{anyOobName} =w or %{isNegativeName}, %{isOobName}"); - + var oobLabel = GenLabelName(); var notOobLabel = GenLabelName(); _builder.AppendLine($" jnz %{anyOobName}, @{oobLabel}, @{notOobLabel}"); - + _builder.AppendLine($"@{oobLabel}"); _builder.AppendLine($" call $nub_panic(l $oob_message, l {OutOfBoundsMessage.Length})"); - + _builder.AppendLine($"@{notOobLabel}"); - + // Calculate element address var firstItemPointerName = GenVarName(); _builder.AppendLine($" %{firstItemPointerName} =l add {array}, 8"); @@ -611,7 +569,7 @@ public class Generator _builder.AppendLine($" %{offsetPointerName} =l mul {index}, {QbeTypeSize(arrayBaseType)}"); var resultPointerName = GenVarName(); _builder.AppendLine($" %{resultPointerName} =l add %{firstItemPointerName}, %{offsetPointerName}"); - + // Load the value var outputName = GenVarName(); _builder.AppendLine($" %{outputName} ={SQT(arrayBaseType)} load{SQT(arrayBaseType)} %{resultPointerName}"); @@ -628,11 +586,11 @@ public class Generator var outputName = GenVarName(); _builder.AppendLine($" %{outputName} =l alloc8 %{totalArraySize}"); _builder.AppendLine($" storel {capacity}, %{outputName}"); - + var dataPtr = GenVarName(); _builder.AppendLine($" %{dataPtr} =l add %{outputName}, 8"); _builder.AppendLine($" call $nub_memset(l %{dataPtr}, w 0, l %{capacityInBytes})"); - + return $"%{outputName}"; } @@ -1490,7 +1448,7 @@ public class Generator { throw new Exception($"Struct {structType.Name} is not defined"); } - + var fieldIndex = -1; for (var i = 0; i < structDefinition.Fields.Count; i++) { @@ -1515,14 +1473,54 @@ public class Generator return $"%{outputName}"; } } - + throw new ArgumentOutOfRangeException(nameof(memberAccess.Expression.Type)); } - private string GenerateExpressionFuncCall(FuncCallExpressionNode funcCall) + private string GenerateFuncCall(FuncCallNode funcCall) { var outputName = GenVarName(); - var call = GenerateFuncCall(funcCall.FuncCall); + + var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList()); + if (funcDefinition == null) + { + throw new Exception($"Unknown function {funcCall}"); + } + + var parameterStrings = new List(); + + for (var i = 0; i < funcCall.Parameters.Count; i++) + { + if (i < funcDefinition.Parameters.Count && funcDefinition.Parameters[i].Variadic) + { + parameterStrings.Add("..."); + } + + NubType expectedType; + if (i < funcDefinition.Parameters.Count) + { + expectedType = funcDefinition.Parameters[i].Type; + } + else if (funcDefinition.Parameters[^1].Variadic) + { + expectedType = funcDefinition.Parameters[^1].Type; + } + else + { + throw new Exception($"Parameters for func {funcCall} does not not match"); + } + + var parameter = funcCall.Parameters[i]; + var result = GenerateExpression(parameter); + + var qbeParameterType = SQT(expectedType.Equals(NubPrimitiveType.Any) ? parameter.Type : expectedType); + parameterStrings.Add($"{qbeParameterType} {result}"); + } + + var funcName = _funcNames[funcDefinition]; + + var call = $"call ${funcName}({string.Join(", ", parameterStrings)})"; + _builder.AppendLine($" %{outputName} ={SQT(funcCall.Type)} {call}"); return $"%{outputName}"; } @@ -1531,12 +1529,12 @@ public class Generator { return $"v{++_variableIndex}"; } - + private string GenFuncName() { return $"f{++_funcIndex}"; } - + private string GenLabelName() { return $"l{++_labelIndex}"; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/ArrayIndexNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/ArrayIndexNode.cs deleted file mode 100644 index 174834b..0000000 --- a/src/lang/Nub.Lang/Frontend/Parsing/ArrayIndexNode.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Nub.Lang.Frontend.Lexing; - -namespace Nub.Lang.Frontend.Parsing; - -public class ArrayIndexNode(IReadOnlyList tokens, ExpressionNode expression, ExpressionNode index) : ExpressionNode(tokens) -{ - public ExpressionNode Expression { get; } = expression; - public ExpressionNode Index { get; } = index; -} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/DefinitionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/DefinitionNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/DefinitionNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Definitions/DefinitionNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/FuncDefinitionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/FuncDefinitionNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/StructDefinitionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/StructDefinitionNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/StructDefinitionNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Definitions/StructDefinitionNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/AddressOfNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/AddressOfNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/AddressOfNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/AddressOfNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayIndexAccessNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayIndexAccessNode.cs new file mode 100644 index 0000000..819f237 --- /dev/null +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayIndexAccessNode.cs @@ -0,0 +1,9 @@ +using Nub.Lang.Frontend.Lexing; + +namespace Nub.Lang.Frontend.Parsing; + +public class ArrayIndexAccessNode(IReadOnlyList tokens, ExpressionNode array, ExpressionNode index) : ExpressionNode(tokens) +{ + public ExpressionNode Array { get; } = array; + public ExpressionNode Index { get; } = index; +} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/ArrayInitializerNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayInitializerNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/ArrayInitializerNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayInitializerNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/BinaryExpressionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/BinaryExpressionNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/BinaryExpressionNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/BinaryExpressionNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/CastNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/CastNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/DereferenceNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/DereferenceNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/DereferenceNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/DereferenceNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/ExpressionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ExpressionNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/ExpressionNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/ExpressionNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/FuncCallNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/FuncCallNode.cs new file mode 100644 index 0000000..3609437 --- /dev/null +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/FuncCallNode.cs @@ -0,0 +1,12 @@ +using Nub.Lang.Frontend.Lexing; + +namespace Nub.Lang.Frontend.Parsing; + +public class FuncCallNode(IReadOnlyList tokens, string @namespace, string name, List parameters) : ExpressionNode(tokens) +{ + public string Namespace { get; } = @namespace; + public string Name { get; } = name; + public List Parameters { get; } = parameters; + + public override string ToString() => $"{Name}()"; +} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/IdentifierNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/IdentifierNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/IdentifierNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/IdentifierNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/LiteralNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/LiteralNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/LiteralNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/LiteralNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/MemberAccessNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/MemberAccessNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/MemberAccessNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/MemberAccessNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/StructInitializerNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/StructInitializerNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/StructInitializerNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/StructInitializerNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/UnaryExpressionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/UnaryExpressionNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/UnaryExpressionNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Expressions/UnaryExpressionNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/FuncCall.cs b/src/lang/Nub.Lang/Frontend/Parsing/FuncCall.cs deleted file mode 100644 index 8ee470e..0000000 --- a/src/lang/Nub.Lang/Frontend/Parsing/FuncCall.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Nub.Lang.Frontend.Parsing; - -public class FuncCall(string @namespace, string name, List parameters) -{ - public string Namespace { get; } = @namespace; - public string Name { get; } = name; - public List Parameters { get; } = parameters; - - public override string ToString() => $"{Name}()"; -} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/FuncCallExpressionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/FuncCallExpressionNode.cs deleted file mode 100644 index 3e982c1..0000000 --- a/src/lang/Nub.Lang/Frontend/Parsing/FuncCallExpressionNode.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Nub.Lang.Frontend.Lexing; - -namespace Nub.Lang.Frontend.Parsing; - -public class FuncCallExpressionNode(IReadOnlyList tokens, FuncCall funcCall) : ExpressionNode(tokens) -{ - public FuncCall FuncCall { get; } = funcCall; - - public override string ToString() => FuncCall.ToString(); -} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/FuncCallStatementNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/FuncCallStatementNode.cs deleted file mode 100644 index 16317c8..0000000 --- a/src/lang/Nub.Lang/Frontend/Parsing/FuncCallStatementNode.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Nub.Lang.Frontend.Lexing; - -namespace Nub.Lang.Frontend.Parsing; - -public class FuncCallStatementNode(IReadOnlyList tokens, FuncCall funcCall) : StatementNode(tokens) -{ - public FuncCall FuncCall { get; } = funcCall; - - public override string ToString() => FuncCall.ToString(); -} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs index 00196f0..fc74302 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -178,113 +178,183 @@ public class Parser private StatementNode ParseStatement() { var startIndex = _index; - var token = ExpectToken(); - switch (token) + if (!Peek().TryGetValue(out var token)) { - case IdentifierToken identifier: + throw new ParseException(Diagnostic + .Error("Unexpected end of file while parsing statement") + .At(_tokens.Last()) + .Build()); + } + + if (token is SymbolToken symbol) + { + switch (symbol.Symbol) { - return ParseStatementIdentifier(startIndex, identifier); - } - case SymbolToken symbol: - { - return symbol.Symbol switch - { - Symbol.Return => ParseReturn(startIndex), - Symbol.If => ParseIf(startIndex), - Symbol.While => ParseWhile(startIndex), - Symbol.Let => ParseVariableDeclaration(startIndex), - Symbol.Break => new BreakNode(GetTokensForNode(startIndex)), - Symbol.Continue => new ContinueNode(GetTokensForNode(startIndex)), - _ => throw new ParseException(Diagnostic - .Error($"Unexpected symbol '{symbol.Symbol}' at start of statement") - .WithHelp("Expected identifier, 'let', 'return', 'if', 'while', 'break', or 'continue'") - .At(symbol) - .Build()) - }; - } - default: - { - throw new ParseException(Diagnostic - .Error($"Unexpected token '{token.GetType().Name}' at start of statement") - .WithHelp("Statements must start with an identifier or keyword") - .At(token) - .Build()); + case Symbol.Return: + return ParseReturn(startIndex); + case Symbol.If: + return ParseIf(startIndex); + case Symbol.While: + return ParseWhile(startIndex); + case Symbol.Let: + return ParseVariableDeclaration(startIndex); + case Symbol.Break: + return ParseBreak(startIndex); + case Symbol.Continue: + return ParseContinue(startIndex); } } + + return ParseStatementExpression(startIndex); } - private StatementNode ParseStatementIdentifier(int startIndex, IdentifierToken identifier) + private StatementNode ParseStatementExpression(int startIndex) { - var symbol = ExpectSymbol(); + var expr = ParseExpression(); - if (TryGetBinaryOperator(symbol.Symbol, out var binaryOperator) && Peek().TryGetValue(out var next) && next is SymbolToken { Symbol: Symbol.Assign }) + if (Peek().TryGetValue(out var token)) { - Next(); - var left = new IdentifierNode(GetTokensForNode(startIndex), identifier.Value); - var right = ParseExpression(); - var binOp = new BinaryExpressionNode(GetTokensForNode(startIndex), left, binaryOperator.Value, right); - - return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, binOp); - } - - switch (symbol.Symbol) - { - case Symbol.DoubleColon: + if (token is SymbolToken symbol) { - var name = ExpectIdentifier(); - ExpectSymbol(Symbol.OpenParen); - var parameters = new List(); - while (!TryExpectSymbol(Symbol.CloseParen)) + switch (symbol.Symbol) { - parameters.Add(ParseExpression()); - if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) + case Symbol.Assign: { - _diagnostics.Add(Diagnostic - .Warning("Missing comma between function arguments") - .WithHelp("Add a ',' to separate arguments") - .At(nextToken) - .Build()); + Next(); + switch (expr) + { + case MemberAccessNode memberAccess: + { + var value = ParseExpression(); + return new MemberAssignmentNode(GetTokensForNode(startIndex), memberAccess, value); + } + case ArrayIndexAccessNode arrayIndexAccess: + { + var value = ParseExpression(); + return new ArrayIndexAssignmentNode(GetTokensForNode(startIndex), arrayIndexAccess, value); + } + case IdentifierNode identifier: + { + var value = ParseExpression(); + return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier, value); + } + } + + break; } } - - return new FuncCallStatementNode(GetTokensForNode(startIndex), new FuncCall(identifier.Value, name.Value, parameters)); - } - case Symbol.OpenParen: - { - var parameters = new List(); - while (!TryExpectSymbol(Symbol.CloseParen)) - { - parameters.Add(ParseExpression()); - if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) - { - _diagnostics.Add(Diagnostic - .Warning("Missing comma between function arguments") - .WithHelp("Add a ',' to separate arguments") - .At(nextToken) - .Build()); - } - } - - return new FuncCallStatementNode(GetTokensForNode(startIndex), new FuncCall(_namespace, identifier.Value, parameters)); - } - case Symbol.Assign: - { - var value = ParseExpression(); - return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, value); - } - default: - { - throw new ParseException(Diagnostic - .Error($"Unexpected symbol '{symbol.Symbol}' after identifier") - .WithHelp("Expected '(', '=', or '::' after identifier") - .At(symbol) - .Build()); } } + + return new StatementExpressionNode(GetTokensForNode(startIndex), expr); } + // private StatementNode ParseStatementIdentifier(int startIndex) + // { + // var leftExpr = ParsePrimaryExpression(); + // + // var symbol = ExpectSymbol(); + // + // switch (symbol.Symbol) + // { + // case Symbol.DoubleColon: + // { + // if (leftExpr is not IdentifierNode namespaceNode) + // { + // throw new ParseException(Diagnostic + // .Error("Invalid syntax before '::'") + // .WithHelp("Only identifiers can be used before '::' for namespace resolution") + // .At(symbol) + // .Build()); + // } + // + // var name = ExpectIdentifier(); + // ExpectSymbol(Symbol.OpenParen); + // var parameters = new List(); + // while (!TryExpectSymbol(Symbol.CloseParen)) + // { + // parameters.Add(ParseExpression()); + // if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) + // { + // _diagnostics.Add(Diagnostic + // .Warning("Missing comma between function arguments") + // .WithHelp("Add a ',' to separate arguments") + // .At(nextToken) + // .Build()); + // } + // } + // + // return new FuncCallStatementNode(GetTokensForNode(startIndex), new FuncCall(namespaceNode.Identifier, name.Value, parameters)); + // } + // case Symbol.OpenParen: + // { + // if (leftExpr is not IdentifierNode funcNode) + // { + // throw new ParseException(Diagnostic + // .Error("Invalid syntax before '('") + // .WithHelp("Only identifiers can be called as functions") + // .At(symbol) + // .Build()); + // } + // + // var parameters = new List(); + // while (!TryExpectSymbol(Symbol.CloseParen)) + // { + // parameters.Add(ParseExpression()); + // if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) + // { + // _diagnostics.Add(Diagnostic + // .Warning("Missing comma between function arguments") + // .WithHelp("Add a ',' to separate arguments") + // .At(nextToken) + // .Build()); + // } + // } + // + // return new FuncCallStatementNode(GetTokensForNode(startIndex), new FuncCall(_namespace, funcNode.Identifier, parameters)); + // } + // case Symbol.Assign: + // { + // var value = ParseExpression(); + // + // switch (leftExpr) + // { + // case IdentifierNode identifierNode: + // { + // return new VariableAssignmentNode(GetTokensForNode(startIndex), identifierNode.Identifier, value); + // } + // case ArrayIndexNode arrayIndexNode: + // { + // return new ArrayIndexAssignmentNode(GetTokensForNode(startIndex), arrayIndexNode.Expression, arrayIndexNode.Index, value); + // } + // case MemberAccessNode memberAccessNode: + // { + // return new MemberAssignmentNode(GetTokensForNode(startIndex), memberAccessNode.Expression, memberAccessNode.Member, value); + // } + // default: + // { + // throw new ParseException(Diagnostic + // .Error("Invalid left-hand side in assignment") + // .WithHelp("Left side must be a variable, array element, or struct member") + // .At(symbol) + // .Build()); + // } + // } + // } + // default: + // { + // throw new ParseException(Diagnostic + // .Error($"Unexpected symbol '{symbol.Symbol}' after identifier") + // .WithHelp("Expected '(', '=', or '::' after identifier") + // .At(symbol) + // .Build()); + // } + // } + // } + private VariableDeclarationNode ParseVariableDeclaration(int startIndex) { + ExpectSymbol(Symbol.Let); var name = ExpectIdentifier().Value; var type = Optional.Empty(); if (TryExpectSymbol(Symbol.Colon)) @@ -301,8 +371,22 @@ public class Parser return new VariableDeclarationNode(GetTokensForNode(startIndex), name, type, value); } + private StatementNode ParseBreak(int startIndex) + { + ExpectSymbol(Symbol.Break); + Next(); + return new BreakNode(GetTokensForNode(startIndex)); + } + + private StatementNode ParseContinue(int startIndex) + { + ExpectSymbol(Symbol.Continue); + return new ContinueNode(GetTokensForNode(startIndex)); + } + private ReturnNode ParseReturn(int startIndex) { + ExpectSymbol(Symbol.Return); var value = Optional.Empty(); if (!TryExpectSymbol(Symbol.Semicolon)) { @@ -314,6 +398,7 @@ public class Parser private IfNode ParseIf(int startIndex) { + ExpectSymbol(Symbol.If); var condition = ParseExpression(); var body = ParseBlock(); @@ -331,6 +416,7 @@ public class Parser private WhileNode ParseWhile(int startIndex) { + ExpectSymbol(Symbol.While); var condition = ParseExpression(); var body = ParseBlock(); return new WhileNode(GetTokensForNode(startIndex), condition, body); @@ -454,7 +540,7 @@ public class Parser } } - expr = new FuncCallExpressionNode(GetTokensForNode(startIndex), new FuncCall(identifier.Value, name.Value, parameters)); + expr = new FuncCallNode(GetTokensForNode(startIndex), identifier.Value, name.Value, parameters); break; } case SymbolToken { Symbol: Symbol.OpenParen }: @@ -474,7 +560,7 @@ public class Parser } } - expr = new FuncCallExpressionNode(GetTokensForNode(startIndex), new FuncCall(_namespace, identifier.Value, parameters)); + expr = new FuncCallNode(GetTokensForNode(startIndex), _namespace, identifier.Value, parameters); break; } default: @@ -554,7 +640,7 @@ public class Parser .Build()); } - expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers); + expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers); break; } default: @@ -603,7 +689,7 @@ public class Parser { var index = ParseExpression(); ExpectSymbol(Symbol.CloseBracket); - expr = new ArrayIndexNode(GetTokensForNode(startIndex), expr, index); + expr = new ArrayIndexAccessNode(GetTokensForNode(startIndex), expr, index); continue; } @@ -798,7 +884,7 @@ public class Parser { if (token is SymbolToken { Symbol: Symbol.CloseBrace } or IdentifierToken or SymbolToken { - Symbol: Symbol.Return or Symbol.If or Symbol.While or Symbol.Break or Symbol.Continue + Symbol: Symbol.Return or Symbol.If or Symbol.While or Symbol.Let or Symbol.Break or Symbol.Continue }) { break; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Statements/ArrayIndexAssignmentNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/ArrayIndexAssignmentNode.cs new file mode 100644 index 0000000..754e118 --- /dev/null +++ b/src/lang/Nub.Lang/Frontend/Parsing/Statements/ArrayIndexAssignmentNode.cs @@ -0,0 +1,9 @@ +using Nub.Lang.Frontend.Lexing; + +namespace Nub.Lang.Frontend.Parsing; + +public class ArrayIndexAssignmentNode(IReadOnlyList tokens, ArrayIndexAccessNode arrayIndexAccess, ExpressionNode value) : StatementNode(tokens) +{ + public ArrayIndexAccessNode ArrayIndexAccess { get; } = arrayIndexAccess; + public ExpressionNode Value { get; } = value; +} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/BlockNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/BlockNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/BlockNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/BlockNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/BreakNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/BreakNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/BreakNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/BreakNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/ContinueNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/ContinueNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/ContinueNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/ContinueNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/IfNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/IfNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/IfNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/IfNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Statements/MemberAssignmentNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/MemberAssignmentNode.cs new file mode 100644 index 0000000..b057c31 --- /dev/null +++ b/src/lang/Nub.Lang/Frontend/Parsing/Statements/MemberAssignmentNode.cs @@ -0,0 +1,9 @@ +using Nub.Lang.Frontend.Lexing; + +namespace Nub.Lang.Frontend.Parsing; + +public class MemberAssignmentNode(IReadOnlyList tokens, MemberAccessNode expression, ExpressionNode value) : StatementNode(tokens) +{ + public MemberAccessNode MemberAccess { get; } = expression; + public ExpressionNode Value { get; } = value; +} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/ReturnNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/ReturnNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/ReturnNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/ReturnNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Statements/StatementExpressionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/StatementExpressionNode.cs new file mode 100644 index 0000000..cf2d7d4 --- /dev/null +++ b/src/lang/Nub.Lang/Frontend/Parsing/Statements/StatementExpressionNode.cs @@ -0,0 +1,8 @@ +using Nub.Lang.Frontend.Lexing; + +namespace Nub.Lang.Frontend.Parsing; + +public class StatementExpressionNode(IReadOnlyList tokens, ExpressionNode expression) : StatementNode(tokens) +{ + public ExpressionNode Expression { get; } = expression; +} \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/StatementNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/StatementNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/StatementNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/StatementNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/VariableAssignmentNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/VariableAssignmentNode.cs similarity index 62% rename from src/lang/Nub.Lang/Frontend/Parsing/VariableAssignmentNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/VariableAssignmentNode.cs index 93a3304..dd12c48 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/VariableAssignmentNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Statements/VariableAssignmentNode.cs @@ -3,8 +3,8 @@ using Nub.Lang.Frontend.Typing; namespace Nub.Lang.Frontend.Parsing; -public class VariableAssignmentNode(IReadOnlyList tokens, string name, ExpressionNode value) : StatementNode(tokens) +public class VariableAssignmentNode(IReadOnlyList tokens, IdentifierNode identifier, ExpressionNode value) : StatementNode(tokens) { - public string Name { get; } = name; + public IdentifierNode Identifier { get; } = identifier; public ExpressionNode Value { get; } = value; } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/VariableDeclarationNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/VariableDeclarationNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/VariableDeclarationNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/VariableDeclarationNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Parsing/WhileNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Statements/WhileNode.cs similarity index 100% rename from src/lang/Nub.Lang/Frontend/Parsing/WhileNode.cs rename to src/lang/Nub.Lang/Frontend/Parsing/Statements/WhileNode.cs diff --git a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs index cddf0fe..a1c09e3 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs @@ -108,24 +108,30 @@ public class TypeChecker { switch (statement) { + case ArrayIndexAssignmentNode arrayIndexAssignment: + TypeCheckArrayIndexAssignment(arrayIndexAssignment); + break; case VariableAssignmentNode variableAssignment: TypeCheckVariableAssignment(variableAssignment); break; case VariableDeclarationNode variableDeclaration: TypeCheckVariableVariableDeclaration(variableDeclaration); break; - case FuncCallStatementNode funcCall: - TypeCheckFuncCall(funcCall.FuncCall, funcCall); - break; case IfNode ifNode: TypeCheckIf(ifNode); break; + case MemberAssignmentNode memberAssignment: + TypeCheckMemberAssignment(memberAssignment); + break; case WhileNode whileNode: TypeCheckWhile(whileNode); break; case ReturnNode returnNode: TypeCheckReturn(returnNode); break; + case StatementExpressionNode statementExpression: + TypeCheckExpression(statementExpression.Expression); + break; case BreakNode: case ContinueNode: break; @@ -135,20 +141,46 @@ public class TypeChecker } } + private void TypeCheckMemberAssignment(MemberAssignmentNode memberAssignment) + { + var memberType = TypeCheckExpression(memberAssignment.MemberAccess); + if (memberType == null) return; + var valueType = TypeCheckExpression(memberAssignment.Value); + if (valueType == null) return; + + if (!NubType.IsCompatibleWith(memberType, valueType)) + { + ReportError($"'{valueType}' is not assignable to member of type '{memberType}'", memberAssignment); + } + } + + private void TypeCheckArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment) + { + var itemType = TypeCheckExpression(arrayIndexAssignment.ArrayIndexAccess); + if (itemType == null) return; + var valueType = TypeCheckExpression(arrayIndexAssignment.Value); + if (valueType == null) return; + + if (!NubType.IsCompatibleWith(itemType, valueType)) + { + ReportError($"'{valueType}' is not assignable to array of type '{itemType}'", arrayIndexAssignment); + } + } + private void TypeCheckVariableAssignment(VariableAssignmentNode variableAssignment) { var valueType = TypeCheckExpression(variableAssignment.Value); if (valueType == null) return; - if (!_variables.TryGetValue(variableAssignment.Name, out var existingVariable)) + if (!_variables.TryGetValue(variableAssignment.Identifier.Identifier, out var existingVariable)) { - ReportError($"Variable '{variableAssignment.Name}' is not declared", variableAssignment); + ReportError($"Variable '{variableAssignment.Identifier}' is not declared", variableAssignment); return; } if (!NubType.IsCompatibleWith(variableAssignment.Value.Type, existingVariable)) { - ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Name}' with type '{existingVariable}'", variableAssignment); + ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Identifier}' with type '{existingVariable}'", variableAssignment); } } @@ -204,7 +236,7 @@ public class TypeChecker return nubPointerType.BaseType; } - private NubType? TypeCheckFuncCall(FuncCall funcCall, Node node) + private NubType? TypeCheckFuncCall(FuncCallNode funcCall, Node node) { List parameterTypes = []; foreach (var funcCallParameter in funcCall.Parameters) @@ -314,14 +346,14 @@ public class TypeChecker var resultType = expression switch { AddressOfNode addressOf => TypeCheckAddressOf(addressOf), - ArrayIndexNode arrayIndex => TypeCheckArrayIndex(arrayIndex), + ArrayIndexAccessNode arrayIndex => TypeCheckArrayIndex(arrayIndex), ArrayInitializerNode arrayInitializer => TypeCheckArrayInitializer(arrayInitializer), LiteralNode literal => literal.LiteralType, IdentifierNode identifier => TypeCheckIdentifier(identifier), BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr), CastNode cast => TypeCheckCast(cast), DereferenceNode dereference => TypeCheckDereference(dereference), - FuncCallExpressionNode funcCallExpr => TypeCheckFuncCall(funcCallExpr.FuncCall, funcCallExpr), + FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr), StructInitializerNode structInit => TypeCheckStructInitializer(structInit), UnaryExpressionNode unaryExpression => TypeCheckUnaryExpression(unaryExpression), MemberAccessNode memberAccess => TypeCheckMemberAccess(memberAccess), @@ -342,21 +374,21 @@ public class TypeChecker return null; } - private NubType? TypeCheckArrayIndex(ArrayIndexNode arrayIndex) + private NubType? TypeCheckArrayIndex(ArrayIndexAccessNode arrayIndexAccess) { - var expressionType = TypeCheckExpression(arrayIndex.Expression); + var expressionType = TypeCheckExpression(arrayIndexAccess.Array); if (expressionType == null) return null; if (expressionType is not NubArrayType arrayType) { - ReportError($"Cannot access index of non-array type {expressionType}", arrayIndex.Expression); + ReportError($"Cannot access index of non-array type {expressionType}", arrayIndexAccess.Array); return null; } - var indexType = TypeCheckExpression(arrayIndex.Index); + var indexType = TypeCheckExpression(arrayIndexAccess.Index); if (indexType != null && !IsInteger(indexType)) { - ReportError("Array index type must be an integer", arrayIndex.Index); + ReportError("Array index type must be an integer", arrayIndexAccess.Index); } return arrayType.BaseType;