Anon funcs works

This commit is contained in:
nub31
2025-07-07 18:18:47 +02:00
parent 2a8578726d
commit 8d5b20f6e5
11 changed files with 212 additions and 219 deletions

View File

@@ -1,39 +1,52 @@
struct name // struct name
{ // {
first: cstring // first: cstring
last: cstring // last: cstring
} // }
struct human // struct human
{ // {
name: name // name: name
age: i64 // age: i64
} // }
trait printable // trait printable
{ // {
func print() // func print()
} // }
impl printable for human // impl printable for human
{ // {
func print() { // func print() {
c::puts(this.name.first) // c::puts(this.name.first)
} // }
} // }
func main(args: []cstring): i64 func main(args: []cstring): i64
{ {
let human = alloc human // let human = alloc human
{ // {
name = alloc name { // name = alloc name {
first = "john" // first = "john"
last = "doe" // last = "doe"
} // }
age = 23 // age = 23
} // }
human.print() // human.print()
print_result(12, func(num) { return num == 12 })
return 0 return 0
} }
func print_result(num: u64, delegate: func(u64): bool) {
if (delegate(num))
{
c::puts("true")
}
else
{
c::puts("false")
}
}

View File

@@ -232,8 +232,8 @@ public partial class QBEGenerator
private Val EmitLocalFuncIdent(BoundLocalFuncIdent localFuncIdent) private Val EmitLocalFuncIdent(BoundLocalFuncIdent localFuncIdent)
{ {
var func = _definitionTable.LookupExternFunc(localFuncIdent.Namespace, localFuncIdent.Name); var func = _definitionTable.LookupLocalFunc(localFuncIdent.Namespace, localFuncIdent.Name);
return new Val(ExternFuncName(func), localFuncIdent.Type, ValKind.Direct); return new Val(LocalFuncName(func), localFuncIdent.Type, ValKind.Direct);
} }
private Val EmitVariableIdent(BoundVariableIdent variableIdent) private Val EmitVariableIdent(BoundVariableIdent variableIdent)

View File

