@rhost/testkit 1.5.1 → 1.5.2

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 (157) hide show
  1. package/node_modules/@ursamu/mushcode/.github/workflows/publish.yml +36 -0
  2. package/node_modules/@ursamu/mushcode/LICENSE +21 -0
  3. package/node_modules/@ursamu/mushcode/README.md +110 -0
  4. package/node_modules/@ursamu/mushcode/_dist/mod.d.ts +36 -0
  5. package/node_modules/@ursamu/mushcode/_dist/mod.d.ts.map +1 -0
  6. package/node_modules/@ursamu/mushcode/_dist/parser/mod.d.ts +41 -0
  7. package/node_modules/@ursamu/mushcode/_dist/parser/mod.d.ts.map +1 -0
  8. package/node_modules/@ursamu/mushcode/_dist/src/analyze/commands.d.ts +15 -0
  9. package/node_modules/@ursamu/mushcode/_dist/src/analyze/commands.d.ts.map +1 -0
  10. package/node_modules/@ursamu/mushcode/_dist/src/analyze/deps.d.ts +18 -0
  11. package/node_modules/@ursamu/mushcode/_dist/src/analyze/deps.d.ts.map +1 -0
  12. package/node_modules/@ursamu/mushcode/_dist/src/analyze/mod.d.ts +20 -0
  13. package/node_modules/@ursamu/mushcode/_dist/src/analyze/mod.d.ts.map +1 -0
  14. package/node_modules/@ursamu/mushcode/_dist/src/analyze/tags.d.ts +6 -0
  15. package/node_modules/@ursamu/mushcode/_dist/src/analyze/tags.d.ts.map +1 -0
  16. package/node_modules/@ursamu/mushcode/_dist/src/eval/context.d.ts +85 -0
  17. package/node_modules/@ursamu/mushcode/_dist/src/eval/context.d.ts.map +1 -0
  18. package/node_modules/@ursamu/mushcode/_dist/src/eval/engine.d.ts +48 -0
  19. package/node_modules/@ursamu/mushcode/_dist/src/eval/engine.d.ts.map +1 -0
  20. package/node_modules/@ursamu/mushcode/_dist/src/eval/mod.d.ts +26 -0
  21. package/node_modules/@ursamu/mushcode/_dist/src/eval/mod.d.ts.map +1 -0
  22. package/node_modules/@ursamu/mushcode/_dist/src/eval/stdlib/mod.d.ts +3 -0
  23. package/node_modules/@ursamu/mushcode/_dist/src/eval/stdlib/mod.d.ts.map +1 -0
  24. package/node_modules/@ursamu/mushcode/_dist/src/lint/mod.d.ts +38 -0
  25. package/node_modules/@ursamu/mushcode/_dist/src/lint/mod.d.ts.map +1 -0
  26. package/node_modules/@ursamu/mushcode/_dist/src/print/mod.d.ts +18 -0
  27. package/node_modules/@ursamu/mushcode/_dist/src/print/mod.d.ts.map +1 -0
  28. package/node_modules/@ursamu/mushcode/_dist/src/print/printer.d.ts +15 -0
  29. package/node_modules/@ursamu/mushcode/_dist/src/print/printer.d.ts.map +1 -0
  30. package/node_modules/@ursamu/mushcode/_dist/src/traverse/mod.d.ts +19 -0
  31. package/node_modules/@ursamu/mushcode/_dist/src/traverse/mod.d.ts.map +1 -0
  32. package/node_modules/@ursamu/mushcode/_dist/src/traverse/transform.d.ts +27 -0
  33. package/node_modules/@ursamu/mushcode/_dist/src/traverse/transform.d.ts.map +1 -0
  34. package/node_modules/@ursamu/mushcode/_dist/src/traverse/walk.d.ts +27 -0
  35. package/node_modules/@ursamu/mushcode/_dist/src/traverse/walk.d.ts.map +1 -0
  36. package/node_modules/@ursamu/mushcode/deno.json +26 -0
  37. package/node_modules/@ursamu/mushcode/deno.lock +42 -0
  38. package/node_modules/@ursamu/mushcode/docs/analyze.md +145 -0
  39. package/node_modules/@ursamu/mushcode/docs/eval.md +312 -0
  40. package/node_modules/@ursamu/mushcode/docs/lint.md +152 -0
  41. package/node_modules/@ursamu/mushcode/docs/parser.md +196 -0
  42. package/node_modules/@ursamu/mushcode/docs/print.md +84 -0
  43. package/node_modules/@ursamu/mushcode/docs/stdlib.md +418 -0
  44. package/node_modules/@ursamu/mushcode/docs/traverse.md +167 -0
  45. package/node_modules/@ursamu/mushcode/grammar/mux-softcode.pegjs +781 -0
  46. package/node_modules/@ursamu/mushcode/mod.js +44 -0
  47. package/node_modules/@ursamu/mushcode/mod.js.map +1 -0
  48. package/node_modules/@ursamu/mushcode/mod.ts +63 -0
  49. package/node_modules/@ursamu/mushcode/package.json +38 -0
  50. package/node_modules/@ursamu/mushcode/parser/mod.js +47 -0
  51. package/node_modules/@ursamu/mushcode/parser/mod.js.map +1 -0
  52. package/node_modules/@ursamu/mushcode/parser/mod.ts +99 -0
  53. package/node_modules/@ursamu/mushcode/parser/mux-softcode.js +3833 -0
  54. package/node_modules/@ursamu/mushcode/parser/mux-softcode.mjs +3837 -0
  55. package/node_modules/@ursamu/mushcode/src/analyze/commands.js +29 -0
  56. package/node_modules/@ursamu/mushcode/src/analyze/commands.js.map +1 -0
  57. package/node_modules/@ursamu/mushcode/src/analyze/commands.ts +46 -0
  58. package/node_modules/@ursamu/mushcode/src/analyze/deps.js +45 -0
  59. package/node_modules/@ursamu/mushcode/src/analyze/deps.js.map +1 -0
  60. package/node_modules/@ursamu/mushcode/src/analyze/deps.ts +51 -0
  61. package/node_modules/@ursamu/mushcode/src/analyze/mod.js +18 -0
  62. package/node_modules/@ursamu/mushcode/src/analyze/mod.js.map +1 -0
  63. package/node_modules/@ursamu/mushcode/src/analyze/mod.ts +20 -0
  64. package/node_modules/@ursamu/mushcode/src/analyze/tags.js +11 -0
  65. package/node_modules/@ursamu/mushcode/src/analyze/tags.js.map +1 -0
  66. package/node_modules/@ursamu/mushcode/src/analyze/tags.ts +11 -0
  67. package/node_modules/@ursamu/mushcode/src/eval/context.js +22 -0
  68. package/node_modules/@ursamu/mushcode/src/eval/context.js.map +1 -0
  69. package/node_modules/@ursamu/mushcode/src/eval/context.ts +177 -0
  70. package/node_modules/@ursamu/mushcode/src/eval/engine.js +238 -0
  71. package/node_modules/@ursamu/mushcode/src/eval/engine.js.map +1 -0
  72. package/node_modules/@ursamu/mushcode/src/eval/engine.ts +276 -0
  73. package/node_modules/@ursamu/mushcode/src/eval/mod.js +25 -0
  74. package/node_modules/@ursamu/mushcode/src/eval/mod.js.map +1 -0
  75. package/node_modules/@ursamu/mushcode/src/eval/mod.ts +31 -0
  76. package/node_modules/@ursamu/mushcode/src/eval/stdlib/compare.js +56 -0
  77. package/node_modules/@ursamu/mushcode/src/eval/stdlib/compare.js.map +1 -0
  78. package/node_modules/@ursamu/mushcode/src/eval/stdlib/compare.ts +16 -0
  79. package/node_modules/@ursamu/mushcode/src/eval/stdlib/db.js +91 -0
  80. package/node_modules/@ursamu/mushcode/src/eval/stdlib/db.js.map +1 -0
  81. package/node_modules/@ursamu/mushcode/src/eval/stdlib/db.ts +104 -0
  82. package/node_modules/@ursamu/mushcode/src/eval/stdlib/iter.js +91 -0
  83. package/node_modules/@ursamu/mushcode/src/eval/stdlib/iter.js.map +1 -0
  84. package/node_modules/@ursamu/mushcode/src/eval/stdlib/iter.ts +98 -0
  85. package/node_modules/@ursamu/mushcode/src/eval/stdlib/logic.js +79 -0
  86. package/node_modules/@ursamu/mushcode/src/eval/stdlib/logic.js.map +1 -0
  87. package/node_modules/@ursamu/mushcode/src/eval/stdlib/logic.ts +84 -0
  88. package/node_modules/@ursamu/mushcode/src/eval/stdlib/math.js +120 -0
  89. package/node_modules/@ursamu/mushcode/src/eval/stdlib/math.js.map +1 -0
  90. package/node_modules/@ursamu/mushcode/src/eval/stdlib/math.ts +115 -0
  91. package/node_modules/@ursamu/mushcode/src/eval/stdlib/mod.js +17 -0
  92. package/node_modules/@ursamu/mushcode/src/eval/stdlib/mod.js.map +1 -0
  93. package/node_modules/@ursamu/mushcode/src/eval/stdlib/mod.ts +19 -0
  94. package/node_modules/@ursamu/mushcode/src/eval/stdlib/register.js +28 -0
  95. package/node_modules/@ursamu/mushcode/src/eval/stdlib/register.js.map +1 -0
  96. package/node_modules/@ursamu/mushcode/src/eval/stdlib/register.ts +31 -0
  97. package/node_modules/@ursamu/mushcode/src/eval/stdlib/string.js +153 -0
  98. package/node_modules/@ursamu/mushcode/src/eval/stdlib/string.js.map +1 -0
  99. package/node_modules/@ursamu/mushcode/src/eval/stdlib/string.ts +154 -0
  100. package/node_modules/@ursamu/mushcode/src/lint/builtin_arities.js +212 -0
  101. package/node_modules/@ursamu/mushcode/src/lint/builtin_arities.js.map +1 -0
  102. package/node_modules/@ursamu/mushcode/src/lint/builtin_arities.ts +68 -0
  103. package/node_modules/@ursamu/mushcode/src/lint/mod.js +60 -0
  104. package/node_modules/@ursamu/mushcode/src/lint/mod.js.map +1 -0
  105. package/node_modules/@ursamu/mushcode/src/lint/mod.ts +96 -0
  106. package/node_modules/@ursamu/mushcode/src/lint/rules/arg_count.js +37 -0
  107. package/node_modules/@ursamu/mushcode/src/lint/rules/arg_count.js.map +1 -0
  108. package/node_modules/@ursamu/mushcode/src/lint/rules/arg_count.ts +44 -0
  109. package/node_modules/@ursamu/mushcode/src/lint/rules/iter_var_outside_iter.js +55 -0
  110. package/node_modules/@ursamu/mushcode/src/lint/rules/iter_var_outside_iter.js.map +1 -0
  111. package/node_modules/@ursamu/mushcode/src/lint/rules/iter_var_outside_iter.ts +60 -0
  112. package/node_modules/@ursamu/mushcode/src/lint/rules/missing_wildcard.js +31 -0
  113. package/node_modules/@ursamu/mushcode/src/lint/rules/missing_wildcard.js.map +1 -0
  114. package/node_modules/@ursamu/mushcode/src/lint/rules/missing_wildcard.ts +40 -0
  115. package/node_modules/@ursamu/mushcode/src/lint/rules/register_before_set.js +59 -0
  116. package/node_modules/@ursamu/mushcode/src/lint/rules/register_before_set.js.map +1 -0
  117. package/node_modules/@ursamu/mushcode/src/lint/rules/register_before_set.ts +64 -0
  118. package/node_modules/@ursamu/mushcode/src/print/lock_printer.js +43 -0
  119. package/node_modules/@ursamu/mushcode/src/print/lock_printer.js.map +1 -0
  120. package/node_modules/@ursamu/mushcode/src/print/lock_printer.ts +41 -0
  121. package/node_modules/@ursamu/mushcode/src/print/mod.js +17 -0
  122. package/node_modules/@ursamu/mushcode/src/print/mod.js.map +1 -0
  123. package/node_modules/@ursamu/mushcode/src/print/mod.ts +18 -0
  124. package/node_modules/@ursamu/mushcode/src/print/printer.js +91 -0
  125. package/node_modules/@ursamu/mushcode/src/print/printer.js.map +1 -0
  126. package/node_modules/@ursamu/mushcode/src/print/printer.ts +132 -0
  127. package/node_modules/@ursamu/mushcode/src/traverse/child_slots.js +129 -0
  128. package/node_modules/@ursamu/mushcode/src/traverse/child_slots.js.map +1 -0
  129. package/node_modules/@ursamu/mushcode/src/traverse/child_slots.ts +51 -0
  130. package/node_modules/@ursamu/mushcode/src/traverse/mod.js +17 -0
  131. package/node_modules/@ursamu/mushcode/src/traverse/mod.js.map +1 -0
  132. package/node_modules/@ursamu/mushcode/src/traverse/mod.ts +19 -0
  133. package/node_modules/@ursamu/mushcode/src/traverse/transform.js +70 -0
  134. package/node_modules/@ursamu/mushcode/src/traverse/transform.js.map +1 -0
  135. package/node_modules/@ursamu/mushcode/src/traverse/transform.ts +84 -0
  136. package/node_modules/@ursamu/mushcode/src/traverse/walk.js +55 -0
  137. package/node_modules/@ursamu/mushcode/src/traverse/walk.js.map +1 -0
  138. package/node_modules/@ursamu/mushcode/src/traverse/walk.ts +82 -0
  139. package/node_modules/@ursamu/mushcode/tests/01-literals.test.ts +105 -0
  140. package/node_modules/@ursamu/mushcode/tests/02-substitutions.test.ts +145 -0
  141. package/node_modules/@ursamu/mushcode/tests/03-function-calls.test.ts +184 -0
  142. package/node_modules/@ursamu/mushcode/tests/04-eval-blocks.test.ts +110 -0
  143. package/node_modules/@ursamu/mushcode/tests/05-braced-strings.test.ts +119 -0
  144. package/node_modules/@ursamu/mushcode/tests/06-commands.test.ts +222 -0
  145. package/node_modules/@ursamu/mushcode/tests/07-dollar-patterns.test.ts +156 -0
  146. package/node_modules/@ursamu/mushcode/tests/08-lock-expressions.test.ts +159 -0
  147. package/node_modules/@ursamu/mushcode/tests/09-edge-cases.test.ts +162 -0
  148. package/node_modules/@ursamu/mushcode/tests/10-regression.test.ts +211 -0
  149. package/node_modules/@ursamu/mushcode/tests/11-tags.test.ts +357 -0
  150. package/node_modules/@ursamu/mushcode/tests/12-locations.test.ts +162 -0
  151. package/node_modules/@ursamu/mushcode/tests/13-eval.test.ts +389 -0
  152. package/node_modules/@ursamu/mushcode/tests/analyze.test.ts +194 -0
  153. package/node_modules/@ursamu/mushcode/tests/helpers.ts +69 -0
  154. package/node_modules/@ursamu/mushcode/tests/lint.test.ts +232 -0
  155. package/node_modules/@ursamu/mushcode/tests/print.test.ts +204 -0
  156. package/node_modules/@ursamu/mushcode/tests/traverse.test.ts +211 -0
  157. package/package.json +4 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.js","sources":["./math.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ import type { FunctionImpl } from "../context.ts";
