@jhlagado/azm 0.1.0
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/LICENSE +649 -0
- package/README.md +142 -0
- package/dist/src/analysis.d.ts +11 -0
- package/dist/src/analysis.js +41 -0
- package/dist/src/api-compile.d.ts +8 -0
- package/dist/src/api-compile.js +3 -0
- package/dist/src/api-tooling.d.ts +25 -0
- package/dist/src/api-tooling.js +21 -0
- package/dist/src/cli.d.ts +30 -0
- package/dist/src/cli.js +523 -0
- package/dist/src/compile.d.ts +10 -0
- package/dist/src/compile.js +175 -0
- package/dist/src/compileShared.d.ts +3 -0
- package/dist/src/compileShared.js +7 -0
- package/dist/src/diagnosticTypes.d.ts +77 -0
- package/dist/src/diagnosticTypes.js +53 -0
- package/dist/src/formats/index.d.ts +7 -0
- package/dist/src/formats/index.js +17 -0
- package/dist/src/formats/range.d.ts +17 -0
- package/dist/src/formats/range.js +45 -0
- package/dist/src/formats/types.d.ts +208 -0
- package/dist/src/formats/types.js +1 -0
- package/dist/src/formats/writeAsm80.d.ts +6 -0
- package/dist/src/formats/writeAsm80.js +86 -0
- package/dist/src/formats/writeBin.d.ts +7 -0
- package/dist/src/formats/writeBin.js +23 -0
- package/dist/src/formats/writeD8m.d.ts +9 -0
- package/dist/src/formats/writeD8m.js +239 -0
- package/dist/src/formats/writeHex.d.ts +9 -0
- package/dist/src/formats/writeHex.js +39 -0
- package/dist/src/formats/writeListing.d.ts +8 -0
- package/dist/src/formats/writeListing.js +83 -0
- package/dist/src/frontend/asm80/asmLine.d.ts +39 -0
- package/dist/src/frontend/asm80/asmLine.js +89 -0
- package/dist/src/frontend/asm80/parseAsmRawValues.d.ts +4 -0
- package/dist/src/frontend/asm80/parseAsmRawValues.js +94 -0
- package/dist/src/frontend/asm80/quoteScan.d.ts +10 -0
- package/dist/src/frontend/asm80/quoteScan.js +25 -0
- package/dist/src/frontend/ast.d.ts +376 -0
- package/dist/src/frontend/ast.js +1 -0
- package/dist/src/frontend/directiveAliases.d.ts +14 -0
- package/dist/src/frontend/directiveAliases.js +189 -0
- package/dist/src/frontend/grammarData.d.ts +14 -0
- package/dist/src/frontend/grammarData.js +65 -0
- package/dist/src/frontend/immExprUtils.d.ts +2 -0
- package/dist/src/frontend/immExprUtils.js +12 -0
- package/dist/src/frontend/parseAsmFlatDirectiveLine.d.ts +17 -0
- package/dist/src/frontend/parseAsmFlatDirectiveLine.js +187 -0
- package/dist/src/frontend/parseAsmInstruction.d.ts +3 -0
- package/dist/src/frontend/parseAsmInstruction.js +73 -0
- package/dist/src/frontend/parseAsmStatements.d.ts +6 -0
- package/dist/src/frontend/parseAsmStatements.js +16 -0
- package/dist/src/frontend/parseAsmStream.d.ts +10 -0
- package/dist/src/frontend/parseAsmStream.js +33 -0
- package/dist/src/frontend/parseAsmTopLevel.d.ts +18 -0
- package/dist/src/frontend/parseAsmTopLevel.js +34 -0
- package/dist/src/frontend/parseDiagnostics.d.ts +9 -0
- package/dist/src/frontend/parseDiagnostics.js +16 -0
- package/dist/src/frontend/parseEnum.d.ts +12 -0
- package/dist/src/frontend/parseEnum.js +70 -0
- package/dist/src/frontend/parseImm.d.ts +10 -0
- package/dist/src/frontend/parseImm.js +397 -0
- package/dist/src/frontend/parseLogicalLines.d.ts +11 -0
- package/dist/src/frontend/parseLogicalLines.js +94 -0
- package/dist/src/frontend/parseOp.d.ts +25 -0
- package/dist/src/frontend/parseOp.js +120 -0
- package/dist/src/frontend/parseOpHeader.d.ts +20 -0
- package/dist/src/frontend/parseOpHeader.js +32 -0
- package/dist/src/frontend/parseOperands.d.ts +4 -0
- package/dist/src/frontend/parseOperands.js +290 -0
- package/dist/src/frontend/parseParams.d.ts +6 -0
- package/dist/src/frontend/parseParams.js +62 -0
- package/dist/src/frontend/parseParserRecovery.d.ts +12 -0
- package/dist/src/frontend/parseParserRecovery.js +17 -0
- package/dist/src/frontend/parseParserShared.d.ts +2 -0
- package/dist/src/frontend/parseParserShared.js +8 -0
- package/dist/src/frontend/parseRawDataDirectiveStart.d.ts +1 -0
- package/dist/src/frontend/parseRawDataDirectiveStart.js +3 -0
- package/dist/src/frontend/parseRawDataDirectives.d.ts +7 -0
- package/dist/src/frontend/parseRawDataDirectives.js +142 -0
- package/dist/src/frontend/parseRecordFieldDecl.d.ts +34 -0
- package/dist/src/frontend/parseRecordFieldDecl.js +177 -0
- package/dist/src/frontend/parseSourceItemDispatch.d.ts +46 -0
- package/dist/src/frontend/parseSourceItemDispatch.js +53 -0
- package/dist/src/frontend/parseSourceItemTable.d.ts +16 -0
- package/dist/src/frontend/parseSourceItemTable.js +68 -0
- package/dist/src/frontend/parseTopLevelCommon.d.ts +11 -0
- package/dist/src/frontend/parseTopLevelCommon.js +50 -0
- package/dist/src/frontend/parseTypes.d.ts +24 -0
- package/dist/src/frontend/parseTypes.js +77 -0
- package/dist/src/frontend/parser.d.ts +11 -0
- package/dist/src/frontend/parser.js +88 -0
- package/dist/src/frontend/source.d.ts +28 -0
- package/dist/src/frontend/source.js +58 -0
- package/dist/src/frontend/sourceExtensions.d.ts +2 -0
- package/dist/src/frontend/sourceExtensions.js +6 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +2 -0
- package/dist/src/lintCaseStyle.d.ts +4 -0
- package/dist/src/lintCaseStyle.js +129 -0
- package/dist/src/lowering/asmDirectiveLowering.d.ts +4 -0
- package/dist/src/lowering/asmDirectiveLowering.js +229 -0
- package/dist/src/lowering/asmDirectiveTraversal.d.ts +47 -0
- package/dist/src/lowering/asmDirectiveTraversal.js +52 -0
- package/dist/src/lowering/asmEquResolution.d.ts +8 -0
- package/dist/src/lowering/asmEquResolution.js +69 -0
- package/dist/src/lowering/asmInstructionLdHelpers.d.ts +15 -0
- package/dist/src/lowering/asmInstructionLdHelpers.js +102 -0
- package/dist/src/lowering/asmInstructionLowering.d.ts +5 -0
- package/dist/src/lowering/asmInstructionLowering.js +54 -0
- package/dist/src/lowering/asmInstructionStream.d.ts +46 -0
- package/dist/src/lowering/asmInstructionStream.js +51 -0
- package/dist/src/lowering/asmLoweringBranchCall.d.ts +43 -0
- package/dist/src/lowering/asmLoweringBranchCall.js +254 -0
- package/dist/src/lowering/asmLoweringHost.d.ts +23 -0
- package/dist/src/lowering/asmLoweringHost.js +1 -0
- package/dist/src/lowering/asmLoweringLd.d.ts +28 -0
- package/dist/src/lowering/asmLoweringLd.js +144 -0
- package/dist/src/lowering/asmRangeLowering.d.ts +17 -0
- package/dist/src/lowering/asmRangeLowering.js +39 -0
- package/dist/src/lowering/asmRawDataLowering.d.ts +16 -0
- package/dist/src/lowering/asmRawDataLowering.js +209 -0
- package/dist/src/lowering/asmSourceEmitter.d.ts +4 -0
- package/dist/src/lowering/asmSourceEmitter.js +9 -0
- package/dist/src/lowering/asmSourceInstructionLowering.d.ts +4 -0
- package/dist/src/lowering/asmSourceInstructionLowering.js +14 -0
- package/dist/src/lowering/asmUtils.d.ts +13 -0
- package/dist/src/lowering/asmUtils.js +105 -0
- package/dist/src/lowering/assemblerFlowSetup.d.ts +54 -0
- package/dist/src/lowering/assemblerFlowSetup.js +128 -0
- package/dist/src/lowering/assemblerLoweringContext.d.ts +151 -0
- package/dist/src/lowering/assemblerLoweringContext.js +16 -0
- package/dist/src/lowering/assemblerLoweringContextSplit.d.ts +7 -0
- package/dist/src/lowering/assemblerLoweringContextSplit.js +75 -0
- package/dist/src/lowering/assemblerLoweringPhases.d.ts +66 -0
- package/dist/src/lowering/assemblerLoweringPhases.js +166 -0
- package/dist/src/lowering/bytePlacement.d.ts +7 -0
- package/dist/src/lowering/bytePlacement.js +37 -0
- package/dist/src/lowering/capabilities.d.ts +67 -0
- package/dist/src/lowering/capabilities.js +1 -0
- package/dist/src/lowering/eaResolution.d.ts +58 -0
- package/dist/src/lowering/eaResolution.js +159 -0
- package/dist/src/lowering/emissionCore.d.ts +17 -0
- package/dist/src/lowering/emissionCore.js +21 -0
- package/dist/src/lowering/emit.d.ts +17 -0
- package/dist/src/lowering/emit.js +46 -0
- package/dist/src/lowering/emitContextBuilder.d.ts +63 -0
- package/dist/src/lowering/emitContextBuilder.js +41 -0
- package/dist/src/lowering/emitFinalization.d.ts +61 -0
- package/dist/src/lowering/emitFinalization.js +66 -0
- package/dist/src/lowering/emitFinalizationSetup.d.ts +19 -0
- package/dist/src/lowering/emitFinalizationSetup.js +26 -0
- package/dist/src/lowering/emitPhase1BuildProgramLoweringContext.d.ts +7 -0
- package/dist/src/lowering/emitPhase1BuildProgramLoweringContext.js +119 -0
- package/dist/src/lowering/emitPhase1Helpers.d.ts +4 -0
- package/dist/src/lowering/emitPhase1Helpers.js +12 -0
- package/dist/src/lowering/emitPhase1Types.d.ts +21 -0
- package/dist/src/lowering/emitPhase1Types.js +1 -0
- package/dist/src/lowering/emitPhase1WirePipeline.d.ts +70 -0
- package/dist/src/lowering/emitPhase1WirePipeline.js +203 -0
- package/dist/src/lowering/emitPhase1Workspace.d.ts +82 -0
- package/dist/src/lowering/emitPhase1Workspace.js +55 -0
- package/dist/src/lowering/emitPipeline.d.ts +121 -0
- package/dist/src/lowering/emitPipeline.js +57 -0
- package/dist/src/lowering/emitProgramContext.d.ts +39 -0
- package/dist/src/lowering/emitProgramContext.js +29 -0
- package/dist/src/lowering/emitState.d.ts +90 -0
- package/dist/src/lowering/emitState.js +124 -0
- package/dist/src/lowering/fixupBaseResolution.d.ts +7 -0
- package/dist/src/lowering/fixupBaseResolution.js +23 -0
- package/dist/src/lowering/fixupEmission.d.ts +64 -0
- package/dist/src/lowering/fixupEmission.js +199 -0
- package/dist/src/lowering/immMath.d.ts +2 -0
- package/dist/src/lowering/immMath.js +34 -0
- package/dist/src/lowering/inputAssets.d.ts +7 -0
- package/dist/src/lowering/inputAssets.js +106 -0
- package/dist/src/lowering/ldEncoding.d.ts +15 -0
- package/dist/src/lowering/ldEncoding.js +12 -0
- package/dist/src/lowering/ldEncodingRegMemHelpers.d.ts +5 -0
- package/dist/src/lowering/ldEncodingRegMemHelpers.js +124 -0
- package/dist/src/lowering/ldFormSelection.d.ts +26 -0
- package/dist/src/lowering/ldFormSelection.js +92 -0
- package/dist/src/lowering/ldLowering.d.ts +7 -0
- package/dist/src/lowering/ldLowering.js +13 -0
- package/dist/src/lowering/loweredAsmByteEmission.d.ts +23 -0
- package/dist/src/lowering/loweredAsmByteEmission.js +185 -0
- package/dist/src/lowering/loweredAsmPlacement.d.ts +13 -0
- package/dist/src/lowering/loweredAsmPlacement.js +86 -0
- package/dist/src/lowering/loweredAsmStreamRecording.d.ts +27 -0
- package/dist/src/lowering/loweredAsmStreamRecording.js +215 -0
- package/dist/src/lowering/loweredAsmTypes.d.ts +202 -0
- package/dist/src/lowering/loweredAsmTypes.js +1 -0
- package/dist/src/lowering/loweredFormat.d.ts +3 -0
- package/dist/src/lowering/loweredFormat.js +26 -0
- package/dist/src/lowering/loweredItemSize.d.ts +4 -0
- package/dist/src/lowering/loweredItemSize.js +17 -0
- package/dist/src/lowering/loweringDiagnostics.d.ts +9 -0
- package/dist/src/lowering/loweringDiagnostics.js +55 -0
- package/dist/src/lowering/loweringTypes.d.ts +27 -0
- package/dist/src/lowering/loweringTypes.js +1 -0
- package/dist/src/lowering/opCandidateRegistry.d.ts +9 -0
- package/dist/src/lowering/opCandidateRegistry.js +9 -0
- package/dist/src/lowering/opExpansionExecution.d.ts +15 -0
- package/dist/src/lowering/opExpansionExecution.js +45 -0
- package/dist/src/lowering/opExpansionOrchestration.d.ts +15 -0
- package/dist/src/lowering/opExpansionOrchestration.js +88 -0
- package/dist/src/lowering/opExpansionStream.d.ts +12 -0
- package/dist/src/lowering/opExpansionStream.js +176 -0
- package/dist/src/lowering/opMatching.d.ts +52 -0
- package/dist/src/lowering/opMatching.js +355 -0
- package/dist/src/lowering/opSubstitution.d.ts +13 -0
- package/dist/src/lowering/opSubstitution.js +175 -0
- package/dist/src/lowering/prescanTypes.d.ts +7 -0
- package/dist/src/lowering/prescanTypes.js +1 -0
- package/dist/src/lowering/programLowering.d.ts +144 -0
- package/dist/src/lowering/programLowering.js +2 -0
- package/dist/src/lowering/programLoweringDeclarations.d.ts +5 -0
- package/dist/src/lowering/programLoweringDeclarations.js +5 -0
- package/dist/src/lowering/programLoweringFinalize.d.ts +18 -0
- package/dist/src/lowering/programLoweringFinalize.js +115 -0
- package/dist/src/lowering/programLoweringTraversal.d.ts +2 -0
- package/dist/src/lowering/programLoweringTraversal.js +93 -0
- package/dist/src/lowering/programPrescan.d.ts +3 -0
- package/dist/src/lowering/programPrescan.js +37 -0
- package/dist/src/lowering/traceFormat.d.ts +13 -0
- package/dist/src/lowering/traceFormat.js +211 -0
- package/dist/src/pathCompare.d.ts +3 -0
- package/dist/src/pathCompare.js +26 -0
- package/dist/src/pipeline.d.ts +78 -0
- package/dist/src/pipeline.js +1 -0
- package/dist/src/registerCare/analyze.d.ts +24 -0
- package/dist/src/registerCare/analyze.js +327 -0
- package/dist/src/registerCare/annotate.d.ts +11 -0
- package/dist/src/registerCare/annotate.js +76 -0
- package/dist/src/registerCare/boundaryHints.d.ts +2 -0
- package/dist/src/registerCare/boundaryHints.js +10 -0
- package/dist/src/registerCare/carriers.d.ts +4 -0
- package/dist/src/registerCare/carriers.js +78 -0
- package/dist/src/registerCare/controlFlow.d.ts +5 -0
- package/dist/src/registerCare/controlFlow.js +35 -0
- package/dist/src/registerCare/fix.d.ts +11 -0
- package/dist/src/registerCare/fix.js +119 -0
- package/dist/src/registerCare/liveness.d.ts +7 -0
- package/dist/src/registerCare/liveness.js +227 -0
- package/dist/src/registerCare/profiles.d.ts +11 -0
- package/dist/src/registerCare/profiles.js +45 -0
- package/dist/src/registerCare/programModel.d.ts +3 -0
- package/dist/src/registerCare/programModel.js +181 -0
- package/dist/src/registerCare/report.d.ts +5 -0
- package/dist/src/registerCare/report.js +139 -0
- package/dist/src/registerCare/smartComments.d.ts +5 -0
- package/dist/src/registerCare/smartComments.js +247 -0
- package/dist/src/registerCare/sourceText.d.ts +8 -0
- package/dist/src/registerCare/sourceText.js +15 -0
- package/dist/src/registerCare/summary.d.ts +3 -0
- package/dist/src/registerCare/summary.js +492 -0
- package/dist/src/registerCare/tooling.d.ts +42 -0
- package/dist/src/registerCare/tooling.js +50 -0
- package/dist/src/registerCare/types.d.ts +154 -0
- package/dist/src/registerCare/types.js +1 -0
- package/dist/src/semantics/declVisitor.d.ts +5 -0
- package/dist/src/semantics/declVisitor.js +11 -0
- package/dist/src/semantics/env.d.ts +28 -0
- package/dist/src/semantics/env.js +432 -0
- package/dist/src/semantics/layout.d.ts +21 -0
- package/dist/src/semantics/layout.js +226 -0
- package/dist/src/semantics/layoutCastFold.d.ts +22 -0
- package/dist/src/semantics/layoutCastFold.js +118 -0
- package/dist/src/semantics/semanticsDiagnostics.d.ts +2 -0
- package/dist/src/semantics/semanticsDiagnostics.js +4 -0
- package/dist/src/semantics/typeQueries.d.ts +31 -0
- package/dist/src/semantics/typeQueries.js +124 -0
- package/dist/src/sourceIncludeExpansion.d.ts +17 -0
- package/dist/src/sourceIncludeExpansion.js +124 -0
- package/dist/src/sourceIncludePaths.d.ts +1 -0
- package/dist/src/sourceIncludePaths.js +12 -0
- package/dist/src/sourceLoader.d.ts +15 -0
- package/dist/src/sourceLoader.js +118 -0
- package/dist/src/z80/effects.d.ts +3 -0
- package/dist/src/z80/effects.js +516 -0
- package/dist/src/z80/encode.d.ts +10 -0
- package/dist/src/z80/encode.js +412 -0
- package/dist/src/z80/encodeAlu.d.ts +7 -0
- package/dist/src/z80/encodeAlu.js +219 -0
- package/dist/src/z80/encodeBitOps.d.ts +7 -0
- package/dist/src/z80/encodeBitOps.js +123 -0
- package/dist/src/z80/encodeContext.d.ts +29 -0
- package/dist/src/z80/encodeContext.js +1 -0
- package/dist/src/z80/encodeControl.d.ts +26 -0
- package/dist/src/z80/encodeControl.js +180 -0
- package/dist/src/z80/encodeCoreOps.d.ts +7 -0
- package/dist/src/z80/encodeCoreOps.js +131 -0
- package/dist/src/z80/encodeIo.d.ts +9 -0
- package/dist/src/z80/encodeIo.js +128 -0
- package/dist/src/z80/encodeLd.d.ts +13 -0
- package/dist/src/z80/encodeLd.js +273 -0
- package/dist/src/z80/encoderRegistry.d.ts +13 -0
- package/dist/src/z80/encoderRegistry.js +169 -0
- package/docs/reference/cli.md +134 -0
- package/docs/reference/tooling-api.md +248 -0
- package/package.json +98 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { parseImmExprFromText } from '../parseImm.js';
|
|
2
|
+
import { advanceAsmQuoteScan, createAsmQuoteScanState } from './quoteScan.js';
|
|
3
|
+
export function parseAsmRawValues(path, valuesText, lineSpan, diagnostics, stringEquates) {
|
|
4
|
+
const out = [];
|
|
5
|
+
const parts = splitTopLevelComma(valuesText)
|
|
6
|
+
.map((part) => part.trim())
|
|
7
|
+
.filter((part) => part.length > 0);
|
|
8
|
+
for (const part of parts) {
|
|
9
|
+
const rawString = parseWholeQuotedString(part);
|
|
10
|
+
if (rawString !== undefined) {
|
|
11
|
+
if (part[0] === "'" && rawString.length === 1) {
|
|
12
|
+
const expr = parseImmExprFromText(path, part, lineSpan, diagnostics);
|
|
13
|
+
if (expr) {
|
|
14
|
+
out.push(expr);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
out.push({ kind: 'AsmString', value: rawString });
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const stringEquate = /^[A-Za-z_][A-Za-z0-9_]*$/.exec(part)
|
|
22
|
+
? stringEquates.get(part.toLowerCase())
|
|
23
|
+
: undefined;
|
|
24
|
+
if (stringEquate !== undefined) {
|
|
25
|
+
out.push({ kind: 'AsmString', value: stringEquate });
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const expr = parseImmExprFromText(path, normalizeDoubleQuotedCharExpr(part), lineSpan, diagnostics);
|
|
29
|
+
if (expr)
|
|
30
|
+
out.push(expr);
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
export function parseWholeQuotedString(text) {
|
|
35
|
+
if (text.length < 2)
|
|
36
|
+
return undefined;
|
|
37
|
+
const quote = text[0];
|
|
38
|
+
if ((quote !== '"' && quote !== "'") || text[text.length - 1] !== quote)
|
|
39
|
+
return undefined;
|
|
40
|
+
let value = '';
|
|
41
|
+
for (let i = 1; i < text.length - 1; i++) {
|
|
42
|
+
const ch = text[i];
|
|
43
|
+
if (ch === '\\') {
|
|
44
|
+
if (i + 1 >= text.length - 1)
|
|
45
|
+
return undefined;
|
|
46
|
+
value += text[i + 1];
|
|
47
|
+
i++;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (ch === quote)
|
|
51
|
+
return undefined;
|
|
52
|
+
value += ch;
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
function normalizeDoubleQuotedCharExpr(text) {
|
|
57
|
+
return text.replace(/"([^"\\])"/g, (_match, char) => `'${char}'`);
|
|
58
|
+
}
|
|
59
|
+
function splitTopLevelComma(text) {
|
|
60
|
+
const parts = [];
|
|
61
|
+
let start = 0;
|
|
62
|
+
const quoteState = createAsmQuoteScanState();
|
|
63
|
+
let parenDepth = 0;
|
|
64
|
+
let bracketDepth = 0;
|
|
65
|
+
for (let i = 0; i < text.length; i++) {
|
|
66
|
+
if (advanceAsmQuoteScan(text, i, quoteState))
|
|
67
|
+
continue;
|
|
68
|
+
if (quoteState.inString || quoteState.inChar)
|
|
69
|
+
continue;
|
|
70
|
+
const ch = text[i];
|
|
71
|
+
if (ch === '(') {
|
|
72
|
+
parenDepth++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (ch === ')') {
|
|
76
|
+
parenDepth = Math.max(0, parenDepth - 1);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (ch === '[') {
|
|
80
|
+
bracketDepth++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (ch === ']') {
|
|
84
|
+
bracketDepth = Math.max(0, bracketDepth - 1);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (ch === ',' && parenDepth === 0 && bracketDepth === 0) {
|
|
88
|
+
parts.push(text.slice(start, i));
|
|
89
|
+
start = i + 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
parts.push(text.slice(start));
|
|
93
|
+
return parts;
|
|
94
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type AsmQuoteScanState = {
|
|
2
|
+
inString: boolean;
|
|
3
|
+
inChar: boolean;
|
|
4
|
+
escaped: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function createAsmQuoteScanState(): AsmQuoteScanState;
|
|
7
|
+
export declare function advanceAsmQuoteScan(text: string, index: number, state: AsmQuoteScanState, options?: {
|
|
8
|
+
singleQuoteStartsCharAt?: (text: string, index: number) => boolean;
|
|
9
|
+
}): boolean;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function createAsmQuoteScanState() {
|
|
2
|
+
return { inString: false, inChar: false, escaped: false };
|
|
3
|
+
}
|
|
4
|
+
export function advanceAsmQuoteScan(text, index, state, options = {}) {
|
|
5
|
+
const ch = text[index];
|
|
6
|
+
if (state.escaped) {
|
|
7
|
+
state.escaped = false;
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if ((state.inString || state.inChar) && ch === '\\') {
|
|
11
|
+
state.escaped = true;
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (!state.inChar && ch === '"') {
|
|
15
|
+
state.inString = !state.inString;
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
if (!state.inString &&
|
|
19
|
+
ch === "'" &&
|
|
20
|
+
(state.inChar || (options.singleQuoteStartsCharAt?.(text, index) ?? true))) {
|
|
21
|
+
state.inChar = !state.inChar;
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frontend AST contracts for AZM.
|
|
3
|
+
*
|
|
4
|
+
* This module intentionally defines types/interfaces only (no parsing/semantics).
|
|
5
|
+
* Later PRs extend these contracts via coordinated changes.
|
|
6
|
+
*/
|
|
7
|
+
export interface SourcePosition {
|
|
8
|
+
/** 1-based line number. */
|
|
9
|
+
line: number;
|
|
10
|
+
/** 1-based column number. */
|
|
11
|
+
column: number;
|
|
12
|
+
/** 0-based byte offset in the file. */
|
|
13
|
+
offset: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Source span with inclusive start and end positions.
|
|
17
|
+
*/
|
|
18
|
+
export interface SourceSpan {
|
|
19
|
+
/** User-facing file path (as provided on input). */
|
|
20
|
+
file: string;
|
|
21
|
+
start: SourcePosition;
|
|
22
|
+
end: SourcePosition;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Base shape for all AST nodes.
|
|
26
|
+
*/
|
|
27
|
+
export interface BaseNode {
|
|
28
|
+
kind: string;
|
|
29
|
+
span: SourceSpan;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parsed compilation unit, including the entry file and all loaded source files.
|
|
33
|
+
*/
|
|
34
|
+
export interface ProgramNode extends BaseNode {
|
|
35
|
+
kind: 'Program';
|
|
36
|
+
entryFile: string;
|
|
37
|
+
files: SourceFileNode[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A single AZM source file.
|
|
41
|
+
*/
|
|
42
|
+
export interface SourceFileNode extends BaseNode {
|
|
43
|
+
kind: 'SourceFile';
|
|
44
|
+
path: string;
|
|
45
|
+
items: SourceItemNode[];
|
|
46
|
+
}
|
|
47
|
+
interface AsmEquNode extends BaseNode {
|
|
48
|
+
kind: 'AsmEqu';
|
|
49
|
+
name: string;
|
|
50
|
+
exprText: string;
|
|
51
|
+
}
|
|
52
|
+
interface AsmOrgNode extends BaseNode {
|
|
53
|
+
kind: 'AsmOrg';
|
|
54
|
+
exprText: string;
|
|
55
|
+
}
|
|
56
|
+
interface AsmBinFromNode extends BaseNode {
|
|
57
|
+
kind: 'AsmBinFrom';
|
|
58
|
+
exprText: string;
|
|
59
|
+
}
|
|
60
|
+
interface AsmBinToNode extends BaseNode {
|
|
61
|
+
kind: 'AsmBinTo';
|
|
62
|
+
exprText: string;
|
|
63
|
+
}
|
|
64
|
+
interface AsmEndNode extends BaseNode {
|
|
65
|
+
kind: 'AsmEnd';
|
|
66
|
+
}
|
|
67
|
+
interface AsmAlignNode extends BaseNode {
|
|
68
|
+
kind: 'AsmAlign';
|
|
69
|
+
value: ImmExprNode;
|
|
70
|
+
}
|
|
71
|
+
type AsmRawDataValueNode = ImmExprNode | {
|
|
72
|
+
kind: 'AsmString';
|
|
73
|
+
value: string;
|
|
74
|
+
};
|
|
75
|
+
export type AsmRawDataNode = {
|
|
76
|
+
kind: 'AsmRawData';
|
|
77
|
+
span: SourceSpan;
|
|
78
|
+
name?: string;
|
|
79
|
+
directive: 'db' | 'dw' | 'cstr' | 'pstr' | 'istr';
|
|
80
|
+
values: AsmRawDataValueNode[];
|
|
81
|
+
valuesText?: string;
|
|
82
|
+
} | {
|
|
83
|
+
kind: 'AsmRawData';
|
|
84
|
+
span: SourceSpan;
|
|
85
|
+
name?: string;
|
|
86
|
+
directive: 'ds';
|
|
87
|
+
values?: AsmRawDataValueNode[];
|
|
88
|
+
size?: ImmExprNode;
|
|
89
|
+
fill?: ImmExprNode;
|
|
90
|
+
valuesText?: string;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Top-level items permitted in a source file.
|
|
94
|
+
*/
|
|
95
|
+
export type SourceItemNode = AsmEquNode | AsmOrgNode | AsmBinFromNode | AsmBinToNode | AsmEndNode | AsmAlignNode | AsmRawDataNode | AsmLabelNode | AsmInstructionNode | EnumDeclNode | UnionDeclNode | TypeDeclNode | OpDeclNode;
|
|
96
|
+
/**
|
|
97
|
+
* Packed record layout declaration.
|
|
98
|
+
*/
|
|
99
|
+
export interface TypeDeclNode extends BaseNode {
|
|
100
|
+
kind: 'TypeDecl';
|
|
101
|
+
name: string;
|
|
102
|
+
typeExpr: Extract<TypeExprNode, {
|
|
103
|
+
kind: 'RecordType';
|
|
104
|
+
}>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Union declaration.
|
|
108
|
+
*/
|
|
109
|
+
export interface UnionDeclNode extends BaseNode {
|
|
110
|
+
kind: 'UnionDecl';
|
|
111
|
+
name: string;
|
|
112
|
+
fields: RecordFieldNode[];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Enum declaration.
|
|
116
|
+
*/
|
|
117
|
+
export interface EnumDeclNode extends BaseNode {
|
|
118
|
+
kind: 'EnumDecl';
|
|
119
|
+
name: string;
|
|
120
|
+
members: string[];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* `op` (macro-instruction) declaration.
|
|
124
|
+
*/
|
|
125
|
+
export interface OpDeclNode extends BaseNode {
|
|
126
|
+
kind: 'OpDecl';
|
|
127
|
+
name: string;
|
|
128
|
+
params: OpParamNode[];
|
|
129
|
+
body: AsmBlockNode;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* `op` parameter with a matcher type.
|
|
133
|
+
*/
|
|
134
|
+
export interface OpParamNode extends BaseNode {
|
|
135
|
+
kind: 'OpParam';
|
|
136
|
+
name: string;
|
|
137
|
+
matcher: OpMatcherNode;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Operand matcher variants for `op` parameters.
|
|
141
|
+
*/
|
|
142
|
+
export type OpMatcherNode = {
|
|
143
|
+
kind: 'MatcherReg8';
|
|
144
|
+
span: SourceSpan;
|
|
145
|
+
} | {
|
|
146
|
+
kind: 'MatcherReg16';
|
|
147
|
+
span: SourceSpan;
|
|
148
|
+
} | {
|
|
149
|
+
kind: 'MatcherIdx16';
|
|
150
|
+
span: SourceSpan;
|
|
151
|
+
} | {
|
|
152
|
+
kind: 'MatcherCc';
|
|
153
|
+
span: SourceSpan;
|
|
154
|
+
} | {
|
|
155
|
+
kind: 'MatcherImm8';
|
|
156
|
+
span: SourceSpan;
|
|
157
|
+
} | {
|
|
158
|
+
kind: 'MatcherImm16';
|
|
159
|
+
span: SourceSpan;
|
|
160
|
+
} | {
|
|
161
|
+
kind: 'MatcherEa';
|
|
162
|
+
span: SourceSpan;
|
|
163
|
+
} | {
|
|
164
|
+
kind: 'MatcherMem8';
|
|
165
|
+
span: SourceSpan;
|
|
166
|
+
} | {
|
|
167
|
+
kind: 'MatcherMem16';
|
|
168
|
+
span: SourceSpan;
|
|
169
|
+
} | {
|
|
170
|
+
kind: 'MatcherFixed';
|
|
171
|
+
span: SourceSpan;
|
|
172
|
+
token: string;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Instruction stream inside ASM source or an `op` body.
|
|
176
|
+
*/
|
|
177
|
+
export interface AsmBlockNode extends BaseNode {
|
|
178
|
+
kind: 'AsmBlock';
|
|
179
|
+
items: AsmItemNode[];
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Items that can appear inside an instruction stream.
|
|
183
|
+
*/
|
|
184
|
+
export type AsmItemNode = AsmInstructionNode | AsmLabelNode;
|
|
185
|
+
/**
|
|
186
|
+
* Label definition inside an `asm` stream.
|
|
187
|
+
*/
|
|
188
|
+
export interface AsmLabelNode extends BaseNode {
|
|
189
|
+
kind: 'AsmLabel';
|
|
190
|
+
name: string;
|
|
191
|
+
/** True when the source label used the ASM80-style `@Name:` entry marker. */
|
|
192
|
+
isEntry?: boolean;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Z80 instruction-like statement inside an `asm` stream.
|
|
196
|
+
*/
|
|
197
|
+
export interface AsmInstructionNode extends BaseNode {
|
|
198
|
+
kind: 'AsmInstruction';
|
|
199
|
+
/** Canonical lower-case instruction mnemonic. */
|
|
200
|
+
head: string;
|
|
201
|
+
operands: AsmOperandNode[];
|
|
202
|
+
/** Original unparsed operand tail for ASM80 source preservation. */
|
|
203
|
+
operandText?: string;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Operand variants in `asm` instructions.
|
|
207
|
+
*/
|
|
208
|
+
export type AsmOperandNode = {
|
|
209
|
+
kind: 'Reg';
|
|
210
|
+
span: SourceSpan; /** Canonical upper-case register token. */
|
|
211
|
+
name: string;
|
|
212
|
+
} | {
|
|
213
|
+
kind: 'Imm';
|
|
214
|
+
span: SourceSpan;
|
|
215
|
+
expr: ImmExprNode;
|
|
216
|
+
} | {
|
|
217
|
+
kind: 'Ea';
|
|
218
|
+
span: SourceSpan;
|
|
219
|
+
expr: EaExprNode;
|
|
220
|
+
} | {
|
|
221
|
+
kind: 'Mem';
|
|
222
|
+
span: SourceSpan;
|
|
223
|
+
expr: EaExprNode;
|
|
224
|
+
} | {
|
|
225
|
+
kind: 'PortC';
|
|
226
|
+
span: SourceSpan;
|
|
227
|
+
} | {
|
|
228
|
+
kind: 'PortImm8';
|
|
229
|
+
span: SourceSpan;
|
|
230
|
+
expr: ImmExprNode;
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* Type expression variants.
|
|
234
|
+
*/
|
|
235
|
+
export type TypeExprNode = {
|
|
236
|
+
kind: 'TypeName';
|
|
237
|
+
span: SourceSpan;
|
|
238
|
+
name: string;
|
|
239
|
+
} | {
|
|
240
|
+
kind: 'ArrayType';
|
|
241
|
+
span: SourceSpan;
|
|
242
|
+
element: TypeExprNode;
|
|
243
|
+
length?: number;
|
|
244
|
+
} | {
|
|
245
|
+
kind: 'RecordType';
|
|
246
|
+
span: SourceSpan;
|
|
247
|
+
fields: RecordFieldNode[];
|
|
248
|
+
};
|
|
249
|
+
/**
|
|
250
|
+
* Field inside a record type.
|
|
251
|
+
*/
|
|
252
|
+
export interface RecordFieldNode extends BaseNode {
|
|
253
|
+
kind: 'RecordField';
|
|
254
|
+
name: string;
|
|
255
|
+
typeExpr: TypeExprNode;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Immediate-expression variants.
|
|
259
|
+
*/
|
|
260
|
+
export type ImmExprNode = {
|
|
261
|
+
kind: 'ImmLiteral';
|
|
262
|
+
span: SourceSpan;
|
|
263
|
+
value: number;
|
|
264
|
+
} | {
|
|
265
|
+
kind: 'ImmCurrentLocation';
|
|
266
|
+
span: SourceSpan;
|
|
267
|
+
} | {
|
|
268
|
+
kind: 'ImmName';
|
|
269
|
+
span: SourceSpan;
|
|
270
|
+
name: string;
|
|
271
|
+
} | {
|
|
272
|
+
kind: 'ImmSizeof';
|
|
273
|
+
span: SourceSpan;
|
|
274
|
+
typeExpr: TypeExprNode;
|
|
275
|
+
} | {
|
|
276
|
+
kind: 'ImmOffset';
|
|
277
|
+
span: SourceSpan;
|
|
278
|
+
typeExpr: TypeExprNode;
|
|
279
|
+
path: OffsetPathNode;
|
|
280
|
+
} | {
|
|
281
|
+
kind: 'ImmUnary';
|
|
282
|
+
span: SourceSpan;
|
|
283
|
+
op: '+' | '-' | '~';
|
|
284
|
+
expr: ImmExprNode;
|
|
285
|
+
} | {
|
|
286
|
+
kind: 'ImmBinary';
|
|
287
|
+
span: SourceSpan;
|
|
288
|
+
op: '*' | '/' | '%' | '+' | '-' | '&' | '^' | '|' | '<<' | '>>';
|
|
289
|
+
left: ImmExprNode;
|
|
290
|
+
right: ImmExprNode;
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* Effective-address expression variants.
|
|
294
|
+
*/
|
|
295
|
+
export type EaExprNode = {
|
|
296
|
+
kind: 'EaName';
|
|
297
|
+
span: SourceSpan;
|
|
298
|
+
name: string;
|
|
299
|
+
} | {
|
|
300
|
+
kind: 'EaImm';
|
|
301
|
+
span: SourceSpan;
|
|
302
|
+
expr: ImmExprNode;
|
|
303
|
+
} | {
|
|
304
|
+
kind: 'EaLayoutCast';
|
|
305
|
+
span: SourceSpan;
|
|
306
|
+
typeExpr: TypeExprNode;
|
|
307
|
+
base: EaExprNode;
|
|
308
|
+
} | {
|
|
309
|
+
kind: 'EaField';
|
|
310
|
+
span: SourceSpan;
|
|
311
|
+
base: EaExprNode;
|
|
312
|
+
field: string;
|
|
313
|
+
} | {
|
|
314
|
+
kind: 'EaIndex';
|
|
315
|
+
span: SourceSpan;
|
|
316
|
+
base: EaExprNode;
|
|
317
|
+
index: EaIndexNode;
|
|
318
|
+
} | {
|
|
319
|
+
kind: 'EaAdd';
|
|
320
|
+
span: SourceSpan;
|
|
321
|
+
base: EaExprNode;
|
|
322
|
+
offset: ImmExprNode;
|
|
323
|
+
} | {
|
|
324
|
+
kind: 'EaSub';
|
|
325
|
+
span: SourceSpan;
|
|
326
|
+
base: EaExprNode;
|
|
327
|
+
offset: ImmExprNode;
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* Index expression variants for effective addresses.
|
|
331
|
+
*/
|
|
332
|
+
export type EaIndexNode = {
|
|
333
|
+
kind: 'IndexImm';
|
|
334
|
+
span: SourceSpan;
|
|
335
|
+
value: ImmExprNode;
|
|
336
|
+
} | {
|
|
337
|
+
kind: 'IndexReg8';
|
|
338
|
+
span: SourceSpan; /** Canonical upper-case reg8 token. */
|
|
339
|
+
reg: string;
|
|
340
|
+
} | {
|
|
341
|
+
kind: 'IndexReg16';
|
|
342
|
+
span: SourceSpan; /** Canonical upper-case reg16 token. */
|
|
343
|
+
reg: string;
|
|
344
|
+
} | {
|
|
345
|
+
kind: 'IndexMemHL';
|
|
346
|
+
span: SourceSpan;
|
|
347
|
+
} | {
|
|
348
|
+
kind: 'IndexMemIxIy';
|
|
349
|
+
span: SourceSpan;
|
|
350
|
+
/** Canonical upper-case base register token. */
|
|
351
|
+
base: 'IX' | 'IY';
|
|
352
|
+
/** Optional displacement imm expression (signed). */
|
|
353
|
+
disp?: ImmExprNode;
|
|
354
|
+
} | {
|
|
355
|
+
kind: 'IndexEa';
|
|
356
|
+
span: SourceSpan;
|
|
357
|
+
expr: EaExprNode;
|
|
358
|
+
};
|
|
359
|
+
/**
|
|
360
|
+
* Field path used by the `offset(Type, path)` built-in.
|
|
361
|
+
*/
|
|
362
|
+
export interface OffsetPathNode extends BaseNode {
|
|
363
|
+
kind: 'OffsetPath';
|
|
364
|
+
base?: string;
|
|
365
|
+
steps: OffsetPathStepNode[];
|
|
366
|
+
}
|
|
367
|
+
export type OffsetPathStepNode = {
|
|
368
|
+
kind: 'OffsetField';
|
|
369
|
+
span: SourceSpan;
|
|
370
|
+
name: string;
|
|
371
|
+
} | {
|
|
372
|
+
kind: 'OffsetIndex';
|
|
373
|
+
span: SourceSpan;
|
|
374
|
+
expr: ImmExprNode;
|
|
375
|
+
};
|
|
376
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type DirectiveAliasProfileName = 'azm';
|
|
2
|
+
export type DirectiveAliasProfile = {
|
|
3
|
+
name?: string;
|
|
4
|
+
extends?: DirectiveAliasProfileName;
|
|
5
|
+
directiveAliases?: Record<string, string>;
|
|
6
|
+
};
|
|
7
|
+
export type DirectiveAliasPolicy = {
|
|
8
|
+
directiveAliases: Map<string, string>;
|
|
9
|
+
};
|
|
10
|
+
export declare function defaultDirectiveAliasProfileName(): DirectiveAliasProfileName;
|
|
11
|
+
export declare function buildDirectiveAliasPolicy(profileName: DirectiveAliasProfileName, projectProfiles?: DirectiveAliasProfile[]): DirectiveAliasPolicy;
|
|
12
|
+
export declare function readDirectiveAliasProfile(path: string): Promise<DirectiveAliasProfile>;
|
|
13
|
+
export declare function resolveDirectiveAlias(head: string, policy: DirectiveAliasPolicy | undefined): string | undefined;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { TOP_LEVEL_KEYWORDS } from './grammarData.js';
|
|
3
|
+
const RESERVED_INSTRUCTION_HEADS = new Set([
|
|
4
|
+
'adc',
|
|
5
|
+
'add',
|
|
6
|
+
'and',
|
|
7
|
+
'bit',
|
|
8
|
+
'call',
|
|
9
|
+
'ccf',
|
|
10
|
+
'cp',
|
|
11
|
+
'cpd',
|
|
12
|
+
'cpdr',
|
|
13
|
+
'cpi',
|
|
14
|
+
'cpir',
|
|
15
|
+
'cpl',
|
|
16
|
+
'daa',
|
|
17
|
+
'dec',
|
|
18
|
+
'di',
|
|
19
|
+
'djnz',
|
|
20
|
+
'ei',
|
|
21
|
+
'ex',
|
|
22
|
+
'exx',
|
|
23
|
+
'halt',
|
|
24
|
+
'im',
|
|
25
|
+
'in',
|
|
26
|
+
'inc',
|
|
27
|
+
'ind',
|
|
28
|
+
'indr',
|
|
29
|
+
'ini',
|
|
30
|
+
'inir',
|
|
31
|
+
'jp',
|
|
32
|
+
'jr',
|
|
33
|
+
'ld',
|
|
34
|
+
'ldd',
|
|
35
|
+
'lddr',
|
|
36
|
+
'ldi',
|
|
37
|
+
'ldir',
|
|
38
|
+
'neg',
|
|
39
|
+
'nop',
|
|
40
|
+
'or',
|
|
41
|
+
'otdr',
|
|
42
|
+
'otir',
|
|
43
|
+
'out',
|
|
44
|
+
'outd',
|
|
45
|
+
'outi',
|
|
46
|
+
'pop',
|
|
47
|
+
'push',
|
|
48
|
+
'res',
|
|
49
|
+
'ret',
|
|
50
|
+
'reti',
|
|
51
|
+
'retn',
|
|
52
|
+
'rl',
|
|
53
|
+
'rla',
|
|
54
|
+
'rlc',
|
|
55
|
+
'rlca',
|
|
56
|
+
'rld',
|
|
57
|
+
'rr',
|
|
58
|
+
'rra',
|
|
59
|
+
'rrc',
|
|
60
|
+
'rrca',
|
|
61
|
+
'rrd',
|
|
62
|
+
'rst',
|
|
63
|
+
'sbc',
|
|
64
|
+
'scf',
|
|
65
|
+
'set',
|
|
66
|
+
'sla',
|
|
67
|
+
'sll',
|
|
68
|
+
'sra',
|
|
69
|
+
'srl',
|
|
70
|
+
'sub',
|
|
71
|
+
'xor',
|
|
72
|
+
]);
|
|
73
|
+
const CANONICAL_DIRECTIVES = new Set([
|
|
74
|
+
'.align',
|
|
75
|
+
'.binfrom',
|
|
76
|
+
'.binto',
|
|
77
|
+
'.cstr',
|
|
78
|
+
'.db',
|
|
79
|
+
'.ds',
|
|
80
|
+
'.dw',
|
|
81
|
+
'.end',
|
|
82
|
+
'.equ',
|
|
83
|
+
'.include',
|
|
84
|
+
'.istr',
|
|
85
|
+
'.org',
|
|
86
|
+
'.pstr',
|
|
87
|
+
]);
|
|
88
|
+
const BUILTIN_PROFILES = {
|
|
89
|
+
azm: {
|
|
90
|
+
name: 'azm',
|
|
91
|
+
directiveAliases: {
|
|
92
|
+
ALIGN: '.align',
|
|
93
|
+
BINFROM: '.binfrom',
|
|
94
|
+
BINTO: '.binto',
|
|
95
|
+
CSTR: '.cstr',
|
|
96
|
+
DB: '.db',
|
|
97
|
+
DS: '.ds',
|
|
98
|
+
DW: '.dw',
|
|
99
|
+
END: '.end',
|
|
100
|
+
EQU: '.equ',
|
|
101
|
+
INCLUDE: '.include',
|
|
102
|
+
ISTR: '.istr',
|
|
103
|
+
ORG: '.org',
|
|
104
|
+
PSTR: '.pstr',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
export function defaultDirectiveAliasProfileName() {
|
|
109
|
+
return 'azm';
|
|
110
|
+
}
|
|
111
|
+
function normalizeAliasKey(key) {
|
|
112
|
+
const trimmed = key.trim();
|
|
113
|
+
if (!/^[.]?[A-Za-z][A-Za-z0-9_]*$/.test(trimmed))
|
|
114
|
+
return undefined;
|
|
115
|
+
return trimmed.replace(/^\./, '').toLowerCase();
|
|
116
|
+
}
|
|
117
|
+
function normalizeAliasTarget(value) {
|
|
118
|
+
const trimmed = value.trim().toLowerCase();
|
|
119
|
+
const dotted = trimmed.startsWith('.') ? trimmed : `.${trimmed}`;
|
|
120
|
+
if (!CANONICAL_DIRECTIVES.has(dotted))
|
|
121
|
+
return undefined;
|
|
122
|
+
return dotted;
|
|
123
|
+
}
|
|
124
|
+
function mergeProfile(profile, out, seen, source, baselineKeys = new Set()) {
|
|
125
|
+
if (profile.extends) {
|
|
126
|
+
if (seen.has(profile.extends)) {
|
|
127
|
+
throw new Error(`Directive alias profile cycle at "${profile.extends}"`);
|
|
128
|
+
}
|
|
129
|
+
seen.add(profile.extends);
|
|
130
|
+
mergeProfile(BUILTIN_PROFILES[profile.extends], out, seen, 'builtin', baselineKeys);
|
|
131
|
+
seen.delete(profile.extends);
|
|
132
|
+
}
|
|
133
|
+
for (const [rawKey, rawTarget] of Object.entries(profile.directiveAliases ?? {})) {
|
|
134
|
+
const key = normalizeAliasKey(rawKey);
|
|
135
|
+
if (!key)
|
|
136
|
+
throw new Error(`Invalid directive alias head "${rawKey}"`);
|
|
137
|
+
if (source === 'project') {
|
|
138
|
+
if (baselineKeys.has(key)) {
|
|
139
|
+
throw new Error(`Directive alias "${rawKey}" conflicts with the AZM baseline`);
|
|
140
|
+
}
|
|
141
|
+
if (RESERVED_INSTRUCTION_HEADS.has(key)) {
|
|
142
|
+
throw new Error(`Directive alias "${rawKey}" conflicts with a Z80 instruction`);
|
|
143
|
+
}
|
|
144
|
+
if (TOP_LEVEL_KEYWORDS.has(key)) {
|
|
145
|
+
throw new Error(`Directive alias "${rawKey}" conflicts with an AZM language keyword`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const target = normalizeAliasTarget(rawTarget);
|
|
149
|
+
if (!target)
|
|
150
|
+
throw new Error(`Invalid directive alias target "${rawTarget}" for "${rawKey}"`);
|
|
151
|
+
out.set(key, target);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export function buildDirectiveAliasPolicy(profileName, projectProfiles = []) {
|
|
155
|
+
const directiveAliases = new Map();
|
|
156
|
+
mergeProfile(BUILTIN_PROFILES[profileName], directiveAliases, new Set([profileName]), 'builtin');
|
|
157
|
+
const baselineKeys = new Set(directiveAliases.keys());
|
|
158
|
+
for (const profile of projectProfiles) {
|
|
159
|
+
mergeProfile(profile, directiveAliases, new Set(), 'project', baselineKeys);
|
|
160
|
+
}
|
|
161
|
+
return { directiveAliases };
|
|
162
|
+
}
|
|
163
|
+
export async function readDirectiveAliasProfile(path) {
|
|
164
|
+
const text = await readFile(path, 'utf8');
|
|
165
|
+
const parsed = JSON.parse(text);
|
|
166
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
167
|
+
throw new Error(`Directive alias file "${path}" must contain a JSON object`);
|
|
168
|
+
}
|
|
169
|
+
const profile = parsed;
|
|
170
|
+
if (profile.extends !== undefined && profile.extends !== 'azm') {
|
|
171
|
+
throw new Error(`Unsupported directive alias base "${String(profile.extends)}" in "${path}"`);
|
|
172
|
+
}
|
|
173
|
+
if (profile.directiveAliases !== undefined &&
|
|
174
|
+
(!profile.directiveAliases ||
|
|
175
|
+
typeof profile.directiveAliases !== 'object' ||
|
|
176
|
+
Array.isArray(profile.directiveAliases))) {
|
|
177
|
+
throw new Error(`Directive alias file "${path}" has invalid "directiveAliases"`);
|
|
178
|
+
}
|
|
179
|
+
return profile;
|
|
180
|
+
}
|
|
181
|
+
export function resolveDirectiveAlias(head, policy) {
|
|
182
|
+
const normalized = normalizeAliasKey(head);
|
|
183
|
+
if (!normalized)
|
|
184
|
+
return undefined;
|
|
185
|
+
const dotted = `.${normalized}`;
|
|
186
|
+
if (head.trim().startsWith('.') && CANONICAL_DIRECTIVES.has(dotted))
|
|
187
|
+
return dotted;
|
|
188
|
+
return policy?.directiveAliases.get(normalized);
|
|
189
|
+
}
|