@greenpandastudios/aug-cli 0.20.1 → 0.21.0

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 (295) hide show
  1. package/README.md +1 -1
  2. package/docs/assets/benchmarks/execution.svg +774 -637
  3. package/docs/assets/benchmarks/http.svg +278 -249
  4. package/docs/assets/benchmarks/improvements.svg +66 -66
  5. package/docs/assets/benchmarks/kernels-mobile.svg +1 -0
  6. package/docs/assets/benchmarks/kernels.svg +1 -0
  7. package/docs/assets/benchmarks/memory.svg +153 -153
  8. package/docs/benchmark-results.json +227089 -90363
  9. package/docs/compatibility.md +6 -6
  10. package/docs/contributing-benchmarks.md +36 -6
  11. package/docs/dev-containers.md +8 -15
  12. package/docs/dgx-consumers.json +122 -0
  13. package/docs/dgx-gyms.json +784 -0
  14. package/docs/dgx-kernels.json +1170 -0
  15. package/docs/dgx-performance.json +227849 -0
  16. package/docs/dgx-spark.md +64 -0
  17. package/docs/diagnostics.md +1 -1
  18. package/docs/docker.md +16 -17
  19. package/docs/example-projects.json +32 -0
  20. package/docs/examples/approved-design/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  21. package/docs/examples/approved-design/domain/app.md +4 -4
  22. package/docs/examples/approved-design/main.md +2 -2
  23. package/docs/examples/calls-benchmark/index.md +36 -0
  24. package/docs/examples/calls-benchmark/main.md +78 -0
  25. package/docs/examples/calls-benchmark/operations.md +60 -0
  26. package/docs/examples/developer-workflow/calculator.md +5 -5
  27. package/docs/examples/developer-workflow/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  28. package/docs/examples/developer-workflow/logging/console.md +2 -2
  29. package/docs/examples/developer-workflow/logging/logger.md +2 -2
  30. package/docs/examples/developer-workflow/main.md +2 -2
  31. package/docs/examples/errors-benchmark/index.md +36 -0
  32. package/docs/examples/errors-benchmark/main.md +92 -0
  33. package/docs/examples/errors-benchmark/operations.md +65 -0
  34. package/docs/examples/float-benchmark/index.md +35 -0
  35. package/docs/examples/float-benchmark/main.md +75 -0
  36. package/docs/examples/generic-di/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  37. package/docs/examples/generic-di/main.md +2 -2
  38. package/docs/examples/generic-di/types.md +3 -3
  39. package/docs/examples/hello/app/greeter.md +3 -3
  40. package/docs/examples/hello/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  41. package/docs/examples/hello/logging/console.md +2 -2
  42. package/docs/examples/hello/logging/logger.md +2 -2
  43. package/docs/examples/hello/main.md +2 -2
  44. package/docs/examples/index.md +18 -1
  45. package/docs/examples/interceptors/app.md +5 -5
  46. package/docs/examples/interceptors/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  47. package/docs/examples/interceptors/interceptors.md +2 -2
  48. package/docs/examples/interceptors/logging.md +3 -3
  49. package/docs/examples/interceptors/main.md +2 -2
  50. package/docs/examples/list-benchmark/index.md +35 -0
  51. package/docs/examples/list-benchmark/main.md +78 -0
  52. package/docs/examples/map-churn-benchmark/index.md +35 -0
  53. package/docs/examples/map-churn-benchmark/main.md +106 -0
  54. package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/api.md +104 -0
  55. package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.md +54 -0
  56. package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/native.abi-json.md +48 -0
  57. package/docs/examples/native-blake3/hashing.md +93 -0
  58. package/docs/examples/native-blake3/index.md +38 -0
  59. package/docs/examples/native-blake3/main.md +73 -0
  60. package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/api.md +406 -0
  61. package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.md +51 -0
  62. package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.md +63 -0
  63. package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/native.abi-json.md +161 -0
  64. package/docs/examples/native-pytorch/index.md +38 -0
  65. package/docs/examples/native-pytorch/main.md +73 -0
  66. package/docs/examples/native-pytorch/tensors.md +123 -0
  67. package/docs/examples/native-sqlite/database.md +116 -0
  68. package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/api.md +284 -0
  69. package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.md +51 -0
  70. package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.md +75 -0
  71. package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/native.abi-json.md +119 -0
  72. package/docs/examples/native-sqlite/index.md +38 -0
  73. package/docs/examples/native-sqlite/main.md +73 -0
  74. package/docs/examples/native-zlib/compression.md +99 -0
  75. package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/api.md +153 -0
  76. package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.md +54 -0
  77. package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/native.abi-json.md +76 -0
  78. package/docs/examples/native-zlib/index.md +38 -0
  79. package/docs/examples/native-zlib/main.md +78 -0
  80. package/docs/examples/new-syntax/console.md +2 -2
  81. package/docs/examples/new-syntax/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  82. package/docs/examples/new-syntax/greeter.md +3 -3
  83. package/docs/examples/new-syntax/logger.md +2 -2
  84. package/docs/examples/new-syntax/main.md +2 -2
  85. package/docs/examples/ownership-transfer/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  86. package/docs/examples/ownership-transfer/main.md +2 -2
  87. package/docs/examples/ownership-transfer/resource.md +2 -2
  88. package/docs/examples/packages-math/aug-package-json.md +1 -1
  89. package/docs/examples/records-benchmark/data.md +55 -0
  90. package/docs/examples/records-benchmark/index.md +36 -0
  91. package/docs/examples/records-benchmark/main.md +85 -0
  92. package/docs/examples/strings-benchmark/index.md +35 -0
  93. package/docs/examples/strings-benchmark/main.md +76 -0
  94. package/docs/examples/tasks-benchmark/index.md +36 -0
  95. package/docs/examples/tasks-benchmark/main.md +89 -0
  96. package/docs/examples/tasks-benchmark/operations.md +58 -0
  97. package/docs/getting-started.md +3 -3
  98. package/docs/grammar.md +2 -2
  99. package/docs/gym-results.json +784 -0
  100. package/docs/implementation-map.md +6 -0
  101. package/docs/index.md +1 -1
  102. package/docs/kernel-results.json +1170 -0
  103. package/docs/language-conformance.md +6 -0
  104. package/docs/language-constructs.md +9 -1
  105. package/docs/learn/index.md +1 -1
  106. package/docs/maintaining-docs.md +1 -1
  107. package/docs/native-implementation.md +276 -0
  108. package/docs/native-interop-llvm-plan.md +342 -0
  109. package/docs/native-package-examples.md +684 -0
  110. package/docs/native-packages.md +179 -0
  111. package/docs/packages.md +2 -2
  112. package/docs/performance.md +50 -29
  113. package/docs/production-readiness.md +11 -1
  114. package/docs/public/downloads/approved-design.zip +0 -0
  115. package/docs/public/downloads/calls-benchmark.zip +0 -0
  116. package/docs/public/downloads/developer-workflow.zip +0 -0
  117. package/docs/public/downloads/errors-benchmark.zip +0 -0
  118. package/docs/public/downloads/float-benchmark.zip +0 -0
  119. package/docs/public/downloads/generic-di.zip +0 -0
  120. package/docs/public/downloads/hello.zip +0 -0
  121. package/docs/public/downloads/interceptors.zip +0 -0
  122. package/docs/public/downloads/json-benchmark.zip +0 -0
  123. package/docs/public/downloads/list-benchmark.zip +0 -0
  124. package/docs/public/downloads/map-churn-benchmark.zip +0 -0
  125. package/docs/public/downloads/native-blake3.zip +0 -0
  126. package/docs/public/downloads/native-pytorch.zip +0 -0
  127. package/docs/public/downloads/native-sqlite.zip +0 -0
  128. package/docs/public/downloads/native-zlib.zip +0 -0
  129. package/docs/public/downloads/new-syntax.zip +0 -0
  130. package/docs/public/downloads/oidc-login.zip +0 -0
  131. package/docs/public/downloads/ownership-transfer.zip +0 -0
  132. package/docs/public/downloads/packages-app.zip +0 -0
  133. package/docs/public/downloads/packages-math.zip +0 -0
  134. package/docs/public/downloads/records-benchmark.zip +0 -0
  135. package/docs/public/downloads/strings-benchmark.zip +0 -0
  136. package/docs/public/downloads/tasks-benchmark.zip +0 -0
  137. package/docs/qualification-results.md +66 -0
  138. package/docs/reference.md +24 -0
  139. package/docs/releasing.md +81 -6
  140. package/docs/research/libtorch-native-qualification.md +115 -0
  141. package/docs/research/native-interop-llvm.md +197 -0
  142. package/docs/research/qualification-methods.md +15 -0
  143. package/docs/roadmap.md +1 -0
  144. package/docs/safety-gyms.md +41 -0
  145. package/docs/tooling.md +16 -15
  146. package/docs/web-library-gaps.md +1 -1
  147. package/docs/web.md +4 -0
  148. package/examples/approved-design/.aug-spec/manifest.json +3 -3
  149. package/examples/approved-design/domain/app.aug.md +4 -4
  150. package/examples/approved-design/main.aug.md +2 -2
  151. package/examples/developer-workflow/.aug-spec/manifest.json +3 -3
  152. package/examples/developer-workflow/calculator.aug.md +5 -5
  153. package/examples/developer-workflow/logging/console.aug.md +2 -2
  154. package/examples/developer-workflow/logging/logger.aug.md +2 -2
  155. package/examples/developer-workflow/main.aug.md +2 -2
  156. package/examples/generic-di/.aug-spec/manifest.json +3 -3
  157. package/examples/generic-di/main.aug.md +2 -2
  158. package/examples/generic-di/types.aug.md +3 -3
  159. package/examples/hello/.aug-spec/manifest.json +3 -3
  160. package/examples/hello/app/greeter.aug.md +3 -3
  161. package/examples/hello/logging/console.aug.md +2 -2
  162. package/examples/hello/logging/logger.aug.md +2 -2
  163. package/examples/hello/main.aug.md +2 -2
  164. package/examples/interceptors/.aug-spec/manifest.json +3 -3
  165. package/examples/interceptors/app.aug.md +5 -5
  166. package/examples/interceptors/interceptors.aug.md +2 -2
  167. package/examples/interceptors/logging.aug.md +3 -3
  168. package/examples/interceptors/main.aug.md +2 -2
  169. package/examples/native-blake3/.aug-spec/manifest.json +16 -0
  170. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.1/native.abi.json +29 -0
  171. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/api.aug +14 -0
  172. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/api.aug.md +34 -0
  173. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.aug +4 -0
  174. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.aug.md +8 -0
  175. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/native.abi.json +29 -0
  176. package/examples/native-blake3/AGENTS.md +5 -0
  177. package/examples/native-blake3/aug.lock.json +253 -0
  178. package/examples/native-blake3/hashing.aug +11 -0
  179. package/examples/native-blake3/hashing.aug.md +25 -0
  180. package/examples/native-blake3/main.aug +8 -0
  181. package/examples/native-blake3/main.aug.md +13 -0
  182. package/examples/native-pytorch/.aug-spec/manifest.json +18 -0
  183. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.1/native.abi.json +142 -0
  184. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.3/native.abi.json +142 -0
  185. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/api.aug +101 -0
  186. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/api.aug.md +160 -0
  187. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.aug +3 -0
  188. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.aug.md +8 -0
  189. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.aug +6 -0
  190. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.aug.md +13 -0
  191. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/native.abi.json +142 -0
  192. package/examples/native-pytorch/AGENTS.md +5 -0
  193. package/examples/native-pytorch/aug.lock.json +309 -0
  194. package/examples/native-pytorch/main.aug +8 -0
  195. package/examples/native-pytorch/main.aug.md +13 -0
  196. package/examples/native-pytorch/tensors.aug +23 -0
  197. package/examples/native-pytorch/tensors.aug.md +35 -0
  198. package/examples/native-sqlite/.aug-spec/manifest.json +18 -0
  199. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.2/native.abi.json +100 -0
  200. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/api.aug +48 -0
  201. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/api.aug.md +91 -0
  202. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.aug +3 -0
  203. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.aug.md +8 -0
  204. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.aug +8 -0
  205. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.aug.md +22 -0
  206. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/native.abi.json +100 -0
  207. package/examples/native-sqlite/AGENTS.md +5 -0
  208. package/examples/native-sqlite/aug.lock.json +236 -0
  209. package/examples/native-sqlite/database.aug +15 -0
  210. package/examples/native-sqlite/database.aug.md +27 -0
  211. package/examples/native-sqlite/main.aug +8 -0
  212. package/examples/native-sqlite/main.aug.md +13 -0
  213. package/examples/native-zlib/.aug-spec/manifest.json +16 -0
  214. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.1/native.abi.json +57 -0
  215. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/api.aug +29 -0
  216. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/api.aug.md +54 -0
  217. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.aug +4 -0
  218. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.aug.md +8 -0
  219. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/native.abi.json +57 -0
  220. package/examples/native-zlib/AGENTS.md +5 -0
  221. package/examples/native-zlib/aug.lock.json +236 -0
  222. package/examples/native-zlib/compression.aug +15 -0
  223. package/examples/native-zlib/compression.aug.md +27 -0
  224. package/examples/native-zlib/main.aug +10 -0
  225. package/examples/native-zlib/main.aug.md +13 -0
  226. package/examples/new-syntax/.aug-spec/manifest.json +3 -3
  227. package/examples/new-syntax/console.aug.md +2 -2
  228. package/examples/new-syntax/greeter.aug.md +3 -3
  229. package/examples/new-syntax/logger.aug.md +2 -2
  230. package/examples/new-syntax/main.aug.md +2 -2
  231. package/examples/oidc-login/aug.lock.json +6 -6
  232. package/examples/ownership-transfer/.aug-spec/manifest.json +3 -3
  233. package/examples/ownership-transfer/main.aug.md +2 -2
  234. package/examples/ownership-transfer/resource.aug.md +2 -2
  235. package/examples/packages/math/aug-package.json +1 -1
  236. package/native/compiler-packs.json +43 -0
  237. package/package.json +3 -2
  238. package/runtime/aug_http.c +48 -21
  239. package/runtime/aug_http_ir.c +30 -0
  240. package/runtime/aug_http_ir.h +18 -0
  241. package/runtime/aug_ir.c +209 -0
  242. package/runtime/aug_ir.h +89 -0
  243. package/runtime/aug_json.c +6 -1
  244. package/runtime/aug_runtime.c +82 -16
  245. package/runtime/aug_runtime.h +16 -2
  246. package/runtime/aug_tasks.c +38 -7
  247. package/runtime/aug_values.c +12 -6
  248. package/scripts/bootstrap-native.mjs +4 -1
  249. package/src/ast.js +1 -1
  250. package/src/checker.js +110 -28
  251. package/src/cli.js +92 -14
  252. package/src/codegen.js +31 -6
  253. package/src/compiler-packs.js +66 -0
  254. package/src/config.js +2 -2
  255. package/src/editor.js +15 -6
  256. package/src/formatter.js +4 -2
  257. package/src/git-http.js +137 -0
  258. package/src/git-packages.js +9 -1
  259. package/src/help.js +10 -2
  260. package/src/ir-types.js +5 -0
  261. package/src/ir-verify.js +277 -0
  262. package/src/ir.js +962 -0
  263. package/src/llvm-debug.js +101 -0
  264. package/src/llvm-native.js +152 -0
  265. package/src/llvm-platform.js +20 -0
  266. package/src/llvm.js +781 -0
  267. package/src/native-artifacts.js +207 -0
  268. package/src/native-bindings.js +189 -0
  269. package/src/native-contracts.js +295 -0
  270. package/src/native-declarations.js +68 -0
  271. package/src/native-facts.js +63 -0
  272. package/src/package-locking.js +43 -0
  273. package/src/package-manager.js +23 -8
  274. package/src/parser.js +20 -2
  275. package/src/project.js +2 -2
  276. package/src/runtime-abi.js +23 -0
  277. package/src/runtime-adapters.js +18 -0
  278. package/src/schemas.js +24 -17
  279. package/src/semantic.js +8 -3
  280. package/src/snippets.js +1 -0
  281. package/src/spec.js +49 -8
  282. /package/examples/approved-design/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  283. /package/examples/approved-design/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  284. /package/examples/developer-workflow/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  285. /package/examples/developer-workflow/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  286. /package/examples/generic-di/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  287. /package/examples/generic-di/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  288. /package/examples/hello/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  289. /package/examples/hello/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  290. /package/examples/interceptors/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  291. /package/examples/interceptors/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  292. /package/examples/new-syntax/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  293. /package/examples/new-syntax/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  294. /package/examples/ownership-transfer/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  295. /package/examples/ownership-transfer/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