@@ -67,19 +67,19 @@ public partial class QBEGenerator
foreach (var funcDef in _syntaxTree.Definitions.OfType<BoundLocalFunc>()) foreach (var funcDef in _syntaxTree.Definitions.OfType<BoundLocalFunc>())
{ {
EmitFuncDefinition(funcDef, LocalFuncName(funcDef), funcDef.Parameters, funcDef.ReturnType, funcDef.Body); EmitFuncDefinition(LocalFuncName(funcDef), funcDef.Signature.Parameters, funcDef.Signature.ReturnType, funcDef.Body);
_writer.NewLine(); _writer.NewLine();
} }
while (_anonymousFunctions.TryDequeue(out var anon)) while (_anonymousFunctions.TryDequeue(out var anon))
{ {
EmitFuncDefinition(anon.Func, anon.Name, anon.Func.Parameters, anon.Func.ReturnType, anon.Func.Body); EmitFuncDefinition(anon.Name, anon.Func.Parameters, anon.Func.ReturnType, anon.Func.Body);
_writer.NewLine(); _writer.NewLine();
} }
foreach (var (impl, name) in _implFunctions) foreach (var (impl, name) in _implFunctions)
{ {
EmitFuncDefinition(impl, name, impl.Parameters, impl.ReturnType, impl.Body); EmitFuncDefinition(name, impl.Signature.Parameters, impl.Signature.ReturnType, impl.Body);
_writer.NewLine(); _writer.NewLine();
} }
@@ -347,8 +347,10 @@ public partial class QBEGenerator
return "l"; return "l";
} }
private void EmitFuncDefinition(BoundNode debugNode, string name, List<BoundFuncParameter> parameters, NubType returnType, BoundBlock body) private void EmitFuncDefinition(string name, IEnumerable<BoundFuncParameter> parameters, NubType returnType, BoundBlock body)
{ {
var parameterArray = parameters.ToArray();
_variables.Clear(); _variables.Clear();
_variableScopes.Clear(); _variableScopes.Clear();
_labelIndex = 0; _labelIndex = 0;
@@ -364,14 +366,13 @@ public partial class QBEGenerator
builder.Append(name); builder.Append(name);
var parameterStrings = parameters.Select(x => FuncQBETypeName(x.Type) + $" %{x.Name}"); var parameterStrings = parameterArray.Select(x => FuncQBETypeName(x.Type) + $" %{x.Name}");
builder.Append($"({string.Join(", ", parameterStrings)})"); builder.Append($"({string.Join(", ", parameterStrings)})");
_writer.StartFunction(builder.ToString()); _writer.StartFunction(builder.ToString());
_writer.WriteDebugLocation(debugNode);
var parameterVars = parameters.Select(parameter => new Variable(parameter.Name, new Val("%" + parameter.Name, parameter.Type, ValKind.Direct))).ToList(); var parameterVars = parameterArray.Select(parameter => new Variable(parameter.Name, new Val("%" + parameter.Name, parameter.Type, ValKind.Direct))).ToList();
EmitBlock(body, parameterVars); EmitBlock(body, parameterVars);
@@ -438,7 +439,7 @@ public partial class QBEGenerator
foreach (var func in traitDef.Functions) foreach (var func in traitDef.Functions)
{ {
_writer.Indented($"l, # func {func.Name}({string.Join(", ", func.Parameters.Select(x => $"{x.Name}: {x.Type}"))}): {func.ReturnType}"); _writer.Indented($"l, # func {func.Name}({string.Join(", ", func.Signature.Parameters.Select(x => $"{x.Name}: {x.Type}"))}): {func.Signature.ReturnType}");
} }
_writer.WriteLine("}"); _writer.WriteLine("}");

View File

@@ -13,8 +13,8 @@ public sealed class Binder
private readonly DefinitionTable _definitionTable; private readonly DefinitionTable _definitionTable;
// TODO: Implement proper variable tracking and scoping // TODO: Implement proper variable tracking and scoping
private Dictionary<string, NubType> _variables = new(); private readonly Dictionary<string, NubType> _variables = [];
private NubType? _functionReturnType; private readonly Stack<NubType> _funcReturnTypes = [];
public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable) public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable)
{ {
@@ -24,8 +24,8 @@ public sealed class Binder
public BoundSyntaxTree Bind() public BoundSyntaxTree Bind()
{ {
_variables = []; _variables.Clear();
_functionReturnType = null; _funcReturnTypes.Clear();
var diagnostics = new List<Diagnostic>(); var diagnostics = new List<Diagnostic>();
var definitions = new List<BoundDefinition>(); var definitions = new List<BoundDefinition>();
@@ -63,17 +63,18 @@ public sealed class Binder
_variables.Clear(); _variables.Clear();
var functions = new List<BoundTraitFuncImpl>(); var functions = new List<BoundTraitFuncImpl>();
foreach (var function in node.Functions) foreach (var func in node.Functions)
{ {
var parameters = new List<BoundFuncParameter>(); var signature = BindFuncSignature(func.Signature);
foreach (var parameter in function.Parameters) foreach (var parameter in signature.Parameters)
{ {
_variables[parameter.Name] = parameter.Type; _variables[parameter.Name] = parameter.Type;
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type));
} }
functions.Add(new BoundTraitFuncImpl(function.Tokens, function.Name, parameters, function.ReturnType, BindBlock(function.Body))); var body = BindFuncBody(func.Body, signature.ReturnType);
functions.Add(new BoundTraitFuncImpl(func.Tokens, func.Name, signature, body));
} }
return new BoundTraitImpl(node.Tokens, node.Namespace, node.TraitType, node.ForType, functions); return new BoundTraitImpl(node.Tokens, node.Namespace, node.TraitType, node.ForType, functions);
@@ -85,14 +86,7 @@ public sealed class Binder
foreach (var function in node.Functions) foreach (var function in node.Functions)
{ {
var parameters = new List<BoundFuncParameter>(); functions.Add(new BoundTraitFunc(node.Tokens, function.Name, BindFuncSignature(function.Signature)));
foreach (var parameter in function.Parameters)
{
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type));
}
functions.Add(new BoundTraitFunc(node.Tokens, function.Name, parameters, function.ReturnType));
} }
return new BoundTrait(node.Tokens, node.Namespace, node.Name, functions); return new BoundTrait(node.Tokens, node.Namespace, node.Name, functions);
@@ -119,44 +113,23 @@ public sealed class Binder
private BoundExternFunc BindExternFuncDefinition(ExternFuncSyntax node) private BoundExternFunc BindExternFuncDefinition(ExternFuncSyntax node)
{ {
var parameters = new List<BoundFuncParameter>(); return new BoundExternFunc(node.Tokens, node.Namespace, node.Name, node.CallName, BindFuncSignature(node.Signature));
foreach (var parameter in node.Parameters)
{
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type));
}
return new BoundExternFunc(node.Tokens, node.Namespace, node.Name, node.CallName, parameters, node.ReturnType);
} }
private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node) private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node)
{ {
_variables.Clear(); _variables.Clear();
_functionReturnType = node.ReturnType;
var parameters = new List<BoundFuncParameter>(); var signature = BindFuncSignature(node.Signature);
foreach (var parameter in node.Parameters) foreach (var parameter in signature.Parameters)
{ {
_variables[parameter.Name] = parameter.Type; _variables[parameter.Name] = parameter.Type;
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type));
} }
var body = BindBlock(node.Body); var body = BindFuncBody(node.Body, signature.ReturnType);
return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, parameters, body, node.ReturnType); return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, signature, body);
}
private BoundBlock BindBlock(BlockSyntax node)
{
var statements = new List<BoundStatement>();
foreach (var statement in node.Statements)
{
statements.Add(BindStatement(statement));
}
return new BoundBlock(node.Tokens, statements);
} }
private BoundStatement BindStatement(StatementSyntax node) private BoundStatement BindStatement(StatementSyntax node)
@@ -214,7 +187,7 @@ public sealed class Binder
if (statement.Value.HasValue) if (statement.Value.HasValue)
{ {
value = BindExpression(statement.Value.Value, _functionReturnType); value = BindExpression(statement.Value.Value, _funcReturnTypes.Peek());
} }
return new BoundReturn(statement.Tokens, value); return new BoundReturn(statement.Tokens, value);
@@ -262,7 +235,7 @@ public sealed class Binder
return node switch return node switch
{ {
AddressOfSyntax expression => BindAddressOf(expression), AddressOfSyntax expression => BindAddressOf(expression),
AnonymousFuncSyntax expression => BindAnonymousFunc(expression), AnonymousFuncSyntax expression => BindAnonymousFunc(expression, expectedType),
ArrayIndexAccessSyntax expression => BindArrayIndexAccess(expression), ArrayIndexAccessSyntax expression => BindArrayIndexAccess(expression),
ArrayInitializerSyntax expression => BindArrayInitializer(expression), ArrayInitializerSyntax expression => BindArrayInitializer(expression),
BinaryExpressionSyntax expression => BindBinaryExpression(expression), BinaryExpressionSyntax expression => BindBinaryExpression(expression),
@@ -283,18 +256,37 @@ public sealed class Binder
return new BoundAddressOf(expression.Tokens, new NubPointerType(inner.Type), inner); return new BoundAddressOf(expression.Tokens, new NubPointerType(inner.Type), inner);
} }
private BoundAnonymousFunc BindAnonymousFunc(AnonymousFuncSyntax expression) private BoundAnonymousFunc BindAnonymousFunc(AnonymousFuncSyntax expression, NubType? expectedType = null)
{ {
var parameters = new List<BoundFuncParameter>(); if (expectedType == null)
foreach (var parameter in expression.Parameters)
{ {
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type)); throw new BindException(Diagnostic.Error("Cannot infer argument types for anonymous function").At(expression).Build());
} }
var body = BindBlock(expression.Body); if (expectedType is not NubFuncType funcType)
{
throw new BindException(Diagnostic.Error($"Expected {expectedType}, but got anonymous function").At(expression).Build());
}
return new BoundAnonymousFunc(expression.Tokens, new NubFuncType(expression.ReturnType, parameters.Select(x => x.Type).ToList()), parameters, body, expression.ReturnType); var parameters = new List<BoundFuncParameter>();
for (var i = 0; i < expression.Parameters.Count; i++)
{
if (i >= funcType.Parameters.Count)
{
throw new BindException(Diagnostic.Error($"Anonymous function expected a maximum of {funcType.Parameters.Count} arguments").Build());
}
var expectedParameterType = funcType.Parameters[i];
var parameter = expression.Parameters[i];
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, expectedParameterType));
_variables[parameter.Name] = expectedParameterType;
}
var body = BindFuncBody(expression.Body, funcType.ReturnType);
return new BoundAnonymousFunc(expression.Tokens, new NubFuncType(funcType.ReturnType, parameters.Select(x => x.Type).ToList()), parameters, funcType.ReturnType, body);
} }
private BoundArrayIndexAccess BindArrayIndexAccess(ArrayIndexAccessSyntax expression) private BoundArrayIndexAccess BindArrayIndexAccess(ArrayIndexAccessSyntax expression)
@@ -359,7 +351,7 @@ public sealed class Binder
var localFunc = localFuncs[0]; var localFunc = localFuncs[0];
var type = new NubFuncType(localFunc.ReturnType, localFunc.Parameters.Select(p => p.Type).ToList()); var type = new NubFuncType(localFunc.Signature.ReturnType, localFunc.Signature.Parameters.Select(p => p.Type).ToList());
return new BoundLocalFuncIdent(expression.Tokens, type, @namespace, expression.Name); return new BoundLocalFuncIdent(expression.Tokens, type, @namespace, expression.Name);
} }
@@ -373,7 +365,7 @@ public sealed class Binder
var externFunc = externFuncs[0]; var externFunc = externFuncs[0];
var type = new NubFuncType(externFunc.ReturnType, externFunc.Parameters.Select(p => p.Type).ToList()); var type = new NubFuncType(externFunc.Signature.ReturnType, externFunc.Signature.Parameters.Select(p => p.Type).ToList());
return new BoundExternFuncIdent(expression.Tokens, type, @namespace, expression.Name); return new BoundExternFuncIdent(expression.Tokens, type, @namespace, expression.Name);
} }
@@ -413,7 +405,7 @@ public sealed class Binder
var impl = traitFuncImpls[0]; var impl = traitFuncImpls[0];
var type = new NubFuncType(impl.ReturnType, impl.Parameters.Select(p => p.Type).ToList()); var type = new NubFuncType(impl.Signature.ReturnType, impl.Signature.Parameters.Select(p => p.Type).ToList());
return new BoundTraitImplFuncAccess(expression.Tokens, type, boundExpression, expression.Member); return new BoundTraitImplFuncAccess(expression.Tokens, type, boundExpression, expression.Member);
} }
@@ -439,7 +431,7 @@ public sealed class Binder
var traitFunc = traitFuncs[0]; var traitFunc = traitFuncs[0];
var type = new NubFuncType(traitFunc.ReturnType, traitFunc.Parameters.Select(p => p.Type).ToList()); var type = new NubFuncType(traitFunc.Signature.ReturnType, traitFunc.Signature.Parameters.Select(p => p.Type).ToList());
return new BoundTraitFuncAccess(expression.Tokens, type, customType, boundExpression, expression.Member); return new BoundTraitFuncAccess(expression.Tokens, type, customType, boundExpression, expression.Member);
} }
} }
@@ -551,6 +543,18 @@ public sealed class Binder
return new BoundUnaryExpression(expression.Tokens, type, BindBinaryOperator(expression.Operator), boundOperand); return new BoundUnaryExpression(expression.Tokens, type, BindBinaryOperator(expression.Operator), boundOperand);
} }
private BoundFuncSignature BindFuncSignature(FuncSignatureSyntax node)
{
var parameters = new List<BoundFuncParameter>();
foreach (var parameter in node.Parameters)
{
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type));
}
return new BoundFuncSignature(node.Tokens, parameters, node.ReturnType);
}
private BoundBinaryOperator BindBinaryOperator(BinaryOperator op) private BoundBinaryOperator BindBinaryOperator(BinaryOperator op)
{ {
return op switch return op switch
@@ -578,6 +582,26 @@ public sealed class Binder
_ => throw new ArgumentOutOfRangeException(nameof(op), op, null) _ => throw new ArgumentOutOfRangeException(nameof(op), op, null)
}; };
} }
private BoundBlock BindBlock(BlockSyntax node)
{
var statements = new List<BoundStatement>();
foreach (var statement in node.Statements)
{
statements.Add(BindStatement(statement));
}
return new BoundBlock(node.Tokens, statements);
}
private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType)
{
_funcReturnTypes.Push(returnType);
var body = BindBlock(block);
_funcReturnTypes.Pop();
return body;
}
} }
public class BindException : Exception public class BindException : Exception

