number.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. export const numberMethods = new Set(["toFixed", "toPrecision", "toExponential", "toString"])
  2. export const numberConstants = new Set(["MAX_SAFE_INTEGER", "MIN_SAFE_INTEGER", "MAX_VALUE", "MIN_VALUE", "EPSILON"])
  3. export const numberStatics = new Set(["isInteger", "isFinite", "isNaN", "isSafeInteger", "parseInt", "parseFloat"])
  4. export const invokeNumberMethod = (value: number, name: string, args: Array<unknown>, node: AstNode): unknown => {
  5. const optNum = (index: number): number | undefined => {
  6. const arg = args[index]
  7. if (arg === undefined) return undefined
  8. if (typeof arg !== "number") throw new InterpreterRuntimeError(`Number.${name} expects a number argument.`, node)
  9. return arg
  10. }
  11. let result: unknown
  12. switch (name) {
  13. case "toFixed":
  14. result = value.toFixed(optNum(0))
  15. break
  16. case "toExponential":
  17. result = value.toExponential(optNum(0))
  18. break
  19. case "toPrecision": {
  20. const digits = optNum(0)
  21. result = digits === undefined ? value.toString() : value.toPrecision(digits)
  22. break
  23. }
  24. case "toString": {
  25. const radix = optNum(0)
  26. if (radix !== undefined && (radix < 2 || radix > 36)) {
  27. throw new InterpreterRuntimeError("Number.toString radix must be between 2 and 36.", node)
  28. }
  29. result = value.toString(radix)
  30. break
  31. }
  32. default:
  33. throw new InterpreterRuntimeError(`Number method '${name}' is not available in CodeMode.`, node)
  34. }
  35. return boundedData(result, `Number.${name} result`)
  36. }
  37. export const invokeNumberStatic = (name: string, args: Array<unknown>, node: AstNode): unknown => {
  38. const value = args[0]
  39. switch (name) {
  40. case "isInteger":
  41. return Number.isInteger(value)
  42. case "isFinite":
  43. return Number.isFinite(value)
  44. case "isNaN":
  45. return Number.isNaN(value)
  46. case "isSafeInteger":
  47. return Number.isSafeInteger(value)
  48. case "parseInt": {
  49. const radix = args[1]
  50. if (radix !== undefined && typeof radix !== "number") {
  51. throw new InterpreterRuntimeError("Number.parseInt expects a numeric radix.", node)
  52. }
  53. return parseInt(coerceToString(value), radix)
  54. }
  55. case "parseFloat":
  56. return parseFloat(coerceToString(value))
  57. default:
  58. throw new InterpreterRuntimeError(`Number.${name} is not available in CodeMode.`, node)
  59. }
  60. }
  61. import { type AstNode, InterpreterRuntimeError } from "../interpreter/model.js"
  62. import { boundedData, coerceToString } from "./value.js"