123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- using Jint.Runtime;
- using Jint.Runtime.Descriptors;
- using Jint.Runtime.Environments;
- using Jint.Runtime.Interpreter;
- using Jint.Runtime.Interpreter.Statements;
- using Environment = Jint.Runtime.Environments.Environment;
- namespace Jint.Native.Function;
- public sealed class EvalFunction : Function
- {
- private static readonly JsString _functionName = new("eval");
- internal EvalFunction(
- Engine engine,
- Realm realm,
- FunctionPrototype functionPrototype)
- : base(
- engine,
- realm,
- _functionName,
- StrictModeScope.IsStrictModeCode ? FunctionThisMode.Strict : FunctionThisMode.Global)
- {
- _prototype = functionPrototype;
- _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
- }
- protected internal override JsValue Call(JsValue thisObject, JsCallArguments arguments)
- {
- var callerRealm = _engine.ExecutionContext.Realm;
- var x = arguments.At(0);
- return PerformEval(x, callerRealm, false, false);
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-performeval
- /// </summary>
- internal JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool direct)
- {
- if (!x.IsString())
- {
- return x;
- }
- var evalRealm = _realm;
- _engine._host.EnsureCanCompileStrings(callerRealm, evalRealm);
- var inFunction = false;
- var inMethod = false;
- var inDerivedConstructor = false;
- var inClassFieldInitializer = false;
- if (direct)
- {
- var thisEnvRec = _engine.ExecutionContext.GetThisEnvironment();
- if (thisEnvRec is FunctionEnvironment functionEnvironmentRecord)
- {
- var F = functionEnvironmentRecord._functionObject;
- inFunction = true;
- inMethod = thisEnvRec.HasSuperBinding();
- if (F._constructorKind == ConstructorKind.Derived)
- {
- inDerivedConstructor = true;
- }
- var classFieldInitializerName = (F as ScriptFunction)?._classFieldInitializerName;
- if (!string.IsNullOrEmpty(classFieldInitializerName?.ToString()))
- {
- inClassFieldInitializer = true;
- }
- }
- }
- Script? script = null;
- var parserOptions = _engine.GetActiveParserOptions();
- var adjustedParserOptions = parserOptions with
- {
- AllowReturnOutsideFunction = false,
- AllowNewTargetOutsideFunction = true,
- AllowSuperOutsideMethod = true,
- // This is a workaround, just makes some tests pass. Actually, we need these checks (done either by the parser or by the runtime).
- // TODO: implement a correct solution
- CheckPrivateFields = false
- };
- var parser = _engine.GetParserFor(adjustedParserOptions);
- script = parser.ParseScriptGuarded(_engine.Realm, x.ToString(), strict: strictCaller);
- var body = script.Body;
- if (body.Count == 0)
- {
- return Undefined;
- }
- var analyzer = new EvalScriptAnalyzer();
- analyzer.Visit(script);
- if (!inFunction)
- {
- // if body Contains NewTarget, throw a SyntaxError exception.
- if (analyzer._containsNewTarget)
- {
- Throw.SyntaxError(evalRealm, "new.target expression is not allowed here");
- }
- }
- if (!inMethod)
- {
- // if body Contains SuperProperty, throw a SyntaxError exception.
- if (analyzer._containsSuperProperty)
- {
- Throw.SyntaxError(evalRealm, "'super' keyword unexpected here");
- }
- }
- if (!inDerivedConstructor)
- {
- // if body Contains SuperCall, throw a SyntaxError exception.
- if (analyzer._containsSuperCall)
- {
- Throw.SyntaxError(evalRealm, "'super' keyword unexpected here");
- }
- }
- if (inClassFieldInitializer)
- {
- // if ContainsArguments of body is true, throw a SyntaxError exception.
- if (analyzer._containsArguments)
- {
- Throw.SyntaxError(evalRealm, "'arguments' is not allowed in class field initializer or static initialization block");
- }
- }
- var strictEval = script.Strict || _engine._isStrict;
- var ctx = _engine.ExecutionContext;
- using (new StrictModeScope(strictEval))
- {
- Environment lexEnv;
- Environment varEnv;
- PrivateEnvironment? privateEnv;
- if (direct)
- {
- lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, ctx.LexicalEnvironment);
- varEnv = ctx.VariableEnvironment;
- privateEnv = ctx.PrivateEnvironment;
- }
- else
- {
- lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, evalRealm.GlobalEnv);
- varEnv = evalRealm.GlobalEnv;
- privateEnv = null;
- }
- if (strictEval)
- {
- varEnv = lexEnv;
- }
- // If ctx is not already suspended, suspend ctx.
- Engine.EnterExecutionContext(lexEnv, varEnv, evalRealm, privateEnv);
- try
- {
- Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval);
- var statement = new JintScript(script);
- var context = _engine._activeEvaluationContext ?? new EvaluationContext(_engine);
- var result = statement.Execute(context);
- var value = result.GetValueOrDefault();
- if (result.Type == CompletionType.Throw)
- {
- Throw.JavaScriptException(_engine, value, result);
- return null!;
- }
- else
- {
- return value;
- }
- }
- finally
- {
- Engine.LeaveExecutionContext();
- }
- }
- }
- private sealed class EvalScriptAnalyzer : AstVisitor
- {
- public bool _containsArguments;
- public bool _containsNewTarget;
- public bool _containsSuperCall;
- public bool _containsSuperProperty;
- protected override object VisitIdentifier(Identifier identifier)
- {
- _containsArguments |= string.Equals(identifier.Name, "arguments", StringComparison.Ordinal);
- return identifier;
- }
- protected override object VisitMetaProperty(MetaProperty metaProperty)
- {
- _containsNewTarget |= string.Equals(metaProperty.Meta.Name, "new", StringComparison.Ordinal) && string.Equals(metaProperty.Property.Name, "target", StringComparison.Ordinal);
- return metaProperty;
- }
- protected override object? VisitMemberExpression(MemberExpression memberExpression)
- {
- _containsSuperProperty |= memberExpression.Object.Type == NodeType.Super;
- return base.VisitMemberExpression(memberExpression);
- }
- protected override object? VisitCallExpression(CallExpression callExpression)
- {
- _containsSuperCall |= callExpression.Callee.Type == NodeType.Super;
- return base.VisitCallExpression(callExpression);
- }
- protected override object? VisitFunctionDeclaration(FunctionDeclaration node)
- {
- return node;
- }
- protected override object? VisitFunctionExpression(FunctionExpression node)
- {
- return node;
- }
- }
- }
|