@hyperscale0/hsx 2.4.0 → 3.0.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 (249) hide show
  1. package/CHANGELOG.md +2 -400
  2. package/README.md +3 -92
  3. package/dist/src/ast.d.ts +99 -310
  4. package/dist/src/ast.d.ts.map +1 -1
  5. package/dist/src/ast.js +16 -69
  6. package/dist/src/ast.js.map +1 -1
  7. package/dist/src/cli.d.ts +6 -19
  8. package/dist/src/cli.d.ts.map +1 -1
  9. package/dist/src/cli.js +76 -315
  10. package/dist/src/cli.js.map +1 -1
  11. package/dist/src/compile.d.ts +23 -73
  12. package/dist/src/compile.d.ts.map +1 -1
  13. package/dist/src/compile.js +1113 -148
  14. package/dist/src/compile.js.map +1 -1
  15. package/dist/src/cost.d.ts +8 -77
  16. package/dist/src/cost.d.ts.map +1 -1
  17. package/dist/src/cost.js +13 -422
  18. package/dist/src/cost.js.map +1 -1
  19. package/dist/src/format.d.ts +8 -7
  20. package/dist/src/format.d.ts.map +1 -1
  21. package/dist/src/format.js +9 -175
  22. package/dist/src/format.js.map +1 -1
  23. package/dist/src/headers.d.ts +35 -0
  24. package/dist/src/headers.d.ts.map +1 -0
  25. package/dist/src/headers.js +108 -0
  26. package/dist/src/headers.js.map +1 -0
  27. package/dist/src/index.d.ts +6 -12
  28. package/dist/src/index.d.ts.map +1 -1
  29. package/dist/src/index.js +4 -9
  30. package/dist/src/index.js.map +1 -1
  31. package/dist/src/lex.d.ts +8 -28
  32. package/dist/src/lex.d.ts.map +1 -1
  33. package/dist/src/lex.js +88 -146
  34. package/dist/src/lex.js.map +1 -1
  35. package/dist/src/parse.d.ts +4 -17
  36. package/dist/src/parse.d.ts.map +1 -1
  37. package/dist/src/parse.js +402 -1040
  38. package/dist/src/parse.js.map +1 -1
  39. package/dist/src/std-bundle.d.ts.map +1 -1
  40. package/dist/src/std-bundle.js +12 -20
  41. package/dist/src/std-bundle.js.map +1 -1
  42. package/dist/src/std-library.d.ts +1 -1
  43. package/dist/src/std-library.d.ts.map +1 -1
  44. package/dist/src/std-library.js +1 -5
  45. package/dist/src/std-library.js.map +1 -1
  46. package/dist/src/tunables.d.ts +7 -0
  47. package/dist/src/tunables.d.ts.map +1 -0
  48. package/dist/src/tunables.js +26 -0
  49. package/dist/src/tunables.js.map +1 -0
  50. package/dist/src/version.d.ts +2 -4
  51. package/dist/src/version.d.ts.map +1 -1
  52. package/dist/src/version.js +2 -4
  53. package/dist/src/version.js.map +1 -1
  54. package/docs/README.md +179 -41
  55. package/docs/headers.md +44 -0
  56. package/examples/cost-table.json +99 -751
  57. package/examples/library.hsx +59 -0
  58. package/package.json +9 -17
  59. package/src/ast.ts +82 -441
  60. package/src/cli.ts +77 -362
  61. package/src/compile.ts +1535 -247
  62. package/src/cost.ts +28 -671
  63. package/src/format.ts +12 -256
  64. package/src/headers.ts +126 -0
  65. package/src/index.ts +7 -39
  66. package/src/lex.ts +99 -195
  67. package/src/parse.ts +403 -1209
  68. package/src/std-bundle.ts +12 -20
  69. package/src/std-library.ts +2 -7
  70. package/src/tunables.ts +31 -0
  71. package/src/version.ts +2 -5
  72. package/std/approvals.hsx +17 -0
  73. package/std/cards.hsx +63 -0
  74. package/std/collections.hsx +31 -0
  75. package/std/escrow.hsx +43 -0
  76. package/std/financing.hsx +372 -0
  77. package/std/insurance.hsx +59 -0
  78. package/std/lending.hsx +115 -0
  79. package/std/marketplace.hsx +24 -0
  80. package/std/money.hsx +195 -0
  81. package/std/savings.hsx +44 -0
  82. package/std/travel.hsx +98 -0
  83. package/std/wallet.hsx +41 -0
  84. package/dist/src/diagnostics.d.ts +0 -13
  85. package/dist/src/diagnostics.d.ts.map +0 -1
  86. package/dist/src/diagnostics.js +0 -587
  87. package/dist/src/diagnostics.js.map +0 -1
  88. package/dist/src/emit.d.ts +0 -51
  89. package/dist/src/emit.d.ts.map +0 -1
  90. package/dist/src/emit.js +0 -192
  91. package/dist/src/emit.js.map +0 -1
  92. package/dist/src/entry-overrides.d.ts +0 -58
  93. package/dist/src/entry-overrides.d.ts.map +0 -1
  94. package/dist/src/entry-overrides.js +0 -284
  95. package/dist/src/entry-overrides.js.map +0 -1
  96. package/dist/src/ir.d.ts +0 -73
  97. package/dist/src/ir.d.ts.map +0 -1
  98. package/dist/src/ir.js +0 -15
  99. package/dist/src/ir.js.map +0 -1
  100. package/dist/src/limits.d.ts +0 -23
  101. package/dist/src/limits.d.ts.map +0 -1
  102. package/dist/src/limits.js +0 -23
  103. package/dist/src/limits.js.map +0 -1
  104. package/dist/src/lsp/server.d.ts +0 -32
  105. package/dist/src/lsp/server.d.ts.map +0 -1
  106. package/dist/src/lsp/server.js +0 -391
  107. package/dist/src/lsp/server.js.map +0 -1
  108. package/dist/src/modules.d.ts +0 -38
  109. package/dist/src/modules.d.ts.map +0 -1
  110. package/dist/src/modules.js +0 -372
  111. package/dist/src/modules.js.map +0 -1
  112. package/dist/src/typecheck.d.ts +0 -8
  113. package/dist/src/typecheck.d.ts.map +0 -1
  114. package/dist/src/typecheck.js +0 -4131
  115. package/dist/src/typecheck.js.map +0 -1
  116. package/docs/guide/01-first-program.md +0 -24
  117. package/docs/guide/02-money.md +0 -25
  118. package/docs/guide/03-instruments.md +0 -93
  119. package/docs/guide/04-lifecycles.md +0 -40
  120. package/docs/guide/05-fees-and-splits.md +0 -45
  121. package/docs/guide/06-schedules.md +0 -26
  122. package/docs/guide/07-composition.md +0 -52
  123. package/docs/guide/08-writing-a-module.md +0 -85
  124. package/docs/guide/09-cost.md +0 -24
  125. package/docs/guide/10-diagnostics.md +0 -27
  126. package/docs/llms-full.txt +0 -3684
  127. package/docs/llms.txt +0 -44
  128. package/docs/piece-plans.md +0 -120
  129. package/docs/playground.md +0 -55
  130. package/docs/reference/cli.md +0 -36
  131. package/docs/reference/diagnostics.md +0 -901
  132. package/docs/reference/grammar.md +0 -38
  133. package/docs/reference/std/advance.md +0 -112
  134. package/docs/reference/std/cancellable_booking.md +0 -159
  135. package/docs/reference/std/captured_payment.md +0 -115
  136. package/docs/reference/std/conditional_disbursement.md +0 -101
  137. package/docs/reference/std/credit_facility.md +0 -108
  138. package/docs/reference/std/held_payment.md +0 -173
  139. package/docs/reference/std/instant_transfer.md +0 -97
  140. package/docs/reference/std/metered.md +0 -89
  141. package/docs/reference/std/pooled_split.md +0 -95
  142. package/docs/reference/std/premium_forward.md +0 -119
  143. package/docs/reference/std/reconciled_payout.md +0 -103
  144. package/docs/reference/std/rotating_pool.md +0 -130
  145. package/docs/reference/std/scheduled.md +0 -136
  146. package/docs/reference/std/security_deposit.md +0 -138
  147. package/docs/reference/std/settlement_batch.md +0 -123
  148. package/docs/reference/std/swap.md +0 -133
  149. package/docs/reference/std/threshold_pool.md +0 -138
  150. package/docs/reference/std/weighted_distribution.md +0 -135
  151. package/docs/reference/types.md +0 -61
  152. package/docs/reference/udl-output.md +0 -13
  153. package/examples/01-first-program/README.md +0 -45
  154. package/examples/01-first-program/tip-jar.hsx +0 -17
  155. package/examples/02-imports-and-modules/README.md +0 -96
  156. package/examples/02-imports-and-modules/photo-booth.hsx +0 -37
  157. package/examples/03-diagnostics/README.md +0 -68
  158. package/examples/03-diagnostics/corner-shop-fixed.hsx +0 -22
  159. package/examples/03-diagnostics/corner-shop.hsx +0 -19
  160. package/examples/04-complete-product/README.md +0 -84
  161. package/examples/04-complete-product/study-hall.hsx +0 -67
  162. package/examples/05-authored-instrument/README.md +0 -5
  163. package/examples/05-authored-instrument/payment.hsx +0 -37
  164. package/examples/05-watch-club/README.md +0 -6
  165. package/examples/05-watch-club/watch-club.hsx +0 -123
  166. package/examples/README.md +0 -48
  167. package/examples/advance/README.md +0 -3
  168. package/examples/advance/advance.hsx +0 -13
  169. package/examples/advance/advance.udl +0 -367
  170. package/examples/cancellable_booking/README.md +0 -3
  171. package/examples/cancellable_booking/cancellable_booking.hsx +0 -14
  172. package/examples/cancellable_booking/cancellable_booking.udl +0 -413
  173. package/examples/captured_payment/README.md +0 -3
  174. package/examples/captured_payment/captured_payment.hsx +0 -17
  175. package/examples/captured_payment/captured_payment.udl +0 -686
  176. package/examples/conditional_disbursement/README.md +0 -3
  177. package/examples/conditional_disbursement/conditional_disbursement.hsx +0 -15
  178. package/examples/conditional_disbursement/conditional_disbursement.udl +0 -418
  179. package/examples/credit_facility/README.md +0 -3
  180. package/examples/credit_facility/credit_facility.hsx +0 -24
  181. package/examples/credit_facility/credit_facility.udl +0 -1396
  182. package/examples/held_payment/README.md +0 -3
  183. package/examples/held_payment/held_payment.hsx +0 -13
  184. package/examples/held_payment/held_payment.udl +0 -569
  185. package/examples/instant_transfer/README.md +0 -3
  186. package/examples/instant_transfer/instant_transfer.hsx +0 -16
  187. package/examples/instant_transfer/instant_transfer.udl +0 -376
  188. package/examples/metered/README.md +0 -3
  189. package/examples/metered/metered.hsx +0 -13
  190. package/examples/metered/metered.udl +0 -253
  191. package/examples/pooled_split/README.md +0 -3
  192. package/examples/pooled_split/pooled_split.hsx +0 -15
  193. package/examples/pooled_split/pooled_split.udl +0 -432
  194. package/examples/premium_forward/README.md +0 -3
  195. package/examples/premium_forward/premium_forward.hsx +0 -19
  196. package/examples/premium_forward/premium_forward.udl +0 -604
  197. package/examples/reconciled_payout/README.md +0 -3
  198. package/examples/reconciled_payout/reconciled_payout.hsx +0 -13
  199. package/examples/reconciled_payout/reconciled_payout.udl +0 -312
  200. package/examples/rotating_pool/README.md +0 -3
  201. package/examples/rotating_pool/rotating_pool.hsx +0 -18
  202. package/examples/rotating_pool/rotating_pool.udl +0 -4370
  203. package/examples/scheduled/README.md +0 -3
  204. package/examples/scheduled/scheduled.hsx +0 -12
  205. package/examples/scheduled/scheduled.udl +0 -355
  206. package/examples/security_deposit/README.md +0 -3
  207. package/examples/security_deposit/security_deposit.hsx +0 -21
  208. package/examples/security_deposit/security_deposit.udl +0 -320
  209. package/examples/settlement_batch/README.md +0 -3
  210. package/examples/settlement_batch/settlement_batch.hsx +0 -19
  211. package/examples/settlement_batch/settlement_batch.udl +0 -757
  212. package/examples/swap/README.md +0 -3
  213. package/examples/swap/swap.hsx +0 -19
  214. package/examples/swap/swap.udl +0 -892
  215. package/examples/threshold_pool/README.md +0 -3
  216. package/examples/threshold_pool/threshold_pool.hsx +0 -16
  217. package/examples/threshold_pool/threshold_pool.udl +0 -680
  218. package/examples/weighted_distribution/README.md +0 -3
  219. package/examples/weighted_distribution/weighted_distribution.hsx +0 -20
  220. package/examples/weighted_distribution/weighted_distribution.udl +0 -348
  221. package/skills/hsx/SKILL.md +0 -449
  222. package/src/diagnostics.ts +0 -620
  223. package/src/emit.ts +0 -282
  224. package/src/entry-overrides.ts +0 -428
  225. package/src/ir.ts +0 -113
  226. package/src/limits.ts +0 -22
  227. package/src/lsp/server.ts +0 -460
  228. package/src/modules.ts +0 -452
  229. package/src/typecheck.ts +0 -5381
  230. package/std/SEMANTICS.md +0 -44
  231. package/std/money_flows/advance.hsx +0 -235
  232. package/std/money_flows/cancellable_booking.hsx +0 -402
  233. package/std/money_flows/captured_payment.hsx +0 -220
  234. package/std/money_flows/conditional_disbursement.hsx +0 -226
  235. package/std/money_flows/credit_facility.hsx +0 -214
  236. package/std/money_flows/held_payment.hsx +0 -812
  237. package/std/money_flows/index.hsx +0 -4
  238. package/std/money_flows/instant_transfer.hsx +0 -231
  239. package/std/money_flows/metered.hsx +0 -104
  240. package/std/money_flows/pooled_split.hsx +0 -109
  241. package/std/money_flows/premium_forward.hsx +0 -307
  242. package/std/money_flows/reconciled_payout.hsx +0 -119
  243. package/std/money_flows/rotating_pool.hsx +0 -305
  244. package/std/money_flows/scheduled.hsx +0 -599
  245. package/std/money_flows/security_deposit.hsx +0 -248
  246. package/std/money_flows/settlement_batch.hsx +0 -173
  247. package/std/money_flows/swap.hsx +0 -1192
  248. package/std/money_flows/threshold_pool.hsx +0 -307
  249. package/std/money_flows/weighted_distribution.hsx +0 -237
