@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,19 +1,16 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { dirname, normalize } from 'node:path';
1
+ import { normalize } from 'node:path';
3
2
  import { assembleProgram } from './assembly/assemble-program.js';
3
+ import { emitAssemblyArtifacts } from './api-artifacts.js';
4
+ import { runRegisterContracts, shouldAnalyzeRegisterContracts } from './api-register-contracts.js';
4
5
  import { analyzeProgramNext, loadProgramNext } from './tooling/api.js';
5
6
  import { defaultFormatWriters } from './outputs/index.js';
6
- import { UnsupportedAsm80LoweringError } from './outputs/write-asm80.js';
7
7
  import { writeHex } from './outputs/write-hex.js';
8
- import { analyzeRegisterCare } from './register-care/analyze.js';
9
- import { buildRegisterCareProgramModel } from './register-care/programModel.js';
10
- import { parseAcceptedOutputCandidates } from './register-care/accept-output.js';
11
- import { parseInterfaceContracts } from './register-care/smartComments.js';
8
+ import { buildRegisterContractsProgramModel } from './register-contracts/programModel.js';
12
9
  function parseUnresolvedSymbolName(message) {
13
10
  const match = /^Unresolved symbol "([^"]+)"/.exec(message);
14
11
  return match?.[1];
15
12
  }
16
- function isSuppressedUnknownSymbolInRegisterCareMode(diagnostic, directCalls) {
13
+ function isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls) {
17
14
  if (directCalls === undefined || directCalls.length === 0) {
18
15
  return false;
19
16
  }
@@ -33,7 +30,6 @@ function isSuppressedUnknownSymbolInRegisterCareMode(diagnostic, directCalls) {
33
30
  call.column === diagnostic.column);
34
31
  }
35
32
  export { writeHex, defaultFormatWriters };
36
- let cachedPackageVersion;
37
33
  /**
38
34
  * Compile an AZM/ASM80-style program into in-memory artifacts.
39
35
  */
