@aster-cloud/aster-lang-ts 1.0.30 → 1.0.32

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 (297) hide show
  1. package/dist/scripts/aster.js +11 -26
  2. package/dist/scripts/aster.js.map +1 -1
  3. package/dist/scripts/corpus-loader.d.ts +17 -0
  4. package/dist/scripts/corpus-loader.d.ts.map +1 -0
  5. package/dist/scripts/corpus-loader.js +60 -0
  6. package/dist/scripts/corpus-loader.js.map +1 -0
  7. package/dist/scripts/emit-classfiles-core.js +5 -13
  8. package/dist/scripts/emit-classfiles-core.js.map +1 -1
  9. package/dist/scripts/emit-classfiles.js +7 -12
  10. package/dist/scripts/emit-classfiles.js.map +1 -1
  11. package/dist/scripts/generate_error_codes.js +2 -0
  12. package/dist/scripts/generate_error_codes.js.map +1 -1
  13. package/dist/scripts/golden.js +4 -1
  14. package/dist/scripts/golden.js.map +1 -1
  15. package/dist/scripts/test-lossless-golden.js +2 -1
  16. package/dist/scripts/test-lossless-golden.js.map +1 -1
  17. package/dist/scripts/validate_error_codes.js +1 -0
  18. package/dist/scripts/validate_error_codes.js.map +1 -1
  19. package/dist/scripts/verify-lexicon-sync.js +5 -1
  20. package/dist/scripts/verify-lexicon-sync.js.map +1 -1
  21. package/dist/src/ast/ast.d.ts +1 -1
  22. package/dist/src/ast/ast.d.ts.map +1 -1
  23. package/dist/src/ast/ast.js +2 -1
  24. package/dist/src/ast/ast.js.map +1 -1
  25. package/dist/src/browser.d.ts +7 -0
  26. package/dist/src/browser.d.ts.map +1 -1
  27. package/dist/src/browser.js +4 -0
  28. package/dist/src/browser.js.map +1 -1
  29. package/dist/src/cli/utils/gradle-env.d.ts +9 -0
  30. package/dist/src/cli/utils/gradle-env.d.ts.map +1 -0
  31. package/dist/src/cli/utils/gradle-env.js +18 -0
  32. package/dist/src/cli/utils/gradle-env.js.map +1 -0
  33. package/dist/src/cli/utils/out-dir.d.ts +18 -0
  34. package/dist/src/cli/utils/out-dir.d.ts.map +1 -0
  35. package/dist/src/cli/utils/out-dir.js +49 -0
  36. package/dist/src/cli/utils/out-dir.js.map +1 -0
  37. package/dist/src/cnl-printer.d.ts +10 -0
  38. package/dist/src/cnl-printer.d.ts.map +1 -0
  39. package/dist/src/cnl-printer.js +360 -0
  40. package/dist/src/cnl-printer.js.map +1 -0
  41. package/dist/src/config/lexicons/de-DE.d.ts.map +1 -1
  42. package/dist/src/config/lexicons/de-DE.js +8 -2
  43. package/dist/src/config/lexicons/de-DE.js.map +1 -1
  44. package/dist/src/config/lexicons/en-US.d.ts.map +1 -1
  45. package/dist/src/config/lexicons/en-US.js +8 -4
  46. package/dist/src/config/lexicons/en-US.js.map +1 -1
  47. package/dist/src/config/lexicons/hi-IN.d.ts.map +1 -1
  48. package/dist/src/config/lexicons/hi-IN.js +8 -2
  49. package/dist/src/config/lexicons/hi-IN.js.map +1 -1
  50. package/dist/src/config/lexicons/template.d.ts.map +1 -1
  51. package/dist/src/config/lexicons/template.js +12 -0
  52. package/dist/src/config/lexicons/template.js.map +1 -1
  53. package/dist/src/config/lexicons/zh-CN.d.ts.map +1 -1
  54. package/dist/src/config/lexicons/zh-CN.js +9 -3
  55. package/dist/src/config/lexicons/zh-CN.js.map +1 -1
  56. package/dist/src/config/semantic.d.ts +6 -0
  57. package/dist/src/config/semantic.d.ts.map +1 -1
  58. package/dist/src/config/semantic.js +8 -0
  59. package/dist/src/config/semantic.js.map +1 -1
  60. package/dist/src/config/token-kind.d.ts +12 -0
  61. package/dist/src/config/token-kind.d.ts.map +1 -1
  62. package/dist/src/config/token-kind.js +18 -0
  63. package/dist/src/config/token-kind.js.map +1 -1
  64. package/dist/src/core/core_ir.d.ts +1 -1
  65. package/dist/src/core/core_ir.d.ts.map +1 -1
  66. package/dist/src/core/core_ir.js +3 -1
  67. package/dist/src/core/core_ir.js.map +1 -1
  68. package/dist/src/core/interpreter.d.ts.map +1 -1
  69. package/dist/src/core/interpreter.js +222 -18
  70. package/dist/src/core/interpreter.js.map +1 -1
  71. package/dist/src/cst/cst_printer.d.ts.map +1 -1
  72. package/dist/src/cst/cst_printer.js +66 -32
  73. package/dist/src/cst/cst_printer.js.map +1 -1
  74. package/dist/src/diagnostics/diagnostics.d.ts +1 -0
  75. package/dist/src/diagnostics/diagnostics.d.ts.map +1 -1
  76. package/dist/src/diagnostics/diagnostics.js +1 -0
  77. package/dist/src/diagnostics/diagnostics.js.map +1 -1
  78. package/dist/src/diagnostics/error_codes.d.ts +10 -2
  79. package/dist/src/diagnostics/error_codes.d.ts.map +1 -1
  80. package/dist/src/diagnostics/error_codes.js +64 -0
  81. package/dist/src/diagnostics/error_codes.js.map +1 -1
  82. package/dist/src/effects/effect_inference.js +1 -1
  83. package/dist/src/effects/effect_inference.js.map +1 -1
  84. package/dist/src/formatter.d.ts +3 -0
  85. package/dist/src/formatter.d.ts.map +1 -1
  86. package/dist/src/formatter.js +8 -261
  87. package/dist/src/formatter.js.map +1 -1
  88. package/dist/src/frontend/transformers.d.ts.map +1 -1
  89. package/dist/src/frontend/transformers.js +10 -2
  90. package/dist/src/frontend/transformers.js.map +1 -1
  91. package/dist/src/governance/controls-registry.data.d.ts +40 -0
  92. package/dist/src/governance/controls-registry.data.d.ts.map +1 -0
  93. package/dist/src/governance/controls-registry.data.js +35 -0
  94. package/dist/src/governance/controls-registry.data.js.map +1 -0
  95. package/dist/src/governance/controls.d.ts +23 -0
  96. package/dist/src/governance/controls.d.ts.map +1 -0
  97. package/dist/src/governance/controls.js +77 -0
  98. package/dist/src/governance/controls.js.map +1 -0
  99. package/dist/src/index.d.ts +4 -0
  100. package/dist/src/index.d.ts.map +1 -1
  101. package/dist/src/index.js +2 -0
  102. package/dist/src/index.js.map +1 -1
  103. package/dist/src/lower_to_core.js +1 -1
  104. package/dist/src/lower_to_core.js.map +1 -1
  105. package/dist/src/lsp/completion.d.ts +22 -1
  106. package/dist/src/lsp/completion.d.ts.map +1 -1
  107. package/dist/src/lsp/completion.js +42 -1
  108. package/dist/src/lsp/completion.js.map +1 -1
  109. package/dist/src/lsp/debounce-map.d.ts +16 -0
  110. package/dist/src/lsp/debounce-map.d.ts.map +1 -0
  111. package/dist/src/lsp/debounce-map.js +32 -0
  112. package/dist/src/lsp/debounce-map.js.map +1 -0
  113. package/dist/src/lsp/server.js +6 -8
  114. package/dist/src/lsp/server.js.map +1 -1
  115. package/dist/src/lsp/utils.d.ts.map +1 -1
  116. package/dist/src/lsp/utils.js +2 -0
  117. package/dist/src/lsp/utils.js.map +1 -1
  118. package/dist/src/lsp/workspace/file-watcher.d.ts +1 -0
  119. package/dist/src/lsp/workspace/file-watcher.d.ts.map +1 -1
  120. package/dist/src/lsp/workspace/file-watcher.js +24 -14
  121. package/dist/src/lsp/workspace/file-watcher.js.map +1 -1
  122. package/dist/src/manifest.d.ts +2 -0
  123. package/dist/src/manifest.d.ts.map +1 -1
  124. package/dist/src/manifest.js.map +1 -1
  125. package/dist/src/package/manifest-parser.d.ts +10 -0
  126. package/dist/src/package/manifest-parser.d.ts.map +1 -1
  127. package/dist/src/package/manifest-parser.js +27 -28
  128. package/dist/src/package/manifest-parser.js.map +1 -1
  129. package/dist/src/package/manifest-schema.d.ts +15 -0
  130. package/dist/src/package/manifest-schema.d.ts.map +1 -0
  131. package/dist/src/package/manifest-schema.js +116 -0
  132. package/dist/src/package/manifest-schema.js.map +1 -0
  133. package/dist/src/parser/context.d.ts +2 -0
  134. package/dist/src/parser/context.d.ts.map +1 -1
  135. package/dist/src/parser/context.js +1 -0
  136. package/dist/src/parser/context.js.map +1 -1
  137. package/dist/src/parser/decl-parser.d.ts.map +1 -1
  138. package/dist/src/parser/decl-parser.js +26 -10
  139. package/dist/src/parser/decl-parser.js.map +1 -1
  140. package/dist/src/parser/expr-stmt-parser.d.ts +4 -1
  141. package/dist/src/parser/expr-stmt-parser.d.ts.map +1 -1
  142. package/dist/src/parser/expr-stmt-parser.js +199 -6
  143. package/dist/src/parser/expr-stmt-parser.js.map +1 -1
  144. package/dist/src/parser/import-parser.d.ts +12 -0
  145. package/dist/src/parser/import-parser.d.ts.map +1 -1
  146. package/dist/src/parser/import-parser.js +28 -0
  147. package/dist/src/parser/import-parser.js.map +1 -1
  148. package/dist/src/parser.js +1 -1
  149. package/dist/src/parser.js.map +1 -1
  150. package/dist/src/typecheck/browser.d.ts +3 -0
  151. package/dist/src/typecheck/browser.d.ts.map +1 -1
  152. package/dist/src/typecheck/browser.js +10 -1
  153. package/dist/src/typecheck/browser.js.map +1 -1
  154. package/dist/src/typecheck/context.d.ts +3 -0
  155. package/dist/src/typecheck/context.d.ts.map +1 -1
  156. package/dist/src/typecheck/context.js.map +1 -1
  157. package/dist/src/typecheck/expression.d.ts +6 -0
  158. package/dist/src/typecheck/expression.d.ts.map +1 -1
  159. package/dist/src/typecheck/expression.js +54 -2
  160. package/dist/src/typecheck/expression.js.map +1 -1
  161. package/dist/src/typecheck/generics.d.ts.map +1 -1
  162. package/dist/src/typecheck/generics.js +3 -0
  163. package/dist/src/typecheck/generics.js.map +1 -1
  164. package/dist/src/typecheck/governance.d.ts +43 -0
  165. package/dist/src/typecheck/governance.d.ts.map +1 -0
  166. package/dist/src/typecheck/governance.js +162 -0
  167. package/dist/src/typecheck/governance.js.map +1 -0
  168. package/dist/src/typecheck/module.d.ts.map +1 -1
  169. package/dist/src/typecheck/module.js +10 -1
  170. package/dist/src/typecheck/module.js.map +1 -1
  171. package/dist/src/typecheck/statement.d.ts.map +1 -1
  172. package/dist/src/typecheck/statement.js +2 -2
  173. package/dist/src/typecheck/statement.js.map +1 -1
  174. package/dist/src/typecheck/type_system.d.ts.map +1 -1
  175. package/dist/src/typecheck/type_system.js +4 -0
  176. package/dist/src/typecheck/type_system.js.map +1 -1
  177. package/dist/src/typecheck/verdict_signatures.d.ts +19 -0
  178. package/dist/src/typecheck/verdict_signatures.d.ts.map +1 -0
  179. package/dist/src/typecheck/verdict_signatures.js +23 -0
  180. package/dist/src/typecheck/verdict_signatures.js.map +1 -0
  181. package/dist/src/types/base.d.ts +2 -0
  182. package/dist/src/types/base.d.ts.map +1 -1
  183. package/dist/test/helpers/sibling-source.d.ts +10 -0
  184. package/dist/test/helpers/sibling-source.d.ts.map +1 -0
  185. package/dist/test/helpers/sibling-source.js +20 -0
  186. package/dist/test/helpers/sibling-source.js.map +1 -0
  187. package/dist/test/unit/allocation-budget.test.d.ts +2 -0
  188. package/dist/test/unit/allocation-budget.test.d.ts.map +1 -0
  189. package/dist/test/unit/allocation-budget.test.js +160 -0
  190. package/dist/test/unit/allocation-budget.test.js.map +1 -0
  191. package/dist/test/unit/apply-call.test.js +5 -0
  192. package/dist/test/unit/apply-call.test.js.map +1 -1
  193. package/dist/test/unit/canonicalizer/possessive-anchor.test.js +10 -0
  194. package/dist/test/unit/canonicalizer/possessive-anchor.test.js.map +1 -1
  195. package/dist/test/unit/cli/gradle-env-guard.test.d.ts +2 -0
  196. package/dist/test/unit/cli/gradle-env-guard.test.d.ts.map +1 -0
  197. package/dist/test/unit/cli/gradle-env-guard.test.js +53 -0
  198. package/dist/test/unit/cli/gradle-env-guard.test.js.map +1 -0
  199. package/dist/test/unit/cli/gradle-env.test.d.ts +2 -0
  200. package/dist/test/unit/cli/gradle-env.test.d.ts.map +1 -0
  201. package/dist/test/unit/cli/gradle-env.test.js +31 -0
  202. package/dist/test/unit/cli/gradle-env.test.js.map +1 -0
  203. package/dist/test/unit/cli/out-dir.test.d.ts +2 -0
  204. package/dist/test/unit/cli/out-dir.test.d.ts.map +1 -0
  205. package/dist/test/unit/cli/out-dir.test.js +96 -0
  206. package/dist/test/unit/cli/out-dir.test.js.map +1 -0
  207. package/dist/test/unit/eval-regression-poker-straight-high.test.d.ts +2 -0
  208. package/dist/test/unit/eval-regression-poker-straight-high.test.d.ts.map +1 -0
  209. package/dist/test/unit/eval-regression-poker-straight-high.test.js +61 -0
  210. package/dist/test/unit/eval-regression-poker-straight-high.test.js.map +1 -0
  211. package/dist/test/unit/formatter-corpus-roundtrip.test.d.ts +2 -0
  212. package/dist/test/unit/formatter-corpus-roundtrip.test.d.ts.map +1 -0
  213. package/dist/test/unit/formatter-corpus-roundtrip.test.js +190 -0
  214. package/dist/test/unit/formatter-corpus-roundtrip.test.js.map +1 -0
  215. package/dist/test/unit/formatter-roundtrip.test.d.ts +2 -0
  216. package/dist/test/unit/formatter-roundtrip.test.d.ts.map +1 -0
  217. package/dist/test/unit/formatter-roundtrip.test.js +125 -0
  218. package/dist/test/unit/formatter-roundtrip.test.js.map +1 -0
  219. package/dist/test/unit/governance/controls-registry-parity.test.d.ts +2 -0
  220. package/dist/test/unit/governance/controls-registry-parity.test.d.ts.map +1 -0
  221. package/dist/test/unit/governance/controls-registry-parity.test.js +28 -0
  222. package/dist/test/unit/governance/controls-registry-parity.test.js.map +1 -0
  223. package/dist/test/unit/governance/controls-registry-profiles.test.d.ts +2 -0
  224. package/dist/test/unit/governance/controls-registry-profiles.test.d.ts.map +1 -0
  225. package/dist/test/unit/governance/controls-registry-profiles.test.js +106 -0
  226. package/dist/test/unit/governance/controls-registry-profiles.test.js.map +1 -0
  227. package/dist/test/unit/governance/governance-check.test.d.ts +2 -0
  228. package/dist/test/unit/governance/governance-check.test.d.ts.map +1 -0
  229. package/dist/test/unit/governance/governance-check.test.js +169 -0
  230. package/dist/test/unit/governance/governance-check.test.js.map +1 -0
  231. package/dist/test/unit/governance/profile-check.test.d.ts +2 -0
  232. package/dist/test/unit/governance/profile-check.test.d.ts.map +1 -0
  233. package/dist/test/unit/governance/profile-check.test.js +139 -0
  234. package/dist/test/unit/governance/profile-check.test.js.map +1 -0
  235. package/dist/test/unit/governance/verdict-typecheck.test.d.ts +2 -0
  236. package/dist/test/unit/governance/verdict-typecheck.test.d.ts.map +1 -0
  237. package/dist/test/unit/governance/verdict-typecheck.test.js +80 -0
  238. package/dist/test/unit/governance/verdict-typecheck.test.js.map +1 -0
  239. package/dist/test/unit/interpreter/verdict-builtins.test.d.ts +2 -0
  240. package/dist/test/unit/interpreter/verdict-builtins.test.d.ts.map +1 -0
  241. package/dist/test/unit/interpreter/verdict-builtins.test.js +72 -0
  242. package/dist/test/unit/interpreter/verdict-builtins.test.js.map +1 -0
  243. package/dist/test/unit/list-numeric-fail-loud.test.d.ts +2 -0
  244. package/dist/test/unit/list-numeric-fail-loud.test.d.ts.map +1 -0
  245. package/dist/test/unit/list-numeric-fail-loud.test.js +83 -0
  246. package/dist/test/unit/list-numeric-fail-loud.test.js.map +1 -0
  247. package/dist/test/unit/lossless-mirror.test.d.ts +2 -0
  248. package/dist/test/unit/lossless-mirror.test.d.ts.map +1 -0
  249. package/dist/test/unit/lossless-mirror.test.js +41 -0
  250. package/dist/test/unit/lossless-mirror.test.js.map +1 -0
  251. package/dist/test/unit/lossless-reflow.test.d.ts +2 -0
  252. package/dist/test/unit/lossless-reflow.test.d.ts.map +1 -0
  253. package/dist/test/unit/lossless-reflow.test.js +84 -0
  254. package/dist/test/unit/lossless-reflow.test.js.map +1 -0
  255. package/dist/test/unit/lowering/lowering.test.js +35 -35
  256. package/dist/test/unit/lowering/lowering.test.js.map +1 -1
  257. package/dist/test/unit/lsp/control-completion.test.d.ts +2 -0
  258. package/dist/test/unit/lsp/control-completion.test.d.ts.map +1 -0
  259. package/dist/test/unit/lsp/control-completion.test.js +46 -0
  260. package/dist/test/unit/lsp/control-completion.test.js.map +1 -0
  261. package/dist/test/unit/lsp/debounce-map.test.d.ts +2 -0
  262. package/dist/test/unit/lsp/debounce-map.test.d.ts.map +1 -0
  263. package/dist/test/unit/lsp/debounce-map.test.js +47 -0
  264. package/dist/test/unit/lsp/debounce-map.test.js.map +1 -0
  265. package/dist/test/unit/lsp/file-watcher-restart.test.d.ts +2 -0
  266. package/dist/test/unit/lsp/file-watcher-restart.test.d.ts.map +1 -0
  267. package/dist/test/unit/lsp/file-watcher-restart.test.js +40 -0
  268. package/dist/test/unit/lsp/file-watcher-restart.test.js.map +1 -0
  269. package/dist/test/unit/manifest-parser.test.js +8 -0
  270. package/dist/test/unit/manifest-parser.test.js.map +1 -1
  271. package/dist/test/unit/manifest-schema.test.d.ts +7 -5
  272. package/dist/test/unit/manifest-schema.test.d.ts.map +1 -1
  273. package/dist/test/unit/manifest-schema.test.js +48 -10
  274. package/dist/test/unit/manifest-schema.test.js.map +1 -1
  275. package/dist/test/unit/mapping/redos-budget.test.js +60 -23
  276. package/dist/test/unit/mapping/redos-budget.test.js.map +1 -1
  277. package/dist/test/unit/parser/governance-sugar.test.d.ts +2 -0
  278. package/dist/test/unit/parser/governance-sugar.test.d.ts.map +1 -0
  279. package/dist/test/unit/parser/governance-sugar.test.js +258 -0
  280. package/dist/test/unit/parser/governance-sugar.test.js.map +1 -0
  281. package/dist/test/unit/parser/module-header.test.d.ts +2 -0
  282. package/dist/test/unit/parser/module-header.test.d.ts.map +1 -0
  283. package/dist/test/unit/parser/module-header.test.js +25 -0
  284. package/dist/test/unit/parser/module-header.test.js.map +1 -0
  285. package/dist/test/unit/parser/positional-annotation-args.test.d.ts +2 -0
  286. package/dist/test/unit/parser/positional-annotation-args.test.d.ts.map +1 -0
  287. package/dist/test/unit/parser/positional-annotation-args.test.js +26 -0
  288. package/dist/test/unit/parser/positional-annotation-args.test.js.map +1 -0
  289. package/dist/test/unit/parser/prefix-operator-call.test.d.ts +2 -0
  290. package/dist/test/unit/parser/prefix-operator-call.test.d.ts.map +1 -0
  291. package/dist/test/unit/parser/prefix-operator-call.test.js +185 -0
  292. package/dist/test/unit/parser/prefix-operator-call.test.js.map +1 -0
  293. package/dist/test/unit/scripts/corpus-loader.test.d.ts +2 -0
  294. package/dist/test/unit/scripts/corpus-loader.test.d.ts.map +1 -0
  295. package/dist/test/unit/scripts/corpus-loader.test.js +85 -0
  296. package/dist/test/unit/scripts/corpus-loader.test.js.map +1 -0
  297. package/package.json +1 -1
