xbintsc 0.2.9 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/README.md +17 -2
  2. package/README.zh-CN.md +16 -2
  3. package/bin/xbintsc.js +49 -10
  4. package/dist/src/ast/expressions.d.ts +2 -0
  5. package/dist/src/binder/binder.d.ts +24 -98
  6. package/dist/src/binder/binder.js +13 -559
  7. package/dist/src/binder/binder.js.map +1 -1
  8. package/dist/src/binder/declarations.d.ts +16 -0
  9. package/dist/src/binder/declarations.js +168 -0
  10. package/dist/src/binder/declarations.js.map +1 -0
  11. package/dist/src/binder/helpers.d.ts +11 -0
  12. package/dist/src/binder/helpers.js +46 -0
  13. package/dist/src/binder/helpers.js.map +1 -0
  14. package/dist/src/binder/references.d.ts +21 -0
  15. package/dist/src/binder/references.js +349 -0
  16. package/dist/src/binder/references.js.map +1 -0
  17. package/dist/src/binder/types.d.ts +114 -0
  18. package/dist/src/binder/types.js +27 -0
  19. package/dist/src/binder/types.js.map +1 -0
  20. package/dist/src/cli/main.d.ts +1 -0
  21. package/dist/src/cli/main.js +40 -0
  22. package/dist/src/cli/main.js.map +1 -1
  23. package/dist/src/codegen/generator/calls/access.d.ts +13 -0
  24. package/dist/src/codegen/generator/calls/access.js +115 -0
  25. package/dist/src/codegen/generator/calls/access.js.map +1 -0
  26. package/dist/src/codegen/generator/calls/closures.d.ts +11 -0
  27. package/dist/src/codegen/generator/calls/closures.js +50 -0
  28. package/dist/src/codegen/generator/calls/closures.js.map +1 -0
  29. package/dist/src/codegen/generator/calls/invocation.d.ts +18 -0
  30. package/dist/src/codegen/generator/calls/invocation.js +242 -0
  31. package/dist/src/codegen/generator/calls/invocation.js.map +1 -0
  32. package/dist/src/codegen/generator/calls/literals.d.ts +10 -0
  33. package/dist/src/codegen/generator/calls/literals.js +69 -0
  34. package/dist/src/codegen/generator/calls/literals.js.map +1 -0
  35. package/dist/src/codegen/generator/calls/super.d.ts +10 -0
  36. package/dist/src/codegen/generator/calls/super.js +47 -0
  37. package/dist/src/codegen/generator/calls/super.js.map +1 -0
  38. package/dist/src/codegen/generator/calls.d.ts +15 -24
  39. package/dist/src/codegen/generator/calls.js +15 -482
  40. package/dist/src/codegen/generator/calls.js.map +1 -1
  41. package/dist/src/codegen/generator/context.d.ts +1 -1
  42. package/dist/src/codegen/generator/context.js +2 -2
  43. package/dist/src/codegen/generator/context.js.map +1 -1
  44. package/dist/src/codegen/generator/expressions/assignment.d.ts +13 -0
  45. package/dist/src/codegen/generator/expressions/assignment.js +203 -0
  46. package/dist/src/codegen/generator/expressions/assignment.js.map +1 -0
  47. package/dist/src/codegen/generator/expressions/operators.d.ts +14 -0
  48. package/dist/src/codegen/generator/expressions/operators.js +163 -0
  49. package/dist/src/codegen/generator/expressions/operators.js.map +1 -0
  50. package/dist/src/codegen/generator/expressions/primary.d.ts +17 -0
  51. package/dist/src/codegen/generator/expressions/primary.js +260 -0
  52. package/dist/src/codegen/generator/expressions/primary.js.map +1 -0
  53. package/dist/src/codegen/generator/expressions.d.ts +11 -21
  54. package/dist/src/codegen/generator/expressions.js +11 -494
  55. package/dist/src/codegen/generator/expressions.js.map +1 -1
  56. package/dist/src/codegen/generator/module.js +16 -4
  57. package/dist/src/codegen/generator/module.js.map +1 -1
  58. package/dist/src/codegen/generator/state.js +8 -0
  59. package/dist/src/codegen/generator/state.js.map +1 -1
  60. package/dist/src/codegen/generator/statements/control-flow.d.ts +14 -0
  61. package/dist/src/codegen/generator/statements/control-flow.js +199 -0
  62. package/dist/src/codegen/generator/statements/control-flow.js.map +1 -0
  63. package/dist/src/codegen/generator/statements/dispatch.d.ts +12 -0
  64. package/dist/src/codegen/generator/statements/dispatch.js +100 -0
  65. package/dist/src/codegen/generator/statements/dispatch.js.map +1 -0
  66. package/dist/src/codegen/generator/statements/loops.d.ts +13 -0
  67. package/dist/src/codegen/generator/statements/loops.js +152 -0
  68. package/dist/src/codegen/generator/statements/loops.js.map +1 -0
  69. package/dist/src/codegen/generator/statements/variables.d.ts +13 -0
  70. package/dist/src/codegen/generator/statements/variables.js +146 -0
  71. package/dist/src/codegen/generator/statements/variables.js.map +1 -0
  72. package/dist/src/codegen/generator/statements.d.ts +13 -21
  73. package/dist/src/codegen/generator/statements.js +13 -568
  74. package/dist/src/codegen/generator/statements.js.map +1 -1
  75. package/dist/src/codegen/generator/tables.js +7 -0
  76. package/dist/src/codegen/generator/tables.js.map +1 -1
  77. package/dist/src/codegen/values.d.ts +17 -17
  78. package/dist/src/codegen/values.js +21 -57
  79. package/dist/src/codegen/values.js.map +1 -1
  80. package/dist/src/diagnostics/diagnostic.d.ts +1 -0
  81. package/dist/src/diagnostics/diagnostic.js +1 -0
  82. package/dist/src/diagnostics/diagnostic.js.map +1 -1
  83. package/dist/src/diagnostics/source.d.ts +1 -1
  84. package/dist/src/diagnostics/source.js +7 -12
  85. package/dist/src/diagnostics/source.js.map +1 -1
  86. package/dist/src/driver/compiler.d.ts +4 -0
  87. package/dist/src/driver/compiler.js +51 -16
  88. package/dist/src/driver/compiler.js.map +1 -1
  89. package/dist/src/driver/index.d.ts +5 -2
  90. package/dist/src/driver/index.js +5 -2
  91. package/dist/src/driver/index.js.map +1 -1
  92. package/dist/src/driver/paths.d.ts +20 -0
  93. package/dist/src/driver/paths.js +49 -0
  94. package/dist/src/driver/paths.js.map +1 -1
  95. package/dist/src/driver/runtime-lib.d.ts +18 -0
  96. package/dist/src/driver/runtime-lib.js +31 -0
  97. package/dist/src/driver/runtime-lib.js.map +1 -0
  98. package/dist/src/driver/toolchain-download.d.ts +50 -0
  99. package/dist/src/driver/toolchain-download.js +76 -0
  100. package/dist/src/driver/toolchain-download.js.map +1 -0
  101. package/dist/src/driver/toolchain-provider.d.ts +33 -0
  102. package/dist/src/driver/toolchain-provider.js +71 -0
  103. package/dist/src/driver/toolchain-provider.js.map +1 -0
  104. package/dist/src/driver/toolchain.d.ts +9 -4
  105. package/dist/src/driver/toolchain.js +6 -10
  106. package/dist/src/driver/toolchain.js.map +1 -1
  107. package/dist/src/extensions/node/child_process/index.d.ts +4 -2
  108. package/dist/src/extensions/node/child_process/index.js +4 -2
  109. package/dist/src/extensions/node/child_process/index.js.map +1 -1
  110. package/dist/src/extensions/node/events/index.d.ts +10 -0
  111. package/dist/src/extensions/node/events/index.js +22 -0
  112. package/dist/src/extensions/node/events/index.js.map +1 -0
  113. package/dist/src/extensions/node/index.js +6 -0
  114. package/dist/src/extensions/node/index.js.map +1 -1
  115. package/dist/src/extensions/node/querystring/index.d.ts +10 -0
  116. package/dist/src/extensions/node/querystring/index.js +25 -0
  117. package/dist/src/extensions/node/querystring/index.js.map +1 -0
  118. package/dist/src/extensions/node/util/index.d.ts +11 -0
  119. package/dist/src/extensions/node/util/index.js +41 -0
  120. package/dist/src/extensions/node/util/index.js.map +1 -0
  121. package/dist/src/extensions/registry.d.ts +6 -0
  122. package/dist/src/extensions/registry.js.map +1 -1
  123. package/dist/src/index.d.ts +1 -1
  124. package/dist/src/index.js +1 -1
  125. package/dist/src/index.js.map +1 -1
  126. package/dist/src/lexer/scanner/identifiers.d.ts +9 -0
  127. package/dist/src/lexer/scanner/identifiers.js +33 -0
  128. package/dist/src/lexer/scanner/identifiers.js.map +1 -0
  129. package/dist/src/lexer/scanner/numbers.d.ts +10 -0
  130. package/dist/src/lexer/scanner/numbers.js +89 -0
  131. package/dist/src/lexer/scanner/numbers.js.map +1 -0
  132. package/dist/src/lexer/scanner/punctuation.d.ts +9 -0
  133. package/dist/src/lexer/scanner/punctuation.js +151 -0
  134. package/dist/src/lexer/scanner/punctuation.js.map +1 -0
  135. package/dist/src/lexer/scanner/regex.d.ts +11 -0
  136. package/dist/src/lexer/scanner/regex.js +69 -0
  137. package/dist/src/lexer/scanner/regex.js.map +1 -0
  138. package/dist/src/lexer/scanner/strings.d.ts +13 -0
  139. package/dist/src/lexer/scanner/strings.js +118 -0
  140. package/dist/src/lexer/scanner/strings.js.map +1 -0
  141. package/dist/src/lexer/scanner.d.ts +20 -27
  142. package/dist/src/lexer/scanner.js +11 -415
  143. package/dist/src/lexer/scanner.js.map +1 -1
  144. package/dist/src/parser/declarations/classes.d.ts +14 -0
  145. package/dist/src/parser/declarations/classes.js +191 -0
  146. package/dist/src/parser/declarations/classes.js.map +1 -0
  147. package/dist/src/parser/declarations/functions.d.ts +17 -0
  148. package/dist/src/parser/declarations/functions.js +241 -0
  149. package/dist/src/parser/declarations/functions.js.map +1 -0
  150. package/dist/src/parser/declarations/type-members.d.ts +16 -0
  151. package/dist/src/parser/declarations/type-members.js +156 -0
  152. package/dist/src/parser/declarations/type-members.js.map +1 -0
  153. package/dist/src/parser/declarations.d.ts +13 -24
  154. package/dist/src/parser/declarations.js +13 -571
  155. package/dist/src/parser/declarations.js.map +1 -1
  156. package/dist/src/parser/helpers.js +13 -4
  157. package/dist/src/parser/helpers.js.map +1 -1
  158. package/dist/src/parser/literals.js +10 -1
  159. package/dist/src/parser/literals.js.map +1 -1
  160. package/dist/tests/codegen/llvm.test.js +24 -0
  161. package/dist/tests/codegen/llvm.test.js.map +1 -1
  162. package/dist/tests/driver/compiler.test.js +3 -0
  163. package/dist/tests/driver/compiler.test.js.map +1 -1
  164. package/dist/tests/driver/paths.test.d.ts +1 -0
  165. package/dist/tests/driver/paths.test.js +26 -0
  166. package/dist/tests/driver/paths.test.js.map +1 -0
  167. package/dist/tests/driver/toolchain-download.test.d.ts +1 -0
  168. package/dist/tests/driver/toolchain-download.test.js +38 -0
  169. package/dist/tests/driver/toolchain-download.test.js.map +1 -0
  170. package/dist/tests/driver/toolchain-provider.test.d.ts +1 -0
  171. package/dist/tests/driver/toolchain-provider.test.js +37 -0
  172. package/dist/tests/driver/toolchain-provider.test.js.map +1 -0
  173. package/dist/tests/e2e/compile-node.test.d.ts +7 -0
  174. package/dist/tests/e2e/compile-node.test.js +123 -0
  175. package/dist/tests/e2e/compile-node.test.js.map +1 -0
  176. package/dist/tests/e2e/compile.test.d.ts +4 -1
  177. package/dist/tests/e2e/compile.test.js +78 -130
  178. package/dist/tests/e2e/compile.test.js.map +1 -1
  179. package/dist/tests/e2e/harness.d.ts +36 -0
  180. package/dist/tests/e2e/harness.js +64 -0
  181. package/dist/tests/e2e/harness.js.map +1 -0
  182. package/dist/tests/e2e/node-modules.test.js +60 -0
  183. package/dist/tests/e2e/node-modules.test.js.map +1 -1
  184. package/dist/tests/extensions/registry.test.js +4 -0
  185. package/dist/tests/extensions/registry.test.js.map +1 -1
  186. package/package.json +5 -3
  187. package/runtime/ext_node/buffer/buffer.c +12 -552
  188. package/runtime/ext_node/buffer/parts/byte-access.inc +35 -0
  189. package/runtime/ext_node/buffer/parts/construction.inc +60 -0
  190. package/runtime/ext_node/buffer/parts/integer-io.inc +119 -0
  191. package/runtime/ext_node/buffer/parts/methods.inc +135 -0
  192. package/runtime/ext_node/buffer/parts/prototype.inc +54 -0
  193. package/runtime/ext_node/buffer/parts/search.inc +86 -0
  194. package/runtime/ext_node/buffer/parts/static-api.inc +58 -0
  195. package/runtime/ext_node/child_process/child_process.c +37 -3
  196. package/runtime/ext_node/events/events.c +285 -0
  197. package/runtime/ext_node/http/http.c +11 -736
  198. package/runtime/ext_node/http/parts/client.inc +290 -0
  199. package/runtime/ext_node/http/parts/helpers.inc +45 -0
  200. package/runtime/ext_node/http/parts/prototypes.inc +57 -0
  201. package/runtime/ext_node/http/parts/response.inc +149 -0
  202. package/runtime/ext_node/http/parts/server.inc +133 -0
  203. package/runtime/ext_node/http/parts/string-builder.inc +58 -0
  204. package/runtime/ext_node/net/net.c +12 -504
  205. package/runtime/ext_node/net/parts/construction.inc +22 -0
  206. package/runtime/ext_node/net/parts/platform.inc +60 -0
  207. package/runtime/ext_node/net/parts/prototypes.inc +35 -0
  208. package/runtime/ext_node/net/parts/read-loop.inc +58 -0
  209. package/runtime/ext_node/net/parts/server.inc +131 -0
  210. package/runtime/ext_node/net/parts/socket-methods.inc +100 -0
  211. package/runtime/ext_node/net/parts/static-api.inc +93 -0
  212. package/runtime/ext_node/querystring/querystring.c +251 -0
  213. package/runtime/ext_node/util/util.c +456 -0
  214. package/runtime/rt.h +8 -2
  215. package/runtime/rt_internal.h +34 -0
  216. package/runtime/xt_bigint/arithmetic.inc +135 -0
  217. package/runtime/xt_bigint/bits.inc +98 -0
  218. package/runtime/xt_bigint/bitwise.inc +103 -0
  219. package/runtime/xt_bigint/compare.inc +30 -0
  220. package/runtime/xt_bigint/conversions.inc +51 -0
  221. package/runtime/xt_bigint/division.inc +85 -0
  222. package/runtime/xt_bigint/format.inc +145 -0
  223. package/runtime/xt_bigint/helpers.inc +92 -0
  224. package/runtime/xt_bigint/magnitude.inc +88 -0
  225. package/runtime/xt_bigint/public.inc +59 -0
  226. package/runtime/xt_bigint/small-arithmetic.inc +58 -0
  227. package/runtime/xt_bigint.c +42 -0
  228. package/runtime/xt_builtins.c +1 -0
  229. package/runtime/xt_io.c +7 -0
  230. package/runtime/xt_stdlib/arrays.inc +161 -0
  231. package/runtime/xt_stdlib/dispatch.inc +116 -0
  232. package/runtime/xt_stdlib/helpers.inc +23 -0
  233. package/runtime/xt_stdlib/math.inc +72 -0
  234. package/runtime/xt_stdlib/strings.inc +178 -0
  235. package/runtime/xt_stdlib.c +10 -549
  236. package/runtime/xt_stdlib2/array-statics.inc +37 -0
  237. package/runtime/xt_stdlib2/arrays.inc +189 -0
  238. package/runtime/xt_stdlib2/container.inc +23 -0
  239. package/runtime/xt_stdlib2/date.inc +72 -0
  240. package/runtime/xt_stdlib2/error.inc +22 -0
  241. package/runtime/xt_stdlib2/helpers.inc +43 -0
  242. package/runtime/xt_stdlib2/json.inc +213 -0
  243. package/runtime/xt_stdlib2/map.inc +95 -0
  244. package/runtime/xt_stdlib2/number-string-statics.inc +73 -0
  245. package/runtime/xt_stdlib2/numbers.inc +38 -0
  246. package/runtime/xt_stdlib2/objects.inc +41 -0
  247. package/runtime/xt_stdlib2/regexp-match.inc +204 -0
  248. package/runtime/xt_stdlib2/regexp.inc +20 -0
  249. package/runtime/xt_stdlib2/set.inc +105 -0
  250. package/runtime/xt_stdlib2/strings.inc +94 -0
  251. package/runtime/xt_stdlib2.c +19 -1278
  252. package/runtime/xt_values.c +155 -12
  253. package/scripts/build-runtime.ts +109 -0
  254. package/scripts/fetch-toolchain.ts +101 -0
  255. package/scripts/package-release.ts +192 -0
  256. package/src/ast/expressions.ts +2 -0
  257. package/src/binder/binder.ts +40 -725
  258. package/src/binder/declarations.ts +203 -0
  259. package/src/binder/helpers.ts +47 -0
  260. package/src/binder/references.ts +410 -0
  261. package/src/binder/types.ts +134 -0
  262. package/src/cli/main.ts +43 -0
  263. package/src/codegen/generator/calls/access.ts +139 -0
  264. package/src/codegen/generator/calls/closures.ts +60 -0
  265. package/src/codegen/generator/calls/invocation.ts +282 -0
  266. package/src/codegen/generator/calls/literals.ts +77 -0
  267. package/src/codegen/generator/calls/super.ts +61 -0
  268. package/src/codegen/generator/calls.ts +30 -552
  269. package/src/codegen/generator/context.ts +2 -2
  270. package/src/codegen/generator/expressions/assignment.ts +226 -0
  271. package/src/codegen/generator/expressions/operators.ts +182 -0
  272. package/src/codegen/generator/expressions/primary.ts +304 -0
  273. package/src/codegen/generator/expressions.ts +22 -553
  274. package/src/codegen/generator/module.ts +14 -4
  275. package/src/codegen/generator/state.ts +8 -0
  276. package/src/codegen/generator/statements/control-flow.ts +225 -0
  277. package/src/codegen/generator/statements/dispatch.ts +122 -0
  278. package/src/codegen/generator/statements/loops.ts +173 -0
  279. package/src/codegen/generator/statements/variables.ts +152 -0
  280. package/src/codegen/generator/statements.ts +26 -612
  281. package/src/codegen/generator/tables.ts +7 -0
  282. package/src/codegen/values.ts +22 -57
  283. package/src/diagnostics/diagnostic.ts +1 -0
  284. package/src/diagnostics/source.ts +7 -12
  285. package/src/driver/compiler.ts +61 -18
  286. package/src/driver/index.ts +17 -2
  287. package/src/driver/paths.ts +54 -0
  288. package/src/driver/runtime-lib.ts +32 -0
  289. package/src/driver/toolchain-download.ts +108 -0
  290. package/src/driver/toolchain-provider.ts +91 -0
  291. package/src/driver/toolchain.ts +29 -11
  292. package/src/extensions/node/child_process/index.ts +4 -2
  293. package/src/extensions/node/events/index.ts +27 -0
  294. package/src/extensions/node/index.ts +6 -0
  295. package/src/extensions/node/querystring/index.ts +29 -0
  296. package/src/extensions/node/util/index.ts +48 -0
  297. package/src/extensions/registry.ts +6 -0
  298. package/src/index.ts +1 -0
  299. package/src/lexer/scanner/identifiers.ts +37 -0
  300. package/src/lexer/scanner/numbers.ts +84 -0
  301. package/src/lexer/scanner/punctuation.ts +132 -0
  302. package/src/lexer/scanner/regex.ts +79 -0
  303. package/src/lexer/scanner/strings.ts +128 -0
  304. package/src/lexer/scanner.ts +35 -401
  305. package/src/parser/declarations/classes.ts +215 -0
  306. package/src/parser/declarations/functions.ts +254 -0
  307. package/src/parser/declarations/type-members.ts +181 -0
  308. package/src/parser/declarations.ts +32 -609
  309. package/src/parser/helpers.ts +13 -6
  310. package/src/parser/literals.ts +10 -1
  311. package/scripts/build-runtime.mjs +0 -55
