binder scopes
This commit is contained in:
@@ -34,8 +34,9 @@ func main(args: []cstring): i64
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// human.print()
|
// human.print()
|
||||||
|
let x = 23
|
||||||
|
|
||||||
print_result(12, func(num) { return num == 12 })
|
print_result(12, func(num) { return num == x })
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ public sealed class Binder
|
|||||||
private readonly SyntaxTree _syntaxTree;
|
private readonly SyntaxTree _syntaxTree;
|
||||||
private readonly DefinitionTable _definitionTable;
|
private readonly DefinitionTable _definitionTable;
|
||||||
|
|
||||||
private readonly Stack<Variable> _variables = [];
|
private readonly Stack<Scope> _scopes = [];
|
||||||
private readonly Stack<NubType> _funcReturnTypes = [];
|
private readonly Stack<NubType> _funcReturnTypes = [];
|
||||||
private readonly Stack<int> _variableScopes = [];
|
|
||||||
|
private Scope Scope => _scopes.Peek();
|
||||||
|
|
||||||
public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable)
|
public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable)
|
||||||
{
|
{
|
||||||
@@ -23,9 +24,8 @@ public sealed class Binder
|
|||||||
|
|
||||||
public BoundSyntaxTree Bind()
|
public BoundSyntaxTree Bind()
|
||||||
{
|
{
|
||||||
_variables.Clear();
|
|
||||||
_funcReturnTypes.Clear();
|
_funcReturnTypes.Clear();
|
||||||
_variableScopes.Clear();
|
_scopes.Clear();
|
||||||
|
|
||||||
var diagnostics = new List<Diagnostic>();
|
var diagnostics = new List<Diagnostic>();
|
||||||
var definitions = new List<BoundDefinition>();
|
var definitions = new List<BoundDefinition>();
|
||||||
@@ -60,7 +60,6 @@ public sealed class Binder
|
|||||||
|
|
||||||
private BoundTraitImpl BindTraitImplementation(TraitImplSyntax node)
|
private BoundTraitImpl BindTraitImplementation(TraitImplSyntax node)
|
||||||
{
|
{
|
||||||
_variables.Clear();
|
|
||||||
var functions = new List<BoundTraitFuncImpl>();
|
var functions = new List<BoundTraitFuncImpl>();
|
||||||
|
|
||||||
foreach (var func in node.Functions)
|
foreach (var func in node.Functions)
|
||||||
@@ -112,8 +111,6 @@ public sealed class Binder
|
|||||||
|
|
||||||
private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node)
|
private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node)
|
||||||
{
|
{
|
||||||
_variables.Clear();
|
|
||||||
|
|
||||||
var signature = BindFuncSignature(node.Signature);
|
var signature = BindFuncSignature(node.Signature);
|
||||||
var body = BindFuncBody(node.Body, signature.ReturnType, signature.Parameters);
|
var body = BindFuncBody(node.Body, signature.ReturnType, signature.Parameters);
|
||||||
|
|
||||||
@@ -208,7 +205,7 @@ public sealed class Binder
|
|||||||
throw new NotImplementedException("Diagnostics not implemented");
|
throw new NotImplementedException("Diagnostics not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
_variables.Push(new Variable(statement.Name, type));
|
Scope.Declare(new Variable(statement.Name, type));
|
||||||
|
|
||||||
return new BoundVariableDeclaration(statement.Tokens, statement.Name, assignment, type);
|
return new BoundVariableDeclaration(statement.Tokens, statement.Name, assignment, type);
|
||||||
}
|
}
|
||||||
@@ -357,14 +354,14 @@ public sealed class Binder
|
|||||||
|
|
||||||
if (!expression.Namespace.HasValue)
|
if (!expression.Namespace.HasValue)
|
||||||
{
|
{
|
||||||
var variable = _variables.FirstOrDefault(x => x.Name == expression.Name);
|
var variable = Scope.Lookup(expression.Name);
|
||||||
if (variable != null)
|
if (variable != null)
|
||||||
{
|
{
|
||||||
return new BoundVariableIdent(expression.Tokens, variable.Type, variable.Name);
|
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 the name {(expression.Namespace.HasValue ? $"{expression.Namespace.Value}::" : "")}{expression.Name} exists").Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundLiteral BindLiteral(LiteralSyntax expression, NubType? expectedType = null)
|
private BoundLiteral BindLiteral(LiteralSyntax expression, NubType? expectedType = null)
|
||||||
@@ -573,29 +570,18 @@ public sealed class Binder
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundBlock BindBlock(BlockSyntax node, IEnumerable<Variable>? variables = null)
|
private BoundBlock BindBlock(BlockSyntax node, Scope? scope = 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>();
|
||||||
|
|
||||||
|
_scopes.Push(scope ?? Scope.SubScope());
|
||||||
|
|
||||||
foreach (var statement in node.Statements)
|
foreach (var statement in node.Statements)
|
||||||
{
|
{
|
||||||
statements.Add(BindStatement(statement));
|
statements.Add(BindStatement(statement));
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = _variableScopes.Pop();
|
_scopes.Pop();
|
||||||
while (_variableScopes.Count > count)
|
|
||||||
{
|
|
||||||
_variableScopes.Pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BoundBlock(node.Tokens, statements);
|
return new BoundBlock(node.Tokens, statements);
|
||||||
}
|
}
|
||||||
@@ -603,7 +589,14 @@ public sealed class Binder
|
|||||||
private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType, IEnumerable<BoundFuncParameter> parameters)
|
private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType, IEnumerable<BoundFuncParameter> parameters)
|
||||||
{
|
{
|
||||||
_funcReturnTypes.Push(returnType);
|
_funcReturnTypes.Push(returnType);
|
||||||
var body = BindBlock(block, parameters.Select(x => new Variable(x.Name, x.Type)));
|
|
||||||
|
var scope = new Scope();
|
||||||
|
foreach (var parameter in parameters)
|
||||||
|
{
|
||||||
|
scope.Declare(new Variable(parameter.Name, parameter.Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
var body = BindBlock(block, scope);
|
||||||
_funcReturnTypes.Pop();
|
_funcReturnTypes.Pop();
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
@@ -611,22 +604,24 @@ public sealed class Binder
|
|||||||
|
|
||||||
public record Variable(string Name, NubType Type);
|
public record Variable(string Name, NubType Type);
|
||||||
|
|
||||||
public class Scope(Scope? parent)
|
public class Scope(Scope? parent = null)
|
||||||
{
|
{
|
||||||
private List<Variable> _variables = [];
|
private readonly List<Variable> _variables = [];
|
||||||
|
|
||||||
public Variable Lookup(string name)
|
public Variable? Lookup(string name)
|
||||||
{
|
{
|
||||||
var variable = _variables.FirstOrDefault(x => x.Name == name);
|
var variable = _variables.FirstOrDefault(x => x.Name == name);
|
||||||
if (variable == null)
|
if (variable != null)
|
||||||
{
|
{
|
||||||
if (parent != null)
|
return variable;
|
||||||
{
|
|
||||||
return parent.Lookup(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new BindException(Diagnostic.Error($"Variable {name} is not available in the current scope").Build());
|
return parent?.Lookup(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Declare(Variable variable)
|
||||||
|
{
|
||||||
|
_variables.Add(variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Scope SubScope()
|
public Scope SubScope()
|
||||||
|
|||||||
Reference in New Issue
Block a user