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 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;
} }

View File

@ -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);
} }

View File

@ -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
{
LocalVariables.Add(symbol.Name, obj);
}
} }
else 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) 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))
{ return true;
obj = luaType.Value;
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;
} }
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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"));
} }