freelang-editor 11.7.4

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 (1473) hide show
  1. package/.config/jest.config.js +47 -0
  2. package/.config/jest.fast.config.js +9 -0
  3. package/.config/openapi.yaml +457 -0
  4. package/.config/tsconfig.json +30 -0
  5. package/.github/CODE_OF_CONDUCT.md +176 -0
  6. package/.github/CONTRIBUTING.md +296 -0
  7. package/.github/DISCUSSIONS.md +179 -0
  8. package/.github/ISSUE_TEMPLATE/bug-report.md +44 -0
  9. package/.github/ISSUE_TEMPLATE/feature-request.md +39 -0
  10. package/.github/pull_request_template.md +87 -0
  11. package/.github/workflows/phase-3c-l2-proof.yml +101 -0
  12. package/.github/workflows/phase-c-full-slack.yml +409 -0
  13. package/.github/workflows/phase-c-full.yml +241 -0
  14. package/.github/workflows/phase-c-scan.yml +64 -0
  15. package/.gitmodules +3 -0
  16. package/.tmp.js +3 -0
  17. package/CHANGELOG.md +1182 -0
  18. package/CLAUDE.md +633 -0
  19. package/Dockerfile +3 -0
  20. package/LICENSE +21 -0
  21. package/MISTAKES-COVERAGE.json +115 -0
  22. package/Makefile +95 -0
  23. package/PHASE-F-ROADMAP.md +554 -0
  24. package/README.md +459 -0
  25. package/SELF_HOSTING_CHECKLIST.md +155 -0
  26. package/benchmark-freelang.fl +47 -0
  27. package/benchmark-results.json +37 -0
  28. package/benchmark-simple.fl +38 -0
  29. package/bin/freelang-migrate +310 -0
  30. package/bin/freelang-smart +258 -0
  31. package/bootstrap.js +1134 -0
  32. package/docker-compose.yml +3 -0
  33. package/docs/AI_FRIENDLINESS.md +181 -0
  34. package/docs/AI_LEARNING_PATH.md +542 -0
  35. package/docs/AI_MAINTENANCE.md +153 -0
  36. package/docs/AI_QUICKSTART.md +380 -0
  37. package/docs/AI_REFERENCE.md +559 -0
  38. package/docs/AI_RELIABILITY_GUIDE.md +597 -0
  39. package/docs/AKL_ARCHITECTURE.md +228 -0
  40. package/docs/AKL_P0_KIMDB.md +215 -0
  41. package/docs/API.md +380 -0
  42. package/docs/ARCHITECTURE.md +208 -0
  43. package/docs/CHANGELOG.md +1014 -0
  44. package/docs/CLAUDE.md +991 -0
  45. package/docs/CLAUDE_AI.md +210 -0
  46. package/docs/CODEGEN_IMPROVEMENTS.md +158 -0
  47. package/docs/CODE_OF_CONDUCT.md +337 -0
  48. package/docs/CONTRIBUTING.md +437 -0
  49. package/docs/CRON_AUTOMATION.md +97 -0
  50. package/docs/DEPLOYMENT.md +357 -0
  51. package/docs/DETERMINISM_GUIDE.md +174 -0
  52. package/docs/HUMAN_GUIDE.md +599 -0
  53. package/docs/INDEX.md +199 -0
  54. package/docs/INLINE_TEST_GUIDE.md +231 -0
  55. package/docs/LANGUAGE-FAULTS.md +583 -0
  56. package/docs/LANGUAGE_IMPROVEMENT_REQUESTS.md +187 -0
  57. package/docs/LEARNING.md +257 -0
  58. package/docs/MISTAKES-100.md +52 -0
  59. package/docs/MISTAKES.md +131 -0
  60. package/docs/NAMING_CONVENTIONS.md +158 -0
  61. package/docs/NIGHTLY-MONITORING.md +222 -0
  62. package/docs/OFFICIAL_LANGUAGE.md +249 -0
  63. package/docs/ONBOARDING_1HOUR.md +210 -0
  64. package/docs/PERFORMANCE.md +329 -0
  65. package/docs/PHASE-3C-L2-PROOF-PLAN.md +282 -0
  66. package/docs/PHASE-3C-L2-RESULTS.md +183 -0
  67. package/docs/PHASE-3D-AI-LIBRARY.md +170 -0
  68. package/docs/PHASE-3E-VM-OPTIMIZATION.md +192 -0
  69. package/docs/PHASE-C-CI.md +242 -0
  70. package/docs/PHASE-C-PR-CHECKLIST.md +267 -0
  71. package/docs/PHASE-C-ROADMAP.md +141 -0
  72. package/docs/PHASE-C-SCAN.md +205 -0
  73. package/docs/PHASE-G-ROADMAP.md +228 -0
  74. package/docs/PHASE-X-V11.5-ROADMAP.md +267 -0
  75. package/docs/PHASE4_IMPLEMENTATION_PLAN.md +290 -0
  76. package/docs/PHASE5-COMPLETION.md +186 -0
  77. package/docs/PHASE5-SUMMARY.md +82 -0
  78. package/docs/PLUGIN_GUIDE.md +241 -0
  79. package/docs/PROJECT_OVERVIEW_KO.md +66 -0
  80. package/docs/QUICKSTART.md +160 -0
  81. package/docs/README.md +192 -0
  82. package/docs/RESERVED.md +125 -0
  83. package/docs/ROADMAP.md +191 -0
  84. package/docs/SECURITY.md +518 -0
  85. package/docs/SETUP.md +127 -0
  86. package/docs/SLACK-SETUP.md +190 -0
  87. package/docs/STATE_OF_V11.md +74 -0
  88. package/docs/STDLIB_NAMING_AUDIT.md +154 -0
  89. package/docs/STDLIB_REFERENCE.md +2722 -0
  90. package/docs/STYLE_GUIDE.md +559 -0
  91. package/docs/TASK5-MAP-DESTRUCTURE-DESIGN.md +136 -0
  92. package/docs/TOOLS.md +357 -0
  93. package/docs/TYPE_SYSTEM_GUIDE.md +201 -0
  94. package/docs/UI-PATTERN.md +265 -0
  95. package/docs/V11.5-RULES.md +416 -0
  96. package/docs/V11.6-HARNESS-RULES.md +222 -0
  97. package/docs/V11.6-MULTI-AGENT-PLAN.md +265 -0
  98. package/docs/V11.6-STABILIZATION-PLAN.md +290 -0
  99. package/docs/Y4-2B_DRY_RUN.md +142 -0
  100. package/docs/_classifications.json +882 -0
  101. package/docs/api/stdlib.md +134 -0
  102. package/docs/blog/2026-04-17-v11-ai-first-evolution.md +223 -0
  103. package/docs/blog/2026-04-20-self-hosting-fixedpoint.md +269 -0
  104. package/docs/blog/2026-05-04-mistakes-are-language-faults.md +267 -0
  105. package/docs/blog/2026-05-04-mistakes-coverage-honest.md +170 -0
  106. package/docs/blog/2026-05-04-phase-g-followup-smart-wrapper.md +188 -0
  107. package/docs/blog/2026-05-04-phase-g-mistakes-100.md +269 -0
  108. package/docs/blog/2026-05-04-phase-x-v11.5-launch.md +224 -0
  109. package/docs/blog/2026-05-04-v11.5.0-real-language-change.md +252 -0
  110. package/docs/blog-demo/README.md +44 -0
  111. package/docs/examples/index.md +78 -0
  112. package/docs/examples/todo-app.md +99 -0
  113. package/docs/guide/ai-blocks.md +335 -0
  114. package/docs/guide/basics.md +235 -0
  115. package/docs/guide/frameworks.md +319 -0
  116. package/docs/homepage/README.md +164 -0
  117. package/docs/index.md +183 -0
  118. package/docs/v12-DESIGN.md +214 -0
  119. package/examples/README.md +26 -0
  120. package/examples/browser-test.html +149 -0
  121. package/examples/csv-tool/analyze.fl +222 -0
  122. package/examples/csv-tool/employees.csv +16 -0
  123. package/examples/csv-tool/products.csv +21 -0
  124. package/examples/factorial.fl +9 -0
  125. package/examples/fib30.fl +4 -0
  126. package/examples/hello.fl +2 -0
  127. package/examples/hello.fl.js +3 -0
  128. package/examples/learning-session/01-grade-stats.fl +49 -0
  129. package/examples/learning-session/02-class-stats.fl +52 -0
  130. package/examples/learning-session/03-cart.fl +61 -0
  131. package/examples/learning-session/04-word-freq.fl +57 -0
  132. package/examples/learning-session/05-todo.fl +69 -0
  133. package/examples/learning-session/06-library.fl +76 -0
  134. package/examples/learning-session/07-currency.fl +99 -0
  135. package/examples/learning-session/08-csv-grades.fl +104 -0
  136. package/examples/learning-session/09-calc-repl.fl +92 -0
  137. package/examples/learning-session/10-contacts.fl +109 -0
  138. package/examples/learning-session/11-markdown.fl +107 -0
  139. package/examples/learning-session/12-calendar.fl +87 -0
  140. package/examples/learning-session/13-statistics.fl +123 -0
  141. package/examples/learning-session/14-primes.fl +107 -0
  142. package/examples/learning-session/15-statistics.fl +123 -0
  143. package/examples/learning-session/16-calendar.fl +87 -0
  144. package/examples/learning-session/17-markdown.fl +107 -0
  145. package/examples/learning-session/18-contacts.fl +109 -0
  146. package/examples/learning-session/19-json-serializer.fl +86 -0
  147. package/examples/learning-session/20-template.fl +201 -0
  148. package/examples/learning-session/21-calc-parser.fl +148 -0
  149. package/examples/learning-session/22-table.fl +96 -0
  150. package/examples/patterns/01-map-filter-reduce.fl +50 -0
  151. package/examples/patterns/02-error-handling.fl +51 -0
  152. package/examples/patterns/03-type-validation.fl +57 -0
  153. package/examples/patterns/04-state-management.fl +44 -0
  154. package/examples/patterns/05-api-integration.fl +95 -0
  155. package/examples/patterns/06-database-operations.fl +113 -0
  156. package/examples/patterns/07-string-processing.fl +86 -0
  157. package/examples/patterns/08-data-transformation.fl +92 -0
  158. package/examples/patterns/09-decision-logic.fl +122 -0
  159. package/examples/patterns/10-agent-orchestration.fl +184 -0
  160. package/examples/patterns/README.md +344 -0
  161. package/examples/simple-server.fl +29 -0
  162. package/examples/tables-app.fl +219 -0
  163. package/examples/test-libs.fl +272 -0
  164. package/jest.config.js +4 -0
  165. package/lib/datetime.fl +123 -0
  166. package/lib/http-client.fl +129 -0
  167. package/lib/pipeline.fl +150 -0
  168. package/lib/query.fl +160 -0
  169. package/lib/result.fl +124 -0
  170. package/lib/template.fl +161 -0
  171. package/lib/validate.fl +136 -0
  172. package/package.json +58 -0
  173. package/scripts/ai-eval.js +318 -0
  174. package/scripts/ai-self-verify.js +200 -0
  175. package/scripts/ai-validate.js +302 -0
  176. package/scripts/bench.sh +71 -0
  177. package/scripts/benchmark.js +258 -0
  178. package/scripts/benchmark.sh +99 -0
  179. package/scripts/build-binary.sh +68 -0
  180. package/scripts/build-runtime.sh +46 -0
  181. package/scripts/build-stage1-final.sh +58 -0
  182. package/scripts/build-stage1.sh +119 -0
  183. package/scripts/build-standalone.sh +17 -0
  184. package/scripts/build.js +130 -0
  185. package/scripts/check-let-regressions.js +95 -0
  186. package/scripts/check-parens.py +117 -0
  187. package/scripts/check-ports.sh +49 -0
  188. package/scripts/check-syntax.js +30 -0
  189. package/scripts/cli-extras.js +135 -0
  190. package/scripts/cron-daily-verify.sh +101 -0
  191. package/scripts/deploy.sh +91 -0
  192. package/scripts/dev.sh +37 -0
  193. package/scripts/extract-fl-examples.js +29 -0
  194. package/scripts/extract-runtime-helpers.js +122 -0
  195. package/scripts/fl-compile.sh +14 -0
  196. package/scripts/fl-fixpoint.sh +28 -0
  197. package/scripts/fl-repl.sh +21 -0
  198. package/scripts/fl-run.sh +41 -0
  199. package/scripts/fl-serve.sh +25 -0
  200. package/scripts/fuzz-compiler.js +92 -0
  201. package/scripts/gen-ai-prompt.js +340 -0
  202. package/scripts/gen-fixtures.js +166 -0
  203. package/scripts/gen-mistakes-split.js +199 -0
  204. package/scripts/gen-stdlib-docs.js +69 -0
  205. package/scripts/lint-stdlib-aliases.js +166 -0
  206. package/scripts/measure-baseline.sh +43 -0
  207. package/scripts/property-test.js +885 -0
  208. package/scripts/push-to-gogs.sh +60 -0
  209. package/scripts/regression-scan.js +132 -0
  210. package/scripts/run-jest-shard.sh +85 -0
  211. package/scripts/safe-push.sh +37 -0
  212. package/scripts/scan-fl-tokens.js +170 -0
  213. package/scripts/scan-for-fl-tokens.sh +17 -0
  214. package/scripts/self-diff.sh +95 -0
  215. package/scripts/snapshot-v0.sh +35 -0
  216. package/scripts/test-l2-fixpoint.sh +54 -0
  217. package/scripts/verify-all.sh +130 -0
  218. package/scripts/verify-build-deterministic.sh +110 -0
  219. package/scripts/verify-c7-bootstrap.sh +150 -0
  220. package/scripts/verify-c8-fixed-point-simple.sh +121 -0
  221. package/scripts/verify-c8-fixed-point.sh +133 -0
  222. package/scripts/verify-c9-fuzzing.sh +214 -0
  223. package/scripts/verify-fixed-point-deep.sh +133 -0
  224. package/scripts/verify-fixed-point.sh +65 -0
  225. package/scripts/verify-l2-proof.sh +153 -0
  226. package/scripts/verify-l3-proof.sh +40 -0
  227. package/scripts/verify-mistakes-coverage.js +120 -0
  228. package/scripts/verify-self-host.sh +509 -0
  229. package/self/CHANGELOG.md +964 -0
  230. package/self/COMPILER_REDESIGN_FAILURES.md +59 -0
  231. package/self/INTEGRATION-CHECKLIST.md +113 -0
  232. package/self/README.md +34 -0
  233. package/self/all.fl +1353 -0
  234. package/self/ast.fl +219 -0
  235. package/self/ast.self.js +47 -0
  236. package/self/bench/_bi_json-parse.js +46 -0
  237. package/self/bench/_bi_json-str.js +60 -0
  238. package/self/bench/_bi_list-distinct.js +37 -0
  239. package/self/bench/_bi_list-filter-even.js +56 -0
  240. package/self/bench/_bi_list-first.js +29 -0
  241. package/self/bench/_bi_list-last.js +28 -0
  242. package/self/bench/_bi_list-map-inc.js +41 -0
  243. package/self/bench/_bi_list-range.js +22 -0
  244. package/self/bench/_bi_list-reduce-sum.js +50 -0
  245. package/self/bench/_bi_list-reverse.js +28 -0
  246. package/self/bench/_bi_list-sort.js +35 -0
  247. package/self/bench/_bi_list-take.js +36 -0
  248. package/self/bench/_bi_m-abs.js +24 -0
  249. package/self/bench/_bi_m-floor.js +22 -0
  250. package/self/bench/_bi_m-max.js +26 -0
  251. package/self/bench/_bi_m-min.js +26 -0
  252. package/self/bench/_bi_m-mod.js +21 -0
  253. package/self/bench/_bi_map-has.js +50 -0
  254. package/self/bench/_bi_map-keys.js +50 -0
  255. package/self/bench/_bi_map-values.js +52 -0
  256. package/self/bench/_bi_str-concat.js +36 -0
  257. package/self/bench/_bi_str-contains.js +43 -0
  258. package/self/bench/_bi_str-ends.js +45 -0
  259. package/self/bench/_bi_str-index.js +34 -0
  260. package/self/bench/_bi_str-lower.js +23 -0
  261. package/self/bench/_bi_str-repeat.js +26 -0
  262. package/self/bench/_bi_str-split.js +41 -0
  263. package/self/bench/_bi_str-starts.js +47 -0
  264. package/self/bench/_bi_str-trim.js +26 -0
  265. package/self/bench/_bi_str-upper.js +23 -0
  266. package/self/bench/_bi_t-list.js +24 -0
  267. package/self/bench/_bi_t-null.js +23 -0
  268. package/self/bench/_bi_t-number.js +23 -0
  269. package/self/bench/_bi_t-string.js +25 -0
  270. package/self/bench/_bi_t-typeof.js +25 -0
  271. package/self/bench/_c_parse_probe.fl +426 -0
  272. package/self/bench/_c_parse_probe.js +67 -0
  273. package/self/bench/_codegen_nodrv.fl +751 -0
  274. package/self/bench/_combined2.fl +423 -0
  275. package/self/bench/_combined_arr.fl +422 -0
  276. package/self/bench/_combined_astprobe.fl +429 -0
  277. package/self/bench/_combined_astprobe.js +69 -0
  278. package/self/bench/_combined_cg.fl +424 -0
  279. package/self/bench/_combined_cg.js +64 -0
  280. package/self/bench/_combined_lex.fl +421 -0
  281. package/self/bench/_combined_trace.fl +435 -0
  282. package/self/bench/_combined_trace.js +75 -0
  283. package/self/bench/_ext_abs-neg.js +2 -0
  284. package/self/bench/_ext_and.js +2 -0
  285. package/self/bench/_ext_cond-1.js +2 -0
  286. package/self/bench/_ext_cond-2.js +2 -0
  287. package/self/bench/_ext_do-seq.js +2 -0
  288. package/self/bench/_ext_fact20.js +3 -0
  289. package/self/bench/_ext_fib25.js +3 -0
  290. package/self/bench/_ext_length.js +2 -0
  291. package/self/bench/_ext_let-1d.js +18 -0
  292. package/self/bench/_ext_let-2d.js +2 -0
  293. package/self/bench/_ext_list-sum.js +3 -0
  294. package/self/bench/_ext_math.js +2 -0
  295. package/self/bench/_ext_or.js +2 -0
  296. package/self/bench/_ext_str.js +2 -0
  297. package/self/bench/_fact15.js +2 -0
  298. package/self/bench/_fb_fact15.js +2 -0
  299. package/self/bench/_fb_func-fact.js +2 -0
  300. package/self/bench/_fb_func-multi.js +2 -0
  301. package/self/bench/_fb_func-mutual.js +3 -0
  302. package/self/bench/_fb_func-simple.js +21 -0
  303. package/self/bench/_fib.js +2 -0
  304. package/self/bench/_fn_async-await-seq.js +40 -0
  305. package/self/bench/_fn_async-await.js +3 -0
  306. package/self/bench/_fn_async-print.js +26 -0
  307. package/self/bench/_fn_async-result.js +1 -0
  308. package/self/bench/_fn_call-form.js +24 -0
  309. package/self/bench/_fn_compose.js +37 -0
  310. package/self/bench/_fn_pipe.js +34 -0
  311. package/self/bench/_fn_thread-first-sexpr.js +31 -0
  312. package/self/bench/_fn_thread-first.js +25 -0
  313. package/self/bench/_fn_thread-last.js +31 -0
  314. package/self/bench/_generated.js +35 -0
  315. package/self/bench/_mt_match-default.js +51 -0
  316. package/self/bench/_mt_match-num.js +58 -0
  317. package/self/bench/_mt_match-str.js +56 -0
  318. package/self/bench/_mt_match-var.js +32 -0
  319. package/self/bench/_mt_match-wild.js +36 -0
  320. package/self/bench/_mt_struct-make.js +81 -0
  321. package/self/bench/_mt_struct-tag.js +81 -0
  322. package/self/bench/_probe.fl +1 -0
  323. package/self/bench/_probe2.fl +1 -0
  324. package/self/bench/_probe3.fl +3 -0
  325. package/self/bench/_probe_apply.fl +1 -0
  326. package/self/bench/_probe_args.fl +7 -0
  327. package/self/bench/_probe_arr.fl +7 -0
  328. package/self/bench/_probe_arr2.fl +5 -0
  329. package/self/bench/_probe_block.fl +7 -0
  330. package/self/bench/_probe_call.fl +1 -0
  331. package/self/bench/_probe_cg.fl +27 -0
  332. package/self/bench/_probe_compose.fl +13 -0
  333. package/self/bench/_probe_define.fl +1 -0
  334. package/self/bench/_probe_keys.fl +5 -0
  335. package/self/bench/_probe_length.fl +5 -0
  336. package/self/bench/_probe_lexparse.fl +4 -0
  337. package/self/bench/_probe_loop.fl +12 -0
  338. package/self/bench/_probe_map.fl +8 -0
  339. package/self/bench/_probe_map2.fl +8 -0
  340. package/self/bench/_probe_map3.fl +5 -0
  341. package/self/bench/_probe_mapkeys.fl +5 -0
  342. package/self/bench/_probe_mapv12.fl +1 -0
  343. package/self/bench/_probe_mapv12.js +2 -0
  344. package/self/bench/_probe_match.fl +1 -0
  345. package/self/bench/_probe_match2.fl +1 -0
  346. package/self/bench/_probe_neg.fl +7 -0
  347. package/self/bench/_probe_neg2.fl +3 -0
  348. package/self/bench/_probe_protocol.fl +7 -0
  349. package/self/bench/_probe_self_parse.fl +6 -0
  350. package/self/bench/_probe_struct.fl +1 -0
  351. package/self/bench/_probe_true.fl +3 -0
  352. package/self/bench/_probe_true2.fl +6 -0
  353. package/self/bench/_probe_v12_cg.fl +7 -0
  354. package/self/bench/_probe_v12_extract.fl +8 -0
  355. package/self/bench/_probe_v12_extract.js +7 -0
  356. package/self/bench/_probe_v12_internal.fl +21 -0
  357. package/self/bench/_probe_v12_map_ast.fl +12 -0
  358. package/self/bench/_rs_combo.js +3 -0
  359. package/self/bench/_rs_gcd.js +36 -0
  360. package/self/bench/_rs_grade.js +2 -0
  361. package/self/bench/_rs_mutual-fib.js +2 -0
  362. package/self/bench/_rs_range-sum.js +2 -0
  363. package/self/bench/_rs_sum-10k.js +2 -0
  364. package/self/bench/_rs_sum-5k.js +2 -0
  365. package/self/bench/_sf_loop-fact-10.js +73 -0
  366. package/self/bench/_sf_loop-sum-10k.js +87 -0
  367. package/self/bench/_sf_set-x.js +40 -0
  368. package/self/bench/_sf_throw-catch.js +1 -0
  369. package/self/bench/_sf_while-5.js +62 -0
  370. package/self/bench/_v12_combined.fl +1184 -0
  371. package/self/bench/_v12_extract_test.fl +14 -0
  372. package/self/bench/_v12_extract_test.js +7 -0
  373. package/self/bench/_v12_inspect.js +26 -0
  374. package/self/bench/_v12_inspect_mod.js +137 -0
  375. package/self/bench/_v12_makevartest.fl +8 -0
  376. package/self/bench/_v12_makevartest.js +6 -0
  377. package/self/bench/_v12_parse_probe.fl +9 -0
  378. package/self/bench/_v12_parse_trace.fl +18 -0
  379. package/self/bench/_v12_simple_fn.fl +2 -0
  380. package/self/bench/_v12_simple_fn.js +3 -0
  381. package/self/bench/_v12_trace.fl +2 -0
  382. package/self/bench/_v12_trace.js +3 -0
  383. package/self/bench/collection.js +13 -0
  384. package/self/bench/fib30.fl +4 -0
  385. package/self/bench/final-test.fl +12 -0
  386. package/self/bench/final-test.js +2 -0
  387. package/self/bench/fp1-v12.js +4 -0
  388. package/self/bench/fp1.fl +3 -0
  389. package/self/bench/fp1.fp.js +4 -0
  390. package/self/bench/fp2-v12.js +4 -0
  391. package/self/bench/fp2.fl +3 -0
  392. package/self/bench/fp2.fp.js +4 -0
  393. package/self/bench/fp3-v12.js +8 -0
  394. package/self/bench/fp3.fl +11 -0
  395. package/self/bench/fp3.fp.js +8 -0
  396. package/self/bench/fp4-v12.js +6 -0
  397. package/self/bench/fp4.fl +9 -0
  398. package/self/bench/fp4.fp.js +6 -0
  399. package/self/bench/hello-sample.fl +3 -0
  400. package/self/bench/hello-sample.js +4 -0
  401. package/self/bench/hello.fl +1 -0
  402. package/self/bench/json.js +9 -0
  403. package/self/bench/json1mb.fl +3 -0
  404. package/self/bench/math.js +8 -0
  405. package/self/bench/realworld.fl +17 -0
  406. package/self/bench/realworld.js +8 -0
  407. package/self/bench/regex.js +10 -0
  408. package/self/bench/sample.json +1 -0
  409. package/self/bench/string.js +7 -0
  410. package/self/bench/test-ffi.fl +3 -0
  411. package/self/bench/test-ffi.js +2 -0
  412. package/self/bench/test-hof-advanced.fl +7 -0
  413. package/self/bench/test-hof-advanced.js +2 -0
  414. package/self/bench/test-hof.fl +5 -0
  415. package/self/bench/test-hof.js +2 -0
  416. package/self/bench/test-output.txt +1 -0
  417. package/self/bench/test-phase15-integration.fl +16 -0
  418. package/self/bench/test-phase15-integration.js +3 -0
  419. package/self/bench/test-phase19-complete.fl +24 -0
  420. package/self/bench/test-phase19-complete.js +2 -0
  421. package/self/bench/test-stdlib-codegen.fl +9 -0
  422. package/self/bench/test-stdlib-codegen.js +2 -0
  423. package/self/bench/test-time.fl +8 -0
  424. package/self/bench/test-time.js +2 -0
  425. package/self/bench/time.js +9 -0
  426. package/self/bench/tiny-v12.js +2 -0
  427. package/self/bench/tiny.fl +1 -0
  428. package/self/builtins/core.fl +150 -0
  429. package/self/char-class.fl +45 -0
  430. package/self/codegen-core.fl +733 -0
  431. package/self/codegen-final.fl +135 -0
  432. package/self/codegen.fl +379 -0
  433. package/self/codegen.fl.bak +856 -0
  434. package/self/codegen.self.js +75 -0
  435. package/self/examples/agent-loop.fl +32 -0
  436. package/self/examples/ci-cd-example.fl +114 -0
  437. package/self/examples/cloud-real.fl +134 -0
  438. package/self/examples/docker-example.fl +67 -0
  439. package/self/examples/fullstack-app.fl +330 -0
  440. package/self/examples/k8s-example.fl +91 -0
  441. package/self/examples/microservices.fl +448 -0
  442. package/self/examples/rest-api.fl +253 -0
  443. package/self/examples/style-example.fl +133 -0
  444. package/self/examples/workflow-orchestration.fl +44 -0
  445. package/self/fixtures/eval/add.fl +1 -0
  446. package/self/fixtures/eval/and-sc.fl +1 -0
  447. package/self/fixtures/eval/bool-false.fl +1 -0
  448. package/self/fixtures/eval/bool-true.fl +1 -0
  449. package/self/fixtures/eval/closure.fl +1 -0
  450. package/self/fixtures/eval/cmp-eq.fl +1 -0
  451. package/self/fixtures/eval/cmp-lt.fl +1 -0
  452. package/self/fixtures/eval/cond-first.fl +1 -0
  453. package/self/fixtures/eval/define-fn3.fl +1 -0
  454. package/self/fixtures/eval/define-var.fl +1 -0
  455. package/self/fixtures/eval/defn-bare.fl +1 -0
  456. package/self/fixtures/eval/defn-call.fl +1 -0
  457. package/self/fixtures/eval/div.fl +1 -0
  458. package/self/fixtures/eval/filter-hof.fl +1 -0
  459. package/self/fixtures/eval/floor.fl +1 -0
  460. package/self/fixtures/eval/fn-apply.fl +1 -0
  461. package/self/fixtures/eval/get-idx.fl +1 -0
  462. package/self/fixtures/eval/get-key.fl +1 -0
  463. package/self/fixtures/eval/higher-order.fl +1 -0
  464. package/self/fixtures/eval/let-bare.fl +1 -0
  465. package/self/fixtures/eval/let-flat.fl +1 -0
  466. package/self/fixtures/eval/let-use.fl +1 -0
  467. package/self/fixtures/eval/list-first.fl +1 -0
  468. package/self/fixtures/eval/list-last.fl +1 -0
  469. package/self/fixtures/eval/list-len.fl +1 -0
  470. package/self/fixtures/eval/map-hof.fl +1 -0
  471. package/self/fixtures/eval/mod.fl +1 -0
  472. package/self/fixtures/eval/mul-nested.fl +1 -0
  473. package/self/fixtures/eval/not.fl +1 -0
  474. package/self/fixtures/eval/null-p.fl +1 -0
  475. package/self/fixtures/eval/or-sc.fl +1 -0
  476. package/self/fixtures/eval/pow.fl +1 -0
  477. package/self/fixtures/eval/recursion.fl +1 -0
  478. package/self/fixtures/eval/reduce-hof.fl +1 -0
  479. package/self/fixtures/eval/replace.fl +1 -0
  480. package/self/fixtures/eval/sqrt.fl +1 -0
  481. package/self/fixtures/eval/str-concat.fl +1 -0
  482. package/self/fixtures/eval/str-num.fl +1 -0
  483. package/self/fixtures/eval/sub.fl +1 -0
  484. package/self/fixtures/eval/substring.fl +1 -0
  485. package/self/fixtures/lex/array.fl +1 -0
  486. package/self/fixtures/lex/at-atom.fl +1 -0
  487. package/self/fixtures/lex/block.fl +1 -0
  488. package/self/fixtures/lex/comment.fl +2 -0
  489. package/self/fixtures/lex/deep-array.fl +1 -0
  490. package/self/fixtures/lex/deep-map.fl +1 -0
  491. package/self/fixtures/lex/deep-nest.fl +1 -0
  492. package/self/fixtures/lex/dollar-dot.fl +1 -0
  493. package/self/fixtures/lex/empty-list.fl +1 -0
  494. package/self/fixtures/lex/empty-str.fl +1 -0
  495. package/self/fixtures/lex/empty.fl +1 -0
  496. package/self/fixtures/lex/float.fl +1 -0
  497. package/self/fixtures/lex/hex.fl +1 -0
  498. package/self/fixtures/lex/kebab-sym.fl +1 -0
  499. package/self/fixtures/lex/keyword.fl +1 -0
  500. package/self/fixtures/lex/leading-zero.fl +1 -0
  501. package/self/fixtures/lex/long-num.fl +1 -0
  502. package/self/fixtures/lex/many-args.fl +1 -0
  503. package/self/fixtures/lex/map.fl +1 -0
  504. package/self/fixtures/lex/mixed.fl +1 -0
  505. package/self/fixtures/lex/neg-float.fl +1 -0
  506. package/self/fixtures/lex/negative.fl +1 -0
  507. package/self/fixtures/lex/nested.fl +1 -0
  508. package/self/fixtures/lex/null.fl +1 -0
  509. package/self/fixtures/lex/pipe-op.fl +1 -0
  510. package/self/fixtures/lex/route-like.fl +1 -0
  511. package/self/fixtures/lex/scientific.fl +1 -0
  512. package/self/fixtures/lex/single-num.fl +1 -0
  513. package/self/fixtures/lex/small-sexpr.fl +1 -0
  514. package/self/fixtures/lex/spaces.fl +1 -0
  515. package/self/fixtures/lex/str-quote.fl +1 -0
  516. package/self/fixtures/lex/str-tab.fl +1 -0
  517. package/self/fixtures/lex/string-esc.fl +1 -0
  518. package/self/fixtures/lex/string.fl +1 -0
  519. package/self/fixtures/lex/symbol.fl +1 -0
  520. package/self/fixtures/lex/tabs-nl.fl +3 -0
  521. package/self/fixtures/lex/true-false.fl +1 -0
  522. package/self/fixtures/lex/unicode.fl +1 -0
  523. package/self/fixtures/lex/variable.fl +1 -0
  524. package/self/fixtures/lex/zero.fl +1 -0
  525. package/self/fixtures/parse/and-or.fl +1 -0
  526. package/self/fixtures/parse/array-lit.fl +1 -0
  527. package/self/fixtures/parse/block-func.fl +1 -0
  528. package/self/fixtures/parse/compose.fl +1 -0
  529. package/self/fixtures/parse/cond.fl +1 -0
  530. package/self/fixtures/parse/define-fn.fl +1 -0
  531. package/self/fixtures/parse/define-val.fl +1 -0
  532. package/self/fixtures/parse/defn.fl +1 -0
  533. package/self/fixtures/parse/do-begin.fl +1 -0
  534. package/self/fixtures/parse/dotted.fl +1 -0
  535. package/self/fixtures/parse/empty-fn.fl +1 -0
  536. package/self/fixtures/parse/empty-list.fl +1 -0
  537. package/self/fixtures/parse/fn.fl +1 -0
  538. package/self/fixtures/parse/if-else.fl +1 -0
  539. package/self/fixtures/parse/if-only.fl +1 -0
  540. package/self/fixtures/parse/keyword-arg.fl +1 -0
  541. package/self/fixtures/parse/kw.fl +1 -0
  542. package/self/fixtures/parse/let-1d.fl +1 -0
  543. package/self/fixtures/parse/let-2d.fl +1 -0
  544. package/self/fixtures/parse/let-bare.fl +1 -0
  545. package/self/fixtures/parse/literal-num.fl +1 -0
  546. package/self/fixtures/parse/literal-str.fl +1 -0
  547. package/self/fixtures/parse/loop-recur.fl +1 -0
  548. package/self/fixtures/parse/map-lit.fl +1 -0
  549. package/self/fixtures/parse/match-simple.fl +1 -0
  550. package/self/fixtures/parse/multi-body.fl +1 -0
  551. package/self/fixtures/parse/nested-arr.fl +1 -0
  552. package/self/fixtures/parse/nested-block.fl +1 -0
  553. package/self/fixtures/parse/nested-map.fl +1 -0
  554. package/self/fixtures/parse/nested.fl +1 -0
  555. package/self/fixtures/parse/pipe.fl +1 -0
  556. package/self/fixtures/parse/quote.fl +1 -0
  557. package/self/fixtures/parse/set-bang.fl +1 -0
  558. package/self/fixtures/parse/sexpr.fl +1 -0
  559. package/self/fixtures/parse/str-interp.fl +1 -0
  560. package/self/fixtures/parse/sym.fl +1 -0
  561. package/self/fixtures/parse/thread-first.fl +1 -0
  562. package/self/fixtures/parse/thread-last.fl +1 -0
  563. package/self/fixtures/parse/try-catch.fl +1 -0
  564. package/self/fixtures/parse/var.fl +1 -0
  565. package/self/full-compiler-fixed.fl +1308 -0
  566. package/self/full-compiler-v1-bloated.fl +1298 -0
  567. package/self/full-compiler.fl +1301 -0
  568. package/self/interpreter.fl +351 -0
  569. package/self/lexer.fl +200 -0
  570. package/self/lexer.self.js +30 -0
  571. package/self/main.fl +22 -0
  572. package/self/parser.fl +241 -0
  573. package/self/parser.self.js +33 -0
  574. package/self/runtime/http-server.js +642 -0
  575. package/self/runtime/interpreter.js +30787 -0
  576. package/self/runtime/repl.js +186 -0
  577. package/self/runtime-helpers.ts +282 -0
  578. package/self/scope.fl +80 -0
  579. package/self/scope.self.js +1 -0
  580. package/self/self/bench/_bi_list-distinct.js +2 -0
  581. package/self/self/bench/_bi_list-filter-even.js +2 -0
  582. package/self/self/bench/_bi_list-first.js +2 -0
  583. package/self/self/bench/_bi_list-last.js +2 -0
  584. package/self/self/bench/_bi_list-map-inc.js +2 -0
  585. package/self/self/bench/_bi_list-range.js +2 -0
  586. package/self/self/bench/_bi_list-reduce-sum.js +2 -0
  587. package/self/self/bench/_bi_list-reverse.js +2 -0
  588. package/self/self/bench/_bi_list-sort.js +2 -0
  589. package/self/self/bench/_bi_list-take.js +2 -0
  590. package/self/self/bench/_bi_map-has.js +2 -0
  591. package/self/self/bench/_bi_map-keys.js +2 -0
  592. package/self/self/bench/_bi_map-values.js +2 -0
  593. package/self/self/bench/_bi_str-concat.js +2 -0
  594. package/self/self/bench/_bi_str-contains.js +2 -0
  595. package/self/self/bench/_bi_str-ends.js +2 -0
  596. package/self/self/bench/_bi_str-index.js +2 -0
  597. package/self/self/bench/_bi_str-lower.js +2 -0
  598. package/self/self/bench/_bi_str-repeat.js +2 -0
  599. package/self/self/bench/_bi_str-split.js +2 -0
  600. package/self/self/bench/_bi_str-starts.js +2 -0
  601. package/self/self/bench/_bi_str-trim.js +2 -0
  602. package/self/self/bench/_bi_str-upper.js +2 -0
  603. package/self/self/bench/_ext_abs-neg.js +2 -0
  604. package/self/self/bench/_ext_and.js +2 -0
  605. package/self/self/bench/_ext_cond-1.js +2 -0
  606. package/self/self/bench/_ext_cond-2.js +2 -0
  607. package/self/self/bench/_ext_do-seq.js +2 -0
  608. package/self/self/bench/_ext_fact20.js +3 -0
  609. package/self/self/bench/_ext_fib25.js +3 -0
  610. package/self/self/bench/_ext_length.js +2 -0
  611. package/self/self/bench/_ext_let-1d.js +2 -0
  612. package/self/self/bench/_ext_let-2d.js +2 -0
  613. package/self/self/bench/_ext_list-sum.js +3 -0
  614. package/self/self/bench/_ext_math.js +2 -0
  615. package/self/self/bench/_ext_or.js +2 -0
  616. package/self/self/bench/_ext_str.js +2 -0
  617. package/self/self/bench/_fact15.js +2 -0
  618. package/self/self/bench/_fb_fact15.js +2 -0
  619. package/self/self/bench/_fb_func-fact.js +2 -0
  620. package/self/self/bench/_fb_func-multi.js +2 -0
  621. package/self/self/bench/_fb_func-mutual.js +3 -0
  622. package/self/self/bench/_fb_func-simple.js +2 -0
  623. package/self/self/bench/_fib.js +2 -0
  624. package/self/self/bench/_fn_async-await-seq.js +2 -0
  625. package/self/self/bench/_fn_async-print.js +2 -0
  626. package/self/self/bench/_fn_call-form.js +2 -0
  627. package/self/self/bench/_fn_compose.js +2 -0
  628. package/self/self/bench/_fn_pipe.js +2 -0
  629. package/self/self/bench/_fn_thread-first-sexpr.js +2 -0
  630. package/self/self/bench/_fn_thread-first.js +2 -0
  631. package/self/self/bench/_fn_thread-last.js +2 -0
  632. package/self/self/bench/_generated.js +2 -0
  633. package/self/self/bench/_mt_match-default.js +2 -0
  634. package/self/self/bench/_mt_match-num.js +2 -0
  635. package/self/self/bench/_mt_match-str.js +2 -0
  636. package/self/self/bench/_mt_match-var.js +2 -0
  637. package/self/self/bench/_mt_match-wild.js +2 -0
  638. package/self/self/bench/_mt_struct-make.js +4 -0
  639. package/self/self/bench/_mt_struct-tag.js +4 -0
  640. package/self/self/bench/_rs_combo.js +3 -0
  641. package/self/self/bench/_rs_gcd.js +2 -0
  642. package/self/self/bench/_rs_grade.js +2 -0
  643. package/self/self/bench/_rs_mutual-fib.js +2 -0
  644. package/self/self/bench/_rs_range-sum.js +2 -0
  645. package/self/self/bench/_rs_sum-5k.js +2 -0
  646. package/self/self/bench/_sf_loop-fact-10.js +1 -0
  647. package/self/self/bench/_sf_loop-sum-10k.js +1 -0
  648. package/self/self/bench/_sf_set-x.js +3 -0
  649. package/self/self/bench/_sf_throw-catch.js +1 -0
  650. package/self/self/bench/_sf_while-5.js +3 -0
  651. package/self/stdlib/ai.fl +73 -0
  652. package/self/stdlib/assert.fl +30 -0
  653. package/self/stdlib/async.fl +48 -0
  654. package/self/stdlib/base64.fl +22 -0
  655. package/self/stdlib/binary.fl +30 -0
  656. package/self/stdlib/build.fl +69 -0
  657. package/self/stdlib/collection.fl +37 -0
  658. package/self/stdlib/color.fl +35 -0
  659. package/self/stdlib/crypto-hash.fl +29 -0
  660. package/self/stdlib/crypto.fl +56 -0
  661. package/self/stdlib/data.fl +69 -0
  662. package/self/stdlib/db.fl +53 -0
  663. package/self/stdlib/encoding.fl +49 -0
  664. package/self/stdlib/error.fl +36 -0
  665. package/self/stdlib/feed.fl +86 -0
  666. package/self/stdlib/file.fl +53 -0
  667. package/self/stdlib/format.fl +34 -0
  668. package/self/stdlib/graph.fl +72 -0
  669. package/self/stdlib/hash.fl +32 -0
  670. package/self/stdlib/heap.fl +76 -0
  671. package/self/stdlib/http.fl +47 -0
  672. package/self/stdlib/image.fl +45 -0
  673. package/self/stdlib/json.fl +11 -0
  674. package/self/stdlib/list-extra.fl +32 -0
  675. package/self/stdlib/markdown.fl +59 -0
  676. package/self/stdlib/math-extra.fl +34 -0
  677. package/self/stdlib/math.fl +13 -0
  678. package/self/stdlib/metadata.fl +66 -0
  679. package/self/stdlib/mongodb/bson.fl +21 -0
  680. package/self/stdlib/mongodb/schema.fl +95 -0
  681. package/self/stdlib/mongodb/wire.fl +54 -0
  682. package/self/stdlib/mongodb.fl +172 -0
  683. package/self/stdlib/path.fl +72 -0
  684. package/self/stdlib/plot.fl +56 -0
  685. package/self/stdlib/process.fl +50 -0
  686. package/self/stdlib/queue.fl +65 -0
  687. package/self/stdlib/regex.fl +11 -0
  688. package/self/stdlib/resource.fl +61 -0
  689. package/self/stdlib/search.fl +54 -0
  690. package/self/stdlib/set-extra.fl +35 -0
  691. package/self/stdlib/sort.fl +61 -0
  692. package/self/stdlib/stack.fl +54 -0
  693. package/self/stdlib/stats.fl +110 -0
  694. package/self/stdlib/stream.fl +56 -0
  695. package/self/stdlib/string-extended.fl +25 -0
  696. package/self/stdlib/string-extra.fl +40 -0
  697. package/self/stdlib/string.fl +21 -0
  698. package/self/stdlib/test-helpers.fl +51 -0
  699. package/self/stdlib/test-runner.fl +76 -0
  700. package/self/stdlib/time-extra.fl +27 -0
  701. package/self/stdlib/time.fl +31 -0
  702. package/self/stdlib/tree.fl +57 -0
  703. package/self/stdlib/types.fl +85 -0
  704. package/self/stdlib/url.fl +33 -0
  705. package/self/stdlib/uuid.fl +28 -0
  706. package/self/stdlib/validation.fl +42 -0
  707. package/self/stdlib/vector-math.fl +52 -0
  708. package/self/stdlib/ws.fl +52 -0
  709. package/self/tests/mongodb-phase3.fl +75 -0
  710. package/self/tests/mongodb-wire-phase2.fl +45 -0
  711. package/self/tests/test-ast.fl +36 -0
  712. package/self/tests/test-builtins.fl +340 -0
  713. package/self/tests/test-char-class.fl +29 -0
  714. package/self/tests/test-codegen-builtins.fl +240 -0
  715. package/self/tests/test-codegen-ext.fl +380 -0
  716. package/self/tests/test-codegen-ffi.fl +295 -0
  717. package/self/tests/test-codegen-fn.fl +177 -0
  718. package/self/tests/test-codegen-match.fl +161 -0
  719. package/self/tests/test-codegen-run.fl +252 -0
  720. package/self/tests/test-codegen-sf.fl +262 -0
  721. package/self/tests/test-codegen.fl +260 -0
  722. package/self/tests/test-core-fl.fl +63 -0
  723. package/self/tests/test-forward-decl.fl +5 -0
  724. package/self/tests/test-func-block.fl +4 -0
  725. package/self/tests/test-interp-user-fn.fl +296 -0
  726. package/self/tests/test-interp.fl +225 -0
  727. package/self/tests/test-lexer.fl +162 -0
  728. package/self/tests/test-list-debug.fl +21 -0
  729. package/self/tests/test-mutual-rec.fl +6 -0
  730. package/self/tests/test-parser-debug.fl +35 -0
  731. package/self/tests/test-parser-full-debug.fl +66 -0
  732. package/self/tests/test-parser-lex-debug.fl +107 -0
  733. package/self/tests/test-parser-lex-only.fl +40 -0
  734. package/self/tests/test-parser-simple-debug.fl +35 -0
  735. package/self/tests/test-parser.fl +262 -0
  736. package/self/tests/test-real-stdlib.fl +377 -0
  737. package/self/tests/test-scope.fl +74 -0
  738. package/self/tests/test-selfcompile.fl +325 -0
  739. package/self/tests/test-stdlib.fl +44 -0
  740. package/self/tests/test-tco.fl +16 -0
  741. package/self/tests/test-token.fl +4 -0
  742. package/self/token.fl +38 -0
  743. package/self/token.self.js +8 -0
  744. package/self/v12-driver.fl +16 -0
  745. package/self/verify.fl +39 -0
  746. package/self-evolve/1-observe-ast.fl +28 -0
  747. package/self-evolve/2-inspect-block.fl +35 -0
  748. package/self-evolve/3-full-ast-json.fl +10 -0
  749. package/self-evolve/4-trace-block-fields.fl +23 -0
  750. package/self-evolve/5-analyze-do-ast.fl +29 -0
  751. package/self-evolve/6-test-do-elim-simple.fl +14 -0
  752. package/self-evolve/debug-evaluate.fl +24 -0
  753. package/self-evolve/debug-gen1-const-fold.fl +57 -0
  754. package/self-evolve/debug-map.fl +15 -0
  755. package/self-evolve/debug-optimize-simple.fl +95 -0
  756. package/self-evolve/debug-recursive-map.fl +23 -0
  757. package/self-evolve/logs/gen-0.fl +1658 -0
  758. package/self-evolve/logs/gen-1.fl +1658 -0
  759. package/self-evolve/logs/gen-2.fl +1658 -0
  760. package/self-evolve/logs/speed-gen-0.fl +1423 -0
  761. package/self-evolve/run-semantic-test.js +130 -0
  762. package/self-evolve/test-basic.fl +19 -0
  763. package/self-evolve/test-fold-direct.fl +60 -0
  764. package/self-evolve/test-gen1-simple.fl +67 -0
  765. package/self-evolve/test-optimize-debug.fl +63 -0
  766. package/self-evolve/tmp-test.fl +1 -0
  767. package/self-evolve/v11-analyzer.fl +40 -0
  768. package/self-evolve/v11-benchmark.fl +45 -0
  769. package/self-evolve/v11-evolution-real.fl +45 -0
  770. package/self-evolve/v11-evolution.fl +32 -0
  771. package/self-evolve/v11-gen1-validate.fl +157 -0
  772. package/self-evolve/v11-optimizer-constant-fold.fl +124 -0
  773. package/self-evolve/v11-optimizer-dead-expr.fl +111 -0
  774. package/self-evolve/v11-optimizer-gen1-complete.fl +180 -0
  775. package/self-evolve/v11-optimizer-gen1.fl +68 -0
  776. package/self-evolve/v11-optimizer.fl +56 -0
  777. package/self-evolve/v11-semantic-test.fl +54 -0
  778. package/self-evolve/v11-speed-benchmark.fl +106 -0
  779. package/self-evolve/v11-speed-optimizer.fl +79 -0
  780. package/src/AGENT-DSL.md +527 -0
  781. package/src/CLI-DEPLOYMENT.md +204 -0
  782. package/src/CLI.md +361 -0
  783. package/src/EXPRESS-ADVANCED.md +294 -0
  784. package/src/EXPRESS-AUTH.md +365 -0
  785. package/src/EXPRESS-CACHE.md +409 -0
  786. package/src/EXPRESS-COMPLETE.md +569 -0
  787. package/src/EXPRESS-README.md +121 -0
  788. package/src/EXPRESS-TEST.md +492 -0
  789. package/src/EXPRESS-WEBSOCKET.md +391 -0
  790. package/src/LOGGING-GUIDE.md +354 -0
  791. package/src/STORAGE-GUIDE.md +416 -0
  792. package/src/__tests__/advanced.test.ts +573 -0
  793. package/src/__tests__/ai-library.test.ts +210 -0
  794. package/src/__tests__/build-determinism.test.ts +33 -0
  795. package/src/__tests__/builtins-advanced.test.ts +150 -0
  796. package/src/__tests__/builtins-sanity.test.ts +180 -0
  797. package/src/__tests__/codegen.let.test.ts +81 -0
  798. package/src/__tests__/core.test.ts +188 -0
  799. package/src/__tests__/coverage-boost.test.ts +626 -0
  800. package/src/__tests__/cron-scheduler.test.ts +269 -0
  801. package/src/__tests__/enterprise-blocks.test.ts +63 -0
  802. package/src/__tests__/errors.test.ts +313 -0
  803. package/src/__tests__/integration.test.ts +219 -0
  804. package/src/__tests__/interpreter.test.ts +170 -0
  805. package/src/__tests__/l2-proof.test.ts +78 -0
  806. package/src/__tests__/lexer-parser.test.ts +366 -0
  807. package/src/__tests__/lexer.test.ts +106 -0
  808. package/src/__tests__/mariadb-prepared-statement.test.ts +206 -0
  809. package/src/__tests__/migrate.test.ts +403 -0
  810. package/src/__tests__/mongodb-integration.test.ts.skip +207 -0
  811. package/src/__tests__/mongodb-phase4.test.ts +132 -0
  812. package/src/__tests__/p1-1-parallel-tasks.test.ts +179 -0
  813. package/src/__tests__/p1-2-compensation.test.ts +242 -0
  814. package/src/__tests__/p1-3-distributed.test.ts +160 -0
  815. package/src/__tests__/p1-4-observability.test.ts +161 -0
  816. package/src/__tests__/parser.test.ts +142 -0
  817. package/src/__tests__/phase151-self-evolve.test.ts +161 -0
  818. package/src/__tests__/rate-limiter.test.ts +274 -0
  819. package/src/__tests__/self-hosting.test.ts +174 -0
  820. package/src/__tests__/semantic-preservation.test.ts +207 -0
  821. package/src/__tests__/setup.ts +34 -0
  822. package/src/__tests__/special-forms-advanced.test.ts +106 -0
  823. package/src/__tests__/stdlib-crypto-rsa.test.ts +122 -0
  824. package/src/__tests__/stdlib-f4.test.ts +159 -0
  825. package/src/__tests__/stdlib-helpers.test.ts +128 -0
  826. package/src/__tests__/stdlib-modules.test.ts +161 -0
  827. package/src/__tests__/stdlib-mongodb.test.ts +331 -0
  828. package/src/__tests__/stdlib-new.test.ts +269 -0
  829. package/src/__tests__/stdlib-perf.test.ts +125 -0
  830. package/src/__tests__/stdlib-phase-b.test.ts +249 -0
  831. package/src/__tests__/stdlib.test.ts +163 -0
  832. package/src/__tests__/v12-alpha.test.ts +205 -0
  833. package/src/__tests__/vm-optin.test.ts +141 -0
  834. package/src/__tests__/web-integration.test.ts +1452 -0
  835. package/src/__tests__/weblibs.test.ts +210 -0
  836. package/src/_aliases.json +1123 -0
  837. package/src/_mongodb_helper.js +272 -0
  838. package/src/_stdlib-signatures.json +1 -0
  839. package/src/agent-chain.ts +71 -0
  840. package/src/agent-dsl.fl +168 -0
  841. package/src/agent-example-error-handling.fl +51 -0
  842. package/src/agent-example-sequential.fl +66 -0
  843. package/src/agent-example-state-tracking.fl +70 -0
  844. package/src/agent.ts +393 -0
  845. package/src/align.ts +349 -0
  846. package/src/analogy.ts +78 -0
  847. package/src/ast-helpers.ts +199 -0
  848. package/src/ast.ts +817 -0
  849. package/src/async-runtime.ts +263 -0
  850. package/src/belief.ts +86 -0
  851. package/src/benchmark-self.ts +275 -0
  852. package/src/benchmarks/bench-interpreter.ts +73 -0
  853. package/src/benchmarks/bench-runner.ts +85 -0
  854. package/src/benchmarks/bench-vm.ts +128 -0
  855. package/src/browser-debug-panel.ts +220 -0
  856. package/src/browser-entry.ts +79 -0
  857. package/src/browser-stubs/child-process-stubs.ts +6 -0
  858. package/src/browser-stubs/crypto-stubs.ts +15 -0
  859. package/src/browser-stubs/misc-stubs.ts +4 -0
  860. package/src/browser-stubs/node-stubs.ts +17 -0
  861. package/src/browser-stubs/path-stubs.ts +6 -0
  862. package/src/bytecode.ts +41 -0
  863. package/src/causal.ts +258 -0
  864. package/src/chain-agents.ts +86 -0
  865. package/src/checkpoint.ts +106 -0
  866. package/src/ci-runner.ts +279 -0
  867. package/src/cli.ts +2136 -0
  868. package/src/codegen-js.ts +847 -0
  869. package/src/cognitive.ts +95 -0
  870. package/src/compete.ts +60 -0
  871. package/src/compiler.ts +267 -0
  872. package/src/compose-reason.ts +118 -0
  873. package/src/consensus.ts +109 -0
  874. package/src/context-window.ts +139 -0
  875. package/src/cot.ts +241 -0
  876. package/src/counterfactual.ts +268 -0
  877. package/src/critique.ts +77 -0
  878. package/src/crossover.ts +218 -0
  879. package/src/curiosity.ts +305 -0
  880. package/src/debate.ts +64 -0
  881. package/src/debug-api.ts +92 -0
  882. package/src/debugger.ts +185 -0
  883. package/src/delegate.ts +78 -0
  884. package/src/doc-extractor.ts +255 -0
  885. package/src/doc-renderer.ts +131 -0
  886. package/src/echo-server-demo.fl +17 -0
  887. package/src/error-formatter.ts +369 -0
  888. package/src/error-system.ts +88 -0
  889. package/src/errors.ts +281 -0
  890. package/src/ethics-check.ts +408 -0
  891. package/src/eval-ai-blocks.ts +182 -0
  892. package/src/eval-ai-handlers.ts +132 -0
  893. package/src/eval-builtins-ai.ts +1659 -0
  894. package/src/eval-builtins.ts +5956 -0
  895. package/src/eval-call-function.ts +665 -0
  896. package/src/eval-infra-blocks.ts +450 -0
  897. package/src/eval-module-system.ts +286 -0
  898. package/src/eval-pattern-match.ts +289 -0
  899. package/src/eval-phase150.ts +87 -0
  900. package/src/eval-reasoning-sequence.ts +218 -0
  901. package/src/eval-special-forms.ts +2154 -0
  902. package/src/eval-style-blocks.ts +193 -0
  903. package/src/eval-type-classes.ts +148 -0
  904. package/src/evolve.ts +276 -0
  905. package/src/explain.ts +345 -0
  906. package/src/express-advanced.fl +78 -0
  907. package/src/express-auth.fl +118 -0
  908. package/src/express-cache.fl +118 -0
  909. package/src/express-chat.fl +81 -0
  910. package/src/express-example.fl +67 -0
  911. package/src/express-test.fl +331 -0
  912. package/src/express.fl +92 -0
  913. package/src/fitness.ts +238 -0
  914. package/src/fl-app-demo.fl +19 -0
  915. package/src/fl-files/fl-fmt.fl +29 -0
  916. package/src/fl-files/fl-lint.fl +61 -0
  917. package/src/fl-files/fl-test.fl +52 -0
  918. package/src/fl-http-demo.fl +19 -0
  919. package/src/fl-list-utils.fl +108 -0
  920. package/src/fl-math-lib.fl +14 -0
  921. package/src/fl-sdk.ts +154 -0
  922. package/src/fl-server-demo.fl +74 -0
  923. package/src/fl-str-utils.fl +29 -0
  924. package/src/fl-tutor.ts +126 -0
  925. package/src/formatter.ts +581 -0
  926. package/src/freelang-codegen.fl +904 -0
  927. package/src/freelang-interpreter.fl +483 -0
  928. package/src/freelang-lexer.fl +337 -0
  929. package/src/freelang-parser.fl +349 -0
  930. package/src/freelang-stdlib.fl +246 -0
  931. package/src/freelang-typechecker.fl +422 -0
  932. package/src/freelang-v9-complete.ts +474 -0
  933. package/src/generation.ts +201 -0
  934. package/src/gpt-mini-p3.fl +316 -0
  935. package/src/hot-reload.ts +235 -0
  936. package/src/http-server-runner.ts +89 -0
  937. package/src/hypothesis.ts +62 -0
  938. package/src/immutable.ts +140 -0
  939. package/src/interpreter-context.ts +87 -0
  940. package/src/interpreter-scope.ts +140 -0
  941. package/src/interpreter.ts +2351 -0
  942. package/src/lazy-seq.ts +134 -0
  943. package/src/learned-facts-store.ts +306 -0
  944. package/src/lexer.ts +359 -0
  945. package/src/lint-rules.ts +584 -0
  946. package/src/linter.ts +237 -0
  947. package/src/logger.ts +128 -0
  948. package/src/logging-deterministic.fl +138 -0
  949. package/src/lsp-server.ts +379 -0
  950. package/src/macro-expander.ts +195 -0
  951. package/src/maybe-chain.ts +108 -0
  952. package/src/maybe-type.ts +163 -0
  953. package/src/memory-system.ts +142 -0
  954. package/src/meta-reason.ts +93 -0
  955. package/src/multi-agent-hub.ts +247 -0
  956. package/src/multi-agent.ts +101 -0
  957. package/src/mutate.ts +226 -0
  958. package/src/negotiate.ts +55 -0
  959. package/src/optimizer.ts +277 -0
  960. package/src/orchestrate.ts +154 -0
  961. package/src/package-manager.ts +375 -0
  962. package/src/parser.ts +2722 -0
  963. package/src/peer-review.ts +53 -0
  964. package/src/predict.ts +365 -0
  965. package/src/profiler.ts +150 -0
  966. package/src/prompt-compiler.ts +123 -0
  967. package/src/protocol.ts +114 -0
  968. package/src/prune.ts +195 -0
  969. package/src/quality-loop.ts +105 -0
  970. package/src/rag.ts +81 -0
  971. package/src/reasoning-debugger.ts +122 -0
  972. package/src/refactor-self.ts +362 -0
  973. package/src/reflect.ts +186 -0
  974. package/src/repl.ts +323 -0
  975. package/src/result-type.ts +126 -0
  976. package/src/return-signal.ts +10 -0
  977. package/src/runtime-entry.ts +8 -0
  978. package/src/runtime-helpers.ts +234 -0
  979. package/src/self-evolution-hub.ts +431 -0
  980. package/src/self-improve.ts +107 -0
  981. package/src/source-map.ts +114 -0
  982. package/src/stdlib-agent.js +164 -0
  983. package/src/stdlib-agent.ts +225 -0
  984. package/src/stdlib-ai-native.ts +176 -0
  985. package/src/stdlib-ai-workflow.ts +308 -0
  986. package/src/stdlib-ai.ts +180 -0
  987. package/src/stdlib-async.ts +179 -0
  988. package/src/stdlib-audit.ts +94 -0
  989. package/src/stdlib-auth.ts +196 -0
  990. package/src/stdlib-bits.ts +86 -0
  991. package/src/stdlib-blog.ts +127 -0
  992. package/src/stdlib-browser.ts +239 -0
  993. package/src/stdlib-cache.ts +147 -0
  994. package/src/stdlib-capture-error.ts +183 -0
  995. package/src/stdlib-channel.ts +96 -0
  996. package/src/stdlib-checkpoint.js +109 -0
  997. package/src/stdlib-checkpoint.ts +97 -0
  998. package/src/stdlib-cloud.ts +317 -0
  999. package/src/stdlib-collection.ts +227 -0
  1000. package/src/stdlib-compile.ts +111 -0
  1001. package/src/stdlib-cron.ts +219 -0
  1002. package/src/stdlib-crypto-rsa.ts +82 -0
  1003. package/src/stdlib-crypto.js +203 -0
  1004. package/src/stdlib-crypto.ts +208 -0
  1005. package/src/stdlib-data.ts +614 -0
  1006. package/src/stdlib-db-query.ts +198 -0
  1007. package/src/stdlib-db.ts +185 -0
  1008. package/src/stdlib-distributed.ts +292 -0
  1009. package/src/stdlib-error.ts +90 -0
  1010. package/src/stdlib-fd.ts +130 -0
  1011. package/src/stdlib-feed.ts +171 -0
  1012. package/src/stdlib-file.ts +182 -0
  1013. package/src/stdlib-helpers.ts +273 -0
  1014. package/src/stdlib-http-macro.ts +178 -0
  1015. package/src/stdlib-http-server.ts +1229 -0
  1016. package/src/stdlib-http.ts +405 -0
  1017. package/src/stdlib-image.ts +92 -0
  1018. package/src/stdlib-kebab-aliases.ts +131 -0
  1019. package/src/stdlib-lazy-registry.ts +106 -0
  1020. package/src/stdlib-loader.ts +810 -0
  1021. package/src/stdlib-mail.ts +251 -0
  1022. package/src/stdlib-mariadb.ts +467 -0
  1023. package/src/stdlib-markdown.ts +227 -0
  1024. package/src/stdlib-matrix.ts +170 -0
  1025. package/src/stdlib-middleware.ts +221 -0
  1026. package/src/stdlib-module.ts +178 -0
  1027. package/src/stdlib-mongodb.ts +174 -0
  1028. package/src/stdlib-oci.ts +321 -0
  1029. package/src/stdlib-optional.ts +56 -0
  1030. package/src/stdlib-orm.ts +241 -0
  1031. package/src/stdlib-perf.ts +140 -0
  1032. package/src/stdlib-pg.ts +181 -0
  1033. package/src/stdlib-plot.ts +196 -0
  1034. package/src/stdlib-process.ts +120 -0
  1035. package/src/stdlib-property.ts +157 -0
  1036. package/src/stdlib-pubsub.ts +93 -0
  1037. package/src/stdlib-queue-helpers.ts +92 -0
  1038. package/src/stdlib-registry.ts +78 -0
  1039. package/src/stdlib-resource.ts +553 -0
  1040. package/src/stdlib-rest-crud.ts +146 -0
  1041. package/src/stdlib-service.ts +206 -0
  1042. package/src/stdlib-shell.ts +76 -0
  1043. package/src/stdlib-stats.ts +172 -0
  1044. package/src/stdlib-table.ts +200 -0
  1045. package/src/stdlib-test-enhanced.ts +76 -0
  1046. package/src/stdlib-test.ts +153 -0
  1047. package/src/stdlib-time.js +217 -0
  1048. package/src/stdlib-time.ts +282 -0
  1049. package/src/stdlib-timer.ts +134 -0
  1050. package/src/stdlib-totp.ts +110 -0
  1051. package/src/stdlib-type-predicates.ts +136 -0
  1052. package/src/stdlib-types.ts +107 -0
  1053. package/src/stdlib-validation.ts +248 -0
  1054. package/src/stdlib-verify.ts +181 -0
  1055. package/src/stdlib-webauthn.ts +192 -0
  1056. package/src/stdlib-workflow.js +715 -0
  1057. package/src/stdlib-workflow.ts +950 -0
  1058. package/src/stdlib-ws.ts +333 -0
  1059. package/src/stdlib-wsc.test.ts +122 -0
  1060. package/src/stdlib-wsc.ts +243 -0
  1061. package/src/storage-unified.fl +279 -0
  1062. package/src/streaming.ts +101 -0
  1063. package/src/struct-system.ts +104 -0
  1064. package/src/style-registry.ts +54 -0
  1065. package/src/swarm.ts +89 -0
  1066. package/src/tco.ts +31 -0
  1067. package/src/test-advanced-patterns.ts +211 -0
  1068. package/src/test-ast-debug.ts +20 -0
  1069. package/src/test-ast-helpers.ts +208 -0
  1070. package/src/test-async.ts +406 -0
  1071. package/src/test-bootstrap-self-compile.ts +449 -0
  1072. package/src/test-bootstrap-verification.ts +336 -0
  1073. package/src/test-composition.ts +206 -0
  1074. package/src/test-errors-phase6.ts +166 -0
  1075. package/src/test-extended-monads.ts +313 -0
  1076. package/src/test-field-parsing.ts +135 -0
  1077. package/src/test-first-class-functions.ts +257 -0
  1078. package/src/test-freelang-interpreter.ts +320 -0
  1079. package/src/test-freelang-lexer.ts +306 -0
  1080. package/src/test-freelang-parser.ts +268 -0
  1081. package/src/test-fullstack-core.ts +258 -0
  1082. package/src/test-fullstack-phase7-12.ts +305 -0
  1083. package/src/test-fullstack-practical.ts +338 -0
  1084. package/src/test-integration-stdlib.ts +195 -0
  1085. package/src/test-interpreter-phase6.ts +305 -0
  1086. package/src/test-lexer-comparison.ts +108 -0
  1087. package/src/test-lexer-phase6.ts +271 -0
  1088. package/src/test-modules.ts +325 -0
  1089. package/src/test-monad-laws.ts +383 -0
  1090. package/src/test-monads.ts +197 -0
  1091. package/src/test-p0-checkpoint.ts +304 -0
  1092. package/src/test-p0-conditional.ts +284 -0
  1093. package/src/test-p0-error-handling.ts +231 -0
  1094. package/src/test-p0-error-messages.ts +220 -0
  1095. package/src/test-p1-1-parallel-tasks.js +214 -0
  1096. package/src/test-parser-phase6.ts +222 -0
  1097. package/src/test-performance.ts +206 -0
  1098. package/src/test-phase10-data.ts +259 -0
  1099. package/src/test-phase10-file.ts +216 -0
  1100. package/src/test-phase100-stdlib-ai.ts +343 -0
  1101. package/src/test-phase101-memory.ts +309 -0
  1102. package/src/test-phase102-rag.ts +296 -0
  1103. package/src/test-phase103-multi-agent.ts +418 -0
  1104. package/src/test-phase104-try-reason.ts +459 -0
  1105. package/src/test-phase105-streaming.ts +287 -0
  1106. package/src/test-phase106-quality.ts +397 -0
  1107. package/src/test-phase107-tutor.ts +305 -0
  1108. package/src/test-phase108-debugger.ts +316 -0
  1109. package/src/test-phase109-prompt-compiler.ts +333 -0
  1110. package/src/test-phase11-12-complete.ts +275 -0
  1111. package/src/test-phase11-error.ts +192 -0
  1112. package/src/test-phase110-sdk.ts +320 -0
  1113. package/src/test-phase111-hypothesis.ts +380 -0
  1114. package/src/test-phase112-maybe-chain.ts +313 -0
  1115. package/src/test-phase113-debate.ts +364 -0
  1116. package/src/test-phase114-checkpoint.ts +348 -0
  1117. package/src/test-phase115-meta-reason.ts +277 -0
  1118. package/src/test-phase116-belief.ts +275 -0
  1119. package/src/test-phase117-analogy.ts +325 -0
  1120. package/src/test-phase118-critique.ts +308 -0
  1121. package/src/test-phase119-compose.ts +434 -0
  1122. package/src/test-phase12-http-shell.ts +120 -0
  1123. package/src/test-phase120-cognitive.ts +297 -0
  1124. package/src/test-phase121-consensus.ts +404 -0
  1125. package/src/test-phase122-delegate.ts +411 -0
  1126. package/src/test-phase123-vote.ts +339 -0
  1127. package/src/test-phase124-negotiate.ts +403 -0
  1128. package/src/test-phase125-swarm.ts +321 -0
  1129. package/src/test-phase126-orchestrate.ts +343 -0
  1130. package/src/test-phase127-peer-review.ts +279 -0
  1131. package/src/test-phase128-chain-agents.ts +456 -0
  1132. package/src/test-phase129-compete.ts +256 -0
  1133. package/src/test-phase13-data.ts +223 -0
  1134. package/src/test-phase130-hub.ts +390 -0
  1135. package/src/test-phase131-evolve.ts +536 -0
  1136. package/src/test-phase132-mutate.ts +268 -0
  1137. package/src/test-phase133-crossover.ts +289 -0
  1138. package/src/test-phase134-fitness.ts +306 -0
  1139. package/src/test-phase135-generation.ts +328 -0
  1140. package/src/test-phase136-prune.ts +228 -0
  1141. package/src/test-phase137-refactor-self.ts +354 -0
  1142. package/src/test-phase138-benchmark-self.ts +325 -0
  1143. package/src/test-phase139-version-self.ts +278 -0
  1144. package/src/test-phase14-collection.ts +254 -0
  1145. package/src/test-phase140-self-evolution.ts +410 -0
  1146. package/src/test-phase141-world-model.ts +387 -0
  1147. package/src/test-phase142-causal.ts +384 -0
  1148. package/src/test-phase143-counterfactual.ts +280 -0
  1149. package/src/test-phase144-predict.ts +312 -0
  1150. package/src/test-phase145-explain.ts +287 -0
  1151. package/src/test-phase146-align.ts +439 -0
  1152. package/src/test-phase147-ethics-check.ts +399 -0
  1153. package/src/test-phase148-curiosity.ts +247 -0
  1154. package/src/test-phase149-wisdom.ts +758 -0
  1155. package/src/test-phase15-agent.ts +320 -0
  1156. package/src/test-phase150-complete.ts +481 -0
  1157. package/src/test-phase16-time.ts +292 -0
  1158. package/src/test-phase17-crypto.ts +312 -0
  1159. package/src/test-phase18-integration.ts +429 -0
  1160. package/src/test-phase19-resource.ts +214 -0
  1161. package/src/test-phase20-server-db.ts +160 -0
  1162. package/src/test-phase21-ws-auth-cache-pubsub.ts +212 -0
  1163. package/src/test-phase22-process.ts +166 -0
  1164. package/src/test-phase23-selfhosting.ts +383 -0
  1165. package/src/test-phase24-codegen.ts +236 -0
  1166. package/src/test-phase25-bootstrap.ts +227 -0
  1167. package/src/test-phase26-map-filter-reduce.ts +282 -0
  1168. package/src/test-phase27-stdlib-codegen.ts +325 -0
  1169. package/src/test-phase28-loop-recur.ts +182 -0
  1170. package/src/test-phase29-import.ts +165 -0
  1171. package/src/test-phase3-web-server.ts +234 -0
  1172. package/src/test-phase30-selfcompile.ts +254 -0
  1173. package/src/test-phase31-gen2-lexer.ts +251 -0
  1174. package/src/test-phase33-gen3-bootstrap.ts +323 -0
  1175. package/src/test-phase34-parser-tco.ts +268 -0
  1176. package/src/test-phase35-error-messages.ts +280 -0
  1177. package/src/test-phase36-sourcemap.ts +240 -0
  1178. package/src/test-phase37-variadic.ts +228 -0
  1179. package/src/test-phase38-destructuring.ts +261 -0
  1180. package/src/test-phase39-do-block.ts +288 -0
  1181. package/src/test-phase40-const-fold.ts +249 -0
  1182. package/src/test-phase41-repl.ts +312 -0
  1183. package/src/test-phase42-watch.ts +314 -0
  1184. package/src/test-phase43-format.ts +377 -0
  1185. package/src/test-phase44-check.ts +505 -0
  1186. package/src/test-phase45-interpreter.ts +367 -0
  1187. package/src/test-phase46-match.ts +390 -0
  1188. package/src/test-phase47-file-io.ts +338 -0
  1189. package/src/test-phase48-types.ts +308 -0
  1190. package/src/test-phase49-stdlib.ts +365 -0
  1191. package/src/test-phase5-week1.ts +160 -0
  1192. package/src/test-phase50-fl-server.ts +159 -0
  1193. package/src/test-phase51-transformer.ts +152 -0
  1194. package/src/test-phase52-import.ts +161 -0
  1195. package/src/test-phase53-training.ts +122 -0
  1196. package/src/test-phase54-fl-utils.ts +122 -0
  1197. package/src/test-phase55-http-client.ts +182 -0
  1198. package/src/test-phase56-lexical-scope.ts +230 -0
  1199. package/src/test-phase58-module-refactor.ts +298 -0
  1200. package/src/test-phase59-errors.ts +226 -0
  1201. package/src/test-phase6-compile.ts +227 -0
  1202. package/src/test-phase60-types.ts +457 -0
  1203. package/src/test-phase61-tco.ts +209 -0
  1204. package/src/test-phase63-macros.ts +191 -0
  1205. package/src/test-phase64-protocols.ts +451 -0
  1206. package/src/test-phase65-patterns.ts +301 -0
  1207. package/src/test-phase66-structs.ts +215 -0
  1208. package/src/test-phase67-concurrency.ts +348 -0
  1209. package/src/test-phase68-pipeline.ts +209 -0
  1210. package/src/test-phase69-lazy.ts +237 -0
  1211. package/src/test-phase7-registry.ts +236 -0
  1212. package/src/test-phase70-immutable.ts +488 -0
  1213. package/src/test-phase71-ai-native.ts +252 -0
  1214. package/src/test-phase72-integration.ts +533 -0
  1215. package/src/test-phase73-formatter.ts +361 -0
  1216. package/src/test-phase74-linter.ts +565 -0
  1217. package/src/test-phase75-repl.ts +227 -0
  1218. package/src/test-phase76-testrunner.ts +439 -0
  1219. package/src/test-phase77-doc.ts +416 -0
  1220. package/src/test-phase78-debugger.ts +370 -0
  1221. package/src/test-phase79-watch.ts +224 -0
  1222. package/src/test-phase8-oci.ts +264 -0
  1223. package/src/test-phase80-ci.ts +282 -0
  1224. package/src/test-phase81-pkg.ts +383 -0
  1225. package/src/test-phase82-profiler.ts +336 -0
  1226. package/src/test-phase83-vm.ts +318 -0
  1227. package/src/test-phase84-optimizer.ts +424 -0
  1228. package/src/test-phase85-codegen.ts +380 -0
  1229. package/src/test-phase86-lsp.ts +533 -0
  1230. package/src/test-phase87-packages.ts +277 -0
  1231. package/src/test-phase88-selfhost.ts +412 -0
  1232. package/src/test-phase89-bench.ts +361 -0
  1233. package/src/test-phase9-flnext-v2.ts +372 -0
  1234. package/src/test-phase9-learn.ts +241 -0
  1235. package/src/test-phase9-reasoning.ts +312 -0
  1236. package/src/test-phase9-search.ts +212 -0
  1237. package/src/test-phase90-release.ts +365 -0
  1238. package/src/test-phase91-maybe.ts +257 -0
  1239. package/src/test-phase92-cot.ts +438 -0
  1240. package/src/test-phase93-tot.ts +462 -0
  1241. package/src/test-phase94-reflect.ts +498 -0
  1242. package/src/test-phase95-context.ts +268 -0
  1243. package/src/test-phase96-errors.ts +296 -0
  1244. package/src/test-phase97-tools.ts +344 -0
  1245. package/src/test-phase98-agent.ts +370 -0
  1246. package/src/test-phase99-self-improve.ts +394 -0
  1247. package/src/test-phase9a-websearch.ts +283 -0
  1248. package/src/test-phase9ab-integration.ts +140 -0
  1249. package/src/test-phase9b-persistence.ts +448 -0
  1250. package/src/test-phase9c-conditional.ts +251 -0
  1251. package/src/test-phase9c-extension.ts +270 -0
  1252. package/src/test-phase9c-feedback.ts +263 -0
  1253. package/src/test-phase9c-loop.ts +239 -0
  1254. package/src/test-selfhosting-sh1.ts +41 -0
  1255. package/src/test-selfhosting-sh2.ts +84 -0
  1256. package/src/test-selfhosting-sh3.ts +61 -0
  1257. package/src/test-selfhosting-sh4.ts +65 -0
  1258. package/src/test-type-classes-dispatch.ts +202 -0
  1259. package/src/test-type-classes.ts +320 -0
  1260. package/src/test-type-inference.ts +464 -0
  1261. package/src/test-typeclass-parsing-final.ts +218 -0
  1262. package/src/test-typeclass-parsing.ts +264 -0
  1263. package/src/todo-server-30116.ts +53 -0
  1264. package/src/token.ts +130 -0
  1265. package/src/tool-registry.ts +195 -0
  1266. package/src/tot.ts +258 -0
  1267. package/src/try-reason.ts +109 -0
  1268. package/src/type-check-static.ts +417 -0
  1269. package/src/type-checker.ts +245 -0
  1270. package/src/type-inference.ts +271 -0
  1271. package/src/type-system.ts +169 -0
  1272. package/src/version-self.ts +219 -0
  1273. package/src/vm-eligible.ts +106 -0
  1274. package/src/vm.ts +219 -0
  1275. package/src/vote.ts +127 -0
  1276. package/src/vpm/checksum-test.fl +193 -0
  1277. package/src/vpm/checksum.fl +219 -0
  1278. package/src/vpm/error-test.fl +211 -0
  1279. package/src/vpm/error.fl +218 -0
  1280. package/src/vpm/lock-file.fl +380 -0
  1281. package/src/vpm/logging-test.fl +194 -0
  1282. package/src/vpm/logging.fl +294 -0
  1283. package/src/vpm/resolver-test.fl +117 -0
  1284. package/src/vpm/resolver.fl +618 -0
  1285. package/src/vpm/semver-test.fl +180 -0
  1286. package/src/vpm/semver.fl +143 -0
  1287. package/src/vpm-cli.ts +1955 -0
  1288. package/src/web/app-router.ts +286 -0
  1289. package/src/web/fl-executor.ts +655 -0
  1290. package/src/web/image-optimizer.ts +206 -0
  1291. package/src/web/index.ts +14 -0
  1292. package/src/web/page-renderer.ts +287 -0
  1293. package/src/web/server.ts +553 -0
  1294. package/src/web-search-adapter.ts +348 -0
  1295. package/src/wisdom.ts +441 -0
  1296. package/src/world-model.ts +348 -0
  1297. package/stdlib/cache.fl +42 -0
  1298. package/stdlib/csv.fl +38 -0
  1299. package/stdlib/date-ext.fl +68 -0
  1300. package/stdlib/log.fl +44 -0
  1301. package/stdlib/math-ext.fl +57 -0
  1302. package/stdlib/number-ext.fl +47 -0
  1303. package/stdlib/queue.fl +57 -0
  1304. package/stdlib/string-ext.fl +45 -0
  1305. package/stdlib/validate.fl +123 -0
  1306. package/stdlib/web/components.fl +125 -0
  1307. package/stdlib/web/csrf.fl +61 -0
  1308. package/stdlib/web/format.fl +75 -0
  1309. package/stdlib/web/forms.fl +94 -0
  1310. package/stdlib/web/image.fl +77 -0
  1311. package/stdlib/web/metadata.fl +85 -0
  1312. package/stdlib/web/pagination.fl +62 -0
  1313. package/stdlib/web/state.fl +167 -0
  1314. package/stdlib/web/styles.fl +68 -0
  1315. package/stdlib/web/toast.fl +62 -0
  1316. package/stdlib/web/v9-stdlib-dom.fl +92 -0
  1317. package/stdlib/web/v9-stdlib-fetch.fl +90 -0
  1318. package/stdlib/web/v9-stdlib-storage.fl +70 -0
  1319. package/stdlib/web/v9-stdlib-ui.fl +115 -0
  1320. package/stdlib/web/ws-client.fl +125 -0
  1321. package/tests/.v11-backup/test-migrate-sample.fl +22 -0
  1322. package/tests/PHASE-C-VERIFICATION-REPORT.md +125 -0
  1323. package/tests/benchmark-v11.1.js +103 -0
  1324. package/tests/evidence/01-about.html +1 -0
  1325. package/tests/evidence/02-post-hello.html +1 -0
  1326. package/tests/evidence/02-post-world.html +1 -0
  1327. package/tests/evidence/03-home.html +1 -0
  1328. package/tests/evidence/04-dist/404.html +1 -0
  1329. package/tests/evidence/04-dist/about/index.html +1 -0
  1330. package/tests/evidence/04-dist/index.html +1 -0
  1331. package/tests/evidence/04-dist/post/hello/index.html +1 -0
  1332. package/tests/evidence/04-dist/post/world/index.html +1 -0
  1333. package/tests/evidence/05-dist/404.html +1 -0
  1334. package/tests/evidence/05-dist/about/index.html +1 -0
  1335. package/tests/evidence/05-dist/index.html +1 -0
  1336. package/tests/evidence/05-dist/post/hello/index.html +1 -0
  1337. package/tests/evidence/05-dist/post/world/index.html +1 -0
  1338. package/tests/evidence/06-dist/404.html +1 -0
  1339. package/tests/evidence/06-dist/about/index.html +1 -0
  1340. package/tests/evidence/06-dist/index.html +1 -0
  1341. package/tests/evidence/06-dist/post/hello/index.html +1 -0
  1342. package/tests/evidence/06-dist/post/world/index.html +1 -0
  1343. package/tests/evidence/07-markdown.html +1 -0
  1344. package/tests/evidence/08-rss.xml +25 -0
  1345. package/tests/evidence/09-robots.txt +4 -0
  1346. package/tests/evidence/09-sitemap.xml +12 -0
  1347. package/tests/evidence/10-jsonld.html +1 -0
  1348. package/tests/evidence/_results.txt +11 -0
  1349. package/tests/evidence/about.html +1 -0
  1350. package/tests/evidence/home.html +1 -0
  1351. package/tests/evidence/missing.html +42 -0
  1352. package/tests/evidence/post-hello.html +1 -0
  1353. package/tests/evidence/post-world.html +1 -0
  1354. package/tests/fixtures/basic-app/about/page.fl +1 -0
  1355. package/tests/fixtures/basic-app/api/echo/route.fl +5 -0
  1356. package/tests/fixtures/basic-app/layout.fl +1 -0
  1357. package/tests/fixtures/basic-app/not-found.fl +1 -0
  1358. package/tests/fixtures/basic-app/page.fl +1 -0
  1359. package/tests/fixtures/basic-app/post/[slug]/generate-static-params.fl +1 -0
  1360. package/tests/fixtures/basic-app/post/[slug]/page.fl +1 -0
  1361. package/tests/fixtures/stdlib-probes/blog.fl +6 -0
  1362. package/tests/fixtures/stdlib-probes/jsonld.fl +1 -0
  1363. package/tests/fixtures/stdlib-probes/map-probe.fl +3 -0
  1364. package/tests/fixtures/stdlib-probes/map-shape.fl +2 -0
  1365. package/tests/fixtures/stdlib-probes/md.fl +1 -0
  1366. package/tests/fixtures/stdlib-probes/robots.fl +1 -0
  1367. package/tests/fixtures/stdlib-probes/rss.fl +4 -0
  1368. package/tests/fixtures/stdlib-probes/sitemap.fl +1 -0
  1369. package/tests/l2/case-01-arithmetic.fl +6 -0
  1370. package/tests/l2/case-02-comparisons.fl +15 -0
  1371. package/tests/l2/case-03-logic.fl +15 -0
  1372. package/tests/l2/case-04-control-flow.fl +15 -0
  1373. package/tests/l2/case-05-functions.fl +13 -0
  1374. package/tests/l2/case-06-collections.fl +14 -0
  1375. package/tests/l2/case-07-pattern-matching.fl +14 -0
  1376. package/tests/l2/case-08-recursion.fl +19 -0
  1377. package/tests/l2/case-09-strings.fl +13 -0
  1378. package/tests/l2/case-10-loops.fl +17 -0
  1379. package/tests/l2/case-11-higher-order.fl +13 -0
  1380. package/tests/l2/case-12-edge-cases.fl +14 -0
  1381. package/tests/l2/case-13-ai-vector.fl +22 -0
  1382. package/tests/l2/case-14-ai-cosine.fl +25 -0
  1383. package/tests/l2/case-15-ai-template.fl +22 -0
  1384. package/tests/l2/case-16-ai-ranking.fl +20 -0
  1385. package/tests/l2/case-17-stdlib-extended.fl +32 -0
  1386. package/tests/l2-proof/01-arithmetic.bootstrap.js +141 -0
  1387. package/tests/l2-proof/01-arithmetic.fl +15 -0
  1388. package/tests/l2-proof/01-arithmetic.stage1.js +141 -0
  1389. package/tests/l2-proof/02-comparisons.bootstrap.js +141 -0
  1390. package/tests/l2-proof/02-comparisons.fl +17 -0
  1391. package/tests/l2-proof/03-logic.bootstrap.js +141 -0
  1392. package/tests/l2-proof/03-logic.fl +15 -0
  1393. package/tests/l2-proof/04-control-flow.bootstrap.js +146 -0
  1394. package/tests/l2-proof/04-control-flow.fl +24 -0
  1395. package/tests/l2-proof/05-functions.bootstrap.js +143 -0
  1396. package/tests/l2-proof/05-functions.fl +16 -0
  1397. package/tests/l2-proof/06-collections.bootstrap.js +146 -0
  1398. package/tests/l2-proof/06-collections.fl +27 -0
  1399. package/tests/l2-proof/07-pattern-matching.bootstrap.js +142 -0
  1400. package/tests/l2-proof/07-pattern-matching.fl +23 -0
  1401. package/tests/l2-proof/08-async-errors.bootstrap.js +142 -0
  1402. package/tests/l2-proof/08-async-errors.fl +17 -0
  1403. package/tests/l2-proof/09-strings.bootstrap.js +141 -0
  1404. package/tests/l2-proof/09-strings.fl +13 -0
  1405. package/tests/l2-proof/10-type-checks.bootstrap.js +141 -0
  1406. package/tests/l2-proof/10-type-checks.fl +17 -0
  1407. package/tests/l2-proof/11-recursion.bootstrap.js +143 -0
  1408. package/tests/l2-proof/11-recursion.fl +21 -0
  1409. package/tests/l2-proof/12-edge-cases.bootstrap.js +141 -0
  1410. package/tests/l2-proof/12-edge-cases.fl +17 -0
  1411. package/tests/parity/01-app-router-static.sh +18 -0
  1412. package/tests/parity/02-app-router-dynamic.sh +18 -0
  1413. package/tests/parity/03-layout-children.sh +17 -0
  1414. package/tests/parity/04-not-found.sh +22 -0
  1415. package/tests/parity/05-ssg.sh +21 -0
  1416. package/tests/parity/06-parallel-render.sh +21 -0
  1417. package/tests/parity/07-markdown.sh +16 -0
  1418. package/tests/parity/08-rss-atom.sh +18 -0
  1419. package/tests/parity/09-sitemap-robots.sh +23 -0
  1420. package/tests/parity/10-jsonld.sh +16 -0
  1421. package/tests/parity/11-blog-helpers.sh +28 -0
  1422. package/tests/parity/12-api-routes.sh +25 -0
  1423. package/tests/parity/_lib.sh +53 -0
  1424. package/tests/parity/run-all.sh +89 -0
  1425. package/tests/parity/score.sh +20 -0
  1426. package/tests/phase-c-fuzzing.fl +89 -0
  1427. package/tests/phase-c-property-testing.fl +137 -0
  1428. package/tests/phase-c-sha-verification.fl +117 -0
  1429. package/tests/phase-c-validation.fl +194 -0
  1430. package/tests/property-testing.sh +47 -0
  1431. package/tests/regen/let-in-expr-01.fl +5 -0
  1432. package/tests/regen/let-in-expr-02.fl +6 -0
  1433. package/tests/regen/let-in-expr-03.fl +4 -0
  1434. package/tests/regen/let-in-expr-04.fl +6 -0
  1435. package/tests/regen/let-in-expr-05.fl +5 -0
  1436. package/tests/test-ai-library.fl +36 -0
  1437. package/tests/test-andor.fl +2 -0
  1438. package/tests/test-bootstrap-match.fl +5 -0
  1439. package/tests/test-cg-final.fl +5 -0
  1440. package/tests/test-cli.fl +19 -0
  1441. package/tests/test-codegen.fl +4 -0
  1442. package/tests/test-cond-flat.fl +1 -0
  1443. package/tests/test-fl-exec-op.fl +1 -0
  1444. package/tests/test-fp.fl +10 -0
  1445. package/tests/test-funcs.fl +11 -0
  1446. package/tests/test-fuzz-crash.fl +3 -0
  1447. package/tests/test-http-get.fl +3 -0
  1448. package/tests/test-json-load.fl +32 -0
  1449. package/tests/test-let-flat.fl +2 -0
  1450. package/tests/test-let-order.fl +3 -0
  1451. package/tests/test-let-simple.fl +3 -0
  1452. package/tests/test-let-syntax.fl +2 -0
  1453. package/tests/test-let.fl +3 -0
  1454. package/tests/test-lex-debug.fl +75 -0
  1455. package/tests/test-loop-bug.fl +5 -0
  1456. package/tests/test-map-entries.fl +1 -0
  1457. package/tests/test-map-pattern.fl +3 -0
  1458. package/tests/test-match-syntax.fl +5 -0
  1459. package/tests/test-migrate-sample.fl +22 -0
  1460. package/tests/test-neg.fl +1 -0
  1461. package/tests/test-nested-let.fl +4 -0
  1462. package/tests/test-node-to-pattern.fl +8 -0
  1463. package/tests/test-quant-lib.fl +114 -0
  1464. package/tests/test-reduce.fl +10 -0
  1465. package/tests/test-server.fl +3 -0
  1466. package/tests/test-simple-map.fl +4 -0
  1467. package/tests/test-simple-match.fl +3 -0
  1468. package/tests/test-simple.fl +1 -0
  1469. package/tests/test-try-bootstrap.fl +7 -0
  1470. package/tests/test-try-catch.fl +3 -0
  1471. package/tests/test-watchdog-lib.fl +69 -0
  1472. package/tests/test-which-lex.fl +4 -0
  1473. package/tsconfig.json +39 -0
