EvalFunction.cs 7.8 KB

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