From 403adefa6a57878c4932e8123cdca16132f1f749 Mon Sep 17 00:00:00 2001 From: nub31 Date: Mon, 12 May 2025 20:47:46 +0200 Subject: [PATCH] variadics --- example/c/bindings.nub | 3 +- example/program.nub | 9 +-- run.sh | 1 - src/compiler/Nub.Lang/Backend/Generator.cs | 62 ++++++++++++++----- .../Nub.Lang/Frontend/Lexing/Lexer.cs | 1 - .../Nub.Lang/Frontend/Lexing/SymbolToken.cs | 1 - .../Nub.Lang/Frontend/Parsing/Parser.cs | 57 +++++++---------- .../Parsing/VariableReassignmentNode.cs | 7 --- .../Frontend/Typing/ExpressionTyper.cs | 9 +-- src/compiler/Nub.Lang/FuncParameter.cs | 3 +- src/compiler/Nub.Lang/NubType.cs | 24 +++---- src/runtime/runtime.asm | 2 +- 12 files changed, 84 insertions(+), 95 deletions(-) delete mode 100644 src/compiler/Nub.Lang/Frontend/Parsing/VariableReassignmentNode.cs diff --git a/example/c/bindings.nub b/example/c/bindings.nub index a9d3cdb..3c4ba44 100644 --- a/example/c/bindings.nub +++ b/example/c/bindings.nub @@ -1 +1,2 @@ -extern func puts(str: string); \ No newline at end of file +extern func puts(str: string); +extern func printf(fmt: string, ...args: any); \ No newline at end of file diff --git a/example/program.nub b/example/program.nub index 5dd006a..46dcf7e 100644 --- a/example/program.nub +++ b/example/program.nub @@ -1,12 +1,5 @@ import "c"; global func main() { - if 3 / 3 == 1 { - puts("uwu"); - } - - while 1 == 1 { - puts("test"); - break; - } + printf("something %s\n", "your mom"); } \ No newline at end of file diff --git a/run.sh b/run.sh index 8ddafc7..385090b 100755 --- a/run.sh +++ b/run.sh @@ -1,5 +1,4 @@ #!/bin/sh -set -e ./clean.sh ./build.sh ./out/program diff --git a/src/compiler/Nub.Lang/Backend/Generator.cs b/src/compiler/Nub.Lang/Backend/Generator.cs index 5b73c77..9c528a8 100644 --- a/src/compiler/Nub.Lang/Backend/Generator.cs +++ b/src/compiler/Nub.Lang/Backend/Generator.cs @@ -85,16 +85,33 @@ public class Generator { _builder.Append($"{QbeTypeName(node.ReturnType.Value)} "); } + else + { + _builder.Append("l "); + } _builder.Append('$'); _builder.Append(node.Name); - _builder.AppendLine($"({string.Join(", ", node.Parameters.Select(p => $"{QbeTypeName(p.Type)} %{p.Name}"))}) {{"); + var parameterStrings = new List(); + foreach (var parameter in node.Parameters) + { + if (parameter.Variadic) + { + parameterStrings.Add("..."); + } + else + { + parameterStrings.Add($"{QbeTypeName(parameter.Type)} %{parameter.Name}"); + } + } + + _builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{"); _builder.AppendLine("@start"); GenerateBlock(node.Body); if (!node.ReturnType.HasValue) { - _builder.AppendLine(" ret"); + _builder.AppendLine(" ret 0"); } _builder.AppendLine("}"); @@ -138,9 +155,6 @@ public class Generator case VariableAssignmentNode variableAssignment: GenerateVariableAssignment(variableAssignment); break; - case VariableReassignmentNode variableReassignment: - GenerateVariableReassignment(variableReassignment); - break; case WhileNode whileStatement: GenerateWhile(whileStatement); break; @@ -163,15 +177,39 @@ public class Generator private void GenerateStatementFuncCall(FuncCallStatementNode funcCall) { + var parameterDefinition = _definitions + .OfType() + .FirstOrDefault(d => d.Name == funcCall.FuncCall.Name) + ?.Parameters; + + parameterDefinition ??= _definitions + .OfType() + .FirstOrDefault(d => d.Name == funcCall.FuncCall.Name) + ?.Parameters; + + if (parameterDefinition == null) + { + throw new Exception($"Unknown function {funcCall.FuncCall}"); + } + var results = new List<(string, NubType)>(); foreach (var parameter in funcCall.FuncCall.Parameters) { results.Add((GenerateExpression(parameter), parameter.Type)); } - var parameters = results.Select(p => $"{QbeTypeName(p.Item2)} {p.Item1}"); + var parameterStrings = new List(); + for (var i = 0; i < results.Count; i++) + { + if (parameterDefinition.Count > i && parameterDefinition[i].Variadic) + { + parameterStrings.Add("..."); + } + + parameterStrings.Add($"{QbeTypeName(results[i].Item2)} {results[i].Item1}"); + } - _builder.AppendLine($" call ${funcCall.FuncCall.Name}({string.Join(", ", parameters)})"); + _builder.AppendLine($" call ${funcCall.FuncCall.Name}({string.Join(", ", parameterStrings)})"); } private void GenerateIf(IfNode ifStatement) @@ -221,16 +259,6 @@ public class Generator }; } - private void GenerateVariableReassignment(VariableReassignmentNode variableReassignment) - { - var result = GenerateExpression(variableReassignment.Value); - _variables[variableReassignment.Name] = new Variable - { - Identifier = result, - Type = variableReassignment.Value.Type - }; - } - private void GenerateWhile(WhileNode whileStatement) { var conditionLabel = GenName("condition"); diff --git a/src/compiler/Nub.Lang/Frontend/Lexing/Lexer.cs b/src/compiler/Nub.Lang/Frontend/Lexing/Lexer.cs index a3def22..ed15a4d 100644 --- a/src/compiler/Nub.Lang/Frontend/Lexing/Lexer.cs +++ b/src/compiler/Nub.Lang/Frontend/Lexing/Lexer.cs @@ -8,7 +8,6 @@ public class Lexer ["global"] = Symbol.Global, ["extern"] = Symbol.Extern, ["import"] = Symbol.Import, - ["let"] = Symbol.Let, ["if"] = Symbol.If, ["else"] = Symbol.Else, ["while"] = Symbol.While, diff --git a/src/compiler/Nub.Lang/Frontend/Lexing/SymbolToken.cs b/src/compiler/Nub.Lang/Frontend/Lexing/SymbolToken.cs index a73c376..ccaa7ec 100644 --- a/src/compiler/Nub.Lang/Frontend/Lexing/SymbolToken.cs +++ b/src/compiler/Nub.Lang/Frontend/Lexing/SymbolToken.cs @@ -13,7 +13,6 @@ public enum Symbol Global, Func, Return, - Let, If, Else, While, diff --git a/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs b/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs index c37f2ed..59e8f8b 100644 --- a/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs @@ -68,14 +68,14 @@ public class Parser var returnType = Optional.Empty(); if (TryExpectSymbol(Symbol.Colon)) { - returnType = ParseTypeInstance(); + returnType = ParseType(); } var body = ParseBlock(); return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, false); } - + private LocalFuncDefinitionNode ParseGlobalFuncDefinition() { ExpectSymbol(Symbol.Func); @@ -94,7 +94,7 @@ public class Parser var returnType = Optional.Empty(); if (TryExpectSymbol(Symbol.Colon)) { - returnType = ParseTypeInstance(); + returnType = ParseType(); } var body = ParseBlock(); @@ -120,7 +120,7 @@ public class Parser var returnType = Optional.Empty(); if (TryExpectSymbol(Symbol.Colon)) { - returnType = ParseTypeInstance(); + returnType = ParseType(); } ExpectSymbol(Symbol.Semicolon); @@ -140,7 +140,7 @@ public class Parser { var variableName = ExpectIdentifier().Value; ExpectSymbol(Symbol.Colon); - var variableType = ParseTypeInstance(); + var variableType = ParseType(); var variableValue = Optional.Empty(); @@ -159,11 +159,19 @@ public class Parser private FuncParameter ParseFuncParameter() { + var variadic = false; + if (TryExpectSymbol(Symbol.Period)) + { + ExpectSymbol(Symbol.Period); + ExpectSymbol(Symbol.Period); + variadic = true; + } + var name = ExpectIdentifier(); ExpectSymbol(Symbol.Colon); - var type = ParseTypeInstance(); + var type = ParseType(); - return new FuncParameter(name.Value, type); + return new FuncParameter(name.Value, type, variadic); } private StatementNode ParseStatement() @@ -193,7 +201,7 @@ public class Parser { var value = ParseExpression(); ExpectSymbol(Symbol.Semicolon); - return new VariableReassignmentNode(identifier.Value, value); + return new VariableAssignmentNode(identifier.Value, value); } default: { @@ -206,7 +214,6 @@ public class Parser return symbol.Symbol switch { Symbol.Return => ParseReturn(), - Symbol.Let => ParseVariableAssignment(), Symbol.If => ParseIf(), Symbol.While => ParseWhile(), Symbol.Break => ParseBreak(), @@ -233,16 +240,6 @@ public class Parser return new ReturnNode(value); } - private VariableAssignmentNode ParseVariableAssignment() - { - var name = ExpectIdentifier().Value; - ExpectSymbol(Symbol.Assign); - var value = ParseExpression(); - ExpectSymbol(Symbol.Semicolon); - - return new VariableAssignmentNode(name, value); - } - private IfNode ParseIf() { var condition = ParseExpression(); @@ -381,7 +378,7 @@ public class Parser } case Symbol.New: { - var type = ParseTypeInstance(); + var type = ParseType(); Dictionary initializers = []; ExpectSymbol(Symbol.OpenBrace); while (!TryExpectSymbol(Symbol.CloseBrace)) @@ -424,11 +421,11 @@ public class Parser { Next(); ExpressionNode result = new IdentifierNode(identifier.Value); - + do { var field = ExpectIdentifier(); - result = new StructFieldAccessorNode(result, field.Value); + result = new StructFieldAccessorNode(result, field.Value); } while (TryExpectSymbol(Symbol.Period)); return result; @@ -466,22 +463,10 @@ public class Parser return new BlockNode(statements); } - private NubType ParseTypeInstance() + private NubType ParseType() { - var parameters = new List(); var name = ExpectIdentifier().Value; - - if (TryExpectSymbol(Symbol.LessThan)) - { - do - { - parameters.Add(ParseTypeInstance()); - } while (TryExpectSymbol(Symbol.Comma)); - - ExpectSymbol(Symbol.GreaterThan); - } - - return new NubType(name, parameters.ToArray()); + return new NubType(name); } private Token ExpectToken() diff --git a/src/compiler/Nub.Lang/Frontend/Parsing/VariableReassignmentNode.cs b/src/compiler/Nub.Lang/Frontend/Parsing/VariableReassignmentNode.cs deleted file mode 100644 index 74fa9a4..0000000 --- a/src/compiler/Nub.Lang/Frontend/Parsing/VariableReassignmentNode.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Nub.Lang.Frontend.Parsing; - -public class VariableReassignmentNode(string name, ExpressionNode value) : StatementNode -{ - public string Name { get; } = name; - public ExpressionNode Value { get; } = value; -} \ No newline at end of file diff --git a/src/compiler/Nub.Lang/Frontend/Typing/ExpressionTyper.cs b/src/compiler/Nub.Lang/Frontend/Typing/ExpressionTyper.cs index d637940..63e8ebc 100644 --- a/src/compiler/Nub.Lang/Frontend/Typing/ExpressionTyper.cs +++ b/src/compiler/Nub.Lang/Frontend/Typing/ExpressionTyper.cs @@ -102,9 +102,6 @@ public class ExpressionTyper case VariableAssignmentNode variableAssignment: PopulateVariableAssignment(variableAssignment); break; - case VariableReassignmentNode variableReassignment: - PopulateVariableReassignment(variableReassignment); - break; case WhileNode whileStatement: PopulateWhileStatement(whileStatement); break; @@ -149,9 +146,9 @@ public class ExpressionTyper _variables.Push(new Variable(variableAssignment.Name, variableAssignment.Value.Type)); } - private void PopulateVariableReassignment(VariableReassignmentNode variableReassignment) + private void PopulateVariableReassignment(VariableAssignmentNode variableAssignment) { - PopulateExpression(variableReassignment.Value); + PopulateExpression(variableAssignment.Value); } private void PopulateWhileStatement(WhileNode whileStatement) @@ -200,7 +197,7 @@ public class ExpressionTyper case BinaryExpressionOperator.LessThan: case BinaryExpressionOperator.LessThanOrEqual: { - binaryExpression.Type = new NubType("bool", []); + binaryExpression.Type = new NubType("bool"); break; } case BinaryExpressionOperator.Plus: diff --git a/src/compiler/Nub.Lang/FuncParameter.cs b/src/compiler/Nub.Lang/FuncParameter.cs index f6c49de..6f19992 100644 --- a/src/compiler/Nub.Lang/FuncParameter.cs +++ b/src/compiler/Nub.Lang/FuncParameter.cs @@ -1,9 +1,10 @@ namespace Nub.Lang; -public class FuncParameter(string name, NubType type) +public class FuncParameter(string name, NubType type, bool variadic) { public string Name { get; } = name; public NubType Type { get; } = type; + public bool Variadic { get; } = variadic; public override string ToString() => $"{Name}: {Type}"; } \ No newline at end of file diff --git a/src/compiler/Nub.Lang/NubType.cs b/src/compiler/Nub.Lang/NubType.cs index 3ced0a5..866881e 100644 --- a/src/compiler/Nub.Lang/NubType.cs +++ b/src/compiler/Nub.Lang/NubType.cs @@ -2,37 +2,31 @@ public sealed class NubType { - public NubType(string name, NubType[] generics) + public NubType(string name) { Name = name; - Generics = generics; } public string Name { get; } - public NubType[] Generics { get; } - public static NubType Int64 => new("int64", []); - public static NubType Int32 => new("int32", []); - public static NubType Bool => new("bool", []); - public static NubType String => new("string", []); + public static NubType Int64 => new("i64"); + public static NubType Int32 => new("i32"); + public static NubType Bool => new("bool"); + public static NubType String => new("string"); + public static NubType Any => new("any"); public override bool Equals(object? obj) { - if (obj is not NubType item) - { - return false; - } - - return Name.Equals(item.Name) && Generics.SequenceEqual(item.Generics); + return obj is NubType item && Name.Equals(item.Name); } public override int GetHashCode() { - return HashCode.Combine(Name, Generics); + return HashCode.Combine(Name); } public override string ToString() { - return $"{Name}<{string.Join(", ", Generics.Select(x => x.ToString()))}>"; + return $"{Name}"; } } \ No newline at end of file diff --git a/src/runtime/runtime.asm b/src/runtime/runtime.asm index 57a5bc5..aa8559a 100644 --- a/src/runtime/runtime.asm +++ b/src/runtime/runtime.asm @@ -5,8 +5,8 @@ section .text _start: call gc_init call main + mov rdi, rax mov rax, 60 - mov rdi, 0 syscall global nub_strcmp