JintLiteralExpression.cs 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. using System.Numerics;
  2. using Esprima;
  3. using Esprima.Ast;
  4. using Jint.Native;
  5. namespace Jint.Runtime.Interpreter.Expressions
  6. {
  7. internal sealed class JintLiteralExpression : JintExpression
  8. {
  9. private static readonly object _nullMarker = new();
  10. private JintLiteralExpression(Literal expression) : base(expression)
  11. {
  12. }
  13. internal static JintExpression Build(Literal expression)
  14. {
  15. var value = expression.AssociatedData ??= ConvertToJsValue(expression) ?? _nullMarker;
  16. if (value is JsValue constant)
  17. {
  18. return new JintConstantExpression(expression, constant);
  19. }
  20. return new JintLiteralExpression(expression);
  21. }
  22. internal static JsValue? ConvertToJsValue(Literal literal)
  23. {
  24. if (literal.TokenType == TokenType.BooleanLiteral)
  25. {
  26. return literal.BooleanValue!.Value ? JsBoolean.True : JsBoolean.False;
  27. }
  28. if (literal.TokenType == TokenType.NullLiteral)
  29. {
  30. return JsValue.Null;
  31. }
  32. if (literal.TokenType == TokenType.NumericLiteral)
  33. {
  34. // unbox only once
  35. var numericValue = (double) literal.Value!;
  36. var intValue = (int) numericValue;
  37. return numericValue == intValue
  38. && (intValue != 0 || BitConverter.DoubleToInt64Bits(numericValue) != JsNumber.NegativeZeroBits)
  39. ? JsNumber.Create(intValue)
  40. : JsNumber.Create(numericValue);
  41. }
  42. if (literal.TokenType == TokenType.StringLiteral)
  43. {
  44. return JsString.Create((string) literal.Value!);
  45. }
  46. if (literal.TokenType == TokenType.BigIntLiteral)
  47. {
  48. return JsBigInt.Create((BigInteger) literal.Value!);
  49. }
  50. return null;
  51. }
  52. public override JsValue GetValue(EvaluationContext context)
  53. {
  54. // need to notify correct node when taking shortcut
  55. context.LastSyntaxElement = _expression;
  56. return ResolveValue(context);
  57. }
  58. protected override object EvaluateInternal(EvaluationContext context) => ResolveValue(context);
  59. private JsValue ResolveValue(EvaluationContext context)
  60. {
  61. var expression = (Literal) _expression;
  62. if (expression.TokenType == TokenType.RegularExpression)
  63. {
  64. var regExpLiteral = (RegExpLiteral) _expression;
  65. var regExpParseResult = regExpLiteral.ParseResult;
  66. if (regExpParseResult.Success)
  67. {
  68. return context.Engine.Realm.Intrinsics.RegExp.Construct(regExpParseResult.Regex!, regExpLiteral.Regex.Pattern, regExpLiteral.Regex.Flags, regExpParseResult);
  69. }
  70. ExceptionHelper.ThrowSyntaxError(context.Engine.Realm, $"Unsupported regular expression. {regExpParseResult.ConversionError!.Description}");
  71. }
  72. return JsValue.FromObject(context.Engine, expression.Value);
  73. }
  74. }
  75. }