View File

@@ -9,18 +9,20 @@ public abstract record BoundDefinitionMember(IEnumerable<Token> Tokens) : BoundN
public record BoundFuncParameter(IEnumerable<Token> Tokens, string Name, NubType Type) : BoundDefinitionMember(Tokens); public record BoundFuncParameter(IEnumerable<Token> Tokens, string Name, NubType Type) : BoundDefinitionMember(Tokens);
public record BoundLocalFunc(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundFuncParameter> Parameters, BoundBlock Body, NubType ReturnType) : BoundDefinition(Tokens, Namespace); public record BoundFuncSignature(IEnumerable<Token> Tokens, IEnumerable<BoundFuncParameter> Parameters, NubType ReturnType) : BoundDefinitionMember(Tokens);
public record BoundExternFunc(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<BoundFuncParameter> Parameters, NubType ReturnType) : BoundDefinition(Tokens, Namespace); public record BoundLocalFunc(IEnumerable<Token> Tokens, string Namespace, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinition(Tokens, Namespace);
public record BoundExternFunc(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, BoundFuncSignature Signature) : BoundDefinition(Tokens, Namespace);
public record BoundStructField(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<BoundExpression> Value) : BoundDefinitionMember(Tokens); public record BoundStructField(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<BoundExpression> Value) : BoundDefinitionMember(Tokens);
public record BoundStruct(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundStructField> Fields) : BoundDefinition(Tokens, Namespace); public record BoundStruct(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundStructField> Fields) : BoundDefinition(Tokens, Namespace);
public record BoundTraitFunc(IEnumerable<Token> Tokens, string Name, List<BoundFuncParameter> Parameters, NubType ReturnType) : BoundDefinitionMember(Tokens); public record BoundTraitFunc(IEnumerable<Token> Tokens, string Name, BoundFuncSignature Signature) : BoundDefinitionMember(Tokens);
public record BoundTrait(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundTraitFunc> Functions) : BoundDefinition(Tokens, Namespace); public record BoundTrait(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundTraitFunc> Functions) : BoundDefinition(Tokens, Namespace);
public record BoundTraitFuncImpl(IEnumerable<Token> Tokens, string Name, List<BoundFuncParameter> Parameters, NubType ReturnType, BoundBlock Body) : BoundDefinitionMember(Tokens); public record BoundTraitFuncImpl(IEnumerable<Token> Tokens, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinitionMember(Tokens);
public record BoundTraitImpl(IEnumerable<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, List<BoundTraitFuncImpl> Functions) : BoundDefinition(Tokens, Namespace); public record BoundTraitImpl(IEnumerable<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, List<BoundTraitFuncImpl> Functions) : BoundDefinition(Tokens, Namespace);

View File

@@ -40,7 +40,7 @@ public record BoundArrayInitializer(IEnumerable<Token> Tokens, NubType Type, Bou
public record BoundArrayIndexAccess(IEnumerable<Token> Tokens, NubType Type, BoundExpression Target, BoundExpression Index) : BoundExpression(Tokens, Type); public record BoundArrayIndexAccess(IEnumerable<Token> Tokens, NubType Type, BoundExpression Target, BoundExpression Index) : BoundExpression(Tokens, Type);
public record BoundAnonymousFunc(IEnumerable<Token> Tokens, NubType Type, List<BoundFuncParameter> Parameters, BoundBlock Body, NubType ReturnType) : BoundExpression(Tokens, Type); public record BoundAnonymousFunc(IEnumerable<Token> Tokens, NubType Type, IEnumerable<BoundFuncParameter> Parameters, NubType ReturnType, BoundBlock Body) : BoundExpression(Tokens, Type);
public record BoundAddressOf(IEnumerable<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type); public record BoundAddressOf(IEnumerable<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type);

View File

@@ -9,18 +9,20 @@ public abstract record DefinitionMemberSyntax(IEnumerable<Token> Tokens) : Synta
public record FuncParameterSyntax(IEnumerable<Token> Tokens, string Name, NubType Type) : DefinitionMemberSyntax(Tokens); public record FuncParameterSyntax(IEnumerable<Token> Tokens, string Name, NubType Type) : DefinitionMemberSyntax(Tokens);
public record LocalFuncSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, List<FuncParameterSyntax> Parameters, BlockSyntax Body, NubType ReturnType) : DefinitionSyntax(Tokens, Namespace); public record FuncSignatureSyntax(IEnumerable<Token> Tokens, IEnumerable<FuncParameterSyntax> Parameters, NubType ReturnType) : DefinitionMemberSyntax(Tokens);
public record ExternFuncSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<FuncParameterSyntax> Parameters, NubType ReturnType) : DefinitionSyntax(Tokens, Namespace); public record LocalFuncSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Tokens, Namespace);
public record ExternFuncSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Tokens, Namespace);
public record StructFieldSyntax(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<ExpressionSyntax> Value) : DefinitionMemberSyntax(Tokens); public record StructFieldSyntax(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<ExpressionSyntax> Value) : DefinitionMemberSyntax(Tokens);
public record StructSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, List<StructFieldSyntax> Fields) : DefinitionSyntax(Tokens, Namespace); public record StructSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, List<StructFieldSyntax> Fields) : DefinitionSyntax(Tokens, Namespace);
public record TraitFuncSyntax(IEnumerable<Token> Tokens, string Name, List<FuncParameterSyntax> Parameters, NubType ReturnType) : DefinitionMemberSyntax(Tokens); public record TraitFuncSyntax(IEnumerable<Token> Tokens, string Name, FuncSignatureSyntax Signature) : DefinitionMemberSyntax(Tokens);
public record TraitSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, List<TraitFuncSyntax> Functions) : DefinitionSyntax(Tokens, Namespace); public record TraitSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, List<TraitFuncSyntax> Functions) : DefinitionSyntax(Tokens, Namespace);
public record TraitFuncImplSyntax(IEnumerable<Token> Tokens, string Name, List<FuncParameterSyntax> Parameters, NubType ReturnType, BlockSyntax Body) : DefinitionMemberSyntax(Tokens); public record TraitFuncImplSyntax(IEnumerable<Token> Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionMemberSyntax(Tokens);
public record TraitImplSyntax(IEnumerable<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, List<TraitFuncImplSyntax> Functions) : DefinitionSyntax(Tokens, Namespace); public record TraitImplSyntax(IEnumerable<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, List<TraitFuncImplSyntax> Functions) : DefinitionSyntax(Tokens, Namespace);

View File

@@ -37,7 +37,9 @@ public record ArrayInitializerSyntax(IEnumerable<Token> Tokens, ExpressionSyntax
public record ArrayIndexAccessSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens); public record ArrayIndexAccessSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens);
public record AnonymousFuncSyntax(IEnumerable<Token> Tokens, List<FuncParameterSyntax> Parameters, BlockSyntax Body, NubType ReturnType) : ExpressionSyntax(Tokens); public record AnonymousFuncParameterSyntax(IEnumerable<Token> Tokens, string Name) : ExpressionSyntax(Tokens);
public record AnonymousFuncSyntax(IEnumerable<Token> Tokens, List<AnonymousFuncParameterSyntax> Parameters, BlockSyntax Body) : ExpressionSyntax(Tokens);
public record AddressOfSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens); public record AddressOfSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens);

