public override void Optimize(ref CodeNode _this, Expressions.FunctionDefinition owner, InternalCompilerMessageCallback message, Options opts, FunctionInfo stats) { _original.Optimize(ref _this, owner, message, opts, stats); }
public override bool Build(ref CodeNode _this, int expressionDepth, Dictionary <string, VariableDescriptor> variables, CodeContext codeContext, InternalCompilerMessageCallback message, FunctionInfo stats, Options opts) { return(_original.Build(ref _this, expressionDepth, variables, codeContext, message, stats, opts)); }
/// <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) { 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 = Tools.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, null); 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 (!_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); } finally { context._thisBind = oldThisBind; if (runContextOfEval) { context.Deactivate(); } } } finally { if (runned) { this.Deactivate(); } this._debugging = debugging; } }
public abstract void Decompose(ref CodeNode self);
public virtual void Optimize(ref CodeNode _this, FunctionDefinition owner, CompilerMessageCallback message, Options opts, FunctionInfo stats) { }
public virtual bool Build(ref CodeNode _this, int expressionDepth, Dictionary <string, VariableDescriptor> variables, CodeContext codeContext, CompilerMessageCallback message, FunctionInfo stats, Options opts) { return(false); }