@@ -0,0 +1,59 @@
1
+ program library "Standard library"
2
+ use money
3
+ use marketplace
4
+ use escrow
5
+ use wallet
6
+ use financing
7
+ use lending
8
+ use insurance
9
+ use approvals
10
+ use collections
11
+ use travel
12
+ use cards
13
+ use savings
14
+ party buyer: person
15
+ party seller: business
16
+ party officer: staff role credit_underwriter
17
+ party carrier: business role insurance_carrier
18
+ party merchant: business
19
+
20
+ transfer = money.transfer { payer: buyer, payee: seller, amount: 100 SAR }
21
+ hold = money.hold { payer: buyer, payee: seller, amount: 100 SAR }
22
+ split = money.split { payer: buyer, amount: 100 SAR, shares { seller: 70%, merchant: 30% } }
23
+ schedule = money.schedule { payer: buyer, payee: seller, amount: 100 SAR, count: 3 }
24
+ pool = money.pool { payer: buyer, payee: seller, target: 100 SAR, closes: 2030-01-01 }
25
+ swap = money.swap { first: buyer, second: seller, first_amount: 100 SAR, second_amount: 50 SAR, expires: 2030-01-01 }
26
+ deposit = money.deposit { payer: buyer, payee: seller, amount: 100 SAR, expires: 2030-01-01, approval: officer }
27
+ payout = money.payout { payer: seller, payee: buyer, amount: 100 SAR, reconcile_within: 3d }
28
+ metered = money.metered { payer: buyer, payee: seller, unit_price: 10 SAR, units: 2 }
29
+ batch = money.batch { payer: buyer, payee: seller, closes: 2030-01-01, approval: officer }
30
+ listing = marketplace.listing { seller: seller }
31
+ order = marketplace.order { listing: listing, buyer: buyer }
32
+ sale = escrow.hold { payer: buyer, payee: seller, for: order, fee { seller: 1% cap 750 SAR, tax: 15% }, dispute { refund_after: return_verified } }
33
+ purse = wallet.balance { holder: buyer, spend_limit: 1000 SAR }
34
+ spend = wallet.spend { wallet: purse, payee: seller }
35
+ limits = financing.limits { per_borrower: 10000 SAR, portfolio: 100000 SAR, borrower: buyer }
36
+ plan = financing.installments { months: 3, profit: 3%, funds: sale, approval: officer }
37
+ plan_schedule = financing.installments { months: 6, profit: 3%, funds: sale, approval: officer, disburse_to: borrower, profit_earned: by_schedule, apply: principal_profit, payoff_rebate: 50% }
38
+ plan_upfront = financing.installments { months: 3, profit: 3%, funds: sale, approval: officer, disburse_to: funds, profit_earned: at_disbursement, apply: pro_rata, payoff_rebate: 0% }
39
+ late = financing.late_charge { on: [plan, plan_schedule, plan_upfront], approval: officer, fines_to: seller, costs_to: seller }
40
+ line = financing.credit_line { borrower: buyer, lender: seller, limit: 1000 SAR, expires: 2030-01-01 }
41
+ advance = financing.advance { line: line, amount: 100 SAR }
42
+ round = lending.round { borrower: buyer, capital: seller, plan: plan }
43
+ ticket = lending.commitment { round: round, wallet: purse }
44
+ distribution = lending.distribution { round: round, receipt: plan.settlement, residual_to: seller }
45
+ cover = insurance.cover { holder: buyer, insurer: carrier, covers: sale, commission: 10% }
46
+ claim = insurance.claim { cover: cover, approved_by: carrier }
47
+ decision = approvals.decision { for: transfer, approved_by: officer, action: "pay" }
48
+ case = collections.case { on: plan, agency: seller, fee: 20% }
49
+ contact = collections.contact { case: case, agency: seller }
50
+ package = travel.package { price: 1000 SAR, supplier_cost: 700 SAR, departure: 2030-01-01 }
51
+ booking = travel.booking { package: package, buyer: buyer, supplier: seller, cover: travel_cover }
52
+ cardholder = cards.cardholder { holder: buyer }
53
+ card = cards.card { holder: cardholder, spend_limit: 100 SAR }
54
+ authorization = cards.authorization { card: card, merchant: merchant, approval: officer }
55
+ transaction = cards.transaction { authorization: authorization }
56
+ dispute = cards.dispute { transaction: transaction, approved_by: officer }
57
+ circle = savings.circle { contribution: 100 SAR, members: 3, starts: 2030-01-01 }
58
+ membership = savings.membership { circle: circle, member: buyer }
59
+ travel_cover = insurance.cover { holder: buyer, insurer: carrier, commission: 10%, covers: booking }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperscale0/hsx",
3
- "version": "2.4.0",
3
+ "version": "3.0.0",
4
4
  "description": "The strictly typed HSX language: compile total financial programs into canonical UDL.",