@@ -0,0 +1,83 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { compile } from '../../src/browser.js';
4
+ import { evaluate } from '../../src/core/interpreter.js';
5
+ // List.sum/min/max/sort/sortBy/minBy/maxBy 对非数值元素必须**响亮失败**,
6
+ // 与 truffle `Builtins.toDouble`(`Double.parseDouble` 抛 NumberFormatException)对齐。
7
+ //
8
+ // ★修复前(issue #193):这七个 builtin 直接 `Number(x)`,`Number("2o")` 得 NaN 后
9
+ // sum 静默产出 NaN、max/min 因 `NaN > x` 恒假静默返回首元素、sort 顺序未定义——
10
+ // 规则跑通了、结果是错的,且与 Java 侧一个响亮失败一个静默错答案。
11
+ function run(expr, ret = 'Int', rules = '') {
12
+ const c = compile(`Module probe.\n${rules}Rule r given a as Int, produce ${ret}:\n Return ${expr}.\n`);
13
+ if (!c.core)
14
+ return { ok: false, value: undefined, error: 'compile failed' };
15
+ const ev = evaluate(c.core, 'r', { a: 1 });
16
+ return { ok: ev.success, value: ev.value, error: String(ev.error ?? '') };
17
+ }
18
+ const ID_RULE = 'Rule id given x, produce:\n Return x.\n';
19
+ describe('List 数值 builtin 对非数值元素响亮失败(与 truffle toDouble 对齐)', () => {
20
+ const cases = [
21
+ ['List.sum', 'List.sum(["10", "2o"])', 'Int'],
22
+ ['List.min', 'List.min(["x", "y"])', 'Text'],
23
+ ['List.max', 'List.max(["x", "y"])', 'Text'],
24
+ ['List.sort', 'List.get(List.sort(["1", "b"]), 0)', 'Text'],
25
+ ['List.sum 空串', 'List.sum([""])', 'Int'],
26
+ ['List.sum 字符串 NaN', 'List.sum(["NaN"])', 'Int'],
27
+ ['List.sum 字符串 Infinity', 'List.sum(["Infinity"])', 'Int'],
28
+ ['List.sum 十六进制', 'List.sum(["0x10"])', 'Int'],
29
+ ['List.sum 布尔', 'List.sum([true])', 'Int'],
30
+ ];
31
+ for (const [name, expr, ret] of cases) {
32
+ it(`${name} 非数值元素必须报错,而不是静默给答案`, () => {
33
+ const r = run(expr, ret);
34
+ assert.equal(r.ok, false, `★${name} 静默返回了 ${JSON.stringify(r.value)}——静默错答案比报错危险`);
35
+ assert.match(r.error, /expected Number/i);
36
+ });
37
+ }
38
+ const keyed = [
39
+ ['List.sortBy', 'List.get(List.sortBy(["1", "b"], id), 0)', 'Text'],
40
+ ['List.minBy', 'List.minBy(["x", "y"], id)', 'Text'],
41
+ ['List.maxBy', 'List.maxBy(["x", "y"], id)', 'Text'],
42
+ ];
43
+ for (const [name, expr, ret] of keyed) {
44
+ it(`${name} 键函数返回非数值必须报错`, () => {
45
+ const r = run(expr, ret, ID_RULE);
46
+ assert.equal(r.ok, false, `★${name} 静默返回了 ${JSON.stringify(r.value)}`);
47
+ assert.match(r.error, /expected Number/i);
48
+ });
49
+ }
50
+ // 反向保险:合法数值(含可解析的字符串、前后空白)不得被误伤
51
+ it('数值列表照常工作', () => {
52
+ assert.equal(run('List.sum([3, 8, 1, 9])').value, 21);
53
+ assert.equal(run('List.max([3, 8, 1, 9])').value, 9);
54
+ assert.equal(run('List.min([3, 8, 1, 9])').value, 1);
55
+ assert.equal(run('List.get(List.sort([3, 8, 1]), 0)').value, 1);
56
+ assert.equal(run('List.maxBy([3, 8, 1], id)', 'Int', ID_RULE).value, 8);
57
+ });
58
+ it('可解析的数值字符串(含前后空白、小数、科学计数)照常换算', () => {
59
+ assert.equal(run('List.sum(["10", " 2 ", "1.5", "1e1"])', 'Decimal').value, 23.5);
60
+ assert.equal(run('List.max(["10", "9"])', 'Text').value, '10');
61
+ });
62
+ });
63
+ // ★issue #204:List.combinations 的 k 曾是裸 Number(),Number.isInteger 只拦得住 NaN:
64
+ // ""→0、true→1、"0x2"→2 静默被接受,而 truffle 侧 toInt(Integer.parseInt)一律抛错。
65
+ describe('List.combinations 的 k 非法时响亮失败(与 truffle toInt 对齐)', () => {
66
+ for (const k of ['""', 'true', '"0x2"', '"2o"', '"2.0"']) {
67
+ it(`k=${k} 必须报错,而不是静默给答案`, () => {
68
+ const r = run(`List.length(List.combinations([1, 2, 3], ${k}))`);
69
+ assert.equal(r.ok, false, `★静默返回了 ${JSON.stringify(r.value)}`);
70
+ assert.match(r.error, /List\.combinations: expected Int/);
71
+ });
72
+ }
73
+ it('k 为负数仍报错', () => {
74
+ const r = run('List.length(List.combinations([1, 2, 3], 0 minus 1))');
75
+ assert.equal(r.ok, false);
76
+ assert.match(r.error, /非负整数/);
77
+ });
78
+ it('合法 k(数字、整数字符串)照常工作', () => {
79
+ assert.equal(run('List.length(List.combinations([1, 2, 3], 2))').value, 3);
80
+ assert.equal(run('List.length(List.combinations([1, 2, 3], "2"))').value, 3);
81
+ });
82
+ });
83
+ //# sourceMappingURL=list-numeric-fail-loud.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-numeric-fail-loud.test.js","sourceRoot":"","sources":["../../../test/unit/list-numeric-fail-loud.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lossless-mirror.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lossless-mirror.test.d.ts","sourceRoot":"","sources":["../../../test/unit/lossless-mirror.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * lossless golden 的真源是本仓 test/lossless/golden/;兄弟仓 aster-lang-test 的
3
+ * corpus/tier3-fixtures/lossless/ 是它的镜像(落位规则同 aster-lang-test scripts/classify-existing.mjs 的 tier3:
4
+ * 原样复制 .aster,并配同名 meta)。golden 改动后须同步镜像,否则本测试失败。
5
+ * CI 的 test job 会 checkout aster-lang-test,因此 CI 中缺失即失败;仅本地未并列 checkout 时跳过。
6
+ */
7
+ import { test } from 'node:test';
8
+ import assert from 'node:assert/strict';
9
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
10
+ import { dirname, join } from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+ // 编译后从 dist/test/unit 运行:上溯 3 级到仓库根
13
+ const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
14
+ const goldenDir = join(repoRoot, 'test', 'lossless', 'golden');
15
+ const MIRROR = ['corpus', 'tier3-fixtures', 'lossless'];
16
+ function mirrorDir() {
17
+ return [join(repoRoot, '..', 'aster-lang-test', ...MIRROR), join(repoRoot, 'aster-lang-test', ...MIRROR)]
18
+ .find((c) => existsSync(c));
19
+ }
20
+ const asterFiles = (dir) => readdirSync(dir).filter((n) => n.endsWith('.aster')).sort();
21
+ // 与 classify-existing.mjs 写 tier3 meta 的方式逐字节相同
22
+ function expectedMeta(name) {
23
+ const meta = { tier: 3, bucket: 'lossless', engines: ['ts'], lexicon: 'en-US', source: `aster-lang-ts/test/lossless/golden/${name}` };
24
+ return JSON.stringify(meta, null, 2) + '\n';
25
+ }
26
+ test('lossless golden 与 aster-lang-test 镜像逐字节一致', (t) => {
27
+ const mirror = mirrorDir();
28
+ if (mirror === undefined) {
29
+ assert.ok(!process.env.CI, 'CI 中须 checkout aster-lang-test(见 .github/workflows/ci.yml test job)');
30
+ return t.skip('aster-lang-test 未并列 checkout');
31
+ }
32
+ const names = asterFiles(goldenDir);
33
+ assert.deepEqual(asterFiles(mirror), names, '镜像的 .aster 文件集合须与 golden 相同');
34
+ for (const name of names) {
35
+ assert.ok(readFileSync(join(mirror, name)).equals(readFileSync(join(goldenDir, name))), `${name} 与 golden 不一致`);
36
+ const metaPath = join(mirror, name.replace(/\.aster$/, '.meta.json'));
37
+ assert.ok(existsSync(metaPath), `${name} 缺同名 meta`);
38
+ assert.equal(readFileSync(metaPath, 'utf8'), expectedMeta(name), `${name} 的 meta 不符合落位规则`);
39
+ }
40
+ });
41
+ //# sourceMappingURL=lossless-mirror.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lossless-mirror.test.js","sourceRoot":"","sources":["../../../test/unit/lossless-mirror.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lossless-reflow.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lossless-reflow.test.d.ts","sourceRoot":"","sources":["../../../test/unit/lossless-reflow.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * lossless 模式的 reflow:只整理记号之间的空白,不得改动字符串字面量、注释正文与语句结构。
3
+ * LSP 默认格式化即 lossless + reflow,任何改动都会直接改写用户源码。
4
+ */
5
+ import { describe, test } from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import { readdirSync, readFileSync } from 'node:fs';
8
+ import { dirname, join } from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+ import { buildCstLossless } from '../../src/cst/cst_builder.js';
11
+ import { printCNLFromCst, printRangeFromCst } from '../../src/cst/cst_printer.js';
12
+ import { canonicalize } from '../../src/frontend/canonicalizer.js';
13
+ import { lex } from '../../src/frontend/lexer.js';
14
+ import { parse } from '../../src/parser.js';
15
+ import { lowerModule } from '../../src/lower_to_core.js';
16
+ // 编译后从 dist/test/unit 运行:上溯 3 级到仓库根
17
+ const goldenDir = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'test', 'lossless', 'golden');
18
+ const reflow = (src) => printCNLFromCst(buildCstLossless(src), { reflow: true });
19
+ function coreJson(src) {
20
+ const result = parse(lex(canonicalize(src)));
21
+ const errors = result.diagnostics.filter((d) => d.severity === 'error');
22
+ if (errors.length > 0)
23
+ throw new Error(errors.map((d) => d.message).join('; '));
24
+ return JSON.stringify(lowerModule(result.ast), (k, v) => (k === 'origin' ? undefined : v));
25
+ }
26
+ describe('lossless reflow 只动记号之间的空白', () => {
27
+ test('标点前同行空白、行尾空白、`. :` 与多余结尾换行被整理', () => {
28
+ const src = 'Module m . \n\nRule r given a as Int , produce Int . : \n Return a .\n\n\n';
29
+ assert.equal(reflow(src), 'Module m.\n\nRule r given a as Int, produce Int:\n Return a.\n');
30
+ });
31
+ test('字符串字面量原样保留', () => {
32
+ const src = 'Module m.\n\nRule r, produce Text:\n Return "Hi , there . : ! ?" .\n';
33
+ assert.equal(reflow(src), 'Module m.\n\nRule r, produce Text:\n Return "Hi , there . : ! ?".\n');
34
+ });
35
+ test('注释正文原样保留(只去行尾空白)', () => {
36
+ const src = '// 注释 , 带空格 . \nModule m. // 行尾 : 注释\n';
37
+ assert.equal(reflow(src), '// 注释 , 带空格 .\nModule m. // 行尾 : 注释\n');
38
+ });
39
+ test('独占一行的句点(workflow 结束)不被拉到上一行', () => {
40
+ const src = ['Module m.', '', 'Rule run, produce. It performs io:', ' workflow:', ' step only:',
41
+ ' Return ok of 1.', '', ' .', ''].join('\n');
42
+ assert.equal(reflow(src), src);
43
+ });
44
+ test('文件中间只含空白的行被清空', () => {
45
+ const src = 'Module m.\n \nRule r, produce Int:\n Let x be 1.\n \t \n Return x.\n';
46
+ assert.equal(reflow(src), 'Module m.\n\nRule r, produce Int:\n Let x be 1.\n\n Return x.\n');
47
+ });
48
+ test('文件末尾的空白行与行尾空白去掉,至多留一个换行', () => {
49
+ const body = 'Module m.\n\nRule r, produce Int:\n Return 1.';
50
+ assert.equal(reflow(`${body}\n \n \n`), `${body}\n`);
51
+ assert.equal(reflow(`${body}\n\n `), `${body}\n`);
52
+ assert.equal(reflow(`${body} `), body);
53
+ });
54
+ test('CRLF 文件去掉换行前的空白并保持 CRLF', () => {
55
+ const src = 'Module m. \r\n \r\nRule r, produce Int: \r\n // 注释 , 不动 \r\n Return 1. \r\n \r\n\r\n';
56
+ const want = 'Module m.\r\n\r\nRule r, produce Int:\r\n // 注释 , 不动\r\n Return 1.\r\n';
57
+ assert.equal(reflow(src), want);
58
+ });
59
+ test('reflow 幂等', () => {
60
+ const src = 'Module m . \r\n \r\nRule r given a as Int , produce Int . : \r\n Return a . \r\n \r\n ';
61
+ assert.equal(reflow(reflow(src)), reflow(src));
62
+ });
63
+ test('区间格式化同样不改字符串', () => {
64
+ const src = 'Module m.\n\nRule r, produce Text:\n Return "a , b" .\n';
65
+ const cst = buildCstLossless(src);
66
+ const start = src.indexOf('Return');
67
+ assert.equal(printRangeFromCst(cst, start, src.length, { reflow: true }), 'Return "a , b".\n');
68
+ });
69
+ });
70
+ describe('lossless golden', () => {
71
+ const inputs = readdirSync(goldenDir).filter((f) => f.endsWith('.in.aster')).sort();
72
+ for (const file of inputs) {
73
+ test(file, () => {
74
+ const src = readFileSync(join(goldenDir, file), 'utf8');
75
+ const expected = readFileSync(join(goldenDir, file.replace(/\.in\.aster$/, '.out.aster')), 'utf8');
76
+ assert.equal(printCNLFromCst(buildCstLossless(src)), src, '无 reflow 时须逐字节还原');
77
+ // 与 scripts/test-lossless-golden 同一比较口径:只忽略期望文件末尾的单个换行,其余空白逐字比较
78
+ const norm = (t) => t.replace(/\n$/, '');
79
+ assert.equal(norm(reflow(src)), norm(expected));
80
+ assert.equal(coreJson(expected), coreJson(src), 'reflow 前后 Core IR 须相同');
81
+ });
82
+ }
83
+ });
84
+ //# sourceMappingURL=lossless-reflow.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lossless-reflow.test.js","sourceRoot":"","sources":["../../../test/unit/lossless-reflow.test.ts"],"names":[],"mappings":"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"}
@@ -123,7 +123,7 @@ Rule makeIdentity, produce Fn1:
123
123
  retType: Node.TypeName('Fn1'),
