@jhlagado/azm 0.2.7 → 0.2.8
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 +170 -69
- 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 +31 -230
- 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/fixup-emission.js +30 -48
- 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/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 +68 -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 +128 -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/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 +14 -0
- package/dist/src/syntax/parse-directive-statement.js +307 -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 +180 -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 +4 -272
- 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/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/reference/cli.md +42 -35
- package/docs/reference/tooling-api.md +20 -16
- package/package.json +1 -1
- 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/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
|
@@ -7,36 +7,53 @@ function unique(units) {
|
|
|
7
7
|
}
|
|
8
8
|
function boundaryTarget(routine, index, effect) {
|
|
9
9
|
const item = routine.instructions[index];
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
return (callBoundaryTarget(effect) ??
|
|
11
|
+
tailJumpBoundaryTarget(item, effect) ??
|
|
12
|
+
rstBoundaryTarget(routine, index, effect));
|
|
13
|
+
}
|
|
14
|
+
function callBoundaryTarget(effect) {
|
|
15
|
+
return effect.control.kind === 'call' && effect.control.target
|
|
16
|
+
? {
|
|
12
17
|
targets: [effect.control.target],
|
|
13
18
|
conditional: effect.control.conditional,
|
|
14
19
|
subject: `CALL ${effect.control.target}`,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
}
|
|
21
|
+
: undefined;
|
|
22
|
+
}
|
|
23
|
+
function tailJumpBoundaryTarget(item, effect) {
|
|
24
|
+
if (!isTailJumpBoundary(item, effect))
|
|
25
|
+
return undefined;
|
|
26
|
+
return {
|
|
27
|
+
targets: [effect.control.target],
|
|
28
|
+
conditional: false,
|
|
29
|
+
subject: `JP ${effect.control.target}`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function isTailJumpBoundary(item, effect) {
|
|
33
|
+
return (effect.control.kind === 'jump' &&
|
|
18
34
|
item?.instruction.mnemonic === 'jp' &&
|
|
19
35
|
!effect.control.conditional &&
|
|
20
|
-
effect.control.target &&
|
|
21
|
-
!effect.control.target.startsWith('.'))
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
effect.control.target !== undefined &&
|
|
37
|
+
!effect.control.target.startsWith('.'));
|
|
38
|
+
}
|
|
39
|
+
function rstBoundaryTarget(routine, index, effect) {
|
|
40
|
+
if (effect.control.kind !== 'rst' || effect.control.vector === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
const target = rstTargetName(effect.control.vector);
|
|
43
|
+
return {
|
|
44
|
+
targets: rstBoundaryTargets(routine, index, effect.control.vector, target),
|
|
45
|
+
conditional: false,
|
|
46
|
+
subject: target,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function rstBoundaryTargets(routine, index, vector, fallbackTarget) {
|
|
50
|
+
const previous = routine.instructions[index - 1];
|
|
51
|
+
const service = precedingCServiceName(previous);
|
|
52
|
+
return [
|
|
53
|
+
...rstDispatcherServiceTargetNames(vector, (register) => precedingRegisterImmediateValue(previous, register)),
|
|
54
|
+
...(service ? [rstServiceTargetName(vector, service)] : []),
|
|
55
|
+
fallbackTarget,
|
|
56
|
+
];
|
|
40
57
|
}
|
|
41
58
|
function summaryForBoundary(boundary, summaries) {
|
|
42
59
|
for (const target of boundary.targets) {
|
|
@@ -70,50 +87,59 @@ function unionLive(sets) {
|
|
|
70
87
|
return out;
|
|
71
88
|
}
|
|
72
89
|
function transferLiveBefore(item, effect, boundary, summary, liveAfter, hints) {
|
|
90
|
+
const live = liveBeforeBoundary(item, boundary, summary, liveAfter, hints);
|
|
91
|
+
removeInstructionWrites(live, effect);
|
|
92
|
+
addInstructionReads(live, item, effect, liveAfter);
|
|
93
|
+
return live;
|
|
94
|
+
}
|
|
95
|
+
function liveBeforeBoundary(item, boundary, summary, liveAfter, hints) {
|
|
73
96
|
const live = new Set(liveAfter);
|
|
74
97
|
if (boundary && summary) {
|
|
75
|
-
|
|
76
|
-
for (const unit of hintUnitsForLine(hints, item.file, item.line))
|
|
77
|
-
accepted.add(unit);
|
|
78
|
-
for (const unit of outputUnits(summary))
|
|
79
|
-
accepted.add(unit);
|
|
80
|
-
if (!boundary.conditional) {
|
|
81
|
-
for (const unit of summary.mayWrite)
|
|
82
|
-
live.delete(unit);
|
|
83
|
-
for (const unit of accepted)
|
|
84
|
-
live.delete(unit);
|
|
85
|
-
}
|
|
86
|
-
for (const unit of summary.mayRead)
|
|
87
|
-
live.add(unit);
|
|
98
|
+
applyBoundarySummary(live, item, boundary, summary, hints);
|
|
88
99
|
}
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
return live;
|
|
101
|
+
}
|
|
102
|
+
function applyBoundarySummary(live, item, boundary, summary, hints) {
|
|
103
|
+
const accepted = acceptedOutputUnits(item, summary, hints);
|
|
104
|
+
if (!boundary.conditional) {
|
|
105
|
+
for (const unit of summary.mayWrite)
|
|
106
|
+
live.delete(unit);
|
|
107
|
+
for (const unit of accepted)
|
|
108
|
+
live.delete(unit);
|
|
109
|
+
}
|
|
110
|
+
for (const unit of summary.mayRead)
|
|
111
|
+
live.add(unit);
|
|
112
|
+
}
|
|
113
|
+
function acceptedOutputUnits(item, summary, hints) {
|
|
114
|
+
return new Set([...hintUnitsForLine(hints, item.file, item.line), ...outputUnits(summary)]);
|
|
115
|
+
}
|
|
116
|
+
function removeInstructionWrites(live, effect) {
|
|
117
|
+
if (!instructionWritesAreConditional(effect)) {
|
|
91
118
|
for (const unit of effect.writes)
|
|
92
119
|
live.delete(unit);
|
|
93
120
|
}
|
|
121
|
+
}
|
|
122
|
+
function instructionWritesAreConditional(effect) {
|
|
123
|
+
return effect.control.kind === 'call' && effect.control.conditional;
|
|
124
|
+
}
|
|
125
|
+
function addInstructionReads(live, item, effect, liveAfter) {
|
|
94
126
|
for (const unit of semanticReadsForLiveness(item, effect, liveAfter))
|
|
95
127
|
live.add(unit);
|
|
96
|
-
return live;
|
|
97
128
|
}
|
|
98
129
|
function semanticReadsForLiveness(item, effect, liveAfter) {
|
|
99
|
-
if (item
|
|
100
|
-
item.instruction.source.kind === 'reg8' &&
|
|
101
|
-
item.instruction.source.register === 'a' &&
|
|
102
|
-
!liveAfter.has('zero') &&
|
|
103
|
-
!liveAfter.has('sign') &&
|
|
104
|
-
!liveAfter.has('parity')) {
|
|
105
|
-
return effect.reads.filter((unit) => unit !== 'A');
|
|
106
|
-
}
|
|
107
|
-
if (item.instruction.mnemonic === 'and' &&
|
|
108
|
-
item.instruction.source.kind === 'reg8' &&
|
|
109
|
-
item.instruction.source.register === 'a' &&
|
|
110
|
-
!liveAfter.has('zero') &&
|
|
111
|
-
!liveAfter.has('sign') &&
|
|
112
|
-
!liveAfter.has('parity')) {
|
|
130
|
+
if (isAccumulatorFlagRefresh(item) && !hasAccumulatorDerivedFlags(liveAfter)) {
|
|
113
131
|
return effect.reads.filter((unit) => unit !== 'A');
|
|
114
132
|
}
|
|
115
133
|
return effect.reads;
|
|
116
134
|
}
|
|
135
|
+
function isAccumulatorFlagRefresh(item) {
|
|
136
|
+
return ((item.instruction.mnemonic === 'or' || item.instruction.mnemonic === 'and') &&
|
|
137
|
+
item.instruction.source.kind === 'reg8' &&
|
|
138
|
+
item.instruction.source.register === 'a');
|
|
139
|
+
}
|
|
140
|
+
function hasAccumulatorDerivedFlags(liveAfter) {
|
|
141
|
+
return liveAfter.has('zero') || liveAfter.has('sign') || liveAfter.has('parity');
|
|
142
|
+
}
|
|
117
143
|
function liveSetsForRoutine(routine, summaries, hints = []) {
|
|
118
144
|
const labels = labelIndex(routine);
|
|
119
145
|
const effects = routine.instructions.map((item) => getZ80InstructionEffect(item.instruction));
|
|
@@ -157,7 +183,7 @@ function resolvedBoundariesForRoutine(routine, summaries) {
|
|
|
157
183
|
}
|
|
158
184
|
return out;
|
|
159
185
|
}
|
|
160
|
-
export function
|
|
186
|
+
export function findRegisterContractsConflicts(routine, summaries, hints) {
|
|
161
187
|
const conflicts = [];
|
|
162
188
|
const { liveOut } = liveSetsForRoutine(routine, summaries, hints);
|
|
163
189
|
for (const { item, index, boundary, target, summary } of resolvedBoundariesForRoutine(routine, summaries)) {
|
|
@@ -190,30 +216,36 @@ export function findCallerOutputCandidateObservations(routines, summaries) {
|
|
|
190
216
|
for (const routine of routines) {
|
|
191
217
|
const { liveOut } = liveSetsForRoutine(routine, summaries);
|
|
192
218
|
for (const { item, index, boundary, target, summary } of resolvedBoundariesForRoutine(routine, summaries)) {
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (liveOut[index].has(unit) && !intentionalOutputs.has(unit)) {
|
|
197
|
-
carrierSources.push(unit);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
for (const unit of intentionalOutputs) {
|
|
201
|
-
if (liveOut[index].has(unit)) {
|
|
202
|
-
carrierSources.push(unit);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
const carriers = unique(carrierSources);
|
|
206
|
-
if (carriers.length > 0) {
|
|
207
|
-
out.push({
|
|
208
|
-
file: item.file,
|
|
209
|
-
line: item.line,
|
|
210
|
-
column: item.column,
|
|
211
|
-
routine: target,
|
|
212
|
-
carriers,
|
|
213
|
-
message: candidateMessage(boundary, carriers),
|
|
214
|
-
});
|
|
215
|
-
}
|
|
219
|
+
const candidate = callerOutputCandidate(item, boundary, target, summary, liveOut[index]);
|
|
220
|
+
if (candidate)
|
|
221
|
+
out.push(candidate);
|
|
216
222
|
}
|
|
217
223
|
}
|
|
218
224
|
return out;
|
|
219
225
|
}
|
|
226
|
+
function callerOutputCandidate(item, boundary, target, summary, liveAfter) {
|
|
227
|
+
const carriers = callerOutputCandidateCarriers(summary, liveAfter);
|
|
228
|
+
return carriers.length > 0
|
|
229
|
+
? {
|
|
230
|
+
file: item.file,
|
|
231
|
+
line: item.line,
|
|
232
|
+
column: item.column,
|
|
233
|
+
routine: target,
|
|
234
|
+
carriers,
|
|
235
|
+
message: candidateMessage(boundary, carriers),
|
|
236
|
+
}
|
|
237
|
+
: undefined;
|
|
238
|
+
}
|
|
239
|
+
function callerOutputCandidateCarriers(summary, liveAfter) {
|
|
240
|
+
const intentionalOutputs = new Set(outputUnits(summary));
|
|
241
|
+
return unique([
|
|
242
|
+
...unintentionalLiveWrites(summary, intentionalOutputs, liveAfter),
|
|
243
|
+
...intentionalLiveOutputs(intentionalOutputs, liveAfter),
|
|
244
|
+
]);
|
|
245
|
+
}
|
|
246
|
+
function unintentionalLiveWrites(summary, intentionalOutputs, liveAfter) {
|
|
247
|
+
return summary.mayWrite.filter((unit) => liveAfter.has(unit) && !intentionalOutputs.has(unit));
|
|
248
|
+
}
|
|
249
|
+
function intentionalLiveOutputs(intentionalOutputs, liveAfter) {
|
|
250
|
+
return [...intentionalOutputs].filter((unit) => liveAfter.has(unit));
|
|
251
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function regName(operand) {
|
|
2
|
+
if (operand === undefined)
|
|
3
|
+
return undefined;
|
|
4
|
+
switch (operand.kind) {
|
|
5
|
+
case 'reg8':
|
|
6
|
+
case 'reg16':
|
|
7
|
+
case 'reg-index16':
|
|
8
|
+
case 'reg-half-index':
|
|
9
|
+
return operand.register.toUpperCase();
|
|
10
|
+
default:
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface
|
|
1
|
+
import type { RegisterContractsUnit, RoutineSummary } from './types.js';
|
|
2
|
+
export interface RegisterContractsProfileSummary {
|
|
3
3
|
name: 'mon3';
|
|
4
4
|
rst: Map<number, RoutineSummary>;
|
|
5
5
|
rstServices: Map<string, RoutineSummary>;
|
|
6
6
|
rstDispatchers: Map<number, {
|
|
7
|
-
selector:
|
|
7
|
+
selector: RegisterContractsUnit;
|
|
8
8
|
services: Map<number, RoutineSummary>;
|
|
9
9
|
}>;
|
|
10
10
|
}
|
|
11
11
|
export declare function rstTargetName(vector: number): string;
|
|
12
12
|
export declare function rstServiceTargetName(vector: number, service: string): string;
|
|
13
|
-
export declare function rstDispatcherServiceTargetNames(vector: number, selectorValue: (register:
|
|
14
|
-
export declare function
|
|
13
|
+
export declare function rstDispatcherServiceTargetNames(vector: number, selectorValue: (register: RegisterContractsUnit) => number | undefined): string[];
|
|
14
|
+
export declare function getRegisterContractsProfile(name: 'mon3' | undefined): RegisterContractsProfileSummary | undefined;
|
|
@@ -95,7 +95,7 @@ function mon3ApiServices(overrides) {
|
|
|
95
95
|
]));
|
|
96
96
|
}
|
|
97
97
|
export function rstDispatcherServiceTargetNames(vector, selectorValue) {
|
|
98
|
-
const mon3 =
|
|
98
|
+
const mon3 = getRegisterContractsProfile('mon3');
|
|
99
99
|
const dispatcher = mon3?.rstDispatchers.get(vector);
|
|
100
100
|
if (dispatcher === undefined)
|
|
101
101
|
return [];
|
|
@@ -105,7 +105,7 @@ export function rstDispatcherServiceTargetNames(vector, selectorValue) {
|
|
|
105
105
|
const service = dispatcher.services.get(value);
|
|
106
106
|
return service ? [service.name] : [];
|
|
107
107
|
}
|
|
108
|
-
export function
|
|
108
|
+
export function getRegisterContractsProfile(name) {
|
|
109
109
|
if (name !== 'mon3')
|
|
110
110
|
return undefined;
|
|
111
111
|
const matrixScan = {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SourceItem } from '../model/source-item.js';
|
|
2
|
+
import type { RegisterContractsDirectCall } from './types.js';
|
|
3
|
+
export declare function instructionCallTarget(item: SourceItem): string | undefined;
|
|
4
|
+
export declare function pushDirectBoundary(boundaries: RegisterContractsDirectCall[], target: string, subject: string, file: string, line: number, column: number): void;
|
|
5
|
+
export declare function collectFilesWithEntryLabels(items: readonly SourceItem[]): Set<string>;
|
|
6
|
+
export declare function collectDirectTailJumps(items: readonly SourceItem[], filesWithEntryLabels: ReadonlySet<string>): RegisterContractsDirectCall[];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
function routineNameFromExpression(expression) {
|
|
2
|
+
return expression.kind === 'symbol' ? expression.name : undefined;
|
|
3
|
+
}
|
|
4
|
+
export function instructionCallTarget(item) {
|
|
5
|
+
if (item.kind !== 'instruction')
|
|
6
|
+
return undefined;
|
|
7
|
+
const mnemonic = item.instruction.mnemonic;
|
|
8
|
+
if (mnemonic === 'call' || mnemonic === 'call-cc') {
|
|
9
|
+
return routineNameFromExpression(item.instruction.expression);
|
|
10
|
+
}
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
function instructionTailJumpTarget(item, entryNames) {
|
|
14
|
+
if (item.kind !== 'instruction')
|
|
15
|
+
return undefined;
|
|
16
|
+
if (!isTailJumpInstruction(item.instruction, entryNames))
|
|
17
|
+
return undefined;
|
|
18
|
+
const target = routineNameFromExpression(item.instruction.expression);
|
|
19
|
+
return isEligibleTailJumpTarget(target, entryNames) ? target : undefined;
|
|
20
|
+
}
|
|
21
|
+
function isTailJumpInstruction(instruction, entryNames) {
|
|
22
|
+
return (instruction.mnemonic === 'jp' || (instruction.mnemonic === 'jp-cc' && entryNames !== undefined));
|
|
23
|
+
}
|
|
24
|
+
function isEligibleTailJumpTarget(target, entryNames) {
|
|
25
|
+
if (target === undefined || target.startsWith('.'))
|
|
26
|
+
return false;
|
|
27
|
+
return entryNames === undefined || entryNames.has(target);
|
|
28
|
+
}
|
|
29
|
+
export function pushDirectBoundary(boundaries, target, subject, file, line, column) {
|
|
30
|
+
boundaries.push({ target, subject, file, line, column });
|
|
31
|
+
}
|
|
32
|
+
export function collectFilesWithEntryLabels(items) {
|
|
33
|
+
return new Set(items
|
|
34
|
+
.filter((item) => item.kind === 'label')
|
|
35
|
+
.filter((item) => item.isEntry === true)
|
|
36
|
+
.map((item) => item.span.sourceName));
|
|
37
|
+
}
|
|
38
|
+
function entryNamesByFile(items) {
|
|
39
|
+
const namesByFile = new Map();
|
|
40
|
+
for (const item of items) {
|
|
41
|
+
if (item.kind !== 'label' || item.isEntry !== true)
|
|
42
|
+
continue;
|
|
43
|
+
const names = namesByFile.get(item.span.sourceName) ?? new Set();
|
|
44
|
+
names.add(item.name);
|
|
45
|
+
namesByFile.set(item.span.sourceName, names);
|
|
46
|
+
}
|
|
47
|
+
return namesByFile;
|
|
48
|
+
}
|
|
49
|
+
export function collectDirectTailJumps(items, filesWithEntryLabels) {
|
|
50
|
+
const entriesByFile = entryNamesByFile(items);
|
|
51
|
+
const directTailJumps = [];
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
if (item.kind !== 'instruction')
|
|
54
|
+
continue;
|
|
55
|
+
const entryNames = filesWithEntryLabels.has(item.span.sourceName)
|
|
56
|
+
? entriesByFile.get(item.span.sourceName)
|
|
57
|
+
: undefined;
|
|
58
|
+
const target = instructionTailJumpTarget(item, entryNames);
|
|
59
|
+
if (target === undefined)
|
|
60
|
+
continue;
|
|
61
|
+
pushDirectBoundary(directTailJumps, target, `JP ${target}`, item.span.sourceName, item.span.line, item.span.column);
|
|
62
|
+
}
|
|
63
|
+
return directTailJumps;
|
|
64
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SourceItem } from '../model/source-item.js';
|
|
2
|
+
import type { RegisterContractsDirectCall, RegisterContractsRoutine } from './types.js';
|
|
3
|
+
export interface RoutineBuildResult {
|
|
4
|
+
routines: RegisterContractsRoutine[];
|
|
5
|
+
directCalls: RegisterContractsDirectCall[];
|
|
6
|
+
}
|
|
7
|
+
export declare function buildRoutinesAndDirectCalls(items: readonly SourceItem[], constants: ReadonlyMap<string, number>, filesWithEntryLabels: ReadonlySet<string>): RoutineBuildResult;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { instructionCallTarget, pushDirectBoundary } from './programModel-boundaries.js';
|
|
2
|
+
function isGlobalLabel(name) {
|
|
3
|
+
return !name.startsWith('.');
|
|
4
|
+
}
|
|
5
|
+
function emptyState() {
|
|
6
|
+
return {
|
|
7
|
+
entryLabels: [],
|
|
8
|
+
labels: [],
|
|
9
|
+
instructions: [],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function toInstruction(item, labels, constants) {
|
|
13
|
+
return {
|
|
14
|
+
instruction: item.instruction,
|
|
15
|
+
file: item.span.sourceName,
|
|
16
|
+
line: item.span.line,
|
|
17
|
+
column: item.span.column,
|
|
18
|
+
labels: [...labels],
|
|
19
|
+
constants,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function startRoutine(state, item) {
|
|
23
|
+
state.sourceName = item.span.sourceName;
|
|
24
|
+
state.routineName = item.name;
|
|
25
|
+
state.entryLabels = item.isEntry === true ? [item.name] : [];
|
|
26
|
+
state.labels = [item.name];
|
|
27
|
+
state.routineStartLine = item.span.line;
|
|
28
|
+
state.routineStartColumn = item.span.column;
|
|
29
|
+
state.instructions = [];
|
|
30
|
+
}
|
|
31
|
+
function routineSpan(state, end) {
|
|
32
|
+
const line = state.routineStartLine ?? 1;
|
|
33
|
+
return {
|
|
34
|
+
file: state.sourceName ?? '',
|
|
35
|
+
start: { line, column: state.routineStartColumn ?? 1 },
|
|
36
|
+
end: { line: end?.line ?? line, column: end?.column ?? state.routineStartColumn ?? 1 },
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function flushRoutine(routines, state, constants) {
|
|
40
|
+
if (state.routineName === undefined || state.routineStartLine === undefined)
|
|
41
|
+
return;
|
|
42
|
+
const end = state.instructions[state.instructions.length - 1];
|
|
43
|
+
routines.push({
|
|
44
|
+
name: state.routineName,
|
|
45
|
+
labels: [...state.labels],
|
|
46
|
+
entryLabels: [...state.entryLabels],
|
|
47
|
+
instructions: [...state.instructions],
|
|
48
|
+
constants,
|
|
49
|
+
span: routineSpan(state, end),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function resetAndStart(routines, state, constants, item) {
|
|
53
|
+
flushRoutine(routines, state, constants);
|
|
54
|
+
Object.assign(state, emptyState());
|
|
55
|
+
startRoutine(state, item);
|
|
56
|
+
}
|
|
57
|
+
function appendDirectCall(directCalls, item) {
|
|
58
|
+
const directTarget = instructionCallTarget(item);
|
|
59
|
+
if (directTarget === undefined)
|
|
60
|
+
return;
|
|
61
|
+
pushDirectBoundary(directCalls, directTarget, `CALL ${directTarget}`, item.span.sourceName, item.span.line, item.span.column);
|
|
62
|
+
}
|
|
63
|
+
function handleInstruction(state, directCalls, item, constants) {
|
|
64
|
+
if (state.routineName === undefined || state.sourceName === undefined)
|
|
65
|
+
return;
|
|
66
|
+
if (item.span.sourceName !== state.sourceName)
|
|
67
|
+
return;
|
|
68
|
+
state.instructions.push(toInstruction(item, state.labels, constants));
|
|
69
|
+
appendDirectCall(directCalls, item);
|
|
70
|
+
}
|
|
71
|
+
function handleGlobalLabel(routines, state, item, constants, filesWithEntryLabels) {
|
|
72
|
+
if (state.routineName === undefined) {
|
|
73
|
+
if (shouldIgnoreNonEntryLabel(item, filesWithEntryLabels))
|
|
74
|
+
return;
|
|
75
|
+
startRoutine(state, item);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (isDifferentRoutineSource(state, item)) {
|
|
79
|
+
resetAndStart(routines, state, constants, item);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (state.instructions.length > 0) {
|
|
83
|
+
if (shouldKeepPostInstructionAlias(item, filesWithEntryLabels)) {
|
|
84
|
+
appendRoutineLabel(state, item);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
resetAndStart(routines, state, constants, item);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
appendRoutineLabel(state, item);
|
|
91
|
+
}
|
|
92
|
+
function shouldIgnoreNonEntryLabel(item, filesWithEntryLabels) {
|
|
93
|
+
return filesWithEntryLabels.has(item.span.sourceName) && item.isEntry !== true;
|
|
94
|
+
}
|
|
95
|
+
function isDifferentRoutineSource(state, item) {
|
|
96
|
+
return state.sourceName === undefined || state.sourceName !== item.span.sourceName;
|
|
97
|
+
}
|
|
98
|
+
function shouldKeepPostInstructionAlias(item, filesWithEntryLabels) {
|
|
99
|
+
return shouldIgnoreNonEntryLabel(item, filesWithEntryLabels);
|
|
100
|
+
}
|
|
101
|
+
function appendRoutineLabel(state, item) {
|
|
102
|
+
state.labels.push(item.name);
|
|
103
|
+
if (item.isEntry === true)
|
|
104
|
+
state.entryLabels.push(item.name);
|
|
105
|
+
}
|
|
106
|
+
function handleLabel(routines, state, item, constants, filesWithEntryLabels) {
|
|
107
|
+
if (!isGlobalLabel(item.name)) {
|
|
108
|
+
if (state.routineName !== undefined)
|
|
109
|
+
state.labels.push(item.name);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
handleGlobalLabel(routines, state, item, constants, filesWithEntryLabels);
|
|
113
|
+
}
|
|
114
|
+
export function buildRoutinesAndDirectCalls(items, constants, filesWithEntryLabels) {
|
|
115
|
+
const routines = [];
|
|
116
|
+
const directCalls = [];
|
|
117
|
+
const state = emptyState();
|
|
118
|
+
for (const item of items) {
|
|
119
|
+
if (item.kind === 'instruction') {
|
|
120
|
+
handleInstruction(state, directCalls, item, constants);
|
|
121
|
+
}
|
|
122
|
+
else if (item.kind === 'label') {
|
|
123
|
+
handleLabel(routines, state, item, constants, filesWithEntryLabels);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
flushRoutine(routines, state, constants);
|
|
127
|
+
return { routines, directCalls };
|
|
128
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { collectConstants } from './constants.js';
|
|
2
|
+
import { collectDirectTailJumps, collectFilesWithEntryLabels } from './programModel-boundaries.js';
|
|
3
|
+
import { buildRoutinesAndDirectCalls } from './programModel-routines.js';
|
|
4
|
+
export function buildRegisterContractsProgramModel(items) {
|
|
5
|
+
const constants = collectConstants(items);
|
|
6
|
+
const filesWithEntryLabels = collectFilesWithEntryLabels(items);
|
|
7
|
+
const { routines, directCalls } = buildRoutinesAndDirectCalls(items, constants, filesWithEntryLabels);
|
|
8
|
+
const directTailJumps = collectDirectTailJumps(items, filesWithEntryLabels);
|
|
9
|
+
return {
|
|
10
|
+
routines,
|
|
11
|
+
directCalls,
|
|
12
|
+
directBoundaries: [...directCalls, ...directTailJumps],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RegisterContractsReportModel, RegisterContractsUnit, RoutineSummary } from './types.js';
|
|
2
|
+
export declare function contractCarrierList(units: RegisterContractsUnit[]): string;
|
|
3
|
+
export declare function renderRegisterContractsReport(model: RegisterContractsReportModel): string;
|
|
4
|
+
export declare function renderRegisterContractsInterface(summaries: RoutineSummary[]): string;
|
|
5
|
+
export declare function renderRegisterContractsSourceBlock(summary: RoutineSummary): string[];
|
|
@@ -71,27 +71,41 @@ function stackStatus(summary) {
|
|
|
71
71
|
function relationOutUnits(summary) {
|
|
72
72
|
return new Set(summary.valueRelations.flatMap((rel) => rel.out));
|
|
73
73
|
}
|
|
74
|
-
export function
|
|
75
|
-
const lines = [
|
|
74
|
+
export function renderRegisterContractsReport(model) {
|
|
75
|
+
const lines = [
|
|
76
|
+
'AZM Register Contracts Report',
|
|
77
|
+
`Entry: ${model.entryFile}`,
|
|
78
|
+
`Mode: ${model.mode}`,
|
|
79
|
+
];
|
|
76
80
|
if (model.profile)
|
|
77
81
|
lines.push(`Profile: ${model.profile}`);
|
|
78
82
|
lines.push('');
|
|
83
|
+
appendRoutineSummaries(lines, model);
|
|
84
|
+
appendConflicts(lines, model);
|
|
85
|
+
appendOutputCandidates(lines, model);
|
|
86
|
+
appendUnknownCalls(lines, model);
|
|
87
|
+
return `${lines.join('\n')}\n`;
|
|
88
|
+
}
|
|
89
|
+
function appendRoutineSummaries(lines, model) {
|
|
79
90
|
if (model.summaries.length === 0) {
|
|
80
91
|
lines.push('Routines: none', '');
|
|
92
|
+
return;
|
|
81
93
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
+
for (const summary of model.summaries)
|
|
95
|
+
appendRoutineSummary(lines, summary);
|
|
96
|
+
}
|
|
97
|
+
function appendRoutineSummary(lines, summary) {
|
|
98
|
+
lines.push(`Routine: ${summary.name}`);
|
|
99
|
+
lines.push(` reads: ${list(summary.mayRead)}`);
|
|
100
|
+
lines.push(` writes: ${list(summary.mayWrite)}`);
|
|
101
|
+
lines.push(` preserves: ${list(summary.preserved)}`);
|
|
102
|
+
lines.push(` stack: ${stackStatus(summary)}`);
|
|
103
|
+
for (const rel of summary.valueRelations) {
|
|
104
|
+
lines.push(` relation: ${list(rel.out)} <= ${list(rel.from)}`);
|
|
94
105
|
}
|
|
106
|
+
lines.push('');
|
|
107
|
+
}
|
|
108
|
+
function appendConflicts(lines, model) {
|
|
95
109
|
lines.push('Conflicts:');
|
|
96
110
|
if (model.conflicts.length === 0) {
|
|
97
111
|
lines.push(' none');
|
|
@@ -102,6 +116,8 @@ export function renderRegisterCareReport(model) {
|
|
|
102
116
|
}
|
|
103
117
|
}
|
|
104
118
|
lines.push('');
|
|
119
|
+
}
|
|
120
|
+
function appendOutputCandidates(lines, model) {
|
|
105
121
|
lines.push('Output candidates:');
|
|
106
122
|
if (!model.outputCandidates || model.outputCandidates.length === 0) {
|
|
107
123
|
lines.push(' none');
|
|
@@ -112,6 +128,8 @@ export function renderRegisterCareReport(model) {
|
|
|
112
128
|
}
|
|
113
129
|
}
|
|
114
130
|
lines.push('');
|
|
131
|
+
}
|
|
132
|
+
function appendUnknownCalls(lines, model) {
|
|
115
133
|
lines.push('Unknown calls:');
|
|
116
134
|
if (model.unknownCalls.length === 0) {
|
|
117
135
|
lines.push(' none');
|
|
@@ -121,9 +139,8 @@ export function renderRegisterCareReport(model) {
|
|
|
121
139
|
lines.push(` ${call}`);
|
|
122
140
|
}
|
|
123
141
|
lines.push('');
|
|
124
|
-
return `${lines.join('\n')}\n`;
|
|
125
142
|
}
|
|
126
|
-
export function
|
|
143
|
+
export function renderRegisterContractsInterface(summaries) {
|
|
127
144
|
const lines = [];
|
|
128
145
|
for (const summary of summaries) {
|
|
129
146
|
lines.push(`extern ${summary.name}`);
|
|
@@ -134,6 +151,6 @@ export function renderRegisterCareInterface(summaries) {
|
|
|
134
151
|
}
|
|
135
152
|
return `${lines.join('\n')}\n`;
|
|
136
153
|
}
|
|
137
|
-
export function
|
|
154
|
+
export function renderRegisterContractsSourceBlock(summary) {
|
|
138
155
|
return sourceContractEntries(summary).map((entry) => `;! ${entry.keyword.padEnd(10)}${entry.carriers}`);
|
|
139
156
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RegisterContractsRoutine, RoutineContract, RoutineSummary } from './types.js';
|
|
2
|
+
export declare function summariesWithExternalContracts(summaries: RoutineSummary[], contracts: Map<string, RoutineContract>, routineNameSet: Set<string>): RoutineSummary[];
|
|
3
|
+
export declare function inferRoutineSummariesToFixedPoint(routines: RegisterContractsRoutine[], contracts: Map<string, RoutineContract>, routineNameSet: Set<string>, profileSummaries: RoutineSummary[]): Array<{
|
|
4
|
+
routine: RegisterContractsRoutine;
|
|
5
|
+
summary: RoutineSummary;
|
|
6
|
+
}>;
|
|
@@ -45,6 +45,16 @@ function buildBoundarySummaryMap(summaries, routineSummaries, profileSummaries)
|
|
|
45
45
|
}
|
|
46
46
|
return boundarySummaryMap;
|
|
47
47
|
}
|
|
48
|
+
function buildOptimisticInternalBoundarySummaryMap(routines) {
|
|
49
|
+
const out = new Map();
|
|
50
|
+
for (const routine of routines) {
|
|
51
|
+
const summary = emptyRoutineSummary(routine.name);
|
|
52
|
+
for (const label of boundaryLabels(routine)) {
|
|
53
|
+
out.set(label, summary);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
48
58
|
function summarizeRoutines(routines, contracts, boundarySummaryMap = new Map()) {
|
|
49
59
|
return routines.map((routine) => {
|
|
50
60
|
const inferred = inferRoutineSummary(routine, boundarySummaryMap);
|
|
@@ -73,7 +83,7 @@ function routineSummariesFingerprint(routineSummaries) {
|
|
|
73
83
|
return routineSummaries.map((item) => summaryFingerprint(item.summary)).join('\n');
|
|
74
84
|
}
|
|
75
85
|
export function inferRoutineSummariesToFixedPoint(routines, contracts, routineNameSet, profileSummaries) {
|
|
76
|
-
let routineSummaries = summarizeRoutines(routines, contracts);
|
|
86
|
+
let routineSummaries = summarizeRoutines(routines, contracts, buildOptimisticInternalBoundarySummaryMap(routines));
|
|
77
87
|
const maxPasses = Math.max(2, routines.length + 2);
|
|
78
88
|
for (let pass = 0; pass < maxPasses; pass += 1) {
|
|
79
89
|
const summaries = summariesWithExternalContracts(routineSummaries.map((item) => item.summary), contracts, routineNameSet);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { LocatedSmartComment, RegisterContractsRoutine } from './types.js';
|
|
2
|
+
export declare function collectPrecedingCommentBlock(routine: RegisterContractsRoutine, sourceTexts: ReadonlyMap<string, string>): {
|
|
3
|
+
comments: LocatedSmartComment[];
|
|
4
|
+
complete: boolean;
|
|
5
|
+
};
|