@@ -3,6 +3,10 @@
3
3
  *
4
4
  * Additional Array/String/Number/Object methods and statics, JSON, and basic
5
5
  * Map / Set / Date / RegExp implementations.
6
+ *
7
+ * The implementation is grouped by functional area under `xt_stdlib2/` and
8
+ * `#include`d here as a single translation unit, so the section helpers stay
9
+ * `static` while each file stays focused on one area.
6
10
  */
7
11
 
8
12
  #include "rt_internal.h"
@@ -19,1281 +23,18 @@
19
23
  #include <string.h>
20
24
  #include <time.h>
21
25
 
22
- /*
23
- * `timegm` and `gmtime_r` are POSIX extensions that MSVC's CRT does not
24
- * provide. Wrap the platform-specific equivalents so the Date implementation
25
- * below compiles everywhere.
26
- */
27
- #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
28
- static time_t xt_timegm(struct tm *tm) { return (time_t)_mkgmtime64(tm); }
29
- static struct tm *xt_gmtime_r(const time_t *timer, struct tm *buf) {
30
- return gmtime_s(buf, timer) == 0 ? buf : NULL;
31
- }
32
- #else
33
- static time_t xt_timegm(struct tm *tm) { return timegm(tm); }
34
- static struct tm *xt_gmtime_r(const time_t *timer, struct tm *buf) { return gmtime_r(timer, buf); }
35
- #endif
36
-
37
- int xt_value_equals(xt_value a, xt_value b) {
38
- if (XT_IS_NUMBER(a) && XT_IS_NUMBER(b)) {
39
- double x = xt_to_double(a);
40
- double y = xt_to_double(b);
41
- if (isnan(x) && isnan(y)) return 1;
42
- return x == y;
43
- }
44
- return xt_truthy(xt_seq(a, b));
45
- }
46
-
47
- static xt_value xt_number_to_radix(double value, int radix) {
48
- if (radix < 2 || radix > 36 || value != floor(value) || fabs(value) > 9.0e15) {
49
- return xt_to_string(xt_number(value));
50
- }
51
- int negative = value < 0;
52
- unsigned long long n = (unsigned long long)(negative ? -value : value);
53
- static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
54
- char buffer[80];
55
- int pos = 0;
56
- if (n == 0) buffer[pos++] = '0';
57
- while (n > 0) { buffer[pos++] = digits[n % (unsigned)radix]; n /= (unsigned)radix; }
58
- char out[80];
59
- int o = 0;
60
- if (negative) out[o++] = '-';
61
- while (pos > 0) out[o++] = buffer[--pos];
62
- return xt_string_new(out, (size_t)o);
63
- }
64
-
65
- /* -- array methods -------------------------------------------------------- */
66
-
67
- static xt_value xt_array_at(xt_value value, xt_value indexValue) {
68
- xt_array *array = xt_as_array(value);
69
- if (!array) return XT_UNDEFINED;
70
- int32_t index = indexValue == XT_UNDEFINED ? 0 : xt_to_int32(indexValue);
71
- if (index < 0) index += (int32_t)array->length;
72
- if (index < 0 || (uint32_t)index >= array->length) return XT_UNDEFINED;
73
- return array->items[index];
74
- }
75
-
76
- static xt_value xt_array_find(xt_value value, xt_value fn, int mode) {
77
- xt_array *array = xt_as_array(value);
78
- if (!array) return (mode == 0 || mode == 2) ? XT_UNDEFINED : xt_number(-1);
79
- int reverse = (mode == 2 || mode == 3);
80
- for (uint32_t step = 0; step < array->length; step++) {
81
- int32_t i = reverse ? (int32_t)(array->length - 1 - step) : (int32_t)step;
82
- xt_value args[3] = {array->items[i], xt_number((double)i), value};
83
- if (xt_truthy(xt_closure_call(fn, 3, args))) return (mode == 0 || mode == 2) ? array->items[i] : xt_number((double)i);
84
- }
85
- return (mode == 0 || mode == 2) ? XT_UNDEFINED : xt_number(-1);
86
- }
87
-
88
- static xt_value xt_array_quantifier(xt_value value, xt_value fn, int every) {
89
- xt_array *array = xt_as_array(value);
90
- if (!array) return xt_bool(every ? 1 : 0);
91
- for (uint32_t i = 0; i < array->length; i++) {
92
- xt_value args[3] = {array->items[i], xt_number((double)i), value};
93
- int ok = xt_truthy(xt_closure_call(fn, 3, args));
94
- if (every && !ok) return XT_FALSE;
95
- if (!every && ok) return XT_TRUE;
96
- }
97
- return xt_bool(every ? 1 : 0);
98
- }
99
-
100
- static int xt_array_compare_values(xt_value a, xt_value b) {
101
- if (xt_truthy(xt_gt(a, b))) return 1;
102
- if (xt_truthy(xt_lt(a, b))) return -1;
103
- return 0;
104
- }
105
-
106
- static xt_value xt_array_sort(xt_value value, xt_value fn) {
107
- xt_array *array = xt_as_array(value);
108
- if (!array || array->length < 2) return value;
109
- int hasFn = XT_IS_FUNCTION(fn);
110
- for (uint32_t i = 1; i < array->length; i++) {
111
- xt_value key = array->items[i];
112
- int32_t j = (int32_t)i - 1;
113
- while (j >= 0) {
114
- int cmp;
115
- if (hasFn) {
116
- xt_value args[2] = {array->items[j], key};
117
- cmp = (int)xt_to_number(xt_closure_call(fn, 2, args));
118
- } else {
119
- cmp = xt_array_compare_values(array->items[j], key);
120
- }
121
- if (cmp <= 0) break;
122
- array->items[j + 1] = array->items[j];
123
- j--;
124
- }
125
- array->items[j + 1] = key;
126
- }
127
- return value;
128
- }
129
-
130
- static void xt_array_flatten_into(xt_value out, xt_value value, int depth) {
131
- xt_array *array = xt_as_array(value);
132
- if (!array) { xt_array_push(out, value); return; }
133
- for (uint32_t i = 0; i < array->length; i++) {
134
- if (depth > 0 && XT_IS_ARRAY(array->items[i])) xt_array_flatten_into(out, array->items[i], depth - 1);
135
- else xt_array_push(out, array->items[i]);
136
- }
137
- }
138
-
139
- static xt_value xt_array_flat_map(xt_value value, xt_value fn) {
140
- xt_array *array = xt_as_array(value);
141
- xt_value out = xt_array_new(0, NULL);
142
- if (!array) return out;
143
- for (uint32_t i = 0; i < array->length; i++) {
144
- xt_value args[3] = {array->items[i], xt_number((double)i), value};
145
- xt_value mapped = xt_closure_call(fn, 3, args);
146
- if (XT_IS_ARRAY(mapped)) {
147
- xt_array *m = xt_as_array(mapped);
148
- for (uint32_t j = 0; j < m->length; j++) xt_array_push(out, m->items[j]);
149
- } else xt_array_push(out, mapped);
150
- }
151
- return out;
152
- }
153
-
154
- static xt_value xt_array_last_index_of(xt_value value, xt_value needle, xt_value fromValue) {
155
- xt_array *array = xt_as_array(value);
156
- if (!array) return xt_number(-1);
157
- int32_t from = fromValue == XT_UNDEFINED ? (int32_t)array->length - 1 : xt_to_int32(fromValue);
158
- if (from < 0) from += (int32_t)array->length;
159
- if (from >= (int32_t)array->length) from = (int32_t)array->length - 1;
160
- for (int32_t i = from; i >= 0; i--) if (xt_value_equals(array->items[i], needle)) return xt_number((double)i);
161
- return xt_number(-1);
162
- }
163
-
164
- static xt_value xt_array_fill(xt_value value, xt_value fillValue, xt_value startValue, xt_value endValue) {
165
- xt_array *array = xt_as_array(value);
166
- if (!array) return value;
167
- int32_t len = (int32_t)array->length;
168
- int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
169
- int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
170
- if (start < 0) start += len;
171
- if (end < 0) end += len;
172
- if (start < 0) start = 0;
173
- if (end > len) end = len;
174
- for (int32_t i = start; i < end; i++) array->items[i] = fillValue;
175
- return value;
176
- }
177
-
178
- static xt_value xt_array_copy_within(xt_value value, xt_value targetValue, xt_value startValue, xt_value endValue) {
179
- xt_array *array = xt_as_array(value);
180
- if (!array) return value;
181
- int32_t len = (int32_t)array->length;
182
- int32_t target = xt_to_int32(targetValue == XT_UNDEFINED ? xt_number(0) : targetValue);
183
- int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
184
- int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
185
- if (target < 0) target += len;
186
- if (start < 0) start += len;
187
- if (end < 0) end += len;
188
- if (target < 0 || start < 0 || target >= len || start >= len) return value;
189
- if (end > len) end = len;
190
- int32_t count = end - start;
191
- if (count > len - target) count = len - target;
192
- if (count <= 0) return value;
193
- memmove(array->items + target, array->items + start, sizeof(xt_value) * (size_t)count);
194
- return value;
195
- }
196
-
197
- xt_value xt_ext_array_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
198
- *handled = 1;
199
- if (strcmp(method, "at") == 0) return xt_array_at(target, xt_arg_at(argc, argv, 0));
200
- if (strcmp(method, "find") == 0) return xt_array_find(target, xt_arg_at(argc, argv, 0), 0);
201
- if (strcmp(method, "findIndex") == 0) return xt_array_find(target, xt_arg_at(argc, argv, 0), 1);
202
- if (strcmp(method, "findLast") == 0) return xt_array_find(target, xt_arg_at(argc, argv, 0), 2);
203
- if (strcmp(method, "findLastIndex") == 0) return xt_array_find(target, xt_arg_at(argc, argv, 0), 3);
204
- if (strcmp(method, "some") == 0) return xt_array_quantifier(target, xt_arg_at(argc, argv, 0), 0);
205
- if (strcmp(method, "every") == 0) return xt_array_quantifier(target, xt_arg_at(argc, argv, 0), 1);
206
- if (strcmp(method, "sort") == 0) return xt_array_sort(target, xt_arg_at(argc, argv, 0));
207
- if (strcmp(method, "flat") == 0) {
208
- double depth = xt_arg_at(argc, argv, 0) == XT_UNDEFINED ? 1 : xt_to_number(argv[0]);
209
- if (depth < 0) depth = 0;
210
- xt_value out = xt_array_new(0, NULL);
211
- xt_array_flatten_into(out, target, (int)depth);
212
- return out;
213
- }
214
- if (strcmp(method, "flatMap") == 0) return xt_array_flat_map(target, xt_arg_at(argc, argv, 0));
215
- if (strcmp(method, "lastIndexOf") == 0) return xt_array_last_index_of(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
216
- if (strcmp(method, "fill") == 0) return xt_array_fill(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), xt_arg_at(argc, argv, 2));
217
- if (strcmp(method, "copyWithin") == 0) return xt_array_copy_within(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), xt_arg_at(argc, argv, 2));
218
- if (strcmp(method, "reduceRight") == 0) {
219
- xt_array *array = xt_as_array(target);
220
- if (!array) return XT_UNDEFINED;
221
- xt_value fn = xt_arg_at(argc, argv, 0);
222
- int32_t i = (int32_t)array->length - 1;
223
- xt_value acc;
224
- if (argc >= 2) acc = argv[1];
225
- else if (array->length > 0) acc = array->items[i--];
226
- else { xt_throw(xt_string_from_cstr("TypeError: Reduce of empty array with no initial value")); return XT_UNDEFINED; }
227
- for (; i >= 0; i--) {
228
- xt_value args[4] = {acc, array->items[i], xt_number((double)i), target};
229
- acc = xt_closure_call(fn, 4, args);
230
- }
231
- return acc;
232
- }
233
- if (strcmp(method, "toString") == 0) return xt_call_method(target, xt_string_from_cstr("join"), 0, NULL);
234
- if (strcmp(method, "keys") == 0 || strcmp(method, "values") == 0 || strcmp(method, "entries") == 0) {
235
- xt_array *array = xt_as_array(target);
236
- xt_value out = xt_array_new(0, NULL);
237
- if (!array) return out;
238
- int key = strcmp(method, "keys") == 0;
239
- int entries = strcmp(method, "entries") == 0;
240
- for (uint32_t i = 0; i < array->length; i++) {
241
- if (entries) {
242
- xt_value pair = xt_array_new(0, NULL);
243
- xt_array_push(pair, xt_number((double)i));
244
- xt_array_push(pair, array->items[i]);
245
- xt_array_push(out, pair);
246
- } else if (key) xt_array_push(out, xt_number((double)i));
247
- else xt_array_push(out, array->items[i]);
248
- }
249
- return out;
250
- }
251
- *handled = 0;
252
- return XT_UNDEFINED;
253
- }
254
-
255
- /* -- string methods ------------------------------------------------------- */
256
-
257
- static xt_value xt_string_pad(xt_value value, xt_value lengthValue, xt_value padValue, int start) {
258
- xt_string *s = xt_as_string(value);
259
- if (!s) return value;
260
- int32_t target = xt_to_int32(lengthValue);
261
- if (target <= (int32_t)s->length) return value;
262
- xt_string *pad = xt_as_string(xt_to_string(padValue == XT_UNDEFINED ? xt_string_from_cstr(" ") : padValue));
263
- if (!pad || pad->length == 0) return value;
264
- size_t total = (size_t)target;
265
- xt_string *out = xt_string_alloc(total);
266
- size_t needed = total - s->length;
267
- if (start) {
268
- for (size_t i = 0; i < needed; i++) out->data[i] = pad->data[i % pad->length];
269
- memcpy(out->data + needed, s->data, s->length);
270
- } else {
271
- memcpy(out->data, s->data, s->length);
272
- for (size_t i = 0; i < needed; i++) out->data[s->length + i] = pad->data[i % pad->length];
273
- }
274
- return XT_FROM_PTR(XT_TAG_STRING, out);
275
- }
276
-
277
- static xt_value xt_string_trim_side(xt_value value, int start) {
278
- xt_string *s = xt_as_string(value);
279
- if (!s) return value;
280
- uint32_t begin = 0;
281
- uint32_t end = s->length;
282
- if (start) { while (begin < end && isspace((unsigned char)s->data[begin])) begin++; }
283
- else { while (end > begin && isspace((unsigned char)s->data[end - 1])) end--; }
284
- return xt_string_new(s->data + begin, end - begin);
285
- }
286
-
287
- static xt_value xt_string_at(xt_value value, xt_value indexValue) {
288
- xt_string *s = xt_as_string(value);
289
- if (!s) return XT_UNDEFINED;
290
- int32_t index = indexValue == XT_UNDEFINED ? 0 : xt_to_int32(indexValue);
291
- if (index < 0) index += (int32_t)s->length;
292
- if (index < 0 || (uint32_t)index >= s->length) return XT_UNDEFINED;
293
- return xt_string_new(s->data + index, 1);
294
- }
295
-
296
- static xt_value xt_string_replace_all(xt_value value, xt_value searchValue, xt_value replacementValue) {
297
- if (xt_is_regexp(searchValue)) return xt_regexp_replace(value, searchValue, replacementValue);
298
- xt_string *s = xt_as_string(value);
299
- if (!s) return value;
300
- xt_string *search = xt_as_string(xt_to_string(searchValue));
301
- xt_string *replacement = xt_as_string(xt_to_string(replacementValue));
302
- if (!search || search->length == 0) return value;
303
- size_t capacity = s->length + replacement->length * 4 + 16;
304
- char *out = (char *)malloc(capacity);
305
- if (!out) abort();
306
- size_t length = 0;
307
- uint32_t i = 0;
308
- while (i < s->length) {
309
- if (i + search->length <= s->length && memcmp(s->data + i, search->data, search->length) == 0) {
310
- if (length + replacement->length + 2 > capacity) { capacity = (length + replacement->length + 2) * 2; out = (char *)realloc(out, capacity); if (!out) abort(); }
311
- memcpy(out + length, replacement->data, replacement->length);
312
- length += replacement->length;
313
- i += search->length;
314
- } else {
315
- if (length + 2 > capacity) { capacity *= 2; out = (char *)realloc(out, capacity); if (!out) abort(); }
316
- out[length++] = s->data[i++];
317
- }
318
- }
319
- xt_value result = xt_string_new(out, length);
320
- free(out);
321
- return result;
322
- }
323
-
324
- xt_value xt_ext_string_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
325
- *handled = 1;
326
- if (strcmp(method, "at") == 0) return xt_string_at(target, xt_arg_at(argc, argv, 0));
327
- if (strcmp(method, "padStart") == 0) return xt_string_pad(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), 1);
328
- if (strcmp(method, "padEnd") == 0) return xt_string_pad(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), 0);
329
- if (strcmp(method, "trimStart") == 0) return xt_string_trim_side(target, 1);
330
- if (strcmp(method, "trimEnd") == 0) return xt_string_trim_side(target, 0);
331
- if (strcmp(method, "replaceAll") == 0) return xt_string_replace_all(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
332
- if (strcmp(method, "localeCompare") == 0) {
333
- xt_string *a = xt_as_string(target);
334
- xt_string *b = xt_as_string(xt_to_string(xt_arg_at(argc, argv, 0)));
335
- int cmp = strcmp(a ? a->data : "", b ? b->data : "");
336
- return xt_number(cmp < 0 ? -1 : cmp > 0 ? 1 : 0);
337
- }
338
- if (strcmp(method, "codePointAt") == 0) {
339
- xt_string *s = xt_as_string(target);
340
- if (!s) return XT_UNDEFINED;
341
- int32_t index = xt_to_int32(xt_arg_at(argc, argv, 0));
342
- if (index < 0 || (uint32_t)index >= s->length) return XT_UNDEFINED;
343
- return xt_number((double)(unsigned char)s->data[index]);
344
- }
345
- if (strcmp(method, "valueOf") == 0 || strcmp(method, "toString") == 0) return target;
346
- *handled = 0;
347
- return XT_UNDEFINED;
348
- }
349
-
350
- /* -- number methods ------------------------------------------------------- */
351
-
352
- xt_value xt_ext_number_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
353
- *handled = 1;
354
- double n = xt_to_double(target);
355
- if (strcmp(method, "toFixed") == 0) {
356
- int precision = argc >= 1 ? xt_to_int32(argv[0]) : 0;
357
- if (precision < 0) precision = 0;
358
- if (precision > 100) precision = 100;
359
- char buffer[512];
360
- snprintf(buffer, sizeof(buffer), "%.*f", precision, n);
361
- return xt_string_from_cstr(buffer);
362
- }
363
- if (strcmp(method, "toPrecision") == 0) {
364
- if (argc == 0 || argv[0] == XT_UNDEFINED) return xt_to_string(target);
365
- int precision = xt_to_int32(argv[0]);
366
- if (precision < 1) precision = 1;
367
- if (precision > 100) precision = 100;
368
- char buffer[512];
369
- snprintf(buffer, sizeof(buffer), "%.*g", precision, n);
370
- return xt_string_from_cstr(buffer);
371
- }
372
- if (strcmp(method, "toExponential") == 0) {
373
- int precision = argc >= 1 ? xt_to_int32(argv[0]) : 6;
374
- if (precision < 0) precision = 0;
375
- if (precision > 100) precision = 100;
376
- char buffer[512];
377
- snprintf(buffer, sizeof(buffer), "%.*e", precision, n);
378
- return xt_string_from_cstr(buffer);
379
- }
380
- if (strcmp(method, "toString") == 0) {
381
- int radix = argc >= 1 ? xt_to_int32(argv[0]) : 10;
382
- return xt_number_to_radix(n, radix);
383
- }
384
- if (strcmp(method, "valueOf") == 0) return target;
385
- *handled = 0;
386
- return XT_UNDEFINED;
387
- }
388
-
389
- xt_value xt_ext_object_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
390
- *handled = 1;
391
- if (strcmp(method, "hasOwnProperty") == 0) return xt_object_has_own(target, xt_arg_at(argc, argv, 0));
392
- if (strcmp(method, "toString") == 0) return xt_string_from_cstr("[object Object]");
393
- if (strcmp(method, "valueOf") == 0) return target;
394
- *handled = 0;
395
- return XT_UNDEFINED;
396
- }
397
-
398
- /* -- Object statics ------------------------------------------------------- */
399
-
400
- xt_value xt_object_static(xt_value name, int32_t argc, xt_value *argv) {
401
- const char *fn = xt_string_data(name);
402
- if (!fn) return XT_UNDEFINED;
403
- if (strcmp(fn, "keys") == 0) return xt_object_keys(xt_arg_at(argc, argv, 0));
404
- if (strcmp(fn, "values") == 0) return xt_object_values(xt_arg_at(argc, argv, 0));
405
- if (strcmp(fn, "entries") == 0) return xt_object_entries(xt_arg_at(argc, argv, 0));
406
- if (strcmp(fn, "assign") == 0) return xt_object_assign(argc, argv);
407
- if (strcmp(fn, "freeze") == 0) return xt_object_freeze(xt_arg_at(argc, argv, 0));
408
- if (strcmp(fn, "isFrozen") == 0) return xt_bool(xt_object_is_frozen(xt_arg_at(argc, argv, 0)));
409
- if (strcmp(fn, "fromEntries") == 0) return xt_object_from_entries(xt_arg_at(argc, argv, 0));
410
- if (strcmp(fn, "getPrototypeOf") == 0) return xt_object_get_prototype(xt_arg_at(argc, argv, 0));
411
- if (strcmp(fn, "setPrototypeOf") == 0) return xt_object_set_prototype(xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
412
- if (strcmp(fn, "hasOwn") == 0) return xt_object_has_own(xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
413
- if (strcmp(fn, "is") == 0) {
414
- xt_value a = xt_arg_at(argc, argv, 0);
415
- xt_value b = xt_arg_at(argc, argv, 1);
416
- if (XT_IS_NUMBER(a) && XT_IS_NUMBER(b)) {
417
- double x = xt_to_double(a), y = xt_to_double(b);
418
- if (isnan(x) && isnan(y)) return XT_TRUE;
419
- if (x == 0 && y == 0) return xt_bool(signbit(x) == signbit(y));
420
- return xt_bool(x == y);
421
- }
422
- return xt_seq(a, b);
423
- }
424
- if (strcmp(fn, "create") == 0) {
425
- xt_value proto = xt_arg_at(argc, argv, 0);
426
- return xt_object_new_with_proto(proto == XT_NULL ? XT_UNDEFINED : proto);
427
- }
428
- return XT_UNDEFINED;
429
- }
430
-
431
- /* -- Array statics -------------------------------------------------------- */
432
-
433
- xt_value xt_array_static(xt_value name, int32_t argc, xt_value *argv) {
434
- const char *fn = xt_string_data(name);
435
- if (!fn) return XT_UNDEFINED;
436
- if (strcmp(fn, "isArray") == 0) return xt_bool(XT_IS_ARRAY(xt_arg_at(argc, argv, 0)));
437
- if (strcmp(fn, "of") == 0) return xt_array_new(argc, argv);
438
- if (strcmp(fn, "from") == 0) {
439
- xt_value source = xt_arg_at(argc, argv, 0);
440
- xt_value mapper = xt_arg_at(argc, argv, 1);
441
- xt_value out = xt_array_new(0, NULL);
442
- if (XT_IS_ARRAY(source)) {
443
- xt_array *array = xt_as_array(source);
444
- for (uint32_t i = 0; i < array->length; i++) {
445
- xt_value item = array->items[i];
446
- if (XT_IS_FUNCTION(mapper)) { xt_value args[2] = {item, xt_number((double)i)}; item = xt_closure_call(mapper, 2, args); }
447
- xt_array_push(out, item);
448
- }
449
- } else if (XT_IS_STRING(source)) {
450
- xt_string *s = xt_as_string(source);
451
- for (uint32_t i = 0; i < s->length; i++) {
452
- xt_value item = xt_string_new(s->data + i, 1);
453
- if (XT_IS_FUNCTION(mapper)) { xt_value args[2] = {item, xt_number((double)i)}; item = xt_closure_call(mapper, 2, args); }
454
- xt_array_push(out, item);
455
- }
456
- } else {
457
- double length = xt_to_number(xt_get(source, xt_string_from_cstr("length")));
458
- for (int32_t i = 0; i < (int32_t)length; i++) {
459
- xt_value item = xt_get(source, xt_number((double)i));
460
- if (XT_IS_FUNCTION(mapper)) { xt_value args[2] = {item, xt_number((double)i)}; item = xt_closure_call(mapper, 2, args); }
461
- xt_array_push(out, item);
462
- }
463
- }
464
- return out;
465
- }
466
- return XT_UNDEFINED;
467
- }
468
-
469
- /* -- Number / String statics ---------------------------------------------- */
470
-
471
- xt_value xt_number_static(xt_value name, int32_t argc, xt_value *argv) {
472
- const char *fn = xt_string_data(name);
473
- if (!fn) return XT_UNDEFINED;
474
- if (strcmp(fn, "isInteger") == 0) {
475
- xt_value v = xt_arg_at(argc, argv, 0);
476
- if (!XT_IS_NUMBER(v)) return XT_FALSE;
477
- double d = xt_to_double(v);
478
- return xt_bool(isfinite(d) && floor(d) == d);
479
- }
480
- if (strcmp(fn, "isSafeInteger") == 0) {
481
- xt_value v = xt_arg_at(argc, argv, 0);
482
- if (!XT_IS_NUMBER(v)) return XT_FALSE;
483
- double d = xt_to_double(v);
484
- return xt_bool(isfinite(d) && floor(d) == d && fabs(d) <= 9007199254740991.0);
485
- }
486
- if (strcmp(fn, "isFinite") == 0) {
487
- xt_value v = xt_arg_at(argc, argv, 0);
488
- if (!XT_IS_NUMBER(v)) return XT_FALSE;
489
- return xt_bool(isfinite(xt_to_double(v)));
490
- }
491
- if (strcmp(fn, "isNaN") == 0) {
492
- xt_value v = xt_arg_at(argc, argv, 0);
493
- if (!XT_IS_NUMBER(v)) return XT_FALSE;
494
- return xt_bool(isnan(xt_to_double(v)));
495
- }
496
- if (strcmp(fn, "parseFloat") == 0) return xt_parse_float(argc, argv);
497
- if (strcmp(fn, "parseInt") == 0) return xt_parse_int(argc, argv);
498
- if (strcmp(fn, "MAX_SAFE_INTEGER") == 0) return xt_number(9007199254740991.0);
499
- if (strcmp(fn, "MIN_SAFE_INTEGER") == 0) return xt_number(-9007199254740991.0);
500
- if (strcmp(fn, "MAX_VALUE") == 0) return xt_number(1.7976931348623157e308);
501
- if (strcmp(fn, "MIN_VALUE") == 0) return xt_number(5e-324);
502
- if (strcmp(fn, "EPSILON") == 0) return xt_number(2.220446049250313e-16);
503
- if (strcmp(fn, "POSITIVE_INFINITY") == 0) return xt_number(INFINITY);
504
- if (strcmp(fn, "NEGATIVE_INFINITY") == 0) return xt_number(-INFINITY);
505
- if (strcmp(fn, "NaN") == 0) return xt_number(NAN);
506
- return XT_UNDEFINED;
507
- }
508
-
509
- xt_value xt_string_static(xt_value name, int32_t argc, xt_value *argv) {
510
- const char *fn = xt_string_data(name);
511
- if (!fn) return XT_UNDEFINED;
512
- if (strcmp(fn, "fromCharCode") == 0 || strcmp(fn, "fromCodePoint") == 0) {
513
- xt_string *out = xt_string_alloc((size_t)argc * 4 + 1);
514
- size_t length = 0;
515
- for (int32_t i = 0; i < argc; i++) {
516
- unsigned code = (unsigned)xt_to_int32(argv[i]);
517
- char buffer[4];
518
- int bytes = 0;
519
- if (code < 0x80) buffer[bytes++] = (char)code;
520
- else if (code < 0x800) { buffer[bytes++] = (char)(0xC0 | (code >> 6)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
521
- else if (code < 0x10000) { buffer[bytes++] = (char)(0xE0 | (code >> 12)); buffer[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
522
- else { buffer[bytes++] = (char)(0xF0 | (code >> 18)); buffer[bytes++] = (char)(0x80 | ((code >> 12) & 0x3F)); buffer[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
523
- memcpy(out->data + length, buffer, (size_t)bytes);
524
- length += (size_t)bytes;
525
- }
526
- out->length = (uint32_t)length;
527
- return XT_FROM_PTR(XT_TAG_STRING, out);
528
- }
529
- if (strcmp(fn, "raw") == 0) {
530
- xt_value strings = xt_arg_at(argc, argv, 0);
531
- xt_value raw = xt_object_get(strings, xt_string_from_cstr("raw"));
532
- xt_value out = xt_string_from_cstr("");
533
- double length = xt_to_number(xt_get(raw, xt_string_from_cstr("length")));
534
- for (int32_t i = 0; i < (int32_t)length; i++) {
535
- out = xt_add(out, xt_get(raw, xt_number((double)i)));
536
- if (i + 1 < (int32_t)length && i + 1 < argc) out = xt_add(out, xt_to_string(argv[i + 1]));
537
- }
538
- return out;
539
- }
540
- return XT_UNDEFINED;
541
- }
542
-
543
- /* -- JSON ----------------------------------------------------------------- */
544
-
545
- typedef struct { const char *data; size_t length; size_t pos; } xt_json_cursor;
546
-
547
- static void xt_json_skip_ws(xt_json_cursor *c) {
548
- while (c->pos < c->length) {
549
- char ch = c->data[c->pos];
550
- if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') c->pos++;
551
- else break;
552
- }
553
- }
554
-
555
- static xt_value xt_json_parse_value(xt_json_cursor *c);
556
-
557
- static xt_value xt_json_parse_string(xt_json_cursor *c) {
558
- c->pos++;
559
- size_t capacity = 32, length = 0;
560
- char *out = (char *)malloc(capacity);
561
- if (!out) abort();
562
- while (c->pos < c->length) {
563
- char ch = c->data[c->pos++];
564
- if (ch == '"') break;
565
- if (ch == '\\' && c->pos < c->length) {
566
- char esc = c->data[c->pos++];
567
- if (esc == 'n') ch = '\n';
568
- else if (esc == 't') ch = '\t';
569
- else if (esc == 'r') ch = '\r';
570
- else if (esc == 'b') ch = '\b';
571
- else if (esc == 'f') ch = '\f';
572
- else if (esc == 'u') {
573
- unsigned code = 0;
574
- for (int i = 0; i < 4 && c->pos < c->length; i++) {
575
- char h = c->data[c->pos++];
576
- code <<= 4;
577
- if (h >= '0' && h <= '9') code |= (unsigned)(h - '0');
578
- else if (h >= 'a' && h <= 'f') code |= (unsigned)(h - 'a' + 10);
579
- else if (h >= 'A' && h <= 'F') code |= (unsigned)(h - 'A' + 10);
580
- }
581
- if (code >= 0x80) {
582
- char tmp[4];
583
- int bytes = 0;
584
- if (code < 0x800) { tmp[bytes++] = (char)(0xC0 | (code >> 6)); tmp[bytes++] = (char)(0x80 | (code & 0x3F)); }
585
- else { tmp[bytes++] = (char)(0xE0 | (code >> 12)); tmp[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); tmp[bytes++] = (char)(0x80 | (code & 0x3F)); }
586
- if (length + (size_t)bytes + 1 > capacity) { capacity = (length + (size_t)bytes + 1) * 2; out = (char *)realloc(out, capacity); if (!out) abort(); }
587
- memcpy(out + length, tmp, (size_t)bytes);
588
- length += (size_t)bytes;
589
- continue;
590
- }
591
- ch = (char)code;
592
- } else ch = esc;
593
- }
594
- if (length + 2 > capacity) { capacity *= 2; out = (char *)realloc(out, capacity); if (!out) abort(); }
595
- out[length++] = ch;
596
- }
597
- xt_value result = xt_string_new(out, length);
598
- free(out);
599
- return result;
600
- }
601
-
602
- static xt_value xt_json_parse_number(xt_json_cursor *c) {
603
- size_t start = c->pos;
604
- if (c->pos < c->length && (c->data[c->pos] == '-' || c->data[c->pos] == '+')) c->pos++;
605
- while (c->pos < c->length && (isdigit((unsigned char)c->data[c->pos]) || c->data[c->pos] == '.' ||
606
- c->data[c->pos] == 'e' || c->data[c->pos] == 'E' ||
607
- c->data[c->pos] == '+' || c->data[c->pos] == '-')) c->pos++;
608
- char buffer[64];
609
- size_t n = c->pos - start;
610
- if (n >= sizeof(buffer)) n = sizeof(buffer) - 1;
611
- memcpy(buffer, c->data + start, n);
612
- buffer[n] = '\0';
613
- return xt_number(strtod(buffer, NULL));
614
- }
615
-
616
- static xt_value xt_json_parse_value(xt_json_cursor *c) {
617
- xt_json_skip_ws(c);
618
- if (c->pos >= c->length) return XT_UNDEFINED;
619
- char ch = c->data[c->pos];
620
- if (ch == '"') return xt_json_parse_string(c);
621
- if (ch == '{') {
622
- c->pos++;
623
- xt_value object = xt_object_new();
624
- xt_json_skip_ws(c);
625
- if (c->pos < c->length && c->data[c->pos] == '}') { c->pos++; return object; }
626
- for (;;) {
627
- xt_json_skip_ws(c);
628
- if (c->pos >= c->length || c->data[c->pos] != '"') break;
629
- xt_value key = xt_json_parse_string(c);
630
- xt_json_skip_ws(c);
631
- if (c->pos < c->length && c->data[c->pos] == ':') c->pos++;
632
- xt_value value = xt_json_parse_value(c);
633
- xt_object_set(object, key, value);
634
- xt_json_skip_ws(c);
635
- if (c->pos < c->length && c->data[c->pos] == ',') { c->pos++; continue; }
636
- if (c->pos < c->length && c->data[c->pos] == '}') c->pos++;
637
- break;
638
- }
639
- return object;
640
- }
641
- if (ch == '[') {
642
- c->pos++;
643
- xt_value array = xt_array_new(0, NULL);
644
- xt_json_skip_ws(c);
645
- if (c->pos < c->length && c->data[c->pos] == ']') { c->pos++; return array; }
646
- for (;;) {
647
- xt_array_push(array, xt_json_parse_value(c));
648
- xt_json_skip_ws(c);
649
- if (c->pos < c->length && c->data[c->pos] == ',') { c->pos++; continue; }
650
- if (c->pos < c->length && c->data[c->pos] == ']') c->pos++;
651
- break;
652
- }
653
- return array;
654
- }
655
- if (c->pos + 4 <= c->length && memcmp(c->data + c->pos, "true", 4) == 0) { c->pos += 4; return XT_TRUE; }
656
- if (c->pos + 5 <= c->length && memcmp(c->data + c->pos, "false", 5) == 0) { c->pos += 5; return XT_FALSE; }
657
- if (c->pos + 4 <= c->length && memcmp(c->data + c->pos, "null", 4) == 0) { c->pos += 4; return XT_NULL; }
658
- return xt_json_parse_number(c);
659
- }
660
-
661
- xt_value xt_json_parse(int32_t argc, xt_value *argv) {
662
- xt_value input = xt_to_string(xt_arg_at(argc, argv, 0));
663
- xt_string *s = xt_as_string(input);
664
- if (!s) return XT_UNDEFINED;
665
- xt_json_cursor cursor = {s->data, s->length, 0};
666
- return xt_json_parse_value(&cursor);
667
- }
668
-
669
- static void xt_json_stringify_value(xt_value value, int indent, int depth, xt_value *out);
670
-
671
- static void xt_json_indent(xt_value *out, int indent, int depth) {
672
- if (indent <= 0) return;
673
- *out = xt_add(*out, xt_string_from_cstr("\n"));
674
- for (int i = 0; i < indent * depth; i++) *out = xt_add(*out, xt_string_from_cstr(" "));
675
- }
676
-
677
- static void xt_json_stringify_array(xt_value value, int indent, int depth, xt_value *out) {
678
- xt_array *array = xt_as_array(value);
679
- if (!array || array->length == 0) { *out = xt_add(*out, xt_string_from_cstr("[]")); return; }
680
- *out = xt_add(*out, xt_string_from_cstr("["));
681
- for (uint32_t i = 0; i < array->length; i++) {
682
- if (i > 0) *out = xt_add(*out, xt_string_from_cstr(","));
683
- xt_json_indent(out, indent, depth + 1);
684
- xt_json_stringify_value(array->items[i], indent, depth + 1, out);
685
- }
686
- xt_json_indent(out, indent, depth);
687
- *out = xt_add(*out, xt_string_from_cstr("]"));
688
- }
689
-
690
- static void xt_json_stringify_object(xt_value value, int indent, int depth, xt_value *out) {
691
- xt_value keys = xt_object_keys(value);
692
- xt_array *array = xt_as_array(keys);
693
- if (!array || array->length == 0) { *out = xt_add(*out, xt_string_from_cstr("{}")); return; }
694
- *out = xt_add(*out, xt_string_from_cstr("{"));
695
- for (uint32_t i = 0; i < array->length; i++) {
696
- if (i > 0) *out = xt_add(*out, xt_string_from_cstr(","));
697
- xt_json_indent(out, indent, depth + 1);
698
- xt_value key = array->items[i];
699
- *out = xt_add(*out, xt_string_from_cstr("\""));
700
- *out = xt_add(*out, key);
701
- *out = xt_add(*out, xt_string_from_cstr("\":"));
702
- if (indent > 0) *out = xt_add(*out, xt_string_from_cstr(" "));
703
- xt_json_stringify_value(xt_object_get(value, key), indent, depth + 1, out);
704
- }
705
- xt_json_indent(out, indent, depth);
706
- *out = xt_add(*out, xt_string_from_cstr("}"));
707
- }
708
-
709
- static void xt_json_stringify_value(xt_value value, int indent, int depth, xt_value *out) {
710
- if (value == XT_UNDEFINED || value == XT_NULL || XT_IS_FUNCTION(value)) {
711
- *out = xt_add(*out, xt_string_from_cstr("null"));
712
- return;
713
- }
714
- if (XT_IS_BOOL(value)) { *out = xt_add(*out, value == XT_TRUE ? xt_string_from_cstr("true") : xt_string_from_cstr("false")); return; }
715
- if (XT_IS_NUMBER(value)) {
716
- double d = xt_to_double(value);
717
- if (!isfinite(d)) *out = xt_add(*out, xt_string_from_cstr("null"));
718
- else *out = xt_add(*out, xt_to_string(value));
719
- return;
720
- }
721
- if (XT_IS_STRING(value)) {
722
- xt_string *s = xt_as_string(value);
723
- *out = xt_add(*out, xt_string_from_cstr("\""));
724
- for (uint32_t i = 0; i < s->length; i++) {
725
- char ch = s->data[i];
726
- if (ch == '"') *out = xt_add(*out, xt_string_from_cstr("\\\""));
727
- else if (ch == '\\') *out = xt_add(*out, xt_string_from_cstr("\\\\"));
728
- else if (ch == '\n') *out = xt_add(*out, xt_string_from_cstr("\\n"));
729
- else if (ch == '\r') *out = xt_add(*out, xt_string_from_cstr("\\r"));
730
- else if (ch == '\t') *out = xt_add(*out, xt_string_from_cstr("\\t"));
731
- else *out = xt_add(*out, xt_string_new(&ch, 1));
732
- }
733
- *out = xt_add(*out, xt_string_from_cstr("\""));
734
- return;
735
- }
736
- if (XT_IS_ARRAY(value)) { xt_json_stringify_array(value, indent, depth, out); return; }
737
- if (XT_IS_OBJECT(value)) { xt_json_stringify_object(value, indent, depth, out); return; }
738
- *out = xt_add(*out, xt_string_from_cstr("null"));
739
- }
740
-
741
- xt_value xt_json_stringify(int32_t argc, xt_value *argv) {
742
- int indent = 0;
743
- xt_value space = xt_arg_at(argc, argv, 1);
744
- if (XT_IS_NUMBER(space)) indent = xt_to_int32(space);
745
- else if (XT_IS_STRING(space)) indent = (int)((xt_string *)XT_GET_PTR(space))->length;
746
- if (indent < 0) indent = 0;
747
- if (indent > 10) indent = 10;
748
- xt_value out = xt_string_from_cstr("");
749
- xt_json_stringify_value(xt_arg_at(argc, argv, 0), indent, 0, &out);
750
- return out;
751
- }
752
-
753
- /* -- Map ------------------------------------------------------------------ */
754
-
755
- int xt_is_map(xt_value value) {
756
- return XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_MAP;
757
- }
758
-
759
- int32_t xt_map_size(xt_value value) {
760
- if (!xt_is_map(value)) return 0;
761
- return (int32_t)((xt_map *)XT_GET_PTR(value))->count;
762
- }
763
-
764
- static int32_t xt_map_index(xt_map *map, xt_value key) {
765
- for (uint32_t i = 0; i < map->count; i++) if (xt_value_equals(map->keys[i], key)) return (int32_t)i;
766
- return -1;
767
- }
768
-
769
- static void xt_map_set(xt_map *map, xt_value key, xt_value value) {
770
- int32_t index = xt_map_index(map, key);
771
- if (index >= 0) { map->values[index] = value; return; }
772
- if (map->count >= map->capacity) {
773
- uint32_t capacity = map->capacity == 0 ? 8 : map->capacity * 2;
774
- map->keys = (xt_value *)realloc(map->keys, sizeof(xt_value) * capacity);
775
- map->values = (xt_value *)realloc(map->values, sizeof(xt_value) * capacity);
776
- if (!map->keys || !map->values) abort();
777
- map->capacity = capacity;
778
- }
779
- map->keys[map->count] = key;
780
- map->values[map->count] = value;
781
- map->count++;
782
- }
783
-
784
- static int xt_map_delete(xt_map *map, xt_value key) {
785
- int32_t index = xt_map_index(map, key);
786
- if (index < 0) return 0;
787
- for (uint32_t i = (uint32_t)index + 1; i < map->count; i++) {
788
- map->keys[i - 1] = map->keys[i];
789
- map->values[i - 1] = map->values[i];
790
- }
791
- map->count--;
792
- return 1;
793
- }
794
-
795
- xt_value xt_map_ctor(int32_t argc, xt_value *argv) {
796
- xt_map *map = (xt_map *)xt_alloc(sizeof(xt_map), XT_OBJECT_KIND_MAP);
797
- map->keys = NULL; map->values = NULL; map->count = 0; map->capacity = 0;
798
- xt_value iterable = xt_arg_at(argc, argv, 0);
799
- if (XT_IS_ARRAY(iterable)) {
800
- xt_array *array = xt_as_array(iterable);
801
- for (uint32_t i = 0; i < array->length; i++) {
802
- xt_array *pair = xt_as_array(array->items[i]);
803
- if (pair && pair->length >= 2) xt_map_set(map, pair->items[0], pair->items[1]);
804
- }
805
- }
806
- return XT_FROM_PTR(XT_TAG_OBJECT, map);
807
- }
808
-
809
- static xt_value xt_map_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
810
- *handled = 1;
811
- xt_map *map = (xt_map *)XT_GET_PTR(target);
812
- if (strcmp(method, "set") == 0) { xt_map_set(map, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1)); return target; }
813
- if (strcmp(method, "get") == 0) {
814
- int32_t index = xt_map_index(map, xt_arg_at(argc, argv, 0));
815
- return index >= 0 ? map->values[index] : XT_UNDEFINED;
816
- }
817
- if (strcmp(method, "has") == 0) return xt_bool(xt_map_index(map, xt_arg_at(argc, argv, 0)) >= 0);
818
- if (strcmp(method, "delete") == 0) return xt_bool(xt_map_delete(map, xt_arg_at(argc, argv, 0)));
819
- if (strcmp(method, "clear") == 0) { map->count = 0; return XT_UNDEFINED; }
820
- if (strcmp(method, "forEach") == 0) {
821
- xt_value fn = xt_arg_at(argc, argv, 0);
822
- for (uint32_t i = 0; i < map->count; i++) { xt_value args[3] = {map->values[i], map->keys[i], target}; xt_closure_call(fn, 3, args); }
823
- return XT_UNDEFINED;
824
- }
825
- if (strcmp(method, "keys") == 0) {
826
- xt_value out = xt_array_new(0, NULL);
827
- for (uint32_t i = 0; i < map->count; i++) xt_array_push(out, map->keys[i]);
828
- return out;
829
- }
830
- if (strcmp(method, "values") == 0) {
831
- xt_value out = xt_array_new(0, NULL);
832
- for (uint32_t i = 0; i < map->count; i++) xt_array_push(out, map->values[i]);
833
- return out;
834
- }
835
- if (strcmp(method, "entries") == 0) {
836
- xt_value out = xt_array_new(0, NULL);
837
- for (uint32_t i = 0; i < map->count; i++) {
838
- xt_value pair = xt_array_new(0, NULL);
839
- xt_array_push(pair, map->keys[i]);
840
- xt_array_push(pair, map->values[i]);
841
- xt_array_push(out, pair);
842
- }
843
- return out;
844
- }
845
- *handled = 0;
846
- return XT_UNDEFINED;
847
- }
848
-
849
- /* -- Set ------------------------------------------------------------------ */
850
-
851
- int xt_is_set(xt_value value) {
852
- return XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_SET;
853
- }
854
-
855
- int32_t xt_set_size(xt_value value) {
856
- if (!xt_is_set(value)) return 0;
857
- return (int32_t)((xt_set_object *)XT_GET_PTR(value))->count;
858
- }
859
-
860
- /* -- for...of iteration --------------------------------------------------- */
861
-
862
- /* `for...of` lowers to a length check plus an index lookup. Arrays and strings
863
- index directly; Maps yield `[key, value]` pairs and Sets yield their values. */
864
- xt_value xt_iter_length(xt_value value) {
865
- if (xt_is_map(value)) return xt_number((double)xt_map_size(value));
866
- if (xt_is_set(value)) return xt_number((double)xt_set_size(value));
867
- return xt_array_length(value);
868
- }
869
-
870
- xt_value xt_iter_value(xt_value value, xt_value index) {
871
- if (xt_is_map(value)) {
872
- xt_map *map = (xt_map *)XT_GET_PTR(value);
873
- int64_t i = (int64_t)xt_to_int32(index);
874
- if (i < 0 || i >= (int64_t)map->count) return XT_UNDEFINED;
875
- xt_value pair = xt_array_new(0, NULL);
876
- xt_array_push(pair, map->keys[i]);
877
- xt_array_push(pair, map->values[i]);
878
- return pair;
879
- }
880
- if (xt_is_set(value)) {
881
- xt_set_object *set = (xt_set_object *)XT_GET_PTR(value);
882
- int64_t i = (int64_t)xt_to_int32(index);
883
- if (i < 0 || i >= (int64_t)set->count) return XT_UNDEFINED;
884
- return set->values[i];
885
- }
886
- return xt_get(value, index);
887
- }
888
-
889
- static int32_t xt_set_index(xt_set_object *set, xt_value key) {
890
- for (uint32_t i = 0; i < set->count; i++) if (xt_value_equals(set->values[i], key)) return (int32_t)i;
891
- return -1;
892
- }
893
-
894
- static void xt_set_add(xt_set_object *set, xt_value value) {
895
- if (xt_set_index(set, value) >= 0) return;
896
- if (set->count >= set->capacity) {
897
- uint32_t capacity = set->capacity == 0 ? 8 : set->capacity * 2;
898
- set->values = (xt_value *)realloc(set->values, sizeof(xt_value) * capacity);
899
- if (!set->values) abort();
900
- set->capacity = capacity;
901
- }
902
- set->values[set->count++] = value;
903
- }
904
-
905
- static int xt_set_delete(xt_set_object *set, xt_value value) {
906
- int32_t index = xt_set_index(set, value);
907
- if (index < 0) return 0;
908
- for (uint32_t i = (uint32_t)index + 1; i < set->count; i++) set->values[i - 1] = set->values[i];
909
- set->count--;
910
- return 1;
911
- }
912
-
913
- xt_value xt_set_ctor(int32_t argc, xt_value *argv) {
914
- xt_set_object *set = (xt_set_object *)xt_alloc(sizeof(xt_set_object), XT_OBJECT_KIND_SET);
915
- set->values = NULL; set->count = 0; set->capacity = 0;
916
- xt_value iterable = xt_arg_at(argc, argv, 0);
917
- if (XT_IS_ARRAY(iterable)) {
918
- xt_array *array = xt_as_array(iterable);
919
- for (uint32_t i = 0; i < array->length; i++) xt_set_add(set, array->items[i]);
920
- }
921
- return XT_FROM_PTR(XT_TAG_OBJECT, set);
922
- }
923
-
924
- static xt_value xt_set_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
925
- *handled = 1;
926
- xt_set_object *set = (xt_set_object *)XT_GET_PTR(target);
927
- if (strcmp(method, "add") == 0) { xt_set_add(set, xt_arg_at(argc, argv, 0)); return target; }
928
- if (strcmp(method, "has") == 0) return xt_bool(xt_set_index(set, xt_arg_at(argc, argv, 0)) >= 0);
929
- if (strcmp(method, "delete") == 0) return xt_bool(xt_set_delete(set, xt_arg_at(argc, argv, 0)));
930
- if (strcmp(method, "clear") == 0) { set->count = 0; return XT_UNDEFINED; }
931
- if (strcmp(method, "forEach") == 0) {
932
- xt_value fn = xt_arg_at(argc, argv, 0);
933
- for (uint32_t i = 0; i < set->count; i++) { xt_value args[3] = {set->values[i], set->values[i], target}; xt_closure_call(fn, 3, args); }
934
- return XT_UNDEFINED;
935
- }
936
- if (strcmp(method, "values") == 0 || strcmp(method, "keys") == 0) {
937
- xt_value out = xt_array_new(0, NULL);
938
- for (uint32_t i = 0; i < set->count; i++) xt_array_push(out, set->values[i]);
939
- return out;
940
- }
941
- if (strcmp(method, "entries") == 0) {
942
- xt_value out = xt_array_new(0, NULL);
943
- for (uint32_t i = 0; i < set->count; i++) {
944
- xt_value pair = xt_array_new(0, NULL);
945
- xt_array_push(pair, set->values[i]);
946
- xt_array_push(pair, set->values[i]);
947
- xt_array_push(out, pair);
948
- }
949
- return out;
950
- }
951
- *handled = 0;
952
- return XT_UNDEFINED;
953
- }
954
-
955
- /* -- Date ----------------------------------------------------------------- */
956
-
957
- int xt_is_date(xt_value value) {
958
- return XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_DATE;
959
- }
960
-
961
- xt_value xt_date_ctor(int32_t argc, xt_value *argv) {
962
- xt_date *date = (xt_date *)xt_alloc(sizeof(xt_date), XT_OBJECT_KIND_DATE);
963
- if (argc == 0) date->time = (double)time(NULL) * 1000.0;
964
- else if (argc == 1) date->time = XT_IS_STRING(argv[0]) ? 0.0 : xt_to_number(argv[0]);
965
- else {
966
- struct tm tm;
967
- memset(&tm, 0, sizeof(tm));
968
- tm.tm_year = xt_to_int32(argv[0]) - 1900;
969
- tm.tm_mon = xt_to_int32(argv[1]);
970
- tm.tm_mday = argc > 2 ? xt_to_int32(argv[2]) : 1;
971
- tm.tm_hour = argc > 3 ? xt_to_int32(argv[3]) : 0;
972
- tm.tm_min = argc > 4 ? xt_to_int32(argv[4]) : 0;
973
- tm.tm_sec = argc > 5 ? xt_to_int32(argv[5]) : 0;
974
- tm.tm_isdst = -1;
975
- date->time = (double)mktime(&tm) * 1000.0;
976
- }
977
- return XT_FROM_PTR(XT_TAG_OBJECT, date);
978
- }
979
-
980
- xt_value xt_date_static(xt_value name, int32_t argc, xt_value *argv) {
981
- const char *fn = xt_string_data(name);
982
- if (!fn) return XT_UNDEFINED;
983
- if (strcmp(fn, "now") == 0) return xt_number((double)time(NULL) * 1000.0);
984
- if (strcmp(fn, "parse") == 0) return xt_number(0);
985
- if (strcmp(fn, "UTC") == 0) {
986
- struct tm tm;
987
- memset(&tm, 0, sizeof(tm));
988
- tm.tm_year = xt_to_int32(xt_arg_at(argc, argv, 0)) - 1900;
989
- tm.tm_mon = xt_to_int32(xt_arg_at(argc, argv, 1));
990
- tm.tm_mday = argc > 2 ? xt_to_int32(xt_arg_at(argc, argv, 2)) : 1;
991
- return xt_number((double)xt_timegm(&tm) * 1000.0);
992
- }
993
- return XT_UNDEFINED;
994
- }
995
-
996
- static xt_value xt_date_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
997
- *handled = 1;
998
- xt_date *date = (xt_date *)XT_GET_PTR(target);
999
- time_t seconds = (time_t)(date->time / 1000.0);
1000
- struct tm tm;
1001
- xt_gmtime_r(&seconds, &tm);
1002
- if (strcmp(method, "getTime") == 0 || strcmp(method, "valueOf") == 0) return xt_number(date->time);
1003
- const char *name = method;
1004
- char utc[32];
1005
- if (strncmp(method, "getUTC", 6) == 0) {
1006
- snprintf(utc, sizeof(utc), "get%s", method + 6);
1007
- name = utc;
1008
- }
1009
- if (strcmp(name, "getFullYear") == 0) return xt_number(tm.tm_year + 1900);
1010
- if (strcmp(name, "getMonth") == 0) return xt_number(tm.tm_mon);
1011
- if (strcmp(name, "getDate") == 0) return xt_number(tm.tm_mday);
1012
- if (strcmp(name, "getDay") == 0) return xt_number(tm.tm_wday);
1013
- if (strcmp(name, "getHours") == 0) return xt_number(tm.tm_hour);
1014
- if (strcmp(name, "getMinutes") == 0) return xt_number(tm.tm_min);
1015
- if (strcmp(name, "getSeconds") == 0) return xt_number(tm.tm_sec);
1016
- if (strcmp(name, "getMilliseconds") == 0) return xt_number(fmod(date->time, 1000.0));
1017
- if (strcmp(method, "toISOString") == 0) {
1018
- char buffer[64];
1019
- snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", tm.tm_year + 1900, tm.tm_mon + 1,
1020
- tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)fmod(date->time, 1000.0));
1021
- return xt_string_from_cstr(buffer);
1022
- }
1023
- if (strcmp(method, "toJSON") == 0 || strcmp(method, "toString") == 0) return xt_call_method(target, xt_string_from_cstr("toISOString"), 0, NULL);
1024
- *handled = 0;
1025
- return XT_UNDEFINED;
1026
- }
1027
-
1028
- /* -- RegExp (POSIX ERE subset) -------------------------------------------- */
1029
-
1030
- int xt_is_regexp(xt_value value) {
1031
- return XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_REGEXP;
1032
- }
1033
-
1034
- xt_value xt_regexp_ctor(int32_t argc, xt_value *argv) {
1035
- xt_regexp *regexp = (xt_regexp *)xt_alloc(sizeof(xt_regexp), XT_OBJECT_KIND_REGEXP);
1036
- xt_value source = xt_arg_at(argc, argv, 0);
1037
- xt_value flags = xt_arg_at(argc, argv, 1);
1038
- if (XT_IS_OBJECT(source) && ((xt_object *)XT_GET_PTR(source))->header.kind == XT_OBJECT_KIND_REGEXP) {
1039
- xt_regexp *other = (xt_regexp *)XT_GET_PTR(source);
1040
- regexp->source = other->source;
1041
- regexp->flags = flags == XT_UNDEFINED ? other->flags : xt_to_string(flags);
1042
- } else {
1043
- regexp->source = source == XT_UNDEFINED ? xt_string_from_cstr("(?:)") : xt_to_string(source);
1044
- regexp->flags = flags == XT_UNDEFINED ? xt_string_from_cstr("") : xt_to_string(flags);
1045
- }
1046
- return XT_FROM_PTR(XT_TAG_OBJECT, regexp);
1047
- }
1048
-
1049
- xt_value xt_error_ctor(int32_t argc, xt_value *argv) {
1050
- xt_value error = xt_object_new();
1051
- xt_value name = xt_arg_at(argc, argv, 1);
1052
- xt_value message = xt_arg_at(argc, argv, 0);
1053
- xt_object_set(error, xt_string_from_cstr("name"),
1054
- name == XT_UNDEFINED ? xt_string_from_cstr("Error") : name);
1055
- xt_object_set(error, xt_string_from_cstr("message"),
1056
- message == XT_UNDEFINED ? xt_string_from_cstr("") : message);
1057
- return error;
1058
- }
1059
-
1060
- /* `super(message)` inside a subclass of the builtin `Error`: initialize the
1061
- * already-allocated instance instead of creating a fresh object. */
1062
- xt_value xt_error_init(xt_value thisValue, int32_t argc, xt_value *argv) {
1063
- xt_value name = xt_arg_at(argc, argv, 1);
1064
- xt_value message = xt_arg_at(argc, argv, 0);
1065
- xt_object_set(thisValue, xt_string_from_cstr("name"),
1066
- name == XT_UNDEFINED ? xt_string_from_cstr("Error") : name);
1067
- xt_object_set(thisValue, xt_string_from_cstr("message"),
1068
- message == XT_UNDEFINED ? xt_string_from_cstr("") : message);
1069
- return thisValue;
1070
- }
1071
-
1072
- /* Compile `regexp` and search `input` starting at byte offset `start`.
1073
- * Returns 1 and fills `matchStart`/`matchEnd` (absolute offsets into `input`)
1074
- * when a match is found, otherwise 0. */
1075
-
1076
- static int xt_regex_hex_digit(char c) {
1077
- if (c >= '0' && c <= '9') return c - '0';
1078
- if (c >= 'a' && c <= 'f') return c - 'a' + 10;
1079
- if (c >= 'A' && c <= 'F') return c - 'A' + 10;
1080
- return -1;
1081
- }
1082
-
1083
- /* JavaScript regexes use escapes POSIX ERE does not understand (`\r`, `\n`,
1084
- * `\d`, `\w`, `\s`, `(?:...)`, ...). Rewrite the common ones into their POSIX
1085
- * equivalents before handing the pattern to the engine. Returns a malloc'd,
1086
- * NUL-terminated string the caller must free. */
1087
- static char *xt_regexp_translate_js(const char *pattern) {
1088
- size_t length = strlen(pattern);
1089
- size_t capacity = length * 16 + 16;
1090
- char *out = (char *)malloc(capacity);
1091
- if (!out) abort();
1092
- size_t written = 0;
1093
- for (size_t i = 0; i < length; i++) {
1094
- char c = pattern[i];
1095
- const char *replacement = NULL;
1096
- char literal = 0;
1097
- int consume = 0;
1098
- if (c == '\\') {
1099
- char next = (i + 1 < length) ? pattern[i + 1] : '\0';
1100
- switch (next) {
1101
- case 'r': literal = '\r'; consume = 1; break;
1102
- case 'n': literal = '\n'; consume = 1; break;
1103
- case 't': literal = '\t'; consume = 1; break;
1104
- case 'f': literal = '\f'; consume = 1; break;
1105
- case 'v': literal = '\v'; consume = 1; break;
1106
- case 'd': replacement = "[0-9]"; consume = 1; break;
1107
- case 'D': replacement = "[^0-9]"; consume = 1; break;
1108
- case 'w': replacement = "[A-Za-z0-9_]"; consume = 1; break;
1109
- case 'W': replacement = "[^A-Za-z0-9_]"; consume = 1; break;
1110
- case 's': replacement = "[ \t\n\r\f\v]"; consume = 1; break;
1111
- case 'S': replacement = "[^ \t\n\r\f\v]"; consume = 1; break;
1112
- case 'x': {
1113
- int hi = (i + 2 < length) ? xt_regex_hex_digit(pattern[i + 2]) : -1;
1114
- int lo = (i + 3 < length) ? xt_regex_hex_digit(pattern[i + 3]) : -1;
1115
- if (hi >= 0 && lo >= 0) { literal = (char)(hi * 16 + lo); consume = 3; }
1116
- break;
1117
- }
1118
- default: break;
1119
- }
1120
- } else if (c == '(' && i + 2 < length && pattern[i + 1] == '?' && pattern[i + 2] == ':') {
1121
- /* POSIX ERE has no non-capturing groups; a capturing group matches the
1122
- * same text, only the capture bookkeeping differs. */
1123
- literal = '(';
1124
- consume = 2;
1125
- }
1126
- if (replacement) {
1127
- size_t addition = strlen(replacement);
1128
- if (written + addition + 1 > capacity) { capacity = (written + addition) * 2 + 16; out = (char *)realloc(out, capacity); if (!out) abort(); }
1129
- memcpy(out + written, replacement, addition);
1130
- written += addition;
1131
- } else if (consume || literal) {
1132
- if (written + 2 > capacity) { capacity = capacity * 2 + 16; out = (char *)realloc(out, capacity); if (!out) abort(); }
1133
- out[written++] = literal;
1134
- } else {
1135
- if (written + 2 > capacity) { capacity = capacity * 2 + 16; out = (char *)realloc(out, capacity); if (!out) abort(); }
1136
- out[written++] = c;
1137
- }
1138
- i += (size_t)consume;
1139
- }
1140
- out[written] = '\0';
1141
- return out;
1142
- }
1143
-
1144
- int xt_regexp_find(xt_value regexpValue, xt_value input, int32_t start, int32_t *matchStart, int32_t *matchEnd) {
1145
- xt_regexp *regexp = (xt_regexp *)XT_GET_PTR(regexpValue);
1146
- xt_string *pattern = xt_as_string(regexp->source);
1147
- xt_string *text = xt_as_string(xt_to_string(input));
1148
- if (!pattern || !text) return 0;
1149
- if (start < 0) start = 0;
1150
- if ((uint32_t)start > text->length) return 0;
1151
- int flags = REG_EXTENDED;
1152
- xt_string *f = xt_as_string(regexp->flags);
1153
- if (f) for (uint32_t i = 0; i < f->length; i++) if (f->data[i] == 'i') flags |= REG_ICASE;
1154
- char *translated = xt_regexp_translate_js(pattern->data);
1155
- if (!translated) return 0;
1156
- regex_t compiled;
1157
- if (regcomp(&compiled, translated, flags) != 0) {
1158
- free(translated);
1159
- return 0;
1160
- }
1161
- free(translated);
1162
- regmatch_t match;
1163
- match.rm_so = 0;
1164
- match.rm_eo = 0;
1165
- int ok = regexec(&compiled, text->data + start, 1, &match, 0) == 0;
1166
- regfree(&compiled);
1167
- if (!ok) return 0;
1168
- if (matchStart) *matchStart = start + (int32_t)match.rm_so;
1169
- if (matchEnd) *matchEnd = start + (int32_t)match.rm_eo;
1170
- return 1;
1171
- }
1172
-
1173
- static int xt_regexp_is_global(xt_value regexpValue) {
1174
- xt_regexp *regexp = (xt_regexp *)XT_GET_PTR(regexpValue);
1175
- xt_string *f = xt_as_string(regexp->flags);
1176
- if (!f) return 0;
1177
- for (uint32_t i = 0; i < f->length; i++) if (f->data[i] == 'g') return 1;
1178
- return 0;
1179
- }
1180
-
1181
- static xt_value xt_regexp_test(xt_value target, xt_value input) {
1182
- return xt_bool(xt_regexp_find(target, input, 0, NULL, NULL));
1183
- }
1184
-
1185
- /* JavaScript-style match object: `[0]` is the matched text, `index` is the
1186
- * match offset and `input` is the searched string. */
1187
- xt_value xt_regexp_exec(xt_value target, xt_value input) {
1188
- int32_t start = 0;
1189
- int32_t end = 0;
1190
- if (!xt_regexp_find(target, input, 0, &start, &end)) return XT_NULL;
1191
- xt_value textValue = xt_to_string(input);
1192
- xt_string *text = xt_as_string(textValue);
1193
- xt_value out = xt_object_new();
1194
- xt_object_set(out, xt_string_from_cstr("0"), xt_string_new(text->data + start, (int64_t)(end - start)));
1195
- xt_object_set(out, xt_string_from_cstr("index"), xt_number((double)start));
1196
- xt_object_set(out, xt_string_from_cstr("input"), textValue);
1197
- xt_object_set(out, xt_string_from_cstr("length"), xt_number(1));
1198
- return out;
1199
- }
1200
-
1201
- /* `String.prototype.replace`/`replaceAll` with a RegExp search value. */
1202
- xt_value xt_regexp_replace(xt_value value, xt_value regexpValue, xt_value replacementValue) {
1203
- xt_string *text = xt_as_string(xt_to_string(value));
1204
- if (!text) return value;
1205
- xt_string *replacement = xt_as_string(xt_to_string(replacementValue));
1206
- if (!replacement) return value;
1207
- int global = xt_regexp_is_global(regexpValue);
1208
- size_t capacity = text->length + replacement->length + 16;
1209
- char *out = (char *)malloc(capacity);
1210
- if (!out) abort();
1211
- size_t length = 0;
1212
- int32_t cursor = 0;
1213
- int replaced = 0;
1214
- for (;;) {
1215
- int32_t start = 0;
1216
- int32_t end = 0;
1217
- if (!xt_regexp_find(regexpValue, value, cursor, &start, &end)) break;
1218
- size_t prefix = (size_t)(start - cursor);
1219
- size_t needed = length + prefix + replacement->length + 2;
1220
- if (needed > capacity) {
1221
- capacity = needed * 2;
1222
- out = (char *)realloc(out, capacity);
1223
- if (!out) abort();
1224
- }
1225
- memcpy(out + length, text->data + cursor, prefix);
1226
- length += prefix;
1227
- memcpy(out + length, replacement->data, replacement->length);
1228
- length += replacement->length;
1229
- replaced = 1;
1230
- if (end > start) {
1231
- cursor = end;
1232
- } else {
1233
- /* Zero-width match: copy one byte so the scan always progresses. */
1234
- if (cursor >= (int32_t)text->length) break;
1235
- out[length++] = text->data[cursor++];
1236
- }
1237
- if (!global) break;
1238
- }
1239
- if (!replaced) {
1240
- free(out);
1241
- return value;
1242
- }
1243
- size_t tail = text->length - (size_t)cursor;
1244
- if (length + tail + 1 > capacity) {
1245
- capacity = length + tail + 1;
1246
- out = (char *)realloc(out, capacity);
1247
- if (!out) abort();
1248
- }
1249
- memcpy(out + length, text->data + cursor, tail);
1250
- length += tail;
1251
- xt_value result = xt_string_new(out, (int64_t)length);
1252
- free(out);
1253
- return result;
1254
- }
1255
-
1256
- /* Property access (`re.source`, `re.flags`, `re.global`, ...). */
1257
- xt_value xt_regexp_get_property(xt_value target, xt_value key) {
1258
- xt_regexp *regexp = (xt_regexp *)XT_GET_PTR(target);
1259
- if (!XT_IS_STRING(key)) return XT_UNDEFINED;
1260
- xt_string *k = xt_as_string(key);
1261
- xt_string *f = xt_as_string(regexp->flags);
1262
- int flag = 0;
1263
- if (k->length == 6 && memcmp(k->data, "source", 6) == 0) return regexp->source;
1264
- if (k->length == 5 && memcmp(k->data, "flags", 5) == 0) return regexp->flags;
1265
- if (k->length == 9 && memcmp(k->data, "lastIndex", 9) == 0) return xt_number(0);
1266
- if (k->length == 6 && memcmp(k->data, "global", 6) == 0) flag = 'g';
1267
- else if (k->length == 10 && memcmp(k->data, "ignoreCase", 10) == 0) flag = 'i';
1268
- else if (k->length == 9 && memcmp(k->data, "multiline", 9) == 0) flag = 'm';
1269
- else if (k->length == 6 && memcmp(k->data, "sticky", 6) == 0) flag = 'y';
1270
- if (flag) {
1271
- if (f) for (uint32_t i = 0; i < f->length; i++) if (f->data[i] == flag) return XT_TRUE;
1272
- return XT_FALSE;
1273
- }
1274
- return XT_UNDEFINED;
1275
- }
1276
-
1277
- xt_value xt_ext_container_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
1278
- xt_object *obj = (xt_object *)XT_GET_PTR(target);
1279
- if (obj->header.kind == XT_OBJECT_KIND_MAP) return xt_map_method(target, method, argc, argv, handled);
1280
- if (obj->header.kind == XT_OBJECT_KIND_SET) return xt_set_method(target, method, argc, argv, handled);
1281
- if (obj->header.kind == XT_OBJECT_KIND_DATE) return xt_date_method(target, method, argc, argv, handled);
1282
- if (obj->header.kind == XT_OBJECT_KIND_REGEXP) {
1283
- xt_regexp *regexp = (xt_regexp *)obj;
1284
- *handled = 1;
1285
- if (strcmp(method, "test") == 0) return xt_regexp_test(target, xt_arg_at(argc, argv, 0));
1286
- if (strcmp(method, "exec") == 0) return xt_regexp_exec(target, xt_arg_at(argc, argv, 0));
1287
- if (strcmp(method, "toString") == 0) {
1288
- xt_value out = xt_string_from_cstr("/");
1289
- out = xt_add(out, regexp->source);
1290
- out = xt_add(out, xt_string_from_cstr("/"));
1291
- out = xt_add(out, regexp->flags);
1292
- return out;
1293
- }
1294
- *handled = 0;
1295
- return XT_UNDEFINED;
1296
- }
1297
- *handled = 0;
1298
- return XT_UNDEFINED;
1299
- }
26
+ #include "xt_stdlib2/helpers.inc"
27
+ #include "xt_stdlib2/arrays.inc"
28
+ #include "xt_stdlib2/strings.inc"
29
+ #include "xt_stdlib2/numbers.inc"
30
+ #include "xt_stdlib2/objects.inc"
31
+ #include "xt_stdlib2/array-statics.inc"
32
+ #include "xt_stdlib2/number-string-statics.inc"
33
+ #include "xt_stdlib2/json.inc"
34
+ #include "xt_stdlib2/map.inc"
35
+ #include "xt_stdlib2/set.inc"
36
+ #include "xt_stdlib2/date.inc"
37
+ #include "xt_stdlib2/regexp.inc"
38
+ #include "xt_stdlib2/error.inc"
39
+ #include "xt_stdlib2/regexp-match.inc"
40
+ #include "xt_stdlib2/container.inc"