public override void RebuildScope(FunctionInfo functionInfo, Dictionary <string, VariableDescriptor> transferedVariables, int scopeBias) { ScopeBias = scopeBias; VariableDescriptor desc = null; if (transferedVariables != null && transferedVariables.TryGetValue(Name, out desc)) { _descriptor?.references.Remove(this); desc.references.Add(this); _descriptor = desc; } }
/// <summary> /// Evaluate script /// </summary> /// <param name="code">Code in JavaScript</param> /// <param name="suppressScopeCreation">If true, scope will not be created. All variables, which will be defined via let, const or class will not be destructed after evalution</param> /// <returns>Result of last evaluated operation</returns> public JSValue Eval(string code, JSValue thisBind, bool suppressScopeCreation = false) { if (_parent == null) { throw new InvalidOperationException("Cannot execute script in global context"); } if (string.IsNullOrEmpty(code)) { return(JSValue.undefined); } // чистить кэш тут не достаточно. // Мы не знаем, где объявлена одноимённая переменная // и в тех случаях, когда она пришла из функции выше // или даже глобального контекста, её кэш может быть // не сброшен вовремя и значение будет браться из контекста // eval'а, а не того контекста, в котором её позовут. /* * function a(){ * var c = 1; * function b(){ * eval("var c = 2"); * // переменная объявлена в контексте b, значит и значение должно быть из * // контекста b, но если по выходу из b кэш этой переменной сброшен не будет, * // то в a её значение будет 2 * } * } */ var mainFunctionContext = this; var stack = GetCurrectContextStack(); while (stack != null && stack.Count > 1 && stack[stack.Count - 2] == mainFunctionContext._parent && stack[stack.Count - 2]._owner == mainFunctionContext._owner) { mainFunctionContext = mainFunctionContext._parent; } int index = 0; string c = Parser.RemoveComments(code, 0); var ps = new ParseInfo(c, code, null) { strict = _strict, AllowDirectives = true, CodeContext = CodeContext.InEval }; var body = CodeBlock.Parse(ps, ref index) as CodeBlock; if (index < c.Length) { throw new ArgumentException("Invalid char"); } var variables = new Dictionary <string, VariableDescriptor>(); var stats = new FunctionInfo(); CodeNode cb = body; Parser.Build(ref cb, 0, variables, (_strict ? CodeContext.Strict : CodeContext.None) | CodeContext.InEval, null, stats, Options.None); var tv = stats.WithLexicalEnvironment ? null : new Dictionary <string, VariableDescriptor>(); body.RebuildScope(stats, tv, body._variables.Length == 0 || !stats.WithLexicalEnvironment ? 1 : 0); if (tv != null) { var newVarDescs = new VariableDescriptor[tv.Values.Count]; tv.Values.CopyTo(newVarDescs, 0); body._variables = newVarDescs; body._suppressScopeIsolation = SuppressScopeIsolationMode.DoNotSuppress; } body.Optimize(ref cb, null, null, Options.SuppressUselessExpressionsElimination | Options.SuppressConstantPropogation, stats); body = cb as CodeBlock ?? body; if (stats.NeedDecompose) { body.Decompose(ref cb); } body._suppressScopeIsolation = SuppressScopeIsolationMode.Suppress; var debugging = _debugging; _debugging = false; var runned = this.Activate(); try { var context = suppressScopeCreation || (!stats.WithLexicalEnvironment && !body._strict && !_strict) ? this : new Context(this, false, _owner) { _strict = _strict || body._strict }; if (suppressScopeCreation || (!_strict && !body._strict)) { for (var i = 0; i < body._variables.Length; i++) { if (!body._variables[i].lexicalScope) { JSValue variable; var cc = mainFunctionContext; while (cc._parent._parent != null && (cc._variables == null || !cc._variables.TryGetValue(body._variables[i].name, out variable))) { cc = cc._parent; } if (cc._definedVariables != null) { for (var j = 0; j < cc._definedVariables.Length; j++) { if (cc._definedVariables[j].name == body._variables[i].name) { cc._definedVariables[j].definitionScopeLevel = -1; } } } variable = mainFunctionContext.DefineVariable(body._variables[i].name, !suppressScopeCreation); if (body._variables[i].initializer != null) { variable.Assign(body._variables[i].initializer.Evaluate(context)); } // блокирует создание переменной в конктексте eval body._variables[i].lexicalScope = true; // блокирует кеширование body._variables[i].definitionScopeLevel = -1; } } } if (body._lines.Length == 0) { return(JSValue.undefined); } var oldThisBind = ThisBind; var runContextOfEval = context.Activate(); context._thisBind = thisBind; try { return(body.Evaluate(context) ?? context._lastResult ?? JSValue.notExists); } catch (JSException e) { if ((e.Code == null || e.CodeCoordinates == null) && e.ExceptionMaker != null) { e.Code = code; e.CodeCoordinates = CodeCoordinates.FromTextPosition(code, e.ExceptionMaker.Position, e.ExceptionMaker.Length); } throw; } finally { context._thisBind = oldThisBind; if (runContextOfEval) { context.Deactivate(); } } } finally { if (runned) { this.Deactivate(); } this._debugging = debugging; } }
public VariableDebuggerProxy(VariableDescriptor variableDescriptor) { _variable = variableDescriptor; }