From 00a249f84d8fec6e90737cc19cf27f44865a0c6f Mon Sep 17 00:00:00 2001 From: nub31 Date: Mon, 2 Jun 2025 15:52:06 +0200 Subject: [PATCH] ... --- example/main.nub | 31 ++++-- src/lang/Nub.Lang/Backend/Generator.cs | 68 +++++------- .../Parsing/Definitions/FuncDefinitionNode.cs | 8 +- src/lang/Nub.Lang/Frontend/Parsing/Parser.cs | 103 ------------------ 4 files changed, 56 insertions(+), 154 deletions(-) diff --git a/example/main.nub b/example/main.nub index d589687..8282950 100644 --- a/example/main.nub +++ b/example/main.nub @@ -1,12 +1,29 @@ namespace main -export func main(args: []^string) { - c::printf("%d\n", args.count) - - let i: i64 +struct Human { + name: string + age: i64 +} - while i < args.count { - c::printf("%s\n", args[i]) - i = i + 1 +export func main(args: []^string) { + // c::printf("%d\n", args.count) + + // let i: i64 + + // while i < args.count { + // c::printf("%s\n", args[i]) + // i = i + 1 + // } + + let human = alloc Human { + age = 23 + name = "oliver" } + + c::printf("%s is %d years old\n", human.name, human.age) + + // human.name = "hubert" + // human.age = 92 + + c::printf("%s is %d years old\n", human.name, human.age) } \ 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 6a721fb..5394d73 100644 --- a/src/lang/Nub.Lang/Backend/Generator.cs +++ b/src/lang/Nub.Lang/Backend/Generator.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System.Diagnostics; +using System.Globalization; using System.Text; using Nub.Lang.Frontend.Parsing; using Nub.Lang.Frontend.Typing; @@ -255,11 +256,6 @@ public class Generator case NubStructType nubStructType: { var definition = LookupStructDefinition(nubStructType.Namespace, nubStructType.Name); - if (definition == null) - { - throw new Exception($"Cannot determine size of non-existent type {nubStructType}"); - } - return definition.Fields.Sum(f => QbeTypeSize(f.Type)); } case NubPointerType: @@ -381,7 +377,7 @@ public class Generator GenerateIf(ifStatement); break; case MemberAssignmentNode memberAssignment: - throw new NotImplementedException(); + GenerateMemberAssignment(memberAssignment); break; case ReturnNode @return: GenerateReturn(@return); @@ -449,6 +445,17 @@ public class Generator _builder.AppendLine($"@{endLabel}"); } + private void GenerateMemberAssignment(MemberAssignmentNode memberAssignment) + { + var structType = memberAssignment.MemberAccess.Expression.Type as NubStructType; + Debug.Assert(structType != null); + + var structDefinition = LookupStructDefinition(structType.Namespace, structType.Name); + var item = GenerateExpression(memberAssignment.MemberAccess.Expression); + var value = GenerateExpression(memberAssignment.Value); + + } + private void GenerateReturn(ReturnNode @return) { if (@return.Value.HasValue) @@ -1340,13 +1347,8 @@ public class Generator private string GenerateStructInitializer(StructInitializerNode structInitializer) { var structDefinition = LookupStructDefinition(structInitializer.StructType.Namespace, structInitializer.StructType.Name); - if (structDefinition == null) - { - throw new Exception($"Struct {structInitializer.StructType.Name} is not defined"); - } - + var structVar = GenVarName(); - var size = structDefinition.Fields.Sum(x => QbeTypeSize(x.Type)); _builder.AppendLine($" %{structVar} =l alloc8 {size}"); @@ -1426,7 +1428,7 @@ public class Generator private string GenerateMemberAccess(MemberAccessNode memberAccess) { - var expression = GenerateExpression(memberAccess.Expression); + var item = GenerateExpression(memberAccess.Expression); switch (memberAccess.Expression.Type) { @@ -1435,7 +1437,7 @@ public class Generator if (memberAccess.Member == "count") { var outputName = GenVarName(); - _builder.AppendLine($" %{outputName} =l loadl {expression}"); + _builder.AppendLine($" %{outputName} =l loadl {item}"); return $"%{outputName}"; } @@ -1443,29 +1445,10 @@ public class Generator } case NubStructType structType: { - var structDefinition = LookupStructDefinition(structType.Namespace, structType.Namespace); - if (structDefinition == null) - { - throw new Exception($"Struct {structType.Name} is not defined"); - } - - var fieldIndex = -1; - for (var i = 0; i < structDefinition.Fields.Count; i++) - { - if (structDefinition.Fields[i].Name == memberAccess.Member) - { - fieldIndex = i; - break; - } - } - - if (fieldIndex == -1) - { - throw new Exception($"Field {memberAccess.Member} is not defined in struct {structType.Name}"); - } + var structDefinition = LookupStructDefinition(structType.Namespace, structType.Name); var offsetName = GenVarName(); - _builder.AppendLine($" %{offsetName} =l add {expression}, {fieldIndex * QbeTypeSize(memberAccess.Type)}"); + _builder.AppendLine($" %{offsetName} =l add {item}, {LookupStructOffset(structDefinition, memberAccess.Member)}"); var outputName = GenVarName(); _builder.AppendLine($" %{outputName} ={SQT(memberAccess.Type)} load{SQT(memberAccess.Type)} %{offsetName}"); @@ -1540,22 +1523,27 @@ public class Generator return $"l{++_labelIndex}"; } - private IFuncSignature? LookupFuncSignature(string @namespace, string name, List parameters) + private IFuncSignature LookupFuncSignature(string @namespace, string name, List parameters) { return _sourceFiles .Where(f => f.Namespace == @namespace) .SelectMany(f => f.Definitions) .OfType() - .FirstOrDefault(f => f.SignatureMatches(name, parameters)); + .Single(f => f.SignatureMatches(name, parameters)); } - private StructDefinitionNode? LookupStructDefinition(string @namespace, string name) + private StructDefinitionNode LookupStructDefinition(string @namespace, string name) { return _sourceFiles .Where(f => f.Namespace == @namespace) .SelectMany(f => f.Definitions) .OfType() - .FirstOrDefault(d => d.Name == name); + .Single(s => s.Name == name); + } + + private int LookupStructOffset(StructDefinitionNode structDefinition, string member) + { + return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => QbeTypeSize(f.Type)); } private class Variable diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs index c139f2e..01b9e6e 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs @@ -23,12 +23,12 @@ public interface IFuncSignature if (Name != name) return false; if (Parameters.Count == 0 && parameters.Count == 0) return true; if (Parameters.Count > parameters.Count) return false; - + for (var i = 0; i < parameters.Count; i++) { - if (i > Parameters.Count) + if (i >= Parameters.Count) { - if (Parameters[^1].Variadic) + if (Parameters.Count > 0 && Parameters[^1].Variadic) { if (!NubType.IsCompatibleWith(parameters[i], Parameters[^1].Type)) { @@ -45,7 +45,7 @@ public interface IFuncSignature return false; } } - + return true; } diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs index fc74302..d612c7b 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -249,109 +249,6 @@ public class Parser 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);