124
124
  statements: [Node.Return(lambdaExpr)],
125
125
  });
126
- const moduleAst = Node.Module('test.lowering.lambda_capture', [funcDecl]);
126
+ const moduleAst = Node.Module('test.lowering.lambda_capture', null, [funcDecl]);
127
127
  const core = lowerAst(moduleAst);
128
128
  const func = core.decls.find(d => d.kind === 'Func');
129
129
  const lambda = func.body.statements[0].expr;
@@ -137,7 +137,7 @@ Rule makeIdentity, produce Fn1:
137
137
  retType: Node.TypeName('Text'),
138
138
  statements: [Node.Return(awaitExpr)],
139
139
  });
140
- const moduleAst = Node.Module('test.lowering.await_expr', [funcDecl]);
140
+ const moduleAst = Node.Module('test.lowering.await_expr', null, [funcDecl]);
141
141
  const core = lowerAst(moduleAst);
142
142
  const func = core.decls[0];
143
143
  const retExpr = func.body.statements[0].expr;
@@ -151,7 +151,7 @@ Rule makeIdentity, produce Fn1:
151
151
  retType: Node.TypeName('Int'),
152
152
  statements: [Node.Block([Node.Let('inner', Node.Int(2))]), inner],
153
153
  });
154
- const moduleAst = Node.Module('test.lowering.scope_block', [funcDecl]);
154
+ const moduleAst = Node.Module('test.lowering.scope_block', null, [funcDecl]);
155
155
  const core = lowerAst(moduleAst);