View File

@@ -12,7 +12,6 @@ public sealed class Parser
private readonly IEnumerable<Token> _tokens; private readonly IEnumerable<Token> _tokens;
private readonly List<Diagnostic> _diagnostics = []; private readonly List<Diagnostic> _diagnostics = [];
private NubType? _functionReturnType;
private int _tokenIndex; private int _tokenIndex;
public Parser(IEnumerable<Token> tokens) public Parser(IEnumerable<Token> tokens)
@@ -24,7 +23,6 @@ public sealed class Parser
public SyntaxTree Parse() public SyntaxTree Parse()
{ {
_diagnostics.Clear(); _diagnostics.Clear();
_functionReturnType = null;
_tokenIndex = 0; _tokenIndex = 0;
if (TryExpectSymbol(Symbol.Namespace)) if (TryExpectSymbol(Symbol.Namespace))
@@ -61,7 +59,7 @@ public sealed class Parser
Symbol.Func => ParseFunc(startIndex), Symbol.Func => ParseFunc(startIndex),
Symbol.Struct => ParseStruct(startIndex), Symbol.Struct => ParseStruct(startIndex),
Symbol.Trait => ParseTrait(startIndex), Symbol.Trait => ParseTrait(startIndex),
Symbol.Impl => ParseImplementation(startIndex), Symbol.Impl => ParseImpl(startIndex),
_ => throw new ParseException(Diagnostic _ => throw new ParseException(Diagnostic
.Error($"Expected 'func' or 'struct', but found '{keyword.Symbol}'") .Error($"Expected 'func' or 'struct', but found '{keyword.Symbol}'")
.WithHelp("Valid definition keywords are 'func' and 'struct'") .WithHelp("Valid definition keywords are 'func' and 'struct'")
@@ -72,6 +70,48 @@ public sealed class Parser
return node; return node;
} }
private FuncSignatureSyntax ParseFuncSignature(FuncParameterSyntax? thisArg = null)
{
var startIndex = _tokenIndex;
List<FuncParameterSyntax> parameters = [];
if (thisArg != null)
{
parameters.Add(thisArg);
}
ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseFuncParameter());
if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen })
{
_diagnostics.Add(Diagnostic
.Warning("Missing comma between function parameters")
.WithHelp("Add a ',' to separate parameters")
.At(token)
.Build());
}
}
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
return new FuncSignatureSyntax(GetTokens(startIndex), parameters, returnType);
}
private FuncParameterSyntax ParseFuncParameter()
{
var startIndex = _tokenIndex;
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon);
var type = ParseType();
return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
}
private DefinitionSyntax ParseExtern(int startIndex) private DefinitionSyntax ParseExtern(int startIndex)
{ {
var keyword = ExpectSymbol(); var keyword = ExpectSymbol();
@@ -85,25 +125,6 @@ public sealed class Parser
private ExternFuncSyntax ParseExternFunc(int startIndex) private ExternFuncSyntax ParseExternFunc(int startIndex)
{ {
var name = ExpectIdentifier(); var name = ExpectIdentifier();
List<FuncParameterSyntax> parameters = [];
ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseFuncParameter());
if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen })
{
_diagnostics.Add(Diagnostic
.Warning("Missing comma between function parameters")
.WithHelp("Add a ',' to separate parameters")
.At(token)
.Build());
}
}
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
var callName = name.Value; var callName = name.Value;
if (TryExpectSymbol(Symbol.Calls)) if (TryExpectSymbol(Symbol.Calls))
@@ -111,36 +132,18 @@ public sealed class Parser
callName = ExpectIdentifier().Value; callName = ExpectIdentifier().Value;
} }
return new ExternFuncSyntax(GetTokens(startIndex), _namespace, name.Value, callName, parameters, returnType); var signature = ParseFuncSignature();
return new ExternFuncSyntax(GetTokens(startIndex), _namespace, name.Value, callName, signature);
} }
private LocalFuncSyntax ParseFunc(int startIndex) private LocalFuncSyntax ParseFunc(int startIndex)
{ {
var name = ExpectIdentifier(); var name = ExpectIdentifier();
List<FuncParameterSyntax> parameters = []; var signature = ParseFuncSignature();
ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseFuncParameter());
if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen })
{
_diagnostics.Add(Diagnostic
.Warning("Missing comma between function parameters")
.WithHelp("Add a ',' to separate parameters")
.At(token)
.Build());
}
}
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
_functionReturnType = returnType;
var body = ParseBlock(); var body = ParseBlock();
return new LocalFuncSyntax(GetTokens(startIndex), _namespace, name.Value, parameters, body, returnType); return new LocalFuncSyntax(GetTokens(startIndex), _namespace, name.Value, signature, body);
} }
private StructSyntax ParseStruct(int startIndex) private StructSyntax ParseStruct(int startIndex)
@@ -189,32 +192,15 @@ public sealed class Parser
ExpectSymbol(Symbol.Func); ExpectSymbol(Symbol.Func);
var funcName = ExpectIdentifier().Value; var funcName = ExpectIdentifier().Value;
var parameters = new List<FuncParameterSyntax>(); var signature = ParseFuncSignature();
ExpectSymbol(Symbol.OpenParen); functions.Add(new TraitFuncSyntax(GetTokens(funcStartIndex), funcName, signature));
while (!TryExpectSymbol(Symbol.CloseParen))
{
var parameter = ParseFuncParameter();
parameters.Add(parameter);
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());
}
}
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
functions.Add(new TraitFuncSyntax(GetTokens(funcStartIndex), funcName, parameters, returnType));
} }
return new TraitSyntax(GetTokens(startIndex), _namespace, name, functions); return new TraitSyntax(GetTokens(startIndex), _namespace, name, functions);
} }
private TraitImplSyntax ParseImplementation(int startIndex) private TraitImplSyntax ParseImpl(int startIndex)
{ {
var traitType = ParseType(); var traitType = ParseType();
ExpectSymbol(Symbol.For); ExpectSymbol(Symbol.For);
@@ -228,47 +214,16 @@ public sealed class Parser
var funcStartIndex = _tokenIndex; var funcStartIndex = _tokenIndex;
ExpectSymbol(Symbol.Func); ExpectSymbol(Symbol.Func);
var functionName = ExpectIdentifier().Value; var functionName = ExpectIdentifier().Value;
var parameters = new List<FuncParameterSyntax>
{
new([], "this", forType)
};
ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseFuncParameter());
if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen })
{
_diagnostics.Add(Diagnostic
.Warning("Missing comma between function parameters")
.WithHelp("Add a ',' to separate parameters")
.At(token)
.Build());
}
}
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
var signature = ParseFuncSignature(new FuncParameterSyntax([], "this", forType));
var body = ParseBlock(); var body = ParseBlock();
functions.AddRange(new TraitFuncImplSyntax(GetTokens(funcStartIndex), functionName, parameters, returnType, body)); functions.AddRange(new TraitFuncImplSyntax(GetTokens(funcStartIndex), functionName, signature, body));
} }
return new TraitImplSyntax(GetTokens(startIndex), _namespace, traitType, forType, functions); return new TraitImplSyntax(GetTokens(startIndex), _namespace, traitType, forType, functions);
} }
private FuncParameterSyntax ParseFuncParameter()
{
var startIndex = _tokenIndex;
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon);
var type = ParseType();
return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
}
private StatementSyntax ParseStatement() private StatementSyntax ParseStatement()
{ {
var startIndex = _tokenIndex; var startIndex = _tokenIndex;
@@ -353,7 +308,8 @@ public sealed class Parser
ExpectSymbol(Symbol.Return); ExpectSymbol(Symbol.Return);
var value = Optional<ExpressionSyntax>.Empty(); var value = Optional<ExpressionSyntax>.Empty();
if (_functionReturnType is not NubVoidType)
if (!TryExpectSymbol(Symbol.Semi))
{ {
value = ParseExpression(); value = ParseExpression();
} }
@@ -500,27 +456,18 @@ public sealed class Parser
{ {
case Symbol.Func: case Symbol.Func:
{ {
List<FuncParameterSyntax> parameters = []; List<AnonymousFuncParameterSyntax> parameters = [];
ExpectSymbol(Symbol.OpenParen); ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen)) while (!TryExpectSymbol(Symbol.CloseParen))
{ {
var parameter = ParseFuncParameter(); var parameterStartIndex = _tokenIndex;
parameters.Add(parameter); var name = ExpectIdentifier();
if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) parameters.Add(new AnonymousFuncParameterSyntax(GetTokens(parameterStartIndex), name.Value));
{
_diagnostics.Add(Diagnostic
.Warning("Missing comma between function arguments")
.WithHelp("Add a ',' to separate arguments")
.At(nextToken)
.Build());
}
} }
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
var body = ParseBlock(); var body = ParseBlock();
expr = new AnonymousFuncSyntax(GetTokens(startIndex), parameters, body, returnType); expr = new AnonymousFuncSyntax(GetTokens(startIndex), parameters, body);
break; break;
} }
case Symbol.OpenParen: case Symbol.OpenParen:

View File

@@ -70,5 +70,6 @@ public enum Symbol
Trait, Trait,
Impl, Impl,
For, For,
Extern Extern,
Semi
} }

View File

@@ -55,6 +55,7 @@ public sealed class Tokenizer
['!'] = Symbol.Bang, ['!'] = Symbol.Bang,
['^'] = Symbol.Caret, ['^'] = Symbol.Caret,
['&'] = Symbol.Ampersand, ['&'] = Symbol.Ampersand,
[';'] = Symbol.Semi,
}; };
private readonly SourceText _sourceText; private readonly SourceText _sourceText;