More fixes for scope
This commit is contained in:
parent
1f57eed3e7
commit
b3b26964cc
|
@ -8,31 +8,24 @@ namespace Upsilon.BaseTypes
|
||||||
{
|
{
|
||||||
internal class LuaTable : LuaType, IIndexable, IScopeOwner
|
internal class LuaTable : LuaType, IIndexable, IScopeOwner
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, VariableSymbol> _variableLookup;
|
|
||||||
public EvaluationScope EvaluationScope { get; }
|
public EvaluationScope EvaluationScope { get; }
|
||||||
|
|
||||||
public LuaTable(EvaluationScope scope)
|
public LuaTable(EvaluationScope scope)
|
||||||
{
|
{
|
||||||
EvaluationScope = scope;
|
EvaluationScope = scope;
|
||||||
_variableLookup = scope.Variables.ToDictionary(x => x.Key.Name, x => x.Key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override Type Type => Type.Table;
|
public override Type Type => Type.Table;
|
||||||
public override object ToCSharpObject()
|
public override object ToCSharpObject()
|
||||||
{
|
{
|
||||||
return EvaluationScope.Variables.Where(x => !x.Key.Local)
|
return EvaluationScope.Variables.ToDictionary(x => x.Key, x => x.Value.ToCSharpObject());
|
||||||
.ToDictionary(x => x.Key.Name, x => x.Value.ToCSharpObject());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public LuaType Get(string s, EvaluationScope scope)
|
public LuaType Get(string s, EvaluationScope scope)
|
||||||
{
|
{
|
||||||
if (!_variableLookup.TryGetValue(s, out var variableSymbol))
|
if (EvaluationScope.TryGet(s, out var o))
|
||||||
return new LuaNull();
|
|
||||||
if (variableSymbol.Local && scope != EvaluationScope)
|
|
||||||
return new LuaNull();
|
|
||||||
if (EvaluationScope.TryGet(variableSymbol, out var o))
|
|
||||||
{
|
{
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ namespace Upsilon.Binder
|
||||||
private readonly Diagnostics _diagnostics;
|
private readonly Diagnostics _diagnostics;
|
||||||
public BoundScope Scope { get; private set; }
|
public BoundScope Scope { get; private set; }
|
||||||
|
|
||||||
private Dictionary<FunctionVariableSymbol, UnboundFunctionExpression> _unboundFunctions =
|
private Dictionary<string, UnboundFunctionExpression> _unboundFunctions =
|
||||||
new Dictionary<FunctionVariableSymbol, UnboundFunctionExpression>();
|
new Dictionary<string, UnboundFunctionExpression>();
|
||||||
|
|
||||||
public Binder(Diagnostics diagnostics, Dictionary<string, VariableSymbol> variables)
|
public Binder(Diagnostics diagnostics, Dictionary<string, VariableSymbol> variables)
|
||||||
{
|
{
|
||||||
|
@ -35,9 +35,8 @@ namespace Upsilon.Binder
|
||||||
unboundFunctionStatement.Value.Block =
|
unboundFunctionStatement.Value.Block =
|
||||||
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock);
|
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock);
|
||||||
Scope = Scope.ParentScope;
|
Scope = Scope.ParentScope;
|
||||||
unboundFunctionStatement.Key.IsBound = true;
|
|
||||||
}
|
}
|
||||||
_unboundFunctions = new Dictionary<FunctionVariableSymbol, UnboundFunctionExpression>();
|
_unboundFunctions = new Dictionary<string, UnboundFunctionExpression>();
|
||||||
return new BoundScript((BoundBlockStatement) bound);
|
return new BoundScript((BoundBlockStatement) bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,12 +184,12 @@ namespace Upsilon.Binder
|
||||||
Scope.SetVariable(functionVariable);
|
Scope.SetVariable(functionVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
var unboundFunctionStatement = _unboundFunctions[function];
|
var unboundFunctionStatement = _unboundFunctions[function.Name];
|
||||||
unboundFunctionStatement.Block =
|
unboundFunctionStatement.Block =
|
||||||
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
|
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
|
||||||
Scope = Scope.ParentScope;
|
Scope = Scope.ParentScope;
|
||||||
function.IsBound = true;
|
function.IsBound = true;
|
||||||
_unboundFunctions.Remove(function);
|
_unboundFunctions.Remove(function.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +306,7 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundExpression BindFunctionExpression(FunctionExpressionSyntax e)
|
private BoundExpression BindFunctionExpression(FunctionExpressionSyntax e, string variableSymbol = null)
|
||||||
{
|
{
|
||||||
var innerScope = new BoundScope(Scope);
|
var innerScope = new BoundScope(Scope);
|
||||||
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
|
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
|
||||||
|
@ -329,21 +328,27 @@ namespace Upsilon.Binder
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block);
|
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block);
|
||||||
_unboundFunctions.Add(
|
if (variableSymbol == null)
|
||||||
new FunctionVariableSymbol(Guid.NewGuid().ToString(), Type.Unknown, true, parameters.ToImmutable()),
|
{
|
||||||
unbound);
|
_unboundFunctions.Add( Guid.NewGuid().ToString(), unbound);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_unboundFunctions.Add(variableSymbol, unbound);
|
||||||
|
}
|
||||||
return unbound;
|
return unbound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundStatement BindFunctionAssignmentStatement(FunctionAssignmentStatementSyntax e)
|
private BoundStatement BindFunctionAssignmentStatement(FunctionAssignmentStatementSyntax e)
|
||||||
{
|
{
|
||||||
var func = (BoundFunctionExpression)BindFunctionExpression(e.FunctionExpression);
|
|
||||||
var name = e.Identifier.Name;
|
var name = e.Identifier.Name;
|
||||||
var isLocal = e.LocalToken != null;
|
var isLocal = e.LocalToken != null;
|
||||||
|
|
||||||
var innerScope = new BoundScope(Scope);
|
var innerScope = new BoundScope(Scope);
|
||||||
|
|
||||||
|
var func = (BoundFunctionExpression)BindFunctionExpression(e.FunctionExpression, name);
|
||||||
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
|
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
|
||||||
|
|
||||||
foreach (var identifierToken in func.Parameters)
|
foreach (var identifierToken in func.Parameters)
|
||||||
{
|
{
|
||||||
var vari = new VariableSymbol(identifierToken.Name, Type.Unknown, true);
|
var vari = new VariableSymbol(identifierToken.Name, Type.Unknown, true);
|
||||||
|
@ -351,9 +356,11 @@ namespace Upsilon.Binder
|
||||||
innerScope.SetVariable(vari);
|
innerScope.SetVariable(vari);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
|
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
|
||||||
{
|
{
|
||||||
variable = new FunctionVariableSymbol(name, Type.Function, isLocal, parameters.ToImmutable());
|
variable = new FunctionVariableSymbol(name, Type.Function, isLocal, parameters.ToImmutable());
|
||||||
|
((FunctionVariableSymbol) variable).IsBound = !(func is UnboundFunctionExpression);
|
||||||
if (isLocal)
|
if (isLocal)
|
||||||
Scope.SetVariable(variable);
|
Scope.SetVariable(variable);
|
||||||
else
|
else
|
||||||
|
@ -376,8 +383,6 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
((FunctionVariableSymbol) variable).IsBound = true;
|
|
||||||
|
|
||||||
return new BoundFunctionAssignmentStatement(variable, func);
|
return new BoundFunctionAssignmentStatement(variable, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,35 +9,53 @@ namespace Upsilon.Evaluator
|
||||||
private readonly EvaluationScope _parentScope;
|
private readonly EvaluationScope _parentScope;
|
||||||
private EvaluationScope _getOnlyParentScope;
|
private EvaluationScope _getOnlyParentScope;
|
||||||
|
|
||||||
internal readonly Dictionary<VariableSymbol, LuaType> Variables;
|
internal readonly Dictionary<string, LuaType> Variables;
|
||||||
|
internal readonly Dictionary<string, LuaType> LocalVariables;
|
||||||
|
|
||||||
|
|
||||||
internal EvaluationScope(EvaluationScope parentScope)
|
internal EvaluationScope(EvaluationScope parentScope)
|
||||||
{
|
{
|
||||||
_parentScope = parentScope;
|
_parentScope = parentScope;
|
||||||
Variables = new Dictionary<VariableSymbol, LuaType>();
|
Variables = new Dictionary<string, LuaType>();
|
||||||
|
LocalVariables = new Dictionary<string, LuaType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal EvaluationScope(Dictionary<VariableSymbol, LuaType> vars)
|
internal EvaluationScope(Dictionary<string, LuaType> vars)
|
||||||
{
|
{
|
||||||
Variables = vars;
|
Variables = vars;
|
||||||
|
LocalVariables = new Dictionary<string, LuaType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static EvaluationScope CreateWithGetOnlyParent(EvaluationScope parent)
|
internal static EvaluationScope CreateWithGetOnlyParent(EvaluationScope parent)
|
||||||
{
|
{
|
||||||
var scope = new EvaluationScope(new Dictionary<VariableSymbol, LuaType>()) {_getOnlyParentScope = parent};
|
var scope = new EvaluationScope(new Dictionary<string, LuaType>()) {_getOnlyParentScope = parent};
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(VariableSymbol symbol, LuaType obj)
|
public void Set(VariableSymbol symbol, LuaType obj)
|
||||||
{
|
{
|
||||||
if (Variables.ContainsKey(symbol))
|
if (symbol.Local)
|
||||||
{
|
{
|
||||||
Variables[symbol] = obj;
|
if (LocalVariables.ContainsKey(symbol.Name))
|
||||||
|
{
|
||||||
|
LocalVariables[symbol.Name] = obj;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Variables.Add(symbol, obj);
|
LocalVariables.Add(symbol.Name, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Variables.ContainsKey(symbol.Name))
|
||||||
|
{
|
||||||
|
Variables[symbol.Name] = obj;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Variables.Add(symbol.Name, obj);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +71,9 @@ namespace Upsilon.Evaluator
|
||||||
|
|
||||||
public bool TryGet(VariableSymbol symbol, out LuaType obj)
|
public bool TryGet(VariableSymbol symbol, out LuaType obj)
|
||||||
{
|
{
|
||||||
if (Variables.TryGetValue(symbol, out obj))
|
if (Variables.TryGetValue(symbol.Name, out obj))
|
||||||
|
return true;
|
||||||
|
if (LocalVariables.TryGetValue(symbol.Name, out obj))
|
||||||
return true;
|
return true;
|
||||||
if (_parentScope != null)
|
if (_parentScope != null)
|
||||||
if (_parentScope.TryGet(symbol, out obj))
|
if (_parentScope.TryGet(symbol, out obj))
|
||||||
|
@ -66,18 +86,16 @@ namespace Upsilon.Evaluator
|
||||||
|
|
||||||
public bool TryGet(string variable, out LuaType obj)
|
public bool TryGet(string variable, out LuaType obj)
|
||||||
{
|
{
|
||||||
foreach (var luaType in Variables)
|
if (Variables.TryGetValue(variable, out obj))
|
||||||
{
|
return true;
|
||||||
if (luaType.Key.Name == variable)
|
if (LocalVariables.TryGetValue(variable, out obj))
|
||||||
{
|
|
||||||
obj = luaType.Value;
|
|
||||||
return true;
|
return true;
|
||||||
};
|
|
||||||
}
|
|
||||||
if (_parentScope != null)
|
if (_parentScope != null)
|
||||||
if (_parentScope.TryGet(variable, out obj))
|
if (_parentScope.TryGet(variable, out obj))
|
||||||
return true;
|
return true;
|
||||||
obj = null;
|
if (_getOnlyParentScope != null)
|
||||||
|
if (_getOnlyParentScope.TryGet(variable, out obj))
|
||||||
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Upsilon.Evaluator
|
||||||
private bool HasReturned { get; set; }
|
private bool HasReturned { get; set; }
|
||||||
public int Identifier { get; }
|
public int Identifier { get; }
|
||||||
|
|
||||||
internal Evaluator(Diagnostics diagnostics, Dictionary<VariableSymbol, LuaType> variables)
|
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
|
||||||
{
|
{
|
||||||
_diagnostics = diagnostics;
|
_diagnostics = diagnostics;
|
||||||
Scope = new EvaluationScope(variables);
|
Scope = new EvaluationScope(variables);
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Upsilon.Evaluator
|
||||||
Diagnostics = new Diagnostics(ScriptString);
|
Diagnostics = new Diagnostics(ScriptString);
|
||||||
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
||||||
Binder = new Binder.Binder(Diagnostics, new Dictionary<string, VariableSymbol>());
|
Binder = new Binder.Binder(Diagnostics, new Dictionary<string, VariableSymbol>());
|
||||||
Evaluator = new Evaluator( Diagnostics, new Dictionary<VariableSymbol, LuaType>());
|
Evaluator = new Evaluator( Diagnostics, new Dictionary<string, LuaType>());
|
||||||
Scope = Evaluator.Scope;
|
Scope = Evaluator.Scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ testFunc(100)
|
||||||
";
|
";
|
||||||
var script = new Script(input);
|
var script = new Script(input);
|
||||||
Assert.Empty(script.Diagnostics.Messages);
|
Assert.Empty(script.Diagnostics.Messages);
|
||||||
var val = script.Evaluate();
|
script.Evaluate();
|
||||||
Assert.Single(script.Diagnostics.Messages);
|
Assert.Single(script.Diagnostics.Messages);
|
||||||
Assert.True(script.HasVariable("testFunc"));
|
Assert.True(script.HasVariable("testFunc"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue