JintIdentifierExpression.cs 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using System.Diagnostics.CodeAnalysis;
  2. using System.Runtime.CompilerServices;
  3. using Esprima.Ast;
  4. using Jint.Native;
  5. using Jint.Runtime.Environments;
  6. using Environment = Jint.Runtime.Environments.Environment;
  7. namespace Jint.Runtime.Interpreter.Expressions;
  8. internal sealed class JintIdentifierExpression : JintExpression
  9. {
  10. private readonly Environment.BindingName _identifier;
  11. public JintIdentifierExpression(Identifier expression) : this(expression, new Environment.BindingName(expression.Name))
  12. {
  13. _identifier = new Environment.BindingName(((Identifier) _expression).Name);
  14. }
  15. public JintIdentifierExpression(Identifier identifier, Environment.BindingName bindingName) : base(identifier)
  16. {
  17. _identifier = bindingName;
  18. }
  19. public Environment.BindingName Identifier => _identifier;
  20. public bool HasEvalOrArguments
  21. {
  22. get
  23. {
  24. var key = _identifier.Key;
  25. return key == KnownKeys.Eval || key == KnownKeys.Arguments;
  26. }
  27. }
  28. protected override object EvaluateInternal(EvaluationContext context)
  29. {
  30. var engine = context.Engine;
  31. var env = engine.ExecutionContext.LexicalEnvironment;
  32. var strict = StrictModeScope.IsStrictModeCode;
  33. var identifierEnvironment = JintEnvironment.TryGetIdentifierEnvironmentWithBinding(env, _identifier, out var temp)
  34. ? temp
  35. : JsValue.Undefined;
  36. return engine._referencePool.Rent(identifierEnvironment, _identifier.Value, strict, thisValue: null);
  37. }
  38. public override JsValue GetValue(EvaluationContext context)
  39. {
  40. // need to notify correct node when taking shortcut
  41. context.LastSyntaxElement = _expression;
  42. var identifier = Identifier;
  43. if (identifier.CalculatedValue is not null)
  44. {
  45. return identifier.CalculatedValue;
  46. }
  47. var strict = StrictModeScope.IsStrictModeCode;
  48. var engine = context.Engine;
  49. var env = engine.ExecutionContext.LexicalEnvironment;
  50. if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
  51. env,
  52. identifier,
  53. strict,
  54. out _,
  55. out var value))
  56. {
  57. if (value is null)
  58. {
  59. ThrowNotInitialized(engine);
  60. }
  61. }
  62. else
  63. {
  64. var reference = engine._referencePool.Rent(JsValue.Undefined, identifier.Value, strict, thisValue: null);
  65. value = engine.GetValue(reference, returnReferenceToPool: true);
  66. }
  67. // make sure arguments access freezes state
  68. if (value is JsArguments argumentsInstance)
  69. {
  70. argumentsInstance.Materialize();
  71. }
  72. return value;
  73. }
  74. [DoesNotReturn]
  75. [MethodImpl(MethodImplOptions.NoInlining)]
  76. private void ThrowNotInitialized(Engine engine)
  77. {
  78. ExceptionHelper.ThrowReferenceError(engine.Realm, $"{_identifier.Key.Name} has not been initialized");
  79. }
  80. }