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";
|
||||
|
||||
global func main() {
|
||||
if 3 / 3 == 1 {
|
||||
puts("uwu");
|
||||
}
|
||||
|
||||
while 1 == 1 {
|
||||
puts("test");
|
||||
break;
|
||||
}
|
||||
printf("something %s\n", "your mom");
|
||||
}
|
||||
@@ -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<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");
|
||||
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<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)>();
|
||||
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<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)
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -13,7 +13,6 @@ public enum Symbol
|
||||
Global,
|
||||
Func,
|
||||
Return,
|
||||
Let,
|
||||
If,
|
||||
Else,
|
||||
While,
|
||||
|
||||
@@ -68,14 +68,14 @@ public class Parser
|
||||
var returnType = Optional<NubType>.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<NubType>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Colon))
|
||||
{
|
||||
returnType = ParseTypeInstance();
|
||||
returnType = ParseType();
|
||||
}
|
||||
|
||||
var body = ParseBlock();
|
||||
@@ -120,7 +120,7 @@ public class Parser
|
||||
var returnType = Optional<NubType>.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<ExpressionNode>.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<string, ExpressionNode> 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<NubType>();
|
||||
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()
|
||||
|
||||
@@ -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:
|
||||
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:
|
||||
|
||||
@@ -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}";
|
||||
}
|
||||
@@ -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}";
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user