2
+
3
+ // ── Helpers ───────────────────────────────────────────────────────────────────
4
+
5
+ function toNum(s: string): number {
6
+ const n = Number(s);
7
+ if (!isFinite(n)) throw new Error(`ARGUMENT (${s}) IS NOT A NUMBER`);
8
+ return n;
9
+ }
10
+
11
+ /** Format a result: integers stay integers; floats get at most 6 sig digits. */
12
+ function fmt(n: number): string {
13
+ if (!isFinite(n)) throw new Error("RESULT IS NOT A NUMBER");
14
+ if (Number.isInteger(n)) return String(n);
15
+ return String(parseFloat(n.toPrecision(6)));
16
+ }
17
+
18
+ // ── Math functions ────────────────────────────────────────────────────────────
19
+
20
+ export const mathFunctions: Record<string, FunctionImpl> = {
21
+ add: {
22
+ minArgs: 2, maxArgs: Infinity,
23
+ exec(args) {
24
+ return fmt((args as string[]).map(toNum).reduce((a, b) => a + b, 0));
25
+ },
26
+ },
27
+
28
+ sub: {
29
+ minArgs: 2, maxArgs: 2,
30
+ exec(args) {
31
+ const [a, b] = args as string[];
32
+ return fmt(toNum(a) - toNum(b));
33
+ },
34
+ },
35
+
36
+ mul: {
37
+ minArgs: 2, maxArgs: Infinity,
38
+ exec(args) {
39
+ return fmt((args as string[]).map(toNum).reduce((a, b) => a * b, 1));
40
+ },
41
+ },
42
+
43
+ div: {
44
+ minArgs: 2, maxArgs: 2,
45
+ exec(args) {
46
+ const [a, b] = args as string[];
47
+ const na = toNum(a), nb = toNum(b);
48
+ if (nb === 0) throw new Error("DIVIDE BY ZERO");
49
+ if (Number.isInteger(na) && Number.isInteger(nb)) return String(Math.trunc(na / nb));
50
+ return fmt(na / nb);
51
+ },
52
+ },
53
+
54
+ mod: {
55
+ minArgs: 2, maxArgs: 2,
56
+ exec(args) {
57
+ const [a, b] = args as string[];
58
+ const na = toNum(a), nb = toNum(b);
59
+ if (nb === 0) throw new Error("DIVIDE BY ZERO");
60
+ return fmt(na % nb);
61
+ },
62
+ },
63
+
64
+ abs: {
65
+ minArgs: 1, maxArgs: 1,
66
+ exec(args) { return fmt(Math.abs(toNum((args as string[])[0]))); },
67
+ },
68
+
69
+ round: {
70
+ minArgs: 2, maxArgs: 2,
71
+ exec(args) {
72
+ const [a, p] = args as string[];
73
+ const prec = Math.max(0, Math.trunc(toNum(p)));
74
+ const factor = Math.pow(10, prec);
75
+ return fmt(Math.round(toNum(a) * factor) / factor);
76
+ },
77
+ },
78
+
79
+ floor: {
80
+ minArgs: 1, maxArgs: 1,
81
+ exec(args) { return String(Math.floor(toNum((args as string[])[0]))); },
82
+ },
83
+
84
+ ceil: {
85
+ minArgs: 1, maxArgs: 1,
86
+ exec(args) { return String(Math.ceil(toNum((args as string[])[0]))); },
87
+ },
88
+
89
+ max: {
90
+ minArgs: 2, maxArgs: Infinity,
91
+ exec(args) { return fmt(Math.max(...(args as string[]).map(toNum))); },
92
+ },
93
+
94
+ min: {
95
+ minArgs: 2, maxArgs: Infinity,
96
+ exec(args) { return fmt(Math.min(...(args as string[]).map(toNum))); },
97
+ },
98
+
99
+ power: {
100
+ minArgs: 2, maxArgs: 2,
101
+ exec(args) {
102
+ const [a, b] = args as string[];
103
+ return fmt(Math.pow(toNum(a), toNum(b)));
104
+ },
105
+ },
106
+
107
+ sqrt: {
108
+ minArgs: 1, maxArgs: 1,
109
+ exec(args) {
110
+ const n = toNum((args as string[])[0]);
111
+ if (n < 0) throw new Error("ARGUMENT OUT OF RANGE");
112
+ return fmt(Math.sqrt(n));
113
+ },
114
+ },
115
+ };
@@ -0,0 +1,17 @@
1
+ import { mathFunctions } from "./math.js";
2
+ import { stringFunctions } from "./string.js";
3
+ import { compareFunctions } from "./compare.js";
4
+ import { logicFunctions } from "./logic.js";
5
+ import { registerFunctions } from "./register.js";
6
+ import { iterFunctions } from "./iter.js";
7
+ import { dbFunctions } from "./db.js";
8
+ /** Register the full standard softcode function library on an engine. */ export function registerStdlib(engine) {
9
+ for (const [n, impl] of Object.entries(mathFunctions))engine.registerFunction(n, impl);
10
+ for (const [n, impl] of Object.entries(stringFunctions))engine.registerFunction(n, impl);
11
+ for (const [n, impl] of Object.entries(compareFunctions))engine.registerFunction(n, impl);
12
+ for (const [n, impl] of Object.entries(logicFunctions))engine.registerFunction(n, impl);
13
+ for (const [n, impl] of Object.entries(registerFunctions))engine.registerFunction(n, impl);
14
+ for (const [n, impl] of Object.entries(iterFunctions))engine.registerFunction(n, impl);
15
+ for (const [n, impl] of Object.entries(dbFunctions))engine.registerFunction(n, impl);
16
+ }
17
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","sources":["./mod.ts"],"names":[],"mappings":"AACA,SAAS,aAAa,oBAAwB;AAC9C,SAAS,eAAe,sBAAwB;AAChD,SAAS,gBAAgB,uBAAwB;AACjD,SAAS,cAAc,qBAAwB;AAC/C,SAAS,iBAAiB,wBAAwB;AAClD,SAAS,aAAa,oBAAwB;AAC9C,SAAS,WAAW,kBAAwB;AAE5C,uEAAuE,GACvE,OAAO,SAAS,eAAe,MAAmB;EAChD,KAAK,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,OAAO,CAAC,eAAmB,OAAO,gBAAgB,CAAC,GAAG;EACrF,KAAK,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,OAAO,CAAC,iBAAmB,OAAO,gBAAgB,CAAC,GAAG;EACrF,KAAK,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,OAAO,CAAC,kBAAmB,OAAO,gBAAgB,CAAC,GAAG;EACrF,KAAK,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,OAAO,CAAC,gBAAmB,OAAO,gBAAgB,CAAC,GAAG;EACrF,KAAK,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,OAAO,CAAC,mBAAmB,OAAO,gBAAgB,CAAC,GAAG;EACrF,KAAK,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,OAAO,CAAC,eAAmB,OAAO,gBAAgB,CAAC,GAAG;EACrF,KAAK,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,OAAO,CAAC,aAAmB,OAAO,gBAAgB,CAAC,GAAG;AACvF"}
@@ -0,0 +1,19 @@
1
+ import type { IEvalEngine } from "../context.ts";
2
+ import { mathFunctions } from "./math.js";
3
+ import { stringFunctions } from "./string.js";
4
+ import { compareFunctions } from "./compare.js";
5
+ import { logicFunctions } from "./logic.js";
6
+ import { registerFunctions } from "./register.js";
7
+ import { iterFunctions } from "./iter.js";
8
+ import { dbFunctions } from "./db.js";
9
+
10
+ /** Register the full standard softcode function library on an engine. */
11
+ export function registerStdlib(engine: IEvalEngine): void {
12
+ for (const [n, impl] of Object.entries(mathFunctions)) engine.registerFunction(n, impl);
13
+ for (const [n, impl] of Object.entries(stringFunctions)) engine.registerFunction(n, impl);
14
+ for (const [n, impl] of Object.entries(compareFunctions)) engine.registerFunction(n, impl);
15
+ for (const [n, impl] of Object.entries(logicFunctions)) engine.registerFunction(n, impl);
16
+ for (const [n, impl] of Object.entries(registerFunctions))engine.registerFunction(n, impl);
17
+ for (const [n, impl] of Object.entries(iterFunctions)) engine.registerFunction(n, impl);
18
+ for (const [n, impl] of Object.entries(dbFunctions)) engine.registerFunction(n, impl);
19
+ }
@@ -0,0 +1,28 @@
1
+ export const registerFunctions = {
2
+ /** setq(reg, value) — store value in named register; returns "". */ setq: {
3
+ minArgs: 2,
4
+ maxArgs: 2,
5
+ exec (args, ctx) {
6
+ const [reg, val] = args;
7
+ ctx.registers.set(reg, val);
8
+ return "";
9
+ }
10
+ },
11
+ /** r(reg) — read named register (empty string if unset). */ r: {
12
+ minArgs: 1,
13
+ maxArgs: 1,
14
+ exec (args, ctx) {
15
+ return ctx.registers.get(args[0]) ?? "";
16
+ }
17
+ },
18
+ /** setr(reg, value) — like setq but returns value. */ setr: {
19
+ minArgs: 2,
20
+ maxArgs: 2,
21
+ exec (args, ctx) {
22
+ const [reg, val] = args;
23
+ ctx.registers.set(reg, val);
24
+ return val;
25
+ }
26
+ }
27
+ };
28
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sources":["./register.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,oBAAkD;EAC7D,kEAAkE,GAClE,MAAM;IACJ,SAAS;IAAG,SAAS;IACrB,MAAK,IAAI,EAAE,GAAG;MACZ,MAAM,CAAC,KAAK,IAAI,GAAG;MACnB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK;MACvB,OAAO;IACT;EACF;EAEA,0DAA0D,GAC1D,GAAG;IACD,SAAS;IAAG,SAAS;IACrB,MAAK,IAAI,EAAE,GAAG;MACZ,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,AAAC,IAAiB,CAAC,EAAE,KAAK;IACrD;EACF;EAEA,oDAAoD,GACpD,MAAM;IACJ,SAAS;IAAG,SAAS;IACrB,MAAK,IAAI,EAAE,GAAG;MACZ,MAAM,CAAC,KAAK,IAAI,GAAG;MACnB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK;MACvB,OAAO;IACT;EACF;AACF,EAAE"}
@@ -0,0 +1,31 @@
1
+ import type { FunctionImpl } from "../context.ts";
2
+
3
+ export const registerFunctions: Record<string, FunctionImpl> = {
4
+ /** setq(reg, value) — store value in named register; returns "". */
5
+ setq: {
6
+ minArgs: 2, maxArgs: 2,
7
+ exec(args, ctx) {
8
+ const [reg, val] = args as string[];
9
+ ctx.registers.set(reg, val);
10
+ return "";
11
+ },
12
+ },
13
+
14
+ /** r(reg) — read named register (empty string if unset). */
15
+ r: {
16
+ minArgs: 1, maxArgs: 1,
17
+ exec(args, ctx) {
18
+ return ctx.registers.get((args as string[])[0]) ?? "";
19
+ },
20
+ },
21
+
22
+ /** setr(reg, value) — like setq but returns value. */
23
+ setr: {
24
+ minArgs: 2, maxArgs: 2,
25
+ exec(args, ctx) {
26
+ const [reg, val] = args as string[];
27
+ ctx.registers.set(reg, val);
28
+ return val;
29
+ },
30
+ },
31
+ };
@@ -0,0 +1,153 @@
1
+ // ── Constants ─────────────────────────────────────────────────────────────────
2
+ /**
3
+ * Maximum number of characters any single string-building function may produce.
4
+ * Mirrors TinyMUX's per-expression output limit (~8 000 chars).
5
+ * Prevents unbounded memory allocation from player-authored softcode.
6
+ */ export const MAX_STRING_LEN = 8_000;
7
+ // ── Helpers ───────────────────────────────────────────────────────────────────
8
+ function pad(str, width, fill, align) {
9
+ if (width > MAX_STRING_LEN) throw new Error("OUTPUT TOO LONG");
10
+ const ch = fill[0] ?? " ";
11
+ const len = str.length;
12
+ if (len >= width) return str;
13
+ const total = width - len;
14
+ if (align === "left") return str + ch.repeat(total);
15
+ if (align === "right") return ch.repeat(total) + str;
16
+ const lPad = Math.floor(total / 2);
17
+ return ch.repeat(lPad) + str + ch.repeat(total - lPad);
18
+ }
19
+ // ── String functions ──────────────────────────────────────────────────────────
20
+ export const stringFunctions = {
21
+ strlen: {
22
+ minArgs: 1,
23
+ maxArgs: 1,
24
+ exec (args) {
25
+ return String(args[0].length);
26
+ }
27
+ },
28
+ /** mid(str, start, length) — 0-based start position (TinyMUX convention). Negative start clamped to 0. */ mid: {
29
+ minArgs: 3,
30
+ maxArgs: 3,
31
+ exec (args) {
32
+ const [str, startStr, lenStr] = args;
33
+ const start = parseInt(startStr, 10);
34
+ const len = parseInt(lenStr, 10);
35
+ if (isNaN(start) || isNaN(len)) throw new Error("ARGUMENT IS NOT A NUMBER");
36
+ const s = Math.max(0, start);
37
+ return str.slice(s, s + Math.max(0, len));
38
+ }
39
+ },
40
+ left: {
41
+ minArgs: 2,
42
+ maxArgs: 2,
43
+ exec (args) {
44
+ const [str, nStr] = args;
45
+ const n = parseInt(nStr, 10);
46
+ if (isNaN(n)) throw new Error("ARGUMENT IS NOT A NUMBER");
47
+ return str.slice(0, Math.max(0, n));
48
+ }
49
+ },
50
+ right: {
51
+ minArgs: 2,
52
+ maxArgs: 2,
53
+ exec (args) {
54
+ const [str, nStr] = args;
55
+ const n = parseInt(nStr, 10);
56
+ if (isNaN(n)) throw new Error("ARGUMENT IS NOT A NUMBER");
57
+ return n > 0 ? str.slice(-n) : "";
58
+ }
59
+ },
60
+ /** trim(str[, side[, char]]) — side: "l"|"r"|"b" (both, default). */ trim: {
61
+ minArgs: 1,
62
+ maxArgs: 3,
63
+ exec (args) {
64
+ const [str, side = "b", char = " "] = args;
65
+ const ch = (char[0] ?? " ").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
66
+ const s = side.toLowerCase();
67
+ if (s === "l") return str.replace(new RegExp(`^${ch}+`), "");
68
+ if (s === "r") return str.replace(new RegExp(`${ch}+$`), "");
69
+ return str.replace(new RegExp(`^${ch}+`), "").replace(new RegExp(`${ch}+$`), "");
70
+ }
71
+ },
72
+ ljust: {
73
+ minArgs: 2,
74
+ maxArgs: 3,
75
+ exec (args) {
76
+ const [str, wStr, fill = " "] = args;
77
+ const w = parseInt(wStr, 10);
78
+ if (isNaN(w)) throw new Error("ARGUMENT IS NOT A NUMBER");
79
+ return pad(str, w, fill, "left");
80
+ }
81
+ },
82
+ rjust: {
83
+ minArgs: 2,
84
+ maxArgs: 3,
85
+ exec (args) {
86
+ const [str, wStr, fill = " "] = args;
87
+ const w = parseInt(wStr, 10);
88
+ if (isNaN(w)) throw new Error("ARGUMENT IS NOT A NUMBER");
89
+ return pad(str, w, fill, "right");
90
+ }
91
+ },
92
+ center: {
93
+ minArgs: 2,
94
+ maxArgs: 3,
95
+ exec (args) {
96
+ const [str, wStr, fill = " "] = args;
97
+ const w = parseInt(wStr, 10);
98
+ if (isNaN(w)) throw new Error("ARGUMENT IS NOT A NUMBER");
99
+ return pad(str, w, fill, "center");
100
+ }
101
+ },
102
+ ucstr: {
103
+ minArgs: 1,
104
+ maxArgs: 1,
105
+ exec (args) {
106
+ return args[0].toUpperCase();
107
+ }
108
+ },
109
+ lcstr: {
110
+ minArgs: 1,
111
+ maxArgs: 1,
112
+ exec (args) {
113
+ return args[0].toLowerCase();
114
+ }
115
+ },
116
+ capstr: {
117
+ minArgs: 1,
118
+ maxArgs: 1,
119
+ exec (args) {
120
+ const s = args[0];
121
+ return s ? s[0].toUpperCase() + s.slice(1) : "";
122
+ }
123
+ },
124
+ /** cat(str1, str2, ...) — joins with a single space. */ cat: {
125
+ minArgs: 2,
126
+ maxArgs: Infinity,
127
+ exec (args) {
128
+ return args.join(" ");
129
+ }
130
+ },
131
+ space: {
132
+ minArgs: 1,
133
+ maxArgs: 1,
134
+ exec (args) {
135
+ const n = parseInt(args[0], 10);
136
+ if (isNaN(n) || n < 0) throw new Error("ARGUMENT IS NOT A NUMBER");
137
+ if (n > MAX_STRING_LEN) throw new Error("OUTPUT TOO LONG");
138
+ return " ".repeat(n);
139
+ }
140
+ },
141
+ repeat: {
142
+ minArgs: 2,
143
+ maxArgs: 2,
144
+ exec (args) {
145
+ const [str, nStr] = args;
146
+ const n = parseInt(nStr, 10);
147
+ if (isNaN(n) || n < 0) throw new Error("ARGUMENT IS NOT A NUMBER");
148
+ if (str.length * n > MAX_STRING_LEN) throw new Error("OUTPUT TOO LONG");
149
+ return str.repeat(n);
150
+ }
151
+ }
152
+ };
153
+ //# sourceMappingURL=string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string.js","sources":["./string.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ import type { FunctionImpl } from "../context.ts";
2
+
3
+ // ── Constants ─────────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * Maximum number of characters any single string-building function may produce.
7
+ * Mirrors TinyMUX's per-expression output limit (~8 000 chars).
8
+ * Prevents unbounded memory allocation from player-authored softcode.
9
+ */
10
+ export const MAX_STRING_LEN = 8_000;
11
+
12
+ // ── Helpers ───────────────────────────────────────────────────────────────────
13
+
14
+ function pad(str: string, width: number, fill: string, align: "left" | "right" | "center"): string {
15
+ if (width > MAX_STRING_LEN) throw new Error("OUTPUT TOO LONG");
16
+ const ch = fill[0] ?? " ";
17
+ const len = str.length;
18
+ if (len >= width) return str;
19
+ const total = width - len;
20
+ if (align === "left") return str + ch.repeat(total);
21
+ if (align === "right") return ch.repeat(total) + str;
22
+ const lPad = Math.floor(total / 2);
23
+ return ch.repeat(lPad) + str + ch.repeat(total - lPad);
24
+ }
25
+
26
+ // ── String functions ──────────────────────────────────────────────────────────
27
+
28
+ export const stringFunctions: Record<string, FunctionImpl> = {
29
+ strlen: {
30
+ minArgs: 1, maxArgs: 1,
31
+ exec(args) { return String((args as string[])[0].length); },
32
+ },
33
+
34
+ /** mid(str, start, length) — 0-based start position (TinyMUX convention). Negative start clamped to 0. */
35
+ mid: {
36
+ minArgs: 3, maxArgs: 3,
37
+ exec(args) {
38
+ const [str, startStr, lenStr] = args as string[];
39
+ const start = parseInt(startStr, 10);
40
+ const len = parseInt(lenStr, 10);
41
+ if (isNaN(start) || isNaN(len)) throw new Error("ARGUMENT IS NOT A NUMBER");
42
+ const s = Math.max(0, start);
43
+ return str.slice(s, s + Math.max(0, len));
44
+ },
45
+ },
46
+
47
+ left: {
48
+ minArgs: 2, maxArgs: 2,
49
+ exec(args) {
50
+ const [str, nStr] = args as string[];
51
+ const n = parseInt(nStr, 10);
52
+ if (isNaN(n)) throw new Error("ARGUMENT IS NOT A NUMBER");
53
+ return str.slice(0, Math.max(0, n));
54
+ },
55
+ },
56
+
57
+ right: {
58
+ minArgs: 2, maxArgs: 2,
59
+ exec(args) {
60
+ const [str, nStr] = args as string[];
61
+ const n = parseInt(nStr, 10);
62
+ if (isNaN(n)) throw new Error("ARGUMENT IS NOT A NUMBER");
63
+ return n > 0 ? str.slice(-n) : "";
64
+ },
65
+ },
66
+
67
+ /** trim(str[, side[, char]]) — side: "l"|"r"|"b" (both, default). */
68
+ trim: {
69
+ minArgs: 1, maxArgs: 3,
70
+ exec(args) {
71
+ const [str, side = "b", char = " "] = args as string[];
72
+ const ch = (char[0] ?? " ").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
73
+ const s = side.toLowerCase();
74
+ if (s === "l") return str.replace(new RegExp(`^${ch}+`), "");
75
+ if (s === "r") return str.replace(new RegExp(`${ch}+$`), "");
76
+ return str.replace(new RegExp(`^${ch}+`), "").replace(new RegExp(`${ch}+$`), "");
77
+ },
78
+ },
79
+
80
+ ljust: {
81
+ minArgs: 2, maxArgs: 3,
82
+ exec(args) {
83
+ const [str, wStr, fill = " "] = args as string[];
84
+ const w = parseInt(wStr, 10);
85
+ if (isNaN(w)) throw new Error("ARGUMENT IS NOT A NUMBER");
86
+ return pad(str, w, fill, "left");
87
+ },
88
+ },
89
+
90
+ rjust: {
91
+ minArgs: 2, maxArgs: 3,
92
+ exec(args) {
93
+ const [str, wStr, fill = " "] = args as string[];
94
+ const w = parseInt(wStr, 10);
95
+ if (isNaN(w)) throw new Error("ARGUMENT IS NOT A NUMBER");
96
+ return pad(str, w, fill, "right");
97
+ },
98
+ },
99
+
100
+ center: {
101
+ minArgs: 2, maxArgs: 3,
102
+ exec(args) {
103
+ const [str, wStr, fill = " "] = args as string[];
104
+ const w = parseInt(wStr, 10);
105
+ if (isNaN(w)) throw new Error("ARGUMENT IS NOT A NUMBER");
106
+ return pad(str, w, fill, "center");
107
+ },
108
+ },
109
+
110
+ ucstr: {
111
+ minArgs: 1, maxArgs: 1,
112
+ exec(args) { return (args as string[])[0].toUpperCase(); },
113
+ },
114
+
115
+ lcstr: {
116
+ minArgs: 1, maxArgs: 1,
117
+ exec(args) { return (args as string[])[0].toLowerCase(); },
118
+ },
119
+
120
+ capstr: {
121
+ minArgs: 1, maxArgs: 1,
122
+ exec(args) {
123
+ const s = (args as string[])[0];
124
+ return s ? s[0].toUpperCase() + s.slice(1) : "";
125
+ },
126
+ },
127
+
128
+ /** cat(str1, str2, ...) — joins with a single space. */
129
+ cat: {
130
+ minArgs: 2, maxArgs: Infinity,
131
+ exec(args) { return (args as string[]).join(" "); },
132
+ },
133
+
134
+ space: {
135
+ minArgs: 1, maxArgs: 1,
136
+ exec(args) {
137
+ const n = parseInt((args as string[])[0], 10);
138
+ if (isNaN(n) || n < 0) throw new Error("ARGUMENT IS NOT A NUMBER");
139
+ if (n > MAX_STRING_LEN) throw new Error("OUTPUT TOO LONG");
140
+ return " ".repeat(n);
141
+ },
142
+ },
143
+
144
+ repeat: {
145
+ minArgs: 2, maxArgs: 2,
146
+ exec(args) {
147
+ const [str, nStr] = args as string[];
148
+ const n = parseInt(nStr, 10);
149
+ if (isNaN(n) || n < 0) throw new Error("ARGUMENT IS NOT A NUMBER");
150
+ if (str.length * n > MAX_STRING_LEN) throw new Error("OUTPUT TOO LONG");
151
+ return str.repeat(n);
152
+ },
153
+ },
154
+ };