5
5
  "keywords": [
6
6
  "hsx",
@@ -40,10 +40,6 @@
40
40
  "types": "./dist/src/cost.d.ts",
41
41
  "default": "./dist/src/cost.js"
42
42
  },
43
- "./lsp": {
44
- "types": "./dist/src/lsp/server.d.ts",
45
- "default": "./dist/src/lsp/server.js"
46
- },
47
43
  "./package.json": "./package.json",
48
44
  "./std/*": "./std/*"
49
45
  },
@@ -59,7 +55,6 @@
59
55
  "dist",
60
56
  "docs",
61
57
  "examples",
62
- "skills",
63
58
  "std",
64
59
  "src"
65
60
  ],
@@ -70,22 +65,19 @@
70
65
  "access": "public"
71
66
  },
72
67
  "scripts": {
73
- "build": "bun run generate && tsc -p tsconfig.build.json",
74
- "check": "bun run generate && bun test && bun run playground:check && tsc -p tsconfig.json && bun run build && bun scripts/check-bin.ts",
75
- "docs:build": "bun scripts/docs/build.ts && bun scripts/docs/check.ts",
76
- "examples:build": "bun scripts/examples/build.ts",
77
- "playground:build": "bun scripts/build-playground.ts",
78
- "playground:check": "bun scripts/build-playground.ts --check",
68
+ "build": "tsc -p tsconfig.build.json",
69
+ "typecheck": "tsc -p tsconfig.json",
70
+ "test": "bun test test",
71
+ "docs:build": "bun scripts/docs.ts",
79
72
  "postpack": "bun scripts/pack-exports.ts restore",
80
73
  "prepack": "bun run build && bun scripts/pack-exports.ts apply",
81
74
  "std:bundle": "bun scripts/bundle-std.ts",
82
- "test": "bun run generate && bun test",
83
- "typecheck": "bun run generate && tsc -p tsconfig.json",
75
+ "generate": "bun run std:bundle && bun run docs:build",
84
76
  "prepare": "bun run std:bundle",
85
- "generate": "bun run std:bundle && bun run docs:build && bun run playground:build"
77
+ "check": "bun run generate && bun run typecheck && bun run build && tsc -p playground/tsconfig.json && bun scripts/build-playground.ts && bun test test"
86
78
  },
