variadics
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
extern func puts(str: string);
|
extern func puts(str: string);
|
||||||
|
extern func printf(fmt: string, ...args: any);
|
||||||
@@ -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
1
run.sh
@@ -1,5 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
|
||||||
./clean.sh
|
./clean.sh
|
||||||
./build.sh
|
./build.sh
|
||||||
./out/program
|
./out/program
|
||||||
|
|||||||
@@ -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("...");
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
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");
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ public enum Symbol
|
|||||||
Global,
|
Global,
|
||||||
Func,
|
Func,
|
||||||
Return,
|
Return,
|
||||||
Let,
|
|
||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
While,
|
While,
|
||||||
|
|||||||
@@ -68,14 +68,14 @@ 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();
|
||||||
|
|
||||||
return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, false);
|
return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalFuncDefinitionNode ParseGlobalFuncDefinition()
|
private LocalFuncDefinitionNode ParseGlobalFuncDefinition()
|
||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.Func);
|
ExpectSymbol(Symbol.Func);
|
||||||
@@ -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))
|
||||||
@@ -424,11 +421,11 @@ public class Parser
|
|||||||
{
|
{
|
||||||
Next();
|
Next();
|
||||||
ExpressionNode result = new IdentifierNode(identifier.Value);
|
ExpressionNode result = new IdentifierNode(identifier.Value);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
var field = ExpectIdentifier();
|
var field = ExpectIdentifier();
|
||||||
result = new StructFieldAccessorNode(result, field.Value);
|
result = new StructFieldAccessorNode(result, field.Value);
|
||||||
} while (TryExpectSymbol(Symbol.Period));
|
} while (TryExpectSymbol(Symbol.Period));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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}";
|
||||||
}
|
}
|
||||||
@@ -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}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user