using Esprima; using Esprima.Ast; using Jint.Runtime; using Jint.Runtime.Descriptors; using Jint.Runtime.Environments; using Jint.Runtime.Interpreter.Statements; namespace Jint.Native.Function { public sealed class EvalFunctionInstance : FunctionInstance { private static readonly ParserOptions ParserOptions = new ParserOptions { AdaptRegexp = true, Tolerant = false }; private static readonly JsString _functionName = new JsString("eval"); public EvalFunctionInstance(Engine engine) : base(engine, _functionName, StrictModeScope.IsStrictModeCode ? FunctionThisMode.Strict : FunctionThisMode.Global) { _prototype = Engine.Function.PrototypeObject; _length = PropertyDescriptor.AllForbiddenDescriptor.NumberOne; } public override JsValue Call(JsValue thisObject, JsValue[] arguments) { return Call(thisObject, arguments, false); } /// /// https://tc39.es/ecma262/#sec-performeval /// public JsValue Call(JsValue thisObject, JsValue[] arguments, bool direct) { if (!(arguments.At(0) is JsString x)) { return arguments.At(0); } var parser = new JavaScriptParser(x.ToString(), ParserOptions); Script script; try { script = parser.ParseScript(StrictModeScope.IsStrictModeCode); } catch (ParserException e) { return e.Description == Messages.InvalidLHSInAssignment ? ExceptionHelper.ThrowReferenceError(_engine) : ExceptionHelper.ThrowSyntaxError(_engine); } var body = script.Body; if (body.Count == 0) { return Undefined; } var strictEval = script.Strict || _engine._isStrict; var ctx = _engine.ExecutionContext; using (new StrictModeScope(strictEval)) { LexicalEnvironment lexEnv; LexicalEnvironment varEnv; if (direct) { lexEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, ctx.LexicalEnvironment); varEnv = ctx.VariableEnvironment; } else { lexEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, Engine.GlobalEnvironment); varEnv = Engine.GlobalEnvironment; } if (strictEval) { varEnv = lexEnv; } // If ctx is not already suspended, suspend ctx. Engine.EnterExecutionContext(lexEnv, varEnv); try { Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, strictEval); var statement = JintStatement.Build(_engine, script); var result = statement.Execute(); var value = result.GetValueOrDefault(); if (result.Type == CompletionType.Throw) { var ex = new JavaScriptException(value).SetCallstack(_engine, result.Location); throw ex; } else { return value; } } finally { Engine.LeaveExecutionContext(); } } } } }