More fixes for scope

This commit is contained in:
Deukhoofd 2018-11-19 12:49:48 +01:00
parent 1f57eed3e7
commit b3b26964cc
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
6 changed files with 59 additions and 43 deletions

View File

@ -8,31 +8,24 @@ namespace Upsilon.BaseTypes
{
internal class LuaTable : LuaType, IIndexable, IScopeOwner
{
private readonly Dictionary<string, VariableSymbol> _variableLookup;
public EvaluationScope EvaluationScope { get; }
public LuaTable(EvaluationScope scope)
{
EvaluationScope = scope;
_variableLookup = scope.Variables.ToDictionary(x => x.Key.Name, x => x.Key);
}
public override Type Type => Type.Table;
public override object ToCSharpObject()
{
return EvaluationScope.Variables.Where(x => !x.Key.Local)
.ToDictionary(x => x.Key.Name, x => x.Value.ToCSharpObject());
return EvaluationScope.Variables.ToDictionary(x => x.Key, x => x.Value.ToCSharpObject());
}
public LuaType Get(string s, EvaluationScope scope)
{
if (!_variableLookup.TryGetValue(s, out var variableSymbol))
return new LuaNull();
if (variableSymbol.Local && scope != EvaluationScope)
return new LuaNull();
if (EvaluationScope.TryGet(variableSymbol, out var o))
if (EvaluationScope.TryGet(s, out var o))
{
return o;
}

View File

@ -13,8 +13,8 @@ namespace Upsilon.Binder
private readonly Diagnostics _diagnostics;
public BoundScope Scope { get; private set; }
private Dictionary<FunctionVariableSymbol, UnboundFunctionExpression> _unboundFunctions =
new Dictionary<FunctionVariableSymbol, UnboundFunctionExpression>();
private Dictionary<string, UnboundFunctionExpression> _unboundFunctions =
new Dictionary<string, UnboundFunctionExpression>();
public Binder(Diagnostics diagnostics, Dictionary<string, VariableSymbol> variables)
{
@ -35,9 +35,8 @@ namespace Upsilon.Binder
unboundFunctionStatement.Value.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.Value.UnboundBlock);
Scope = Scope.ParentScope;
unboundFunctionStatement.Key.IsBound = true;
}
_unboundFunctions = new Dictionary<FunctionVariableSymbol, UnboundFunctionExpression>();
_unboundFunctions = new Dictionary<string, UnboundFunctionExpression>();
return new BoundScript((BoundBlockStatement) bound);
}
@ -185,12 +184,12 @@ namespace Upsilon.Binder
Scope.SetVariable(functionVariable);
}
var unboundFunctionStatement = _unboundFunctions[function];
var unboundFunctionStatement = _unboundFunctions[function.Name];
unboundFunctionStatement.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
Scope = Scope.ParentScope;
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 parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
@ -329,21 +328,27 @@ namespace Upsilon.Binder
else
{
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block);
_unboundFunctions.Add(
new FunctionVariableSymbol(Guid.NewGuid().ToString(), Type.Unknown, true, parameters.ToImmutable()),
unbound);
if (variableSymbol == null)
{
_unboundFunctions.Add( Guid.NewGuid().ToString(), unbound);
}
else
{
_unboundFunctions.Add(variableSymbol, unbound);
}
return unbound;
}
}
private BoundStatement BindFunctionAssignmentStatement(FunctionAssignmentStatementSyntax e)
{
var func = (BoundFunctionExpression)BindFunctionExpression(e.FunctionExpression);
var name = e.Identifier.Name;
var isLocal = e.LocalToken != null;
var innerScope = new BoundScope(Scope);
var func = (BoundFunctionExpression)BindFunctionExpression(e.FunctionExpression, name);
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
foreach (var identifierToken in func.Parameters)
{
var vari = new VariableSymbol(identifierToken.Name, Type.Unknown, true);
@ -351,9 +356,11 @@ namespace Upsilon.Binder
innerScope.SetVariable(vari);
}
if (!Scope.TryGetVariable(name, !isLocal, out var variable))
{
variable = new FunctionVariableSymbol(name, Type.Function, isLocal, parameters.ToImmutable());
((FunctionVariableSymbol) variable).IsBound = !(func is UnboundFunctionExpression);
if (isLocal)
Scope.SetVariable(variable);
else
@ -376,8 +383,6 @@ namespace Upsilon.Binder
}
}
((FunctionVariableSymbol) variable).IsBound = true;
return new BoundFunctionAssignmentStatement(variable, func);
}

View File

@ -9,35 +9,53 @@ namespace Upsilon.Evaluator
private readonly EvaluationScope _parentScope;
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)
{
_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;
LocalVariables = new Dictionary<string, LuaType>();
}
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;
}
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
{
LocalVariables.Add(symbol.Name, obj);
}
}
else
{
Variables.Add(symbol, obj);
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)
{
if (Variables.TryGetValue(symbol, out obj))
if (Variables.TryGetValue(symbol.Name, out obj))
return true;
if (LocalVariables.TryGetValue(symbol.Name, out obj))
return true;
if (_parentScope != null)
if (_parentScope.TryGet(symbol, out obj))
@ -66,18 +86,16 @@ namespace Upsilon.Evaluator
public bool TryGet(string variable, out LuaType obj)
{
foreach (var luaType in Variables)
{
if (luaType.Key.Name == variable)
{
obj = luaType.Value;
return true;
};
}
if (Variables.TryGetValue(variable, out obj))
return true;
if (LocalVariables.TryGetValue(variable, out obj))
return true;
if (_parentScope != null)
if (_parentScope.TryGet(variable, out obj))
return true;
obj = null;
if (_getOnlyParentScope != null)
if (_getOnlyParentScope.TryGet(variable, out obj))
return true;
return false;
}
}

View File

@ -17,7 +17,7 @@ namespace Upsilon.Evaluator
private bool HasReturned { get; set; }
public int Identifier { get; }
internal Evaluator(Diagnostics diagnostics, Dictionary<VariableSymbol, LuaType> variables)
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
{
_diagnostics = diagnostics;
Scope = new EvaluationScope(variables);

View File

@ -25,7 +25,7 @@ namespace Upsilon.Evaluator
Diagnostics = new Diagnostics(ScriptString);
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
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;
}

View File

@ -54,7 +54,7 @@ testFunc(100)
";
var script = new Script(input);
Assert.Empty(script.Diagnostics.Messages);
var val = script.Evaluate();
script.Evaluate();
Assert.Single(script.Diagnostics.Messages);
Assert.True(script.HasVariable("testFunc"));
}