xbintsc 0.2.9 → 0.3.3

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
@@ -0,0 +1,73 @@
1
+ /* -- Number / String statics ---------------------------------------------- */
2
+
3
+ xt_value xt_number_static(xt_value name, int32_t argc, xt_value *argv) {
4
+ const char *fn = xt_string_data(name);
5
+ if (!fn) return XT_UNDEFINED;
6
+ if (strcmp(fn, "isInteger") == 0) {
7
+ xt_value v = xt_arg_at(argc, argv, 0);
8
+ if (!XT_IS_NUMBER(v)) return XT_FALSE;
9
+ double d = xt_to_double(v);
10
+ return xt_bool(isfinite(d) && floor(d) == d);
11
+ }
12
+ if (strcmp(fn, "isSafeInteger") == 0) {
13
+ xt_value v = xt_arg_at(argc, argv, 0);
14
+ if (!XT_IS_NUMBER(v)) return XT_FALSE;
15
+ double d = xt_to_double(v);
16
+ return xt_bool(isfinite(d) && floor(d) == d && fabs(d) <= 9007199254740991.0);
17
+ }
18
+ if (strcmp(fn, "isFinite") == 0) {
19
+ xt_value v = xt_arg_at(argc, argv, 0);
20
+ if (!XT_IS_NUMBER(v)) return XT_FALSE;
21
+ return xt_bool(isfinite(xt_to_double(v)));
22
+ }
23
+ if (strcmp(fn, "isNaN") == 0) {
24
+ xt_value v = xt_arg_at(argc, argv, 0);
25
+ if (!XT_IS_NUMBER(v)) return XT_FALSE;
26
+ return xt_bool(isnan(xt_to_double(v)));
27
+ }
28
+ if (strcmp(fn, "parseFloat") == 0) return xt_parse_float(argc, argv);
29
+ if (strcmp(fn, "parseInt") == 0) return xt_parse_int(argc, argv);
30
+ if (strcmp(fn, "MAX_SAFE_INTEGER") == 0) return xt_number(9007199254740991.0);
31
+ if (strcmp(fn, "MIN_SAFE_INTEGER") == 0) return xt_number(-9007199254740991.0);
32
+ if (strcmp(fn, "MAX_VALUE") == 0) return xt_number(1.7976931348623157e308);
33
+ if (strcmp(fn, "MIN_VALUE") == 0) return xt_number(5e-324);
34
+ if (strcmp(fn, "EPSILON") == 0) return xt_number(2.220446049250313e-16);
35
+ if (strcmp(fn, "POSITIVE_INFINITY") == 0) return xt_number(INFINITY);
36
+ if (strcmp(fn, "NEGATIVE_INFINITY") == 0) return xt_number(-INFINITY);
37
+ if (strcmp(fn, "NaN") == 0) return xt_number(NAN);
38
+ return XT_UNDEFINED;
39
+ }
40
+
41
+ xt_value xt_string_static(xt_value name, int32_t argc, xt_value *argv) {
42
+ const char *fn = xt_string_data(name);
43
+ if (!fn) return XT_UNDEFINED;
44
+ if (strcmp(fn, "fromCharCode") == 0 || strcmp(fn, "fromCodePoint") == 0) {
45
+ xt_string *out = xt_string_alloc((size_t)argc * 4 + 1);
46
+ size_t length = 0;
47
+ for (int32_t i = 0; i < argc; i++) {
48
+ unsigned code = (unsigned)xt_to_int32(argv[i]);
49
+ char buffer[4];
50
+ int bytes = 0;
51
+ if (code < 0x80) buffer[bytes++] = (char)code;
52
+ else if (code < 0x800) { buffer[bytes++] = (char)(0xC0 | (code >> 6)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
53
+ else if (code < 0x10000) { buffer[bytes++] = (char)(0xE0 | (code >> 12)); buffer[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
54
+ 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)); }
55
+ memcpy(out->data + length, buffer, (size_t)bytes);
56
+ length += (size_t)bytes;
57
+ }
58
+ out->length = (uint32_t)length;
59
+ return XT_FROM_PTR(XT_TAG_STRING, out);
60
+ }
61
+ if (strcmp(fn, "raw") == 0) {
62
+ xt_value strings = xt_arg_at(argc, argv, 0);
63
+ xt_value raw = xt_object_get(strings, xt_string_from_cstr("raw"));
64
+ xt_value out = xt_string_from_cstr("");
65
+ double length = xt_to_number(xt_get(raw, xt_string_from_cstr("length")));
66
+ for (int32_t i = 0; i < (int32_t)length; i++) {
67
+ out = xt_add(out, xt_get(raw, xt_number((double)i)));
68
+ if (i + 1 < (int32_t)length && i + 1 < argc) out = xt_add(out, xt_to_string(argv[i + 1]));
69
+ }
70
+ return out;
71
+ }
72
+ return XT_UNDEFINED;
73
+ }
@@ -0,0 +1,38 @@
1
+ /* -- number methods ------------------------------------------------------- */
2
+
3
+ xt_value xt_ext_number_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
4
+ *handled = 1;
5
+ double n = xt_to_double(target);
6
+ if (strcmp(method, "toFixed") == 0) {
7
+ int precision = argc >= 1 ? xt_to_int32(argv[0]) : 0;
8
+ if (precision < 0) precision = 0;
9
+ if (precision > 100) precision = 100;
10
+ char buffer[512];
11
+ snprintf(buffer, sizeof(buffer), "%.*f", precision, n);
12
+ return xt_string_from_cstr(buffer);
13
+ }
14
+ if (strcmp(method, "toPrecision") == 0) {
15
+ if (argc == 0 || argv[0] == XT_UNDEFINED) return xt_to_string(target);
16
+ int precision = xt_to_int32(argv[0]);
17
+ if (precision < 1) precision = 1;
18
+ if (precision > 100) precision = 100;
19
+ char buffer[512];
20
+ snprintf(buffer, sizeof(buffer), "%.*g", precision, n);
21
+ return xt_string_from_cstr(buffer);
22
+ }
23
+ if (strcmp(method, "toExponential") == 0) {
24
+ int precision = argc >= 1 ? xt_to_int32(argv[0]) : 6;
25
+ if (precision < 0) precision = 0;
26
+ if (precision > 100) precision = 100;
27
+ char buffer[512];
28
+ snprintf(buffer, sizeof(buffer), "%.*e", precision, n);
29
+ return xt_string_from_cstr(buffer);
30
+ }
31
+ if (strcmp(method, "toString") == 0) {
32
+ int radix = argc >= 1 ? xt_to_int32(argv[0]) : 10;
33
+ return xt_number_to_radix(n, radix);
34
+ }
35
+ if (strcmp(method, "valueOf") == 0) return target;
36
+ *handled = 0;
37
+ return XT_UNDEFINED;
38
+ }
@@ -0,0 +1,41 @@
1
+ xt_value xt_ext_object_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
2
+ *handled = 1;
3
+ if (strcmp(method, "hasOwnProperty") == 0) return xt_object_has_own(target, xt_arg_at(argc, argv, 0));
4
+ if (strcmp(method, "toString") == 0) return xt_string_from_cstr("[object Object]");
5
+ if (strcmp(method, "valueOf") == 0) return target;
6
+ *handled = 0;
7
+ return XT_UNDEFINED;
8
+ }
9
+
10
+ /* -- Object statics ------------------------------------------------------- */
11
+
12
+ xt_value xt_object_static(xt_value name, int32_t argc, xt_value *argv) {
13
+ const char *fn = xt_string_data(name);
14
+ if (!fn) return XT_UNDEFINED;
15
+ if (strcmp(fn, "keys") == 0) return xt_object_keys(xt_arg_at(argc, argv, 0));
16
+ if (strcmp(fn, "values") == 0) return xt_object_values(xt_arg_at(argc, argv, 0));
17
+ if (strcmp(fn, "entries") == 0) return xt_object_entries(xt_arg_at(argc, argv, 0));
18
+ if (strcmp(fn, "assign") == 0) return xt_object_assign(argc, argv);
19
+ if (strcmp(fn, "freeze") == 0) return xt_object_freeze(xt_arg_at(argc, argv, 0));
20
+ if (strcmp(fn, "isFrozen") == 0) return xt_bool(xt_object_is_frozen(xt_arg_at(argc, argv, 0)));
21
+ if (strcmp(fn, "fromEntries") == 0) return xt_object_from_entries(xt_arg_at(argc, argv, 0));
22
+ if (strcmp(fn, "getPrototypeOf") == 0) return xt_object_get_prototype(xt_arg_at(argc, argv, 0));
23
+ if (strcmp(fn, "setPrototypeOf") == 0) return xt_object_set_prototype(xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
24
+ if (strcmp(fn, "hasOwn") == 0) return xt_object_has_own(xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
25
+ if (strcmp(fn, "is") == 0) {
26
+ xt_value a = xt_arg_at(argc, argv, 0);
27
+ xt_value b = xt_arg_at(argc, argv, 1);
28
+ if (XT_IS_NUMBER(a) && XT_IS_NUMBER(b)) {
29
+ double x = xt_to_double(a), y = xt_to_double(b);
30
+ if (isnan(x) && isnan(y)) return XT_TRUE;
31
+ if (x == 0 && y == 0) return xt_bool(signbit(x) == signbit(y));
32
+ return xt_bool(x == y);
33
+ }
34
+ return xt_seq(a, b);
35
+ }
36
+ if (strcmp(fn, "create") == 0) {
37
+ xt_value proto = xt_arg_at(argc, argv, 0);
38
+ return xt_object_new_with_proto(proto == XT_NULL ? XT_UNDEFINED : proto);
39
+ }
40
+ return XT_UNDEFINED;
41
+ }
@@ -0,0 +1,204 @@
1
+ /* Compile `regexp` and search `input` starting at byte offset `start`.
2
+ * Returns 1 and fills `matchStart`/`matchEnd` (absolute offsets into `input`)
3
+ * when a match is found, otherwise 0. */
4
+
5
+ static int xt_regex_hex_digit(char c) {
6
+ if (c >= '0' && c <= '9') return c - '0';
7
+ if (c >= 'a' && c <= 'f') return c - 'a' + 10;
8
+ if (c >= 'A' && c <= 'F') return c - 'A' + 10;
9
+ return -1;
10
+ }
11
+
12
+ /* JavaScript regexes use escapes POSIX ERE does not understand (`\r`, `\n`,
13
+ * `\d`, `\w`, `\s`, `(?:...)`, ...). Rewrite the common ones into their POSIX
14
+ * equivalents before handing the pattern to the engine. Returns a malloc'd,
15
+ * NUL-terminated string the caller must free. */
16
+ static char *xt_regexp_translate_js(const char *pattern) {
17
+ size_t length = strlen(pattern);
18
+ size_t capacity = length * 16 + 16;
19
+ char *out = (char *)malloc(capacity);
20
+ if (!out) abort();
21
+ size_t written = 0;
22
+ for (size_t i = 0; i < length; i++) {
23
+ char c = pattern[i];
24
+ const char *replacement = NULL;
25
+ char literal = 0;
26
+ int consume = 0;
27
+ if (c == '\\') {
28
+ char next = (i + 1 < length) ? pattern[i + 1] : '\0';
29
+ switch (next) {
30
+ case 'r': literal = '\r'; consume = 1; break;
31
+ case 'n': literal = '\n'; consume = 1; break;
32
+ case 't': literal = '\t'; consume = 1; break;
33
+ case 'f': literal = '\f'; consume = 1; break;
34
+ case 'v': literal = '\v'; consume = 1; break;
35
+ case 'd': replacement = "[0-9]"; consume = 1; break;
36
+ case 'D': replacement = "[^0-9]"; consume = 1; break;
37
+ case 'w': replacement = "[A-Za-z0-9_]"; consume = 1; break;
38
+ case 'W': replacement = "[^A-Za-z0-9_]"; consume = 1; break;
39
+ case 's': replacement = "[ \t\n\r\f\v]"; consume = 1; break;
40
+ case 'S': replacement = "[^ \t\n\r\f\v]"; consume = 1; break;
41
+ case 'x': {
42
+ int hi = (i + 2 < length) ? xt_regex_hex_digit(pattern[i + 2]) : -1;
43
+ int lo = (i + 3 < length) ? xt_regex_hex_digit(pattern[i + 3]) : -1;
44
+ if (hi >= 0 && lo >= 0) { literal = (char)(hi * 16 + lo); consume = 3; }
45
+ break;
46
+ }
47
+ default: break;
48
+ }
49
+ } else if (c == '(' && i + 2 < length && pattern[i + 1] == '?' && pattern[i + 2] == ':') {
50
+ /* POSIX ERE has no non-capturing groups; a capturing group matches the
51
+ * same text, only the capture bookkeeping differs. */
52
+ literal = '(';
53
+ consume = 2;
54
+ }
55
+ if (replacement) {
56
+ size_t addition = strlen(replacement);
57
+ if (written + addition + 1 > capacity) { capacity = (written + addition) * 2 + 16; out = (char *)realloc(out, capacity); if (!out) abort(); }
58
+ memcpy(out + written, replacement, addition);
59
+ written += addition;
60
+ } else if (consume || literal) {
61
+ if (written + 2 > capacity) { capacity = capacity * 2 + 16; out = (char *)realloc(out, capacity); if (!out) abort(); }
62
+ out[written++] = literal;
63
+ } else {
64
+ if (written + 2 > capacity) { capacity = capacity * 2 + 16; out = (char *)realloc(out, capacity); if (!out) abort(); }
65
+ out[written++] = c;
66
+ }
67
+ i += (size_t)consume;
68
+ }
69
+ out[written] = '\0';
70
+ return out;
71
+ }
72
+
73
+ int xt_regexp_find(xt_value regexpValue, xt_value input, int32_t start, int32_t *matchStart, int32_t *matchEnd) {
74
+ xt_regexp *regexp = (xt_regexp *)XT_GET_PTR(regexpValue);
75
+ xt_string *pattern = xt_as_string(regexp->source);
76
+ xt_string *text = xt_as_string(xt_to_string(input));
77
+ if (!pattern || !text) return 0;
78
+ if (start < 0) start = 0;
79
+ if ((uint32_t)start > text->length) return 0;
80
+ int flags = REG_EXTENDED;
81
+ xt_string *f = xt_as_string(regexp->flags);
82
+ if (f) for (uint32_t i = 0; i < f->length; i++) if (f->data[i] == 'i') flags |= REG_ICASE;
83
+ char *translated = xt_regexp_translate_js(pattern->data);
84
+ if (!translated) return 0;
85
+ regex_t compiled;
86
+ if (regcomp(&compiled, translated, flags) != 0) {
87
+ free(translated);
88
+ return 0;
89
+ }
90
+ free(translated);
91
+ regmatch_t match;
92
+ match.rm_so = 0;
93
+ match.rm_eo = 0;
94
+ int ok = regexec(&compiled, text->data + start, 1, &match, 0) == 0;
95
+ regfree(&compiled);
96
+ if (!ok) return 0;
97
+ if (matchStart) *matchStart = start + (int32_t)match.rm_so;
98
+ if (matchEnd) *matchEnd = start + (int32_t)match.rm_eo;
99
+ return 1;
100
+ }
101
+
102
+ static int xt_regexp_is_global(xt_value regexpValue) {
103
+ xt_regexp *regexp = (xt_regexp *)XT_GET_PTR(regexpValue);
104
+ xt_string *f = xt_as_string(regexp->flags);
105
+ if (!f) return 0;
106
+ for (uint32_t i = 0; i < f->length; i++) if (f->data[i] == 'g') return 1;
107
+ return 0;
108
+ }
109
+
110
+ static xt_value xt_regexp_test(xt_value target, xt_value input) {
111
+ return xt_bool(xt_regexp_find(target, input, 0, NULL, NULL));
112
+ }
113
+
114
+ /* JavaScript-style match object: `[0]` is the matched text, `index` is the
115
+ * match offset and `input` is the searched string. */
116
+ xt_value xt_regexp_exec(xt_value target, xt_value input) {
117
+ int32_t start = 0;
118
+ int32_t end = 0;
119
+ if (!xt_regexp_find(target, input, 0, &start, &end)) return XT_NULL;
120
+ xt_value textValue = xt_to_string(input);
121
+ xt_string *text = xt_as_string(textValue);
122
+ xt_value out = xt_object_new();
123
+ xt_object_set(out, xt_string_from_cstr("0"), xt_string_new(text->data + start, (int64_t)(end - start)));
124
+ xt_object_set(out, xt_string_from_cstr("index"), xt_number((double)start));
125
+ xt_object_set(out, xt_string_from_cstr("input"), textValue);
126
+ xt_object_set(out, xt_string_from_cstr("length"), xt_number(1));
127
+ return out;
128
+ }
129
+
130
+ /* `String.prototype.replace`/`replaceAll` with a RegExp search value. */
131
+ xt_value xt_regexp_replace(xt_value value, xt_value regexpValue, xt_value replacementValue) {
132
+ xt_string *text = xt_as_string(xt_to_string(value));
133
+ if (!text) return value;
134
+ xt_string *replacement = xt_as_string(xt_to_string(replacementValue));
135
+ if (!replacement) return value;
136
+ int global = xt_regexp_is_global(regexpValue);
137
+ size_t capacity = text->length + replacement->length + 16;
138
+ char *out = (char *)malloc(capacity);
139
+ if (!out) abort();
140
+ size_t length = 0;
141
+ int32_t cursor = 0;
142
+ int replaced = 0;
143
+ for (;;) {
144
+ int32_t start = 0;
145
+ int32_t end = 0;
146
+ if (!xt_regexp_find(regexpValue, value, cursor, &start, &end)) break;
147
+ size_t prefix = (size_t)(start - cursor);
148
+ size_t needed = length + prefix + replacement->length + 2;
149
+ if (needed > capacity) {
150
+ capacity = needed * 2;
151
+ out = (char *)realloc(out, capacity);
152
+ if (!out) abort();
153
+ }
154
+ memcpy(out + length, text->data + cursor, prefix);
155
+ length += prefix;
156
+ memcpy(out + length, replacement->data, replacement->length);
157
+ length += replacement->length;
158
+ replaced = 1;
159
+ if (end > start) {
160
+ cursor = end;
161
+ } else {
162
+ /* Zero-width match: copy one byte so the scan always progresses. */
163
+ if (cursor >= (int32_t)text->length) break;
164
+ out[length++] = text->data[cursor++];
165
+ }
166
+ if (!global) break;
167
+ }
168
+ if (!replaced) {
169
+ free(out);
170
+ return value;
171
+ }
172
+ size_t tail = text->length - (size_t)cursor;
173
+ if (length + tail + 1 > capacity) {
174
+ capacity = length + tail + 1;
175
+ out = (char *)realloc(out, capacity);
176
+ if (!out) abort();
177
+ }
178
+ memcpy(out + length, text->data + cursor, tail);
179
+ length += tail;
180
+ xt_value result = xt_string_new(out, (int64_t)length);
181
+ free(out);
182
+ return result;
183
+ }
184
+
185
+ /* Property access (`re.source`, `re.flags`, `re.global`, ...). */
186
+ xt_value xt_regexp_get_property(xt_value target, xt_value key) {
187
+ xt_regexp *regexp = (xt_regexp *)XT_GET_PTR(target);
188
+ if (!XT_IS_STRING(key)) return XT_UNDEFINED;
189
+ xt_string *k = xt_as_string(key);
190
+ xt_string *f = xt_as_string(regexp->flags);
191
+ int flag = 0;
192
+ if (k->length == 6 && memcmp(k->data, "source", 6) == 0) return regexp->source;
193
+ if (k->length == 5 && memcmp(k->data, "flags", 5) == 0) return regexp->flags;
194
+ if (k->length == 9 && memcmp(k->data, "lastIndex", 9) == 0) return xt_number(0);
195
+ if (k->length == 6 && memcmp(k->data, "global", 6) == 0) flag = 'g';
196
+ else if (k->length == 10 && memcmp(k->data, "ignoreCase", 10) == 0) flag = 'i';
197
+ else if (k->length == 9 && memcmp(k->data, "multiline", 9) == 0) flag = 'm';
198
+ else if (k->length == 6 && memcmp(k->data, "sticky", 6) == 0) flag = 'y';
199
+ if (flag) {
200
+ if (f) for (uint32_t i = 0; i < f->length; i++) if (f->data[i] == flag) return XT_TRUE;
201
+ return XT_FALSE;
202
+ }
203
+ return XT_UNDEFINED;
204
+ }
@@ -0,0 +1,20 @@
1
+ /* -- RegExp (POSIX ERE subset) -------------------------------------------- */
2
+
3
+ int xt_is_regexp(xt_value value) {
4
+ return XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_REGEXP;
5
+ }
6
+
7
+ xt_value xt_regexp_ctor(int32_t argc, xt_value *argv) {
8
+ xt_regexp *regexp = (xt_regexp *)xt_alloc(sizeof(xt_regexp), XT_OBJECT_KIND_REGEXP);
9
+ xt_value source = xt_arg_at(argc, argv, 0);
10
+ xt_value flags = xt_arg_at(argc, argv, 1);
11
+ if (XT_IS_OBJECT(source) && ((xt_object *)XT_GET_PTR(source))->header.kind == XT_OBJECT_KIND_REGEXP) {
12
+ xt_regexp *other = (xt_regexp *)XT_GET_PTR(source);
13
+ regexp->source = other->source;
14
+ regexp->flags = flags == XT_UNDEFINED ? other->flags : xt_to_string(flags);
15
+ } else {
16
+ regexp->source = source == XT_UNDEFINED ? xt_string_from_cstr("(?:)") : xt_to_string(source);
17
+ regexp->flags = flags == XT_UNDEFINED ? xt_string_from_cstr("") : xt_to_string(flags);
18
+ }
19
+ return XT_FROM_PTR(XT_TAG_OBJECT, regexp);
20
+ }
@@ -0,0 +1,105 @@
1
+ /* -- Set ------------------------------------------------------------------ */
2
+
3
+ int xt_is_set(xt_value value) {
4
+ return XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_SET;
5
+ }
6
+
7
+ int32_t xt_set_size(xt_value value) {
8
+ if (!xt_is_set(value)) return 0;
9
+ return (int32_t)((xt_set_object *)XT_GET_PTR(value))->count;
10
+ }
11
+
12
+ /* -- for...of iteration --------------------------------------------------- */
13
+
14
+ /* `for...of` lowers to a length check plus an index lookup. Arrays and strings
15
+ index directly; Maps yield `[key, value]` pairs and Sets yield their values. */
16
+ xt_value xt_iter_length(xt_value value) {
17
+ if (xt_is_map(value)) return xt_number((double)xt_map_size(value));
18
+ if (xt_is_set(value)) return xt_number((double)xt_set_size(value));
19
+ return xt_array_length(value);
20
+ }
21
+
22
+ xt_value xt_iter_value(xt_value value, xt_value index) {
23
+ if (xt_is_map(value)) {
24
+ xt_map *map = (xt_map *)XT_GET_PTR(value);
25
+ int64_t i = (int64_t)xt_to_int32(index);
26
+ if (i < 0 || i >= (int64_t)map->count) return XT_UNDEFINED;
27
+ xt_value pair = xt_array_new(0, NULL);
28
+ xt_array_push(pair, map->keys[i]);
29
+ xt_array_push(pair, map->values[i]);
30
+ return pair;
31
+ }
32
+ if (xt_is_set(value)) {
33
+ xt_set_object *set = (xt_set_object *)XT_GET_PTR(value);
34
+ int64_t i = (int64_t)xt_to_int32(index);
35
+ if (i < 0 || i >= (int64_t)set->count) return XT_UNDEFINED;
36
+ return set->values[i];
37
+ }
38
+ return xt_get(value, index);
39
+ }
40
+
41
+ static int32_t xt_set_index(xt_set_object *set, xt_value key) {
42
+ for (uint32_t i = 0; i < set->count; i++) if (xt_value_equals(set->values[i], key)) return (int32_t)i;
43
+ return -1;
44
+ }
45
+
46
+ static void xt_set_add(xt_set_object *set, xt_value value) {
47
+ if (xt_set_index(set, value) >= 0) return;
48
+ if (set->count >= set->capacity) {
49
+ uint32_t capacity = set->capacity == 0 ? 8 : set->capacity * 2;
50
+ set->values = (xt_value *)realloc(set->values, sizeof(xt_value) * capacity);
51
+ if (!set->values) abort();
52
+ set->capacity = capacity;
53
+ }
54
+ set->values[set->count++] = value;
55
+ }
56
+
57
+ static int xt_set_delete(xt_set_object *set, xt_value value) {
58
+ int32_t index = xt_set_index(set, value);
59
+ if (index < 0) return 0;
60
+ for (uint32_t i = (uint32_t)index + 1; i < set->count; i++) set->values[i - 1] = set->values[i];
61
+ set->count--;
62
+ return 1;
63
+ }
64
+
65
+ xt_value xt_set_ctor(int32_t argc, xt_value *argv) {
66
+ xt_set_object *set = (xt_set_object *)xt_alloc(sizeof(xt_set_object), XT_OBJECT_KIND_SET);
67
+ set->values = NULL; set->count = 0; set->capacity = 0;
68
+ xt_value iterable = xt_arg_at(argc, argv, 0);
69
+ if (XT_IS_ARRAY(iterable)) {
70
+ xt_array *array = xt_as_array(iterable);
71
+ for (uint32_t i = 0; i < array->length; i++) xt_set_add(set, array->items[i]);
72
+ }
73
+ return XT_FROM_PTR(XT_TAG_OBJECT, set);
74
+ }
75
+
76
+ static xt_value xt_set_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
77
+ *handled = 1;
78
+ xt_set_object *set = (xt_set_object *)XT_GET_PTR(target);
79
+ if (strcmp(method, "add") == 0) { xt_set_add(set, xt_arg_at(argc, argv, 0)); return target; }
80
+ if (strcmp(method, "has") == 0) return xt_bool(xt_set_index(set, xt_arg_at(argc, argv, 0)) >= 0);
81
+ if (strcmp(method, "delete") == 0) return xt_bool(xt_set_delete(set, xt_arg_at(argc, argv, 0)));
82
+ if (strcmp(method, "clear") == 0) { set->count = 0; return XT_UNDEFINED; }
83
+ if (strcmp(method, "forEach") == 0) {
84
+ xt_value fn = xt_arg_at(argc, argv, 0);
85
+ 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); }
86
+ return XT_UNDEFINED;
87
+ }
88
+ if (strcmp(method, "values") == 0 || strcmp(method, "keys") == 0) {
89
+ xt_value out = xt_array_new(0, NULL);
90
+ for (uint32_t i = 0; i < set->count; i++) xt_array_push(out, set->values[i]);
91
+ return out;
92
+ }
93
+ if (strcmp(method, "entries") == 0) {
94
+ xt_value out = xt_array_new(0, NULL);
95
+ for (uint32_t i = 0; i < set->count; i++) {
96
+ xt_value pair = xt_array_new(0, NULL);
97
+ xt_array_push(pair, set->values[i]);
98
+ xt_array_push(pair, set->values[i]);
99
+ xt_array_push(out, pair);
100
+ }
101
+ return out;
102
+ }
103
+ *handled = 0;
104
+ return XT_UNDEFINED;
105
+ }
@@ -0,0 +1,94 @@
1
+ /* -- string methods ------------------------------------------------------- */
2
+
3
+ static xt_value xt_string_pad(xt_value value, xt_value lengthValue, xt_value padValue, int start) {
4
+ xt_string *s = xt_as_string(value);
5
+ if (!s) return value;
6
+ int32_t target = xt_to_int32(lengthValue);
7
+ if (target <= (int32_t)s->length) return value;
8
+ xt_string *pad = xt_as_string(xt_to_string(padValue == XT_UNDEFINED ? xt_string_from_cstr(" ") : padValue));
9
+ if (!pad || pad->length == 0) return value;
10
+ size_t total = (size_t)target;
11
+ xt_string *out = xt_string_alloc(total);
12
+ size_t needed = total - s->length;
13
+ if (start) {
14
+ for (size_t i = 0; i < needed; i++) out->data[i] = pad->data[i % pad->length];
15
+ memcpy(out->data + needed, s->data, s->length);
16
+ } else {
17
+ memcpy(out->data, s->data, s->length);
18
+ for (size_t i = 0; i < needed; i++) out->data[s->length + i] = pad->data[i % pad->length];
19
+ }
20
+ return XT_FROM_PTR(XT_TAG_STRING, out);
21
+ }
22
+
23
+ static xt_value xt_string_trim_side(xt_value value, int start) {
24
+ xt_string *s = xt_as_string(value);
25
+ if (!s) return value;
26
+ uint32_t begin = 0;
27
+ uint32_t end = s->length;
28
+ if (start) { while (begin < end && isspace((unsigned char)s->data[begin])) begin++; }
29
+ else { while (end > begin && isspace((unsigned char)s->data[end - 1])) end--; }
30
+ return xt_string_new(s->data + begin, end - begin);
31
+ }
32
+
33
+ static xt_value xt_string_at(xt_value value, xt_value indexValue) {
34
+ xt_string *s = xt_as_string(value);
35
+ if (!s) return XT_UNDEFINED;
36
+ int32_t index = indexValue == XT_UNDEFINED ? 0 : xt_to_int32(indexValue);
37
+ if (index < 0) index += (int32_t)s->length;
38
+ if (index < 0 || (uint32_t)index >= s->length) return XT_UNDEFINED;
39
+ return xt_string_new(s->data + index, 1);
40
+ }
41
+
42
+ static xt_value xt_string_replace_all(xt_value value, xt_value searchValue, xt_value replacementValue) {
43
+ if (xt_is_regexp(searchValue)) return xt_regexp_replace(value, searchValue, replacementValue);
44
+ xt_string *s = xt_as_string(value);
45
+ if (!s) return value;
46
+ xt_string *search = xt_as_string(xt_to_string(searchValue));
47
+ xt_string *replacement = xt_as_string(xt_to_string(replacementValue));
48
+ if (!search || search->length == 0) return value;
49
+ size_t capacity = s->length + replacement->length * 4 + 16;
50
+ char *out = (char *)malloc(capacity);
51
+ if (!out) abort();
52
+ size_t length = 0;
53
+ uint32_t i = 0;
54
+ while (i < s->length) {
55
+ if (i + search->length <= s->length && memcmp(s->data + i, search->data, search->length) == 0) {
56
+ if (length + replacement->length + 2 > capacity) { capacity = (length + replacement->length + 2) * 2; out = (char *)realloc(out, capacity); if (!out) abort(); }
57
+ memcpy(out + length, replacement->data, replacement->length);
58
+ length += replacement->length;
59
+ i += search->length;
60
+ } else {
61
+ if (length + 2 > capacity) { capacity *= 2; out = (char *)realloc(out, capacity); if (!out) abort(); }
62
+ out[length++] = s->data[i++];
63
+ }
64
+ }
65
+ xt_value result = xt_string_new(out, length);
66
+ free(out);
67
+ return result;
68
+ }
69
+
70
+ xt_value xt_ext_string_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
71
+ *handled = 1;
72
+ if (strcmp(method, "at") == 0) return xt_string_at(target, xt_arg_at(argc, argv, 0));
73
+ if (strcmp(method, "padStart") == 0) return xt_string_pad(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), 1);
74
+ if (strcmp(method, "padEnd") == 0) return xt_string_pad(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), 0);
75
+ if (strcmp(method, "trimStart") == 0) return xt_string_trim_side(target, 1);
76
+ if (strcmp(method, "trimEnd") == 0) return xt_string_trim_side(target, 0);
77
+ if (strcmp(method, "replaceAll") == 0) return xt_string_replace_all(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
78
+ if (strcmp(method, "localeCompare") == 0) {
79
+ xt_string *a = xt_as_string(target);
80
+ xt_string *b = xt_as_string(xt_to_string(xt_arg_at(argc, argv, 0)));
81
+ int cmp = strcmp(a ? a->data : "", b ? b->data : "");
82
+ return xt_number(cmp < 0 ? -1 : cmp > 0 ? 1 : 0);
83
+ }
84
+ if (strcmp(method, "codePointAt") == 0) {
85
+ xt_string *s = xt_as_string(target);
86
+ if (!s) return XT_UNDEFINED;
87
+ int32_t index = xt_to_int32(xt_arg_at(argc, argv, 0));
88
+ if (index < 0 || (uint32_t)index >= s->length) return XT_UNDEFINED;
89
+ return xt_number((double)(unsigned char)s->data[index]);
90
+ }
91
+ if (strcmp(method, "valueOf") == 0 || strcmp(method, "toString") == 0) return target;
92
+ *handled = 0;
93
+ return XT_UNDEFINED;
94
+ }