@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
@@ -4,10 +4,9 @@ import { createSourceFile } from '../source/source-file.js';
4
4
  import { scanLogicalLines } from '../source/logical-lines.js';
5
5
  import { stripLineComment } from '../source/strip-line-comment.js';
6
6
  import { parseLogicalLine } from '../syntax/parse-line.js';
7
- import { parseExpression, parseTypeExpr } from '../syntax/parse-expression.js';
8
- import { collectOps, expandOpInvocation, parseOpInvocation } from '../expansion/op-expansion.js';
9
- import { normalizeDirectiveAlias } from '../syntax/directive-aliases.js';
10
- import { evaluateExpression, lookupEquateRecord, } from '../semantics/expression-evaluation.js';
7
+ import { parseLayoutDeclarationAt } from '../syntax/parse-layout-declarations.js';
8
+ import { collectOps, expandOpInvocation, parseOpInvocation, } from '../expansion/op-expansion.js';
9
+ import { applyConditionalAssembly } from './conditional-assembly.js';
11
10
  export function parseNextSourceItems(lines, options = {}) {
12
11
  const diagnostics = [];
13
12
  const items = [];
@@ -17,233 +16,67 @@ export function parseNextSourceItems(lines, options = {}) {
17
16
  const conditional = applyConditionalAssembly(lines, diagnostics, parseOptions.directiveAliasPolicy);
18
17
  const pendingLines = [...conditional.lines];
19
18
  const { ops, opLineIndexes } = collectOps(pendingLines, diagnostics, parseOptions);
19
+ const context = {
20
+ diagnostics,
21
+ items,
22
+ lines: pendingLines,
23
+ ops,
24
+ opLineIndexes,
25
+ parseOptions,
26
+ };
20
27
  let afterTopLevelEnd = false;
21
28
  for (let index = 0; index < pendingLines.length; index += 1) {
22
- if (opLineIndexes.has(index)) {
23
- continue;
24
- }
25
- const line = pendingLines[index];
26
- if (afterTopLevelEnd && !isPostEndParseAllowed(line.text)) {
27
- continue;
28
- }
29
- const nameLeftTypeAlias = /^([A-Za-z_][A-Za-z0-9_]*)(?::\s*|\s+)\.typealias\s+(.+)$/.exec(stripLineComment(line.text).trim());
30
- if (nameLeftTypeAlias) {
31
- const typeExprText = nameLeftTypeAlias[2] ?? '';
32
- const typeExpr = parseTypeExpr(typeExprText);
33
- if (!typeExpr) {
34
- diagnostics.push(parseDiagnostic(line, `invalid .typealias target: ${typeExprText}`));
35
- }
36
- else {
37
- items.push({
38
- kind: 'type-alias',
39
- name: nameLeftTypeAlias[1] ?? '',
40
- typeExpr,
41
- span: { sourceName: line.sourceName, line: line.line, column: firstColumn(line.text) },
42
- });
43
- }
44
- continue;
45
- }
46
- const typeAlias = /^\.type\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+)$/.exec(stripLineComment(line.text).trim());
47
- if (typeAlias) {
48
- diagnostics.push(parseDiagnostic(line, `Use "${typeAlias[1] ?? ''} .typealias ..." for type aliases.`));
49
- continue;
50
- }
51
- const nameLeftLayoutHeader = /^([A-Za-z_][A-Za-z0-9_]*)(?::\s*|\s+)\.(type|union)\s*$/.exec(stripLineComment(line.text).trim());
52
- const prefixLayoutHeader = /^\.(type|union)\s+([A-Za-z_][A-Za-z0-9_]*)\s*$/.exec(stripLineComment(line.text).trim());
53
- if (prefixLayoutHeader) {
54
- const directive = prefixLayoutHeader[1] ?? 'type';
55
- diagnostics.push(parseDiagnostic(line, `Use "${prefixLayoutHeader[2] ?? ''} .${directive}" for layouts.`));
56
- const endDirective = directive === 'union' ? '.endunion' : '.endtype';
57
- for (index += 1; index < pendingLines.length; index += 1) {
58
- if (stripLineComment(pendingLines[index].text).trim() === endDirective) {
59
- break;
60
- }
61
- }
62
- continue;
63
- }
64
- const layoutHeader = nameLeftLayoutHeader
65
- ? {
66
- directive: nameLeftLayoutHeader[2] ?? '',
67
- name: nameLeftLayoutHeader[1] ?? '',
68
- }
69
- : undefined;
70
- if (layoutHeader) {
71
- const layoutKind = layoutHeader.directive === 'union' ? 'union' : 'record';
72
- const endDirective = layoutKind === 'union' ? '.endunion' : '.endtype';
73
- const fields = [];
74
- let terminated = false;
75
- for (index += 1; index < pendingLines.length; index += 1) {
76
- const fieldLine = pendingLines[index];
77
- const fieldText = stripLineComment(fieldLine.text).trim();
78
- if (fieldText.length === 0) {
79
- continue;
80
- }
81
- if (fieldText === endDirective) {
82
- terminated = true;
83
- break;
84
- }
85
- const field = parseLayoutField(fieldText);
86
- if (!field) {
87
- diagnostics.push(parseDiagnostic(fieldLine, `invalid .${layoutHeader.directive} field declaration`));
88
- continue;
89
- }
90
- fields.push(field);
91
- }
92
- if (!terminated) {
93
- diagnostics.push(parseDiagnostic(line, `.${layoutHeader.directive} ${layoutHeader.name} missing ${endDirective}`));
94
- }
95
- items.push({
96
- kind: 'type',
97
- name: layoutHeader.name,
98
- layoutKind,
99
- fields,
100
- span: { sourceName: line.sourceName, line: line.line, column: firstColumn(line.text) },
101
- });
102
- continue;
103
- }
104
- const opCall = parseOpInvocation(line);
105
- if (opCall && !isTopLevelEnd(line.text)) {
106
- const overloads = ops.get(opCall.name);
107
- if (overloads) {
108
- const expanded = expandOpInvocation(ops, overloads, opCall.operands, line, diagnostics);
109
- if (expanded) {
110
- items.push(...expanded);
111
- }
112
- continue;
113
- }
114
- }
115
- const result = parseLogicalLine(line, parseOptions);
116
- diagnostics.push(...result.diagnostics);
117
- items.push(...result.items);
118
- if (result.items.some((item) => item.kind === 'end')) {
119
- afterTopLevelEnd = true;
120
- }
29
+ const step = parsePendingLine(context, index, afterTopLevelEnd);
30
+ index = step.consumedUntilIndex;
31
+ afterTopLevelEnd = step.afterTopLevelEnd;
121
32
  }
122
33
  return { diagnostics, items };
123
34
  }
