@jhlagado/azm 0.2.7 → 0.2.9

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 (253) hide show
  1. package/README.md +239 -76
  2. package/dist/src/api-artifacts.d.ts +20 -0
  3. package/dist/src/api-artifacts.js +165 -0
  4. package/dist/src/api-compile.d.ts +8 -2
  5. package/dist/src/api-compile.js +55 -227
  6. package/dist/src/api-register-contracts.d.ts +9 -0
  7. package/dist/src/api-register-contracts.js +77 -0
  8. package/dist/src/api-tooling.d.ts +2 -2
  9. package/dist/src/api-tooling.js +1 -1
  10. package/dist/src/assembly/address-planning.d.ts +1 -2
  11. package/dist/src/assembly/address-planning.js +119 -218
  12. package/dist/src/assembly/address-symbols.d.ts +12 -0
  13. package/dist/src/assembly/address-symbols.js +118 -0
  14. package/dist/src/assembly/assemble-program.js +5 -0
  15. package/dist/src/assembly/fixup-emission.js +30 -48
  16. package/dist/src/assembly/import-visibility.d.ts +3 -0
  17. package/dist/src/assembly/import-visibility.js +204 -0
  18. package/dist/src/assembly/program-emission.js +163 -164
  19. package/dist/src/cli/artifact-files.d.ts +15 -0
  20. package/dist/src/cli/artifact-files.js +86 -0
  21. package/dist/src/cli/parse-args.d.ts +6 -5
  22. package/dist/src/cli/parse-args.js +162 -136
  23. package/dist/src/cli/run.js +4 -1
  24. package/dist/src/cli/usage.d.ts +1 -0
  25. package/dist/src/cli/usage.js +33 -0
  26. package/dist/src/cli/write-artifacts.js +18 -91
  27. package/dist/src/core/compile.js +51 -274
  28. package/dist/src/core/conditional-assembly.d.ts +6 -0
  29. package/dist/src/core/conditional-assembly.js +181 -0
  30. package/dist/src/expansion/op-constant-expression.d.ts +3 -0
  31. package/dist/src/expansion/op-constant-expression.js +52 -0
  32. package/dist/src/expansion/op-expand-selected.d.ts +5 -0
  33. package/dist/src/expansion/op-expand-selected.js +143 -0
  34. package/dist/src/expansion/op-expansion.d.ts +5 -53
  35. package/dist/src/expansion/op-expansion.js +85 -815
  36. package/dist/src/expansion/op-instruction-instantiation.d.ts +3 -0
  37. package/dist/src/expansion/op-instruction-instantiation.js +194 -0
  38. package/dist/src/expansion/op-local-labels.d.ts +8 -0
  39. package/dist/src/expansion/op-local-labels.js +166 -0
  40. package/dist/src/expansion/op-operand-splitting.d.ts +1 -0
  41. package/dist/src/expansion/op-operand-splitting.js +44 -0
  42. package/dist/src/expansion/op-operands.d.ts +53 -0
  43. package/dist/src/expansion/op-operands.js +66 -0
  44. package/dist/src/expansion/op-selection.d.ts +18 -0
  45. package/dist/src/expansion/op-selection.js +172 -0
  46. package/dist/src/index.d.ts +2 -1
  47. package/dist/src/index.js +1 -1
  48. package/dist/src/model/diagnostic.d.ts +4 -0
  49. package/dist/src/model/diagnostic.js +4 -0
  50. package/dist/src/node/source-host.js +40 -13
  51. package/dist/src/outputs/asm80-expression-evaluation.d.ts +10 -0
  52. package/dist/src/outputs/asm80-expression-evaluation.js +75 -0
  53. package/dist/src/outputs/asm80-expressions.d.ts +5 -0
  54. package/dist/src/outputs/asm80-expressions.js +47 -0
  55. package/dist/src/outputs/asm80-instruction-operands.d.ts +16 -0
  56. package/dist/src/outputs/asm80-instruction-operands.js +38 -0
  57. package/dist/src/outputs/asm80-instructions.d.ts +5 -0
  58. package/dist/src/outputs/asm80-instructions.js +272 -0
  59. package/dist/src/outputs/asm80-ld-operands.d.ts +10 -0
  60. package/dist/src/outputs/asm80-ld-operands.js +157 -0
  61. package/dist/src/outputs/asm80-strings.d.ts +4 -0
  62. package/dist/src/outputs/asm80-strings.js +14 -0
  63. package/dist/src/outputs/d8-files.d.ts +10 -0
  64. package/dist/src/outputs/d8-files.js +103 -0
  65. package/dist/src/outputs/d8-helpers.d.ts +21 -0
  66. package/dist/src/outputs/d8-helpers.js +136 -0
  67. package/dist/src/outputs/hex.js +26 -18
  68. package/dist/src/outputs/types.d.ts +16 -10
  69. package/dist/src/outputs/write-asm80.js +72 -597
  70. package/dist/src/outputs/write-d8.js +6 -216
  71. package/dist/src/register-contracts/accept-output.d.ts +2 -0
  72. package/dist/src/register-contracts/analyze-helpers.d.ts +29 -0
  73. package/dist/src/register-contracts/analyze-helpers.js +162 -0
  74. package/dist/src/{register-care → register-contracts}/analyze.d.ts +6 -6
  75. package/dist/src/register-contracts/analyze.js +73 -0
  76. package/dist/src/register-contracts/annotate.d.ts +11 -0
  77. package/dist/src/{register-care → register-contracts}/annotate.js +3 -3
  78. package/dist/src/register-contracts/annotations.d.ts +8 -0
  79. package/dist/src/{register-care → register-contracts}/annotations.js +3 -3
  80. package/dist/src/register-contracts/boundaryHints.d.ts +3 -0
  81. package/dist/src/register-contracts/boundaryHints.js +24 -0
  82. package/dist/src/register-contracts/carriers.d.ts +2 -0
  83. package/dist/src/register-contracts/constants.d.ts +4 -0
  84. package/dist/src/register-contracts/constants.js +51 -0
  85. package/dist/src/register-contracts/controlFlow.d.ts +5 -0
  86. package/dist/src/register-contracts/controlFlow.js +55 -0
  87. package/dist/src/register-contracts/fix.d.ts +11 -0
  88. package/dist/src/{register-care → register-contracts}/fix.js +47 -30
  89. package/dist/src/register-contracts/instruction-head.d.ts +2 -0
  90. package/dist/src/register-contracts/instruction-head.js +3 -0
  91. package/dist/src/register-contracts/instruction-operands.d.ts +3 -0
  92. package/dist/src/register-contracts/instruction-operands.js +101 -0
  93. package/dist/src/register-contracts/instruction-predicates.d.ts +6 -0
  94. package/dist/src/register-contracts/instruction-predicates.js +44 -0
  95. package/dist/src/register-contracts/interfaceContracts.d.ts +2 -0
  96. package/dist/src/register-contracts/interfaceContracts.js +68 -0
  97. package/dist/src/register-contracts/liveness.d.ts +3 -0
  98. package/dist/src/{register-care → register-contracts}/liveness.js +111 -79
  99. package/dist/src/register-contracts/operand-register-name.d.ts +2 -0
  100. package/dist/src/register-contracts/operand-register-name.js +13 -0
  101. package/dist/src/{register-care → register-contracts}/profiles.d.ts +5 -5
  102. package/dist/src/{register-care → register-contracts}/profiles.js +2 -2
  103. package/dist/src/register-contracts/programModel-boundaries.d.ts +6 -0
  104. package/dist/src/register-contracts/programModel-boundaries.js +64 -0
  105. package/dist/src/register-contracts/programModel-routines.d.ts +7 -0
  106. package/dist/src/register-contracts/programModel-routines.js +144 -0
  107. package/dist/src/register-contracts/programModel.d.ts +3 -0
  108. package/dist/src/register-contracts/programModel.js +14 -0
  109. package/dist/src/register-contracts/report.d.ts +5 -0
  110. package/dist/src/{register-care → register-contracts}/report.js +34 -17
  111. package/dist/src/register-contracts/routine-summaries.d.ts +6 -0
  112. package/dist/src/{register-care → register-contracts}/routine-summaries.js +11 -1
  113. package/dist/src/register-contracts/smartCommentBlocks.d.ts +5 -0
  114. package/dist/src/register-contracts/smartCommentBlocks.js +30 -0
  115. package/dist/src/register-contracts/smartCommentParsing.d.ts +3 -0
  116. package/dist/src/register-contracts/smartCommentParsing.js +80 -0
  117. package/dist/src/register-contracts/smartComments.d.ts +5 -0
  118. package/dist/src/register-contracts/smartComments.js +92 -0
  119. package/dist/src/register-contracts/summaries.d.ts +12 -0
  120. package/dist/src/{register-care → register-contracts}/summaries.js +7 -7
  121. package/dist/src/register-contracts/summary-boundary.d.ts +2 -0
  122. package/dist/src/register-contracts/summary-boundary.js +40 -0
  123. package/dist/src/register-contracts/summary-contract.d.ts +2 -0
  124. package/dist/src/register-contracts/summary-contract.js +45 -0
  125. package/dist/src/register-contracts/summary-result.d.ts +7 -0
  126. package/dist/src/register-contracts/summary-result.js +122 -0
  127. package/dist/src/register-contracts/summary-state.d.ts +23 -0
  128. package/dist/src/register-contracts/summary-state.js +88 -0
  129. package/dist/src/register-contracts/summary-token-transfer.d.ts +3 -0
  130. package/dist/src/register-contracts/summary-token-transfer.js +67 -0
  131. package/dist/src/register-contracts/summary.d.ts +3 -0
  132. package/dist/src/register-contracts/summary.js +266 -0
  133. package/dist/src/register-contracts/tooling.d.ts +57 -0
  134. package/dist/src/{register-care → register-contracts}/tooling.js +8 -6
  135. package/dist/src/register-contracts/types.d.ts +188 -0
  136. package/dist/src/semantics/binary-operators.d.ts +2 -0
  137. package/dist/src/semantics/binary-operators.js +15 -0
  138. package/dist/src/semantics/byte-functions.d.ts +2 -0
  139. package/dist/src/semantics/byte-functions.js +7 -0
  140. package/dist/src/semantics/constant-operator-types.d.ts +10 -0
  141. package/dist/src/semantics/constant-operator-types.js +1 -0
  142. package/dist/src/semantics/constant-operators.d.ts +3 -0
  143. package/dist/src/semantics/constant-operators.js +3 -0
  144. package/dist/src/semantics/diagnostics.d.ts +3 -0
  145. package/dist/src/semantics/diagnostics.js +10 -0
  146. package/dist/src/semantics/expression-evaluation.d.ts +11 -19
  147. package/dist/src/semantics/expression-evaluation.js +22 -334
  148. package/dist/src/semantics/layout-evaluation.d.ts +23 -0
  149. package/dist/src/semantics/layout-evaluation.js +202 -0
  150. package/dist/src/semantics/layout-format.d.ts +5 -0
  151. package/dist/src/semantics/layout-format.js +31 -0
  152. package/dist/src/semantics/layout-path.d.ts +24 -0
  153. package/dist/src/semantics/layout-path.js +58 -0
  154. package/dist/src/semantics/unary-operators.d.ts +2 -0
  155. package/dist/src/semantics/unary-operators.js +8 -0
  156. package/dist/src/source/line-comment-scanner.d.ts +1 -0
  157. package/dist/src/source/line-comment-scanner.js +51 -0
  158. package/dist/src/source/logical-lines.d.ts +3 -0
  159. package/dist/src/source/source-span.d.ts +2 -0
  160. package/dist/src/source/strip-line-comment.js +8 -44
  161. package/dist/src/syntax/directive-aliases.js +36 -22
  162. package/dist/src/syntax/expression-tokenizer.d.ts +30 -0
  163. package/dist/src/syntax/expression-tokenizer.js +310 -0
  164. package/dist/src/syntax/parse-directive-statement.d.ts +9 -0
  165. package/dist/src/syntax/parse-directive-statement.js +309 -0
  166. package/dist/src/syntax/parse-expression.d.ts +2 -2
  167. package/dist/src/syntax/parse-expression.js +7 -568
  168. package/dist/src/syntax/parse-layout-declarations.d.ts +9 -0
  169. package/dist/src/syntax/parse-layout-declarations.js +189 -0
  170. package/dist/src/syntax/parse-layout-expression.d.ts +5 -0
  171. package/dist/src/syntax/parse-layout-expression.js +175 -0
  172. package/dist/src/syntax/parse-line.js +21 -273
  173. package/dist/src/syntax/parse-token-expression.d.ts +3 -0
  174. package/dist/src/syntax/parse-token-expression.js +133 -0
  175. package/dist/src/tooling/api.js +1 -1
  176. package/dist/src/tooling/case-style.js +47 -30
  177. package/dist/src/z80/effect-groups.d.ts +38 -0
  178. package/dist/src/z80/effect-groups.js +265 -0
  179. package/dist/src/z80/effect-units.d.ts +18 -0
  180. package/dist/src/z80/effect-units.js +165 -0
  181. package/dist/src/z80/effects.d.ts +1 -1
  182. package/dist/src/z80/effects.js +94 -557
  183. package/dist/src/z80/encode-core.d.ts +2 -0
  184. package/dist/src/z80/encode-core.js +42 -0
  185. package/dist/src/z80/encode-ld-helpers.d.ts +25 -0
  186. package/dist/src/z80/encode-ld-helpers.js +172 -0
  187. package/dist/src/z80/encode-ld.d.ts +2 -0
  188. package/dist/src/z80/encode-ld.js +285 -0
  189. package/dist/src/z80/encode.js +190 -542
  190. package/dist/src/z80/ld-support.d.ts +3 -0
  191. package/dist/src/z80/ld-support.js +146 -0
  192. package/dist/src/z80/operand-split-state.d.ts +8 -0
  193. package/dist/src/z80/operand-split-state.js +46 -0
  194. package/dist/src/z80/operand-split.d.ts +1 -0
  195. package/dist/src/z80/operand-split.js +13 -0
  196. package/dist/src/z80/parse-basic.d.ts +4 -0
  197. package/dist/src/z80/parse-basic.js +39 -0
  198. package/dist/src/z80/parse-branch.d.ts +4 -0
  199. package/dist/src/z80/parse-branch.js +218 -0
  200. package/dist/src/z80/parse-conditions.d.ts +6 -0
  201. package/dist/src/z80/parse-conditions.js +10 -0
  202. package/dist/src/z80/parse-exchange.d.ts +2 -0
  203. package/dist/src/z80/parse-exchange.js +30 -0
  204. package/dist/src/z80/parse-instruction.js +224 -1010
  205. package/dist/src/z80/parse-io-control.d.ts +5 -0
  206. package/dist/src/z80/parse-io-control.js +108 -0
  207. package/dist/src/z80/parse-ld.d.ts +2 -0
  208. package/dist/src/z80/parse-ld.js +83 -0
  209. package/dist/src/z80/parse-operands.d.ts +41 -0
  210. package/dist/src/z80/parse-operands.js +259 -0
  211. package/docs/codebase/01-orientation-and-repository-layout.md +192 -0
  212. package/docs/codebase/02-source-loading-and-parsing.md +263 -0
  213. package/docs/codebase/03-assembly-and-z80-emission.md +251 -0
  214. package/docs/codebase/04-ops-and-register-contracts.md +237 -0
  215. package/docs/codebase/05-interfaces-and-output-artifacts.md +253 -0
  216. package/docs/codebase/06-verification-and-maintenance.md +202 -0
  217. package/docs/codebase/appendices/a-directory-file-reference.md +253 -0
  218. package/docs/codebase/appendices/b-compile-flow-reference.md +103 -0
  219. package/docs/codebase/appendices/c-public-surface-reference.md +106 -0
  220. package/docs/codebase/appendices/index.md +16 -0
  221. package/docs/codebase/index.md +46 -0
  222. package/package.json +2 -3
  223. package/dist/src/register-care/accept-output.d.ts +0 -2
  224. package/dist/src/register-care/analyze.js +0 -166
  225. package/dist/src/register-care/annotate.d.ts +0 -11
  226. package/dist/src/register-care/annotations.d.ts +0 -8
  227. package/dist/src/register-care/boundaryHints.d.ts +0 -3
  228. package/dist/src/register-care/boundaryHints.js +0 -80
  229. package/dist/src/register-care/carriers.d.ts +0 -2
  230. package/dist/src/register-care/controlFlow.d.ts +0 -5
  231. package/dist/src/register-care/controlFlow.js +0 -38
  232. package/dist/src/register-care/fix.d.ts +0 -11
  233. package/dist/src/register-care/instruction-shape.d.ts +0 -11
  234. package/dist/src/register-care/instruction-shape.js +0 -129
  235. package/dist/src/register-care/liveness.d.ts +0 -3
  236. package/dist/src/register-care/programModel.d.ts +0 -3
  237. package/dist/src/register-care/programModel.js +0 -266
  238. package/dist/src/register-care/report.d.ts +0 -5
  239. package/dist/src/register-care/routine-summaries.d.ts +0 -6
  240. package/dist/src/register-care/smartComments.d.ts +0 -5
  241. package/dist/src/register-care/smartComments.js +0 -243
  242. package/dist/src/register-care/summaries.d.ts +0 -12
  243. package/dist/src/register-care/summary.d.ts +0 -3
  244. package/dist/src/register-care/summary.js +0 -474
  245. package/dist/src/register-care/tooling.d.ts +0 -43
  246. package/dist/src/register-care/types.d.ts +0 -172
  247. package/docs/reference/cli.md +0 -151
  248. package/docs/reference/tooling-api.md +0 -316
  249. /package/dist/src/{register-care → register-contracts}/accept-output.js +0 -0
  250. /package/dist/src/{register-care → register-contracts}/carriers.js +0 -0
  251. /package/dist/src/{register-care → register-contracts}/sourceText.d.ts +0 -0
  252. /package/dist/src/{register-care → register-contracts}/sourceText.js +0 -0
  253. /package/dist/src/{register-care → register-contracts}/types.js +0 -0