87
79
  "dependencies": {
88
- "@hyperscale0/udl": "2.6.0"
80
+ "@hyperscale0/udl": "3.0.0"
89
81
  },
90
82
  "devDependencies": {
91
83
  "bun-types": "1.4.2",
@@ -96,5 +88,5 @@
96
88
  "Amir Ayub",
97
89
  "Sara AlBakaawi"
98
90
  ],
99
- "gitHead": "cd1e1ff5c188de94ff8bb0761cb3258746196bf2"
91
+ "gitHead": "b84ee93a5016401a5f8287745a2fb23ba5647e43"
100
92
  }
package/src/ast.ts CHANGED
@@ -1,454 +1,95 @@
1
- /**
2
- * The HSX abstract syntax tree.
3
- *
4
- * Every node carries a byte-offset span into the original source. Spans are
5
- * the compiler's source-mapping currency: diagnostics at every later stage
6
- * (typecheck, lowering, verdicts) point at source coordinates, never at
7
- * lowered IR paths. Offsets convert to line/column via `lineColAt`.
8
- */
9
-
10
1
  export interface Span {
11
- /** Inclusive start byte offset into the source text. */
12
- readonly start: number;
13
- /** Exclusive end byte offset into the source text. */
14
- readonly end: number;
2
+ start: number;
3
+ end: number;
15
4
  }
