JintLiteralExpression.cs 3.3 KB

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