This commit is contained in:
nub31
2025-07-07 18:30:20 +02:00
parent 8d5b20f6e5
commit 777ce4bcfc

View File

@@ -6,15 +6,14 @@ using NubLang.Syntax.Tokenization;
namespace NubLang.Syntax.Binding; namespace NubLang.Syntax.Binding;
// TODO: Currently anonymous function does not get a new scope
public sealed class Binder public sealed class Binder
{ {
private readonly SyntaxTree _syntaxTree; private readonly SyntaxTree _syntaxTree;
private readonly DefinitionTable _definitionTable; private readonly DefinitionTable _definitionTable;
// TODO: Implement proper variable tracking and scoping private readonly Stack<Variable> _variables = [];
private readonly Dictionary<string, NubType> _variables = [];
private readonly Stack<NubType> _funcReturnTypes = []; private readonly Stack<NubType> _funcReturnTypes = [];
private readonly Stack<int> _variableScopes = [];
public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable) public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable)
{ {
@@ -26,6 +25,7 @@ public sealed class Binder
{ {
_variables.Clear(); _variables.Clear();
_funcReturnTypes.Clear(); _funcReturnTypes.Clear();
_variableScopes.Clear();
var diagnostics = new List<Diagnostic>(); var diagnostics = new List<Diagnostic>();
var definitions = new List<BoundDefinition>(); var definitions = new List<BoundDefinition>();
@@ -66,13 +66,7 @@ public sealed class Binder
foreach (var func in node.Functions) foreach (var func in node.Functions)
{ {
var signature = BindFuncSignature(func.Signature); var signature = BindFuncSignature(func.Signature);
var body = BindFuncBody(func.Body, signature.ReturnType, signature.Parameters);
foreach (var parameter in signature.Parameters)
{
_variables[parameter.Name] = parameter.Type;
}
var body = BindFuncBody(func.Body, signature.ReturnType);
functions.Add(new BoundTraitFuncImpl(func.Tokens, func.Name, signature, body)); functions.Add(new BoundTraitFuncImpl(func.Tokens, func.Name, signature, body));
} }
@@ -121,13 +115,7 @@ public sealed class Binder
_variables.Clear(); _variables.Clear();
var signature = BindFuncSignature(node.Signature); var signature = BindFuncSignature(node.Signature);
var body = BindFuncBody(node.Body, signature.ReturnType, signature.Parameters);
foreach (var parameter in signature.Parameters)
{
_variables[parameter.Name] = parameter.Type;
}
var body = BindFuncBody(node.Body, signature.ReturnType);
return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, signature, body); return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, signature, body);
} }
@@ -220,7 +208,7 @@ public sealed class Binder
throw new NotImplementedException("Diagnostics not implemented"); throw new NotImplementedException("Diagnostics not implemented");
} }
_variables[statement.Name] = type; _variables.Push(new Variable(statement.Name, type));
return new BoundVariableDeclaration(statement.Tokens, statement.Name, assignment, type); return new BoundVariableDeclaration(statement.Tokens, statement.Name, assignment, type);
} }
@@ -280,11 +268,9 @@ public sealed class Binder
var expectedParameterType = funcType.Parameters[i]; var expectedParameterType = funcType.Parameters[i];
var parameter = expression.Parameters[i]; var parameter = expression.Parameters[i];
parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, expectedParameterType)); parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, expectedParameterType));
_variables[parameter.Name] = expectedParameterType;
} }
var body = BindFuncBody(expression.Body, funcType.ReturnType); var body = BindFuncBody(expression.Body, funcType.ReturnType, parameters);
return new BoundAnonymousFunc(expression.Tokens, new NubFuncType(funcType.ReturnType, parameters.Select(x => x.Type).ToList()), parameters, funcType.ReturnType, body); return new BoundAnonymousFunc(expression.Tokens, new NubFuncType(funcType.ReturnType, parameters.Select(x => x.Type).ToList()), parameters, funcType.ReturnType, body);
} }
@@ -371,7 +357,11 @@ public sealed class Binder
if (!expression.Namespace.HasValue) if (!expression.Namespace.HasValue)
{ {
return new BoundVariableIdent(expression.Tokens, _variables[expression.Name], expression.Name); var variable = _variables.FirstOrDefault(x => x.Name == expression.Name);
if (variable != null)
{
return new BoundVariableIdent(expression.Tokens, variable.Type, variable.Name);
}
} }
throw new BindException(Diagnostic.Error($"No identifier with then name {(expression.Namespace.HasValue ? $"{expression.Namespace.Value}::" : "")}{expression.Name} exists").Build()); throw new BindException(Diagnostic.Error($"No identifier with then name {(expression.Namespace.HasValue ? $"{expression.Namespace.Value}::" : "")}{expression.Name} exists").Build());
@@ -583,8 +573,17 @@ public sealed class Binder
}; };
} }
private BoundBlock BindBlock(BlockSyntax node) private BoundBlock BindBlock(BlockSyntax node, IEnumerable<Variable>? variables = null)
{ {
_variableScopes.Push(_variables.Count);
if (variables != null)
{
foreach (var variable in variables)
{
_variables.Push(variable);
}
}
var statements = new List<BoundStatement>(); var statements = new List<BoundStatement>();
foreach (var statement in node.Statements) foreach (var statement in node.Statements)
@@ -592,18 +591,50 @@ public sealed class Binder
statements.Add(BindStatement(statement)); statements.Add(BindStatement(statement));
} }
var count = _variableScopes.Pop();
while (_variableScopes.Count > count)
{
_variableScopes.Pop();
}
return new BoundBlock(node.Tokens, statements); return new BoundBlock(node.Tokens, statements);
} }
private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType) private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType, IEnumerable<BoundFuncParameter> parameters)
{ {
_funcReturnTypes.Push(returnType); _funcReturnTypes.Push(returnType);
var body = BindBlock(block); var body = BindBlock(block, parameters.Select(x => new Variable(x.Name, x.Type)));
_funcReturnTypes.Pop(); _funcReturnTypes.Pop();
return body; return body;
} }
} }
public record Variable(string Name, NubType Type);
public class Scope(Scope? parent)
{
private List<Variable> _variables = [];
public Variable Lookup(string name)
{
var variable = _variables.FirstOrDefault(x => x.Name == name);
if (variable == null)
{
if (parent != null)
{
return parent.Lookup(name);
}
}
throw new BindException(Diagnostic.Error($"Variable {name} is not available in the current scope").Build());
}
public Scope SubScope()
{
return new Scope(this);
}
}
public class BindException : Exception public class BindException : Exception
{ {
public Diagnostic Diagnostic { get; } public Diagnostic Diagnostic { get; }