EvalFunction.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using Jint.Runtime;
  2. using Jint.Runtime.Descriptors;
  3. using Jint.Runtime.Environments;
  4. using Jint.Runtime.Interpreter.Statements;
  5. using Environment = Jint.Runtime.Environments.Environment;
  6. namespace Jint.Native.Function;
  7. public sealed class EvalFunction : Function
  8. {
  9. private static readonly JsString _functionName = new("eval");
  10. internal EvalFunction(
  11. Engine engine,
  12. Realm realm,
  13. FunctionPrototype functionPrototype)
  14. : base(
  15. engine,
  16. realm,
  17. _functionName,
  18. StrictModeScope.IsStrictModeCode ? FunctionThisMode.Strict : FunctionThisMode.Global)
  19. {
  20. _prototype = functionPrototype;
  21. _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
  22. }
  23. protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
  24. {
  25. var callerRealm = _engine.ExecutionContext.Realm;
  26. var x = arguments.At(0);
  27. return PerformEval(x, callerRealm, false, false);
  28. }
  29. /// <summary>
  30. /// https://tc39.es/ecma262/#sec-performeval
  31. /// </summary>
  32. internal JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool direct)
  33. {
  34. if (!x.IsString())
  35. {
  36. return x;
  37. }
  38. var evalRealm = _realm;
  39. _engine._host.EnsureCanCompileStrings(callerRealm, evalRealm);
  40. var inFunction = false;
  41. var inMethod = false;
  42. var inDerivedConstructor = false;
  43. var inClassFieldInitializer = false;
  44. if (direct)
  45. {
  46. var thisEnvRec = _engine.ExecutionContext.GetThisEnvironment();
  47. if (thisEnvRec is FunctionEnvironment functionEnvironmentRecord)
  48. {
  49. var F = functionEnvironmentRecord._functionObject;
  50. inFunction = true;
  51. inMethod = thisEnvRec.HasSuperBinding();
  52. if (F._constructorKind == ConstructorKind.Derived)
  53. {
  54. inDerivedConstructor = true;
  55. }
  56. var classFieldInitializerName = (F as ScriptFunction)?._classFieldInitializerName;
  57. if (!string.IsNullOrEmpty(classFieldInitializerName?.ToString()))
  58. {
  59. inClassFieldInitializer = true;
  60. }
  61. }
  62. }
  63. Script? script = null;
  64. var parserOptions = _engine.GetActiveParserOptions();
  65. var adjustedParserOptions = parserOptions with
  66. {
  67. AllowReturnOutsideFunction = false,
  68. AllowNewTargetOutsideFunction = true,
  69. AllowSuperOutsideMethod = true,
  70. // This is a workaround, just makes some tests pass. Actually, we need these checks (done either by the parser or by the runtime).
  71. // TODO: implement a correct solution
  72. CheckPrivateFields = false
  73. };
  74. var parser = _engine.GetParserFor(adjustedParserOptions);
  75. try
  76. {
  77. script = parser.ParseScript(x.ToString(), strict: strictCaller);
  78. }
  79. catch (ParseErrorException e)
  80. {
  81. if (string.Equals(e.Error.Code, "InvalidLhsInAssignment", StringComparison.Ordinal))
  82. {
  83. ExceptionHelper.ThrowReferenceError(callerRealm, (string?) null);
  84. }
  85. else
  86. {
  87. ExceptionHelper.ThrowSyntaxError(callerRealm, e.Message);
  88. }
  89. }
  90. var body = script.Body;
  91. if (body.Count == 0)
  92. {
  93. return Undefined;
  94. }
  95. var analyzer = new EvalScriptAnalyzer();
  96. analyzer.Visit(script);
  97. if (!inFunction)
  98. {
  99. // if body Contains NewTarget, throw a SyntaxError exception.
  100. if (analyzer._containsNewTarget)
  101. {
  102. ExceptionHelper.ThrowSyntaxError(evalRealm, "new.target expression is not allowed here");
  103. }
  104. }
  105. if (!inMethod)
  106. {
  107. // if body Contains SuperProperty, throw a SyntaxError exception.
  108. if (analyzer._containsSuperProperty)
  109. {
  110. ExceptionHelper.ThrowSyntaxError(evalRealm, "'super' keyword unexpected here");
  111. }
  112. }
  113. if (!inDerivedConstructor)
  114. {
  115. // if body Contains SuperCall, throw a SyntaxError exception.
  116. if (analyzer._containsSuperCall)
  117. {
  118. ExceptionHelper.ThrowSyntaxError(evalRealm, "'super' keyword unexpected here");
  119. }
  120. }
  121. if (inClassFieldInitializer)
  122. {
  123. // if ContainsArguments of body is true, throw a SyntaxError exception.
  124. if (analyzer._containsArguments)
  125. {
  126. ExceptionHelper.ThrowSyntaxError(evalRealm, "'arguments' is not allowed in class field initializer or static initialization block");
  127. }
  128. }
  129. var strictEval = script.Strict || _engine._isStrict;
  130. var ctx = _engine.ExecutionContext;
  131. using (new StrictModeScope(strictEval))
  132. {
  133. Environment lexEnv;
  134. Environment varEnv;
  135. PrivateEnvironment? privateEnv;
  136. if (direct)
  137. {
  138. lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, ctx.LexicalEnvironment);
  139. varEnv = ctx.VariableEnvironment;
  140. privateEnv = ctx.PrivateEnvironment;
  141. }
  142. else
  143. {
  144. lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, evalRealm.GlobalEnv);
  145. varEnv = evalRealm.GlobalEnv;
  146. privateEnv = null;
  147. }
  148. if (strictEval)
  149. {
  150. varEnv = lexEnv;
  151. }
  152. // If ctx is not already suspended, suspend ctx.
  153. Engine.EnterExecutionContext(lexEnv, varEnv, evalRealm, privateEnv);
  154. try
  155. {
  156. Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval);
  157. var statement = new JintScript(script);
  158. var result = statement.Execute(_engine._activeEvaluationContext!);
  159. var value = result.GetValueOrDefault();
  160. if (result.Type == CompletionType.Throw)
  161. {
  162. ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
  163. return null!;
  164. }
  165. else
  166. {
  167. return value;
  168. }
  169. }
  170. finally
  171. {
  172. Engine.LeaveExecutionContext();
  173. }
  174. }
  175. }
  176. private sealed class EvalScriptAnalyzer : AstVisitor
  177. {
  178. public bool _containsArguments;
  179. public bool _containsNewTarget;
  180. public bool _containsSuperCall;
  181. public bool _containsSuperProperty;
  182. protected override object VisitIdentifier(Identifier identifier)
  183. {
  184. _containsArguments |= string.Equals(identifier.Name, "arguments", StringComparison.Ordinal);
  185. return identifier;
  186. }
  187. protected override object VisitMetaProperty(MetaProperty metaProperty)
  188. {
  189. _containsNewTarget |= string.Equals(metaProperty.Meta.Name, "new", StringComparison.Ordinal) && string.Equals(metaProperty.Property.Name, "target", StringComparison.Ordinal);
  190. return metaProperty;
  191. }
  192. protected override object? VisitMemberExpression(MemberExpression memberExpression)
  193. {
  194. _containsSuperProperty |= memberExpression.Object.Type == NodeType.Super;
  195. return base.VisitMemberExpression(memberExpression);
  196. }
  197. protected override object? VisitCallExpression(CallExpression callExpression)
  198. {
  199. _containsSuperCall |= callExpression.Callee.Type == NodeType.Super;
  200. return base.VisitCallExpression(callExpression);
  201. }
  202. }
  203. }