16
-
17
- export interface LineCol {
18
- /** 1-indexed line. */
19
- readonly line: number;
20
- /** 1-indexed column, counted in UTF-16 code units. */
21
- readonly column: number;
22
- }
23
-
24
- /** Convert a byte offset to a 1-indexed line/column position. */
25
- export function lineColAt(source: string, offset: number): LineCol {
26
- let line = 1;
27
- let lineStart = 0;
28
- const clamped = Math.max(0, Math.min(offset, source.length));
29
- for (let index = 0; index < clamped; index += 1) {
30
- if (source.charCodeAt(index) === 10) {
31
- line += 1;
32
- lineStart = index + 1;
33
- }
34
- }
35
- return { column: clamped - lineStart + 1, line };
5
+ export interface Diagnostic {
6
+ code: string;
7
+ message: string;
8
+ fix: string;
9
+ span: Span;
36
10
  }
37
-
38
- const utf8Encoder = new TextEncoder();
39
-
40
- /**
41
- * Convert a UTF-8 byte offset to a UTF-16 code-unit offset over a string.
42
- * Walks Unicode code points, counting UTF-8 bytes and UTF-16 code units.
43
- * Clamps to [0, source.length].
44
- */
45
- export function byteOffsetToCodeUnit(
46
- source: string,
47
- byteOffset: number,
48
- ): number {
49
- if (byteOffset <= 0) return 0;
50
- let currentByte = 0;
51
- let codeUnit = 0;
52
-
53
- for (const char of source) {
54
- const charBytes = utf8Encoder.encode(char).length;
55
- if (currentByte + charBytes > byteOffset) {
56
- return codeUnit;
11
+ export type Expr =
12
+ | {
13
+ kind:
14
+ | "name"
15
+ | "text"
16
+ | "number"
17
+ | "money"
18
+ | "percent"
19
+ | "duration"
20
+ | "date";
21
+ value: string;
22
+ span: Span;
57
23
  }
58
- currentByte += charBytes;
59
- codeUnit += char.length;
60
- if (currentByte === byteOffset) {
61
- return codeUnit;
24
+ | { kind: "list"; items: Expr[]; span: Span }
25
+ | { kind: "block"; entries: Entry[]; span: Span }
26
+ | { kind: "call"; name: string; args: Expr[]; span: Span }
27
+ | {
28
+ kind: "type";
29
+ name: string;
30
+ target?: string;
31
+ owner?: string;
32
+ optional: boolean;
33
+ many?: boolean;
34
+ span: Span;
62
35
  }
63
- }
64
-
65
- return source.length;
66
- }
67
-
68
- /**
69
- * One source scanned once, so many offsets resolve without rescanning it.
70
- * `lineColAt` walks from offset zero every time, which turns a run of d
71
- * diagnostics over an n-byte source into O(n*d) work. A caller holding this
72
- * pays O(n) once and O(log n) per offset.
73
- */
74
- export interface LineIndex {
75
- /** Source length, so `lineColIn` clamps exactly as `lineColAt` does. */
76
- readonly length: number;
77
- /** Offset of the first character of each line, ascending. Line 1 starts at 0. */
78
- readonly starts: readonly number[];
79
- }
80
-
81
- /** Scan a source once for the offset every line starts at. */
82
- export function lineIndex(source: string): LineIndex {
83
- const starts = [0];
84
- for (let index = 0; index < source.length; index += 1) {
85
- if (source.charCodeAt(index) === 10) starts.push(index + 1);
86
- }
87
- return { length: source.length, starts };
88
- }
89
-
90
- /**
91
- * Resolve one offset against a prebuilt index. Returns exactly what
92
- * `lineColAt` returns for the same source and offset.
93
- */
94
- export function lineColIn(index: LineIndex, offset: number): LineCol {
95
- const clamped = Math.max(0, Math.min(offset, index.length));
96
- let low = 0;
97
- let high = index.starts.length - 1;
98
- while (low < high) {
99
- const middle = Math.floor((low + high + 1) / 2);
100
- if ((index.starts[middle] as number) <= clamped) low = middle;
101
- else high = middle - 1;
102
- }
103
- return { column: clamped - (index.starts[low] as number) + 1, line: low + 1 };
104
- }
105
-
106
- // --- Expressions -----------------------------------------------------------
107
-
108
- export interface IdentExpr {
109
- readonly kind: "ident";
110
- readonly name: string;
111
- /** A literal quoted block key keeps its exact spelling during JSON lowering. */
112
- readonly quoted?: boolean;
113
- readonly span: Span;
114
- }
115
-
116
- export interface StringExpr {
117
- readonly kind: "string";
118
- readonly span: Span;
119
- readonly value: string;
120
- }
121
-
122
- export interface NumberExpr {
123
- readonly kind: "number";
124
- /** The literal exactly as written, e.g. "99.5". Interpretation is typed later. */
125
- readonly raw: string;
126
- readonly span: Span;
127
- }
128
-
129
- export interface BooleanExpr {
130
- readonly kind: "boolean";
131
- readonly span: Span;
132
- readonly value: boolean;
133
- }
134
-
135
- /** A currency-indexed literal. The checker converts it to integer minor units. */
136
- export interface MoneyExpr {
137
- readonly currency: IdentExpr;
138
- readonly kind: "money";
139
- readonly raw: string;
140
- readonly span: Span;
141
- }
142
-
143
- /** A dotted name used for modules, UDL operations, and field paths. */
144
- export interface PathExpr {
145
- readonly kind: "path";
146
- readonly parts: readonly IdentExpr[];
147
- readonly span: Span;
148
- }
149
-
150
- /** A nominal type application such as `money<SAR>` or `ref<invoice>`. */
151
- export interface TypeApplyExpr {
152
- readonly args: readonly Expr[];
153
- readonly callee: IdentExpr;
154
- readonly kind: "type_apply";
155
- readonly span: Span;
156
- }
157
-
158
- /** A general instrument or constant application, with optional type arguments. */
159
- export interface ApplyExpr {
160
- readonly args: readonly Expr[];
161
- readonly callee: PathExpr;
162
- readonly kind: "apply";
163
- readonly span: Span;
164
- readonly typeArgs: readonly Expr[];
165
- }
166
-
167
- export interface PercentExpr {
168
- /** Exact basis points: 99.5% is 9950. Percents never round. */
169
- readonly bps: number;
170
- readonly kind: "percent";
171
- readonly raw: string;
172
- readonly span: Span;
173
- }
174
-
175
- /** A type or constructor application: `money(SAR)`, `id(vehicle)`. */
176
- export interface CallExpr {
177
- readonly args: readonly Expr[];
178
- readonly callee: IdentExpr;
179
- readonly kind: "call";
180
- readonly span: Span;
181
- }
182
-
183
- /**
184
- * An exit amount chosen by a decision port and bounded by stored money:
185
- * `decided { field: damageAmount, bound: depositAmount, remainder: return }`.
186
- */
187
- export interface DecidedAmountExpr {
188
- readonly body: BlockExpr;
189
- readonly kind: "decided_amount";
190
- readonly span: Span;
191
- }
192
-
193
- /**
194
- * A reference to a decision port, optionally bounded (`port dispute within
195
- * P14D`) or carrying the date that decides when the port has not
196
- * (`port approve_release | at(releaseDueAt)`).
197
- */
198
- export interface PortRefExpr {
199
- /** `| at(<field>)`, the stored date field that resolves an undecided hold. */
200
- readonly deadline?: IdentExpr;
201
- readonly kind: "port_ref";
202
- readonly name: IdentExpr;
203
- readonly span: Span;
204
- readonly within?: IdentExpr;
205
- }
206
-
207
- /**
208
- * `retention.release`, one settlement naming another settlement's declared
209
- * referenceable exit. The checker resolves it wholly before lowering.
210
- */
211
- export interface SettlementRefExpr {
212
- readonly kind: "settlement_ref";
213
- /** The exit named on the owner, e.g. `release`. */
214
- readonly member: IdentExpr;
215
- /** The settlement being referenced. */
216
- readonly owner: IdentExpr;
217
- readonly span: Span;
218
- }
219
-
220
- export interface ListExpr {
221
- readonly items: readonly Expr[];
222
- readonly kind: "list";
223
- readonly span: Span;
224
- }
225
-
226
- /** A brace block of entries: `{ buyer: 1%, seller: 2% }`. */
227
- export interface BlockExpr {
228
- readonly entries: readonly Entry[];
229
- readonly kind: "block";
230
- readonly span: Span;
231
- }
232
-
233
- /**
234
- * A named typed binding inside an expression position:
235
- * `amount: price: money(SAR)` binds the field name `price` to type
236
- * `money(SAR)`: the entry key is `amount`, the value is this binding.
237
- */
238
- export interface BindingExpr {
239
- readonly kind: "binding";
240
- readonly name: IdentExpr;
241
- readonly span: Span;
242
- readonly type: Expr;
243
- }
244
-
245
- export type Expr =
246
- | ApplyExpr
247
- | BindingExpr
248
- | BlockExpr
249
- | BooleanExpr
250
- | CallExpr
251
- | DecidedAmountExpr
252
- | IdentExpr
253
- | ListExpr
254
- | MoneyExpr
255
- | NumberExpr
256
- | PathExpr
257
- | PercentExpr
258
- | PortRefExpr
259
- | SettlementRefExpr
260
- | StringExpr
261
- | TypeApplyExpr;
262
-
263
- // --- Entries ---------------------------------------------------------------
264
-
265
- /**
266
- * One keyed entry inside a declaration body. Three surface shapes normalize
267
- * here: `payer: buyer` (key + value), `fees { ... }` (key + block value),
268
- * and `on_cancel(funded) { ... }` (key + qualifiers + block value).
269
- */
36
+ | { kind: "default"; type: Expr; value: Expr; span: Span }
37
+ | { kind: "capped"; rate: Expr; cap: Expr; span: Span };
270
38
  export interface Entry {
271
- /** Port dependencies retained through compile-time selection and substitution. */
272
- readonly conditionPorts?: readonly string[];
273
- /** `for item in bound { ... }`, expanded before binding or UDL lowering. */
274
- readonly iteration?: {
275
- readonly binding: IdentExpr;
276
- readonly bound: Expr;
277
- };
278
- readonly key: IdentExpr;
279
- readonly qualifiers: readonly IdentExpr[];
280
- readonly span: Span;
281
- readonly value: Expr;
282
- }
283
-
284
- // --- Declarations ----------------------------------------------------------
285
-
286
- /** `program used_car_escrow "Used-car escrow"` names the company program. */
287
- export interface ProgramDecl {
288
- readonly kind: "program";
289
- readonly name: IdentExpr;
290
- readonly span: Span;
291
- readonly title?: StringExpr;
292
- }
293
-
294
- /** `use held_settlement` selects one published catalog instrument. */
295
- export interface UseDecl {
296
- readonly instrument: IdentExpr;
297
- readonly kind: "use";
298
- readonly span: Span;
299
- }
300
-
301
- /** `expose held_settlement.release as releaseFunds` names a public action. */
302
- export interface ExposeDecl {
303
- readonly action: IdentExpr;
304
- readonly instrument: IdentExpr;
305
- readonly kind: "expose";
306
- readonly publicName: IdentExpr;
307
- readonly span: Span;
308
- }
309
-
310
- /** `import { held_payment } from "std/money_flows"`. */
311
- export interface ImportDecl {
312
- readonly from: StringExpr;
313
- readonly kind: "import";
314
- readonly names: readonly IdentExpr[];
315
- readonly span: Span;
316
- }
317
-
318
- /** `party buyer: person` with an optional attribute block. */
319
- export interface PartyDecl {
320
- readonly attrs?: BlockExpr;
321
- readonly kind: "party";
322
- readonly name: IdentExpr;
323
- readonly partyKind: IdentExpr;
324
- readonly span: Span;
325
- }
326
-
327
- /** `asset vehicle: good { title_transfer: off_platform }`. */
328
- export interface AssetDecl {
329
- readonly assetKind: IdentExpr;
330
- readonly attrs?: BlockExpr;
331
- readonly kind: "asset";
332
- readonly name: IdentExpr;
333
- readonly span: Span;
334
- }
335
-
336
- /** A full UDL subject-kind declaration. `asset` remains shorthand for this form. */
337
- export interface SubjectDecl {
338
- readonly body: BlockExpr;
339
- readonly kind: "subject";
340
- readonly name: IdentExpr;
341
- readonly span: Span;
342
- }
343
-
344
- /** `port confirm_handover { allowed: [buyer], ... }`. */
345
- export interface PortDecl {
346
- readonly body: BlockExpr;
347
- readonly kind: "port";
348
- readonly name: IdentExpr;
349
- readonly span: Span;
39
+ key: string;
40
+ value: Expr;
41
+ span: Span;
350
42
  }
351
-
352
- /** `module std.money_flows` gives a file its importable module name. */
353
- export interface ModuleDecl {
354
- readonly kind: "module";
355
- readonly name: PathExpr;
356
- readonly span: Span;
357
- }
358
-
359
- export interface TypeParameter {
360
- readonly name: IdentExpr;
361
- readonly span: Span;
362
- }
363
-
364
- export interface Parameter {
365
- readonly name: IdentExpr;
366
- readonly span: Span;
367
- readonly type: Expr;
368
- }
369
-
370
- /** The single general instrument definition form. */
371
43
  export interface InstrumentDecl {
372
- readonly body: BlockExpr;
373
- /** Module-local declarations carried only while this template is bound. */
374
- readonly declarationScope?: readonly ApplicationScopeDecl[];
375
- readonly exported: boolean;
376
- /** True when the source declared a parameter list, including an empty `()`. */
377
- readonly hasParameterList: boolean;
378
- readonly kind: "instrument";
379
- readonly name: IdentExpr;
380
- readonly parameters: readonly Parameter[];
381
- readonly span: Span;
382
- readonly typeParameters: readonly TypeParameter[];
383
- }
384
-
385
- /** Instantiation of an exported parameterized instrument. */
386
- export interface InstrumentApplyDecl {
387
- readonly application: ApplyExpr;
388
- /** Module-local declarations carried only while this application is bound. */
389
- readonly declarationScope?: readonly ApplicationScopeDecl[];
390
- readonly exported: boolean;
391
- readonly kind: "instrument_apply";
392
- readonly metadata?: BlockExpr;
393
- readonly name: IdentExpr;
394
- readonly span: Span;
395
- }
396
-
397
- export interface TypeDecl {
398
- readonly exported: boolean;
399
- readonly kind: "type";
400
- readonly name: IdentExpr;
401
- readonly span: Span;
402
- readonly value: Expr;
403
- }
404
-
405
- export interface ConstDecl {
406
- readonly exported: boolean;
407
- readonly kind: "const";
408
- readonly name: IdentExpr;
409
- readonly span: Span;
410
- readonly type?: Expr;
411
- readonly value: Expr;
44
+ kind: "instrument";
45
+ name: string;
46
+ parameters: Entry[];
47
+ body: Extract<Expr, { kind: "block" }>;
48
+ span: Span;
49
+ }
50
+ export interface ObjectDecl {
51
+ kind: "object";
52
+ name: string;
53
+ object: string;
54
+ body: Extract<Expr, { kind: "block" }>;
55
+ span: Span;
412
56
  }
413
-
414
- export type ApplicationScopeDecl =
415
- | ConstDecl
416
- | InstrumentDecl
417
- | PartyDecl
418
- | PortDecl
419
- | TypeDecl;
420
-
421
57
  export type Decl =
422
- | AssetDecl
423
- | ConstDecl
424
- | ExposeDecl
425
- | ImportDecl
426
- | InstrumentApplyDecl
427
58
  | InstrumentDecl
428
- | ModuleDecl
429
- | PartyDecl
430
- | PortDecl
431
- | ProgramDecl
432
- | SubjectDecl
433
- | TypeDecl
434
- | UseDecl;
435
-
436
- // --- Program ---------------------------------------------------------------
437
-
59
+ | ObjectDecl
60
+ | {
61
+ kind: "party";
62
+ name: string;
63
+ partyKind: string;
64
+ role?: string;
65
+ span: Span;
66
+ }
67
+ | { kind: "use"; name: string; span: Span }
68
+ | { kind: "expose"; target: string; name: string; span: Span }
69
+ | { kind: "hide"; target: string; span: Span };
438
70
  export interface Program {
439
- readonly decls: readonly Decl[];
440
- readonly span: Span;
441
- }
442
-
443
- // --- Diagnostics -----------------------------------------------------------
444
-
445
- /**
446
- * A parse-stage problem, worded for the program's author. Parsing is total:
447
- * it never throws, it returns the best-effort tree plus these.
448
- */
449
- export interface Diagnostic {
450
- readonly code?: string;
451
- readonly fix?: string;
452
- readonly message: string;
453
- readonly span: Span;
71
+ name: string;
72
+ title: string;
73
+ currency: string;
74
+ header: boolean;
75
+ decls: Decl[];
76
+ span: Span;
77
+ }
78
+ export const lineColAt = (source: string, offset: number) => {
79
+ const before = source.slice(0, offset);
80
+ return {
81
+ line: before.split("\n").length,
82
+ column: offset - before.lastIndexOf("\n"),
83
+ };
84
+ };
85
+ export function byteOffsetToCodeUnit(source: string, offset: number): number {
86
+ let bytes = 0;
87
+ let units = 0;
88
+ for (const c of source) {
89
+ bytes += new TextEncoder().encode(c).length;
90
+ if (bytes > offset) break;
91
+ units += c.length;
92
+ }
93
+ return units;
454
94
  }
95
+ export type BlockExpr = Extract<Expr, { kind: "block" }>;