156
156
  const func = core.decls[0];
157
157
  assert.equal(func.body.statements[0].kind, 'Scope');
@@ -171,7 +171,7 @@ Rule makeIdentity, produce Fn1:
171
171
  retType: Node.TypeName('List'),
172
172
  statements: [Node.Return(resultCall), Node.Return(listCall)],
173
173
  });
174
- const moduleAst = Node.Module('test.lowering.map_calls', [funcDecl]);
174
+ const moduleAst = Node.Module('test.lowering.map_calls', null, [funcDecl]);
175
175
  const core = lowerAst(moduleAst);
176
176
  const body = core.decls[0].body.statements;
177
177
  const resultExpr = body[0].expr;
@@ -184,7 +184,7 @@ Rule makeIdentity, produce Fn1:
184
184
  it('effectCaps 显式声明应完整传递', () => {
185
185
  const caps = [CapabilityKind.SECRETS];
186
186
  const funcDecl = Node.Func('readSecret', [], [], Node.TypeName('Text'), [], caps, true, Node.Block([Node.Return(Node.String('ok'))]));
187
- const moduleAst = Node.Module('test.lowering.effectcaps.explicit', [funcDecl]);
187
+ const moduleAst = Node.Module('test.lowering.effectcaps.explicit', null, [funcDecl]);
188
188
  const core = lowerAst(moduleAst);
189
189
  const func = core.decls[0];
190
190
  assert.deepEqual(func.effectCaps, caps);
@@ -194,7 +194,7 @@ Rule makeIdentity, produce Fn1:
194
194
  it('effectCaps 推断结果应保持并标记为隐式', () => {
195
195
  const caps = [CapabilityKind.FILES, CapabilityKind.TIME];
196
196
  const funcDecl = Node.Func('touchFile', [], [], Node.TypeName('Bool'), [], caps, false, Node.Block([Node.Return(Node.Bool(true))]));
197
- const moduleAst = Node.Module('test.lowering.effectcaps.implicit', [funcDecl]);
197
+ const moduleAst = Node.Module('test.lowering.effectcaps.implicit', null, [funcDecl]);
198
198
  const core = lowerAst(moduleAst);
199
199
  const func = core.decls[0];
200
200
  assert.deepEqual(func.effectCaps, caps);
@@ -203,7 +203,7 @@ Rule makeIdentity, produce Fn1:
203
203
  });
204
204
  it('未知 effect 应抛出诊断错误', () => {
205
205
  const funcDecl = Node.Func('useUnknownEffect', [], [], Node.TypeName('Int'), ['teleport'], [], false, Node.Block([Node.Return(Node.Int(1))]));
206
- const moduleAst = Node.Module('test.lowering.effectcaps.unknown', [funcDecl]);
206
+ const moduleAst = Node.Module('test.lowering.effectcaps.unknown', null, [funcDecl]);
207
207
  assert.throws(() => lowerAst(moduleAst), /Unknown effect/);
208
208
  });
209
209
  it('Set 语句应降级为 Core.Set 并保留表达式', () => {
@@ -217,7 +217,7 @@ Rule makeIdentity, produce Fn1:
217
217
  Node.Return(Node.Name('counter')),
218
218
  ],
219
219
  });
220
- const moduleAst = Node.Module('test.lowering.set.basic', [funcDecl]);
220
+ const moduleAst = Node.Module('test.lowering.set.basic', null, [funcDecl]);
221
221
  const core = lowerAst(moduleAst);
222
222
  const func = core.decls[0];
223
223
  const body = func.body.statements;
@@ -237,7 +237,7 @@ Rule makeIdentity, produce Fn1:
237
237
  Node.Return(Node.Name('a')),
238
238
  ],
