From b3b26964cce2dee74ed6b264da1fa87d64ca02c2 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Mon, 19 Nov 2018 12:49:48 +0100 Subject: [PATCH] More fixes for scope --- Upsilon/BaseTypes/LuaTable.cs | 11 ++---- Upsilon/Binder/Binder.cs | 33 ++++++++++-------- Upsilon/Evaluator/EvaluationScope.cs | 52 +++++++++++++++++++--------- Upsilon/Evaluator/Evaluator.cs | 2 +- Upsilon/Evaluator/Script.cs | 2 +- UpsilonTests/FunctionTests.cs | 2 +- 6 files changed, 59 insertions(+), 43 deletions(-) diff --git a/Upsilon/BaseTypes/LuaTable.cs b/Upsilon/BaseTypes/LuaTable.cs index f78d078..a1fe201 100644 --- a/Upsilon/BaseTypes/LuaTable.cs +++ b/Upsilon/BaseTypes/LuaTable.cs @@ -8,31 +8,24 @@ namespace Upsilon.BaseTypes { internal class LuaTable : LuaType, IIndexable, IScopeOwner { - private readonly Dictionary _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; } diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index d7587ed..1053bde 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -13,8 +13,8 @@ namespace Upsilon.Binder private readonly Diagnostics _diagnostics; public BoundScope Scope { get; private set; } - private Dictionary _unboundFunctions = - new Dictionary(); + private Dictionary _unboundFunctions = + new Dictionary(); public Binder(Diagnostics diagnostics, Dictionary 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(); + _unboundFunctions = new Dictionary(); 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(); @@ -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(); + 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); } diff --git a/Upsilon/Evaluator/EvaluationScope.cs b/Upsilon/Evaluator/EvaluationScope.cs index fab9831..7cab80e 100644 --- a/Upsilon/Evaluator/EvaluationScope.cs +++ b/Upsilon/Evaluator/EvaluationScope.cs @@ -9,35 +9,53 @@ namespace Upsilon.Evaluator private readonly EvaluationScope _parentScope; private EvaluationScope _getOnlyParentScope; - internal readonly Dictionary Variables; + internal readonly Dictionary Variables; + internal readonly Dictionary LocalVariables; internal EvaluationScope(EvaluationScope parentScope) { _parentScope = parentScope; - Variables = new Dictionary(); + Variables = new Dictionary(); + LocalVariables = new Dictionary(); } - internal EvaluationScope(Dictionary vars) + internal EvaluationScope(Dictionary vars) { Variables = vars; + LocalVariables = new Dictionary(); } internal static EvaluationScope CreateWithGetOnlyParent(EvaluationScope parent) { - var scope = new EvaluationScope(new Dictionary()) {_getOnlyParentScope = parent}; + var scope = new EvaluationScope(new Dictionary()) {_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; } } diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 26d965c..efa7a22 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -17,7 +17,7 @@ namespace Upsilon.Evaluator private bool HasReturned { get; set; } public int Identifier { get; } - internal Evaluator(Diagnostics diagnostics, Dictionary variables) + internal Evaluator(Diagnostics diagnostics, Dictionary variables) { _diagnostics = diagnostics; Scope = new EvaluationScope(variables); diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index 0e8e502..cf0148c 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -25,7 +25,7 @@ namespace Upsilon.Evaluator Diagnostics = new Diagnostics(ScriptString); _parsed = Parser.Parser.Parse(scriptString, Diagnostics); Binder = new Binder.Binder(Diagnostics, new Dictionary()); - Evaluator = new Evaluator( Diagnostics, new Dictionary()); + Evaluator = new Evaluator( Diagnostics, new Dictionary()); Scope = Evaluator.Scope; } diff --git a/UpsilonTests/FunctionTests.cs b/UpsilonTests/FunctionTests.cs index 2479cbc..caf620b 100644 --- a/UpsilonTests/FunctionTests.cs +++ b/UpsilonTests/FunctionTests.cs @@ -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")); }