124
- function applyConditionalAssembly(lines, diagnostics, directiveAliasPolicy) {
125
- const out = [];
126
- const equates = new Map();
127
- const locationDependentEquates = new Set();
128
- const stack = [];
129
- for (const line of lines) {
130
- const text = stripLineComment(line.text).trim();
131
- const ifDirective = /^\.if\s+(.+)$/.exec(text);
132
- if (ifDirective) {
133
- const parentActive = conditionalActive(stack);
134
- const expressionText = ifDirective[1] ?? '';
135
- const value = parentActive
136
- ? evaluateConditionalExpression(line, expressionText, equates, locationDependentEquates, diagnostics)
137
- : undefined;
138
- const conditionActive = parentActive && value !== undefined && value !== 0;
139
- stack.push({ line, parentActive, conditionActive, elseSeen: false });
140
- continue;
141
- }
142
- if (/^\.else\s*$/.test(text)) {
143
- const frame = stack.pop();
144
- if (!frame) {
145
- diagnostics.push(parseDiagnostic(line, 'unmatched .else'));
146
- continue;
147
- }
148
- if (frame.elseSeen) {
149
- diagnostics.push(parseDiagnostic(line, 'duplicate .else'));
150
- }
151
- stack.push({
152
- line: frame.line,
153
- parentActive: frame.parentActive,
154
- conditionActive: frame.parentActive && !frame.conditionActive,
155
- elseSeen: true,
156
- });
157
- continue;
158
- }
159
- if (/^\.endif\s*$/.test(text)) {
160
- if (!stack.pop()) {
161
- diagnostics.push(parseDiagnostic(line, 'unmatched .endif'));
162
- }
163
- continue;
164
- }
165
- if (!conditionalActive(stack)) {
166
- continue;
167
- }
168
- out.push(line);
169
- recordConditionalEquate(line, equates, locationDependentEquates, directiveAliasPolicy);
35
+ function parsePendingLine(context, index, afterTopLevelEnd) {
36
+ const line = context.lines[index];
37
+ if (shouldSkipPendingLine(context, index, line, afterTopLevelEnd)) {
38
+ return { consumedUntilIndex: index, afterTopLevelEnd };
170
39
  }
171
- for (const frame of stack) {
172
- diagnostics.push(parseDiagnostic(frame.line, 'unterminated .if'));
40
+ const layoutStep = parseLayoutLine(context, index);
41
+ if (layoutStep)
42
+ return { ...layoutStep, afterTopLevelEnd };
43
+ if (parseExpandedOpLine(context, line)) {
44
+ return { consumedUntilIndex: index, afterTopLevelEnd };
173
45
  }
174
- return { lines: out };
46
+ return parseNormalLine(context, index, line, afterTopLevelEnd);
175
47
  }
176
- function conditionalActive(stack) {
177
- return stack.every((frame) => frame.parentActive && frame.conditionActive);
48
+ function shouldSkipPendingLine(context, index, line, afterTopLevelEnd) {
49
+ return context.opLineIndexes.has(index) || (afterTopLevelEnd && !isPostEndParseAllowed(line.text));
178
50
  }
179
- function evaluateConditionalExpression(line, expressionText, equates, locationDependentEquates, diagnostics) {
180
- const expression = parseExpression(expressionText);
181
- if (!expression) {
182
- diagnostics.push(parseDiagnostic(line, `invalid .if expression: ${expressionText}`));
183
- return undefined;
184
- }
185
- if (expressionReferencesCurrentLocation(expression, equates, locationDependentEquates)) {
186
- diagnostics.push(parseDiagnostic(line, 'invalid .if expression: current location is not available during conditional assembly'));
51
+ function parseLayoutLine(context, index) {
52
+ const layoutDeclaration = parseLayoutDeclarationAt(context.lines, index);
53
+ if (layoutDeclaration === undefined)
187
54
  return undefined;
55
+ context.diagnostics.push(...layoutDeclaration.diagnostics);
56
+ if (layoutDeclaration.item !== undefined) {
57
+ context.items.push(layoutDeclaration.item);
188
58
  }
189
- return evaluateExpression(expression, {}, equates, { sourceName: line.sourceName, line: line.line, column: firstColumn(line.text) }, diagnostics, { currentLocation: 0 });
190
- }
191
- function recordConditionalEquate(line, equates, locationDependentEquates, directiveAliasPolicy) {
192
- const text = normalizeDirectiveAlias(stripLineComment(line.text), directiveAliasPolicy).trim();
193
- const equ = /^([A-Za-z_.$?][A-Za-z0-9_.$?]*)(?::\s*|\s+)\.equ\s+(.+)$/.exec(text);
194
- if (!equ) {
195
- return;
196
- }
197
- const name = equ[1] ?? '';
198
- const expressionText = equ[2] ?? '';
199
- const expression = parseExpression(expressionText);
200
- if (!expression) {
201
- return;
202
- }
203
- if (expressionReferencesCurrentLocation(expression, equates, locationDependentEquates)) {
204
- locationDependentEquates.add(canonicalConditionalSymbolKey(name));
205
- }
206
- equates.set(name, {
207
- expression,
208
- span: { sourceName: line.sourceName, line: line.line, column: firstColumn(line.text) },
209
- currentLocation: 0,
210
- });
59
+ return { consumedUntilIndex: layoutDeclaration.consumedUntilIndex };
211
60
  }
212
- function expressionReferencesCurrentLocation(expression, equates, locationDependentEquates, visiting = new Set()) {
213
- switch (expression.kind) {
214
- case 'current-location':
215
- return true;
216
- case 'symbol': {
217
- if (locationDependentEquates.has(canonicalConditionalSymbolKey(expression.name))) {
218
- return true;
219
- }
220
- const lookup = lookupEquateRecord(equates, expression.name);
221
- if (!lookup || visiting.has(canonicalConditionalSymbolKey(lookup.key))) {
222
- return false;
223
- }
224
- const nextVisiting = new Set(visiting);
225
- nextVisiting.add(canonicalConditionalSymbolKey(lookup.key));
226
- return expressionReferencesCurrentLocation(lookup.record.expression, equates, locationDependentEquates, nextVisiting);
227
- }
228
- case 'byte-function':
229
- case 'unary':
230
- return expressionReferencesCurrentLocation(expression.expression, equates, locationDependentEquates, visiting);
231
- case 'binary':
232
- return (expressionReferencesCurrentLocation(expression.left, equates, locationDependentEquates, visiting) ||
233
- expressionReferencesCurrentLocation(expression.right, equates, locationDependentEquates, visiting));
234
- case 'layout-cast':
235
- return (expressionReferencesCurrentLocation(expression.base, equates, locationDependentEquates, visiting) ||
236
- expression.path.some((part) => part.kind === 'index' &&
237
- expressionReferencesCurrentLocation(part.expression, equates, locationDependentEquates, visiting)));
238
- case 'number':
239
- case 'type-size':
240
- case 'sizeof':
241
- case 'offset':
242
- return false;
243
- }
61
+ function parseExpandedOpLine(context, line) {
62
+ const opCall = parseOpInvocation(line);
63
+ if (!opCall || isTopLevelEnd(line.text))
64
+ return false;
65
+ const overloads = context.ops.get(opCall.name);
66
+ if (!overloads)
67
+ return false;
68
+ const expanded = expandOpInvocation(context.ops, overloads, opCall.operands, line, context.diagnostics);
69
+ context.items.push(...expanded);
70
+ return true;
244
71
  }
245
- function canonicalConditionalSymbolKey(name) {
246
- return name.toLowerCase();
72
+ function parseNormalLine(context, index, line, afterTopLevelEnd) {
73
+ const result = parseLogicalLine(line, context.parseOptions);
74
+ context.diagnostics.push(...result.diagnostics);
75
+ context.items.push(...result.items);
76
+ return {
77
+ consumedUntilIndex: index,
78
+ afterTopLevelEnd: afterTopLevelEnd || result.items.some((item) => item.kind === 'end'),
79
+ };
247
80
  }
248
81
  export function compileSource(sourceText, options = {}) {
249
82
  const source = createSourceFile(options.entryName ?? '<memory>', sourceText);
@@ -273,59 +106,3 @@ function isTopLevelEnd(text) {
273
106
  function isPostEndParseAllowed(text) {
274
107
  return /^(?:\.binfrom|\.binto|binfrom|binto)\b/i.test(stripLineComment(text).trim());
275
108
  }
276
- function parseLayoutField(text) {
277
- const match = /^([A-Za-z_][A-Za-z0-9_]*)\s+(\.(?:field|byte|word|addr))(?:\s+(.+))?$/.exec(text);
278
- if (!match) {
279
- return undefined;
280
- }
281
- const name = match[1] ?? '';
282
- const directive = (match[2] ?? '').toLowerCase();
283
- const operand = match[3]?.trim();
284
- switch (directive) {
285
- case '.byte':
286
- return operand === undefined ? { name, size: 1 } : undefined;
287
- case '.word':
288
- case '.addr':
289
- return operand === undefined ? { name, size: 2 } : undefined;
290
- case '.field': {
291
- if (operand === undefined) {
292
- return undefined;
293
- }
294
- const size = /^[0-9]+$/.test(operand) ? Number.parseInt(operand, 10) : undefined;
295
- if (size !== undefined) {
296
- return size > 0 ? { name, size } : undefined;
297
- }
298
- const scalar = scalarFieldSize(operand);
299
- if (scalar !== undefined) {
300
- return { name, size: scalar };
301
- }
302
- const typeExpr = parseTypeExpr(operand);
303
- return typeExpr ? { name, size: 0, typeExpr } : undefined;
304
- }
305
- }
306
- }
307
- function scalarFieldSize(typeName) {
308
- switch (typeName.toLowerCase()) {
309
- case 'byte':
310
- return 1;
311
- case 'word':
312
- case 'addr':
313
- return 2;
314
- default:
315
- return undefined;
316
- }
317
- }
318
- function parseDiagnostic(line, message) {
319
- return {
320
- severity: 'error',
321
- code: 'AZMN_PARSE',
322
- message,
323
- sourceName: line.sourceName,
324
- line: line.line,
325
- column: firstColumn(line.text),
326
- };
327
- }
328
- function firstColumn(text) {
329
- const match = /\S/.exec(text);
330
- return match ? match.index + 1 : 1;
331
- }
@@ -0,0 +1,6 @@
1
+ import type { Diagnostic } from '../model/diagnostic.js';
2
+ import type { LogicalLine } from '../source/logical-lines.js';
3
+ import { type DirectiveAliasPolicy } from '../syntax/directive-aliases.js';
4
+ export declare function applyConditionalAssembly(lines: readonly LogicalLine[], diagnostics: Diagnostic[], directiveAliasPolicy: DirectiveAliasPolicy | undefined): {
5
+ readonly lines: readonly LogicalLine[];
6
+ };
@@ -0,0 +1,181 @@
1
+ import { stripLineComment } from '../source/strip-line-comment.js';
2
+ import { normalizeDirectiveAlias } from '../syntax/directive-aliases.js';
3
+ import { parseExpression } from '../syntax/parse-expression.js';
4
+ import { evaluateExpression, lookupEquateRecord, } from '../semantics/expression-evaluation.js';
5
+ export function applyConditionalAssembly(lines, diagnostics, directiveAliasPolicy) {
6
+ const out = [];
7
+ const equates = new Map();
8
+ const locationDependentEquates = new Set();
9
+ const stack = [];
10
+ for (const line of lines) {
11
+ const directive = parseConditionalDirective(line);
12
+ if (applyConditionalDirective(directive, line, stack, equates, locationDependentEquates, diagnostics)) {
13
+ continue;
14
+ }
15
+ if (!conditionalActive(stack)) {
16
+ continue;
17
+ }
18
+ out.push(line);
19
+ recordConditionalEquate(line, equates, locationDependentEquates, directiveAliasPolicy);
20
+ }
21
+ for (const frame of stack) {
22
+ diagnostics.push(parseDiagnostic(frame.line, 'unterminated .if'));
23
+ }
24
+ return { lines: out };
25
+ }
26
+ function parseConditionalDirective(line) {
27
+ const text = stripLineComment(line.text).trim();
28
+ const ifDirective = /^\.if\s+(.+)$/.exec(text);
29
+ if (ifDirective)
30
+ return { kind: 'if', expressionText: ifDirective[1] ?? '' };
31
+ if (/^\.else\s*$/.test(text))
32
+ return { kind: 'else' };
33
+ if (/^\.endif\s*$/.test(text))
34
+ return { kind: 'endif' };
35
+ return { kind: 'none' };
36
+ }
37
+ function applyConditionalDirective(directive, line, stack, equates, locationDependentEquates, diagnostics) {
38
+ switch (directive.kind) {
39
+ case 'if':
40
+ pushConditionalFrame(line, directive.expressionText, stack, equates, locationDependentEquates, diagnostics);
41
+ return true;
42
+ case 'else':
43
+ flipConditionalFrame(line, stack, diagnostics);
44
+ return true;
45
+ case 'endif':
46
+ popConditionalFrame(line, stack, diagnostics);
47
+ return true;
48
+ case 'none':
49
+ return false;
50
+ }
51
+ }
52
+ function pushConditionalFrame(line, expressionText, stack, equates, locationDependentEquates, diagnostics) {
53
+ const parentActive = conditionalActive(stack);
54
+ const value = parentActive
55
+ ? evaluateConditionalExpression(line, expressionText, equates, locationDependentEquates, diagnostics)
56
+ : undefined;
57
+ stack.push({
58
+ line,
59
+ parentActive,
60
+ conditionActive: parentActive && value !== undefined && value !== 0,
61
+ elseSeen: false,
62
+ });
63
+ }
64
+ function flipConditionalFrame(line, stack, diagnostics) {
65
+ const frame = stack.pop();
66
+ if (!frame) {
67
+ diagnostics.push(parseDiagnostic(line, 'unmatched .else'));
68
+ return;
69
+ }
70
+ if (frame.elseSeen) {
71
+ diagnostics.push(parseDiagnostic(line, 'duplicate .else'));
72
+ }
73
+ stack.push({
74
+ line: frame.line,
75
+ parentActive: frame.parentActive,
76
+ conditionActive: frame.parentActive && !frame.conditionActive,
77
+ elseSeen: true,
78
+ });
79
+ }
80
+ function popConditionalFrame(line, stack, diagnostics) {
81
+ if (!stack.pop()) {
82
+ diagnostics.push(parseDiagnostic(line, 'unmatched .endif'));
83
+ }
84
+ }
85
+ function conditionalActive(stack) {
86
+ return stack.every((frame) => frame.parentActive && frame.conditionActive);
87
+ }
88
+ function evaluateConditionalExpression(line, expressionText, equates, locationDependentEquates, diagnostics) {
89
+ const expression = parseExpression(expressionText);
90
+ if (!expression) {
91
+ diagnostics.push(parseDiagnostic(line, `invalid .if expression: ${expressionText}`));
92
+ return undefined;
93
+ }
94
+ if (expressionReferencesCurrentLocation(expression, equates, locationDependentEquates)) {
95
+ diagnostics.push(parseDiagnostic(line, 'invalid .if expression: current location is not available during conditional assembly'));
96
+ return undefined;
97
+ }
98
+ return evaluateExpression(expression, {}, equates, { sourceName: line.sourceName, line: line.line, column: firstColumn(line.text) }, diagnostics, { currentLocation: 0 });
99
+ }
100
+ function recordConditionalEquate(line, equates, locationDependentEquates, directiveAliasPolicy) {
101
+ const text = normalizeDirectiveAlias(stripLineComment(line.text), directiveAliasPolicy).trim();
102
+ const equ = /^([A-Za-z_.$?][A-Za-z0-9_.$?]*)(?::\s*|\s+)\.equ\s+(.+)$/.exec(text);
103
+ if (!equ) {
104
+ return;
105
+ }
106
+ const name = equ[1] ?? '';
107
+ const expressionText = equ[2] ?? '';
108
+ const expression = parseExpression(expressionText);
109
+ if (!expression) {
110
+ return;
111
+ }
112
+ if (expressionReferencesCurrentLocation(expression, equates, locationDependentEquates)) {
113
+ locationDependentEquates.add(canonicalConditionalSymbolKey(name));
114
+ }
115
+ equates.set(name, {
116
+ expression,
117
+ span: { sourceName: line.sourceName, line: line.line, column: firstColumn(line.text) },
118
+ currentLocation: 0,
119
+ });
120
+ }
121
+ function expressionReferencesCurrentLocation(expression, equates, locationDependentEquates, visiting = new Set()) {
122
+ if (expression.kind === 'current-location')
123
+ return true;
124
+ if (expression.kind === 'symbol') {
125
+ return symbolReferencesCurrentLocation(expression.name, equates, locationDependentEquates, visiting);
126
+ }
127
+ return expressionChildExpressions(expression).some((child) => expressionReferencesCurrentLocation(child, equates, locationDependentEquates, visiting));
128
+ }
129
+ function expressionChildExpressions(expression) {
130
+ switch (expression.kind) {
131
+ case 'byte-function':
132
+ case 'unary':
133
+ return [expression.expression];
134
+ case 'binary':
135
+ return [expression.left, expression.right];
136
+ case 'layout-cast':
137
+ return layoutCastChildExpressions(expression);
138
+ default:
139
+ return [];
140
+ }
141
+ }
142
+ function layoutCastChildExpressions(expression) {
143
+ return [
144
+ expression.base,
145
+ ...expression.path.flatMap((part) => (part.kind === 'index' ? [part.expression] : [])),
146
+ ];
147
+ }
148
+ function symbolReferencesCurrentLocation(name, equates, locationDependentEquates, visiting) {
149
+ if (locationDependentEquates.has(canonicalConditionalSymbolKey(name))) {
150
+ return true;
151
+ }
152
+ const lookup = lookupEquateRecord(equates, name);
153
+ if (!lookup)
154
+ return false;
155
+ return equateReferencesCurrentLocation(lookup, equates, locationDependentEquates, visiting);
156
+ }
157
+ function equateReferencesCurrentLocation(lookup, equates, locationDependentEquates, visiting) {
158
+ const key = canonicalConditionalSymbolKey(lookup.key);
159
+ if (visiting.has(key))
160
+ return false;
161
+ const nextVisiting = new Set(visiting);
162
+ nextVisiting.add(key);
163
+ return expressionReferencesCurrentLocation(lookup.record.expression, equates, locationDependentEquates, nextVisiting);
164
+ }
165
+ function canonicalConditionalSymbolKey(name) {
166
+ return name.toLowerCase();
167
+ }
168
+ function parseDiagnostic(line, message) {
169
+ return {
170
+ severity: 'error',
171
+ code: 'AZMN_PARSE',
172
+ message,
173
+ sourceName: line.sourceName,
174
+ line: line.line,
175
+ column: firstColumn(line.text),
176
+ };
177
+ }
178
+ function firstColumn(text) {
179
+ const match = /\S/.exec(text);
180
+ return match ? match.index + 1 : 1;
181
+ }
@@ -0,0 +1,3 @@
1
+ import type { Expression } from '../model/expression.js';
2
+ export declare function expressionFitsKnownImm8(expression: Expression): boolean;
3
+ export declare function expressionFitsKnownImm16(expression: Expression): boolean;
@@ -0,0 +1,52 @@
1
+ const BINARY_CONSTANT_OPERATORS = new Map([
2
+ ['+', (left, right) => left + right],
3
+ ['-', (left, right) => left - right],
4
+ ['*', (left, right) => left * right],
5
+ ['/', (left, right) => (right === 0 ? undefined : Math.trunc(left / right))],
6
+ ['%', (left, right) => (right === 0 ? undefined : left % right)],
7
+ ['&', (left, right) => left & right],
8
+ ['^', (left, right) => left ^ right],
9
+ ['|', (left, right) => left | right],
10
+ ['<<', (left, right) => left << right],
11
+ ['>>', (left, right) => left >> right],
12
+ ]);
13
+ export function expressionFitsKnownImm8(expression) {
14
+ const value = expressionConstantValue(expression);
15
+ return value === undefined || (value >= -0x80 && value <= 0xff);
16
+ }
17
+ export function expressionFitsKnownImm16(expression) {
18
+ const value = expressionConstantValue(expression);
19
+ return value === undefined || (value >= -0x8000 && value <= 0xffff);
20
+ }
21
+ function expressionConstantValue(expression) {
22
+ switch (expression.kind) {
23
+ case 'number':
24
+ return expression.value;
25
+ case 'unary':
26
+ return unaryConstantValue(expression);
27
+ case 'binary':
28
+ return binaryConstantValue(expression);
29
+ default:
30
+ return undefined;
31
+ }
32
+ }
33
+ function unaryConstantValue(expression) {
34
+ const value = expressionConstantValue(expression.expression);
35
+ if (value === undefined)
36
+ return undefined;
37
+ switch (expression.operator) {
38
+ case '+':
39
+ return value;
40
+ case '-':
41
+ return -value;
42
+ case '~':
43
+ return ~value;
44
+ }
45
+ }
46
+ function binaryConstantValue(expression) {
47
+ const left = expressionConstantValue(expression.left);
48
+ const right = expressionConstantValue(expression.right);
49
+ if (left === undefined || right === undefined)
50
+ return undefined;
51
+ return BINARY_CONSTANT_OPERATORS.get(expression.operator)?.(left, right);
52
+ }
@@ -0,0 +1,5 @@
1
+ import type { Diagnostic } from '../model/diagnostic.js';
2
+ import type { SourceItem } from '../model/source-item.js';
3
+ import type { LogicalLineLike, OpDecl } from './op-expansion.js';
4
+ import { type OpOperand } from './op-operands.js';
5
+ export declare function expandSelectedOp(ops: ReadonlyMap<string, readonly OpDecl[]>, overloads: readonly OpDecl[], operands: readonly OpOperand[], line: LogicalLineLike, diagnostics: Diagnostic[], stack: readonly OpDecl[]): readonly SourceItem[];