@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
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { buildRegisterCareProgramModel } from './programModel.js';
|
|
2
|
-
import { buildRoutineContracts, parseSmartComments } from './smartComments.js';
|
|
3
|
-
import { renderRegisterCareInterface, renderRegisterCareReport } from './report.js';
|
|
4
|
-
import { autoFixableCandidateKeys, findExpectOutFixesForCandidates } from './fix.js';
|
|
5
|
-
import { findCallerOutputCandidateObservations, findRegisterCareConflicts, } from './liveness.js';
|
|
6
|
-
import { buildAnnotations } from './annotations.js';
|
|
7
|
-
import { buildOutputCandidateFixability, buildProfileSummaries, buildProfileSummaryLookup, buildSummaries, buildSummaryByName, outputCandidateKey, routineNames, unknownBoundaryDiagnostics, unknownCallList, withAcceptedOutputs, } from './summaries.js';
|
|
8
|
-
function candidateMessageWithFixability(candidate, autoFixable) {
|
|
9
|
-
const carriers = candidate.carriers.join(',');
|
|
10
|
-
const expectation = candidate.carriers.length === 1 ? candidate.carriers[0] : `{${carriers}}`;
|
|
11
|
-
const base = `CALL ${candidate.routine} writes ${carriers} and caller reads it later`;
|
|
12
|
-
return autoFixable
|
|
13
|
-
? `${base}; generated contracts promote this to \`out ${expectation}\` automatically.`
|
|
14
|
-
: `${base}; manual review required before adding \`; expects out ${expectation}\` because the later read is not a simple direct continuation.`;
|
|
15
|
-
}
|
|
16
|
-
export function analyzeRegisterCare(loaded, options) {
|
|
17
|
-
const file = loaded.program.files[0];
|
|
18
|
-
const items = file?.items ?? [];
|
|
19
|
-
const program = buildRegisterCareProgramModel(items);
|
|
20
|
-
const smartComments = parseSmartComments(loaded.sourceLineComments);
|
|
21
|
-
const contractMap = buildRoutineContracts(smartComments, program.routines, loaded.sourceTexts);
|
|
22
|
-
if (options.interfaceContracts !== undefined) {
|
|
23
|
-
for (const contract of options.interfaceContracts) {
|
|
24
|
-
contractMap.set(contract.name, contract);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const profileSummaries = buildProfileSummaries(options.registerCareProfile);
|
|
28
|
-
let summaries = buildSummaries(program.routines, contractMap, profileSummaries);
|
|
29
|
-
summaries = withAcceptedOutputs(summaries, options.acceptedOutputCandidates);
|
|
30
|
-
let summariesByName = buildSummaryByName(program.routines, summaries, profileSummaries);
|
|
31
|
-
const knownRoutines = new Set(routineNames(program.routines));
|
|
32
|
-
for (const [name] of contractMap) {
|
|
33
|
-
knownRoutines.add(name);
|
|
34
|
-
}
|
|
35
|
-
for (const name of buildProfileSummaryLookup(options.registerCareProfile).keys()) {
|
|
36
|
-
knownRoutines.add(name);
|
|
37
|
-
}
|
|
38
|
-
const diagnostics = [];
|
|
39
|
-
const shouldBuildOutputCandidates = options.mode !== 'off' ||
|
|
40
|
-
options.emitAnnotations === true ||
|
|
41
|
-
options.fixRegisterContracts === true;
|
|
42
|
-
const outputCandidates = shouldBuildOutputCandidates
|
|
43
|
-
? findCallerOutputCandidateObservations(program.routines, summariesByName)
|
|
44
|
-
: [];
|
|
45
|
-
const autoAcceptedOutputs = autoAcceptedOutputCandidateMap(program.routines, outputCandidates, loaded.sourceTexts);
|
|
46
|
-
if (autoAcceptedOutputs.size > 0) {
|
|
47
|
-
summaries = withAcceptedOutputs(summaries, autoAcceptedOutputs);
|
|
48
|
-
summariesByName = buildSummaryByName(program.routines, summaries, profileSummaries);
|
|
49
|
-
}
|
|
50
|
-
const allSummaries = [...summaries, ...profileSummaries];
|
|
51
|
-
const conflicts = shouldBuildOutputCandidates
|
|
52
|
-
? program.routines.flatMap((routine) => findRegisterCareConflicts(routine, summariesByName, smartComments))
|
|
53
|
-
: [];
|
|
54
|
-
const outputCandidateFixability = buildOutputCandidateFixability(program.routines, outputCandidates, autoFixableCandidateKeys);
|
|
55
|
-
const outputCandidatesWithFixability = outputCandidates.map((candidate) => {
|
|
56
|
-
const autoFixable = outputCandidateFixability.get(outputCandidateKey(candidate.file, candidate.line, candidate.column)) ?? false;
|
|
57
|
-
return {
|
|
58
|
-
...candidate,
|
|
59
|
-
autoFixable,
|
|
60
|
-
message: candidateMessageWithFixability(candidate, autoFixable),
|
|
61
|
-
};
|
|
62
|
-
});
|
|
63
|
-
if (options.mode !== 'audit') {
|
|
64
|
-
for (const conflict of conflicts) {
|
|
65
|
-
diagnostics.push({
|
|
66
|
-
severity: options.mode === 'error' ? 'error' : 'warning',
|
|
67
|
-
code: 'AZMN_REGISTER_CARE',
|
|
68
|
-
sourceName: conflict.file,
|
|
69
|
-
line: conflict.line,
|
|
70
|
-
column: conflict.column,
|
|
71
|
-
message: conflict.message,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (options.mode === 'strict') {
|
|
76
|
-
diagnostics.push(...unknownBoundaryDiagnostics(program.directBoundaries, knownRoutines));
|
|
77
|
-
}
|
|
78
|
-
const reportModel = {
|
|
79
|
-
entryFile: loaded.program.entryFile,
|
|
80
|
-
mode: options.mode,
|
|
81
|
-
summaries: allSummaries,
|
|
82
|
-
conflicts,
|
|
83
|
-
outputCandidates: outputCandidatesWithFixability,
|
|
84
|
-
...(options.registerCareProfile !== undefined ? { profile: options.registerCareProfile } : {}),
|
|
85
|
-
unknownCalls: options.mode === 'off' ? [] : unknownCallList(program.directBoundaries, knownRoutines),
|
|
86
|
-
};
|
|
87
|
-
const summariesForAnnotations = new Map(summariesByName);
|
|
88
|
-
const outputCandidatesByRoutine = new Map();
|
|
89
|
-
for (const candidate of outputCandidatesWithFixability) {
|
|
90
|
-
const existing = outputCandidatesByRoutine.get(candidate.routine) ?? [];
|
|
91
|
-
for (const unit of candidate.carriers) {
|
|
92
|
-
if (!existing.includes(unit))
|
|
93
|
-
existing.push(unit);
|
|
94
|
-
}
|
|
95
|
-
outputCandidatesByRoutine.set(candidate.routine, existing);
|
|
96
|
-
}
|
|
97
|
-
for (const [name, summary] of summariesForAnnotations) {
|
|
98
|
-
const candidates = outputCandidatesByRoutine.get(name);
|
|
99
|
-
if (candidates !== undefined && candidates.length > 0) {
|
|
100
|
-
summariesForAnnotations.set(name, { ...summary, outputCandidates: candidates });
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
const annotations = options.emitAnnotations
|
|
104
|
-
? buildAnnotations(loaded, program.routines, summariesForAnnotations, outputCandidatesWithFixability, {
|
|
105
|
-
fixOutputCandidates: options.fixRegisterContracts === true,
|
|
106
|
-
outputCandidateFixability,
|
|
107
|
-
outputCandidateKey,
|
|
108
|
-
})
|
|
109
|
-
: [];
|
|
110
|
-
return {
|
|
111
|
-
diagnostics,
|
|
112
|
-
outputCandidates: outputCandidatesWithFixability,
|
|
113
|
-
...(options.emitReport ? { reportText: renderRegisterCareReport(reportModel) } : {}),
|
|
114
|
-
...(options.emitInterface ? { interfaceText: renderRegisterCareInterface(summaries) } : {}),
|
|
115
|
-
...(annotations.length > 0 ? { annotations } : {}),
|
|
116
|
-
...(reportModel.unknownCalls.length > 0 ? { unknownCalls: reportModel.unknownCalls } : {}),
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function autoAcceptedOutputCandidateMap(routines, outputCandidates, sourceTexts) {
|
|
120
|
-
const out = new Map();
|
|
121
|
-
const sourceMaybeOut = sourceMaybeOutByRoutine(routines, sourceTexts);
|
|
122
|
-
for (const fix of findExpectOutFixesForCandidates([...routines], [...outputCandidates])) {
|
|
123
|
-
const declaredMaybeOut = sourceMaybeOut.get(fix.routine) ?? [];
|
|
124
|
-
const eligibleCarriers = fix.carriers.filter((carrier) => declaredMaybeOut.includes(carrier));
|
|
125
|
-
if (eligibleCarriers.length === 0)
|
|
126
|
-
continue;
|
|
127
|
-
const carriers = out.get(fix.routine) ?? [];
|
|
128
|
-
for (const carrier of eligibleCarriers) {
|
|
129
|
-
if (!carriers.includes(carrier))
|
|
130
|
-
carriers.push(carrier);
|
|
131
|
-
}
|
|
132
|
-
out.set(fix.routine, carriers);
|
|
133
|
-
}
|
|
134
|
-
return out;
|
|
135
|
-
}
|
|
136
|
-
function sourceMaybeOutByRoutine(routines, sourceTexts) {
|
|
137
|
-
const out = new Map();
|
|
138
|
-
for (const routine of routines) {
|
|
139
|
-
const source = sourceTexts.get(routine.span.file);
|
|
140
|
-
if (source === undefined)
|
|
141
|
-
continue;
|
|
142
|
-
const lines = source.split(/\r?\n/);
|
|
143
|
-
const units = [];
|
|
144
|
-
for (let index = routine.span.start.line - 2; index >= 0; index -= 1) {
|
|
145
|
-
const text = lines[index] ?? '';
|
|
146
|
-
if (!/^\s*;/.test(text))
|
|
147
|
-
break;
|
|
148
|
-
const match = /^\s*;\s*!\s*maybe-out\s+(.+)$/i.exec(text);
|
|
149
|
-
if (!match)
|
|
150
|
-
continue;
|
|
151
|
-
for (const token of match[1].split(',')) {
|
|
152
|
-
const unit = token.trim();
|
|
153
|
-
if (unit.length > 0 && !units.includes(unit))
|
|
154
|
-
units.push(unit);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (units.length === 0)
|
|
158
|
-
continue;
|
|
159
|
-
out.set(routine.name, units);
|
|
160
|
-
for (const label of routine.labels)
|
|
161
|
-
out.set(label, units);
|
|
162
|
-
for (const label of routine.entryLabels)
|
|
163
|
-
out.set(label, units);
|
|
164
|
-
}
|
|
165
|
-
return out;
|
|
166
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { RegisterCareRoutine, RoutineSummary } from './types.js';
|
|
2
|
-
export interface RegisterCareAnnotatedFile {
|
|
3
|
-
path: string;
|
|
4
|
-
text: string;
|
|
5
|
-
}
|
|
6
|
-
interface RegisterCareAnnotationInput {
|
|
7
|
-
routine: RegisterCareRoutine;
|
|
8
|
-
summary: RoutineSummary;
|
|
9
|
-
}
|
|
10
|
-
export declare function annotateRegisterCareContracts(sourceTexts: ReadonlyMap<string, string>, routines: RegisterCareAnnotationInput[]): RegisterCareAnnotatedFile[];
|
|
11
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { RegisterCareAnnotationFile, RegisterCareOutputCandidate, RegisterCareRoutine, RoutineSummary } from './types.js';
|
|
2
|
-
export declare function buildAnnotations(loaded: {
|
|
3
|
-
sourceTexts: ReadonlyMap<string, string>;
|
|
4
|
-
}, programRoutines: readonly RegisterCareRoutine[], summariesByName: ReadonlyMap<string, RoutineSummary>, outputCandidates: readonly RegisterCareOutputCandidate[], options: {
|
|
5
|
-
fixOutputCandidates: boolean;
|
|
6
|
-
outputCandidateFixability: ReadonlyMap<string, boolean>;
|
|
7
|
-
outputCandidateKey: (file: string, line: number, column: number) => string;
|
|
8
|
-
}): readonly RegisterCareAnnotationFile[];
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { RegisterCareInstruction } from './types.js';
|
|
2
|
-
export declare function precedingCServiceName(item: RegisterCareInstruction | undefined): string | undefined;
|
|
3
|
-
export declare function precedingRegisterImmediateValue(item: RegisterCareInstruction | undefined, register: string): number | undefined;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
export function precedingCServiceName(item) {
|
|
2
|
-
const instruction = item?.instruction;
|
|
3
|
-
if (!instruction || instruction.mnemonic !== 'ld')
|
|
4
|
-
return undefined;
|
|
5
|
-
if (instruction.target?.kind !== 'reg8' || instruction.target.register !== 'c')
|
|
6
|
-
return undefined;
|
|
7
|
-
if (instruction.source.kind === 'imm' && instruction.source.expression.kind === 'symbol') {
|
|
8
|
-
return instruction.source.expression.name;
|
|
9
|
-
}
|
|
10
|
-
return undefined;
|
|
11
|
-
}
|
|
12
|
-
function evaluateKnownConstant(expression, constants) {
|
|
13
|
-
switch (expression.kind) {
|
|
14
|
-
case 'number':
|
|
15
|
-
return expression.value;
|
|
16
|
-
case 'symbol':
|
|
17
|
-
return constants.get(expression.name);
|
|
18
|
-
case 'unary': {
|
|
19
|
-
const value = evaluateKnownConstant(expression.expression, constants);
|
|
20
|
-
if (value === undefined)
|
|
21
|
-
return undefined;
|
|
22
|
-
switch (expression.operator) {
|
|
23
|
-
case '+':
|
|
24
|
-
return value;
|
|
25
|
-
case '-':
|
|
26
|
-
return -value;
|
|
27
|
-
case '~':
|
|
28
|
-
return ~value;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
case 'binary': {
|
|
32
|
-
const left = evaluateKnownConstant(expression.left, constants);
|
|
33
|
-
const right = evaluateKnownConstant(expression.right, constants);
|
|
34
|
-
if (left === undefined || right === undefined)
|
|
35
|
-
return undefined;
|
|
36
|
-
switch (expression.operator) {
|
|
37
|
-
case '+':
|
|
38
|
-
return left + right;
|
|
39
|
-
case '-':
|
|
40
|
-
return left - right;
|
|
41
|
-
case '*':
|
|
42
|
-
return left * right;
|
|
43
|
-
case '/':
|
|
44
|
-
return right === 0 ? undefined : Math.trunc(left / right);
|
|
45
|
-
case '%':
|
|
46
|
-
return right === 0 ? undefined : left % right;
|
|
47
|
-
case '&':
|
|
48
|
-
return left & right;
|
|
49
|
-
case '^':
|
|
50
|
-
return left ^ right;
|
|
51
|
-
case '|':
|
|
52
|
-
return left | right;
|
|
53
|
-
case '<<':
|
|
54
|
-
return left << right;
|
|
55
|
-
case '>>':
|
|
56
|
-
return left >> right;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
case 'byte-function': {
|
|
60
|
-
const value = evaluateKnownConstant(expression.expression, constants);
|
|
61
|
-
if (value === undefined)
|
|
62
|
-
return undefined;
|
|
63
|
-
return expression.function === 'LSB' ? value & 0xff : (value >> 8) & 0xff;
|
|
64
|
-
}
|
|
65
|
-
default:
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
export function precedingRegisterImmediateValue(item, register) {
|
|
70
|
-
const instruction = item?.instruction;
|
|
71
|
-
if (!instruction || instruction.mnemonic !== 'ld')
|
|
72
|
-
return undefined;
|
|
73
|
-
if (instruction.target?.kind !== 'reg8' ||
|
|
74
|
-
instruction.target.register !== register.toLowerCase()) {
|
|
75
|
-
return undefined;
|
|
76
|
-
}
|
|
77
|
-
if (instruction.source.kind !== 'imm')
|
|
78
|
-
return undefined;
|
|
79
|
-
return evaluateKnownConstant(instruction.source.expression, item.constants ?? new Map());
|
|
80
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { InstructionEffect, RegisterCareRoutine } from './types.js';
|
|
2
|
-
export declare function labelIndex(routine: RegisterCareRoutine): Map<string, number>;
|
|
3
|
-
export declare function instructionSuccessors(routine: RegisterCareRoutine, index: number, effect: InstructionEffect, labels: ReadonlyMap<string, number>, options?: {
|
|
4
|
-
boundaryFallthrough?: boolean;
|
|
5
|
-
}): number[];
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
function unique(items) {
|
|
2
|
-
return [...new Set(items)];
|
|
3
|
-
}
|
|
4
|
-
export function labelIndex(routine) {
|
|
5
|
-
const out = new Map();
|
|
6
|
-
routine.instructions.forEach((item, index) => {
|
|
7
|
-
for (const label of item.labels)
|
|
8
|
-
out.set(label, index);
|
|
9
|
-
});
|
|
10
|
-
return out;
|
|
11
|
-
}
|
|
12
|
-
function localTargetIndex(labels, target) {
|
|
13
|
-
if (!target)
|
|
14
|
-
return undefined;
|
|
15
|
-
return labels.get(target);
|
|
16
|
-
}
|
|
17
|
-
export function instructionSuccessors(routine, index, effect, labels, options = {}) {
|
|
18
|
-
const next = index + 1 < routine.instructions.length ? index + 1 : undefined;
|
|
19
|
-
if (effect.control.kind === 'fallthrough' ||
|
|
20
|
-
(options.boundaryFallthrough &&
|
|
21
|
-
(effect.control.kind === 'call' || effect.control.kind === 'rst'))) {
|
|
22
|
-
return next === undefined ? [] : [next];
|
|
23
|
-
}
|
|
24
|
-
if (effect.control.kind === 'jump') {
|
|
25
|
-
const target = localTargetIndex(labels, effect.control.target);
|
|
26
|
-
if (effect.control.conditional) {
|
|
27
|
-
return unique([
|
|
28
|
-
...(target === undefined ? [] : [target]),
|
|
29
|
-
...(next === undefined ? [] : [next]),
|
|
30
|
-
]);
|
|
31
|
-
}
|
|
32
|
-
return target === undefined ? [] : [target];
|
|
33
|
-
}
|
|
34
|
-
if (effect.control.kind === 'return') {
|
|
35
|
-
return effect.control.conditional && next !== undefined ? [next] : [];
|
|
36
|
-
}
|
|
37
|
-
return [];
|
|
38
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { RegisterCareOutputCandidate, RegisterCareRoutine, RegisterCareUnit } from './types.js';
|
|
2
|
-
export interface RegisterCareExpectOutFix {
|
|
3
|
-
file: string;
|
|
4
|
-
line: number;
|
|
5
|
-
column: number;
|
|
6
|
-
routine: string;
|
|
7
|
-
carriers: RegisterCareUnit[];
|
|
8
|
-
}
|
|
9
|
-
export declare function findExpectOutFixesForCandidates(routines: RegisterCareRoutine[], candidates: RegisterCareOutputCandidate[]): RegisterCareExpectOutFix[];
|
|
10
|
-
export declare function autoFixableCandidateKeys(routines: RegisterCareRoutine[], candidates: RegisterCareOutputCandidate[]): Set<string>;
|
|
11
|
-
export declare function applyExpectOutFixesToSource(source: string, fixes: RegisterCareExpectOutFix[], referenceSource?: string): string;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Z80Instruction, Z80Operand } from '../z80/instruction.js';
|
|
2
|
-
import type { RegisterCareInstruction } from './types.js';
|
|
3
|
-
export declare function instructionHead(item: RegisterCareInstruction): string;
|
|
4
|
-
export declare function regName(operand: Z80Operand | undefined): string | undefined;
|
|
5
|
-
export declare function instructionOperandCount(instruction: Z80Instruction): number;
|
|
6
|
-
export declare function instructionOperand(instruction: Z80Instruction, index: number): Z80Operand | undefined;
|
|
7
|
-
export declare function isUnconditionalReturnInstruction(item: RegisterCareInstruction): boolean;
|
|
8
|
-
export declare function isPureTokenTransferInstruction(item: RegisterCareInstruction): boolean;
|
|
9
|
-
export declare function isAccumulatorSelfOperand(item: RegisterCareInstruction): boolean;
|
|
10
|
-
export declare function isImmediateZeroOperand(item: RegisterCareInstruction): boolean;
|
|
11
|
-
export declare function isRegisterOperand(item: RegisterCareInstruction | undefined, index: number, name: string): boolean;
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
export function instructionHead(item) {
|
|
2
|
-
return item.instruction.mnemonic.toLowerCase();
|
|
3
|
-
}
|
|
4
|
-
export function regName(operand) {
|
|
5
|
-
if (operand === undefined)
|
|
6
|
-
return undefined;
|
|
7
|
-
switch (operand.kind) {
|
|
8
|
-
case 'reg8':
|
|
9
|
-
return operand.register.toUpperCase();
|
|
10
|
-
case 'reg16':
|
|
11
|
-
return operand.register.toUpperCase();
|
|
12
|
-
case 'reg-index16':
|
|
13
|
-
return operand.register.toUpperCase();
|
|
14
|
-
case 'reg-half-index':
|
|
15
|
-
return operand.register.toUpperCase();
|
|
16
|
-
default:
|
|
17
|
-
return undefined;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function immValue(operand) {
|
|
21
|
-
if (operand?.kind !== 'imm')
|
|
22
|
-
return undefined;
|
|
23
|
-
const expression = operand.expression;
|
|
24
|
-
return expression.kind === 'number' ? expression.value : undefined;
|
|
25
|
-
}
|
|
26
|
-
export function instructionOperandCount(instruction) {
|
|
27
|
-
switch (instruction.mnemonic) {
|
|
28
|
-
case 'ret':
|
|
29
|
-
case 'ret-cc':
|
|
30
|
-
return instruction.mnemonic === 'ret' ? 0 : 1;
|
|
31
|
-
case 'ld':
|
|
32
|
-
return 2;
|
|
33
|
-
case 'ex':
|
|
34
|
-
return 2;
|
|
35
|
-
case 'jp':
|
|
36
|
-
case 'jp-cc':
|
|
37
|
-
case 'jr':
|
|
38
|
-
case 'jr-cc':
|
|
39
|
-
case 'djnz':
|
|
40
|
-
case 'call':
|
|
41
|
-
case 'call-cc':
|
|
42
|
-
return 1;
|
|
43
|
-
case 'add':
|
|
44
|
-
case 'adc':
|
|
45
|
-
case 'sbc':
|
|
46
|
-
return 'target' in instruction ? 2 : 1;
|
|
47
|
-
case 'sub':
|
|
48
|
-
case 'and':
|
|
49
|
-
case 'or':
|
|
50
|
-
case 'xor':
|
|
51
|
-
case 'cp':
|
|
52
|
-
return 1;
|
|
53
|
-
default:
|
|
54
|
-
return 0;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
export function instructionOperand(instruction, index) {
|
|
58
|
-
switch (instruction.mnemonic) {
|
|
59
|
-
case 'ld':
|
|
60
|
-
return index === 0 ? instruction.target : index === 1 ? instruction.source : undefined;
|
|
61
|
-
case 'ex': {
|
|
62
|
-
if (index === 0) {
|
|
63
|
-
return instruction.form === 'de-hl'
|
|
64
|
-
? { kind: 'reg16', register: 'de' }
|
|
65
|
-
: instruction.form === 'af-af'
|
|
66
|
-
? { kind: 'reg16', register: 'af' }
|
|
67
|
-
: undefined;
|
|
68
|
-
}
|
|
69
|
-
if (index === 1) {
|
|
70
|
-
return instruction.form === 'de-hl'
|
|
71
|
-
? { kind: 'reg16', register: 'hl' }
|
|
72
|
-
: undefined;
|
|
73
|
-
}
|
|
74
|
-
return undefined;
|
|
75
|
-
}
|
|
76
|
-
case 'add':
|
|
77
|
-
case 'adc':
|
|
78
|
-
case 'sbc':
|
|
79
|
-
if ('target' in instruction) {
|
|
80
|
-
return index === 0 ? instruction.target : index === 1 ? instruction.source : undefined;
|
|
81
|
-
}
|
|
82
|
-
return index === 0 ? instruction.source : undefined;
|
|
83
|
-
case 'sub':
|
|
84
|
-
case 'and':
|
|
85
|
-
case 'or':
|
|
86
|
-
case 'xor':
|
|
87
|
-
case 'cp':
|
|
88
|
-
return index === 0 ? instruction.source : undefined;
|
|
89
|
-
default:
|
|
90
|
-
return undefined;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
export function isUnconditionalReturnInstruction(item) {
|
|
94
|
-
const head = instructionHead(item);
|
|
95
|
-
if (head === 'ret')
|
|
96
|
-
return item.instruction.mnemonic === 'ret';
|
|
97
|
-
return head === 'retn' || head === 'reti';
|
|
98
|
-
}
|
|
99
|
-
export function isPureTokenTransferInstruction(item) {
|
|
100
|
-
const head = instructionHead(item);
|
|
101
|
-
if (head === 'ex')
|
|
102
|
-
return true;
|
|
103
|
-
if (head !== 'ld' || instructionOperandCount(item.instruction) !== 2)
|
|
104
|
-
return false;
|
|
105
|
-
const dst = instructionOperand(item.instruction, 0);
|
|
106
|
-
const src = instructionOperand(item.instruction, 1);
|
|
107
|
-
if (regName(dst) === undefined)
|
|
108
|
-
return false;
|
|
109
|
-
return regName(src) !== undefined || src?.kind === 'imm';
|
|
110
|
-
}
|
|
111
|
-
export function isAccumulatorSelfOperand(item) {
|
|
112
|
-
const inst = item.instruction;
|
|
113
|
-
if (inst.mnemonic === 'or' || inst.mnemonic === 'and' || inst.mnemonic === 'xor') {
|
|
114
|
-
return inst.source.kind === 'reg8' && inst.source.register === 'a';
|
|
115
|
-
}
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
export function isImmediateZeroOperand(item) {
|
|
119
|
-
const inst = item.instruction;
|
|
120
|
-
if (inst.mnemonic !== 'cp')
|
|
121
|
-
return false;
|
|
122
|
-
return immValue(inst.source) === 0;
|
|
123
|
-
}
|
|
124
|
-
export function isRegisterOperand(item, index, name) {
|
|
125
|
-
if (item === undefined)
|
|
126
|
-
return false;
|
|
127
|
-
const operand = instructionOperand(item.instruction, index);
|
|
128
|
-
return regName(operand) === name.toUpperCase();
|
|
129
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { LocatedSmartComment, RegisterCareConflict, RegisterCareOutputCandidate, RegisterCareRoutine, RoutineSummary } from './types.js';
|
|
2
|
-
export declare function findRegisterCareConflicts(routine: RegisterCareRoutine, summaries: Map<string, RoutineSummary>, hints: LocatedSmartComment[]): RegisterCareConflict[];
|
|
3
|
-
export declare function findCallerOutputCandidateObservations(routines: RegisterCareRoutine[], summaries: Map<string, RoutineSummary>): RegisterCareOutputCandidate[];
|