variadics

This commit is contained in:
nub31
2025-05-12 20:47:46 +02:00
parent 66fd6e3beb
commit 403adefa6a
12 changed files with 84 additions and 95 deletions

View File

@@ -1 +1,2 @@
extern func puts(str: string); extern func puts(str: string);
extern func printf(fmt: string, ...args: any);

View File

@@ -1,12 +1,5 @@
import "c"; import "c";
global func main() { global func main() {
if 3 / 3 == 1 { printf("something %s\n", "your mom");
puts("uwu");
}
while 1 == 1 {
puts("test");
break;
}
} }

1
run.sh
View File

@@ -1,5 +1,4 @@
#!/bin/sh #!/bin/sh
set -e
./clean.sh ./clean.sh
./build.sh ./build.sh
./out/program ./out/program

View File

@@ -85,16 +85,33 @@ public class Generator
{ {
_builder.Append($"{QbeTypeName(node.ReturnType.Value)} "); _builder.Append($"{QbeTypeName(node.ReturnType.Value)} ");
} }
else
{
_builder.Append("l ");
}
_builder.Append('$'); _builder.Append('$');
_builder.Append(node.Name); _builder.Append(node.Name);
_builder.AppendLine($"({string.Join(", ", node.Parameters.Select(p => $"{QbeTypeName(p.Type)} %{p.Name}"))}) {{"); var parameterStrings = new List<string>();
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"); _builder.AppendLine("@start");
GenerateBlock(node.Body); GenerateBlock(node.Body);
if (!node.ReturnType.HasValue) if (!node.ReturnType.HasValue)
{ {
_builder.AppendLine(" ret"); _builder.AppendLine(" ret 0");
} }
_builder.AppendLine("}"); _builder.AppendLine("}");
@@ -138,9 +155,6 @@ public class Generator
case VariableAssignmentNode variableAssignment: case VariableAssignmentNode variableAssignment:
GenerateVariableAssignment(variableAssignment); GenerateVariableAssignment(variableAssignment);
break; break;
case VariableReassignmentNode variableReassignment:
GenerateVariableReassignment(variableReassignment);
break;
case WhileNode whileStatement: case WhileNode whileStatement:
GenerateWhile(whileStatement); GenerateWhile(whileStatement);
break; break;
@@ -163,15 +177,39 @@ public class Generator
private void GenerateStatementFuncCall(FuncCallStatementNode funcCall) private void GenerateStatementFuncCall(FuncCallStatementNode funcCall)
{ {
var parameterDefinition = _definitions
.OfType<LocalFuncDefinitionNode>()
.FirstOrDefault(d => d.Name == funcCall.FuncCall.Name)
?.Parameters;
parameterDefinition ??= _definitions
.OfType<ExternFuncDefinitionNode>()
.FirstOrDefault(d => d.Name == funcCall.FuncCall.Name)
?.Parameters;
if (parameterDefinition == null)
{
throw new Exception($"Unknown function {funcCall.FuncCall}");
}
var results = new List<(string, NubType)>(); var results = new List<(string, NubType)>();
foreach (var parameter in funcCall.FuncCall.Parameters) foreach (var parameter in funcCall.FuncCall.Parameters)
{ {
results.Add((GenerateExpression(parameter), parameter.Type)); results.Add((GenerateExpression(parameter), parameter.Type));
} }
var parameters = results.Select(p => $"{QbeTypeName(p.Item2)} {p.Item1}"); var parameterStrings = new List<string>();
for (var i = 0; i < results.Count; i++)
{
if (parameterDefinition.Count > i && parameterDefinition[i].Variadic)
{
parameterStrings.Add("...");
}
_builder.AppendLine($" call ${funcCall.FuncCall.Name}({string.Join(", ", parameters)})"); parameterStrings.Add($"{QbeTypeName(results[i].Item2)} {results[i].Item1}");
}
_builder.AppendLine($" call ${funcCall.FuncCall.Name}({string.Join(", ", parameterStrings)})");
} }
private void GenerateIf(IfNode ifStatement) 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) private void GenerateWhile(WhileNode whileStatement)
{ {
var conditionLabel = GenName("condition"); var conditionLabel = GenName("condition");

View File

@@ -8,7 +8,6 @@ public class Lexer
["global"] = Symbol.Global, ["global"] = Symbol.Global,
["extern"] = Symbol.Extern, ["extern"] = Symbol.Extern,
["import"] = Symbol.Import, ["import"] = Symbol.Import,
["let"] = Symbol.Let,
["if"] = Symbol.If, ["if"] = Symbol.If,
["else"] = Symbol.Else, ["else"] = Symbol.Else,
["while"] = Symbol.While, ["while"] = Symbol.While,

View File

@@ -13,7 +13,6 @@ public enum Symbol
Global, Global,
Func, Func,
Return, Return,
Let,
If, If,
Else, Else,
While, While,

View File

@@ -68,7 +68,7 @@ public class Parser
var returnType = Optional<NubType>.Empty(); var returnType = Optional<NubType>.Empty();
if (TryExpectSymbol(Symbol.Colon)) if (TryExpectSymbol(Symbol.Colon))
{ {
returnType = ParseTypeInstance(); returnType = ParseType();
} }
var body = ParseBlock(); var body = ParseBlock();
@@ -94,7 +94,7 @@ public class Parser
var returnType = Optional<NubType>.Empty(); var returnType = Optional<NubType>.Empty();
if (TryExpectSymbol(Symbol.Colon)) if (TryExpectSymbol(Symbol.Colon))
{ {
returnType = ParseTypeInstance(); returnType = ParseType();
} }
var body = ParseBlock(); var body = ParseBlock();
@@ -120,7 +120,7 @@ public class Parser
var returnType = Optional<NubType>.Empty(); var returnType = Optional<NubType>.Empty();
if (TryExpectSymbol(Symbol.Colon)) if (TryExpectSymbol(Symbol.Colon))
{ {
returnType = ParseTypeInstance(); returnType = ParseType();
} }
ExpectSymbol(Symbol.Semicolon); ExpectSymbol(Symbol.Semicolon);
@@ -140,7 +140,7 @@ public class Parser
{ {
var variableName = ExpectIdentifier().Value; var variableName = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Colon); ExpectSymbol(Symbol.Colon);
var variableType = ParseTypeInstance(); var variableType = ParseType();
var variableValue = Optional<ExpressionNode>.Empty(); var variableValue = Optional<ExpressionNode>.Empty();
@@ -159,11 +159,19 @@ public class Parser
private FuncParameter ParseFuncParameter() private FuncParameter ParseFuncParameter()
{ {
var variadic = false;
if (TryExpectSymbol(Symbol.Period))
{
ExpectSymbol(Symbol.Period);
ExpectSymbol(Symbol.Period);
variadic = true;
}
var name = ExpectIdentifier(); var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon); 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() private StatementNode ParseStatement()
@@ -193,7 +201,7 @@ public class Parser
{ {
var value = ParseExpression(); var value = ParseExpression();
ExpectSymbol(Symbol.Semicolon); ExpectSymbol(Symbol.Semicolon);
return new VariableReassignmentNode(identifier.Value, value); return new VariableAssignmentNode(identifier.Value, value);
} }
default: default:
{ {
@@ -206,7 +214,6 @@ public class Parser
return symbol.Symbol switch return symbol.Symbol switch
{ {
Symbol.Return => ParseReturn(), Symbol.Return => ParseReturn(),
Symbol.Let => ParseVariableAssignment(),
Symbol.If => ParseIf(), Symbol.If => ParseIf(),
Symbol.While => ParseWhile(), Symbol.While => ParseWhile(),
Symbol.Break => ParseBreak(), Symbol.Break => ParseBreak(),
@@ -233,16 +240,6 @@ public class Parser
return new ReturnNode(value); 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() private IfNode ParseIf()
{ {
var condition = ParseExpression(); var condition = ParseExpression();
@@ -381,7 +378,7 @@ public class Parser
} }
case Symbol.New: case Symbol.New:
{ {
var type = ParseTypeInstance(); var type = ParseType();
Dictionary<string, ExpressionNode> initializers = []; Dictionary<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace); ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace)) while (!TryExpectSymbol(Symbol.CloseBrace))
@@ -466,22 +463,10 @@ public class Parser
return new BlockNode(statements); return new BlockNode(statements);
} }
private NubType ParseTypeInstance() private NubType ParseType()
{ {
var parameters = new List<NubType>();
var name = ExpectIdentifier().Value; var name = ExpectIdentifier().Value;
return new NubType(name);
if (TryExpectSymbol(Symbol.LessThan))
{
do
{
parameters.Add(ParseTypeInstance());
} while (TryExpectSymbol(Symbol.Comma));
ExpectSymbol(Symbol.GreaterThan);
}
return new NubType(name, parameters.ToArray());
} }
private Token ExpectToken() private Token ExpectToken()

View File

@@ -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;
}

View File

@@ -102,9 +102,6 @@ public class ExpressionTyper
case VariableAssignmentNode variableAssignment: case VariableAssignmentNode variableAssignment:
PopulateVariableAssignment(variableAssignment); PopulateVariableAssignment(variableAssignment);
break; break;
case VariableReassignmentNode variableReassignment:
PopulateVariableReassignment(variableReassignment);
break;
case WhileNode whileStatement: case WhileNode whileStatement:
PopulateWhileStatement(whileStatement); PopulateWhileStatement(whileStatement);
break; break;
@@ -149,9 +146,9 @@ public class ExpressionTyper
_variables.Push(new Variable(variableAssignment.Name, variableAssignment.Value.Type)); _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) private void PopulateWhileStatement(WhileNode whileStatement)
@@ -200,7 +197,7 @@ public class ExpressionTyper
case BinaryExpressionOperator.LessThan: case BinaryExpressionOperator.LessThan:
case BinaryExpressionOperator.LessThanOrEqual: case BinaryExpressionOperator.LessThanOrEqual:
{ {
binaryExpression.Type = new NubType("bool", []); binaryExpression.Type = new NubType("bool");
break; break;
} }
case BinaryExpressionOperator.Plus: case BinaryExpressionOperator.Plus:

View File

@@ -1,9 +1,10 @@
namespace Nub.Lang; 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 string Name { get; } = name;
public NubType Type { get; } = type; public NubType Type { get; } = type;
public bool Variadic { get; } = variadic;
public override string ToString() => $"{Name}: {Type}"; public override string ToString() => $"{Name}: {Type}";
} }

View File

@@ -2,37 +2,31 @@
public sealed class NubType public sealed class NubType
{ {
public NubType(string name, NubType[] generics) public NubType(string name)
{ {
Name = name; Name = name;
Generics = generics;
} }
public string Name { get; } public string Name { get; }
public NubType[] Generics { get; }
public static NubType Int64 => new("int64", []); public static NubType Int64 => new("i64");
public static NubType Int32 => new("int32", []); public static NubType Int32 => new("i32");
public static NubType Bool => new("bool", []); public static NubType Bool => new("bool");
public static NubType String => new("string", []); public static NubType String => new("string");
public static NubType Any => new("any");
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
if (obj is not NubType item) return obj is NubType item && Name.Equals(item.Name);
{
return false;
}
return Name.Equals(item.Name) && Generics.SequenceEqual(item.Generics);
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return HashCode.Combine(Name, Generics); return HashCode.Combine(Name);
} }
public override string ToString() public override string ToString()
{ {
return $"{Name}<{string.Join(", ", Generics.Select(x => x.ToString()))}>"; return $"{Name}";
} }
} }

View File

@@ -5,8 +5,8 @@ section .text
_start: _start:
call gc_init call gc_init
call main call main
mov rdi, rax
mov rax, 60 mov rax, 60
mov rdi, 0
syscall syscall
global nub_strcmp global nub_strcmp