239
239
  });
240
- const moduleAst = Node.Module('test.lowering.set.sequence', [funcDecl]);
240
+ const moduleAst = Node.Module('test.lowering.set.sequence', null, [funcDecl]);
241
241
  const core = lowerAst(moduleAst);
242
242
  const func = core.decls[0];
243
243
  const body = func.body.statements;
@@ -256,7 +256,7 @@ Rule makeIdentity, produce Fn1:
256
256
  retType: Node.TypeName('Int'),
257
257
  statements: [matchStmt],
258
258
  });
259
- const moduleAst = Node.Module('test.lowering.match.null', [funcDecl]);
259
+ const moduleAst = Node.Module('test.lowering.match.null', null, [funcDecl]);
260
260
  const core = lowerAst(moduleAst);
261
261
  const matchCore = (core.decls[0].body.statements[0]);
262
262
  assert.equal(matchCore.cases[0]?.pattern.kind, 'PatNull');
@@ -271,7 +271,7 @@ Rule makeIdentity, produce Fn1:
271
271
  retType: Node.TypeName('Int'),
272
272
  statements: [matchStmt],
273
273
  });
274
- const moduleAst = Node.Module('test.lowering.match.ctor', [funcDecl]);
274
+ const moduleAst = Node.Module('test.lowering.match.ctor', null, [funcDecl]);
275
275
  const core = lowerAst(moduleAst);