@@ -1,6 +1,29 @@
1
1
  import { diagnostic, evaluateExpression, lookupEquateRecord, validateLayouts, } from '../semantics/expression-evaluation.js';
2
2
  import { instructionSize } from './fixup-emission.js';
3
3
  import { advanceCodePlacement, advancePlacement, applyOrg, createPlacementState, placementAddress, placementForOrg, } from './placement.js';
4
+ export { resolveSymbols } from './address-symbols.js';
5
+ import { defineEnumMembers, defineEquate, defineLabel, defineLayout, defineTypeAlias, } from './address-symbols.js';
6
+ const ADDRESS_ITEM_HANDLERS = {
7
+ org: (context, item, items, itemIndex) => applyAddressOrg(context, items, itemIndex, item),
8
+ type: (context, item) => defineAddressLayout(context, item),
9
+ 'type-alias': (context, item) => defineAddressTypeAlias(context, item),
10
+ equ: (context, item) => defineAddressEquate(context, item),
11
+ enum: (context, item) => defineAddressEnum(context, item),
12
+ comment: () => undefined,
13
+ label: (context, item) => defineAddressLabel(context, item),
14
+ db: (context, item) => advancePlacement(context.placement, dbSize(item, context.lookupEquates)),
15
+ dw: (context, item) => advancePlacement(context.placement, item.values.length * 2),
16
+ ds: (context, item) => advanceStorage(context, item),
17
+ align: (context, item) => advanceAlignment(context, item),
18
+ end: () => true,
19
+ binfrom: () => undefined,
20
+ binto: () => undefined,
21
+ 'string-data': (context, item) => {
22
+ const stringItem = item;
23
+ advancePlacement(context.placement, stringDirectiveBytes(stringItem.directive, stringItem.value).length);
24
+ },
25
+ instruction: (context, item) => advanceInstruction(context, item),
26
+ };
4
27
  export function buildAddressState(items, diagnostics) {
5
28
  let state = buildAddressStateOnce(items, [], undefined, false);
6
29
  let previousSignature = '';
@@ -15,115 +38,110 @@ export function buildAddressState(items, diagnostics) {
15
38
  return buildAddressStateOnce(items, diagnostics, state, true);
16
39
  }
17
40
  function buildAddressStateOnce(items, diagnostics, previous, reportUnknown) {
18
- const labels = {};
19
- const equates = new Map();
20
- const layouts = new Map();
21
- const enumNames = new Set();
22
- const enumNamesLower = new Set();
23
- let origin = 0;
24
- let originSet = false;
25
- const placement = createPlacementState();
41
+ const context = createAddressBuildContext(previous, diagnostics, reportUnknown);
26
42
  let ended = false;
27
- const lookupLabels = previous?.labels ?? labels;
28
- const lookupEquates = previous?.equates ?? equates;
29
- const lookupLayouts = previous?.layouts ?? layouts;
30
43
  for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
31
44
  const item = items[itemIndex];
32
- if (ended && item.kind !== 'binfrom' && item.kind !== 'binto') {
45
+ if (shouldSkipAfterEnd(ended, item)) {
33
46
  continue;
34
47
  }
35
- switch (item.kind) {
36
- case 'org': {
37
- placement.activePlacement = placementForOrg(items, itemIndex);
38
- const value = evaluateExpression(item.expression, lookupLabels, lookupEquates, item.span, diagnostics, {
39
- currentLocation: placementAddress(placement),
40
- layouts: lookupLayouts,
41
- reportUnknown,
42
- });
43
- if (value !== undefined) {
44
- if (!originSet) {
45
- origin = value;
46
- originSet = true;
47
- }
48
- applyOrg(placement, value);
49
- }
50
- break;
51
- }
52
- case 'type':
53
- defineLayout(layouts, labels, equates, enumNamesLower, item.name, item.layoutKind, item.fields, item.span, diagnostics);
54
- break;
55
- case 'type-alias':
56
- defineTypeAlias(layouts, labels, equates, enumNamesLower, item.name, item.typeExpr, item.span, diagnostics);
57
- break;
58
- case 'equ':
59
- defineEquate(equates, labels, layouts, enumNames, enumNamesLower, item.name, item.expression, item.span, placementAddress(placement), diagnostics, item.stringValue);
60
- break;
61
- case 'enum':
62
- defineEnumMembers(equates, labels, layouts, enumNames, enumNamesLower, item.name, item.members, item.span, diagnostics);
63
- break;
64
- case 'comment':
65
- break;
66
- case 'label':
67
- defineLabel(labels, equates, layouts, enumNamesLower, item.name, placementAddress(placement), item.span, diagnostics);
68
- break;
69
- case 'db':
70
- advancePlacement(placement, item.values.reduce((size, value) => size + dataValueSize(value, lookupEquates), 0));
71
- break;
72
- case 'dw':
73
- advancePlacement(placement, item.values.length * 2);
74
- break;
75
- case 'ds': {
76
- const size = evaluateExpression(item.size, lookupLabels, lookupEquates, item.span, diagnostics, {
77
- currentLocation: placementAddress(placement),
78
- layouts: lookupLayouts,
79
- reportUnknown,
80
- });
81
- if (size !== undefined) {
82
- advancePlacement(placement, size);
83
- }
84
- break;
85
- }
86
- case 'align': {
87
- const alignment = evaluateExpression(item.alignment, lookupLabels, lookupEquates, item.span, diagnostics, {
88
- currentLocation: placementAddress(placement),
89
- layouts: lookupLayouts,
90
- reportUnknown,
91
- });
92
- if (alignment !== undefined) {
93
- if (alignment <= 0) {
94
- if (reportUnknown) {
95
- diagnostics.push(diagnostic(item.span, `.align value must be positive: ${alignment}.`));
96
- }
97
- }
98
- else {
99
- advancePlacement(placement, alignmentPadding(placementAddress(placement), alignment));
100
- }
101
- }
102
- break;
103
- }
104
- case 'end':
105
- ended = true;
106
- break;
107
- case 'binfrom':
108
- case 'binto':
109
- break;
110
- case 'string-data':
111
- advancePlacement(placement, stringDirectiveBytes(item.directive, item.value).length);
112
- break;
113
- case 'instruction': {
114
- const instructionBytes = instructionSize(item.instruction);
115
- advanceCodePlacement(placement, instructionBytes);
116
- if (placement.activePlacement === 'data') {
117
- advancePlacement(placement, instructionBytes);
118
- }
119
- break;
120
- }
48
+ ended = ADDRESS_ITEM_HANDLERS[item.kind](context, item, items, itemIndex) === true || ended;
49
+ }
50
+ if (context.reportUnknown) {
51
+ validateLayouts(context.layouts, diagnostics);
52
+ }
53
+ return {
54
+ labels: context.labels,
55
+ equates: context.equates,
56
+ layouts: context.layouts,
57
+ origin: context.origin,
58
+ };
59
+ }
60
+ function shouldSkipAfterEnd(ended, item) {
61
+ return ended && item.kind !== 'binfrom' && item.kind !== 'binto';
62
+ }
63
+ function createAddressBuildContext(previous, diagnostics, reportUnknown) {
64
+ const labels = {};
65
+ const equates = new Map();
66
+ const layouts = new Map();
67
+ return {
68
+ labels,
69
+ equates,
70
+ layouts,
71
+ enumNames: new Set(),
72
+ enumNamesLower: new Set(),
73
+ diagnostics,
74
+ lookupLabels: previous?.labels ?? labels,
75
+ lookupEquates: previous?.equates ?? equates,
76
+ lookupLayouts: previous?.layouts ?? layouts,
77
+ reportUnknown,
78
+ placement: createPlacementState(),
79
+ origin: 0,
80
+ originSet: false,
81
+ };
82
+ }
83
+ function applyAddressOrg(context, items, itemIndex, item) {
84
+ context.placement.activePlacement = placementForOrg(items, itemIndex);
85
+ const value = evaluateAddressExpression(context, item.expression, item.span);
86
+ if (value === undefined) {
87
+ return;
88
+ }
89
+ if (!context.originSet) {
90
+ context.origin = value;
91
+ context.originSet = true;
92
+ }
93
+ applyOrg(context.placement, value);
94
+ }
95
+ function defineAddressLayout(context, item) {
96
+ defineLayout(context.layouts, context.labels, context.equates, context.enumNamesLower, item.name, item.layoutKind, item.fields, item.span, context.diagnostics);
97
+ }
98
+ function defineAddressTypeAlias(context, item) {
99
+ defineTypeAlias(context.layouts, context.labels, context.equates, context.enumNamesLower, item.name, item.typeExpr, item.span, context.diagnostics);
100
+ }
101
+ function defineAddressEquate(context, item) {
102
+ defineEquate(context.equates, context.labels, context.layouts, context.enumNames, context.enumNamesLower, item.name, item.expression, item.span, placementAddress(context.placement), context.diagnostics, item.stringValue);
103
+ }
104
+ function defineAddressEnum(context, item) {
105
+ defineEnumMembers(context.equates, context.labels, context.layouts, context.enumNames, context.enumNamesLower, item.name, item.members, item.span, context.diagnostics);
106
+ }
107
+ function defineAddressLabel(context, item) {
108
+ defineLabel(context.labels, context.equates, context.layouts, context.enumNamesLower, item.name, placementAddress(context.placement), item.span, context.diagnostics);
109
+ }
110
+ function advanceStorage(context, item) {
111
+ const size = evaluateAddressExpression(context, item.size, item.span);
112
+ if (size !== undefined) {
113
+ advancePlacement(context.placement, size);
114
+ }
115
+ }
116
+ function advanceAlignment(context, item) {
117
+ const alignment = evaluateAddressExpression(context, item.alignment, item.span);
118
+ if (alignment === undefined) {
119
+ return;
120
+ }
121
+ if (alignment <= 0) {
122
+ if (context.reportUnknown) {
123
+ context.diagnostics.push(diagnostic(item.span, `.align value must be positive: ${alignment}.`));
121
124
  }
125
+ return;
122
126
  }
123
- if (reportUnknown) {
124
- validateLayouts(layouts, diagnostics);
127
+ advancePlacement(context.placement, alignmentPadding(placementAddress(context.placement), alignment));
128
+ }
129
+ function advanceInstruction(context, item) {
130
+ const instructionBytes = instructionSize(item.instruction);
131
+ advanceCodePlacement(context.placement, instructionBytes);
132
+ if (context.placement.activePlacement === 'data') {
133
+ advancePlacement(context.placement, instructionBytes);
125
134
  }
126
- return { labels, equates, layouts, origin };
135
+ }
136
+ function evaluateAddressExpression(context, expression, span) {
137
+ return evaluateExpression(expression, context.lookupLabels, context.lookupEquates, span, context.diagnostics, {
138
+ currentLocation: placementAddress(context.placement),
139
+ layouts: context.lookupLayouts,
140
+ reportUnknown: context.reportUnknown,
141
+ });
142
+ }
143
+ function dbSize(item, lookupEquates) {
144
+ return item.values.reduce((size, value) => size + dataValueSize(value, lookupEquates), 0);
127
145
  }
128
146
  export function stringDirectiveBytes(directive, value) {
129
147
  const bytes = [...value].map((char) => char.codePointAt(0) ?? 0);
@@ -167,120 +185,3 @@ function addressStateSignature(state) {
167
185
  origin: state.origin,
168
186
  });
169
187
  }
170
- function defineLayout(layouts, labels, equates, enumNamesLower, name, layoutKind, fields, span, diagnostics) {
171
- const lowerName = name.toLowerCase();
172
- if (hasCaseInsensitiveMapKey(layouts, lowerName) ||
173
- hasCaseInsensitiveKey(labels, lowerName) ||
174
- hasCaseInsensitiveMapKey(equates, lowerName) ||
175
- enumNamesLower.has(lowerName)) {
176
- diagnostics.push(diagnostic(span, `duplicate type name: ${name}`));
177
- return;
178
- }
179
- const fieldNames = new Set();
180
- for (const field of fields) {
181
- const fieldLower = field.name.toLowerCase();
182
- if (fieldNames.has(fieldLower)) {
183
- diagnostics.push(diagnostic(span, `duplicate type field name: ${field.name}`));
184
- continue;
185
- }
186
- fieldNames.add(fieldLower);
187
- }
188
- layouts.set(name, { kind: layoutKind, fields, span });
189
- }
190
- function defineTypeAlias(layouts, labels, equates, enumNamesLower, name, typeExpr, span, diagnostics) {
191
- const lowerName = name.toLowerCase();
192
- if (hasCaseInsensitiveMapKey(layouts, lowerName) ||
193
- hasCaseInsensitiveKey(labels, lowerName) ||
194
- hasCaseInsensitiveMapKey(equates, lowerName) ||
195
- enumNamesLower.has(lowerName)) {
196
- diagnostics.push(diagnostic(span, `duplicate type name: ${name}`));
197
- return;
198
- }
199
- layouts.set(name, { kind: 'alias', typeExpr, span });
200
- }
201
- function defineLabel(labels, equates, layouts, enumNamesLower, name, address, span, diagnostics) {
202
- if (labels[name] !== undefined ||
203
- equates.has(name) ||
204
- hasCaseInsensitiveMapKey(layouts, name.toLowerCase()) ||
205
- enumNamesLower.has(name.toLowerCase())) {
206
- diagnostics.push(diagnostic(span, `duplicate symbol: ${name}`));
207
- return;
208
- }
209
- labels[name] = address;
210
- }
211
- function defineEquate(equates, labels, layouts, enumNames, enumNamesLower, name, expression, span, currentLocation, diagnostics, stringValue) {
212
- if (labels[name] !== undefined ||
213
- equates.has(name) ||
214
- hasCaseInsensitiveMapKey(layouts, name.toLowerCase()) ||
215
- enumNames.has(name) ||
216
- enumNamesLower.has(name.toLowerCase())) {
217
- diagnostics.push(diagnostic(span, `duplicate symbol: ${name}`));
218
- return;
219
- }
220
- equates.set(name, {
221
- expression,
222
- span,
223
- currentLocation,
224
- ...(stringValue !== undefined ? { stringValue } : {}),
225
- });
226
- }
227
- function defineEnumMembers(equates, labels, layouts, enumNames, enumNamesLower, enumName, members, span, diagnostics) {
228
- const enumNameLower = enumName.toLowerCase();
229
- if (hasCaseInsensitiveKey(labels, enumNameLower) ||
230
- hasCaseInsensitiveMapKey(equates, enumNameLower) ||
231
- hasCaseInsensitiveMapKey(layouts, enumNameLower) ||
232
- enumNamesLower.has(enumNameLower)) {
233
- diagnostics.push(diagnostic(span, `duplicate enum name: ${enumName}`));
234
- return;
235
- }
236
- enumNames.add(enumName);
237
- enumNamesLower.add(enumNameLower);
238
- const memberNames = new Set();
239
- for (let index = 0; index < members.length; index += 1) {
240
- const member = members[index] ?? '';
241
- const memberLower = member.toLowerCase();
242
- if (memberNames.has(memberLower)) {
243
- diagnostics.push(diagnostic(span, `duplicate enum member name: ${member}`));
244
- continue;
245
- }
246
- memberNames.add(memberLower);
247
- const qualifiedName = `${enumName}.${member}`;
248
- if (hasCaseInsensitiveKey(labels, qualifiedName.toLowerCase()) ||
249
- hasCaseInsensitiveMapKey(equates, qualifiedName.toLowerCase())) {
250
- diagnostics.push(diagnostic(span, `duplicate symbol: ${qualifiedName}`));
251
- continue;
252
- }
253
- equates.set(qualifiedName, {
254
- expression: { kind: 'number', value: index },
255
- span,
256
- currentLocation: 0,
257
- enumMember: true,
258
- });
259
- }
260
- }
261
- function hasCaseInsensitiveKey(record, lowerName) {
262
- return Object.keys(record).some((key) => key.toLowerCase() === lowerName);
263
- }
264
- function hasCaseInsensitiveMapKey(map, lowerName) {
265
- for (const key of map.keys()) {
266
- if (key.toLowerCase() === lowerName) {
267
- return true;
268
- }
269
- }
270
- return false;
271
- }
272
- export function resolveSymbols(labels, equates, layouts, diagnostics) {
273
- const symbols = { ...labels };
274
- for (const [name, record] of equates) {
275
- const value = evaluateExpression(record.expression, labels, equates, record.span, diagnostics, {
276
- currentLocation: record.currentLocation,
277
- visiting: new Set([name]),
278
- layouts,
279
- reportUnknown: false,
280
- });
281
- if (value !== undefined) {
282
- symbols[name] = value;
283
- }
284
- }
285
- return symbols;
286
- }
@@ -0,0 +1,12 @@
1
+ import type { Diagnostic } from '../model/diagnostic.js';
2
+ import type { Expression, TypeExpr } from '../model/expression.js';
3
+ import type { LayoutField } from '../model/source-item.js';
4
+ import type { SymbolTable } from '../model/symbol.js';
5
+ import type { SourceSpan } from '../source/source-span.js';
6
+ import { type EquateRecord, type LayoutRecord } from '../semantics/expression-evaluation.js';
7
+ export declare function defineLayout(layouts: Map<string, LayoutRecord>, labels: Readonly<Record<string, number>>, equates: ReadonlyMap<string, EquateRecord>, enumNamesLower: ReadonlySet<string>, name: string, layoutKind: 'record' | 'union', fields: readonly LayoutField[], span: SourceSpan, diagnostics: Diagnostic[]): void;
8
+ export declare function defineTypeAlias(layouts: Map<string, LayoutRecord>, labels: Readonly<Record<string, number>>, equates: ReadonlyMap<string, EquateRecord>, enumNamesLower: ReadonlySet<string>, name: string, typeExpr: TypeExpr, span: SourceSpan, diagnostics: Diagnostic[]): void;
9
+ export declare function defineLabel(labels: Record<string, number>, equates: ReadonlyMap<string, EquateRecord>, layouts: ReadonlyMap<string, LayoutRecord>, enumNamesLower: ReadonlySet<string>, name: string, address: number, span: SourceSpan, diagnostics: Diagnostic[]): void;
10
+ export declare function defineEquate(equates: Map<string, EquateRecord>, labels: Readonly<Record<string, number>>, layouts: ReadonlyMap<string, LayoutRecord>, enumNames: ReadonlySet<string>, enumNamesLower: ReadonlySet<string>, name: string, expression: Expression, span: SourceSpan, currentLocation: number, diagnostics: Diagnostic[], stringValue?: string): void;
11
+ export declare function defineEnumMembers(equates: Map<string, EquateRecord>, labels: Readonly<Record<string, number>>, layouts: ReadonlyMap<string, LayoutRecord>, enumNames: Set<string>, enumNamesLower: Set<string>, enumName: string, members: readonly string[], span: SourceSpan, diagnostics: Diagnostic[]): void;
12
+ export declare function resolveSymbols(labels: Readonly<Record<string, number>>, equates: ReadonlyMap<string, EquateRecord>, layouts: ReadonlyMap<string, LayoutRecord>, diagnostics: Diagnostic[]): SymbolTable;
@@ -0,0 +1,118 @@
1
+ import { diagnostic, evaluateExpression, } from '../semantics/expression-evaluation.js';
2
+ export function defineLayout(layouts, labels, equates, enumNamesLower, name, layoutKind, fields, span, diagnostics) {
3
+ const lowerName = name.toLowerCase();
4
+ if (hasCaseInsensitiveMapKey(layouts, lowerName) ||
5
+ hasCaseInsensitiveKey(labels, lowerName) ||
6
+ hasCaseInsensitiveMapKey(equates, lowerName) ||
7
+ enumNamesLower.has(lowerName)) {
8
+ diagnostics.push(diagnostic(span, `duplicate type name: ${name}`));
9
+ return;
10
+ }
11
+ const fieldNames = new Set();
12
+ for (const field of fields) {
13
+ const fieldLower = field.name.toLowerCase();
14
+ if (fieldNames.has(fieldLower)) {
15
+ diagnostics.push(diagnostic(span, `duplicate type field name: ${field.name}`));
16
+ continue;
17
+ }
18
+ fieldNames.add(fieldLower);
19
+ }
20
+ layouts.set(name, { kind: layoutKind, fields, span });
21
+ }
22
+ export function defineTypeAlias(layouts, labels, equates, enumNamesLower, name, typeExpr, span, diagnostics) {
23
+ const lowerName = name.toLowerCase();
24
+ if (hasCaseInsensitiveMapKey(layouts, lowerName) ||
25
+ hasCaseInsensitiveKey(labels, lowerName) ||
26
+ hasCaseInsensitiveMapKey(equates, lowerName) ||
27
+ enumNamesLower.has(lowerName)) {
28
+ diagnostics.push(diagnostic(span, `duplicate type name: ${name}`));
29
+ return;
30
+ }
31
+ layouts.set(name, { kind: 'alias', typeExpr, span });
32
+ }
33
+ export function defineLabel(labels, equates, layouts, enumNamesLower, name, address, span, diagnostics) {
34
+ if (labels[name] !== undefined ||
35
+ equates.has(name) ||
36
+ hasCaseInsensitiveMapKey(layouts, name.toLowerCase()) ||
37
+ enumNamesLower.has(name.toLowerCase())) {
38
+ diagnostics.push(diagnostic(span, `duplicate symbol: ${name}`));
39
+ return;
40
+ }
41
+ labels[name] = address;
42
+ }
43
+ export function defineEquate(equates, labels, layouts, enumNames, enumNamesLower, name, expression, span, currentLocation, diagnostics, stringValue) {
44
+ if (labels[name] !== undefined ||
45
+ equates.has(name) ||
46
+ hasCaseInsensitiveMapKey(layouts, name.toLowerCase()) ||
47
+ enumNames.has(name) ||
48
+ enumNamesLower.has(name.toLowerCase())) {
49
+ diagnostics.push(diagnostic(span, `duplicate symbol: ${name}`));
50
+ return;
51
+ }
52
+ equates.set(name, {
53
+ expression,
54
+ span,
55
+ currentLocation,
56
+ ...(stringValue !== undefined ? { stringValue } : {}),
57
+ });
58
+ }
59
+ export function defineEnumMembers(equates, labels, layouts, enumNames, enumNamesLower, enumName, members, span, diagnostics) {
60
+ const enumNameLower = enumName.toLowerCase();
61
+ if (hasCaseInsensitiveKey(labels, enumNameLower) ||
62
+ hasCaseInsensitiveMapKey(equates, enumNameLower) ||
63
+ hasCaseInsensitiveMapKey(layouts, enumNameLower) ||
64
+ enumNamesLower.has(enumNameLower)) {
65
+ diagnostics.push(diagnostic(span, `duplicate enum name: ${enumName}`));
66
+ return;
67
+ }
68
+ enumNames.add(enumName);
69
+ enumNamesLower.add(enumNameLower);
70
+ const memberNames = new Set();
71
+ for (let index = 0; index < members.length; index += 1) {
72
+ const member = members[index] ?? '';
73
+ const memberLower = member.toLowerCase();
74
+ if (memberNames.has(memberLower)) {
75
+ diagnostics.push(diagnostic(span, `duplicate enum member name: ${member}`));
76
+ continue;
77
+ }
78
+ memberNames.add(memberLower);
79
+ const qualifiedName = `${enumName}.${member}`;
80
+ if (hasCaseInsensitiveKey(labels, qualifiedName.toLowerCase()) ||
81
+ hasCaseInsensitiveMapKey(equates, qualifiedName.toLowerCase())) {
82
+ diagnostics.push(diagnostic(span, `duplicate symbol: ${qualifiedName}`));
83
+ continue;
84
+ }
85
+ equates.set(qualifiedName, {
86
+ expression: { kind: 'number', value: index },
87
+ span,
88
+ currentLocation: 0,
89
+ enumMember: true,
90
+ });
91
+ }
92
+ }
93
+ export function resolveSymbols(labels, equates, layouts, diagnostics) {
94
+ const symbols = { ...labels };
95
+ for (const [name, record] of equates) {
96
+ const value = evaluateExpression(record.expression, labels, equates, record.span, diagnostics, {
97
+ currentLocation: record.currentLocation,
98
+ visiting: new Set([name]),
99
+ layouts,
100
+ reportUnknown: false,
101
+ });
102
+ if (value !== undefined) {
103
+ symbols[name] = value;
104
+ }
105
+ }
106
+ return symbols;
107
+ }
108
+ function hasCaseInsensitiveKey(record, lowerName) {
109
+ return Object.keys(record).some((key) => key.toLowerCase() === lowerName);
110
+ }
111
+ function hasCaseInsensitiveMapKey(map, lowerName) {
112
+ for (const key of map.keys()) {
113
+ if (key.toLowerCase() === lowerName) {
114
+ return true;
115
+ }
116
+ }
117
+ return false;
118
+ }
@@ -1,4 +1,5 @@
1
1
  import { buildAddressState, resolveSymbols } from './address-planning.js';
2
+ import { validateImportVisibility } from './import-visibility.js';
2
3
  import { emitProgramImage } from './program-emission.js';
3
4
  function emptyAssemblyResult(diagnostics, partial = {}) {
4
5
  return {
@@ -13,6 +14,10 @@ function emptyAssemblyResult(diagnostics, partial = {}) {
13
14
  }
14
15
  export function assembleProgram(items) {
15
16
  const diagnostics = [];
17
+ validateImportVisibility(items, diagnostics);
18
+ if (diagnostics.length > 0) {
19
+ return emptyAssemblyResult(diagnostics);
20
+ }
16
21
  const addressState = buildAddressState(items, diagnostics);
17
22
  if (diagnostics.length > 0) {
18
23
  return emptyAssemblyResult(diagnostics, { origin: addressState.origin });
@@ -1,4 +1,5 @@
1
1
  import { diagnostic, evaluateExpression, lookupSymbolValue, } from '../semantics/expression-evaluation.js';
2
+ import { applyBinaryOperator, applyUnaryOperator, } from '../semantics/constant-operators.js';
2
3
  import { encodeZ80Instruction } from '../z80/encode.js';
3
4
  export function emitInstruction(instruction, span, currentAddress, labels, equates, diagnostics, bytes, fixups, layouts) {
4
5
  const encoded = encodeZ80Instruction(instruction);
@@ -169,25 +170,34 @@ function fixupTargetFromExpression(expression) {
169
170
  if (expression.kind === 'symbol') {
170
171
  return { symbol: expression.name, addend: 0 };
171
172
  }
172
- if (expression.kind !== 'binary') {
173
+ return expression.kind === 'binary' ? binaryFixupTarget(expression) : undefined;
174
+ }
175
+ function binaryFixupTarget(expression) {
176
+ if (expression.operator !== '+' && expression.operator !== '-')
173
177
  return undefined;
174
- }
175
- if (expression.operator === '+' || expression.operator === '-') {
176
- const leftSymbol = expression.left.kind === 'symbol' ? expression.left.name : undefined;
177
- const rightSymbol = expression.right.kind === 'symbol' ? expression.right.name : undefined;
178
- const leftConstant = constantExpressionValue(expression.left);
179
- const rightConstant = constantExpressionValue(expression.right);
180
- if (leftSymbol && rightConstant !== undefined) {
181
- return {
182
- symbol: leftSymbol,
183
- addend: expression.operator === '+' ? rightConstant : -rightConstant,
184
- };
185
- }
186
- if (expression.operator === '+' && rightSymbol && leftConstant !== undefined) {
187
- return { symbol: rightSymbol, addend: leftConstant };
188
- }
189
- }
190
- return undefined;
178
+ return leftSymbolFixupTarget(expression) ?? rightSymbolFixupTarget(expression);
179
+ }
180
+ function expressionSymbol(expression) {
181
+ return expression.kind === 'symbol' ? expression.name : undefined;
182
+ }
183
+ function leftSymbolFixupTarget(expression) {
184
+ const symbol = expressionSymbol(expression.left);
185
+ const rightConstant = constantExpressionValue(expression.right);
186
+ if (!symbol || rightConstant === undefined)
187
+ return undefined;
188
+ return {
189
+ symbol,
190
+ addend: expression.operator === '+' ? rightConstant : -rightConstant,
191
+ };
192
+ }
193
+ function rightSymbolFixupTarget(expression) {
194
+ if (expression.operator !== '+')
195
+ return undefined;
196
+ const symbol = expressionSymbol(expression.right);
197
+ const leftConstant = constantExpressionValue(expression.left);
198
+ return symbol && leftConstant !== undefined
199
+ ? { symbol, addend: leftConstant }
200
+ : undefined;
191
201
  }
192
202
  function constantExpressionValue(expression) {
193
203
  switch (expression.kind) {
@@ -207,14 +217,7 @@ function constantUnaryExpressionValue(expression) {
207
217
  if (value === undefined) {
208
218
  return undefined;
209
219
  }
210
- switch (expression.operator) {
211
- case '+':
212
- return value;
213
- case '-':
214
- return -value;
215
- case '~':
216
- return ~value;
217
- }
220
+ return applyUnaryOperator(expression.operator, value);
218
221
  }
219
222
  function constantBinaryExpressionValue(expression) {
220
223
  const left = constantExpressionValue(expression.left);
@@ -222,26 +225,5 @@ function constantBinaryExpressionValue(expression) {
222
225
  if (left === undefined || right === undefined) {
223
226
  return undefined;
224
227
  }
225
- switch (expression.operator) {
226
- case '*':
227
- return left * right;
228
- case '/':
229
- return right === 0 ? undefined : Math.trunc(left / right);
230
- case '%':
231
- return right === 0 ? undefined : left % right;
232
- case '+':
233
- return left + right;
234
- case '-':
235
- return left - right;
236
- case '&':
237
- return left & right;
238
- case '^':
239
- return left ^ right;
240
- case '|':
241
- return left | right;
242
- case '<<':
243
- return left << right;
244
- case '>>':
245
- return left >> right;
246
- }
228
+ return applyBinaryOperator(expression.operator, left, right);
247
229
  }
@@ -0,0 +1,3 @@
1
+ import type { Diagnostic } from '../model/diagnostic.js';
2
+ import type { SourceItem } from '../model/source-item.js';
3
+ export declare function validateImportVisibility(items: readonly SourceItem[], diagnostics: Diagnostic[]): void;