@@ -0,0 +1,2154 @@
1
+ // eval-special-forms.ts — FreeLang v9 Special Form Evaluation
2
+ // Phase 57 리팩토링: interpreter.ts의 특수 폼을 분리
3
+ // fn, async, set!, define, func-ref, call, compose, pipe,
4
+ // let, set, if, cond, do/begin/progn, loop, recur, while, and, or, map
5
+ // Phase 63: defmacro, macroexpand 추가
6
+ // Phase 61: TCO 모드에서 꼬리 위치 함수 호출 → TailCall 토큰 반환
7
+ // Phase 66: defstruct — 타입이 있는 레코드 타입
8
+ // Phase 96: fl-try — Result 기반 에러 처리
9
+
10
+ import { Interpreter } from "./interpreter";
11
+ import { SExpr, ASTNode, Variable, Literal } from "./ast";
12
+ import { isBlock, isControlBlock } from "./ast";
13
+ import { tailCall, isTailCall } from "./tco";
14
+ import { StructRegistry } from "./struct-system"; // Phase 66
15
+ import { ok, err, isOk, isErr, fromThrown, ErrorCategory } from "./result-type"; // Phase 96
16
+ import { ReturnSignal } from "./return-signal";
17
+ import { BytecodeCompiler } from "./compiler"; // Phase 3-E: VM defn 컴파일
18
+ import { registerVMFunction } from "./vm-eligible"; // Phase 3-E: VM 함수 등록
19
+ import { FLRuntimeError, ErrorCodes } from "./errors"; // Phase A: 통일 에러
20
+ import { propRegistry, PropDef } from "./stdlib-property"; // AI-Native Phase 4
21
+ import { ScopeVarMeta } from "./interpreter-scope"; // Phase Y-1: 변수 메타정보
22
+
23
+ const _vmCompiler = new BytecodeCompiler(); // Phase 3-E
24
+
25
+ // ── AI-Native Phase 1: 함수 메타 레지스트리 ────────────────────────
26
+ export interface FnMeta {
27
+ doc?: string; // v11.7.3: 함수 설명
28
+ returns?: string;
29
+ context?: string;
30
+ effects?: string[];
31
+ examples?: string;
32
+ property?: any; // raw AST node — evaluated lazily by defn handler
33
+ line?: number;
34
+ file?: string;
35
+ }
36
+ export const fnMetaRegistry = new Map<string, FnMeta>();
37
+
38
+ const META_KEYS = new Set(["doc", "returns", "context", "effects", "examples", "property"]);
39
+
40
+ function extractMapMeta(mapNode: any): FnMeta | null {
41
+ if (mapNode?.kind !== "block" || mapNode?.type !== "Map") return null;
42
+ const fields: Map<string, any> = mapNode.fields;
43
+ if (!fields || !(fields instanceof Map)) return null;
44
+ if (!META_KEYS.has([...fields.keys()].find(k => META_KEYS.has(k)) ?? "")) return null;
45
+ const meta: FnMeta = {};
46
+ const strVal = (n: any): string | undefined =>
47
+ n?.kind === "literal" ? String(n.value) : undefined;
48
+ if (fields.has("doc")) meta.doc = strVal(fields.get("doc"));
49
+ if (fields.has("returns")) meta.returns = strVal(fields.get("returns"));
50
+ if (fields.has("context")) meta.context = strVal(fields.get("context"));
51
+ if (fields.has("examples")) meta.examples = strVal(fields.get("examples"));
52
+ if (fields.has("effects")) {
53
+ const eNode = fields.get("effects") as any;
54
+ if (eNode?.kind === "block" && eNode?.type === "Array") {
55
+ const items = eNode.fields?.get("items") as any[];
56
+ if (Array.isArray(items)) meta.effects = items.map(it => strVal(it) ?? "?");
57
+ }
58
+ }
59
+ if (fields.has("property")) meta.property = fields.get("property"); // raw node
60
+ return meta;
61
+ }
62
+
63
+ // ── Phase Y-1: 타입 추론 헬퍼 ─────────────────────────────
64
+ function inferType(value: any): { kind: "type"; name: string } | undefined {
65
+ if (typeof value === "number") return { kind: "type", name: "number" };
66
+ if (typeof value === "string") return { kind: "type", name: "string" };
67
+ if (typeof value === "boolean") return { kind: "type", name: "boolean" };
68
+ if (value === null) return { kind: "type", name: "nil" };
69
+ if (Array.isArray(value)) return { kind: "type", name: "list" };
70
+ if (value && typeof value === "object") {
71
+ if ((value as any)["_isVMFunc"] || (value as any).params) return { kind: "type", name: "function" };
72
+ return { kind: "type", name: "map" };
73
+ }
74
+ return undefined;
75
+ }
76
+
77
+ // ── AI-Native Phase 2: Effects 정적 분석 ─────────────────────────
78
+ // 함수명 → 발생 effect 매핑 (well-known side effects)
79
+ export const EFFECT_CATALOG = new Map<string, string>([
80
+ // HTTP 클라이언트
81
+ ["http_get", "http"], ["http-get", "http"],
82
+ ["http_post", "http"], ["http-post", "http"],
83
+ ["http_put", "http"], ["http-put", "http"],
84
+ ["http_delete", "http"], ["http-delete", "http"],
85
+ ["http_patch", "http"], ["http-patch", "http"],
86
+ ["http_get_bearer", "http"], ["http_post_bearer", "http"],
87
+ ["http_post_json", "http"], ["http_get_json", "http"],
88
+ // 파일 I/O
89
+ ["file_read", "file-read"], ["file-read", "file-read"],
90
+ ["file_write", "file-write"], ["file-write", "file-write"],
91
+ ["file_append","file-write"], ["file_delete","file-write"],
92
+ ["file_exists","file-read"], ["file_list", "file-read"],
93
+ // DB
94
+ ["db_query", "db-read"], ["db-query", "db-read"],
95
+ ["db_execute", "db-write"], ["db-execute", "db-write"],
96
+ ["db_insert", "db-write"], ["db-insert", "db-write"],
97
+ ["db_update", "db-write"], ["db-update", "db-write"],
98
+ ["db_delete", "db-write"], ["db-delete", "db-write"],
99
+ // Shell
100
+ ["shell_exec", "shell"], ["shell-exec", "shell"],
101
+ ["shell_exec_result", "shell"], ["shell-exec-result", "shell"],
102
+ ["shell_run", "shell"],
103
+ // I/O (stdout)
104
+ ["println", "io"], ["print", "io"],
105
+ ["log/info", "io"], ["log/warn", "io"], ["log/error", "io"],
106
+ // 시간/랜덤 (non-determinism)
107
+ ["now", "time"], ["timestamp", "time"],
108
+ ["random", "random"], ["rand-int", "random"],
109
+ // HTTP 서버 시작
110
+ ["server_start", "server"], ["server-start", "server"],
111
+ ]);
112
+
113
+ function collectBodyEffects(node: any, found: Set<string>): void {
114
+ if (!node) return;
115
+ if (node.kind === "sexpr") {
116
+ const op: string = node.op ?? "";
117
+ const eff = EFFECT_CATALOG.get(op);
118
+ if (eff) found.add(eff);
119
+ if (Array.isArray(node.args)) node.args.forEach((a: any) => collectBodyEffects(a, found));
120
+ } else if (node.kind === "block") {
121
+ if (node.fields instanceof Map) node.fields.forEach((v: any) => collectBodyEffects(v, found));
122
+ } else if (node.kind === "literal" || node.kind === "variable") {
123
+ // leaf — no recursion needed
124
+ }
125
+ }
126
+
127
+ function checkEffects(fnName: string, declaredEffects: string[], bodyNode: any, line?: number, isPure?: boolean): void {
128
+ const found = new Set<string>();
129
+ collectBodyEffects(bodyNode, found);
130
+
131
+ const pure = isPure || declaredEffects.length === 0;
132
+ const declaredSet = new Set(declaredEffects.map(e =>
133
+ e.startsWith(":") ? e.slice(1) : e));
134
+
135
+ const undeclared: string[] = [];
136
+ for (const eff of found) {
137
+ if (!declaredSet.has(eff)) undeclared.push(eff);
138
+ }
139
+
140
+ if (undeclared.length > 0) {
141
+ const hint = undeclared.map(e => `:${e}`).join(" ");
142
+ if (pure) {
143
+ // Phase 3: ^pure/:effects [] 위반 → 컴파일 에러
144
+ throw new FLRuntimeError(
145
+ ErrorCodes.PURE_VIOLATION,
146
+ `${fnName}: ^pure 함수에서 side effect 감지 — ${hint}`,
147
+ { fn: fnName, expected: "no side effects", got: hint },
148
+ undefined, line
149
+ );
150
+ }
151
+ process.stderr.write(
152
+ `\x1b[33m[effects]\x1b[0m \x1b[1m${fnName}\x1b[0m` +
153
+ `${line ? ` (line ${line})` : ""}` +
154
+ ` 선언 안 된 effect: \x1b[33m${hint}\x1b[0m` +
155
+ ` → :effects 에 추가 필요\n`
156
+ );
157
+ }
158
+ }
159
+
160
+ // ── Phase A: 통일 에러 helper ────────────────────────────────────
161
+ function throwArgCount(fn: string, expected: string, got: number, line?: number): never {
162
+ throw new FLRuntimeError(
163
+ ErrorCodes.ARG_COUNT,
164
+ `${fn}: expects ${expected} args, got ${got}`,
165
+ { fn, expected, got: String(got) },
166
+ undefined, line
167
+ );
168
+ }
169
+
170
+ function throwInvalidForm(fn: string, msg: string, line?: number): never {
171
+ throw new FLRuntimeError(
172
+ ErrorCodes.INVALID_FORM,
173
+ `${fn}: ${msg}`,
174
+ { fn },
175
+ undefined, line
176
+ );
177
+ }
178
+
179
+ function throwFnNotFound(fnName: string, line?: number): never {
180
+ throw new FLRuntimeError(
181
+ ErrorCodes.FN_NOT_FOUND,
182
+ `Function not found: ${fnName}`,
183
+ { fn: fnName },
184
+ undefined, line
185
+ );
186
+ }
187
+
188
+ export function evalSpecialForm(interp: Interpreter, op: string, expr: SExpr): any {
189
+ const ev = (node: any) => (interp as any).eval(node);
190
+ const callUser = (name: string, a: any[]) => (interp as any).callUserFunction(name, a);
191
+ const callFnVal = (fn: any, a: any[]) => (interp as any).callFunctionValue(fn, a);
192
+ const callAsyncFnVal = (fn: any, a: any[]) => (interp as any).callAsyncFunctionValue(fn, a);
193
+ const callFn = (fn: any, a: any[]) => (interp as any).callFunction(fn, a);
194
+ const ctx = interp.context;
195
+
196
+ // ── use ──────────────────────────────────────────────────────────
197
+ // Phase D: (use NAME) — self/stdlib/NAME.fl 자동 로드 (간소 import)
198
+ // 이미 import된 모듈은 cache로 skip (interp.importedFiles)
199
+ if (op === "use") {
200
+ if (expr.args.length < 1) throwArgCount("use", ">=1", expr.args.length, expr.line);
201
+ const fs = require("fs");
202
+ const path = require("path");
203
+ let loadedAny = false;
204
+ for (const arg of expr.args) {
205
+ // arg는 literal symbol 또는 string. value로 통일
206
+ let name: string | null = null;
207
+ if ((arg as any).kind === "literal") name = String((arg as any).value);
208
+ else if ((arg as any).kind === "variable") name = String((arg as any).name).replace(/^\$/, "");
209
+ if (!name) throwInvalidForm("use", "module name must be symbol or string", expr.line);
210
+ // Y5: 플러그인 탐색 경로 (우선순위)
211
+ // 1. ./plugins/NAME.fl (로컬)
212
+ // 2. ~/.fl/plugins/NAME.fl (글로벌)
213
+ // 3. self/stdlib/NAME.fl (내장)
214
+ // 4. NAME.fl (프로젝트)
215
+ const homeDir = require("os").homedir();
216
+ const candidates = [
217
+ path.resolve(process.cwd(), "plugins", name + ".fl"),
218
+ path.resolve(homeDir, ".fl", "plugins", name + ".fl"),
219
+ path.resolve(process.cwd(), "self/stdlib", name + ".fl"),
220
+ path.resolve(process.cwd(), name + ".fl"),
221
+ path.resolve(process.cwd(), name),
222
+ ];
223
+ let absPath: string | null = null;
224
+ for (const c of candidates) {
225
+ if (fs.existsSync(c) && fs.statSync(c).isFile()) { absPath = c; break; }
226
+ }
227
+ if (!absPath) {
228
+ throw new FLRuntimeError(
229
+ ErrorCodes.RUNTIME,
230
+ `(use ${name}): module not found. Tried: ${candidates.join(", ")}`,
231
+ { fn: "use", varName: name },
232
+ undefined, expr.line
233
+ );
234
+ }
235
+ // 이미 로드된 파일이면 skip
236
+ const importedSet: Set<string> = (interp as any).importedFiles ?? new Set();
237
+ if (importedSet.has(absPath)) continue;
238
+ importedSet.add(absPath);
239
+ (interp as any).importedFiles = importedSet;
240
+ // 파일 로드 + 평가
241
+ const src = fs.readFileSync(absPath, "utf-8");
242
+ const { lex } = require("./lexer");
243
+ const { parse } = require("./parser");
244
+ (interp as any).interpret(parse(lex(src, absPath)));
245
+ loadedAny = true;
246
+ }
247
+ return loadedAny;
248
+ }
249
+
250
+ // ── fn ───────────────────────────────────────────────────────────
251
+ if (op === "fn") {
252
+ if (expr.args.length < 2) throwArgCount("fn", ">=2", expr.args.length, expr.line);
253
+ const paramsNode = expr.args[0];
254
+ const params: any[] = [];
255
+ const paramDefaults: (any | undefined)[] = []; // parallel to params, undefined if no default
256
+ if ((paramsNode as any).kind === "block" && (paramsNode as any).type === "Array") {
257
+ const items = (paramsNode as any).fields.get("items");
258
+ if (Array.isArray(items)) {
259
+ for (const item of items) {
260
+ // ^type 힌트 심볼은 스킵 (타입 힌트는 런타임에서 무시)
261
+ if ((item as any).kind === "literal" && (item as any).type === "symbol"
262
+ && String((item as any).value).startsWith("^")) continue;
263
+ // Map 구조분해: {:keys [name age]} 패턴 — AST 노드 그대로 저장
264
+ if ((item as any).kind === "block" && (item as any).type === "Map") {
265
+ params.push(item);
266
+ paramDefaults.push(undefined);
267
+ continue;
268
+ }
269
+ // 기본값: [$var defaultExpr] → 중첩 Array 블록
270
+ if ((item as any).kind === "block" && (item as any).type === "Array") {
271
+ const inner = (item as any).fields?.get("items") ?? [];
272
+ if (inner.length >= 2) {
273
+ const nameNode = inner[0] as any;
274
+ const n = nameNode.kind === "variable" ? nameNode.name
275
+ : nameNode.kind === "literal" ? String(nameNode.value) : "";
276
+ params.push(n.startsWith("$") ? n.slice(1) : n);
277
+ paramDefaults.push(inner[1]); // AST 노드 저장 → 호출 시점 lazy 평가
278
+ }
279
+ continue;
280
+ }
281
+ // v11.1: variable ($x) 또는 bare symbol (x) 모두 허용 → 정식 이름은 $-접두사 포함
282
+ if ((item as any).kind === "variable") {
283
+ const n = (item as Variable).name;
284
+ params.push(n.startsWith("$") ? n.slice(1) : n);
285
+ paramDefaults.push(undefined);
286
+ } else if ((item as any).kind === "literal" && (item as any).type === "symbol") {
287
+ const v = (item as any).value as string;
288
+ params.push(v.startsWith("$") ? v.slice(1) : v);
289
+ paramDefaults.push(undefined);
290
+ }
291
+ }
292
+ }
293
+ } else if ((paramsNode as any).kind === "sexpr") {
294
+ throwInvalidForm(
295
+ "fn",
296
+ `파라미터 목록은 대괄호 [ ]를 사용하세요.\n 잘못된 예: (fn (x y) ...)\n 올바른 예: (fn [$x $y] ...)`,
297
+ expr
298
+ );
299
+ } else {
300
+ throwInvalidForm(
301
+ "fn",
302
+ `파라미터는 [변수1 변수2 ...] 형태여야 합니다.`,
303
+ expr
304
+ );
305
+ }
306
+ const body = expr.args.length === 2
307
+ ? expr.args[1]
308
+ : { kind: "sexpr" as const, op: "do", args: expr.args.slice(1) };
309
+ const hasDefaults = paramDefaults.some((d) => d !== undefined);
310
+ return {
311
+ kind: "function-value",
312
+ params,
313
+ ...(hasDefaults && { paramDefaults }),
314
+ body,
315
+ capturedEnv: ctx.variables.snapshot(),
316
+ name: undefined,
317
+ };
318
+ }
319
+
320
+ // ── defn (v11.1: Clojure 스타일 sugar) ───────────────────────────
321
+ // (defn name [params...] body) → (define name (fn [params...] body))
322
+ if (op === "defn" || op === "defun") {
323
+ if (expr.args.length < 3) throwArgCount("defn", ">=3", expr.args.length, expr.line);
324
+ // ^return-type 또는 ^pure 힌트가 첫 arg로 올 수 있음
325
+ let argIdx = 0;
326
+ let isPureHint = false;
327
+ if (expr.args[argIdx]?.kind === "literal" && String((expr.args[argIdx] as any).value).startsWith("^")) {
328
+ const hint = String((expr.args[argIdx] as any).value);
329
+ if (hint === "^pure") isPureHint = true;
330
+ argIdx++;
331
+ }
332
+ const nameNode = expr.args[argIdx++] as any;
333
+ let name: string;
334
+ if (nameNode.kind === "variable") name = nameNode.name;
335
+ else if (nameNode.kind === "literal" && nameNode.type === "symbol") name = nameNode.value as string;
336
+ else throwInvalidForm("defn", "first argument must be a symbol (function name)", expr.line);
337
+
338
+ const paramsNode = expr.args[argIdx];
339
+ let bodyArgs = expr.args.slice(argIdx + 1);
340
+
341
+ // AI-Native Phase 1+2: 첫 body 표현식이 메타 맵이면 분리 + effects 검사
342
+ let registeredMeta: FnMeta | null = null;
343
+ if (bodyArgs.length > 1) {
344
+ const meta = extractMapMeta(bodyArgs[0]);
345
+ if (meta) {
346
+ meta.line = expr.line;
347
+ fnMetaRegistry.set(name!, meta);
348
+ registeredMeta = meta;
349
+ bodyArgs = bodyArgs.slice(1);
350
+ }
351
+ }
352
+
353
+ const body = bodyArgs.length === 1
354
+ ? bodyArgs[0]
355
+ : ({ kind: "sexpr" as const, op: "do", args: bodyArgs } as any);
356
+
357
+ // AI-Native Phase 2+3: effects 검사 + ^pure 강제
358
+ if (isPureHint) {
359
+ // ^pure 힌트: :effects []와 동일 — effect 발견 시 에러
360
+ checkEffects(name!, [], body, expr.line, true);
361
+ // 메타에도 기록
362
+ if (!registeredMeta) {
363
+ registeredMeta = { line: expr.line, effects: [] };
364
+ fnMetaRegistry.set(name!, registeredMeta);
365
+ } else if (!registeredMeta.effects) {
366
+ registeredMeta.effects = [];
367
+ }
368
+ } else if (registeredMeta?.effects !== undefined) {
369
+ checkEffects(name!, registeredMeta.effects, body, expr.line);
370
+ }
371
+
372
+ // (fn [params] body) 를 synth → 현재 scope에서 eval하여 function-value 획득
373
+ const fnExpr: any = { kind: "sexpr", op: "fn", args: [paramsNode, body] };
374
+ const fnValue = (interp as any).evalSExpr(fnExpr);
375
+
376
+ // Phase 3-E: VM 함수 컴파일 및 등록
377
+ try {
378
+ const funcChunk = _vmCompiler.compileFunctionBody(fnValue.params, fnValue.body, name);
379
+ const vmFuncObj = {
380
+ _isVMFunc: true,
381
+ _chunk: funcChunk,
382
+ _params: fnValue.params,
383
+ _closure: fnValue.capturedEnv ? [...fnValue.capturedEnv.entries()] : []
384
+ };
385
+ registerVMFunction(name, vmFuncObj);
386
+ } catch {
387
+ // 컴파일 실패 시 이름만 등록 (fallback)
388
+ registerVMFunction(name);
389
+ }
390
+
391
+ // functions에도 등록 (callUserFunction 경로 지원)
392
+ const funcDef: any = {
393
+ name,
394
+ params: fnValue.params,
395
+ body: fnValue.body,
396
+ capturedEnv: fnValue.capturedEnv,
397
+ };
398
+ if (fnValue.paramDefaults) funcDef.paramDefaults = fnValue.paramDefaults;
399
+ ctx.functions.set(name, funcDef);
400
+
401
+ // AI-Native Phase 4: :property 인라인 → defprop 자동 등록
402
+ if (registeredMeta?.property) {
403
+ try {
404
+ const propNode = registeredMeta.property as any;
405
+ // :property 맵에서 :args, :check, :samples 추출
406
+ if (propNode?.kind === "block" && propNode?.type === "Map") {
407
+ const pf: Map<string, any> = propNode.fields;
408
+ const argsNode = pf.get("args") as any;
409
+ let argTypes: string[] = [];
410
+ if (argsNode?.kind === "block" && argsNode?.type === "Array") {
411
+ const items = argsNode.fields?.get("items") as any[];
412
+ if (Array.isArray(items)) argTypes = items.map((it: any) =>
413
+ it?.kind === "literal" ? String(it.value).replace(/^:/, "") : "any");
414
+ }
415
+ const checkNode = pf.get("check") as any;
416
+ const checkFn = checkNode ? ev(checkNode) : null;
417
+ const samplesNode = pf.get("samples") as any;
418
+ const samples = samplesNode?.kind === "literal" && typeof samplesNode.value === "number"
419
+ ? samplesNode.value : 100;
420
+ propRegistry.set(`prop-${name}`, {
421
+ name: `prop-${name}`, fn: name!, args: argTypes,
422
+ check: checkFn, samples, line: expr.line,
423
+ });
424
+ }
425
+ } catch { /* property 등록 실패 시 무시 */ }
426
+ }
427
+
428
+ // name을 set → bare symbol/variable 둘 다로 접근 가능하게 저장
429
+ ctx.variables.set("$" + name, fnValue);
430
+ ctx.variables.set(name, fnValue);
431
+ return fnValue;
432
+ }
433
+
434
+ // ── defprop (AI-Native Phase 4) ──────────────────────────────────
435
+ // (defprop name {:fn "add" :args [:int :int] :check (fn [$a $b] ...) :samples 100})
436
+ if (op === "defprop") {
437
+ if (expr.args.length < 2) throwArgCount("defprop", ">=2", expr.args.length, expr.line);
438
+ const nameNode = expr.args[0] as any;
439
+ const propName: string = nameNode?.kind === "variable" ? nameNode.name
440
+ : nameNode?.kind === "literal" ? String(nameNode.value) : "prop-" + Date.now();
441
+
442
+ const specNode = expr.args[1] as any;
443
+ if (specNode?.kind !== "block" || specNode?.type !== "Map") {
444
+ throw new FLRuntimeError(ErrorCodes.INVALID_FORM,
445
+ `defprop: 두 번째 인자는 맵이어야 합니다 {:fn :args :check}`, {}, undefined, expr.line);
446
+ }
447
+ const fields: Map<string, any> = specNode.fields;
448
+
449
+ // :fn — 대상 함수명
450
+ const fnNode = fields.get("fn") as any;
451
+ const fnName: string = fnNode?.kind === "literal" ? String(fnNode.value) : "";
452
+
453
+ // :args — 타입 배열 [:int :int]
454
+ const argsNode = fields.get("args") as any;
455
+ let argTypes: string[] = [];
456
+ if (argsNode?.kind === "block" && argsNode?.type === "Array") {
457
+ const items = argsNode.fields?.get("items") as any[];
458
+ if (Array.isArray(items)) {
459
+ argTypes = items.map((it: any) =>
460
+ it?.kind === "literal" ? String(it.value).replace(/^:/, "") : "any");
461
+ }
462
+ }
463
+
464
+ // :check — FL 함수 (evaluate now)
465
+ const checkNode = fields.get("check") as any;
466
+ const checkFn = checkNode ? ev(checkNode) : null;
467
+
468
+ // :samples — 횟수 (기본 100)
469
+ const samplesNode = fields.get("samples") as any;
470
+ const samples = samplesNode?.kind === "literal" && typeof samplesNode.value === "number"
471
+ ? samplesNode.value : 100;
472
+
473
+ const prop: PropDef = {
474
+ name: propName, fn: fnName, args: argTypes,
475
+ check: checkFn, samples, line: expr.line,
476
+ };
477
+ propRegistry.set(propName, prop);
478
+ return prop;
479
+ }
480
+
481
+ // ── async ─────────────────────────────────────────────────────────
482
+ if (op === "async") {
483
+ if (expr.args.length < 3) throwArgCount("async", ">=3", expr.args.length, expr.line);
484
+ const nameNode = expr.args[0];
485
+ const name = (nameNode as Variable).name || "async-fn";
486
+ const paramsNode = expr.args[1];
487
+ const params: string[] = [];
488
+ if ((paramsNode as any).kind === "block" && (paramsNode as any).type === "Array") {
489
+ const items = (paramsNode as any).fields.get("items");
490
+ if (Array.isArray(items)) {
491
+ for (const item of items) {
492
+ if ((item as any).kind === "variable") params.push((item as Variable).name);
493
+ }
494
+ }
495
+ } else if ((paramsNode as any).kind === "sexpr") {
496
+ throwInvalidForm(
497
+ "async",
498
+ `파라미터 목록은 대괄호 [ ]를 사용하세요.\n 잘못된 예: (async myFn (x) ...)\n 올바른 예: (async myFn [$x] ...)`,
499
+ expr
500
+ );
501
+ } else {
502
+ throwInvalidForm(
503
+ "async",
504
+ `파라미터는 [변수1 변수2 ...] 형태여야 합니다.`,
505
+ expr
506
+ );
507
+ }
508
+ return {
509
+ kind: "async-function-value",
510
+ name,
511
+ params,
512
+ body: expr.args[2],
513
+ capturedEnv: ctx.variables.snapshot(),
514
+ };
515
+ }
516
+
517
+ // ── set! ──────────────────────────────────────────────────────────
518
+ if (op === "set!") {
519
+ if (expr.args.length < 2) throwArgCount("set!", ">=2", expr.args.length, expr.line);
520
+ // #17/#18: v12에서 set! 완전 제거 (FL_V12=1 시 에러, 기본은 경고)
521
+ const varHint = (expr.args[0] as any)?.name ?? (expr.args[0] as any)?.value ?? "x";
522
+ if (process.env.FL_V12 === "1") {
523
+ throw new FLRuntimeError(
524
+ ErrorCodes.INVALID_FORM,
525
+ `[v12] set!은 제거됐습니다 (line ${expr.line ?? "?"}). atom을 사용하세요:\n (define ${varHint} (atom 초기값)) → (swap! ${varHint} (fn [v] 새값)) 또는 (reset! ${varHint} 새값)`,
526
+ { fn: "set!" },
527
+ undefined, expr.line
528
+ );
529
+ }
530
+ console.warn(`⚠️ [FreeLang] set! is deprecated (line ${expr.line ?? "?"}). 전역 변수 수정은 클로저에 전파되지 않습니다. atom 권장: (define x (atom 0)) (swap! x + 1)`);
531
+ const nameNode = expr.args[0];
532
+
533
+ // (set! (get $obj "key") value) — map/array 프로퍼티 뮤테이션
534
+ if ((nameNode as any).kind === "sexpr" && (nameNode as any).op === "get") {
535
+ const getArgs = (nameNode as any).args;
536
+ const obj = ev(getArgs[0]);
537
+ const key = ev(getArgs[1]);
538
+ const value = ev(expr.args[1]);
539
+ if (obj !== null && typeof obj === "object") {
540
+ const k = typeof key === "string" && key.startsWith(":") ? key.slice(1) : String(key);
541
+ obj[k] = value;
542
+ }
543
+ return ev(expr.args[1]);
544
+ }
545
+
546
+ let name: string;
547
+ if ((nameNode as any).kind === "variable") {
548
+ name = "$" + (nameNode as any).name;
549
+ } else if ((nameNode as any).kind === "literal") {
550
+ name = "$" + (nameNode as any).value;
551
+ } else {
552
+ throwInvalidForm("set!", "first argument must be a symbol", expr.line);
553
+ }
554
+ const value = ev(expr.args[1]);
555
+ if (!ctx.variables.mutate(name, value)) ctx.variables.set(name, value);
556
+ return value;
557
+ }
558
+
559
+ // ── define ────────────────────────────────────────────────────────
560
+ if (op === "define") {
561
+ if (expr.args.length < 2) throwArgCount("define", ">=2", expr.args.length, expr.line);
562
+ const nameNode = expr.args[0];
563
+ let name: string;
564
+ if ((nameNode as any).kind === "literal") {
565
+ name = (nameNode as Literal).value as string;
566
+ } else if ((nameNode as any).kind === "variable") {
567
+ name = (nameNode as Variable).name;
568
+ } else {
569
+ throwInvalidForm("define", "first argument must be a symbol or string", expr.line);
570
+ }
571
+
572
+ // 3-arg form: (define name [params] body) → define function
573
+ if (expr.args.length >= 3) {
574
+ const paramsNode = expr.args[1];
575
+ const bodyNode = expr.args.length === 3
576
+ ? expr.args[2]
577
+ : { kind: "sexpr" as const, op: "do", args: expr.args.slice(2) };
578
+ const items = (paramsNode as any).kind === "block" && (paramsNode as any).type === "Array"
579
+ ? (paramsNode as any).fields.get("items") || []
580
+ : (paramsNode as any).kind === "array"
581
+ ? (paramsNode as any).items || []
582
+ : [];
583
+ const params = (items as any[]).map((item: any) => {
584
+ if (item.kind === "variable") return item.name.startsWith("$") ? item.name : "$" + item.name;
585
+ if (item.kind === "literal") return "$" + item.value;
586
+ return "$" + (item.name || item.value || "?");
587
+ });
588
+ ctx.functions.set(name, { name, params, body: bodyNode });
589
+ return null;
590
+ }
591
+
592
+ const value = ev(expr.args[1]);
593
+ if (value !== null && value !== undefined && (value as any).kind === "function-value") {
594
+ const funcDef: any = {
595
+ name,
596
+ params: (value as any).params,
597
+ body: (value as any).body,
598
+ capturedEnv: (value as any).capturedEnv,
599
+ };
600
+ if ((value as any)._call) funcDef._call = (value as any)._call;
601
+ ctx.functions.set(name, funcDef);
602
+ if (ctx.typeChecker) {
603
+ const paramTypes = (value as any).params.map(() => ({ kind: "type" as const, name: "any" }));
604
+ ctx.typeChecker.registerFunction(name, paramTypes, { kind: "type" as const, name: "any" });
605
+ }
606
+ return value;
607
+ } else {
608
+ // Phase Y-1: 타입 추론 및 메타정보 저장
609
+ const meta: Partial<ScopeVarMeta> = {
610
+ file: (expr as any).file,
611
+ line: expr.line || (nameNode as any).line,
612
+ col: (nameNode as any).col,
613
+ type: inferType(value),
614
+ };
615
+
616
+ // #16: 재정의 감지 — FL_V12=1 시 에러, 기본은 경고
617
+ if (ctx.variables.has("$" + name)) {
618
+ if (process.env.FL_V12 === "1") {
619
+ throw new FLRuntimeError(
620
+ ErrorCodes.INVALID_FORM,
621
+ `[v12] '${name}'은(는) 이미 정의됐습니다 (line ${expr.line ?? "?"}). 가변 값은 atom을 사용하세요:\n (define ${name} (atom 초기값)) → (swap! ${name} (fn [v] 새값))`,
622
+ { fn: "define", varName: name },
623
+ undefined, expr.line
624
+ );
625
+ }
626
+ console.warn(`⚠️ [FreeLang] '${name}'은(는) 이미 정의됐습니다 (line ${expr.line ?? "?"}). 가변 값은 atom을 사용하세요: (define ${name} (atom ${JSON.stringify(value)})) → (swap! ${name} (fn [v] 새값))`);
627
+ }
628
+ ctx.variables.set("$" + name, value, meta);
629
+ return value;
630
+ }
631
+ }
632
+
633
+ // ── func-ref ──────────────────────────────────────────────────────
634
+ if (op === "func-ref") {
635
+ if (expr.args.length < 1) throwArgCount("func-ref", ">=1", expr.args.length, expr.line);
636
+ const funcName = (expr.args[0] as any).name || String(expr.args[0]);
637
+ const func = ctx.functions.get(funcName);
638
+ if (!func) throwFnNotFound(funcName, expr.line);
639
+ return {
640
+ kind: "function-value",
641
+ params: func.params,
642
+ body: func.body,
643
+ capturedEnv: ctx.variables.snapshot(),
644
+ name: funcName,
645
+ };
646
+ }
647
+
648
+ // ── call ──────────────────────────────────────────────────────────
649
+ if (op === "call") {
650
+ if (expr.args.length < 1) throwArgCount("call", ">=1", expr.args.length, expr.line);
651
+ const fn = ev(expr.args[0]);
652
+ const evaluatedArgs = expr.args.slice(1).map((a) => ev(a));
653
+ if ((fn as any).kind === "builtin-function") return (fn as any).fn(evaluatedArgs);
654
+ if ((fn as any).kind === "function-value") return callFnVal(fn, evaluatedArgs);
655
+ if ((fn as any).kind === "async-function-value") return callAsyncFnVal(fn, evaluatedArgs);
656
+ if (typeof fn === "string") return callUser(fn, evaluatedArgs);
657
+ throw new Error(`call expects function-value, got ${(fn as any).kind || typeof fn}`);
658
+ }
659
+
660
+ // ── compose / comp ───────────────────────────────────────────────
661
+ // (comp f g h) → (fn [x] (f (g (h x)))) — 오른쪽부터 적용
662
+ // 유저 함수·function-value·빌트인 모두 지원
663
+ if (op === "compose" || op === "comp") {
664
+ if (expr.args.length < 1) throw new Error(`${op} requires at least 1 function`);
665
+
666
+ // 각 인자를 핸들로 변환: 심볼은 name으로, 나머지는 즉시 평가
667
+ const handles = expr.args.map((arg: any) => {
668
+ const fk = arg.kind;
669
+ if (fk === "variable") return { type: "name", name: arg.name };
670
+ if (fk === "literal" && arg.type === "symbol") return { type: "name", name: String(arg.value) };
671
+ return { type: "val", val: ev(arg) };
672
+ });
673
+
674
+ // _call: 호출 시점의 interp.context 사용
675
+ const compFn = { kind: "function-value", name: `(${op})`, params: ["__x__"], body: null, env: null };
676
+ (compFn as any)._call = (x: any) => {
677
+ let result = x;
678
+ for (let i = handles.length - 1; i >= 0; i--) {
679
+ const handle = handles[i];
680
+ if (handle.type === "val") {
681
+ result = interp.callFunctionValue(handle.val, [result]);
682
+ } else {
683
+ // functions 맵에 있으면 callUserFunction (모듈 함수 포함)
684
+ result = interp.callUserFunction(handle.name, [result]);
685
+ }
686
+ }
687
+ return result;
688
+ };
689
+ return compFn;
690
+ }
691
+
692
+ // ── pipe ──────────────────────────────────────────────────────────
693
+ if (op === "pipe") {
694
+ if (expr.args.length < 2) throw new Error(`pipe requires at least a value and one function`);
695
+ let pipeValue = ev(expr.args[0]);
696
+ for (let i = 1; i < expr.args.length; i++) {
697
+ const fnArg = expr.args[i];
698
+ let pipeResult: any;
699
+ if ((fnArg as any).kind === "literal" && (fnArg as any).type === "symbol") {
700
+ const fnName = (fnArg as Literal).value as string;
701
+ if (ctx.functions.has(fnName)) pipeResult = callUser(fnName, [pipeValue]);
702
+ else throw new Error(`Unknown function: ${fnName}`);
703
+ } else if ((fnArg as any).kind === "variable") {
704
+ const fnName = (fnArg as Variable).name;
705
+ if (ctx.functions.has(fnName)) pipeResult = callUser(fnName, [pipeValue]);
706
+ else if (ctx.variables.has(fnName)) pipeResult = callFn(ctx.variables.get(fnName), [pipeValue]);
707
+ else throw new Error(`Unknown function or variable: ${fnName}`);
708
+ } else {
709
+ const fn = ev(fnArg);
710
+ pipeResult = callFn(fn, [pipeValue]);
711
+ }
712
+ pipeValue = pipeResult;
713
+ }
714
+ return pipeValue;
715
+ }
716
+
717
+ // ── -> (thread-first) ────────────────────────────────────────────
718
+ // (-> val (f1 extra) f2 (f3 a b))
719
+ // => (f3 (f2 (f1 val extra)) a b)
720
+ // val이 각 form의 첫 번째 인자 위치에 삽입됨
721
+ if (op === "->") {
722
+ if (expr.args.length < 2) throw new Error(`-> requires at least a value and one step`);
723
+ const TMP_VAR = "__thread_first_tmp__";
724
+ let val = ev(expr.args[0]);
725
+ for (let i = 1; i < expr.args.length; i++) {
726
+ const form = expr.args[i];
727
+ const fk = (form as any).kind;
728
+ if (fk === "sexpr") {
729
+ // (f extra-args...) → (f val extra-args...)
730
+ const sform = form as SExpr;
731
+ ctx.variables.set(TMP_VAR, val);
732
+ const tmpVar: Variable = { kind: "variable", name: TMP_VAR };
733
+ const newSexpr: SExpr = { kind: "sexpr", op: sform.op, args: [tmpVar, ...sform.args] };
734
+ val = ev(newSexpr);
735
+ ctx.variables.delete(TMP_VAR);
736
+ } else if (fk === "variable") {
737
+ const fnName = (form as Variable).name;
738
+ if (ctx.functions.has(fnName)) val = callUser(fnName, [val]);
739
+ else if (ctx.variables.has(fnName)) val = callFn(ctx.variables.get(fnName), [val]);
740
+ else throw new Error(`->: unknown function or variable: ${fnName}`);
741
+ } else if (fk === "literal" && (form as Literal).type === "symbol") {
742
+ const fnName = (form as Literal).value as string;
743
+ if (ctx.functions.has(fnName)) val = callUser(fnName, [val]);
744
+ else throw new Error(`->: unknown function: ${fnName}`);
745
+ } else {
746
+ const fn = ev(form);
747
+ val = callFn(fn, [val]);
748
+ }
749
+ }
750
+ return val;
751
+ }
752
+
753
+ // ── ->> (thread-last) ────────────────────────────────────────────
754
+ // (->> val (f1 extra) f2 (f3 a b))
755
+ // => (f3 a b (f2 (f1 val extra)))
756
+ // val이 각 form의 마지막 인자 위치에 삽입됨
757
+ if (op === "->>") {
758
+ if (expr.args.length < 2) throw new Error(`->> requires at least a value and one step`);
759
+ const TMP_VAR = "__thread_last_tmp__";
760
+ let val = ev(expr.args[0]);
761
+ for (let i = 1; i < expr.args.length; i++) {
762
+ const form = expr.args[i];
763
+ const fk = (form as any).kind;
764
+ if (fk === "sexpr") {
765
+ // (f existing-args...) → (f existing-args... val)
766
+ const sform = form as SExpr;
767
+ ctx.variables.set(TMP_VAR, val);
768
+ const tmpVar: Variable = { kind: "variable", name: TMP_VAR };
769
+ const newSexpr: SExpr = { kind: "sexpr", op: sform.op, args: [...sform.args, tmpVar] };
770
+ val = ev(newSexpr);
771
+ ctx.variables.delete(TMP_VAR);
772
+ } else if (fk === "variable") {
773
+ const fnName = (form as Variable).name;
774
+ if (ctx.functions.has(fnName)) val = callUser(fnName, [val]);
775
+ else if (ctx.variables.has(fnName)) val = callFn(ctx.variables.get(fnName), [val]);
776
+ else throw new Error(`->>: unknown function or variable: ${fnName}`);
777
+ } else if (fk === "literal" && (form as Literal).type === "symbol") {
778
+ const fnName = (form as Literal).value as string;
779
+ if (ctx.functions.has(fnName)) val = callUser(fnName, [val]);
780
+ else throw new Error(`->>: unknown function: ${fnName}`);
781
+ } else {
782
+ const fn = ev(form);
783
+ val = callFn(fn, [val]);
784
+ }
785
+ }
786
+ return val;
787
+ }
788
+
789
+ // ── ?. (nil-safe deep access) ────────────────────────────────────
790
+ // (?. $obj :key1 :key2 ...) → nil이 나오면 즉시 nil 반환
791
+ // get-in과 유사하지만 키 배열 대신 variadic 인자
792
+ if (op === "?.") {
793
+ if (expr.args.length < 1) return null;
794
+ let val = ev(expr.args[0]);
795
+ for (let i = 1; i < expr.args.length; i++) {
796
+ if (val === null || val === undefined) return null;
797
+ const keyArg = expr.args[i];
798
+ let key: any;
799
+ if ((keyArg as any).kind === "literal") {
800
+ key = (keyArg as Literal).value;
801
+ } else {
802
+ key = ev(keyArg);
803
+ }
804
+ if (typeof key === "string" && key.startsWith(":")) key = key.slice(1);
805
+ val = val instanceof Map
806
+ ? (val.get(key) ?? val.get(":" + key) ?? null)
807
+ : (val?.[String(key)] ?? null);
808
+ }
809
+ return val ?? null;
810
+ }
811
+
812
+ // ── as-> (thread with named binding) ────────────────────────────
813
+ // (as-> val $name form1 form2 ...)
814
+ // 각 form 안에서 $name 이 이전 결과를 가리킴 → 임의 위치에 삽입 가능
815
+ if (op === "as->") {
816
+ if (expr.args.length < 3) throw new Error(`as-> requires: (as-> val $name form ...)`);
817
+ const bindArg = expr.args[1];
818
+ let bindName: string;
819
+ if ((bindArg as any).kind === "variable") {
820
+ bindName = (bindArg as Variable).name; // "$v" 형태
821
+ } else if ((bindArg as any).kind === "literal") {
822
+ bindName = "$" + String((bindArg as Literal).value); // "v" → "$v"
823
+ } else {
824
+ throw new Error(`as->: second arg must be a binding name like $v`);
825
+ }
826
+ let val = ev(expr.args[0]);
827
+ ctx.variables.push();
828
+ try {
829
+ for (let i = 2; i < expr.args.length; i++) {
830
+ ctx.variables.set(bindName, val);
831
+ val = ev(expr.args[i]);
832
+ }
833
+ } finally {
834
+ ctx.variables.pop();
835
+ }
836
+ return val;
837
+ }
838
+
839
+ // ── ?? (nil 병합) ────────────────────────────────────────────────
840
+ // (?? expr default) → expr이 nil이면 default, 아니면 expr
841
+ // (?? a b c) → 왼쪽부터 첫 번째 non-nil 값 반환
842
+ if (op === "??") {
843
+ if (expr.args.length < 2) throw new Error(`?? requires at least 2 arguments`);
844
+ for (let i = 0; i < expr.args.length; i++) {
845
+ const val = ev(expr.args[i]);
846
+ if (val !== null && val !== undefined) return val;
847
+ }
848
+ return null;
849
+ }
850
+
851
+ // ── |> (thread-last pipe) ────────────────────────────────────────
852
+ // (|> val (f arg...) ...) → pipeVal을 각 단계의 마지막 인자로 주입
853
+ // (|> [1 2 3] (filter even?) (map inc)) → (map inc (filter even? [1 2 3]))
854
+ if (op === "|>") {
855
+ if (expr.args.length < 2) throw new Error(`|> requires at least a value and one function`);
856
+ let pipeVal = ev(expr.args[0]);
857
+ for (let i = 1; i < expr.args.length; i++) {
858
+ const step = expr.args[i];
859
+ const fk = (step as any).kind;
860
+ if (fk === "sexpr") {
861
+ // (f arg1 arg2 ...) → 임시 변수에 pipeVal 바인딩 후 마지막 인자로 주입
862
+ const s = step as SExpr;
863
+ const tmpVar = `__pipe_${i}__`;
864
+ ctx.variables.set(tmpVar, pipeVal);
865
+ const injectedArg: Variable = { kind: "variable", name: tmpVar };
866
+ const newSExpr: SExpr = { kind: "sexpr", op: s.op, args: [...s.args, injectedArg], line: s.line };
867
+ try {
868
+ pipeVal = ev(newSExpr);
869
+ } finally {
870
+ ctx.variables.delete(tmpVar);
871
+ }
872
+ } else if (fk === "variable") {
873
+ const fnName = (step as Variable).name;
874
+ if (ctx.functions.has(fnName)) pipeVal = callUser(fnName, [pipeVal]);
875
+ else if (ctx.variables.has(fnName)) pipeVal = callFn(ctx.variables.get(fnName), [pipeVal]);
876
+ } else if (fk === "literal" && (step as Literal).type === "symbol") {
877
+ const fnName = String((step as Literal).value);
878
+ if (ctx.functions.has(fnName)) pipeVal = callUser(fnName, [pipeVal]);
879
+ else if (ctx.variables.has(fnName)) pipeVal = callFn(ctx.variables.get(fnName), [pipeVal]);
880
+ } else {
881
+ const fn = ev(step);
882
+ pipeVal = callFn(fn, [pipeVal]);
883
+ }
884
+ }
885
+ return pipeVal;
886
+ }
887
+
888
+ // ── let ───────────────────────────────────────────────────────────
889
+ if (op === "let") {
890
+ return evalLet(interp, expr.args);
891
+ }
892
+
893
+ // ── if-let / when-let / when / unless (P3, 2026-04-25) ──────────────
894
+ // (if-let [[x expr]] then else?) — expr 평가해서 truthy면 x 바인딩 + then, 아니면 else
895
+ // (when-let [[x expr]] body...) — truthy면 x 바인딩 + body, 아니면 nil
896
+ // (when cond body...) — cond truthy면 body 실행, 아니면 nil
897
+ // (unless cond body...) — cond falsy면 body 실행
898
+ if (op === "if-let" || op === "when-let") {
899
+ if (expr.args.length < 2) throwArgCount(op, ">=2", expr.args.length, expr.line);
900
+ const bindingsNode = expr.args[0] as any;
901
+ const outerItems: any[] =
902
+ bindingsNode.kind === "block" && bindingsNode.type === "Array"
903
+ ? bindingsNode.fields?.get("items") ?? []
904
+ : [];
905
+ if (outerItems.length < 1) throwInvalidForm(op, "binding 형태가 [$x expr] 이어야 함", expr.line);
906
+
907
+ // 평탄형: [$x expr] — outerItems[0]이 variable이면 flat
908
+ // 이중 괄호형: [[x expr]] — outerItems[0]이 Array 블록
909
+ let pairItems: any[];
910
+ const firstItem = outerItems[0] as any;
911
+ if (firstItem.kind === "variable" || firstItem.kind === "literal") {
912
+ // flat form: [$x expr] → pairItems = outerItems
913
+ pairItems = outerItems;
914
+ } else {
915
+ // double-bracket form: [[x expr]] → pairItems = firstItem.items
916
+ pairItems = firstItem.kind === "block" && firstItem.type === "Array"
917
+ ? firstItem.fields?.get("items") ?? []
918
+ : [];
919
+ }
920
+ if (pairItems.length < 2) throwInvalidForm(op, "[$x expr] 형태가 잘못됨", expr.line);
921
+ const varName = pairItems[0].kind === "variable" ? pairItems[0].name
922
+ : pairItems[0].kind === "literal" ? String(pairItems[0].value) : "";
923
+ const value = ev(pairItems[1]);
924
+ const truthy = value !== null && value !== undefined && value !== false;
925
+ if (truthy) {
926
+ interp.context.variables.push();
927
+ try {
928
+ // Phase Y-1: 메타정보 저장
929
+ const meta: Partial<ScopeVarMeta> = {
930
+ line: (pairItems[0] as any).line,
931
+ col: (pairItems[0] as any).col,
932
+ type: inferType(value),
933
+ };
934
+ interp.context.variables.set(varName, value, meta);
935
+ if (op === "if-let") {
936
+ // (if-let [[x expr]] then else?)
937
+ return ev(expr.args[1]);
938
+ } else {
939
+ // (when-let [[x expr]] body...) — body는 args[1..]
940
+ let result: any = null;
941
+ for (let i = 1; i < expr.args.length; i++) result = ev(expr.args[i]);
942
+ return result;
943
+ }
944
+ } finally {
945
+ interp.context.variables.pop();
946
+ }
947
+ } else {
948
+ if (op === "if-let" && expr.args.length >= 3) return ev(expr.args[2]);
949
+ return null;
950
+ }
951
+ }
952
+ if (op === "when") {
953
+ if (expr.args.length < 2) throwArgCount("when", ">=2", expr.args.length, expr.line);
954
+ const c = ev(expr.args[0]);
955
+ if (c !== null && c !== undefined && c !== false) {
956
+ let result: any = null;
957
+ for (let i = 1; i < expr.args.length; i++) result = ev(expr.args[i]);
958
+ return result;
959
+ }
960
+ return null;
961
+ }
962
+ if (op === "unless") {
963
+ if (expr.args.length < 2) throwArgCount("unless", ">=2", expr.args.length, expr.line);
964
+ const c = ev(expr.args[0]);
965
+ if (c === null || c === undefined || c === false) {
966
+ let result: any = null;
967
+ for (let i = 1; i < expr.args.length; i++) result = ev(expr.args[i]);
968
+ return result;
969
+ }
970
+ return null;
971
+ }
972
+
973
+ // ── set ───────────────────────────────────────────────────────────
974
+ if (op === "set") {
975
+ if (expr.args.length !== 2) throwArgCount("set", "exactly 2", expr.args.length, expr.line);
976
+ const varNode = expr.args[0] as any;
977
+ let varName: string;
978
+ if (varNode.kind === "variable") varName = varNode.name;
979
+ else if (varNode.kind === "literal" && varNode.type === "symbol") varName = "$" + varNode.value;
980
+ else throwInvalidForm("set", "first argument must be a variable", expr.line);
981
+ const newValue = ev(expr.args[1]);
982
+ if (!ctx.variables.mutate(varName, newValue)) throw new Error(`set: variable ${varName} not found in scope`);
983
+ return newValue;
984
+ }
985
+
986
+ // ── if ────────────────────────────────────────────────────────────
987
+ if (op === "if") {
988
+ const condition = ev(expr.args[0]);
989
+ const branch = condition ? expr.args[1] : (expr.args[2] || null);
990
+ if (branch === null) return null;
991
+ // Phase 61: TCO 모드 — 꼬리 위치의 사용자 함수 호출을 TailCall 토큰으로 반환
992
+ if ((interp as any).tcoMode && branch !== null) {
993
+ const b = branch as any;
994
+ if (b.kind === "sexpr") {
995
+ const bop = b.op;
996
+ // 사용자 정의 함수이거나 아직 알 수 없는 함수 호출 — 일단 eval해서 확인
997
+ // (builtin이면 그냥 실행, user-func이면 TailCall)
998
+ const ctx = interp.context;
999
+ if (typeof bop === "string" && ctx.functions.has(bop)) {
1000
+ // 꼬리 위치 user-function 호출 → TailCall 토큰 반환 (스택 없이)
1001
+ const tailArgs = b.args.map((a: any) => ev(a));
1002
+ return tailCall(bop, tailArgs);
1003
+ }
1004
+ }
1005
+ }
1006
+ return ev(branch);
1007
+ }
1008
+
1009
+ // ── cond ──────────────────────────────────────────────────────────
1010
+ if (op === "cond") {
1011
+ return evalCond(interp, expr.args);
1012
+ }
1013
+
1014
+ // ── do / begin / progn ───────────────────────────────────────────
1015
+ if (op === "do" || op === "begin" || op === "progn") {
1016
+ // IIFE: ((fn-expr) arg1 arg2 ...) — parser creates do-block; detect and call
1017
+ if (expr.args.length >= 2) {
1018
+ const first = ev(expr.args[0]);
1019
+ const isCallable = typeof first === "function"
1020
+ || first?.kind === "function-value"
1021
+ || first?.kind === "async-function-value"
1022
+ || first?.kind === "closure";
1023
+ if (isCallable) {
1024
+ const callArgs = expr.args.slice(1).map((a) => ev(a));
1025
+ if (typeof first === "function") return first(...callArgs);
1026
+ if (first?.kind === "function-value" || first?.kind === "async-function-value") return (interp as any).callFunctionValue(first, callArgs);
1027
+ if (first?.kind === "closure") {
1028
+ const params: string[] = first.params || [];
1029
+ ctx.variables.push();
1030
+ try {
1031
+ if (first["closure-env"]) {
1032
+ for (const [k, v] of Object.entries((first["closure-env"] as any).vars || {})) ctx.variables.set(k, v);
1033
+ }
1034
+ for (let i = 0; i < params.length; i++) ctx.variables.set(params[i], callArgs[i] ?? null);
1035
+ let result: any = null;
1036
+ for (const node of (first.body || [])) result = ev(node);
1037
+ return result;
1038
+ } finally { ctx.variables.pop(); }
1039
+ }
1040
+ }
1041
+ // not callable: args[0] already evaluated as `first`, evaluate remaining args
1042
+ let result: any = first;
1043
+ for (const arg of expr.args.slice(1)) {
1044
+ if (isBlock(arg) && isControlBlock(arg as any)) {
1045
+ (interp as any).evalBlock(arg);
1046
+ result = null;
1047
+ continue;
1048
+ }
1049
+ result = ev(arg);
1050
+ }
1051
+ return result;
1052
+ }
1053
+ let result: any = null;
1054
+ for (const arg of expr.args) {
1055
+ if (isBlock(arg) && isControlBlock(arg as any)) {
1056
+ (interp as any).evalBlock(arg);
1057
+ result = null;
1058
+ continue;
1059
+ }
1060
+ result = ev(arg);
1061
+ }
1062
+ return result;
1063
+ }
1064
+
1065
+ // ── loop ──────────────────────────────────────────────────────────
1066
+ // Phase B-1: Two syntax variants supported:
1067
+ // 1. Classic: (loop [var1 val1 var2 val2...] body...) with (recur new-vals...)
1068
+ // 2. Modern: (loop [($var init) condition update] body...)
1069
+ if (op === "loop") {
1070
+ const bindingsNode = expr.args[0];
1071
+ const bodyNodes = expr.args.slice(1);
1072
+
1073
+ // Get array items
1074
+ const bindingItems: any[] =
1075
+ (bindingsNode as any).kind === "array"
1076
+ ? (bindingsNode as any).items || []
1077
+ : (bindingsNode as any).kind === "block" && (bindingsNode as any).type === "Array"
1078
+ ? (bindingsNode as any).fields?.get?.("items") || []
1079
+ : [];
1080
+
1081
+ // Detect modern syntax: [($var init) condition update]
1082
+ const isModernSyntax = bindingItems.length === 3 &&
1083
+ (bindingItems[0] as any).kind === "sexpr";
1084
+
1085
+ if (isModernSyntax) {
1086
+ // Modern syntax: (loop [($var init) condition update] body)
1087
+ const initExpr = bindingItems[0];
1088
+ const condExpr = bindingItems[1];
1089
+ const updateExpr = bindingItems[2];
1090
+
1091
+ // Extract variable name from ($var init)
1092
+ const varName = (initExpr as any).op || "$i";
1093
+ const initVal = ev((initExpr as any).args[0]);
1094
+
1095
+ ctx.variables.push();
1096
+ ctx.variables.set(varName, initVal);
1097
+
1098
+ let result: any = null;
1099
+ try {
1100
+ while (true) {
1101
+ const condVal = ev(condExpr);
1102
+ const isTruthy = condVal !== null && condVal !== undefined && condVal !== false;
1103
+ if (!isTruthy) break;
1104
+
1105
+ for (const bodyNode of bodyNodes) {
1106
+ result = ev(bodyNode);
1107
+ }
1108
+ const newVal = ev(updateExpr);
1109
+ ctx.variables.set(varName, newVal);
1110
+ }
1111
+ return result;
1112
+ } finally {
1113
+ ctx.variables.pop();
1114
+ }
1115
+ }
1116
+
1117
+ // Classic syntax: (loop [var1 val1 var2 val2...] body...) with (recur...)
1118
+ const loopVars: string[] = [];
1119
+ const loopInits: any[] = [];
1120
+ for (let i = 0; i < bindingItems.length; i += 2) {
1121
+ const varNode = bindingItems[i];
1122
+ const valNode = bindingItems[i + 1];
1123
+ const varName = varNode.kind === "variable" ? varNode.name
1124
+ : varNode.kind === "literal" ? String(varNode.value)
1125
+ : String(varNode.name || varNode.value);
1126
+ loopVars.push(varName);
1127
+ loopInits.push(ev(valNode));
1128
+ }
1129
+
1130
+ ctx.variables.push();
1131
+ for (let i = 0; i < loopVars.length; i++) {
1132
+ ctx.variables.set(loopVars[i], loopInits[i]);
1133
+ }
1134
+
1135
+ let result: any = null;
1136
+ const maxIter = 100000;
1137
+ let iter = 0;
1138
+ try {
1139
+ while (iter++ < maxIter) {
1140
+ let recurred = false;
1141
+ for (const bodyNode of bodyNodes) {
1142
+ result = ev(bodyNode);
1143
+ if (result && typeof result === "object" && result.__FL_RECUR__) {
1144
+ const newVals = result.__args as any[];
1145
+ for (let i = 0; i < loopVars.length && i < newVals.length; i++) {
1146
+ ctx.variables.set(loopVars[i], newVals[i]);
1147
+ }
1148
+ recurred = true;
1149
+ break;
1150
+ }
1151
+ }
1152
+ if (!recurred) break;
1153
+ }
1154
+ } finally {
1155
+ ctx.variables.pop();
1156
+ }
1157
+ return result;
1158
+ }
1159
+
1160
+ // ── recur ─────────────────────────────────────────────────────────
1161
+ if (op === "recur") {
1162
+ const newVals = expr.args.map((a) => ev(a));
1163
+ return { __FL_RECUR__: true, __args: newVals };
1164
+ }
1165
+
1166
+ // ── while ─────────────────────────────────────────────────────────
1167
+ if (op === "while") {
1168
+ let result: any = null;
1169
+ while (ev(expr.args[0])) {
1170
+ for (let i = 1; i < expr.args.length; i++) result = ev(expr.args[i]);
1171
+ }
1172
+ return result;
1173
+ }
1174
+
1175
+ // ── when-not — (when-not cond body...) ───────────────────────────
1176
+ if (op === "when-not") {
1177
+ if (expr.args.length < 2) return null;
1178
+ const c = ev(expr.args[0]);
1179
+ if (c === null || c === undefined || c === false) {
1180
+ let result: any = null;
1181
+ for (let i = 1; i < expr.args.length; i++) result = ev(expr.args[i]);
1182
+ return result;
1183
+ }
1184
+ return null;
1185
+ }
1186
+
1187
+ // ── dotimes — (dotimes [i n] body...) iterate 0..n-1 ────────────
1188
+ if (op === "dotimes") {
1189
+ const bindingNode = expr.args[0] as any;
1190
+ const items: any[] = bindingNode?.kind === "array"
1191
+ ? bindingNode.items || []
1192
+ : bindingNode?.fields?.get?.("items") || [];
1193
+ if (items.length < 2) return null;
1194
+ const bindName = (items[0] as any)?.name || (items[0] as any)?.value || "";
1195
+ const n = Number(ev(items[1]));
1196
+ for (let i = 0; i < n; i++) {
1197
+ interp.context.variables.push();
1198
+ try {
1199
+ interp.context.variables.set(bindName, i);
1200
+ for (let j = 1; j < expr.args.length; j++) ev(expr.args[j]);
1201
+ } finally {
1202
+ interp.context.variables.pop();
1203
+ }
1204
+ }
1205
+ return null;
1206
+ }
1207
+
1208
+ // ── doseq — (doseq [x coll] body...) side-effect iteration ───────
1209
+ if (op === "doseq") {
1210
+ const bindingNode = expr.args[0] as any;
1211
+ const items: any[] = bindingNode?.kind === "array"
1212
+ ? bindingNode.items || []
1213
+ : bindingNode?.fields?.get?.("items") || [];
1214
+ if (items.length < 2) return null;
1215
+ const bindName = (items[0] as any)?.name || (items[0] as any)?.value || String((items[0] as any)?.value ?? "");
1216
+ const coll = ev(items[1]);
1217
+ if (!Array.isArray(coll)) return null;
1218
+ for (const item of coll) {
1219
+ interp.context.variables.push();
1220
+ try {
1221
+ interp.context.variables.set(bindName, item);
1222
+ for (let i = 1; i < expr.args.length; i++) ev(expr.args[i]);
1223
+ } finally {
1224
+ interp.context.variables.pop();
1225
+ }
1226
+ }
1227
+ return null;
1228
+ }
1229
+
1230
+ // ── case — (case expr val1 res1 val2 res2 ... default) ───────────
1231
+ if (op === "case") {
1232
+ if (expr.args.length === 0) return null;
1233
+ const testVal = ev(expr.args[0]);
1234
+ let i = 1;
1235
+ while (i < expr.args.length - 1) {
1236
+ const matchVal = ev(expr.args[i]);
1237
+ if (testVal === matchVal) return ev(expr.args[i + 1]);
1238
+ i += 2;
1239
+ }
1240
+ // 홀수개 남으면 기본값
1241
+ if (i === expr.args.length - 1) return ev(expr.args[i]);
1242
+ return null;
1243
+ }
1244
+
1245
+ // ── for — (for [x coll :when pred] body) → array ─────────────────
1246
+ if (op === "for") {
1247
+ const bindingNode = expr.args[0] as any;
1248
+ const items: any[] = bindingNode?.kind === "array"
1249
+ ? bindingNode.items || []
1250
+ : bindingNode?.fields?.get?.("items") || [];
1251
+ if (items.length < 2) return [];
1252
+ const bindName = (items[0] as any)?.name || (items[0] as any)?.value || "";
1253
+ const coll = ev(items[1]);
1254
+ if (!Array.isArray(coll)) return [];
1255
+
1256
+ // :when 필터 추출 (선택적)
1257
+ let whenFn: any = null;
1258
+ for (let wi = 2; wi < items.length - 1; wi++) {
1259
+ const kw = (items[wi] as any)?.value || (items[wi] as any)?.name || "";
1260
+ if (kw === ":when" || kw === "when") {
1261
+ whenFn = items[wi + 1];
1262
+ break;
1263
+ }
1264
+ }
1265
+
1266
+ const result: any[] = [];
1267
+ for (const item of coll) {
1268
+ interp.context.variables.push();
1269
+ try {
1270
+ interp.context.variables.set(bindName, item);
1271
+ if (whenFn) {
1272
+ const pass = ev(whenFn);
1273
+ if (!pass && pass !== 0) { continue; }
1274
+ }
1275
+ let val: any = null;
1276
+ for (let bi = 1; bi < expr.args.length; bi++) val = ev(expr.args[bi]);
1277
+ result.push(val);
1278
+ } finally {
1279
+ interp.context.variables.pop();
1280
+ }
1281
+ }
1282
+ return result;
1283
+ }
1284
+
1285
+ // ── and (short-circuit) ───────────────────────────────────────────
1286
+ if (op === "and") {
1287
+ let result: any = true;
1288
+ for (const arg of expr.args) {
1289
+ result = ev(arg);
1290
+ if (!result) return result;
1291
+ }
1292
+ return result;
1293
+ }
1294
+
1295
+ // ── or (short-circuit) ────────────────────────────────────────────
1296
+ // Lisp 표준: nil/false만 falsy. 0/""/[]/{} 는 truthy
1297
+ if (op === "or") {
1298
+ let last: any = null;
1299
+ for (const arg of expr.args) {
1300
+ last = ev(arg);
1301
+ if (last !== null && last !== undefined && last !== false) return last;
1302
+ }
1303
+ return last;
1304
+ }
1305
+
1306
+ // ── map (inline comprehension, 3-arg form) ────────────────────────
1307
+ if (op === "map" && expr.args.length === 3) {
1308
+ const arr = ev(expr.args[0]);
1309
+ const paramNode = expr.args[1];
1310
+ const bodyNode = expr.args[2];
1311
+ const items: any[] =
1312
+ (paramNode as any).kind === "block" && (paramNode as any).type === "Array"
1313
+ ? (paramNode as any).fields.get?.("items") || []
1314
+ : (paramNode as any).kind === "array"
1315
+ ? (paramNode as any).items || []
1316
+ : [];
1317
+ const paramNames = items.map((item: any) => {
1318
+ if (item.kind === "variable") return item.name;
1319
+ if (item.kind === "literal") return "$" + item.value;
1320
+ return "$" + (item.name || item.value || "_");
1321
+ });
1322
+ if (Array.isArray(arr) && paramNames.length > 0) {
1323
+ return arr.map((elem: any) => {
1324
+ ctx.variables.push();
1325
+ ctx.variables.set(paramNames[0], elem);
1326
+ try {
1327
+ return ev(bodyNode);
1328
+ } finally {
1329
+ ctx.variables.pop();
1330
+ }
1331
+ });
1332
+ }
1333
+ // Fall through: return undefined (caller will evaluate args and try builtins)
1334
+ return undefined;
1335
+ }
1336
+
1337
+ // ── 테스트 프레임워크 ─────────────────────────────────────────────
1338
+ // (deftest "name" body...) — 테스트 등록 + 즉시 실행
1339
+ // (describe "suite" body...) — 동일 (별칭)
1340
+ // (it "name" body...) — describe 내부용 (동일)
1341
+ if (op === "deftest" || op === "describe" || op === "it") {
1342
+ const ctx = interp.context as any;
1343
+ if (!ctx._testResults) ctx._testResults = { passed: 0, failed: 0, errors: [] as string[] };
1344
+ const name = expr.args.length > 0 ? String(ev(expr.args[0])) : "(anonymous)";
1345
+ const bodies = expr.args.slice(1);
1346
+ try {
1347
+ for (const b of bodies) ev(b);
1348
+ ctx._testResults.passed++;
1349
+ process.stdout.write(` ✓ ${name}\n`);
1350
+ } catch (e: any) {
1351
+ ctx._testResults.failed++;
1352
+ const msg = e?.message ?? String(e);
1353
+ ctx._testResults.errors.push(` ✗ ${name}: ${msg}`);
1354
+ process.stdout.write(` ✗ ${name}: ${msg}\n`);
1355
+ }
1356
+ return null;
1357
+ }
1358
+
1359
+ // (is expr) — truthy assertion
1360
+ // (is= expected got) — equality assertion
1361
+ if (op === "is") {
1362
+ const val = expr.args.length > 0 ? ev(expr.args[0]) : false;
1363
+ const msg = expr.args.length > 1 ? String(ev(expr.args[1])) : `Expected truthy, got: ${JSON.stringify(val)}`;
1364
+ if (!val) throw new Error(msg);
1365
+ return val;
1366
+ }
1367
+ if (op === "is=") {
1368
+ if (expr.args.length < 2) throwArgCount("is=", "2", expr.args.length, expr.line);
1369
+ const expected = ev(expr.args[0]);
1370
+ const actual = ev(expr.args[1]);
1371
+ const eq = JSON.stringify(expected) === JSON.stringify(actual);
1372
+ if (!eq) throw new Error(`Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
1373
+ return actual;
1374
+ }
1375
+
1376
+ // (run-tests) — 테스트 결과 출력 + 통계 반환
1377
+ if (op === "run-tests") {
1378
+ const ctx = interp.context as any;
1379
+ const r = ctx._testResults ?? { passed: 0, failed: 0, errors: [] };
1380
+ const total = r.passed + r.failed;
1381
+ process.stdout.write(`\nTest Results: ${r.passed}/${total} passed`);
1382
+ if (r.failed > 0) process.stdout.write(` (${r.failed} FAILED)`);
1383
+ process.stdout.write("\n");
1384
+ ctx._testResults = { passed: 0, failed: 0, errors: [] };
1385
+ return { passed: r.passed, failed: r.failed, total };
1386
+ }
1387
+ // (test-summary) — 결과를 Map으로 반환 (출력 없음)
1388
+ if (op === "test-summary") {
1389
+ const ctx = interp.context as any;
1390
+ const r = ctx._testResults ?? { passed: 0, failed: 0, errors: [] };
1391
+ return new Map([["passed", r.passed], ["failed", r.failed], ["total", r.passed + r.failed], ["errors", r.errors]]);
1392
+ }
1393
+
1394
+ // ── import (use 별칭) ─────────────────────────────────────────────
1395
+ // (import "file.fl") — use와 동일하게 파일 로드
1396
+ if (op === "import") {
1397
+ if (expr.args.length < 1) throwArgCount("import", "1", expr.args.length, expr.line);
1398
+ const filePath = String(ev(expr.args[0]));
1399
+ // use 핸들러를 재활용
1400
+ const useExpr = { ...expr, op: "use", args: expr.args };
1401
+ return interp.evalSpecialForm("use", useExpr);
1402
+ }
1403
+
1404
+ // ── migrate — 버전 관리 DB 마이그레이션 ──────────────────────────
1405
+ // (migrate db [["v1" "CREATE TABLE ..."] ["v2" "ALTER TABLE ..."]])
1406
+ // db: string(mariadb DB name) or number(pool-id) or nil(in-memory 테스트)
1407
+ if (op === "migrate") {
1408
+ if (expr.args.length < 2) throwArgCount("migrate", "2", expr.args.length, expr.line);
1409
+ const db = ev(expr.args[0]);
1410
+ const steps = ev(expr.args[1]);
1411
+ if (!Array.isArray(steps)) throw new Error("migrate: second arg must be [[version sql] ...] array");
1412
+
1413
+ const ctx = interp.context as any;
1414
+
1415
+ // in-memory 모드 (db = null/nil): 실제 SQL 없이 버전 추적만
1416
+ if (db === null || db === undefined) {
1417
+ if (!ctx._migrate_applied) ctx._migrate_applied = new Set<string>();
1418
+ const applied: Set<string> = ctx._migrate_applied;
1419
+ let count = 0;
1420
+ for (const step of steps) {
1421
+ const pair = Array.isArray(step) ? step : [step];
1422
+ const version = String(pair[0]);
1423
+ if (applied.has(version)) continue;
1424
+ applied.add(version);
1425
+ count++;
1426
+ process.stdout.write(` [migrate] applied: ${version}\n`);
1427
+ }
1428
+ if (count === 0) process.stdout.write(" [migrate] up to date\n");
1429
+ return { applied: count, total: steps.length };
1430
+ }
1431
+
1432
+ // mariadb-exec 함수 참조
1433
+ const execFn = interp.context.functions.get("mariadb_exec") ??
1434
+ interp.context.functions.get("mariadb-exec");
1435
+ const queryFn = interp.context.functions.get("mariadb_query") ??
1436
+ interp.context.functions.get("mariadb-query");
1437
+ if (!execFn || !queryFn) throw new Error("migrate: mariadb functions not loaded");
1438
+ const exec = (sql: string, params: any[] = []) => callFn(execFn.body ?? execFn, [db, sql, params]);
1439
+ const query = (sql: string, params: any[] = []) => callFn(queryFn.body ?? queryFn, [db, sql, params]);
1440
+
1441
+ // _migrations 테이블 생성
1442
+ exec(`CREATE TABLE IF NOT EXISTS _migrations (
1443
+ version VARCHAR(255) PRIMARY KEY,
1444
+ applied_at BIGINT NOT NULL
1445
+ )`);
1446
+
1447
+ // 적용된 버전 조회
1448
+ const rows = query("SELECT version FROM _migrations") as any[];
1449
+ const applied = new Set((rows ?? []).map((r: any) => String(r.version ?? r[0] ?? "")));
1450
+
1451
+ let count = 0;
1452
+ for (const step of steps) {
1453
+ const pair = Array.isArray(step) ? step : [step];
1454
+ const version = String(pair[0]);
1455
+ const sql = String(pair[1] ?? "");
1456
+ if (applied.has(version)) continue;
1457
+ exec(sql);
1458
+ exec("INSERT INTO _migrations (version, applied_at) VALUES (?, ?)", [version, Date.now()]);
1459
+ count++;
1460
+ process.stdout.write(` [migrate] applied: ${version}\n`);
1461
+ }
1462
+ if (count === 0) process.stdout.write(" [migrate] up to date\n");
1463
+ return { applied: count, total: steps.length };
1464
+ }
1465
+
1466
+ // ── memoize ──────────────────────────────────────────────────────
1467
+ // (memoize fn) → memoized version that caches by JSON(args)
1468
+ if (op === "memoize") {
1469
+ if (expr.args.length < 1) throwArgCount("memoize", "1", expr.args.length, expr.line);
1470
+ const fn = ev(expr.args[0]);
1471
+ const cache = new Map<string, any>();
1472
+ return (...args: any[]) => {
1473
+ const key = JSON.stringify(args);
1474
+ if (cache.has(key)) return cache.get(key);
1475
+ const result = callFn(fn, args);
1476
+ cache.set(key, result);
1477
+ return result;
1478
+ };
1479
+ }
1480
+
1481
+ // ── partial ───────────────────────────────────────────────────────
1482
+ // (partial f arg1 arg2 ...) → fn that prepends partialArgs to call
1483
+ if (op === "partial") {
1484
+ if (expr.args.length < 1) throwArgCount("partial", ">=1", expr.args.length, expr.line);
1485
+ const fn = ev(expr.args[0]);
1486
+ const partialArgs = expr.args.slice(1).map(ev);
1487
+ return (...rest: any[]) => {
1488
+ const allArgs = [...partialArgs, ...rest];
1489
+ if (typeof fn === "function") return fn(...allArgs);
1490
+ return callFn(fn, allArgs);
1491
+ };
1492
+ }
1493
+
1494
+ // ── group-by ─────────────────────────────────────────────────────
1495
+ // (group-by key-fn coll) → {:key [items...]} map
1496
+ // key-fn: keyword string (:status) or FL function
1497
+ if (op === "group-by" || op === "group_by") {
1498
+ if (expr.args.length < 2) throwArgCount("group-by", "2", expr.args.length, expr.line);
1499
+ const keyFn = ev(expr.args[0]);
1500
+ const coll = ev(expr.args[1]);
1501
+ if (!Array.isArray(coll)) return new Map();
1502
+ const getKey = (item: any): any => {
1503
+ if (typeof keyFn === "string") {
1504
+ const k = keyFn.startsWith(":") ? keyFn.slice(1) : keyFn;
1505
+ if (item instanceof Map) return item.get(keyFn) ?? item.get(k) ?? null;
1506
+ return item?.[k] ?? item?.[keyFn] ?? null;
1507
+ }
1508
+ if (typeof keyFn === "function") return keyFn(item);
1509
+ return callFn(keyFn, [item]);
1510
+ };
1511
+ const result = new Map<any, any[]>();
1512
+ for (const item of coll) {
1513
+ const key = getKey(item);
1514
+ if (!result.has(key)) result.set(key, []);
1515
+ result.get(key)!.push(item);
1516
+ }
1517
+ return result;
1518
+ }
1519
+
1520
+ // ── return ───────────────────────────────────────────────────────
1521
+ // (return expr) — fn 본체 내 early exit. try/catch를 통과해 함수 경계에서 캐치됨
1522
+ if (op === "return") {
1523
+ const val = expr.args.length > 0 ? ev(expr.args[0]) : null;
1524
+ throw new ReturnSignal(val);
1525
+ }
1526
+
1527
+ // ── map-vals / map-keys ───────────────────────────────────────────
1528
+ // (map-vals m) → values array (alias for values)
1529
+ // (map-keys m) → keys array (alias for keys)
1530
+ // (map-vals f m) → new map with f applied to each value
1531
+ // (map-keys f m) → new map with f applied to each key
1532
+ if (op === "map-vals" || op === "map_vals" || op === "map-keys" || op === "map_keys") {
1533
+ const isKey = op === "map-keys" || op === "map_keys";
1534
+
1535
+ // 1-arg: (map-keys m) / (map-vals m) → keys or values array
1536
+ if (expr.args.length === 1) {
1537
+ const m = ev(expr.args[0]);
1538
+ if (m instanceof Map) return isKey ? [...(m as Map<any,any>).keys()] : [...(m as Map<any,any>).values()];
1539
+ if (m && typeof m === "object" && !Array.isArray(m)) return isKey ? Object.keys(m) : Object.values(m);
1540
+ return [];
1541
+ }
1542
+
1543
+ // 2-arg: (map-keys f m) / (map-vals f m) → transformed map
1544
+ if (expr.args.length === 2) {
1545
+ const fn = ev(expr.args[0]);
1546
+ const m = ev(expr.args[1]);
1547
+ const applyFn = (fn: any, arg: any): any => callFn(fn, [arg]);
1548
+ if (m instanceof Map) {
1549
+ const out = new Map();
1550
+ for (const [k, v] of (m as Map<any,any>).entries())
1551
+ out.set(isKey ? applyFn(fn, k) : k, isKey ? v : applyFn(fn, v));
1552
+ return out;
1553
+ }
1554
+ if (m && typeof m === "object" && !Array.isArray(m)) {
1555
+ const out: Record<string, any> = {};
1556
+ for (const [k, v] of Object.entries(m))
1557
+ out[isKey ? String(applyFn(fn, k)) : k] = isKey ? v : applyFn(fn, v);
1558
+ return out;
1559
+ }
1560
+ return m;
1561
+ }
1562
+ }
1563
+
1564
+ // ── defstruct ─────────────────────────────────────────────────────
1565
+ // (defstruct Point [:x :float :y :float])
1566
+ // 자동 생성:
1567
+ // (Point 1.0 2.0) → {:x 1.0 :y 2.0 :__type "Point"}
1568
+ // (Point? v) → true/false
1569
+ // (Point.x v) → v.x
1570
+ if (op === "defstruct") {
1571
+ if (expr.args.length < 2) {
1572
+ throw new Error(`defstruct requires a name and a field vector`);
1573
+ }
1574
+
1575
+ // 1. 이름 추출
1576
+ const nameNode = expr.args[0] as any;
1577
+ const structName: string =
1578
+ nameNode.kind === "literal" ? String(nameNode.value)
1579
+ : nameNode.kind === "variable" ? nameNode.name
1580
+ : String(nameNode.value ?? nameNode.name ?? "");
1581
+
1582
+ if (!structName) throw new Error(`defstruct: struct name is required`);
1583
+
1584
+ // 2. 필드 벡터 파싱 [:x :float :y :float]
1585
+ const fieldsNode = expr.args[1] as any;
1586
+ const fields: Array<{ name: string; type: string }> = [];
1587
+
1588
+ if (fieldsNode.kind === "block" && fieldsNode.type === "Array") {
1589
+ const items = fieldsNode.fields.get("items");
1590
+ if (Array.isArray(items)) {
1591
+ // Phase E 후속: 두 형태 모두 지원
1592
+ // 1) 명시적 타입: [:x :int :y :int] — 짝수 개수, item[i]=name, item[i+1]=type
1593
+ // 2) 단순 형태: [x y z] 또는 [:x :y :z] — type 모두 "any"
1594
+ // 자동 감지: 모든 item이 keyword/variable이고 한 칸 건너 type일 가능성 없으면 단순 형태
1595
+ const isSimpleForm = (() => {
1596
+ // 짝수가 아니거나, item 사이에 type-like가 없으면 단순 형태
1597
+ if (items.length % 2 !== 0) return true;
1598
+ // type-keyword pattern check: item[i+1]이 :int :float :string :any 같은 type symbol이면 명시 형태
1599
+ const TYPE_KW = new Set(["int","float","number","string","bool","boolean","any","list","array","map","fn","function"]);
1600
+ for (let i = 1; i < items.length; i += 2) {
1601
+ const it = items[i] as any;
1602
+ const v = it?.kind === "keyword" ? it.name : it?.kind === "variable" ? it.name : it?.value;
1603
+ if (TYPE_KW.has(String(v))) return false; // 명시 형태 확정
1604
+ }
1605
+ return true; // type-keyword 없으면 단순 형태
1606
+ })();
1607
+
1608
+ if (isSimpleForm) {
1609
+ // 단순: 모든 item이 field name (type=any)
1610
+ for (const item of items) {
1611
+ const it = item as any;
1612
+ const fieldName =
1613
+ it.kind === "keyword" ? it.name
1614
+ : it.kind === "variable" ? it.name
1615
+ : it.kind === "literal" ? String(it.value)
1616
+ : "";
1617
+ if (fieldName) fields.push({ name: fieldName, type: "any" });
1618
+ }
1619
+ } else {
1620
+ // 명시: name + type 페어
1621
+ for (let i = 0; i < items.length; i += 2) {
1622
+ const nameItem = items[i] as any;
1623
+ const typeItem = items[i + 1] as any;
1624
+ const fieldName =
1625
+ nameItem.kind === "keyword" ? nameItem.name
1626
+ : nameItem.kind === "variable" ? nameItem.name
1627
+ : nameItem.kind === "literal" ? String(nameItem.value)
1628
+ : "";
1629
+ const fieldType =
1630
+ typeItem === undefined ? "any"
1631
+ : typeItem.kind === "keyword" ? typeItem.name
1632
+ : typeItem.kind === "variable" ? typeItem.name
1633
+ : typeItem.kind === "literal" ? String(typeItem.value)
1634
+ : "any";
1635
+ if (fieldName) fields.push({ name: fieldName, type: fieldType });
1636
+ }
1637
+ }
1638
+ }
1639
+ }
1640
+
1641
+ // 3. StructRegistry에 등록
1642
+ const registry: StructRegistry = ctx.structs;
1643
+ registry.define({ name: structName, fields });
1644
+
1645
+ // 4. constructor 등록 — (Point 1.0 2.0)
1646
+ const ctor = registry.makeConstructor(structName);
1647
+ ctx.functions.set(structName, {
1648
+ name: structName,
1649
+ params: fields.map((f) => f.name),
1650
+ body: { kind: "literal", type: "null", value: null } as any,
1651
+ capturedEnv: new Map([["__struct_ctor__", ctor]]),
1652
+ });
1653
+ // native 함수로도 등록 (eval-builtins fallback이 아닌 직접 호출)
1654
+ (ctx as any)[`__native_${structName}`] = ctor;
1655
+
1656
+ // 5. predicate 등록 — (Point? v)
1657
+ const pred = registry.makePredicate(structName);
1658
+ (ctx as any)[`__native_${structName}?`] = pred;
1659
+
1660
+ // 6. field accessor 등록 — (Point.x v), (Point.y v) ...
1661
+ for (const field of fields) {
1662
+ const accessorName = `${structName}.${field.name}`;
1663
+ const acc = registry.makeAccessor(structName, field.name);
1664
+ (ctx as any)[`__native_${accessorName}`] = acc;
1665
+ }
1666
+
1667
+ return null;
1668
+ }
1669
+
1670
+ // ── defmacro ──────────────────────────────────────────────────────
1671
+ // (defmacro name [$cond $body] (if $cond $body nil))
1672
+ if (op === "defmacro") {
1673
+ if (expr.args.length < 3) throw new Error(`defmacro requires name, params, and body`);
1674
+ const nameNode = expr.args[0] as any;
1675
+ const macroName: string = nameNode.kind === "literal" ? String(nameNode.value)
1676
+ : nameNode.kind === "variable" ? nameNode.name
1677
+ : String(nameNode.value ?? nameNode.name ?? "");
1678
+
1679
+ const paramsNode = expr.args[1] as any;
1680
+ const params: string[] = [];
1681
+ if (paramsNode.kind === "block" && paramsNode.type === "Array") {
1682
+ const items = paramsNode.fields.get("items");
1683
+ if (Array.isArray(items)) {
1684
+ for (const item of items as any[]) {
1685
+ if (item.kind === "variable") params.push(item.name.startsWith("$") ? item.name : "$" + item.name);
1686
+ else if (item.kind === "literal") params.push("$" + item.value);
1687
+ }
1688
+ }
1689
+ }
1690
+ const body = expr.args[2];
1691
+ ctx.macroExpander.define(macroName, params, body);
1692
+ return null;
1693
+ }
1694
+
1695
+ // ── macroexpand ───────────────────────────────────────────────────
1696
+ // (macroexpand '(when true (println "yes"))) → 확장된 AST 출력 (디버깅용)
1697
+ if (op === "macroexpand") {
1698
+ if (expr.args.length < 1) throw new Error(`macroexpand requires 1 argument`);
1699
+ const form = expr.args[0];
1700
+ const expanded = ctx.macroExpander.expand(form);
1701
+ return ctx.macroExpander.astToString(expanded);
1702
+ }
1703
+
1704
+ // ── defprotocol ───────────────────────────────────────────────────
1705
+ // (defprotocol Serializable
1706
+ // [serialize [$self] :string]
1707
+ // [deserialize [$data] :any])
1708
+ if (op === "defprotocol") {
1709
+ if (expr.args.length < 1) throw new Error(`defprotocol requires a name`);
1710
+ const nameNode = expr.args[0] as any;
1711
+ const protoName: string =
1712
+ nameNode.kind === "variable" ? nameNode.name
1713
+ : nameNode.kind === "literal" ? String(nameNode.value)
1714
+ : String(nameNode.name ?? nameNode.value ?? "");
1715
+
1716
+ const methods: Array<{ name: string; params: string[]; returnType?: string }> = [];
1717
+
1718
+ for (let i = 1; i < expr.args.length; i++) {
1719
+ const sigNode = expr.args[i] as any;
1720
+ if (sigNode.kind !== "block" || sigNode.type !== "Array") continue;
1721
+ const items = sigNode.fields.get("items");
1722
+ if (!Array.isArray(items) || items.length < 1) continue;
1723
+
1724
+ const methodNameNode = items[0] as any;
1725
+ const methodName: string =
1726
+ methodNameNode.kind === "variable" ? methodNameNode.name
1727
+ : methodNameNode.kind === "literal" ? String(methodNameNode.value)
1728
+ : String(methodNameNode.name ?? methodNameNode.value ?? "");
1729
+
1730
+ const params: string[] = [];
1731
+ if (items.length > 1) {
1732
+ const paramsNode = items[1] as any;
1733
+ if (paramsNode.kind === "block" && paramsNode.type === "Array") {
1734
+ const pItems = paramsNode.fields.get("items");
1735
+ if (Array.isArray(pItems)) {
1736
+ for (const p of pItems as any[]) {
1737
+ if (p.kind === "variable") params.push(p.name);
1738
+ else if (p.kind === "literal") params.push("$" + p.value);
1739
+ }
1740
+ }
1741
+ }
1742
+ }
1743
+
1744
+ let returnType: string | undefined;
1745
+ if (items.length > 2) {
1746
+ const rtNode = items[2] as any;
1747
+ if (rtNode.kind === "keyword") returnType = rtNode.name;
1748
+ else if (rtNode.kind === "literal") returnType = String(rtNode.value);
1749
+ }
1750
+
1751
+ methods.push({ name: methodName, params, returnType });
1752
+ }
1753
+
1754
+ ctx.protocols.defineProtocol({ name: protoName, methods });
1755
+ return null;
1756
+ }
1757
+
1758
+ // ── impl ──────────────────────────────────────────────────────────
1759
+ // (impl Serializable Point
1760
+ // [serialize [$self] (str "(" $self.x "," $self.y ")")]
1761
+ // [deserialize [$data] {:x 0.0 :y 0.0}])
1762
+ if (op === "impl") {
1763
+ if (expr.args.length < 3) throw new Error(`impl requires protocol name, type name, and at least one method`);
1764
+
1765
+ const protoNameNode = expr.args[0] as any;
1766
+ const protoName: string =
1767
+ protoNameNode.kind === "variable" ? protoNameNode.name
1768
+ : protoNameNode.kind === "literal" ? String(protoNameNode.value)
1769
+ : String(protoNameNode.name ?? protoNameNode.value ?? "");
1770
+
1771
+ const typeNameNode = expr.args[1] as any;
1772
+ const typeName: string =
1773
+ typeNameNode.kind === "variable" ? typeNameNode.name
1774
+ : typeNameNode.kind === "literal" ? String(typeNameNode.value)
1775
+ : String(typeNameNode.name ?? typeNameNode.value ?? "");
1776
+
1777
+ const implMethods = new Map<string, { params: string[]; body: any }>();
1778
+
1779
+ for (let i = 2; i < expr.args.length; i++) {
1780
+ const implNode = expr.args[i] as any;
1781
+ if (implNode.kind !== "block" || implNode.type !== "Array") continue;
1782
+ const items = implNode.fields.get("items");
1783
+ if (!Array.isArray(items) || items.length < 3) continue;
1784
+
1785
+ const methodNameNode = items[0] as any;
1786
+ const methodName: string =
1787
+ methodNameNode.kind === "variable" ? methodNameNode.name
1788
+ : methodNameNode.kind === "literal" ? String(methodNameNode.value)
1789
+ : String(methodNameNode.name ?? methodNameNode.value ?? "");
1790
+
1791
+ const params: string[] = [];
1792
+ const paramsNode = items[1] as any;
1793
+ if (paramsNode.kind === "block" && paramsNode.type === "Array") {
1794
+ const pItems = paramsNode.fields.get("items");
1795
+ if (Array.isArray(pItems)) {
1796
+ for (const p of pItems as any[]) {
1797
+ if (p.kind === "variable") params.push(p.name);
1798
+ else if (p.kind === "literal") params.push("$" + p.value);
1799
+ }
1800
+ }
1801
+ }
1802
+
1803
+ const body = items[2];
1804
+ implMethods.set(methodName, { params, body });
1805
+ }
1806
+
1807
+ ctx.protocols.defineImpl({ protocolName: protoName, typeName, methods: implMethods });
1808
+ return null;
1809
+ }
1810
+
1811
+ // ── parallel ──────────────────────────────────────────────────────
1812
+ // (parallel expr1 expr2 ...) → [result1, result2, ...]
1813
+ // 동기 버전: 순차 실행 후 배열 반환 (FreeLangPromise는 resolve 후 반환)
1814
+ if (op === "parallel") {
1815
+ if (expr.args.length === 0) return [];
1816
+ const results: any[] = [];
1817
+ for (const arg of expr.args) {
1818
+ let val = ev(arg);
1819
+ // FreeLangPromise면 resolved 값 추출 시도
1820
+ if (val && typeof val === "object" && typeof val.getValue === "function") {
1821
+ try { val = val.getValue(); } catch { val = null; }
1822
+ }
1823
+ results.push(val);
1824
+ }
1825
+ return results;
1826
+ }
1827
+
1828
+ // ── race ──────────────────────────────────────────────────────────
1829
+ // (race expr1 expr2 ...) → 첫 번째로 완료된 결과 (동기 버전: 첫 번째 non-null 반환)
1830
+ if (op === "race") {
1831
+ if (expr.args.length === 0) return null;
1832
+ let firstResult: any = undefined;
1833
+ for (const arg of expr.args) {
1834
+ let val = ev(arg);
1835
+ if (val && typeof val === "object" && typeof val.getValue === "function") {
1836
+ try { val = val.getValue(); } catch { val = null; }
1837
+ }
1838
+ if (firstResult === undefined) firstResult = val;
1839
+ if (val !== null && val !== undefined) return val;
1840
+ }
1841
+ return firstResult ?? null;
1842
+ }
1843
+
1844
+ // ── with-timeout ──────────────────────────────────────────────────
1845
+ // (with-timeout ms expr) → result or null
1846
+ // 동기 버전: ms는 무시하고 즉시 실행 (비동기 환경 없으므로)
1847
+ if (op === "with-timeout") {
1848
+ if (expr.args.length < 2) return null;
1849
+ // expr.args[0] = ms (무시), expr.args[1] = expression
1850
+ try {
1851
+ let val = ev(expr.args[1]);
1852
+ if (val && typeof val === "object" && typeof val.getValue === "function") {
1853
+ try { val = val.getValue(); } catch { val = null; }
1854
+ }
1855
+ return val;
1856
+ } catch {
1857
+ return null;
1858
+ }
1859
+ }
1860
+
1861
+ // ── Phase 96: fl-try ─────────────────────────────────────────────────
1862
+ // (fl-try expr)
1863
+ // (fl-try expr :on-err fn)
1864
+ // (fl-try expr :on-type-error fn :on-not-found fn :on-io fn :default fn)
1865
+ if (op === "fl-try") {
1866
+ if (expr.args.length < 1) throw new Error(`fl-try requires at least 1 argument`);
1867
+ const bodyNode = expr.args[0];
1868
+
1869
+ // 나머지 인자에서 키워드-핸들러 쌍 추출
1870
+ // 파서: :on-err → {kind:"literal", type:"string", value:"on-err"} (콜론 제거)
1871
+ // 또는 {kind:"keyword", name:"on-err"} 또는 {kind:"keyword", value:"on-err"}
1872
+ const FL_TRY_KEYS = new Set([
1873
+ "on-err", "on-type-error", "on-not-found", "on-io", "on-arity",
1874
+ "on-ai", "on-timeout", "on-runtime", "default",
1875
+ ]);
1876
+ const handlers = new Map<string, any>();
1877
+ let i = 1;
1878
+ while (i < expr.args.length) {
1879
+ const keyNode = expr.args[i] as any;
1880
+ let key: string | null = null;
1881
+ if (keyNode.kind === "keyword") {
1882
+ const v = String(keyNode.name ?? keyNode.value ?? "");
1883
+ if (FL_TRY_KEYS.has(v)) key = v;
1884
+ } else if (keyNode.kind === "literal" && keyNode.type === "string") {
1885
+ // :on-err → "on-err" (파서가 콜론 제거), 또는 ":on-err" (콜론 포함)
1886
+ const v = keyNode.value.startsWith(":") ? keyNode.value.slice(1) : keyNode.value;
1887
+ if (FL_TRY_KEYS.has(v)) key = v;
1888
+ }
1889
+ if (key !== null && i + 1 < expr.args.length) {
1890
+ handlers.set(key, ev(expr.args[i + 1]));
1891
+ i += 2;
1892
+ } else {
1893
+ i++;
1894
+ }
1895
+ }
1896
+
1897
+ // 본문 실행 — Result로 래핑
1898
+ let result: any;
1899
+ try {
1900
+ const val = ev(bodyNode);
1901
+ // 이미 Result 타입이면 그대로, 아니면 ok로 래핑
1902
+ if (val && typeof val === "object" && (val._tag === "Ok" || val._tag === "Err")) {
1903
+ result = val;
1904
+ } else {
1905
+ result = ok(val);
1906
+ }
1907
+ } catch (e: unknown) {
1908
+ const flErr = fromThrown(e);
1909
+ result = flErr;
1910
+ }
1911
+
1912
+ // 핸들러 처리
1913
+ if (isErr(result)) {
1914
+ const e = result;
1915
+ // 카테고리별 핸들러
1916
+ const categoryHandlerMap: Record<string, ErrorCategory> = {
1917
+ "on-type-error": ErrorCategory.TYPE_ERROR,
1918
+ "on-not-found": ErrorCategory.NOT_FOUND,
1919
+ "on-io": ErrorCategory.IO,
1920
+ "on-arity": ErrorCategory.ARITY,
1921
+ "on-ai": ErrorCategory.AI,
1922
+ "on-timeout": ErrorCategory.TIMEOUT,
1923
+ };
1924
+
1925
+ // 카테고리 매칭 핸들러 우선
1926
+ let handled = false;
1927
+ for (const [handlerKey, category] of Object.entries(categoryHandlerMap)) {
1928
+ if (handlers.has(handlerKey) && e.category === category) {
1929
+ const fn = handlers.get(handlerKey);
1930
+ const handlerResult = callFnVal(fn, [e]);
1931
+ return handlerResult;
1932
+ }
1933
+ }
1934
+
1935
+ // :on-err — 모든 에러
1936
+ if (!handled && handlers.has("on-err")) {
1937
+ const fn = handlers.get("on-err");
1938
+ return callFnVal(fn, [e]);
1939
+ }
1940
+
1941
+ // :default — 나머지
1942
+ if (!handled && handlers.has("default")) {
1943
+ const fn = handlers.get("default");
1944
+ return callFnVal(fn, [e]);
1945
+ }
1946
+
1947
+ // 핸들러 없으면 err 값 그대로 반환
1948
+ return result;
1949
+ }
1950
+
1951
+ return result;
1952
+ }
1953
+
1954
+ throw new Error(`evalSpecialForm: unknown op "${op}"`);
1955
+ }
1956
+
1957
+ // ── Helper: evalLet (v11.1: 1차원/2차원 대괄호 + bare symbol 모두 지원) ───
1958
+ function evalLet(interp: Interpreter, args: ASTNode[]): any {
1959
+ if (args.length < 2) throw new Error(`let requires at least 2 arguments`);
1960
+ const bindings = args[0];
1961
+ const ctx = interp.context;
1962
+ const ev = (node: any) => (interp as any).eval(node);
1963
+
1964
+ const toVarName = (node: any): string => {
1965
+ if (node?.kind === "variable") {
1966
+ const n = node.name as string;
1967
+ return n.startsWith("$") ? n : "$" + n;
1968
+ }
1969
+ if (node?.kind === "literal" && node.type === "symbol") {
1970
+ const v = node.value as string;
1971
+ return v.startsWith("$") ? v : "$" + v;
1972
+ }
1973
+ throw new Error(`Invalid binding variable: expected symbol or variable, got ${node?.kind}`);
1974
+ };
1975
+
1976
+ ctx.variables.push();
1977
+
1978
+ if ((bindings as any).kind === "block" && (bindings as any).type === "Array") {
1979
+ const items = (bindings as any).fields.get("items");
1980
+ if (Array.isArray(items) && items.length > 0) {
1981
+ // 감지: 첫 원소가 Array block 이면 2차원 ([[$x expr] [$y expr]])
1982
+ // 그렇지 않으면 1차원 ([$x expr $y expr] or [x expr y expr])
1983
+ const isNested = items[0]?.kind === "block" && items[0]?.type === "Array";
1984
+
1985
+ // v11.10: 혼합 감지 개선
1986
+ // 2차원: 모든 짝수 위치 (0,2,4...) 원소가 Array block
1987
+ // 1차원: 변수-값 쌍이 평탄하게 배열됨 (첫 원소가 Array block이 아니면 1차원)
1988
+ if (isNested) {
1989
+ // 2차원이면 모든 짝수 위치가 Array block이어야 함
1990
+ for (let i = 0; i < items.length; i += 2) {
1991
+ if (!(items[i]?.kind === "block" && items[i]?.type === "Array")) {
1992
+ ctx.variables.pop();
1993
+ throw new Error(`let: 2차원 바인딩에서 원소 ${i}가 배열이 아님`);
1994
+ }
1995
+ }
1996
+ } else {
1997
+ // 1차원이면 짝수 개여야 함 (변수-값 쌍)
1998
+ // 이미 위에서 확인함
1999
+ }
2000
+
2001
+ if (isNested) {
2002
+ // 기존 2차원 경로 (v11 호환)
2003
+ for (const item of items) {
2004
+ if ((item as any).kind === "block" && (item as any).type === "Array") {
2005
+ const bindingItems = (item as any).fields.get("items");
2006
+ if (Array.isArray(bindingItems) && bindingItems.length >= 2) {
2007
+ const varName = toVarName(bindingItems[0]);
2008
+ const value = ev(bindingItems[1]);
2009
+ // Phase Y-1: 메타정보 저장
2010
+ const meta: Partial<ScopeVarMeta> = {
2011
+ line: (bindingItems[0] as any).line,
2012
+ col: (bindingItems[0] as any).col,
2013
+ type: inferType(value),
2014
+ };
2015
+ ctx.variables.set(varName, value, meta);
2016
+ }
2017
+ }
2018
+ }
2019
+ } else {
2020
+ // v11.1 신규: 1차원 평탄 문법
2021
+ if (items.length % 2 !== 0) {
2022
+ ctx.variables.pop();
2023
+ throw new Error(`let: expected even number of binding items, got ${items.length}`);
2024
+ }
2025
+ for (let i = 0; i < items.length; i += 2) {
2026
+ const pattern = items[i];
2027
+
2028
+ // Map 구조분해: {:keys [name age]} sourceMap
2029
+ if ((pattern as any)?.kind === "block" && (pattern as any)?.type === "Map") {
2030
+ const mapFields = (pattern as any).fields as Map<string, any>;
2031
+ const keysField = mapFields?.get("keys");
2032
+ if (keysField?.kind === "block" && keysField?.type === "Array") {
2033
+ const sourceMap = ev(items[i + 1]);
2034
+ const keyItems: any[] = keysField.fields.get("items") ?? [];
2035
+ for (const keyNode of keyItems) {
2036
+ const rawName: string | null =
2037
+ keyNode?.kind === "literal" && keyNode?.type === "symbol" ? keyNode.value as string
2038
+ : keyNode?.kind === "variable" ? (keyNode.name as string).replace(/^\$/, "")
2039
+ : null;
2040
+ if (rawName !== null) {
2041
+ const varName = rawName.startsWith("$") ? rawName : "$" + rawName;
2042
+ const value = (sourceMap !== null && typeof sourceMap === "object")
2043
+ ? (sourceMap[rawName] ?? null)
2044
+ : null;
2045
+ ctx.variables.set(varName, value, {
2046
+ line: (keyNode as any).line,
2047
+ col: (keyNode as any).col,
2048
+ type: inferType(value),
2049
+ } as Partial<ScopeVarMeta>);
2050
+ }
2051
+ }
2052
+ }
2053
+ continue;
2054
+ }
2055
+
2056
+ const varName = toVarName(pattern);
2057
+ const value = ev(items[i + 1]);
2058
+ // Phase Y-1: 메타정보 저장
2059
+ const meta: Partial<ScopeVarMeta> = {
2060
+ line: (items[i] as any).line,
2061
+ col: (items[i] as any).col,
2062
+ type: inferType(value),
2063
+ };
2064
+ ctx.variables.set(varName, value, meta);
2065
+ }
2066
+ }
2067
+ }
2068
+ }
2069
+
2070
+ let result: any = null;
2071
+ try {
2072
+ for (let bodyIdx = 1; bodyIdx < args.length; bodyIdx++) {
2073
+ result = ev(args[bodyIdx]);
2074
+ }
2075
+ } finally {
2076
+ ctx.variables.pop();
2077
+ }
2078
+ return result;
2079
+ }
2080
+
2081
+ // ── Helper: evalCond ──────────────────────────────────────────────
2082
+ function evalCond(interp: Interpreter, args: ASTNode[]): any {
2083
+ const ev = (node: any) => (interp as any).eval(node);
2084
+
2085
+ // P1-1 (2026-04-25): flat-pair 자동 감지
2086
+ // (cond test1 result1 test2 result2 default) ← Common Lisp 스타일
2087
+ // 분류 규칙: 첫 인자가 block(Array) 또는 sexpr op="do"이면 기존 bracketed
2088
+ // 그 외는 flat-pair (test/result 2개씩)
2089
+ const firstArg = args[0] as any;
2090
+ const isBracketed =
2091
+ (firstArg?.kind === "block" && firstArg?.type === "Array") ||
2092
+ (firstArg?.kind === "sexpr" && firstArg?.op === "do");
2093
+ if (args.length >= 2 && !isBracketed) {
2094
+ // flat-pair 모드: 2개씩 (test, result), 마지막 홀수면 default
2095
+ let i = 0;
2096
+ while (i < args.length - 1) {
2097
+ const testArg = args[i] as any;
2098
+ const isElse = testArg?.kind === "variable" &&
2099
+ (testArg?.name === "else" || testArg?.name === ":else" || testArg?.name === "$else");
2100
+ const test = isElse ? true : ev(testArg);
2101
+ if (test !== null && test !== undefined && test !== false) {
2102
+ return ev(args[i + 1]);
2103
+ }
2104
+ i += 2;
2105
+ }
2106
+ // 홀수개 남았으면 마지막을 default로
2107
+ if (i < args.length) return ev(args[i]);
2108
+ return null;
2109
+ }
2110
+
2111
+ // 기존 로직: bracketed pair [test result] 형식
2112
+ for (const arg of args) {
2113
+ let testNode: any = null;
2114
+ let bodyNodes: any[] = [];
2115
+
2116
+ // [test result...] Array block 형식
2117
+ if ((arg as any).kind === "block" && (arg as any).type === "Array") {
2118
+ const items = (arg as any).fields.get("items");
2119
+ if (Array.isArray(items) && items.length >= 2) {
2120
+ const firstItem = items[0] as any;
2121
+ const isElse = firstItem?.kind === "variable" &&
2122
+ (firstItem?.name === "else" || firstItem?.name === ":else" || firstItem?.name === "$else");
2123
+ testNode = isElse ? { kind: "literal", type: "boolean", value: true } : firstItem;
2124
+ bodyNodes = items.slice(1);
2125
+ }
2126
+ }
2127
+ // ((test-expr) body...) → parser creates SExpr{op:"do", args:[test, body...]}
2128
+ else if ((arg as any).kind === "sexpr" && (arg as any).op === "do" && (arg as any).args.length >= 2) {
2129
+ testNode = (arg as any).args[0];
2130
+ bodyNodes = (arg as any).args.slice(1);
2131
+ }
2132
+ // (test body) → SExpr where op is test symbol and args is rest
2133
+ // e.g. (true result) → SExpr{op:"true", args:[result]}
2134
+ else if ((arg as any).kind === "sexpr" && (arg as any).args.length >= 1) {
2135
+ const s = arg as any;
2136
+ testNode = { kind: "literal", type: "boolean", value: s.op === "true" ? true : s.op === "false" ? false : s.op === "else" ? true : undefined };
2137
+ if (testNode.value === undefined) {
2138
+ // op is a symbol test — reconstruct as variable lookup or literal
2139
+ testNode = { kind: "variable", name: s.op.startsWith("$") ? s.op : "$" + s.op };
2140
+ }
2141
+ bodyNodes = s.args;
2142
+ }
2143
+
2144
+ if (testNode && bodyNodes.length >= 1) {
2145
+ const test = ev(testNode);
2146
+ if (test) {
2147
+ let result: any = null;
2148
+ for (const b of bodyNodes) result = ev(b);
2149
+ return result;
2150
+ }
2151
+ }
2152
+ }
2153
+ return null;
2154
+ }