@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.
- package/README.md +239 -76
- package/dist/src/api-artifacts.d.ts +20 -0
- package/dist/src/api-artifacts.js +165 -0
- package/dist/src/api-compile.d.ts +8 -2
- package/dist/src/api-compile.js +55 -227
- package/dist/src/api-register-contracts.d.ts +9 -0
- package/dist/src/api-register-contracts.js +77 -0
- package/dist/src/api-tooling.d.ts +2 -2
- package/dist/src/api-tooling.js +1 -1
- package/dist/src/assembly/address-planning.d.ts +1 -2
- package/dist/src/assembly/address-planning.js +119 -218
- package/dist/src/assembly/address-symbols.d.ts +12 -0
- package/dist/src/assembly/address-symbols.js +118 -0
- package/dist/src/assembly/assemble-program.js +5 -0
- package/dist/src/assembly/fixup-emission.js +30 -48
- package/dist/src/assembly/import-visibility.d.ts +3 -0
- package/dist/src/assembly/import-visibility.js +204 -0
- package/dist/src/assembly/program-emission.js +163 -164
- package/dist/src/cli/artifact-files.d.ts +15 -0
- package/dist/src/cli/artifact-files.js +86 -0
- package/dist/src/cli/parse-args.d.ts +6 -5
- package/dist/src/cli/parse-args.js +162 -136
- package/dist/src/cli/run.js +4 -1
- package/dist/src/cli/usage.d.ts +1 -0
- package/dist/src/cli/usage.js +33 -0
- package/dist/src/cli/write-artifacts.js +18 -91
- package/dist/src/core/compile.js +51 -274
- package/dist/src/core/conditional-assembly.d.ts +6 -0
- package/dist/src/core/conditional-assembly.js +181 -0
- package/dist/src/expansion/op-constant-expression.d.ts +3 -0
- package/dist/src/expansion/op-constant-expression.js +52 -0
- package/dist/src/expansion/op-expand-selected.d.ts +5 -0
- package/dist/src/expansion/op-expand-selected.js +143 -0
- package/dist/src/expansion/op-expansion.d.ts +5 -53
- package/dist/src/expansion/op-expansion.js +85 -815
- package/dist/src/expansion/op-instruction-instantiation.d.ts +3 -0
- package/dist/src/expansion/op-instruction-instantiation.js +194 -0
- package/dist/src/expansion/op-local-labels.d.ts +8 -0
- package/dist/src/expansion/op-local-labels.js +166 -0
- package/dist/src/expansion/op-operand-splitting.d.ts +1 -0
- package/dist/src/expansion/op-operand-splitting.js +44 -0
- package/dist/src/expansion/op-operands.d.ts +53 -0
- package/dist/src/expansion/op-operands.js +66 -0
- package/dist/src/expansion/op-selection.d.ts +18 -0
- package/dist/src/expansion/op-selection.js +172 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/model/diagnostic.d.ts +4 -0
- package/dist/src/model/diagnostic.js +4 -0
- package/dist/src/node/source-host.js +40 -13
- package/dist/src/outputs/asm80-expression-evaluation.d.ts +10 -0
- package/dist/src/outputs/asm80-expression-evaluation.js +75 -0
- package/dist/src/outputs/asm80-expressions.d.ts +5 -0
- package/dist/src/outputs/asm80-expressions.js +47 -0
- package/dist/src/outputs/asm80-instruction-operands.d.ts +16 -0
- package/dist/src/outputs/asm80-instruction-operands.js +38 -0
- package/dist/src/outputs/asm80-instructions.d.ts +5 -0
- package/dist/src/outputs/asm80-instructions.js +272 -0
- package/dist/src/outputs/asm80-ld-operands.d.ts +10 -0
- package/dist/src/outputs/asm80-ld-operands.js +157 -0
- package/dist/src/outputs/asm80-strings.d.ts +4 -0
- package/dist/src/outputs/asm80-strings.js +14 -0
- package/dist/src/outputs/d8-files.d.ts +10 -0
- package/dist/src/outputs/d8-files.js +103 -0
- package/dist/src/outputs/d8-helpers.d.ts +21 -0
- package/dist/src/outputs/d8-helpers.js +136 -0
- package/dist/src/outputs/hex.js +26 -18
- package/dist/src/outputs/types.d.ts +16 -10
- package/dist/src/outputs/write-asm80.js +72 -597
- package/dist/src/outputs/write-d8.js +6 -216
- package/dist/src/register-contracts/accept-output.d.ts +2 -0
- package/dist/src/register-contracts/analyze-helpers.d.ts +29 -0
- package/dist/src/register-contracts/analyze-helpers.js +162 -0
- package/dist/src/{register-care → register-contracts}/analyze.d.ts +6 -6
- package/dist/src/register-contracts/analyze.js +73 -0
- package/dist/src/register-contracts/annotate.d.ts +11 -0
- package/dist/src/{register-care → register-contracts}/annotate.js +3 -3
- package/dist/src/register-contracts/annotations.d.ts +8 -0
- package/dist/src/{register-care → register-contracts}/annotations.js +3 -3
- package/dist/src/register-contracts/boundaryHints.d.ts +3 -0
- package/dist/src/register-contracts/boundaryHints.js +24 -0
- package/dist/src/register-contracts/carriers.d.ts +2 -0
- package/dist/src/register-contracts/constants.d.ts +4 -0
- package/dist/src/register-contracts/constants.js +51 -0
- package/dist/src/register-contracts/controlFlow.d.ts +5 -0
- package/dist/src/register-contracts/controlFlow.js +55 -0
- package/dist/src/register-contracts/fix.d.ts +11 -0
- package/dist/src/{register-care → register-contracts}/fix.js +47 -30
- package/dist/src/register-contracts/instruction-head.d.ts +2 -0
- package/dist/src/register-contracts/instruction-head.js +3 -0
- package/dist/src/register-contracts/instruction-operands.d.ts +3 -0
- package/dist/src/register-contracts/instruction-operands.js +101 -0
- package/dist/src/register-contracts/instruction-predicates.d.ts +6 -0
- package/dist/src/register-contracts/instruction-predicates.js +44 -0
- package/dist/src/register-contracts/interfaceContracts.d.ts +2 -0
- package/dist/src/register-contracts/interfaceContracts.js +68 -0
- package/dist/src/register-contracts/liveness.d.ts +3 -0
- package/dist/src/{register-care → register-contracts}/liveness.js +111 -79
- package/dist/src/register-contracts/operand-register-name.d.ts +2 -0
- package/dist/src/register-contracts/operand-register-name.js +13 -0
- package/dist/src/{register-care → register-contracts}/profiles.d.ts +5 -5
- package/dist/src/{register-care → register-contracts}/profiles.js +2 -2
- package/dist/src/register-contracts/programModel-boundaries.d.ts +6 -0
- package/dist/src/register-contracts/programModel-boundaries.js +64 -0
- package/dist/src/register-contracts/programModel-routines.d.ts +7 -0
- package/dist/src/register-contracts/programModel-routines.js +144 -0
- package/dist/src/register-contracts/programModel.d.ts +3 -0
- package/dist/src/register-contracts/programModel.js +14 -0
- package/dist/src/register-contracts/report.d.ts +5 -0
- package/dist/src/{register-care → register-contracts}/report.js +34 -17
- package/dist/src/register-contracts/routine-summaries.d.ts +6 -0
- package/dist/src/{register-care → register-contracts}/routine-summaries.js +11 -1
- package/dist/src/register-contracts/smartCommentBlocks.d.ts +5 -0
- package/dist/src/register-contracts/smartCommentBlocks.js +30 -0
- package/dist/src/register-contracts/smartCommentParsing.d.ts +3 -0
- package/dist/src/register-contracts/smartCommentParsing.js +80 -0
- package/dist/src/register-contracts/smartComments.d.ts +5 -0
- package/dist/src/register-contracts/smartComments.js +92 -0
- package/dist/src/register-contracts/summaries.d.ts +12 -0
- package/dist/src/{register-care → register-contracts}/summaries.js +7 -7
- package/dist/src/register-contracts/summary-boundary.d.ts +2 -0
- package/dist/src/register-contracts/summary-boundary.js +40 -0
- package/dist/src/register-contracts/summary-contract.d.ts +2 -0
- package/dist/src/register-contracts/summary-contract.js +45 -0
- package/dist/src/register-contracts/summary-result.d.ts +7 -0
- package/dist/src/register-contracts/summary-result.js +122 -0
- package/dist/src/register-contracts/summary-state.d.ts +23 -0
- package/dist/src/register-contracts/summary-state.js +88 -0
- package/dist/src/register-contracts/summary-token-transfer.d.ts +3 -0
- package/dist/src/register-contracts/summary-token-transfer.js +67 -0
- package/dist/src/register-contracts/summary.d.ts +3 -0
- package/dist/src/register-contracts/summary.js +266 -0
- package/dist/src/register-contracts/tooling.d.ts +57 -0
- package/dist/src/{register-care → register-contracts}/tooling.js +8 -6
- package/dist/src/register-contracts/types.d.ts +188 -0
- package/dist/src/semantics/binary-operators.d.ts +2 -0
- package/dist/src/semantics/binary-operators.js +15 -0
- package/dist/src/semantics/byte-functions.d.ts +2 -0
- package/dist/src/semantics/byte-functions.js +7 -0
- package/dist/src/semantics/constant-operator-types.d.ts +10 -0
- package/dist/src/semantics/constant-operator-types.js +1 -0
- package/dist/src/semantics/constant-operators.d.ts +3 -0
- package/dist/src/semantics/constant-operators.js +3 -0
- package/dist/src/semantics/diagnostics.d.ts +3 -0
- package/dist/src/semantics/diagnostics.js +10 -0
- package/dist/src/semantics/expression-evaluation.d.ts +11 -19
- package/dist/src/semantics/expression-evaluation.js +22 -334
- package/dist/src/semantics/layout-evaluation.d.ts +23 -0
- package/dist/src/semantics/layout-evaluation.js +202 -0
- package/dist/src/semantics/layout-format.d.ts +5 -0
- package/dist/src/semantics/layout-format.js +31 -0
- package/dist/src/semantics/layout-path.d.ts +24 -0
- package/dist/src/semantics/layout-path.js +58 -0
- package/dist/src/semantics/unary-operators.d.ts +2 -0
- package/dist/src/semantics/unary-operators.js +8 -0
- package/dist/src/source/line-comment-scanner.d.ts +1 -0
- package/dist/src/source/line-comment-scanner.js +51 -0
- package/dist/src/source/logical-lines.d.ts +3 -0
- package/dist/src/source/source-span.d.ts +2 -0
- package/dist/src/source/strip-line-comment.js +8 -44
- package/dist/src/syntax/directive-aliases.js +36 -22
- package/dist/src/syntax/expression-tokenizer.d.ts +30 -0
- package/dist/src/syntax/expression-tokenizer.js +310 -0
- package/dist/src/syntax/parse-directive-statement.d.ts +9 -0
- package/dist/src/syntax/parse-directive-statement.js +309 -0
- package/dist/src/syntax/parse-expression.d.ts +2 -2
- package/dist/src/syntax/parse-expression.js +7 -568
- package/dist/src/syntax/parse-layout-declarations.d.ts +9 -0
- package/dist/src/syntax/parse-layout-declarations.js +189 -0
- package/dist/src/syntax/parse-layout-expression.d.ts +5 -0
- package/dist/src/syntax/parse-layout-expression.js +175 -0
- package/dist/src/syntax/parse-line.js +21 -273
- package/dist/src/syntax/parse-token-expression.d.ts +3 -0
- package/dist/src/syntax/parse-token-expression.js +133 -0
- package/dist/src/tooling/api.js +1 -1
- package/dist/src/tooling/case-style.js +47 -30
- package/dist/src/z80/effect-groups.d.ts +38 -0
- package/dist/src/z80/effect-groups.js +265 -0
- package/dist/src/z80/effect-units.d.ts +18 -0
- package/dist/src/z80/effect-units.js +165 -0
- package/dist/src/z80/effects.d.ts +1 -1
- package/dist/src/z80/effects.js +94 -557
- package/dist/src/z80/encode-core.d.ts +2 -0
- package/dist/src/z80/encode-core.js +42 -0
- package/dist/src/z80/encode-ld-helpers.d.ts +25 -0
- package/dist/src/z80/encode-ld-helpers.js +172 -0
- package/dist/src/z80/encode-ld.d.ts +2 -0
- package/dist/src/z80/encode-ld.js +285 -0
- package/dist/src/z80/encode.js +190 -542
- package/dist/src/z80/ld-support.d.ts +3 -0
- package/dist/src/z80/ld-support.js +146 -0
- package/dist/src/z80/operand-split-state.d.ts +8 -0
- package/dist/src/z80/operand-split-state.js +46 -0
- package/dist/src/z80/operand-split.d.ts +1 -0
- package/dist/src/z80/operand-split.js +13 -0
- package/dist/src/z80/parse-basic.d.ts +4 -0
- package/dist/src/z80/parse-basic.js +39 -0
- package/dist/src/z80/parse-branch.d.ts +4 -0
- package/dist/src/z80/parse-branch.js +218 -0
- package/dist/src/z80/parse-conditions.d.ts +6 -0
- package/dist/src/z80/parse-conditions.js +10 -0
- package/dist/src/z80/parse-exchange.d.ts +2 -0
- package/dist/src/z80/parse-exchange.js +30 -0
- package/dist/src/z80/parse-instruction.js +224 -1010
- package/dist/src/z80/parse-io-control.d.ts +5 -0
- package/dist/src/z80/parse-io-control.js +108 -0
- package/dist/src/z80/parse-ld.d.ts +2 -0
- package/dist/src/z80/parse-ld.js +83 -0
- package/dist/src/z80/parse-operands.d.ts +41 -0
- package/dist/src/z80/parse-operands.js +259 -0
- package/docs/codebase/01-orientation-and-repository-layout.md +192 -0
- package/docs/codebase/02-source-loading-and-parsing.md +263 -0
- package/docs/codebase/03-assembly-and-z80-emission.md +251 -0
- package/docs/codebase/04-ops-and-register-contracts.md +237 -0
- package/docs/codebase/05-interfaces-and-output-artifacts.md +253 -0
- package/docs/codebase/06-verification-and-maintenance.md +202 -0
- package/docs/codebase/appendices/a-directory-file-reference.md +253 -0
- package/docs/codebase/appendices/b-compile-flow-reference.md +103 -0
- package/docs/codebase/appendices/c-public-surface-reference.md +106 -0
- package/docs/codebase/appendices/index.md +16 -0
- package/docs/codebase/index.md +46 -0
- package/package.json +2 -3
- package/dist/src/register-care/accept-output.d.ts +0 -2
- package/dist/src/register-care/analyze.js +0 -166
- package/dist/src/register-care/annotate.d.ts +0 -11
- package/dist/src/register-care/annotations.d.ts +0 -8
- package/dist/src/register-care/boundaryHints.d.ts +0 -3
- package/dist/src/register-care/boundaryHints.js +0 -80
- package/dist/src/register-care/carriers.d.ts +0 -2
- package/dist/src/register-care/controlFlow.d.ts +0 -5
- package/dist/src/register-care/controlFlow.js +0 -38
- package/dist/src/register-care/fix.d.ts +0 -11
- package/dist/src/register-care/instruction-shape.d.ts +0 -11
- package/dist/src/register-care/instruction-shape.js +0 -129
- package/dist/src/register-care/liveness.d.ts +0 -3
- package/dist/src/register-care/programModel.d.ts +0 -3
- package/dist/src/register-care/programModel.js +0 -266
- package/dist/src/register-care/report.d.ts +0 -5
- package/dist/src/register-care/routine-summaries.d.ts +0 -6
- package/dist/src/register-care/smartComments.d.ts +0 -5
- package/dist/src/register-care/smartComments.js +0 -243
- package/dist/src/register-care/summaries.d.ts +0 -12
- package/dist/src/register-care/summary.d.ts +0 -3
- package/dist/src/register-care/summary.js +0 -474
- package/dist/src/register-care/tooling.d.ts +0 -43
- package/dist/src/register-care/types.d.ts +0 -172
- package/docs/reference/cli.md +0 -151
- package/docs/reference/tooling-api.md +0 -316
- /package/dist/src/{register-care → register-contracts}/accept-output.js +0 -0
- /package/dist/src/{register-care → register-contracts}/carriers.js +0 -0
- /package/dist/src/{register-care → register-contracts}/sourceText.d.ts +0 -0
- /package/dist/src/{register-care → register-contracts}/sourceText.js +0 -0
- /package/dist/src/{register-care → register-contracts}/types.js +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { expressionFitsKnownImm16, expressionFitsKnownImm8, } from './op-constant-expression.js';
|
|
2
|
+
import { formatOpOperand, isConditionToken, } from './op-operands.js';
|
|
3
|
+
const MATCHER_OPERAND_PREDICATES = {
|
|
4
|
+
reg8: (operand) => operand.kind === 'reg8',
|
|
5
|
+
reg16: (operand) => operand.kind === 'reg16',
|
|
6
|
+
imm8: (operand) => operand.kind === 'imm' && expressionFitsKnownImm8(operand.expression),
|
|
7
|
+
imm16: (operand) => operand.kind === 'imm' && expressionFitsKnownImm16(operand.expression),
|
|
8
|
+
cc: (operand) => isConditionToken(operand.text),
|
|
9
|
+
idx16: (operand) => operand.kind === 'indexed',
|
|
10
|
+
ea: (operand) => operand.kind === 'imm',
|
|
11
|
+
mem8: (operand) => isMemoryOperand(operand),
|
|
12
|
+
mem16: (operand) => isMemoryOperand(operand),
|
|
13
|
+
};
|
|
14
|
+
const MATCHER_EXPECTATIONS = {
|
|
15
|
+
reg8: 'reg8',
|
|
16
|
+
reg16: 'reg16',
|
|
17
|
+
imm8: 'imm8',
|
|
18
|
+
imm16: 'imm16',
|
|
19
|
+
cc: 'condition token NZ/Z/NC/C/PO/PE/P/M',
|
|
20
|
+
idx16: 'IX/IY indexed memory operand',
|
|
21
|
+
ea: 'ea',
|
|
22
|
+
mem8: 'mem8 dereference',
|
|
23
|
+
mem16: 'mem16 dereference',
|
|
24
|
+
};
|
|
25
|
+
export function selectOpOverload(overloads, operands) {
|
|
26
|
+
const arityMatches = overloads.filter((overload) => overload.params.length === operands.length);
|
|
27
|
+
if (arityMatches.length === 0) {
|
|
28
|
+
return { kind: 'arity_mismatch' };
|
|
29
|
+
}
|
|
30
|
+
const matches = arityMatches.filter((overload) => overload.params.every((param, index) => matcherMatchesOperand(param.matcher, operands[index])));
|
|
31
|
+
if (matches.length === 0) {
|
|
32
|
+
return { kind: 'no_match', candidates: arityMatches };
|
|
33
|
+
}
|
|
34
|
+
if (matches.length === 1) {
|
|
35
|
+
return { kind: 'selected', overload: matches[0] };
|
|
36
|
+
}
|
|
37
|
+
const selected = mostSpecificOverload(matches, operands);
|
|
38
|
+
return selected
|
|
39
|
+
? { kind: 'selected', overload: selected }
|
|
40
|
+
: { kind: 'ambiguous', candidates: matches };
|
|
41
|
+
}
|
|
42
|
+
function mostSpecificOverload(overloads, operands) {
|
|
43
|
+
for (const candidate of overloads) {
|
|
44
|
+
let beatsAll = true;
|
|
45
|
+
for (const other of overloads) {
|
|
46
|
+
if (candidate === other)
|
|
47
|
+
continue;
|
|
48
|
+
if (compareOverloadSpecificity(candidate, other, operands) !== 'x') {
|
|
49
|
+
beatsAll = false;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (beatsAll)
|
|
54
|
+
return candidate;
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
function compareOverloadSpecificity(x, y, operands) {
|
|
59
|
+
const votes = operands.reduce((current, operand, index) => {
|
|
60
|
+
return addSpecificityVote(current, compareMatcherSpecificity(x.params[index].matcher, y.params[index].matcher, operand));
|
|
61
|
+
}, { x: 0, y: 0 });
|
|
62
|
+
return specificityFromVotes(votes);
|
|
63
|
+
}
|
|
64
|
+
function addSpecificityVote(votes, comparison) {
|
|
65
|
+
if (comparison === 'x')
|
|
66
|
+
return { ...votes, x: votes.x + 1 };
|
|
67
|
+
if (comparison === 'y')
|
|
68
|
+
return { ...votes, y: votes.y + 1 };
|
|
69
|
+
return votes;
|
|
70
|
+
}
|
|
71
|
+
function specificityFromVotes(votes) {
|
|
72
|
+
if (votes.x > 0 && votes.y === 0)
|
|
73
|
+
return 'x';
|
|
74
|
+
if (votes.y > 0 && votes.x === 0)
|
|
75
|
+
return 'y';
|
|
76
|
+
if (votes.x === 0 && votes.y === 0)
|
|
77
|
+
return 'equal';
|
|
78
|
+
return 'incomparable';
|
|
79
|
+
}
|
|
80
|
+
function compareMatcherSpecificity(x, y, operand) {
|
|
81
|
+
if (x.kind === y.kind)
|
|
82
|
+
return 'equal';
|
|
83
|
+
return (compareFixedMatcherSpecificity(x, y, operand) ??
|
|
84
|
+
compareImmediateMatcherSpecificity(x, y, operand) ??
|
|
85
|
+
'equal');
|
|
86
|
+
}
|
|
87
|
+
function compareFixedMatcherSpecificity(x, y, operand) {
|
|
88
|
+
if (x.kind === 'fixed' && fixedTokenBeatsMatcher(x, y, operand))
|
|
89
|
+
return 'x';
|
|
90
|
+
if (y.kind === 'fixed' && fixedTokenBeatsMatcher(y, x, operand))
|
|
91
|
+
return 'y';
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
function compareImmediateMatcherSpecificity(x, y, operand) {
|
|
95
|
+
if (operand.kind !== 'imm' || !expressionFitsKnownImm8(operand.expression))
|
|
96
|
+
return undefined;
|
|
97
|
+
if (x.kind === 'imm8' && y.kind === 'imm16')
|
|
98
|
+
return 'x';
|
|
99
|
+
if (x.kind === 'imm16' && y.kind === 'imm8')
|
|
100
|
+
return 'y';
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
function fixedTokenBeatsMatcher(fixed, other, operand) {
|
|
104
|
+
return ((other.kind === 'reg8' && operand.kind === 'reg8' && operand.text === fixed.token) ||
|
|
105
|
+
(other.kind === 'reg16' && operand.kind === 'reg16' && operand.text === fixed.token) ||
|
|
106
|
+
(other.kind === 'cc' &&
|
|
107
|
+
isConditionToken(fixed.token) &&
|
|
108
|
+
operand.text.toUpperCase() === fixed.token));
|
|
109
|
+
}
|
|
110
|
+
function matcherMatchesOperand(matcher, operand) {
|
|
111
|
+
if (matcher.kind === 'fixed')
|
|
112
|
+
return operand.text.toUpperCase() === matcher.token;
|
|
113
|
+
return MATCHER_OPERAND_PREDICATES[matcher.kind]?.(operand) ?? false;
|
|
114
|
+
}
|
|
115
|
+
function isMemoryOperand(operand) {
|
|
116
|
+
return operand.kind === 'reg-indirect' || operand.kind === 'mem-abs' || operand.kind === 'indexed';
|
|
117
|
+
}
|
|
118
|
+
export function formatOpSelectionDiagnostic(selection, overloads, operands) {
|
|
119
|
+
const name = overloads[0]?.name ?? '<unknown>';
|
|
120
|
+
const operandSummary = `call-site operands: (${operands.map(formatOpOperand).join(', ')})`;
|
|
121
|
+
switch (selection.kind) {
|
|
122
|
+
case 'arity_mismatch':
|
|
123
|
+
return [
|
|
124
|
+
`No op overload of "${name}" accepts ${operands.length} operand(s).`,
|
|
125
|
+
'available overloads:',
|
|
126
|
+
...overloads.map((overload) => ` - ${formatOpSignature(overload)}`),
|
|
127
|
+
].join('\n');
|
|
128
|
+
case 'no_match':
|
|
129
|
+
return noMatchDiagnostic(selection.candidates, operands, name, operandSummary);
|
|
130
|
+
case 'ambiguous':
|
|
131
|
+
return [
|
|
132
|
+
`Ambiguous op overload for "${name}" (${selection.candidates.length} matches).`,
|
|
133
|
+
operandSummary,
|
|
134
|
+
'equally specific candidates:',
|
|
135
|
+
...selection.candidates.map((candidate) => ` - ${formatOpSignatureWithLocation(candidate)}`),
|
|
136
|
+
].join('\n');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function noMatchDiagnostic(candidates, operands, name, operandSummary) {
|
|
140
|
+
return [
|
|
141
|
+
`No matching op overload for "${name}" with provided operands.`,
|
|
142
|
+
operandSummary,
|
|
143
|
+
'available overloads:',
|
|
144
|
+
...candidates.map((candidate) => {
|
|
145
|
+
const mismatch = firstMismatchReason(candidate, operands);
|
|
146
|
+
return ` - ${formatOpSignatureWithLocation(candidate)}${mismatch ? ` ; ${mismatch}` : ''}`;
|
|
147
|
+
}),
|
|
148
|
+
].join('\n');
|
|
149
|
+
}
|
|
150
|
+
function firstMismatchReason(overload, operands) {
|
|
151
|
+
for (let index = 0; index < overload.params.length; index += 1) {
|
|
152
|
+
const param = overload.params[index];
|
|
153
|
+
const operand = operands[index];
|
|
154
|
+
if (!matcherMatchesOperand(param.matcher, operand)) {
|
|
155
|
+
return `${param.name}: ${matcherMismatchReason(param.matcher, operand)}`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
function matcherMismatchReason(matcher, operand) {
|
|
161
|
+
const expected = matcher.kind === 'fixed' ? matcher.token : MATCHER_EXPECTATIONS[matcher.kind];
|
|
162
|
+
return `expects ${expected}, got ${formatOpOperand(operand)}`;
|
|
163
|
+
}
|
|
164
|
+
function formatOpSignature(op) {
|
|
165
|
+
return `${op.name}(${op.params.map((param) => `${param.name} ${formatMatcher(param.matcher)}`).join(', ')})`;
|
|
166
|
+
}
|
|
167
|
+
function formatOpSignatureWithLocation(op) {
|
|
168
|
+
return `${formatOpSignature(op)} (${op.sourceName}:${op.line})`;
|
|
169
|
+
}
|
|
170
|
+
function formatMatcher(matcher) {
|
|
171
|
+
return matcher.kind === 'fixed' ? matcher.token : matcher.kind;
|
|
172
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -6,9 +6,10 @@ export { formatDiagnostic, formatNextDiagnostic } from './diagnostics/format.js'
|
|
|
6
6
|
export { analyzeProgram, loadProgram, analyzeProgramNext, loadProgramNext } from './tooling/api.js';
|
|
7
7
|
export { DiagnosticIds } from './model/diagnostic.js';
|
|
8
8
|
export type { DiagnosticId, DiagnosticSeverity, Diagnostic } from './model/diagnostic.js';
|
|
9
|
-
export { analyzeRegisterCareForTools, type AnalyzeRegisterCareForToolsOptions, type AnalyzeRegisterCareForToolsResult, type RegisterCareCandidateDiagnostic, type RegisterCareCodeAction, } from './register-
|
|
9
|
+
export { analyzeRegisterCareForTools, analyzeRegisterContractsForTools, 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';
|
|
10
10
|
export { compile, defaultFormatWriters, writeHex } from './api-compile.js';
|
|
11
11
|
export type { AddressRange, Artifact, CompileDependencies, CompileFunctionOptions, CompileResult, CompileNextDependencies, CompileNextFunctionOptions, EmittedByteMap, FormatWriters, CompileNextResult as CompileNextProgramResult, } from './api-compile.js';
|
|
12
12
|
export type { AnalyzeProgramOptions, AnalyzeProgramResult, LoadProgramOptions, LoadProgramResult, LoadedProgram, AnalyzeProgramNextOptions, AnalyzeProgramNextResult, LoadProgramNextOptions, LoadProgramNextResult, LoadedProgramNext, } from './tooling/api.js';
|
|
13
13
|
export type { CaseStyleMode } from './tooling/case-style.js';
|
|
14
|
+
export type { RegisterCareMode, RegisterCareOutputCandidate, RegisterCareUnit, RegisterContractsMode, RegisterContractsOutputCandidate, RegisterContractsUnit, } from './register-contracts/types.js';
|
|
14
15
|
export type { D8mArtifact, D8mGenerator, D8mJson, D8mFileEntry, D8mFileSymbol, D8mSegment, D8mSymbol, SymbolEntry, WriteD8mOptions, } from './outputs/types.js';
|
package/dist/src/index.js
CHANGED
|
@@ -3,5 +3,5 @@ export { compileArtifacts, compileNextArtifacts } from './core/compile-artifacts
|
|
|
3
3
|
export { formatDiagnostic, formatNextDiagnostic } from './diagnostics/format.js';
|
|
4
4
|
export { analyzeProgram, loadProgram, analyzeProgramNext, loadProgramNext } from './tooling/api.js';
|
|
5
5
|
export { DiagnosticIds } from './model/diagnostic.js';
|
|
6
|
-
export { analyzeRegisterCareForTools, } from './register-
|
|
6
|
+
export { analyzeRegisterCareForTools, analyzeRegisterContractsForTools, } from './register-contracts/tooling.js';
|
|
7
7
|
export { compile, defaultFormatWriters, writeHex } from './api-compile.js';
|
|
@@ -44,7 +44,11 @@ export declare const DiagnosticIds: {
|
|
|
44
44
|
readonly TypeError: "AZM403";
|
|
45
45
|
readonly CaseStyleLint: "AZM500";
|
|
46
46
|
readonly IndexParenRedundant: "AZM501";
|
|
47
|
+
readonly RegisterContractsConflict: "AZM600";
|
|
48
|
+
readonly RegisterContractsUnknownBoundary: "AZM601";
|
|
49
|
+
/** @deprecated Use RegisterContractsConflict. */
|
|
47
50
|
readonly RegisterCareConflict: "AZM600";
|
|
51
|
+
/** @deprecated Use RegisterContractsUnknownBoundary. */
|
|
48
52
|
readonly RegisterCareUnknownBoundary: "AZM601";
|
|
49
53
|
};
|
|
50
54
|
export type DiagnosticId = (typeof DiagnosticIds)[keyof typeof DiagnosticIds];
|
|
@@ -24,6 +24,10 @@ export const DiagnosticIds = {
|
|
|
24
24
|
TypeError: 'AZM403',
|
|
25
25
|
CaseStyleLint: 'AZM500',
|
|
26
26
|
IndexParenRedundant: 'AZM501',
|
|
27
|
+
RegisterContractsConflict: 'AZM600',
|
|
28
|
+
RegisterContractsUnknownBoundary: 'AZM601',
|
|
29
|
+
/** @deprecated Use RegisterContractsConflict. */
|
|
27
30
|
RegisterCareConflict: 'AZM600',
|
|
31
|
+
/** @deprecated Use RegisterContractsUnknownBoundary. */
|
|
28
32
|
RegisterCareUnknownBoundary: 'AZM601',
|
|
29
33
|
};
|
|
@@ -18,6 +18,7 @@ export async function expandSourceForTooling(options) {
|
|
|
18
18
|
}
|
|
19
19
|
const sourceTexts = new Map();
|
|
20
20
|
const sourceLineComments = new Map();
|
|
21
|
+
const loadedImports = new Set();
|
|
21
22
|
const includeDirs = (options.includeDirs ?? []).map((path) => normalize(path));
|
|
22
23
|
const lines = await expandFile({
|
|
23
24
|
sourcePath: entryFile,
|
|
@@ -25,7 +26,10 @@ export async function expandSourceForTooling(options) {
|
|
|
25
26
|
sourceTexts,
|
|
26
27
|
sourceLineComments,
|
|
27
28
|
diagnostics,
|
|
28
|
-
|
|
29
|
+
loadedImports,
|
|
30
|
+
sourceStack: [],
|
|
31
|
+
sourceUnit: entryFile,
|
|
32
|
+
sourceRelation: 'entry',
|
|
29
33
|
...(options.preloadedText !== undefined ? { preloadedText: options.preloadedText } : {}),
|
|
30
34
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
31
35
|
});
|
|
@@ -37,11 +41,11 @@ export async function expandSourceForTooling(options) {
|
|
|
37
41
|
async function expandFile(options) {
|
|
38
42
|
options.signal?.throwIfAborted();
|
|
39
43
|
const sourcePath = normalize(options.sourcePath);
|
|
40
|
-
if (options.
|
|
44
|
+
if (options.sourceStack.some((entry) => entry.sourcePath === sourcePath)) {
|
|
41
45
|
options.diagnostics.push({
|
|
42
46
|
severity: 'error',
|
|
43
47
|
code: 'AZMN_SOURCE',
|
|
44
|
-
message: `recursive
|
|
48
|
+
message: `recursive ${options.sourceRelation}: ${sourcePath}`,
|
|
45
49
|
sourceName: sourcePath,
|
|
46
50
|
});
|
|
47
51
|
return undefined;
|
|
@@ -54,28 +58,36 @@ async function expandFile(options) {
|
|
|
54
58
|
const output = [];
|
|
55
59
|
for (const line of scanLogicalLines(createSourceFile(sourcePath, text))) {
|
|
56
60
|
recordLineComment(options.sourceLineComments, line);
|
|
57
|
-
const
|
|
58
|
-
if (!
|
|
59
|
-
output.push(line);
|
|
61
|
+
const directive = parseSourceLoadDirective(line.text);
|
|
62
|
+
if (!directive) {
|
|
63
|
+
output.push(withSourceOwnership(line, options.sourceUnit, options.sourceRelation));
|
|
60
64
|
continue;
|
|
61
65
|
}
|
|
62
|
-
const result = await
|
|
66
|
+
const result = await resolveSourcePath(sourcePath, directive.path, options.includeDirs);
|
|
63
67
|
if (result.resolved === undefined) {
|
|
64
68
|
options.diagnostics.push({
|
|
65
69
|
severity: 'error',
|
|
66
70
|
code: 'AZMN_SOURCE',
|
|
67
|
-
message: `Failed to resolve
|
|
71
|
+
message: `Failed to resolve ${directive.kind} "${directive.path}" from "${sourcePath}". Tried:\n${result.searchCandidates.map((candidate) => `- ${candidate}`).join('\n')}`,
|
|
68
72
|
sourceName: sourcePath,
|
|
69
73
|
line: line.line,
|
|
70
74
|
column: firstColumn(line.text),
|
|
71
75
|
});
|
|
72
76
|
continue;
|
|
73
77
|
}
|
|
78
|
+
if (directive.kind === 'import' && options.loadedImports.has(result.resolved)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (directive.kind === 'import') {
|
|
82
|
+
options.loadedImports.add(result.resolved);
|
|
83
|
+
}
|
|
74
84
|
const { preloadedText: _preloadedText, ...includeOptions } = options;
|
|
75
85
|
const included = await expandFile({
|
|
76
86
|
...includeOptions,
|
|
77
87
|
sourcePath: result.resolved,
|
|
78
|
-
|
|
88
|
+
sourceStack: [...options.sourceStack, { sourcePath }],
|
|
89
|
+
sourceUnit: directive.kind === 'import' ? result.resolved : options.sourceUnit,
|
|
90
|
+
sourceRelation: directive.kind,
|
|
79
91
|
});
|
|
80
92
|
if (included !== undefined) {
|
|
81
93
|
output.push(...included);
|
|
@@ -83,6 +95,13 @@ async function expandFile(options) {
|
|
|
83
95
|
}
|
|
84
96
|
return output;
|
|
85
97
|
}
|
|
98
|
+
function withSourceOwnership(line, sourceUnit, sourceRelation) {
|
|
99
|
+
return {
|
|
100
|
+
...line,
|
|
101
|
+
sourceUnit,
|
|
102
|
+
sourceRelation,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
86
105
|
function recordLineComment(comments, line) {
|
|
87
106
|
const commentText = lineComment(line.text);
|
|
88
107
|
if (commentText === undefined) {
|
|
@@ -112,7 +131,7 @@ async function readSourceText(options, sourcePath) {
|
|
|
112
131
|
return undefined;
|
|
113
132
|
}
|
|
114
133
|
}
|
|
115
|
-
async function
|
|
134
|
+
async function resolveSourcePath(importer, includePath, includeDirs) {
|
|
116
135
|
const candidates = [
|
|
117
136
|
join(dirname(importer), includePath),
|
|
118
137
|
...includeDirs.map((dir) => join(dir, includePath)),
|
|
@@ -128,9 +147,17 @@ async function resolveInclude(importer, includePath, includeDirs) {
|
|
|
128
147
|
}
|
|
129
148
|
return { searchCandidates: candidates.map(normalize) };
|
|
130
149
|
}
|
|
131
|
-
function
|
|
132
|
-
const
|
|
133
|
-
|
|
150
|
+
function parseSourceLoadDirective(text) {
|
|
151
|
+
const trimmed = stripLineComment(text).trim();
|
|
152
|
+
const include = /^\.?include\s+"([^"]+)"\s*$/i.exec(trimmed);
|
|
153
|
+
if (include) {
|
|
154
|
+
return { kind: 'include', path: include[1] ?? '' };
|
|
155
|
+
}
|
|
156
|
+
const sourceImport = /^\.import\s+"([^"]+)"\s*$/.exec(trimmed);
|
|
157
|
+
if (sourceImport) {
|
|
158
|
+
return { kind: 'import', path: sourceImport[1] ?? '' };
|
|
159
|
+
}
|
|
160
|
+
return undefined;
|
|
134
161
|
}
|
|
135
162
|
function lineComment(text) {
|
|
136
163
|
const prefix = stripLineComment(text);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Expression } from '../model/expression.js';
|
|
2
|
+
import { type LayoutRecord } from '../semantics/expression-evaluation.js';
|
|
3
|
+
export type ConstantMap = ReadonlyMap<string, number>;
|
|
4
|
+
export type LayoutMap = ReadonlyMap<string, LayoutRecord>;
|
|
5
|
+
export type LoweredEvalContext = {
|
|
6
|
+
readonly constants: ConstantMap;
|
|
7
|
+
readonly symbols: ConstantMap;
|
|
8
|
+
readonly layouts: LayoutMap;
|
|
9
|
+
};
|
|
10
|
+
export declare function evaluateLoweredConstant(expression: Expression, evalContext: LoweredEvalContext): number | undefined;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { evaluateExpression, } from '../semantics/expression-evaluation.js';
|
|
2
|
+
import { applyBinaryOperator, applyByteFunction, applyUnaryOperator, } from '../semantics/constant-operators.js';
|
|
3
|
+
const silentSpan = { sourceName: '', line: 0, column: 0 };
|
|
4
|
+
export function evaluateLoweredConstant(expression, evalContext) {
|
|
5
|
+
switch (expression.kind) {
|
|
6
|
+
case 'number':
|
|
7
|
+
return expression.value;
|
|
8
|
+
case 'symbol':
|
|
9
|
+
return evalContext.constants.get(expression.name);
|
|
10
|
+
case 'type-size':
|
|
11
|
+
return evaluateLoweredTypeSize(expression, evalContext);
|
|
12
|
+
case 'offset':
|
|
13
|
+
case 'sizeof':
|
|
14
|
+
return evaluateLayoutExpression(expression, evalContext);
|
|
15
|
+
case 'byte-function':
|
|
16
|
+
return evaluateLoweredByteFunction(expression, evalContext);
|
|
17
|
+
case 'unary':
|
|
18
|
+
return evaluateLoweredUnary(expression, evalContext);
|
|
19
|
+
case 'binary':
|
|
20
|
+
return evaluateLoweredBinary(expression, evalContext);
|
|
21
|
+
default:
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function evaluateLoweredTypeSize(expression, evalContext) {
|
|
26
|
+
const constant = evalContext.constants.get(expression.typeExpr.name);
|
|
27
|
+
return constant ?? evaluateLayoutExpression(expression, evalContext);
|
|
28
|
+
}
|
|
29
|
+
function evaluateLayoutExpression(expression, evalContext) {
|
|
30
|
+
return evaluateExpression(expression, {}, new Map(), silentSpan, [], {
|
|
31
|
+
currentLocation: 0,
|
|
32
|
+
layouts: evalContext.layouts,
|
|
33
|
+
reportUnknown: false,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function evaluateLoweredByteFunction(expression, evalContext) {
|
|
37
|
+
const value = evaluateLoweredResolvedConstant(expression.expression, evalContext);
|
|
38
|
+
return value === undefined ? undefined : applyByteFunction(expression.function, value);
|
|
39
|
+
}
|
|
40
|
+
function evaluateLoweredUnary(expression, evalContext) {
|
|
41
|
+
const value = evaluateLoweredConstant(expression.expression, evalContext);
|
|
42
|
+
return value === undefined ? undefined : applyUnaryOperator(expression.operator, value);
|
|
43
|
+
}
|
|
44
|
+
function evaluateLoweredBinary(expression, evalContext) {
|
|
45
|
+
const left = evaluateLoweredConstant(expression.left, evalContext);
|
|
46
|
+
const right = evaluateLoweredConstant(expression.right, evalContext);
|
|
47
|
+
return left === undefined || right === undefined
|
|
48
|
+
? undefined
|
|
49
|
+
: applyBinaryOperator(expression.operator, left, right);
|
|
50
|
+
}
|
|
51
|
+
function evaluateLoweredResolvedConstant(expression, evalContext) {
|
|
52
|
+
switch (expression.kind) {
|
|
53
|
+
case 'symbol':
|
|
54
|
+
return evalContext.symbols.get(expression.name) ?? evalContext.constants.get(expression.name);
|
|
55
|
+
case 'unary':
|
|
56
|
+
return evaluateResolvedUnary(expression, evalContext);
|
|
57
|
+
case 'binary':
|
|
58
|
+
return evaluateResolvedBinary(expression, evalContext);
|
|
59
|
+
case 'byte-function':
|
|
60
|
+
return evaluateLoweredByteFunction(expression, evalContext);
|
|
61
|
+
default:
|
|
62
|
+
return evaluateLoweredConstant(expression, evalContext);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function evaluateResolvedUnary(expression, evalContext) {
|
|
66
|
+
const value = evaluateLoweredResolvedConstant(expression.expression, evalContext);
|
|
67
|
+
return value === undefined ? undefined : applyUnaryOperator(expression.operator, value);
|
|
68
|
+
}
|
|
69
|
+
function evaluateResolvedBinary(expression, evalContext) {
|
|
70
|
+
const left = evaluateLoweredResolvedConstant(expression.left, evalContext);
|
|
71
|
+
const right = evaluateLoweredResolvedConstant(expression.right, evalContext);
|
|
72
|
+
return left === undefined || right === undefined
|
|
73
|
+
? undefined
|
|
74
|
+
: applyBinaryOperator(expression.operator, left, right);
|
|
75
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Expression } from '../model/expression.js';
|
|
2
|
+
import { type LoweredEvalContext } from './asm80-expression-evaluation.js';
|
|
3
|
+
export { evaluateLoweredConstant, type ConstantMap, type LayoutMap, type LoweredEvalContext, } from './asm80-expression-evaluation.js';
|
|
4
|
+
export declare function formatExpression(expression: Expression, evalContext: LoweredEvalContext, width: 'byte' | 'word' | 'auto'): string | undefined;
|
|
5
|
+
export declare function formatLoweredNumber(value: number, width: 'byte' | 'word' | 'auto'): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { evaluateLoweredConstant } from './asm80-expression-evaluation.js';
|
|
2
|
+
export { evaluateLoweredConstant, } from './asm80-expression-evaluation.js';
|
|
3
|
+
const formatUnaryExpression = {
|
|
4
|
+
'+': (inner) => inner,
|
|
5
|
+
'-': (inner) => `-${inner}`,
|
|
6
|
+
'~': () => undefined,
|
|
7
|
+
};
|
|
8
|
+
export function formatExpression(expression, evalContext, width) {
|
|
9
|
+
const value = evaluateLoweredConstant(expression, evalContext);
|
|
10
|
+
if (value !== undefined) {
|
|
11
|
+
return formatLoweredNumber(value, width);
|
|
12
|
+
}
|
|
13
|
+
return formatUnevaluatedExpression(expression, evalContext, width);
|
|
14
|
+
}
|
|
15
|
+
export function formatLoweredNumber(value, width) {
|
|
16
|
+
const normalized = value < 0 ? value & 0xffff : value;
|
|
17
|
+
const digits = normalized.toString(16).toUpperCase();
|
|
18
|
+
const minWidth = width === 'word' || (width === 'auto' && normalized > 0xff) ? 4 : 2;
|
|
19
|
+
return `$${digits.padStart(minWidth, '0')}`;
|
|
20
|
+
}
|
|
21
|
+
function formatUnevaluatedExpression(expression, evalContext, width) {
|
|
22
|
+
switch (expression.kind) {
|
|
23
|
+
case 'symbol':
|
|
24
|
+
return expression.name;
|
|
25
|
+
case 'type-size':
|
|
26
|
+
return expression.typeExpr.name;
|
|
27
|
+
case 'current-location':
|
|
28
|
+
return '$';
|
|
29
|
+
case 'unary':
|
|
30
|
+
return formatUnary(expression, evalContext, width);
|
|
31
|
+
case 'binary':
|
|
32
|
+
return formatBinary(expression, evalContext, width);
|
|
33
|
+
default:
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function formatUnary(expression, evalContext, width) {
|
|
38
|
+
const inner = formatExpression(expression.expression, evalContext, width);
|
|
39
|
+
return inner === undefined ? undefined : formatUnaryExpression[expression.operator](inner);
|
|
40
|
+
}
|
|
41
|
+
function formatBinary(expression, evalContext, width) {
|
|
42
|
+
const left = formatExpression(expression.left, evalContext, width);
|
|
43
|
+
const right = formatExpression(expression.right, evalContext, width);
|
|
44
|
+
return left === undefined || right === undefined
|
|
45
|
+
? undefined
|
|
46
|
+
: `${left}${expression.operator}${right}`;
|
|
47
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Z80Instruction } from '../z80/instruction.js';
|
|
2
|
+
import { type LoweredEvalContext } from './asm80-expressions.js';
|
|
3
|
+
import { formatIndexedMemory, formatLd, type LdOperand } from './asm80-ld-operands.js';
|
|
4
|
+
export type BitInstruction = Extract<Z80Instruction, {
|
|
5
|
+
readonly mnemonic: 'bit' | 'res' | 'set';
|
|
6
|
+
}>;
|
|
7
|
+
export type RotateShiftInstruction = Extract<Z80Instruction, {
|
|
8
|
+
readonly mnemonic: 'rlc' | 'rrc' | 'rl' | 'rr' | 'sla' | 'sra' | 'sll' | 'sls' | 'srl';
|
|
9
|
+
}>;
|
|
10
|
+
export { formatIndexedMemory, formatLd, type LdOperand };
|
|
11
|
+
export declare function formatRotateShift(instruction: RotateShiftInstruction, evalContext: LoweredEvalContext): {
|
|
12
|
+
readonly text: string;
|
|
13
|
+
} | undefined;
|
|
14
|
+
export declare function formatBitOp(instruction: BitInstruction, evalContext: LoweredEvalContext): {
|
|
15
|
+
readonly text: string;
|
|
16
|
+
} | undefined;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { formatLoweredNumber } from './asm80-expressions.js';
|
|
2
|
+
import { formatIndexedMemory, formatLd } from './asm80-ld-operands.js';
|
|
3
|
+
export { formatIndexedMemory, formatLd };
|
|
4
|
+
export function formatRotateShift(instruction, evalContext) {
|
|
5
|
+
const operand = formatBitOperand(instruction.operand, evalContext);
|
|
6
|
+
if (operand === undefined) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const parts = [operand];
|
|
10
|
+
if (instruction.destination) {
|
|
11
|
+
parts.push(instruction.destination.register);
|
|
12
|
+
}
|
|
13
|
+
return { text: `${instruction.mnemonic} ${parts.join(', ')}` };
|
|
14
|
+
}
|
|
15
|
+
export function formatBitOp(instruction, evalContext) {
|
|
16
|
+
const bit = formatLoweredNumber(instruction.bit, 'byte');
|
|
17
|
+
const operand = formatBitOperand(instruction.operand, evalContext);
|
|
18
|
+
if (operand === undefined) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const parts = [bit, operand];
|
|
22
|
+
if (instruction.destination) {
|
|
23
|
+
parts.push(instruction.destination.register);
|
|
24
|
+
}
|
|
25
|
+
return { text: `${instruction.mnemonic} ${parts.join(', ')}` };
|
|
26
|
+
}
|
|
27
|
+
function formatBitOperand(operand, evalContext) {
|
|
28
|
+
if (operand.kind === 'reg8') {
|
|
29
|
+
return operand.register;
|
|
30
|
+
}
|
|
31
|
+
if (operand.kind === 'reg-indirect' && operand.register === 'hl') {
|
|
32
|
+
return '(HL)';
|
|
33
|
+
}
|
|
34
|
+
if (operand.kind === 'indexed') {
|
|
35
|
+
return formatIndexedMemory(operand.register, operand.displacement, evalContext);
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Z80Instruction } from '../z80/instruction.js';
|
|
2
|
+
import { type LoweredEvalContext } from './asm80-expressions.js';
|
|
3
|
+
export declare function formatInstruction(instruction: Z80Instruction, evalContext: LoweredEvalContext): {
|
|
4
|
+
readonly text: string;
|
|
5
|
+
} | undefined;
|