Anon funcs works

This commit is contained in:
nub31
2025-07-07 18:18:47 +02:00
parent 8751419169
commit 411c149de4
11 changed files with 212 additions and 219 deletions

View File

@@ -13,8 +13,8 @@ public sealed class Binder
private readonly DefinitionTable _definitionTable;
// TODO: Implement proper variable tracking and scoping
private Dictionary<string, NubType> _variables = new();
private NubType? _functionReturnType;
private readonly Dictionary<string, NubType> _variables = [];
private readonly Stack<NubType> _funcReturnTypes = [];
public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable)
{
@@ -24,8 +24,8 @@ public sealed class Binder
public BoundSyntaxTree Bind()
{
_variables = [];
_functionReturnType = null;
_variables.Clear();
_funcReturnTypes.Clear();
var diagnostics = new List<Diagnostic>();
var definitions = new List<BoundDefinition>();
@@ -63,17 +63,18 @@ public sealed class Binder
_variables.Clear();
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;
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);
@@ -85,14 +86,7 @@ public sealed class Binder
foreach (var function in node.Functions)
{
var parameters = new List<BoundFuncParameter>();
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));
functions.Add(new BoundTraitFunc(node.Tokens, function.Name, BindFuncSignature(function.Signature)));
}
return new BoundTrait(node.Tokens, node.Namespace, node.Name, functions);
@@ -119,44 +113,23 @@ public sealed class Binder
private BoundExternFunc BindExternFuncDefinition(ExternFuncSyntax node)
{
var parameters = new List<BoundFuncParameter>();
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);
return new BoundExternFunc(node.Tokens, node.Namespace, node.Name, node.CallName, BindFuncSignature(node.Signature));
}
private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node)
{
_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;
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);
}
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);
return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, signature, body);
}
private BoundStatement BindStatement(StatementSyntax node)
@@ -214,7 +187,7 @@ public sealed class Binder
if (statement.Value.HasValue)
{
value = BindExpression(statement.Value.Value, _functionReturnType);
value = BindExpression(statement.Value.Value, _funcReturnTypes.Peek());
}
return new BoundReturn(statement.Tokens, value);
@@ -262,7 +235,7 @@ public sealed class Binder
return node switch
{
AddressOfSyntax expression => BindAddressOf(expression),
AnonymousFuncSyntax expression => BindAnonymousFunc(expression),
AnonymousFuncSyntax expression => BindAnonymousFunc(expression, expectedType),
ArrayIndexAccessSyntax expression => BindArrayIndexAccess(expression),
ArrayInitializerSyntax expression => BindArrayInitializer(expression),
BinaryExpressionSyntax expression => BindBinaryExpression(expression),
@@ -283,18 +256,37 @@ public sealed class Binder
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>();
foreach (var parameter in expression.Parameters)
if (expectedType == null)
{
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)
@@ -359,7 +351,7 @@ public sealed class Binder
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);
}
@@ -373,7 +365,7 @@ public sealed class Binder
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);
}
@@ -413,7 +405,7 @@ public sealed class Binder
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);
}
@@ -439,7 +431,7 @@ public sealed class Binder
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);
}
}
@@ -551,6 +543,18 @@ public sealed class Binder
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)
{
return op switch
@@ -578,6 +582,26 @@ public sealed class Binder
_ => 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