package/src/ir.js ADDED
@@ -0,0 +1,962 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { relative, resolve } from 'node:path';
3
+ import { isStatement, fieldsOf, initializationOf } from "./ast.js";
4
+ import { typeName } from "./ast.js";
5
+ import { errorNames, builtinProperties } from "./builtins.js";
6
+ import { DataSchemas, schemaType } from "./schemas.js";
7
+ import { runtimeAdapters, adapterSymbol } from "./runtime-adapters.js";
8
+ import { generateOpenApi, apiExplorer, apiExplorerScript } from "./openapi.js";
9
+ import { actionSchema, actionTransport } from "./actions.js";
10
+ import { httpPolicyNames } from "./http-policies.js";
11
+ import { interceptorChain, InterceptorInvocation } from "./interceptors.js";
12
+ import { verifyIR } from "./ir-verify.js";
13
+ import { isIRScalar } from "./ir-types.js";
14
+ const dynamicType = { id: 'compiler:dynamic', name: 'Data', args: [], nullable: true, optional: false };
15
+ const scalarType = (name) => ({ id: 'builtin:' + name, name, args: [], nullable: false, optional: false });
16
+ const irType = (type) => ({ id: type.id, name: type.name, args: type.args.map(irType), nullable: type.nullable, optional: !!type.optional });
17
+ export class BackendUnsupported extends Error {
18
+ span;
19
+ code = 'BACKEND_UNSUPPORTED';
20
+ constructor(span, feature) { super('LLVM preview does not support ' + feature + '. No C fallback occurred.'); this.span = span; }
21
+ }
22
+ /** Checked, resolved execution IR. Source AST and semantic facts remain read-only. */
23
+ export function lowerToIR(checked, options = {}) {
24
+ if (checked.diagnostics.some(d => d.severity !== 'warning'))
25
+ throw new Error('Cannot lower a rejected August project');
26
+ const ir = new Lowering(checked, options).lower();
27
+ verifyIR(ir);
28
+ return ir;
29
+ }
30
+ class Lowering {
31
+ checked;
32
+ names = new Map();
33
+ functions = [];
34
+ schemas;
35
+ components = new Set();
36
+ routes = [];
37
+ coverage = new Map();
38
+ options;
39
+ constructor(checked, options) { this.checked = checked; this.options = options; let i = 0; for (const def of checked.project.definitions.values())
40
+ this.names.set(def.id, 'aug_fn_' + i++); this.schemas = new DataSchemas(checked.project, def => this.name(def)); }
41
+ name(def) { return this.names.get(def.id); }
42
+ method(def, name) { return this.name(def) + '_' + name; }
43
+ binding(key) { const i = this.checked.bindings.findIndex(b => b.key === key); if (i < 0)
44
+ throw new Error('Missing checked binding ' + key); return 'aug_resolve_' + i; }
45
+ definition(file, name) { return this.checked.project.scopes.get(file)?.get(name); }
46
+ lower() {
47
+ const active = new Set();
48
+ const visit = (file) => { if (active.has(file))
49
+ return; active.add(file); for (const item of this.checked.project.files.get(file)?.items ?? [])
50
+ if (item.kind === 'import')
51
+ for (const d of this.checked.project.imports.get(item) ?? [])
52
+ visit(d.file); };
53
+ for (const file of this.checked.project.files.values())
54
+ if (!file.builtin)
55
+ visit(file.path);
56
+ for (const def of this.checked.project.definitions.values()) {
57
+ if (!active.has(def.file))
58
+ continue;
59
+ const node = def.node;
60
+ if (node.kind === 'function') {
61
+ if (node.body)
62
+ this.add(def, this.name(def), node, node.params, node.body);
63
+ else if (node.externC && this.checked.interceptorPlans.get(node)?.length) {
64
+ const body = new FunctionLowering(this, def.file, node.span);
65
+ node.params.forEach((param, index) => body.parameter(param, index));
66
+ body.nativeBody(def);
67
+ this.functions.push(body.finish(interceptorChain(this.name(def), this.checked.interceptorPlans.get(node) ?? []).body));
68
+ this.layers(node, this.name(def), node.params, false);
69
+ }
70
+ if (node.endpoint) {
71
+ const body = new FunctionLowering(this, def.file, node.span);
72
+ body.endpoint(def);
73
+ this.functions.push(body.finish(this.name(def) + '_http'));
74
+ this.components.add('http');
75
+ }
76
+ }
77
+ if (node.kind === 'class' || node.kind === 'interceptor') {
78
+ const methods = node.methods.filter(method => node.kind !== 'interceptor' || method.name !== 'around');
79
+ for (const entry of this.checked.defaults.get(def.id)?.values() ?? [])
80
+ if (!methods.some(m => m.name === entry.method.name))
81
+ methods.push(entry.method);
82
+ for (const method of methods)
83
+ if (method.body)
84
+ this.add(def, this.method(def, method.name), method, method.params, method.body, true);
85
+ const body = new FunctionLowering(this, def.file, node.span, def);
86
+ node.fields.forEach((param, i) => body.parameter(param, i));
87
+ body.instruction({ op: 'object', out: 0, type: def.id, fields: fieldsOf(node).map(f => f.name), owned: fieldsOf(node).map(f => f.ownership === 'own'), methods: methods.map(m => ({ name: m.name, function: this.method(def, m.name) })), record: node.kind === 'class' && !!node.record });
88
+ node.fields.forEach((param, i) => { body.runtime('SET_FIELD', [0, body.parameters[i]], undefined, i); if (param.ownership === 'own')
89
+ body.instruction({ op: 'clear', slot: body.parameters[i] }); });
90
+ node.fields.forEach(param => body.locals.delete(param.name));
91
+ body.locals.set('self', 0);
92
+ if (node.kind === 'class')
93
+ for (const stmt of initializationOf(node))
94
+ body.statement(stmt);
95
+ if (node.kind === 'class' && node.record)
96
+ body.runtime('FREEZE', [0]);
97
+ const chain = node.kind === 'class' ? interceptorChain(this.name(def), this.checked.interceptorPlans.get(node) ?? []) : { body: this.name(def) };
98
+ this.functions.push({ ...body.finish(chain.body), failedResult: true });
99
+ if (node.kind === 'class')
100
+ this.layers(node, this.name(def), node.fields, false);
101
+ }
102
+ }
103
+ this.checked.bindings.forEach((binding, index) => {
104
+ const body = new FunctionLowering(this, binding.declaration.span.file, binding.declaration.span);
105
+ if (binding.lifetime !== 'fresh') {
106
+ body.instruction({ op: 'binding-get', out: 0, index });
107
+ const create = body.block(), done = body.block();
108
+ body.terminate({ op: 'null', input: 0, then: create, otherwise: done });
109
+ body.enter(done);
110
+ body.terminate({ op: 'jump', target: 'cleanup' });
111
+ body.enter(create);
112
+ }
113
+ const args = binding.constructorKeys.map(key => body.call(this.binding(key), []));
114
+ body.instruction({ op: 'call', out: 0, function: this.name(binding.target), args });
115
+ body.checkError();
116
+ if (binding.lifetime !== 'fresh')
117
+ body.instruction({ op: 'binding-set', input: 0, index });
118
+ this.functions.push(body.finish('aug_resolve_' + index));
119
+ });
120
+ const main = this.checked.project.main;
121
+ if (!main)
122
+ throw new Error('LLVM executable requires main.aug');
123
+ const body = new FunctionLowering(this, main.path, { file: main.path, start: 0, end: main.source.length, line: 1, column: 1 });
124
+ for (let index = 0; index <= main.items.length; index++) {
125
+ if (this.checked.project.testBodyStart === index)
126
+ body.runtime('TEST_CASE', []);
127
+ const stmt = main.items[index];
128
+ if (stmt && isStatement(stmt))
129
+ body.statement(stmt);
130
+ }
131
+ this.functions.push(body.finish('aug_main_body'));
132
+ const project = this.checked.project, scopes = [...project.packages.scopes.values()];
133
+ const hashes = [...project.files.values()].map(f => {
134
+ const scope = scopes.find(s => f.path.startsWith(s.sourceRoot + '/'));
135
+ const path = scope ? scope.name + '@' + scope.version + '/' + relative(scope.sourceRoot, f.path) : f.builtin ? 'august/' + relative(project.stdlibRoot, f.path) : relative(project.root, f.path);
136
+ return [path.replaceAll('\\', '/'), createHash('sha256').update(f.source).digest('hex')];
137
+ }).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
138
+ const dependencies = scopes.map(s => ({ name: s.name, version: s.version, digest: s.digest, native: s.native?.bindingsSha256 })).sort((a, b) => a.name.localeCompare(b.name, 'en'));
139
+ const web = project.config.web, tls = Object.fromEntries(Object.entries(web.tls).map(([key, value]) => [key, value ? resolve(project.root, value) : '']));
140
+ return { format: 1, sourceRevision: createHash('sha256').update(JSON.stringify({ sources: hashes, configuration: project.config, dependencies })).digest('hex'), functions: this.functions, main: 'aug_main_body', bindings: this.checked.bindings.map((b, i) => ({ function: 'aug_resolve_' + i, shared: b.lifetime === 'shared' })), scoped: this.checked.bindings.map(b => b.lifetime === 'scoped'), test: !!this.checked.project.testMode, schemas: this.schemas.nodes, components: [...this.components].sort(), routes: this.routes, web: { ...web, tls }, coverage: [...this.coverage.values()].sort((a, b) => a.file.localeCompare(b.file, 'en') || a.line - b.line) };
141
+ }
142
+ policy(plan) {
143
+ const options = plan.options;
144
+ return { kind: httpPolicyNames.indexOf(plan.name) + 1, permission: String(options.permission ?? ''), amount: Number(options.requests ?? options.milliseconds ?? 0), seconds: Number(options.seconds ?? 0), credentials: !!options.credentials, origins: (options.origins ?? []).join('\n'), headers: (options.headers ?? []).map(header => header.toLowerCase()).join(', ') };
145
+ }
146
+ routeTable(file, names) {
147
+ this.components.add('http');
148
+ const name = 'aug_routes_' + this.routes.length;
149
+ const items = names.map(name => {
150
+ const def = this.definition(file, name), fn = def.node, endpoint = fn.endpoint;
151
+ return { method: endpoint.method, path: endpoint.path, function: this.name(def) + '_http', stream: endpoint.streams ? fn.returns.name === 'ServerEvent' ? 1 : fn.returns.name === 'Bytes' ? 2 : 3 : 0, status: endpoint.status, policies: (this.checked.httpPolicies.get(fn) ?? []).map(plan => this.policy(plan)) };
152
+ });
153
+ // Reserve its name before adding generated documentation handlers.
154
+ this.routes.push({ name, items });
155
+ const config = this.checked.project.config.openapi;
156
+ const assets = config.enabled ? [
157
+ { path: config.path, type: 'application/json', content: JSON.stringify(generateOpenApi(this.checked).document) },
158
+ { path: config.docs, type: 'text/html; charset=utf-8', content: apiExplorer(config.path, config.docs + '/client.js') },
159
+ { path: config.docs + '/client.js', type: 'application/javascript; charset=utf-8', content: apiExplorerScript }
160
+ ] : [];
161
+ if (this.checked.actions.size)
162
+ assets.push({ path: '/__aug/actions.js', type: 'application/javascript; charset=utf-8', content: actionTransport });
163
+ assets.forEach((asset, index) => {
164
+ const body = new FunctionLowering(this, file, this.checked.project.main.items[0]?.span ?? { file, start: 0, end: 0, line: 1, column: 1 });
165
+ const bytes = body.runtime('STRING_BYTES', [body.literal(asset.content)]), headers = body.runtime('HTTP_HEADERS', []);
166
+ const typed = body.runtime('HTTP_HEADERS_WITH', [headers, body.literal('content-type'), body.literal(asset.type)]);
167
+ const result = body.runtime('HTTP_RESPONSE', [bytes, body.literal(null, { kind: 'int', text: '200' }), typed]);
168
+ body.instruction({ op: 'copy', out: 0, input: result });
169
+ const fn = name + '_asset_' + index;
170
+ this.functions.push(body.finish(fn));
171
+ items.push({ method: 'GET', path: asset.path, function: fn, stream: 0, status: 200, policies: [] });
172
+ });
173
+ return name;
174
+ }
175
+ add(def, name, method, params, stmts, receiver = false) {
176
+ const body = new FunctionLowering(this, method.span.file, method.span, receiver ? def : undefined);
177
+ body.sourceName = method.name;
178
+ if (receiver) {
179
+ body.receiver = body.slot();
180
+ body.locals.set('self', body.receiver);
181
+ }
182
+ params.forEach((p, i) => body.parameter(p, i));
183
+ stmts.forEach(s => body.statement(s));
184
+ this.functions.push(body.finish(interceptorChain(name, this.checked.interceptorPlans.get(method) ?? []).body));
185
+ this.layers(method, name, params, receiver);
186
+ }
187
+ layers(node, name, params, receiver) {
188
+ for (const entry of interceptorChain(name, this.checked.interceptorPlans.get(node) ?? []).entries) {
189
+ const body = new FunctionLowering(this, entry.layer.definition.file, entry.layer.around.span, entry.layer.definition);
190
+ body.sourceName = node.name + ' [' + entry.layer.definition.name + ']';
191
+ if (receiver) {
192
+ body.receiver = body.slot();
193
+ body.locals.set('self', body.receiver);
194
+ }
195
+ params.forEach((param, index) => body.parameter(param, index));
196
+ body.interceptor(entry.layer, params, entry.next);
197
+ entry.layer.around.body.forEach(stmt => body.statement(stmt));
198
+ this.functions.push(body.finish(entry.name));
199
+ }
200
+ }
201
+ }
202
+ class FunctionLowering {
203
+ generator;
204
+ file;
205
+ span;
206
+ owner;
207
+ parameters = [];
208
+ receiver;
209
+ locals = new Map();
210
+ owned = new Set();
211
+ values = [];
212
+ variables = [];
213
+ scopes = [];
214
+ debugScope;
215
+ sourceName;
216
+ continuation;
217
+ constructionNext = false;
218
+ constructorResults = new Set();
219
+ slots = 1;
220
+ sequence = 0;
221
+ source;
222
+ error = 'cleanup';
223
+ returning = 'cleanup';
224
+ blocks = [];
225
+ current;
226
+ constructor(generator, file, span, owner) { this.generator = generator; this.file = file; this.span = span; this.source = span; this.owner = owner; this.values.push({ storage: 'rooted-value', type: dynamicType, span }); this.current = { name: 'entry_body', instructions: [] }; this.blocks.push(this.current); }
227
+ slot(type = dynamicType) { this.values.push({ storage: 'rooted-value', type, span: this.source }); return this.slots++; }
228
+ block() { return 'block_' + this.sequence++; }
229
+ enter(name) { this.current = { name, instructions: [] }; this.blocks.push(this.current); }
230
+ terminate(terminator) { this.current.terminator = terminator; }
231
+ instruction(value) { if (this.current.terminator)
232
+ this.enter(this.block()); this.current.instructions.push({ ...value, span: this.source, debugScope: this.debugScope }); }
233
+ local(name, slot, span, type = this.values[slot].type) {
234
+ this.locals.set(name, slot);
235
+ this.values[slot].type = type;
236
+ const variable = this.variables.length;
237
+ this.variables.push({ name, slot, span, type, scope: this.debugScope });
238
+ const source = this.source;
239
+ this.source = span;
240
+ this.instruction({ op: 'debug-variable', variable });
241
+ this.source = source;
242
+ }
243
+ parameter(param, index) { const type = irType(schemaType(this.generator.checked.project, param.type, this.file)), slot = this.slot(type); this.parameters[index] = slot; this.locals.set(param.name, slot); this.variables.push({ name: param.name, slot, span: param.span, type, argument: index + 1 }); if (param.ownership === 'own')
244
+ this.owned.add(slot); }
245
+ checkError() { const errors = this.block(), next = this.block(); this.terminate({ op: 'cancel', then: this.returning, otherwise: errors }); this.enter(errors); this.terminate({ op: 'error', failed: this.error, success: next }); this.enter(next); }
246
+ runtime(operation, args, text, number, check = true) {
247
+ if (operation.startsWith('HTTP_'))
248
+ this.generator.components.add('http');
249
+ const comparisons = ['==', '!=', '<', '>', '<=', '>='], integers = args.length === 2 && args.every(slot => isIRScalar(this.values[slot].type) && this.values[slot].type.name === 'int');
250
+ const binary = operation === 'BINARY' && integers && (comparisons.includes(text) || ['+', '-', '*', '/'].includes(text));
251
+ const integerResult = ['LIST_LENGTH', 'TUPLE_LENGTH', 'SET_LENGTH', 'MAP_LENGTH', 'STRING_LENGTH', 'BYTES_LENGTH', 'JSON_INTEGER'].includes(operation);
252
+ const booleanResult = ['SET_CONTAINS', 'MAP_CONTAINS', 'STRING_STARTS_WITH', 'STRING_IS_TOKEN', 'IS_TYPE', 'JSON_BOOLEAN'].includes(operation);
253
+ const out = this.slot(integerResult ? scalarType('int') : booleanResult ? scalarType('bool') : binary ? scalarType(comparisons.includes(text) ? 'bool' : 'int') : dynamicType);
254
+ this.instruction({ op: 'runtime', out, operation, args, text, number });
255
+ if (check && !(binary && text !== '/'))
256
+ this.checkError();
257
+ return out;
258
+ }
259
+ call(name, args, receiver) { const out = this.slot(); this.instruction({ op: 'call', out, function: name, args, receiver }); this.checkError(); return out; }
260
+ literal(value, numeric) { const out = this.slot(numeric ? scalarType(numeric.kind) : typeof value === 'boolean' ? scalarType('bool') : dynamicType); this.instruction({ op: 'literal', out, value, numeric }); return out; }
261
+ fieldIndex(object, name) {
262
+ const node = this.generator.checked.expressionTypes.get(object)?.def?.node;
263
+ if (node?.kind === 'class' || node?.kind === 'interceptor') {
264
+ const i = fieldsOf(node).findIndex(f => f.name === name);
265
+ if (i >= 0)
266
+ return i;
267
+ }
268
+ const type = this.generator.checked.expressionTypes.get(object);
269
+ if (type?.kind === 'builtin') {
270
+ const index = builtinProperties[type.name]?.findIndex(field => field.name === name);
271
+ if (index !== undefined && index >= 0)
272
+ return index;
273
+ }
274
+ if (name === 'code')
275
+ return 0;
276
+ if (name === 'message')
277
+ return 1;
278
+ throw new BackendUnsupported(object.span, 'field ' + name);
279
+ }
280
+ field(name) { const node = this.owner?.node; if (node?.kind !== 'class' && node?.kind !== 'interceptor')
281
+ return; const i = fieldsOf(node).findIndex(f => f.name === name); return i < 0 ? undefined : i; }
282
+ arguments(expr, plan) {
283
+ const source = expr.args.map(a => this.expression(a));
284
+ return plan ? plan.sourceIndices.map((index, i) => {
285
+ if (index !== undefined)
286
+ return source[index];
287
+ const injected = plan.injectionSources?.[i];
288
+ if (injected?.startsWith('self.'))
289
+ return this.runtime('FIELD', [this.locals.get('self')], undefined, this.field(injected.slice(5)));
290
+ if (injected) {
291
+ const slot = this.locals.get(injected);
292
+ if (slot !== undefined)
293
+ return slot;
294
+ }
295
+ return plan.bindingKeys[i] ? this.call(this.generator.binding(plan.bindingKeys[i]), []) : this.literal(null);
296
+ }) : source;
297
+ }
298
+ expression(expr) {
299
+ const firstNewSlot = this.slots, result = this.expressionValue(expr), type = this.generator.checked.expressionTypes.get(expr);
300
+ if (result >= firstNewSlot && type)
301
+ this.values[result].type = irType(type);
302
+ return result;
303
+ }
304
+ expressionValue(expr) {
305
+ this.source = expr.span;
306
+ if (expr.kind === 'handle') {
307
+ const plan = this.generator.checked.actions.get(expr), endpoint = plan.endpoint.node.endpoint;
308
+ const metadata = { method: endpoint.method, path: endpoint.path, parameters: plan.parameters.map(({ param, type, form }) => ({ name: param.source?.name ?? param.name, source: param.source?.kind, form, schema: actionSchema(this.generator.checked.project, type) })) };
309
+ const values = expr.call.args.map(argument => argument.kind === 'formInput' ? this.literal(null) : this.expression(argument));
310
+ const args = plan.parameters.map(parameter => parameter.form || parameter.source === undefined ? this.literal(null) : values[parameter.source]);
311
+ return this.runtime('HTTP_ACTION', args, JSON.stringify(metadata));
312
+ }
313
+ if (expr.kind === 'markupText')
314
+ return this.literal(expr.text);
315
+ if (expr.kind === 'markup') {
316
+ const component = this.generator.checked.markupCalls.get(expr);
317
+ if (component)
318
+ return this.expression(component);
319
+ this.generator.components.add('http');
320
+ const names = expr.attributes.map(attribute => this.literal(attribute.name));
321
+ const values = expr.attributes.map(attribute => this.expression(attribute.value)), children = expr.children.map(child => this.expression(child)), out = this.slot();
322
+ this.instruction({ op: 'html', out, tag: expr.tag, attributes: names.flatMap((name, index) => [name, values[index]]), children });
323
+ this.checkError();
324
+ return out;
325
+ }
326
+ if (expr.kind === 'literal')
327
+ return typeof expr.value === 'number' ? this.literal(null, { kind: expr.numericType ?? 'int', text: expr.numericText ?? String(expr.value) }) : this.literal(expr.value);
328
+ if (expr.kind === 'name') {
329
+ const slot = this.locals.get(expr.name);
330
+ if (slot !== undefined)
331
+ return slot;
332
+ const index = this.field(expr.name);
333
+ if (index !== undefined)
334
+ return this.runtime('FIELD', [this.locals.get('self')], undefined, index);
335
+ throw new BackendUnsupported(expr.span, 'unresolved value ' + expr.name);
336
+ }
337
+ if (expr.kind === 'resolve')
338
+ return this.call(this.generator.binding(expr.name + (expr.typeArgs.length ? '<' + expr.typeArgs.map(typeName).join(',') + '>' : '')), []);
339
+ if (expr.kind === 'member')
340
+ return this.runtime('FIELD', [this.expression(expr.object)], undefined, this.fieldIndex(expr.object, expr.name));
341
+ if (expr.kind === 'unary') {
342
+ const input = this.expression(expr.value), type = this.values[input].type;
343
+ const pure = isIRScalar(type) && (type.name === 'int' && expr.op === '-' || type.name === 'bool' && expr.op === '!');
344
+ return this.runtime('UNARY', [input], expr.op, undefined, !pure);
345
+ }
346
+ if (expr.kind === 'binary') {
347
+ const left = this.expression(expr.left);
348
+ if (expr.op === '&&' || expr.op === '||') {
349
+ const out = this.slot();
350
+ this.instruction({ op: 'copy', out, input: left });
351
+ const evaluate = this.block(), after = this.block();
352
+ this.terminate({ op: 'branch', condition: left, then: expr.op === '&&' ? evaluate : after, otherwise: expr.op === '&&' ? after : evaluate });
353
+ this.enter(evaluate);
354
+ const right = this.expression(expr.right);
355
+ this.instruction({ op: 'copy', out, input: right });
356
+ this.terminate({ op: 'jump', target: after });
357
+ this.enter(after);
358
+ return out;
359
+ }
360
+ const right = this.expression(expr.right), a = this.values[left].type, b = this.values[right].type;
361
+ const pure = isIRScalar(a) && isIRScalar(b) && (a.name === 'int' && b.name === 'int' && ['+', '-', '*', '==', '!=', '<', '>', '<=', '>='].includes(expr.op) || a.name === 'bool' && b.name === 'bool' && ['==', '!='].includes(expr.op));
362
+ return this.runtime('BINARY', [left, right], expr.op, undefined, !pure);
363
+ }
364
+ if (expr.kind === 'collection') {
365
+ const values = expr.items.map(item => this.expression(item)), kind = this.generator.checked.expressionTypes.get(expr)?.name ?? expr.collection;
366
+ if (kind === 'Map') {
367
+ const out = this.runtime('MAP', []);
368
+ for (let i = 0; i < values.length; i += 2)
369
+ this.runtime('MAP_SET', [out, values[i], values[i + 1]]);
370
+ return out;
371
+ }
372
+ return this.runtime(kind.toUpperCase(), values);
373
+ }
374
+ if (expr.kind === 'wait') {
375
+ const tasks = expr.tasks.map(task => this.expression(task)), out = this.slot();
376
+ this.instruction({ op: 'wait', out, tasks });
377
+ this.checkError();
378
+ return out;
379
+ }
380
+ if (expr.kind === 'start' && expr.call.kind === 'call') {
381
+ const call = expr.call, receiver = call.callee.kind === 'member' ? this.expression(call.callee.object) : undefined;
382
+ // Capture evaluation and injected dependencies in the parent. The child
383
+ // receives those values; it never reevaluates an argument or resolves DI.
384
+ const args = this.arguments(call, this.generator.checked.callPlans.get(call));
385
+ const thunk = new FunctionLowering(this.generator, this.file, expr.span, this.owner);
386
+ if (receiver !== undefined)
387
+ thunk.receiver = thunk.slot();
388
+ args.forEach((_, i) => {
389
+ const slot = thunk.slot();
390
+ thunk.parameters[i] = slot;
391
+ if (this.generator.checked.callPlans.get(call)?.ownerships?.[i] === 'own')
392
+ thunk.owned.add(slot);
393
+ });
394
+ const result = thunk.invoke(call, thunk.receiver, [...thunk.parameters]);
395
+ thunk.instruction({ op: 'copy', out: 0, input: result });
396
+ if (thunk.owned.has(result))
397
+ thunk.instruction({ op: 'clear', slot: result });
398
+ const name = 'aug_task_thunk_' + this.generator.functions.length;
399
+ this.generator.functions.push(thunk.finish(name));
400
+ const out = this.slot();
401
+ this.instruction({ op: 'start', out, function: name, receiver, args, owned: args.map((_, i) => this.generator.checked.callPlans.get(call)?.ownerships?.[i] === 'own') });
402
+ this.generator.checked.callPlans.get(call)?.ownerships?.forEach((mode, i) => { if (mode === 'own')
403
+ this.instruction({ op: 'clear', slot: args[i] }); });
404
+ this.checkError();
405
+ return out;
406
+ }
407
+ if (expr.kind !== 'call')
408
+ throw new BackendUnsupported(expr.span, expr.kind + ' expressions');
409
+ const receiver = expr.callee.kind === 'member' ? this.expression(expr.callee.object) : undefined;
410
+ const args = expr.callee.kind === 'name' && expr.callee.name === 'next' ? expr.args.map(arg => this.expression(arg)) : this.arguments(expr, this.generator.checked.callPlans.get(expr));
411
+ return this.invoke(expr, receiver, args);
412
+ }
413
+ invoke(expr, receiver, args, unwrapped = false) {
414
+ this.source = expr.span;
415
+ if (expr.callee.kind === 'member') {
416
+ const type = this.generator.checked.expressionTypes.get(expr.callee.object), name = expr.callee.name;
417
+ if (type.kind === 'builtin' && (type.name === 'Json' && name === 'decode' || type.name === 'HttpRequest' && name === 'form')) {
418
+ const out = this.slot(), schema = this.generator.schemas.request(this.generator.checked.expressionTypes.get(expr));
419
+ if (name === 'form')
420
+ this.generator.components.add('http');
421
+ this.instruction({ op: 'decode', out, input: receiver, schema, format: name === 'form' ? 'form' : 'json' });
422
+ this.checkError();
423
+ return out;
424
+ }
425
+ const operations = {
426
+ 'List.length': 'LIST_LENGTH', 'List.get': 'LIST_GET', 'List.at': 'LIST_AT', 'List.append': 'LIST_APPEND', 'Tuple.length': 'TUPLE_LENGTH', 'Tuple.get': 'TUPLE_GET',
427
+ 'Set.length': 'SET_LENGTH', 'Set.add': 'SET_ADD', 'Set.contains': 'SET_CONTAINS', 'Map.length': 'MAP_LENGTH', 'Map.get': 'MAP_GET', 'Map.take': 'MAP_TAKE', 'Map.contains': 'MAP_CONTAINS', 'Map.set': 'MAP_SET',
428
+ 'string.length': 'STRING_LENGTH', 'string.bytes': 'STRING_BYTES', 'string.split': 'STRING_SPLIT', 'string.startsWith': 'STRING_STARTS_WITH', 'string.isToken': 'STRING_IS_TOKEN',
429
+ 'Bytes.length': 'BYTES_LENGTH', 'Bytes.text': 'BYTES_TEXT', 'Bytes.base64url': 'BYTES_BASE64URL',
430
+ 'Json.stringify': 'JSON_STRINGIFY', 'Json.get': 'JSON_GET', 'Json.require': 'JSON_REQUIRE', 'Json.string': 'JSON_STRING',
431
+ 'Json.integer': 'JSON_INTEGER', 'Json.boolean': 'JSON_BOOLEAN', 'Json.items': 'JSON_ITEMS',
432
+ 'Headers.with': 'HTTP_HEADERS_WITH', 'Headers.get': 'HTTP_HEADERS_GET', 'Headers.all': 'HTTP_HEADERS_ALL', 'HttpTestClient.request': 'HTTP_CLIENT_REQUEST'
433
+ };
434
+ const operation = operations[type.name + '.' + name];
435
+ if (operation) {
436
+ const noFailure = ['LIST_LENGTH', 'LIST_AT', 'LIST_APPEND', 'TUPLE_LENGTH', 'SET_LENGTH', 'SET_ADD', 'SET_CONTAINS', 'MAP_LENGTH', 'MAP_SET', 'MAP_GET', 'MAP_TAKE', 'MAP_CONTAINS', 'STRING_LENGTH', 'STRING_BYTES', 'STRING_SPLIT', 'STRING_STARTS_WITH', 'STRING_IS_TOKEN', 'BYTES_LENGTH', 'BYTES_BASE64URL'].includes(operation);
437
+ return this.runtime(operation, [receiver, ...args], undefined, undefined, !noFailure);
438
+ }
439
+ args = this.transferArguments(expr, args, false);
440
+ const out = this.slot();
441
+ this.instruction({ op: 'method', out, receiver: receiver, name, args });
442
+ if (this.generator.checked.callPlans.get(expr)?.returnOwnership === 'own')
443
+ this.owned.add(out);
444
+ this.checkError();
445
+ return out;
446
+ }
447
+ if (expr.callee.kind !== 'name')
448
+ throw new BackendUnsupported(expr.span, 'indirect callable values');
449
+ const name = expr.callee.name;
450
+ if (name === 'next') {
451
+ const next = this.continuation, plan = this.generator.checked.callPlans.get(expr);
452
+ const { args: forwarded, transfers } = next.forward(plan.sourceIndices, args);
453
+ const argumentsList = [...forwarded];
454
+ for (const { original, replacement } of transfers) {
455
+ const temporary = this.slot();
456
+ this.instruction({ op: 'copy', out: temporary, input: replacement });
457
+ argumentsList[this.parameters.indexOf(original)] = temporary;
458
+ if (replacement !== original)
459
+ this.instruction({ op: 'drop', slot: original });
460
+ this.instruction({ op: 'clear', slot: original });
461
+ if (replacement !== original && this.owned.has(replacement))
462
+ this.instruction({ op: 'clear', slot: replacement });
463
+ }
464
+ const out = this.call(next.target, argumentsList, next.receiver);
465
+ if (this.constructionNext)
466
+ this.constructorResults.add(out);
467
+ if (plan.returnOwnership === 'own')
468
+ this.owned.add(out);
469
+ return out;
470
+ }
471
+ if (name === 'assert') {
472
+ this.instruction({ op: 'assert', input: args[0], expression: this.generator.checked.project.files.get(this.file)?.source.slice(expr.args[0].span.start, expr.args[0].span.end) ?? 'assertion' });
473
+ this.checkError();
474
+ return this.literal(null);
475
+ }
476
+ if (name === 'int')
477
+ return args[0];
478
+ if (errorNames.includes(name)) {
479
+ const out = this.slot();
480
+ this.instruction({ op: 'object', out, type: name, fields: [], owned: [], methods: [], record: false });
481
+ return out;
482
+ }
483
+ if (name === 'Shared') {
484
+ const result = this.runtime('SHARED', [args[0]]);
485
+ if (this.owned.has(args[0]))
486
+ this.instruction({ op: 'clear', slot: args[0] });
487
+ return result;
488
+ }
489
+ if (name === 'HttpTestClient') {
490
+ const endpoint = this.generator.checked.project.testEndpoint, out = this.slot(), routes = this.generator.routeTable(endpoint.file, [endpoint.name]);
491
+ this.instruction({ op: 'routes', out, name: routes });
492
+ this.checkError();
493
+ return out;
494
+ }
495
+ const builtins = { exit: 'EXIT', print: 'PRINT', arguments: 'ARGUMENTS', c_int: 'C_INT', read_file: 'READ_FILE', write_file: 'WRITE_FILE', base64url_decode: 'BASE64URL_DECODE', Json: 'JSON_WRAP', Headers: 'HTTP_HEADERS', HttpResponse: 'HTTP_RESPONSE', ServerEvent: 'HTTP_EVENT' };
496
+ if (builtins[name])
497
+ return this.runtime(builtins[name], args);
498
+ if (['List', 'Tuple', 'Set', 'Map'].includes(name))
499
+ return this.runtime(name.toUpperCase(), args);
500
+ const def = this.generator.definition(this.file, name);
501
+ if (!def)
502
+ throw new BackendUnsupported(expr.span, 'builtin ' + name);
503
+ if (def.node.kind === 'function' && def.node.externC) {
504
+ if (!unwrapped && this.generator.checked.interceptorPlans.get(def.node)?.length) {
505
+ const result = this.call(this.generator.name(def), this.transferArguments(expr, args, false));
506
+ if (def.node.returnOwnership === 'own')
507
+ this.owned.add(result);
508
+ return result;
509
+ }
510
+ const binding = this.generator.checked.native.functions.get(def.node), out = this.slot();
511
+ if (binding) {
512
+ args = this.transferArguments(expr, args, true);
513
+ const resources = {};
514
+ for (const [node, resource] of this.generator.checked.native.resources) {
515
+ if (this.generator.checked.native.providers.get(node) !== this.generator.checked.native.providers.get(def.node))
516
+ continue;
517
+ const definition = this.generator.definition(node.span.file, node.name);
518
+ resources[resource.module + '.' + resource.name] = { id: definition.id, release: resource.release };
519
+ }
520
+ const error = this.generator.checked.native.errors.get(def.node);
521
+ this.instruction({ op: 'native', out, binding, args, resources, error: error?.id, errorFactory: error && this.generator.name(error) });
522
+ }
523
+ else {
524
+ if (def.node.valueAbi) {
525
+ // Compiler-owned adapters use the target pack's pointer thunks. Arbitrary
526
+ // aggregate C declarations remain unsupported, even on an LLVM host.
527
+ const adapters = {
528
+ _aug_json_parse: { types: ['string'], result: 'Json', operation: 'JSON_PARSE' },
529
+ _aug_time_now: { types: [], result: 'int', operation: 'TIME_NOW' }
530
+ };
531
+ const adapter = adapters[def.node.name];
532
+ const plain = (type) => !type.nullable && !type.optional && !type.args.length;
533
+ if (adapter && plain(def.node.returns) && def.node.returns.name === adapter.result && def.node.params.length === adapter.types.length && def.node.params.every((param, i) => plain(param.type) && param.type.name === adapter.types[i]))
534
+ this.instruction({ op: 'runtime', out, operation: adapter.operation, args });
535
+ else {
536
+ const entry = runtimeAdapters.find(entry => entry.name === def.node.name);
537
+ if (!entry || def.node.typeParams.length || def.node.returnOwnership !== 'managed' || typeName(def.node.returns) !== entry.returns || def.node.params.length !== entry.parameters.length || def.node.params.some((param, i) => param.ownership !== 'managed' || typeName(param.type) !== entry.parameters[i]))
538
+ throw new BackendUnsupported(expr.span, 'legacy AugValue native adapter ' + def.node.name + ' with this signature');
539
+ this.generator.components.add(entry.component);
540
+ this.instruction({ op: 'adapter', out, name: adapterSymbol(entry), args });
541
+ }
542
+ }
543
+ else
544
+ this.instruction({ op: 'extern', out, name: def.node.name, types: def.node.params.map(p => p.type.name), result: def.node.returns.name, args });
545
+ }
546
+ if (def.node.returnOwnership === 'own')
547
+ this.owned.add(out);
548
+ this.checkError();
549
+ return out;
550
+ }
551
+ args = this.transferArguments(expr, args, false);
552
+ const out = this.slot();
553
+ this.instruction({ op: 'call', out, function: this.generator.name(def), args });
554
+ if (def.node.kind === 'function' && def.node.returnOwnership === 'own')
555
+ this.owned.add(out);
556
+ this.checkError();
557
+ return out;
558
+ }
559
+ transferArguments(expr, args, native) {
560
+ const transferred = [...args], plan = this.generator.checked.callPlans.get(expr);
561
+ plan?.ownerships?.forEach((mode, i) => {
562
+ if (mode !== 'own')
563
+ return;
564
+ const temporary = this.slot();
565
+ this.instruction({ op: 'copy', out: temporary, input: args[i] });
566
+ this.instruction({ op: 'clear', slot: args[i] });
567
+ transferred[i] = temporary;
568
+ // Native marshalling can reject the input before ownership crosses the ABI.
569
+ // The move helper clears this slot only after every input is valid.
570
+ if (native)
571
+ this.owned.add(temporary);
572
+ });
573
+ return transferred;
574
+ }
575
+ interceptor(layer, params, next) {
576
+ this.constructionNext = layer.constructorResultFresh === true;
577
+ this.continuation = new InterceptorInvocation(layer, params, [...this.parameters], next, this.receiver);
578
+ const dependencies = this.continuation.dependencies().map(slot => slot ?? this.literal(null));
579
+ const self = this.call(this.generator.name(layer.definition), dependencies);
580
+ this.locals.set('self', self);
581
+ for (const input of this.continuation.inputs()) {
582
+ if (input.reuseOwnedSlot) {
583
+ this.locals.set(input.name, input.slot);
584
+ continue;
585
+ }
586
+ const slot = this.slot();
587
+ this.locals.set(input.name, slot);
588
+ this.instruction({ op: 'copy', out: slot, input: input.slot ?? this.literal(null) });
589
+ }
590
+ }
591
+ nativeBody(def) {
592
+ const call = { kind: 'call', callee: { kind: 'name', name: def.name, span: def.node.span }, args: [], argLabels: [], typeArgs: [], span: def.node.span };
593
+ const result = this.invoke(call, undefined, [...this.parameters], true);
594
+ this.instruction({ op: 'copy', out: 0, input: result });
595
+ if (this.owned.has(result))
596
+ this.instruction({ op: 'clear', slot: result });
597
+ }
598
+ scoped(stmts, composition = false, setup, span) {
599
+ const locals = new Map(this.locals), owned = new Set(this.owned), parent = this.debugScope;
600
+ const first = span ?? stmts[0]?.span ?? this.source, last = stmts.at(-1)?.span;
601
+ this.debugScope = 'scope_' + this.scopes.length;
602
+ this.scopes.push({ name: this.debugScope, parent, span: { ...first, end: last?.end ?? first.end } });
603
+ setup?.();
604
+ for (const stmt of stmts)
605
+ this.statement(stmt);
606
+ if (composition && !this.current.terminator)
607
+ this.instruction({ op: 'scope', action: 'join' });
608
+ if (!this.current.terminator)
609
+ for (const slot of this.owned)
610
+ if (!owned.has(slot))
611
+ this.instruction({ op: 'drop', slot });
612
+ this.locals.clear();
613
+ for (const [name, slot] of locals)
614
+ this.locals.set(name, slot);
615
+ this.debugScope = parent;
616
+ }
617
+ endpoint(def) {
618
+ const fn = def.node, endpoint = fn.endpoint, request = this.slot(), failed = this.block(), finished = this.block();
619
+ this.parameters.push(request);
620
+ this.error = failed;
621
+ this.returning = failed;
622
+ this.instruction({ op: 'scope', action: 'enter' });
623
+ const args = fn.params.map(() => this.slot());
624
+ fn.params.forEach((param, index) => {
625
+ if (!param.injected)
626
+ return;
627
+ const type = schemaType(this.generator.checked.project, param.type, def.file);
628
+ const key = type.name + (type.args.length ? '<' + type.args.map(arg => arg.name).join(',') + '>' : '');
629
+ const value = this.call(this.generator.binding(key), []);
630
+ this.instruction({ op: 'copy', out: args[index], input: value });
631
+ });
632
+ for (const policy of this.generator.checked.httpPolicies.get(fn) ?? []) {
633
+ this.instruction({ op: 'http-policy', policy: this.generator.policy(policy), args: [request, ...[0, 1].map(index => policy.dependencies[index] === undefined ? this.literal(null) : args[policy.dependencies[index]])] });
634
+ this.checkError();
635
+ }
636
+ fn.params.forEach((param, index) => {
637
+ if (param.injected)
638
+ return;
639
+ const schema = param.source.kind === 'request' ? undefined : this.generator.schemas.request(schemaType(this.generator.checked.project, param.type, def.file));
640
+ this.instruction({ op: 'http-bind', out: args[index], request, source: param.source.kind, name: param.source.name ?? param.name, schema });
641
+ this.checkError();
642
+ });
643
+ const result = this.call(this.generator.name(def), args), response = this.runtime('HTTP_RESPONSE_STATUS', [result, this.literal(null, { kind: 'int', text: String(endpoint.status) })]);
644
+ this.instruction({ op: 'copy', out: 0, input: response });
645
+ this.terminate({ op: 'jump', target: finished });
646
+ this.enter(failed);
647
+ this.instruction({ op: 'http-failure', out: 0, errors: endpoint.errors.map(error => ({ type: this.generator.definition(def.file, error.type.name)?.id ?? error.type.name, status: error.status })) });
648
+ this.terminate({ op: 'jump', target: finished });
649
+ this.enter(finished);
650
+ this.error = 'cleanup';
651
+ this.returning = 'cleanup';
652
+ const completed = this.runtime('HTTP_FINISH', [0]);
653
+ this.instruction({ op: 'copy', out: 0, input: completed });
654
+ }
655
+ tryAlways(stmt) {
656
+ const outerError = this.error, outerReturn = this.returning, owned = new Set(this.owned);
657
+ const caught = this.block(), failed = this.block(), returned = this.block(), cleanup = this.block(), finalized = this.block(), done = this.block();
658
+ const depth = this.slot(), locks = this.slot(), pending = this.slot(), cancelled = this.slot(), returning = this.slot(), failure = this.slot();
659
+ this.instruction({ op: 'scope-depth', out: depth });
660
+ this.instruction({ op: 'lock-depth', out: locks });
661
+ this.instruction({ op: 'copy', out: returning, input: this.literal(false) });
662
+ this.instruction({ op: 'copy', out: failure, input: this.literal(false) });
663
+ this.error = caught;
664
+ this.returning = returned;
665
+ this.scoped(stmt.body);
666
+ if (!this.current.terminator)
667
+ this.terminate({ op: 'jump', target: cleanup });
668
+ this.enter(caught);
669
+ this.instruction({ op: 'lock', action: 'restore', depth: locks });
670
+ this.instruction({ op: 'scope', action: 'join', depth });
671
+ for (const slot of this.owned)
672
+ if (!owned.has(slot))
673
+ this.instruction({ op: 'drop', slot });
674
+ this.instruction({ op: 'scope', action: 'restore', depth });
675
+ const handlers = this.block();
676
+ this.terminate({ op: 'cancel', then: failed, otherwise: handlers });
677
+ this.enter(handlers);
678
+ this.error = failed;
679
+ for (const clause of stmt.catches) {
680
+ const handler = this.block(), next = this.block();
681
+ this.terminate({ op: 'error-type', type: this.generator.definition(this.file, clause.type.name)?.id ?? clause.type.name, then: handler, otherwise: next });
682
+ this.enter(handler);
683
+ const error = this.slot();
684
+ this.instruction({ op: 'take-error', out: error });
685
+ this.scoped(clause.body, false, () => this.local(clause.name, error, clause.span, irType(schemaType(this.generator.checked.project, clause.type, this.file))), clause.span);
686
+ if (!this.current.terminator)
687
+ this.terminate({ op: 'jump', target: cleanup });
688
+ this.enter(next);
689
+ }
690
+ this.terminate({ op: 'jump', target: failed });
691
+ this.enter(failed);
692
+ this.instruction({ op: 'copy', out: failure, input: this.literal(true) });
693
+ this.terminate({ op: 'jump', target: cleanup });
694
+ this.enter(returned);
695
+ this.instruction({ op: 'copy', out: returning, input: this.literal(true) });
696
+ this.terminate({ op: 'jump', target: cleanup });
697
+ this.enter(cleanup);
698
+ this.instruction({ op: 'lock', action: 'restore', depth: locks });
699
+ this.instruction({ op: 'scope', action: 'join', depth });
700
+ for (const slot of this.owned)
701
+ if (!owned.has(slot))
702
+ this.instruction({ op: 'drop', slot });
703
+ this.instruction({ op: 'scope', action: 'restore', depth });
704
+ this.instruction({ op: 'error-state', action: 'save', error: pending, cancelled });
705
+ this.error = finalized;
706
+ this.returning = finalized;
707
+ this.scoped(stmt.always);
708
+ if (!this.current.terminator)
709
+ this.terminate({ op: 'jump', target: finalized });
710
+ this.enter(finalized);
711
+ this.instruction({ op: 'error-state', action: 'restore', error: pending, cancelled });
712
+ const returnedCheck = this.block(), errorCheck = this.block(), failedCheck = this.block();
713
+ this.terminate({ op: 'cancel', then: outerReturn, otherwise: returnedCheck });
714
+ this.enter(returnedCheck);
715
+ this.terminate({ op: 'branch', condition: returning, then: outerReturn, otherwise: errorCheck });
716
+ this.enter(errorCheck);
717
+ this.terminate({ op: 'error', failed: outerError, success: failedCheck });
718
+ this.enter(failedCheck);
719
+ this.terminate({ op: 'branch', condition: failure, then: outerError, otherwise: done });
720
+ this.enter(done);
721
+ this.error = outerError;
722
+ this.returning = outerReturn;
723
+ }
724
+ statement(stmt) {
725
+ this.source = stmt.span;
726
+ if (this.current.terminator)
727
+ this.enter(this.block());
728
+ if (this.generator.options.coverage && !this.generator.checked.project.files.get(stmt.span.file)?.builtin) {
729
+ this.generator.coverage.set(stmt.span.file + ':' + stmt.span.line, { file: stmt.span.file, line: stmt.span.line });
730
+ this.instruction({ op: 'cover', file: stmt.span.file, line: stmt.span.line });
731
+ }
732
+ if (stmt.kind === 'serve') {
733
+ const port = this.expression(stmt.port), routes = this.generator.routeTable(this.file, stmt.names);
734
+ this.instruction({ op: 'routes', name: routes, port });
735
+ this.checkError();
736
+ return;
737
+ }
738
+ if (stmt.kind === 'yield') {
739
+ this.runtime('HTTP_YIELD', [this.expression(stmt.value)]);
740
+ return;
741
+ }
742
+ if (stmt.kind === 'expr') {
743
+ const value = this.expression(stmt.expr);
744
+ if (this.owned.has(value))
745
+ this.instruction({ op: 'drop', slot: value });
746
+ return;
747
+ }
748
+ if (stmt.kind === 'assign') {
749
+ const value = this.expression(stmt.value);
750
+ this.source = stmt.span;
751
+ let targetOwns = stmt.ownership === 'own';
752
+ if (stmt.target.kind === 'name') {
753
+ const field = this.field(stmt.target.name);
754
+ if (!this.locals.has(stmt.target.name) && field !== undefined) {
755
+ targetOwns ||= this.owner?.node.kind === 'class' && fieldsOf(this.owner.node)[field].ownership === 'own';
756
+ this.runtime('SET_FIELD', [this.locals.get('self'), value], undefined, field);
757
+ }
758
+ else {
759
+ let out = this.locals.get(stmt.target.name);
760
+ if (out === undefined) {
761
+ const type = stmt.declaredType ? irType(schemaType(this.generator.checked.project, stmt.declaredType, this.file)) : this.values[value].type;
762
+ out = this.slot(type);
763
+ this.local(stmt.target.name, out, stmt.span, type);
764
+ }
765
+ this.instruction({ op: 'copy', out, input: value });
766
+ if (stmt.ownership === 'own')
767
+ this.owned.add(out);
768
+ }
769
+ }
770
+ else if (stmt.target.kind === 'member') {
771
+ const fieldName = stmt.target.name;
772
+ const node = this.generator.checked.expressionTypes.get(stmt.target.object)?.def?.node;
773
+ targetOwns ||= node?.kind === 'class' && fieldsOf(node).some(field => field.name === fieldName && field.ownership === 'own');
774
+ this.runtime('SET_FIELD', [this.expression(stmt.target.object), value], undefined, this.fieldIndex(stmt.target.object, stmt.target.name));
775
+ }
776
+ if (targetOwns && this.owned.has(value))
777
+ this.instruction({ op: 'clear', slot: value });
778
+ return;
779
+ }
780
+ if (stmt.kind === 'return') {
781
+ if (stmt.value) {
782
+ const value = this.expression(stmt.value);
783
+ this.instruction({ op: 'copy', out: 0, input: value });
784
+ if (this.owned.has(value))
785
+ this.instruction({ op: 'clear', slot: value });
786
+ }
787
+ this.terminate({ op: 'jump', target: this.returning });
788
+ return;
789
+ }
790
+ if (stmt.kind === 'throw') {
791
+ this.instruction({ op: 'throw', input: this.expression(stmt.value) });
792
+ this.terminate({ op: 'jump', target: this.error });
793
+ return;
794
+ }
795
+ if (stmt.kind === 'unsafe' || stmt.kind === 'borrow') {
796
+ this.scoped(stmt.body);
797
+ return;
798
+ }
799
+ if (stmt.kind === 'scope') {
800
+ this.instruction({ op: 'scope', action: 'enter' });
801
+ this.scoped(stmt.body, true);
802
+ if (!this.current.terminator) {
803
+ this.instruction({ op: 'scope', action: 'leave' });
804
+ this.checkError();
805
+ }
806
+ return;
807
+ }
808
+ if (stmt.kind === 'lock') {
809
+ const value = this.runtime('SHARED_LOCK', [this.expression(stmt.value)]);
810
+ this.scoped(stmt.body, false, () => this.local(stmt.name, value, stmt.span), stmt.span);
811
+ if (!this.current.terminator) {
812
+ this.instruction({ op: 'lock', action: 'leave' });
813
+ this.checkError();
814
+ }
815
+ return;
816
+ }
817
+ if (stmt.kind === 'if') {
818
+ const condition = this.expression(stmt.test), yes = this.block(), no = this.block(), done = this.block();
819
+ this.terminate({ op: 'branch', condition, then: yes, otherwise: no });
820
+ this.enter(yes);
821
+ this.scoped(stmt.then);
822
+ if (!this.current.terminator)
823
+ this.terminate({ op: 'jump', target: done });
824
+ this.enter(no);
825
+ this.scoped(stmt.otherwise);
826
+ if (!this.current.terminator)
827
+ this.terminate({ op: 'jump', target: done });
828
+ this.enter(done);
829
+ return;
830
+ }
831
+ if (stmt.kind === 'match') {
832
+ const value = this.expression(stmt.value), done = this.block();
833
+ // Match literals are checked constants. Keep the source ordering used by
834
+ // the reference backend, while evaluating the matched value only once.
835
+ const literals = stmt.cases.map(clause => clause.literal ? this.expression(clause.literal) : undefined);
836
+ for (const [index, clause] of stmt.cases.entries()) {
837
+ const body = this.block(), next = this.block();
838
+ if (clause.pattern === 'else')
839
+ this.terminate({ op: 'jump', target: body });
840
+ else if (clause.pattern === 'null' || clause.pattern === 'some')
841
+ this.terminate({ op: 'null', input: value, then: clause.pattern === 'null' ? body : next, otherwise: clause.pattern === 'null' ? next : body });
842
+ else {
843
+ const condition = clause.pattern === 'type' ? this.runtime('IS_TYPE', [value], this.generator.definition(this.file, clause.type.name)?.id ?? clause.type.name) : this.runtime('BINARY', [value, literals[index]], '==');
844
+ this.terminate({ op: 'branch', condition, then: body, otherwise: next });
845
+ }
846
+ this.enter(body);
847
+ this.scoped(clause.body, false, () => { if (clause.name)
848
+ this.local(clause.name, value, clause.span); }, clause.span);
849
+ if (!this.current.terminator)
850
+ this.terminate({ op: 'jump', target: done });
851
+ this.enter(next);
852
+ }
853
+ this.terminate({ op: 'jump', target: done });
854
+ this.enter(done);
855
+ return;
856
+ }
857
+ if (stmt.kind === 'while') {
858
+ const test = this.block(), body = this.block(), done = this.block();
859
+ this.terminate({ op: 'jump', target: test });
860
+ this.enter(test);
861
+ this.instruction({ op: 'checkpoint' });
862
+ this.checkError();
863
+ const condition = this.expression(stmt.test);
864
+ this.terminate({ op: 'branch', condition, then: body, otherwise: done });
865
+ this.enter(body);
866
+ this.scoped(stmt.body);
867
+ if (!this.current.terminator)
868
+ this.terminate({ op: 'jump', target: test });
869
+ this.enter(done);
870
+ return;
871
+ }
872
+ if (stmt.kind === 'freeze') {
873
+ const value = this.expression(stmt.value), out = this.runtime('FREEZE', [value]);
874
+ this.local(stmt.name, out, stmt.span);
875
+ if (this.owned.has(value))
876
+ this.instruction({ op: 'clear', slot: value });
877
+ return;
878
+ }
879
+ if (stmt.kind === 'destructure') {
880
+ const value = this.expression(stmt.value);
881
+ stmt.names.forEach((name, i) => this.local(name, this.runtime('TUPLE_GET', [value, this.literal(null, { kind: 'int', text: String(i) })]), stmt.span, this.values[value].type.args[i] ?? dynamicType));
882
+ return;
883
+ }
884
+ if (stmt.kind === 'for') {
885
+ const iterable = this.expression(stmt.iterable), map = this.generator.checked.expressionTypes.get(stmt.iterable)?.name === 'Map' && stmt.names.length === 2;
886
+ const values = this.runtime(map ? 'MAP_ITER' : 'ITER', [iterable]), index = this.slot(scalarType('int')), one = this.literal(null, { kind: 'int', text: '1' });
887
+ this.instruction({ op: 'copy', out: index, input: this.literal(null, { kind: 'int', text: '0' }) });
888
+ const length = this.runtime('LIST_LENGTH', [values]), test = this.block(), body = this.block(), done = this.block();
889
+ this.terminate({ op: 'jump', target: test });
890
+ this.enter(test);
891
+ this.instruction({ op: 'checkpoint' });
892
+ this.checkError();
893
+ const condition = this.runtime('BINARY', [index, length], '<');
894
+ this.terminate({ op: 'branch', condition, then: body, otherwise: done });
895
+ this.enter(body);
896
+ this.scoped(stmt.body, false, () => {
897
+ // The private snapshot cannot be changed by source code. Its length
898
+ // guards this index; map snapshots contain an even number of cells.
899
+ // Source List.get still retains its checked bounds behavior.
900
+ if (map) {
901
+ stmt.names.forEach((name, i) => { this.local(name, this.runtime('LIST_AT', [values, index], undefined, undefined, false), stmt.span, this.values[iterable].type.args[i] ?? dynamicType); this.instruction({ op: 'copy', out: index, input: this.runtime('BINARY', [index, one], '+') }); });
902
+ }
903
+ else {
904
+ const item = this.runtime('LIST_AT', [values, index], undefined, undefined, false);
905
+ stmt.names.forEach((name, i) => this.local(name, stmt.names.length === 1 ? item : this.runtime('TUPLE_GET', [item, this.literal(null, { kind: 'int', text: String(i) })]), stmt.span, (stmt.names.length === 1 ? this.values[iterable].type.args[0] : this.values[iterable].type.args[0]?.args[i]) ?? dynamicType));
906
+ this.instruction({ op: 'copy', out: index, input: this.runtime('BINARY', [index, one], '+') });
907
+ }
908
+ }, stmt.span);
909
+ if (!this.current.terminator)
910
+ this.terminate({ op: 'jump', target: test });
911
+ this.enter(done);
912
+ return;
913
+ }
914
+ if (stmt.kind === 'try') {
915
+ if (stmt.always) {
916
+ this.tryAlways(stmt);
917
+ return;
918
+ }
919
+ const outer = this.error, failed = this.block(), done = this.block(), owned = new Set(this.owned), depth = this.slot(), locks = this.slot();
920
+ this.instruction({ op: 'scope-depth', out: depth });
921
+ this.instruction({ op: 'lock-depth', out: locks });
922
+ this.error = failed;
923
+ this.scoped(stmt.body);
924
+ if (!this.current.terminator)
925
+ this.terminate({ op: 'jump', target: done });
926
+ this.enter(failed);
927
+ this.error = outer;
928
+ this.instruction({ op: 'lock', action: 'restore', depth: locks });
929
+ this.instruction({ op: 'scope', action: 'join', depth });
930
+ for (const slot of this.owned)
931
+ if (!owned.has(slot))
932
+ this.instruction({ op: 'drop', slot });
933
+ this.instruction({ op: 'scope', action: 'restore', depth });
934
+ stmt.catches.forEach(clause => {
935
+ const handler = this.block(), next = this.block();
936
+ this.terminate({ op: 'error-type', type: this.generator.definition(this.file, clause.type.name)?.id ?? clause.type.name, then: handler, otherwise: next });
937
+ this.enter(handler);
938
+ const error = this.slot();
939
+ this.instruction({ op: 'take-error', out: error });
940
+ this.scoped(clause.body, false, () => this.local(clause.name, error, clause.span, irType(schemaType(this.generator.checked.project, clause.type, this.file))), clause.span);
941
+ if (!this.current.terminator)
942
+ this.terminate({ op: 'jump', target: done });
943
+ this.enter(next);
944
+ });
945
+ this.terminate({ op: 'jump', target: outer });
946
+ this.enter(done);
947
+ return;
948
+ }
949
+ const unreachable = stmt;
950
+ throw new Error('Unexpected August statement ' + JSON.stringify(unreachable));
951
+ }
952
+ finish(name) {
953
+ for (const value of this.values)
954
+ if (isIRScalar(value.type))
955
+ value.storage = 'scalar-value';
956
+ if (!this.current.terminator)
957
+ this.terminate({ op: 'jump', target: 'cleanup' });
958
+ this.enter('cleanup');
959
+ this.terminate({ op: 'return' });
960
+ return { name, sourceName: this.sourceName ?? this.owner?.name ?? (name === 'aug_main_body' ? 'main' : name), span: this.span, slots: this.slots, values: this.values, variables: this.variables, scopes: this.scopes, parameters: this.parameters, receiver: this.receiver, owned: [...this.owned], constructorResults: [...this.constructorResults], blocks: this.blocks };
961
+ }
962
+ }