276
276
  const matchCore = (core.decls[0].body.statements[0]);
277
277
  const pat = matchCore.cases[0].pattern;
@@ -288,7 +288,7 @@ Rule makeIdentity, produce Fn1:
288
288
  retType: Node.TypeName('Text'),
289
289
  statements: [matchStmt],
290
290
  });
291
- const moduleAst = Node.Module('test.lowering.match.int', [funcDecl]);
291
+ const moduleAst = Node.Module('test.lowering.match.int', null, [funcDecl]);
292
292
  const core = lowerAst(moduleAst);
293
293
  const matchCore = (core.decls[0].body.statements[0]);
294
294
  const pat = matchCore.cases[0].pattern;
@@ -301,7 +301,7 @@ Rule makeIdentity, produce Fn1:
301
301
  retType: Node.TypeName('Result'),
302
302
  statements: [Node.Return(Node.Ok(Node.Int(1)))],
303
303
  });
304
- const moduleAst = Node.Module('test.lowering.expr.ok', [funcDecl]);
304
+ const moduleAst = Node.Module('test.lowering.expr.ok', null, [funcDecl]);
305
305
  const core = lowerAst(moduleAst);
306
306
  const retStmt = core.decls[0].body.statements[0];
307
307
  const expr = retStmt.expr;
