예제 #1
0
 public override void Optimize(ref CodeNode _this, Expressions.FunctionDefinition owner, InternalCompilerMessageCallback message, Options opts, FunctionInfo stats)
 {
     _original.Optimize(ref _this, owner, message, opts, stats);
 }
예제 #2
0
 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));
 }
예제 #3
0
        /// <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;
            }
        }
예제 #4
0
 public abstract void Decompose(ref CodeNode self);
예제 #5
0
 public virtual void Optimize(ref CodeNode _this, FunctionDefinition owner, CompilerMessageCallback message, Options opts, FunctionInfo stats)
 {
 }
예제 #6
0
 public virtual bool Build(ref CodeNode _this, int expressionDepth, Dictionary <string, VariableDescriptor> variables, CodeContext codeContext, CompilerMessageCallback message, FunctionInfo stats, Options opts)
 {
     return(false);
 }