EvalFunction.cs 7.4 KB

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