@@ -314,7 +314,7 @@ Rule makeIdentity, produce Fn1:
314
314
  retType: Node.TypeName('Result'),
315
315
  statements: [Node.Return(Node.Err(Node.String('fail')))],
316
316
  });
317
- const moduleAst = Node.Module('test.lowering.expr.err', [funcDecl]);
317
+ const moduleAst = Node.Module('test.lowering.expr.err', null, [funcDecl]);
318
318
  const core = lowerAst(moduleAst);
319
319
  const retStmt = core.decls[0].body.statements[0];
320
320
  const expr = retStmt.expr;
@@ -327,7 +327,7 @@ Rule makeIdentity, produce Fn1:
327
327
  retType: Node.Maybe(Node.TypeName('Int')),
328
328
  statements: [Node.Return(Node.Some(Node.Int(7))), Node.Return(Node.None())],
329
329
  });
330
- const moduleAst = Node.Module('test.lowering.expr.option', [funcDecl]);
330
+ const moduleAst = Node.Module('test.lowering.expr.option', null, [funcDecl]);
331
331
  const core = lowerAst(moduleAst);
332
332
  const firstReturn = core.decls[0].body.statements[0];
333
333
  const secondReturn = core.decls[0].body.statements[1];
@@ -344,7 +344,7 @@ Rule makeIdentity, produce Fn1:
344
344
  retType: Node.TypeName('Int'),
345
345
  statements: [startStmt, Node.Return(Node.Int(0))],
346
346
  });
347
- const moduleAst = Node.Module('test.lowering.start', [funcDecl]);
347
+ const moduleAst = Node.Module('test.lowering.start', null, [funcDecl]);
348
348
  const core = lowerAst(moduleAst);
349
349
  const stmt = core.decls[0].body.statements[0];
350
350
  assert.equal(stmt.kind, 'Start');
@@ -358,7 +358,7 @@ Rule makeIdentity, produce Fn1:
358
358
  retType: Node.TypeName('Int'),
359
359
  statements: [waitStmt, Node.Return(Node.Int(1))],
360
360
  });
361
- const moduleAst = Node.Module('test.lowering.wait', [funcDecl]);
361
+ const moduleAst = Node.Module('test.lowering.wait', null, [funcDecl]);
362
362
  const core = lowerAst(moduleAst);
363
363
  const stmt = core.decls[0].body.statements[0];
364
364
  assert.equal(stmt.kind, 'Wait');
@@ -371,7 +371,7 @@ Rule makeIdentity, produce Fn1:
371
371
  retType: Node.TypeName('Null'),
372
372
  statements: [callStmt, Node.Return(Node.Null())],
373
373
  });
374
- const moduleAst = Node.Module('test.lowering.callStmt', [funcDecl]);
374
+ const moduleAst = Node.Module('test.lowering.callStmt', null, [funcDecl]);
375
375
  const core = lowerAst(moduleAst);
376
376
  const stmt = core.decls[0].body.statements[0];
377
377
  assert.equal(stmt.kind, 'Let');
@@ -387,7 +387,7 @@ Rule makeIdentity, produce Fn1:
387
387
  retType: Node.TypeName('Int'),
388
388
  statements: [ifStmt, Node.Return(Node.Int(0))],
389
389
  });
390
- const moduleAst = Node.Module('test.lowering.if.then', [funcDecl]);
390
+ const moduleAst = Node.Module('test.lowering.if.then', null, [funcDecl]);
391
391
  const core = lowerAst(moduleAst);
392
392
  const stmt = core.decls[0].body.statements[0];
393
393
  assert.equal(stmt.kind, 'If');
@@ -401,7 +401,7 @@ Rule makeIdentity, produce Fn1:
401
401
  retType: Node.TypeName('Int'),
402
402
  statements: [ifStmt, Node.Return(Node.Int(0))],
403
403
  });
404
- const moduleAst = Node.Module('test.lowering.if.else', [funcDecl]);
404
+ const moduleAst = Node.Module('test.lowering.if.else', null, [funcDecl]);
405
405
  const core = lowerAst(moduleAst);
406
406
  const stmt = core.decls[0].body.statements[0];
407
407
  assert.equal(stmt.elseBlock.statements[0]?.kind, 'Return');
@@ -416,7 +416,7 @@ Rule makeIdentity, produce Fn1:
416
416
  retType: Node.TypeName('Int'),
417
417
  statements: [scopeBlock],
418
418
  });
419
- const moduleAst = Node.Module('test.lowering.scope.single', [funcDecl]);
419
+ const moduleAst = Node.Module('test.lowering.scope.single', null, [funcDecl]);
420
420
  const core = lowerAst(moduleAst);
421
421
  const stmt = core.decls[0].body.statements[0];
422
422
  assert.equal(stmt.kind, 'Scope');
@@ -434,7 +434,7 @@ Rule makeIdentity, produce Fn1:
434
434
  retType: Node.TypeName('Int'),
435
435
  statements: [outer],
436
436
  });
437
- const moduleAst = Node.Module('test.lowering.scope.nested', [funcDecl]);
437
+ const moduleAst = Node.Module('test.lowering.scope.nested', null, [funcDecl]);
438
438
  const core = lowerAst(moduleAst);
439
439
  const scope = core.decls[0].body.statements[0];
440
440
  assert.equal(scope.kind, 'Scope');
@@ -450,7 +450,7 @@ Rule makeIdentity, produce Fn1:
450
450
  retType: Node.TypeName('Bool'),
451
451
  statements: [Node.Return(Node.Bool(true))],
452
452
  });
453
- const moduleAst = Node.Module('test.lowering.type.pii', [funcDecl]);
453
+ const moduleAst = Node.Module('test.lowering.type.pii', null, [funcDecl]);
454
454
  const core = lowerAst(moduleAst);