@@ -54,223 +50,58 @@ export async function compile(entryFile, options = {}, deps = { formats: default
54
50
  const analysis = analyzeProgramNext(loaded.loadedProgram, {
55
51
  ...(options.caseStyle !== undefined ? { caseStyle: options.caseStyle } : {}),
56
52
  });
57
- const registerCareMode = options.registerCare ?? 'off';
58
- const shouldAnalyzeRegisterCare = registerCareMode !== 'off' ||
59
- options.emitRegisterReport === true ||
60
- options.emitRegisterInterface === true ||
61
- options.emitRegisterAnnotations === true ||
62
- options.fixRegisterContracts === true ||
63
- (options.acceptRegisterOutputCandidates?.length ?? 0) > 0 ||
64
- (options.registerCareInterfaces?.length ?? 0) > 0;
65
- const directCalls = shouldAnalyzeRegisterCare
66
- ? buildRegisterCareProgramModel(loaded.loadedProgram.program.files[0]?.items ?? []).directCalls
53
+ const analyzeRegisterContractsNow = shouldAnalyzeRegisterContracts(options);
54
+ const directCalls = analyzeRegisterContractsNow
55
+ ? buildRegisterContractsProgramModel(loaded.loadedProgram.program.files[0]?.items ?? [])
56
+ .directCalls
67
57
  : undefined;
68
- diagnostics.push(...analysis.diagnostics.filter((diagnostic) => shouldAnalyzeRegisterCare
69
- ? !isSuppressedUnknownSymbolInRegisterCareMode(diagnostic, directCalls)
58
+ diagnostics.push(...analysis.diagnostics.filter((diagnostic) => analyzeRegisterContractsNow
59
+ ? !isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls)
70
60
  : true));
71
61
  const artifacts = [];
72
- if (shouldAnalyzeRegisterCare) {
73
- // Validate interface references and accepted output markers now; full analysis is deferred.
74
- const acceptedOutputCandidates = parseAcceptedOutputCandidates(options.acceptRegisterOutputCandidates ?? []);
75
- const interfaceContracts = [];
76
- for (const rawInterface of options.registerCareInterfaces ?? []) {
77
- const contractPath = normalize(rawInterface);
78
- if (contractPath.slice(-5).toLowerCase() !== '.asmi') {
79
- diagnostics.push({
80
- severity: 'error',
81
- code: 'AZMN_REGISTER_CARE',
82
- message: 'Register-care interface files must use the .asmi extension',
83
- sourceName: contractPath,
84
- });
85
- continue;
86
- }
87
- const interfaceText = await readFile(contractPath, 'utf8');
88
- for (const contract of parseInterfaceContracts(interfaceText, contractPath).values()) {
89
- interfaceContracts.push(contract);
90
- }
91
- }
92
- if (hasErrors(diagnostics)) {
93
- return { diagnostics, artifacts: [] };
94
- }
95
- const registerCare = analyzeRegisterCare(loaded.loadedProgram, {
96
- mode: registerCareMode,
97
- emitReport: options.emitRegisterReport === true,
98
- emitInterface: options.emitRegisterInterface === true,
99
- emitAnnotations: options.emitRegisterAnnotations === true || options.fixRegisterContracts === true,
100
- fixRegisterContracts: options.fixRegisterContracts === true,
101
- acceptedOutputCandidates,
102
- ...(options.registerCareProfile !== undefined
103
- ? { registerCareProfile: options.registerCareProfile }
104
- : {}),
105
- ...(interfaceContracts.length > 0 ? { interfaceContracts } : {}),
106
- });
107
- if (registerCare.reportText !== undefined) {
108
- artifacts.push({ kind: 'register-care-report', text: registerCare.reportText });
109
- }
110
- if (registerCare.interfaceText !== undefined) {
111
- artifacts.push({ kind: 'register-care-interface', text: registerCare.interfaceText });
112
- }
113
- if (registerCare.annotations !== undefined && registerCare.annotations.length > 0) {
114
- const files = registerCare.annotations.map((item) => ({
115
- path: item.path,
116
- text: item.text,
117
- }));
118
- artifacts.push({ kind: 'register-care-annotations', files });
119
- }
120
- diagnostics.push(...registerCare.diagnostics);
62
+ if (hasErrors(diagnostics)) {
63
+ sortDiagnosticsInPlace(diagnostics);
64
+ return { diagnostics, artifacts };
65
+ }
66
+ if (analyzeRegisterContractsNow) {
67
+ const registerContracts = await runRegisterContracts(loaded.loadedProgram, options);
68
+ artifacts.push(...registerContracts.artifacts);
69
+ diagnostics.push(...registerContracts.diagnostics);
121
70
  if (hasErrors(diagnostics))
122
- return { diagnostics, artifacts: [] };
71
+ return { diagnostics, artifacts };
123
72
  }
124
73
  if (options.skipAssembly === true) {
125
74
  return { diagnostics, artifacts };
126
75
  }
127
76
  const program = loaded.loadedProgram.program.files[0]?.items ?? [];
128
77
  const assembled = assembleProgram(program);
129
- diagnostics.push(...assembled.diagnostics.filter((diagnostic) => shouldAnalyzeRegisterCare
130
- ? !isSuppressedUnknownSymbolInRegisterCareMode(diagnostic, directCalls)
78
+ diagnostics.push(...assembled.diagnostics.filter((diagnostic) => analyzeRegisterContractsNow
79
+ ? !isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls)
131
80
  : true));
132
81
  sortDiagnosticsInPlace(diagnostics);
133
82
  if (hasErrors(diagnostics)) {
134
83
  return { diagnostics, artifacts: [] };
135
84
  }
136
- const map = assembledImageToMap(assembled.bytes, assembled.origin, assembled.sourceSegments);
137
- const hexMap = assembledInitializedImageToMap(assembled.bytes, assembled.origin, assembled.initializedAddresses);
138
- const sidecarMap = assembledInitializedImageToMap(assembled.bytes, assembled.origin, assembled.initializedAddresses, assembled.sourceSegments);
139
- const symbols = collectSymbolEntries(program, assembled.symbols);
140
- const emit = compileArtifactDefaults(options);
141
- const d8Root = options.sourceRoot ?? dirname(normalizedEntry);
142
- if (emit.emitBin) {
143
- artifacts.push(deps.formats.writeBin(map, symbols));
144
- }
145
- if (emit.emitHex) {
146
- artifacts.push(deps.formats.writeHex(hexMap, symbols));
147
- }
148
- if (emit.emitD8m) {
149
- const main = symbols.find((symbol) => symbol.kind === 'label' && symbol.name.toLowerCase() === 'main');
150
- const d8mOpts = {
151
- rootDir: normalize(d8Root),
152
- packageVersion: await readPackageVersion(),
153
- inputs: {
154
- entry: normalizedEntry,
155
- ...(options.d8mInputs?.hex !== undefined ? { hex: options.d8mInputs.hex } : {}),
156
- ...(options.d8mInputs?.bin !== undefined ? { bin: options.d8mInputs.bin } : {}),
157
- },
158
- ...(main !== undefined ? { entrySymbol: main.name } : {}),
159
- ...(main !== undefined
160
- ? { entryAddress: main.kind === 'constant' ? main.value : main.address }
161
- : {}),
162
- };
163
- artifacts.push(deps.formats.writeD8m(sidecarMap, symbols, d8mOpts));
164
- }
165
- if (emit.emitAsm80) {
166
- if (deps.formats.writeAsm80 !== undefined) {
167
- try {
168
- artifacts.push(deps.formats.writeAsm80(program, symbols));
169
- }
170
- catch (error) {
171
- if (error instanceof UnsupportedAsm80LoweringError) {
172
- diagnostics.push({
173
- severity: 'error',
174
- code: 'AZMN_ASM80',
175
- message: error.message,
176
- sourceName: error.item.span.sourceName,
177
- line: error.item.span.line,
178
- column: error.item.span.column,
179
- });
180
- return { diagnostics, artifacts };
181
- }
182
- throw error;
183
- }
184
- }
185
- }
85
+ const emittedArtifacts = await emitAssemblyArtifacts({
86
+ entryFile: normalizedEntry,
87
+ options,
88
+ formats: deps.formats,
89
+ program,
90
+ bytes: assembled.bytes,
91
+ origin: assembled.origin,
92
+ sourceSegments: assembled.sourceSegments,
93
+ initializedAddresses: assembled.initializedAddresses,
94
+ symbols: assembled.symbols,
95
+ });
96
+ artifacts.push(...emittedArtifacts.artifacts);
97
+ diagnostics.push(...emittedArtifacts.diagnostics);
186
98
  return { diagnostics, artifacts };
187
99
  }
188
- function compileArtifactDefaults(options) {
189
- const anyPrimary = [options.emitBin, options.emitHex, options.emitD8m].some((value) => value !== undefined);
190
- const emitBin = anyPrimary ? (options.emitBin ?? false) : true;
191
- const emitHex = anyPrimary ? (options.emitHex ?? false) : true;
192
- const emitD8m = anyPrimary ? (options.emitD8m ?? false) : true;
193
- const emitAsm80 = options.emitAsm80 ?? false;
194
- return { emitBin, emitHex, emitD8m, emitAsm80 };
195
- }
196
- function assembledImageToMap(bytes, origin, sourceSegments = []) {
197
- const map = new Map();
198
- for (let offset = 0; offset < bytes.length; offset += 1) {
199
- map.set(origin + offset, bytes[offset] ?? 0);
200
- }
201
- const writtenRange = {
202
- start: origin,
203
- end: origin + bytes.length,
204
- };
205
- return { bytes: map, writtenRange, sourceSegments };
206
- }
207
- function assembledInitializedImageToMap(bytes, origin, initializedAddresses, sourceSegments = []) {
208
- const map = new Map();
209
- for (const address of initializedAddresses) {
210
- const offset = address - origin;
211
- if (offset >= 0 && offset < bytes.length) {
212
- map.set(address, bytes[offset] ?? 0);
213
- }
214
- }
215
- return { bytes: map, sourceSegments };
216
- }
217
- function collectSymbolEntries(items, resolvedSymbols) {
218
- const map = new Map();
219
- for (const item of items) {
220
- switch (item.kind) {
221
- case 'equ': {
222
- const value = resolvedSymbols[item.name];
223
- if (value !== undefined) {
224
- map.set(item.name, {
225
- kind: 'constant',
226
- name: item.name,
227
- value,
228
- file: item.span.sourceName,
229
- line: item.span.line,
230
- scope: 'global',
231
- });
232
- }
233
- break;
234
- }
235
- case 'label': {
236
- const address = resolvedSymbols[item.name];
237
- if (address !== undefined) {
238
- map.set(item.name, {
239
- kind: 'label',
240
- name: item.name,
241
- address,
242
- file: item.span.sourceName,
243
- line: item.span.line,
244
- scope: 'global',
245
- });
246
- }
247
- break;
248
- }
249
- case 'enum': {
250
- for (const member of item.members) {
251
- const fullName = `${item.name}.${member}`;
252
- const value = resolvedSymbols[fullName];
253
- if (value !== undefined) {
254
- map.set(fullName, {
255
- kind: 'constant',
256
- name: fullName,
257
- value,
258
- file: item.span.sourceName,
259
- line: item.span.line,
260
- scope: 'global',
261
- });
262
- }
263
- }
264
- break;
265
- }
266
- }
267
- }
268
- return [...map.values()];
269
- }
270
100
  function hasErrors(diagnostics) {
271
101
  return diagnostics.some((diagnostic) => diagnostic.severity === 'error');
272
102
  }
273
103
  function sortDiagnosticsInPlace(diagnostics) {
104
+ dedupeDiagnosticsInPlace(diagnostics);
274
105
  diagnostics.sort((left, right) => {
275
106
  const lineDelta = (left.line ?? 0) - (right.line ?? 0);
276
107
  if (lineDelta !== 0) {
@@ -279,28 +110,25 @@ function sortDiagnosticsInPlace(diagnostics) {
279
110
  return (left.column ?? 0) - (right.column ?? 0);
280
111
  });
281
112
  }
282
- async function readPackageVersion() {
283
- if (cachedPackageVersion !== undefined) {
284
- return cachedPackageVersion;
285
- }
286
- const packageJsonCandidates = [
287
- new URL('../package.json', import.meta.url),
288
- new URL('../../package.json', import.meta.url),
289
- new URL('../../../package.json', import.meta.url),
290
- ];
291
- for (const candidate of packageJsonCandidates) {
292
- try {
293
- const raw = await readFile(candidate, 'utf8');
294
- const json = JSON.parse(raw);
295
- if (json.version !== undefined) {
296
- cachedPackageVersion = json.version;
297
- return cachedPackageVersion;
298
- }
299
- }
300
- catch {
301
- // Continue searching candidates.
113
+ function dedupeDiagnosticsInPlace(diagnostics) {
114
+ const seen = new Set();
115
+ for (let index = diagnostics.length - 1; index >= 0; index -= 1) {
116
+ const diagnostic = diagnostics[index];
117
+ const key = diagnosticKey(diagnostic);
118
+ if (seen.has(key)) {
119
+ diagnostics.splice(index, 1);
120
+ continue;
302
121
  }
122
+ seen.add(key);
303
123
  }
304
- cachedPackageVersion = '0.0.0';
305
- return cachedPackageVersion;
124
+ }
125
+ function diagnosticKey(diagnostic) {
126
+ return [
127
+ diagnostic.severity,
128
+ diagnostic.code,
129
+ diagnostic.message,
130
+ diagnostic.sourceName ?? '',
131
+ diagnostic.line ?? '',
132
+ diagnostic.column ?? '',
133
+ ].join('\0');
306
134
  }
@@ -0,0 +1,9 @@
1
+ import type { Diagnostic } from './model/diagnostic.js';
2
+ import type { Artifact } from './outputs/types.js';
3
+ import type { LoadedProgramNext } from './tooling/api.js';
4
+ import type { CompileNextFunctionOptions } from './api-compile.js';
5
+ export declare function shouldAnalyzeRegisterContracts(options: CompileNextFunctionOptions): boolean;
6
+ export declare function runRegisterContracts(loadedProgram: LoadedProgramNext, options: CompileNextFunctionOptions): Promise<{
7
+ readonly artifacts: readonly Artifact[];
8
+ readonly diagnostics: readonly Diagnostic[];
9
+ }>;
@@ -0,0 +1,77 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { normalize } from 'node:path';
3
+ import { analyzeRegisterContracts } from './register-contracts/analyze.js';
4
+ import { parseAcceptedOutputCandidates } from './register-contracts/accept-output.js';
5
+ import { parseInterfaceContracts } from './register-contracts/interfaceContracts.js';
6
+ export function shouldAnalyzeRegisterContracts(options) {
7
+ const registerContractsMode = options.registerContracts ?? options.registerCare ?? 'off';
8
+ return (registerContractsMode !== 'off' ||
9
+ options.emitRegisterReport === true ||
10
+ options.emitRegisterInterface === true ||
11
+ options.emitRegisterAnnotations === true ||
12
+ options.fixRegisterContracts === true ||
13
+ (options.acceptRegisterOutputCandidates?.length ?? 0) > 0 ||
14
+ (options.registerContractsInterfaces?.length ?? options.registerCareInterfaces?.length ?? 0) > 0);
15
+ }
16
+ export async function runRegisterContracts(loadedProgram, options) {
17
+ const diagnostics = [];
18
+ const artifacts = [];
19
+ const interfaceContracts = await loadInterfaceContracts(options.registerContractsInterfaces ?? options.registerCareInterfaces ?? [], diagnostics);
20
+ if (hasErrors(diagnostics)) {
21
+ return { diagnostics, artifacts };
22
+ }
23
+ const registerContracts = analyzeRegisterContracts(loadedProgram, {
24
+ mode: options.registerContracts ?? options.registerCare ?? 'off',
25
+ emitReport: options.emitRegisterReport === true,
26
+ emitInterface: options.emitRegisterInterface === true,
27
+ emitAnnotations: options.emitRegisterAnnotations === true || options.fixRegisterContracts === true,
28
+ fixRegisterContracts: options.fixRegisterContracts === true,
29
+ acceptedOutputCandidates: parseAcceptedOutputCandidates(options.acceptRegisterOutputCandidates ?? []),
30
+ ...(options.registerContractsProfile !== undefined || options.registerCareProfile !== undefined
31
+ ? {
32
+ registerContractsProfile: options.registerContractsProfile ?? options.registerCareProfile,
33
+ }
34
+ : {}),
35
+ ...(interfaceContracts.length > 0 ? { interfaceContracts } : {}),
36
+ });
37
+ if (registerContracts.reportText !== undefined) {
38
+ artifacts.push({ kind: 'register-contracts-report', text: registerContracts.reportText });
39
+ }
40
+ if (registerContracts.interfaceText !== undefined) {
41
+ artifacts.push({ kind: 'register-contracts-interface', text: registerContracts.interfaceText });
42
+ }
43
+ if (registerContracts.annotations !== undefined && registerContracts.annotations.length > 0) {
44
+ artifacts.push({
45
+ kind: 'register-contracts-annotations',
46
+ files: registerContracts.annotations.map((item) => ({
47
+ path: item.path,
48
+ text: item.text,
49
+ })),
50
+ });
51
+ }
52
+ diagnostics.push(...registerContracts.diagnostics);
53
+ return { artifacts, diagnostics };
54
+ }
55
+ async function loadInterfaceContracts(interfaces, diagnostics) {
56
+ const interfaceContracts = [];
57
+ for (const rawInterface of interfaces) {
58
+ const contractPath = normalize(rawInterface);
59
+ if (contractPath.slice(-5).toLowerCase() !== '.asmi') {
60
+ diagnostics.push({
61
+ severity: 'error',
62
+ code: 'AZMN_REGISTER_CONTRACTS',
63
+ message: 'Register contracts interface files must use the .asmi extension',
64
+ sourceName: contractPath,
65
+ });
66
+ continue;
67
+ }
68
+ const interfaceText = await readFile(contractPath, 'utf8');
69
+ for (const contract of parseInterfaceContracts(interfaceText, contractPath).values()) {
70
+ interfaceContracts.push(contract);
71
+ }
72
+ }
73
+ return interfaceContracts;
74
+ }
75
+ function hasErrors(diagnostics) {
76
+ return diagnostics.some((diagnostic) => diagnostic.severity === 'error');
77
+ }
@@ -1,7 +1,7 @@
1
1
  export { analyzeProgram, analyzeProgramNext, loadProgram, loadProgramNext } from './tooling/api.js';
2
- export { analyzeRegisterCareForTools, codeActionForOutputCandidate, diagnosticForOutputCandidate, type AnalyzeRegisterCareForToolsOptions, type AnalyzeRegisterCareForToolsResult, type RegisterCareCandidateDiagnostic, type RegisterCareCodeAction, type RegisterCareTextEdit, } from './register-care/tooling.js';
2
+ export { analyzeRegisterCareForTools, analyzeRegisterContractsForTools, codeActionForOutputCandidate, diagnosticForOutputCandidate, type AnalyzeRegisterCareForToolsOptions, type AnalyzeRegisterCareForToolsResult, type AnalyzeRegisterContractsForToolsOptions, type AnalyzeRegisterContractsForToolsResult, type RegisterCareCandidateDiagnostic, type RegisterCareCodeAction, type RegisterCareTextEdit, type RegisterContractsCandidateDiagnostic, type RegisterContractsCodeAction, type RegisterContractsTextEdit, } from './register-contracts/tooling.js';
3
3
  export { DiagnosticIds } from './model/diagnostic.js';
4
4
  export type { AnalyzeProgramOptions, AnalyzeProgramResult, LoadedProgram, LoadProgramOptions, LoadProgramResult, AnalyzeProgramNextOptions, AnalyzeProgramNextResult, LoadedProgramNext, LoadProgramNextOptions, LoadProgramNextResult, } from './tooling/api.js';
5
5
  export type { CaseStyleMode } from './tooling/case-style.js';
6
6
  export type { Diagnostic, DiagnosticId, DiagnosticSeverity } from './model/diagnostic.js';
7
- export type { RegisterCareMode, RegisterCareOutputCandidate, RegisterCareUnit, } from './register-care/types.js';
7
+ export type { RegisterCareMode, RegisterCareOutputCandidate, RegisterCareUnit, RegisterContractsMode, RegisterContractsOutputCandidate, RegisterContractsUnit, } from './register-contracts/types.js';
@@ -1,3 +1,3 @@
1
1
  export { analyzeProgram, analyzeProgramNext, loadProgram, loadProgramNext } from './tooling/api.js';
2
- export { analyzeRegisterCareForTools, codeActionForOutputCandidate, diagnosticForOutputCandidate, } from './register-care/tooling.js';
2
+ export { analyzeRegisterCareForTools, analyzeRegisterContractsForTools, codeActionForOutputCandidate, diagnosticForOutputCandidate, } from './register-contracts/tooling.js';
3
3
  export { DiagnosticIds } from './model/diagnostic.js';
@@ -1,7 +1,7 @@
1
1
  import type { Diagnostic } from '../model/diagnostic.js';
2
2
  import type { SourceItem } from '../model/source-item.js';
3
- import type { SymbolTable } from '../model/symbol.js';
4
3
  import { type EquateRecord, type LayoutRecord } from '../semantics/expression-evaluation.js';
4
+ export { resolveSymbols } from './address-symbols.js';
5
5
  export interface AddressState {
6
6
  readonly labels: Record<string, number>;
7
7
  readonly equates: Map<string, EquateRecord>;
@@ -16,4 +16,3 @@ export declare function buildAddressState(items: readonly SourceItem[], diagnost
16
16
  };
17
17
  export declare function stringDirectiveBytes(directive: 'cstr' | 'pstr' | 'istr', value: string): readonly number[];
18
18
  export declare function alignmentPadding(address: number, alignment: number): number;
19
- export declare function resolveSymbols(labels: Readonly<Record<string, number>>, equates: ReadonlyMap<string, EquateRecord>, layouts: ReadonlyMap<string, LayoutRecord>, diagnostics: Diagnostic[]): SymbolTable;