455
455
  const paramType = (core.decls[0].params[0]).type;
456
456
  assert.equal(paramType.kind, 'PiiType');
@@ -464,7 +464,7 @@ Rule makeIdentity, produce Fn1:
464
464
  Node.String('ok'),
465
465
  ])),
466
466
  ]));
467
- const moduleAst = Node.Module('test.lowering.func.pii', [funcDecl]);
467
+ const moduleAst = Node.Module('test.lowering.func.pii', null, [funcDecl]);
468
468
  const core = lowerAst(moduleAst);
469
469
  const func = core.decls[0];
470
470
  assert.equal(func.piiLevel, 'L2');
@@ -472,7 +472,7 @@ Rule makeIdentity, produce Fn1:
472
472
  });
473
473
  it('类型参数引用应降级为 Core.TypeVar', () => {
474
474
  const funcDecl = Node.Func('identity', ['T'], [makeParam('value', Node.TypeName('T'))], Node.TypeName('T'), [], [], false, Node.Block([Node.Return(Node.Name('value'))]));
475
- const moduleAst = Node.Module('test.lowering.type.var', [funcDecl]);
475
+ const moduleAst = Node.Module('test.lowering.type.var', null, [funcDecl]);
476
476
  const core = lowerAst(moduleAst);
477
477
  const func = core.decls[0];
478
478
  assert.equal(func.params[0].type.kind, 'TypeVar');
@@ -480,7 +480,7 @@ Rule makeIdentity, produce Fn1:
480
480
  });
481
481
  it('TypeApp 应降级并保留参数列表', () => {
482
482
  const funcDecl = Node.Func('getFuture', [], [], Node.TypeApp('Future', [Node.TypeName('Text'), Node.TypeName('Int')]), [], [], false, Node.Block([Node.Return(Node.Name('pending'))]));
483
- const moduleAst = Node.Module('test.lowering.type.app', [funcDecl]);
483
+ const moduleAst = Node.Module('test.lowering.type.app', null, [funcDecl]);
484
484
  const core = lowerAst(moduleAst);
485
485
  const ret = core.decls[0].ret;
486
486
  assert.equal(ret.kind, 'TypeApp');
@@ -496,7 +496,7 @@ Rule makeIdentity, produce Fn1:
496
496
  retType: Node.Maybe(Node.TypeName('Text')),
497
497
  statements: [Node.Return(Node.None())],
498
498
  });
499
- const moduleAst = Node.Module('test.lowering.type.option', [funcDecl]);
499
+ const moduleAst = Node.Module('test.lowering.type.option', null, [funcDecl]);
500
500
  const core = lowerAst(moduleAst);
501
501
  const paramType = (core.decls[0].params[0]).type;
502
502
  const ret = core.decls[0].ret;
@@ -511,7 +511,7 @@ Rule makeIdentity, produce Fn1:
511
511
  retType: Node.Result(Node.TypeName('Text'), Node.TypeName('Error')),
512
512
  statements: [Node.Return(Node.Ok(Node.String('ok')))],
513
513
  });
514
- const moduleAst = Node.Module('test.lowering.type.result', [funcDecl]);
514
+ const moduleAst = Node.Module('test.lowering.type.result', null, [funcDecl]);
515
515
  const core = lowerAst(moduleAst);
516
516
  const ret = core.decls[0].ret;
517
517
  assert.equal(ret.kind, 'Result');
@@ -519,7 +519,7 @@ Rule makeIdentity, produce Fn1:
519
519
  assert.equal(ret.err.kind, 'TypeName');
520
520
  });
521
521
  it('Import 声明应直接映射为 Core.Import', () => {
522
- const moduleAst = Node.Module('test.lowering.import', [
522
+ const moduleAst = Node.Module('test.lowering.import', null, [
523
523
  Node.Import('Http.Client', 'HttpClient'),
524
524
  ]);
525
525
  const core = lowerAst(moduleAst);
@@ -530,7 +530,7 @@ Rule makeIdentity, produce Fn1:
530
530
  assert.equal(Object.prototype.hasOwnProperty.call(decl, 'version'), false);
531
531
  });
532
532
  it('Import version 应映射为 Core.Import version', () => {
533
- const moduleAst = Node.Module('test.lowering.import.version', [
533
+ const moduleAst = Node.Module('test.lowering.import.version', null, [
534
534
  Node.Import('risk.Scoring', 'Score', 2),
535
535
  ]);
536
536
  const core = lowerAst(moduleAst);
@@ -552,7 +552,7 @@ Rule makeIdentity, produce Fn1:
552
552
  span: freshSpan(),
553
553
  };
554
554
  const dataDecl = Node.Data('User', [field]);
555
- const moduleAst = Node.Module('test.lowering.data.constraints', [dataDecl]);
555
+ const moduleAst = Node.Module('test.lowering.data.constraints', null, [dataDecl]);
556
556
  const core = lowerAst(moduleAst);
557
557
  const data = core.decls[0];
558
558
  assert.ok(data.fields[0].constraints, '应该存在 constraints');
@@ -582,7 +582,7 @@ Rule makeIdentity, produce Fn1:
582
582
  span: freshSpan(),
583
583
  };
584
584
  const dataDecl = Node.Data('Profile', [fieldWithConstraints, fieldWithoutConstraints]);
585
- const moduleAst = Node.Module('test.lowering.data.multi_constraints', [dataDecl]);
585
+ const moduleAst = Node.Module('test.lowering.data.multi_constraints', null, [dataDecl]);
586
586
  const core = lowerAst(moduleAst);
587
587
  const data = core.decls[0];
588
588
  assert.equal(data.fields[0].constraints.length, 2);
@@ -598,7 +598,7 @@ Rule makeIdentity, produce Fn1:
598
598
  retType: Node.TypeName('User'),
599
599
  statements: [Node.Return(construct)],
600
600
  });
601
- const moduleAst = Node.Module('test.lowering.construct', [funcDecl]);
601
+ const moduleAst = Node.Module('test.lowering.construct', null, [funcDecl]);
602
602
  const core = lowerAst(moduleAst);
603
603
  const expr = core.decls[0].body.statements[0]
604
604
  .expr;
@@ -613,7 +613,7 @@ Rule makeIdentity, produce Fn1:
613
613
  retType: Node.TypeName('Long'),
614
614
  statements: [Node.Return(Node.Long('1234567890123456789'))],
615
615
  });
616
- const moduleAst = Node.Module('test.lowering.long', [funcDecl]);
616
+ const moduleAst = Node.Module('test.lowering.long', null, [funcDecl]);
617
617
  const core = lowerAst(moduleAst);
618
618
  const retStmt = core.decls[0].body.statements[0];
619
619
  const expr = retStmt.expr;
@@ -626,7 +626,7 @@ Rule makeIdentity, produce Fn1:
626
626
  retType: Node.TypeName('Double'),
627
627
  statements: [Node.Return(Node.Double(3.14))],
628
628
  });
629
- const moduleAst = Node.Module('test.lowering.double', [funcDecl]);
629
+ const moduleAst = Node.Module('test.lowering.double', null, [funcDecl]);
630
630
  const core = lowerAst(moduleAst);
631
631
  const retStmt = core.decls[0].body.statements[0];
632
632
  const expr = retStmt.expr;