@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,397 @@
|
|
|
1
|
+
import { parseDiag as diag } from './parseDiagnostics.js';
|
|
2
|
+
import { CHAR_ESCAPE_VALUES, IMM_BINARY_OPERATORS, IMM_BINARY_OPERATOR_PRECEDENCE, IMM_MULTI_CHAR_OPERATORS, IMM_UNARY_OPERATOR_SET, } from './grammarData.js';
|
|
3
|
+
export function immLiteral(filePath, s, value) {
|
|
4
|
+
return { kind: 'ImmLiteral', span: { ...s, file: filePath }, value };
|
|
5
|
+
}
|
|
6
|
+
function immName(filePath, s, name) {
|
|
7
|
+
return { kind: 'ImmName', span: { ...s, file: filePath }, name };
|
|
8
|
+
}
|
|
9
|
+
export function parseTypeExprFromText(typeText, typeSpan) {
|
|
10
|
+
let rest = typeText.trim();
|
|
11
|
+
const nameMatch = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(rest);
|
|
12
|
+
if (!nameMatch)
|
|
13
|
+
return undefined;
|
|
14
|
+
const name = nameMatch[1];
|
|
15
|
+
rest = rest.slice(name.length).trimStart();
|
|
16
|
+
let typeExpr = { kind: 'TypeName', span: typeSpan, name };
|
|
17
|
+
while (rest.startsWith('[')) {
|
|
18
|
+
const m = /^\[\s*([0-9]+)?\s*\]/.exec(rest);
|
|
19
|
+
if (!m)
|
|
20
|
+
return undefined;
|
|
21
|
+
const lenText = m[1];
|
|
22
|
+
if (lenText === undefined)
|
|
23
|
+
return undefined;
|
|
24
|
+
typeExpr = {
|
|
25
|
+
kind: 'ArrayType',
|
|
26
|
+
span: typeSpan,
|
|
27
|
+
element: typeExpr,
|
|
28
|
+
length: Number.parseInt(lenText, 10),
|
|
29
|
+
};
|
|
30
|
+
rest = rest.slice(m[0].length).trimStart();
|
|
31
|
+
}
|
|
32
|
+
if (rest.length > 0)
|
|
33
|
+
return undefined;
|
|
34
|
+
return typeExpr;
|
|
35
|
+
}
|
|
36
|
+
export function diagIfArrayLengthMissing(diagnostics, filePath, typeText, where) {
|
|
37
|
+
if (!/\[\s*\]/.test(typeText))
|
|
38
|
+
return false;
|
|
39
|
+
diag(diagnostics, filePath, `Array length is required here; write T[N].`, where);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
export function parseNumberLiteral(text) {
|
|
43
|
+
const t = text.trim();
|
|
44
|
+
if (/^[0-9][0-9A-Fa-f]*[Hh]$/.test(t)) {
|
|
45
|
+
return Number.parseInt(t.slice(0, -1), 16);
|
|
46
|
+
}
|
|
47
|
+
if (/^[01]+[Bb]$/.test(t)) {
|
|
48
|
+
return Number.parseInt(t.slice(0, -1), 2);
|
|
49
|
+
}
|
|
50
|
+
if (/^\$[0-9A-Fa-f]+$/.test(t)) {
|
|
51
|
+
return Number.parseInt(t.slice(1), 16);
|
|
52
|
+
}
|
|
53
|
+
if (/^%[01]+$/.test(t)) {
|
|
54
|
+
return Number.parseInt(t.slice(1), 2);
|
|
55
|
+
}
|
|
56
|
+
if (/^0b[01]+$/.test(t)) {
|
|
57
|
+
return Number.parseInt(t.slice(2), 2);
|
|
58
|
+
}
|
|
59
|
+
if (/^0x[0-9A-Fa-f]+$/i.test(t)) {
|
|
60
|
+
return Number.parseInt(t.slice(2), 16);
|
|
61
|
+
}
|
|
62
|
+
if (/^[0-9]+$/.test(t)) {
|
|
63
|
+
return Number.parseInt(t, 10);
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
function isImmUnaryOp(op) {
|
|
68
|
+
return IMM_UNARY_OPERATOR_SET.has(op);
|
|
69
|
+
}
|
|
70
|
+
function isImmBinaryOp(op) {
|
|
71
|
+
return IMM_BINARY_OPERATORS.has(op);
|
|
72
|
+
}
|
|
73
|
+
function isImmOpToken(text) {
|
|
74
|
+
return IMM_UNARY_OPERATOR_SET.has(text) || IMM_BINARY_OPERATORS.has(text);
|
|
75
|
+
}
|
|
76
|
+
function scanQuotedByteValue(s, start, quote) {
|
|
77
|
+
let i = start + 1;
|
|
78
|
+
if (i >= s.length)
|
|
79
|
+
return undefined;
|
|
80
|
+
let value;
|
|
81
|
+
if (s[i] === '\\') {
|
|
82
|
+
i++;
|
|
83
|
+
if (i >= s.length)
|
|
84
|
+
return undefined;
|
|
85
|
+
const esc = s[i];
|
|
86
|
+
i++;
|
|
87
|
+
if (esc === 'x') {
|
|
88
|
+
const hex = s.slice(i, i + 2);
|
|
89
|
+
if (!/^[0-9A-Fa-f]{2}$/.test(hex))
|
|
90
|
+
return undefined;
|
|
91
|
+
value = Number.parseInt(hex, 16);
|
|
92
|
+
i += 2;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const escaped = CHAR_ESCAPE_VALUES.get(esc);
|
|
96
|
+
if (escaped === undefined)
|
|
97
|
+
return undefined;
|
|
98
|
+
value = escaped;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
if (s[i] === quote || s[i] === '\n' || s[i] === '\r')
|
|
103
|
+
return undefined;
|
|
104
|
+
const cp = s.codePointAt(i);
|
|
105
|
+
if (cp === undefined)
|
|
106
|
+
return undefined;
|
|
107
|
+
value = cp;
|
|
108
|
+
i += cp > 0xffff ? 2 : 1;
|
|
109
|
+
}
|
|
110
|
+
if (i >= s.length || s[i] !== quote)
|
|
111
|
+
return undefined;
|
|
112
|
+
return { value, end: i + 1 };
|
|
113
|
+
}
|
|
114
|
+
function tokenizeImm(text) {
|
|
115
|
+
const out = [];
|
|
116
|
+
let i = 0;
|
|
117
|
+
const s = text.trim();
|
|
118
|
+
while (i < s.length) {
|
|
119
|
+
const ch = s[i];
|
|
120
|
+
if (/\s/.test(ch)) {
|
|
121
|
+
i++;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (ch === '(') {
|
|
125
|
+
out.push({ kind: 'lparen' });
|
|
126
|
+
i++;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (ch === ',') {
|
|
130
|
+
out.push({ kind: 'comma' });
|
|
131
|
+
i++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (ch === '.') {
|
|
135
|
+
out.push({ kind: 'dot' });
|
|
136
|
+
i++;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (ch === ')') {
|
|
140
|
+
out.push({ kind: 'rparen' });
|
|
141
|
+
i++;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (ch === '[') {
|
|
145
|
+
out.push({ kind: 'lbrack' });
|
|
146
|
+
i++;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (ch === ']') {
|
|
150
|
+
out.push({ kind: 'rbrack' });
|
|
151
|
+
i++;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const two = s.slice(i, i + 2);
|
|
155
|
+
if (IMM_MULTI_CHAR_OPERATORS.has(two)) {
|
|
156
|
+
out.push({ kind: 'op', text: two });
|
|
157
|
+
i += 2;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (ch === '$') {
|
|
161
|
+
if (/^[0-9A-Fa-f]/.test(s[i + 1] ?? '')) {
|
|
162
|
+
const num = /^\$[0-9A-Fa-f]+/.exec(s.slice(i));
|
|
163
|
+
if (!num)
|
|
164
|
+
return undefined;
|
|
165
|
+
out.push({ kind: 'num', text: num[0] });
|
|
166
|
+
i += num[0].length;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (/^[A-Za-z_]/.test(s[i + 1] ?? ''))
|
|
170
|
+
return undefined;
|
|
171
|
+
out.push({ kind: 'current' });
|
|
172
|
+
i++;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (ch === "'" || ch === '"') {
|
|
176
|
+
const quoted = scanQuotedByteValue(s, i, ch);
|
|
177
|
+
if (!quoted)
|
|
178
|
+
return undefined;
|
|
179
|
+
i = quoted.end;
|
|
180
|
+
out.push({ kind: 'num', text: String(quoted.value) });
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const num = /^([0-9][0-9A-Fa-f]*[Hh]|%[01]+|0b[01]+|0x[0-9A-Fa-f]+|[01]+[Bb]|[0-9]+)/i.exec(s.slice(i));
|
|
184
|
+
if (num) {
|
|
185
|
+
out.push({ kind: 'num', text: num[0] });
|
|
186
|
+
i += num[0].length;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (isImmOpToken(ch)) {
|
|
190
|
+
out.push({ kind: 'op', text: ch });
|
|
191
|
+
i++;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const ident = /^[A-Za-z_][A-Za-z0-9_]*/.exec(s.slice(i));
|
|
195
|
+
if (ident) {
|
|
196
|
+
out.push({ kind: 'ident', text: ident[0] });
|
|
197
|
+
i += ident[0].length;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
204
|
+
export function parseImmExprFromText(filePath, exprText, exprSpan, diagnostics, emitDiagnostics = true) {
|
|
205
|
+
const tokenized = tokenizeImm(exprText);
|
|
206
|
+
if (!tokenized) {
|
|
207
|
+
if (emitDiagnostics) {
|
|
208
|
+
diag(diagnostics, filePath, `Invalid imm expression: ${exprText}`, {
|
|
209
|
+
line: exprSpan.start.line,
|
|
210
|
+
column: exprSpan.start.column,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
const tokens = tokenized;
|
|
216
|
+
let idx = 0;
|
|
217
|
+
function parseDottedIdentName() {
|
|
218
|
+
const first = tokens[idx];
|
|
219
|
+
if (!first || first.kind !== 'ident')
|
|
220
|
+
return undefined;
|
|
221
|
+
const parts = [first.text];
|
|
222
|
+
idx++;
|
|
223
|
+
while (tokens[idx]?.kind === 'dot') {
|
|
224
|
+
const next = tokens[idx + 1];
|
|
225
|
+
if (!next || next.kind !== 'ident')
|
|
226
|
+
return undefined;
|
|
227
|
+
parts.push(next.text);
|
|
228
|
+
idx += 2;
|
|
229
|
+
}
|
|
230
|
+
return parts.join('.');
|
|
231
|
+
}
|
|
232
|
+
function parseBuiltinTypeExprArg() {
|
|
233
|
+
const nameTok = tokens[idx];
|
|
234
|
+
if (!nameTok || nameTok.kind !== 'ident')
|
|
235
|
+
return undefined;
|
|
236
|
+
const name = nameTok.text;
|
|
237
|
+
idx++;
|
|
238
|
+
let typeExpr = { kind: 'TypeName', span: exprSpan, name };
|
|
239
|
+
while (tokens[idx]?.kind === 'lbrack') {
|
|
240
|
+
idx++;
|
|
241
|
+
const lenTok = tokens[idx];
|
|
242
|
+
if (!lenTok || lenTok.kind !== 'num')
|
|
243
|
+
return undefined;
|
|
244
|
+
if (!/^[0-9]+$/.test(lenTok.text))
|
|
245
|
+
return undefined;
|
|
246
|
+
const len = Number.parseInt(lenTok.text, 10);
|
|
247
|
+
idx++;
|
|
248
|
+
if (tokens[idx]?.kind !== 'rbrack')
|
|
249
|
+
return undefined;
|
|
250
|
+
idx++;
|
|
251
|
+
typeExpr = { kind: 'ArrayType', span: exprSpan, element: typeExpr, length: len };
|
|
252
|
+
}
|
|
253
|
+
return typeExpr;
|
|
254
|
+
}
|
|
255
|
+
function parseOffsetPathArg() {
|
|
256
|
+
const root = tokens[idx];
|
|
257
|
+
if (!root || (root.kind !== 'ident' && root.kind !== 'lbrack'))
|
|
258
|
+
return undefined;
|
|
259
|
+
const base = root.kind === 'ident' ? root.text : undefined;
|
|
260
|
+
if (base !== undefined)
|
|
261
|
+
idx++;
|
|
262
|
+
const path = {
|
|
263
|
+
kind: 'OffsetPath',
|
|
264
|
+
span: exprSpan,
|
|
265
|
+
...(base !== undefined ? { base } : {}),
|
|
266
|
+
steps: [],
|
|
267
|
+
};
|
|
268
|
+
while (true) {
|
|
269
|
+
if (tokens[idx]?.kind === 'dot') {
|
|
270
|
+
idx++;
|
|
271
|
+
const fieldTok = tokens[idx];
|
|
272
|
+
if (!fieldTok || fieldTok.kind !== 'ident')
|
|
273
|
+
return undefined;
|
|
274
|
+
idx++;
|
|
275
|
+
path.steps.push({ kind: 'OffsetField', span: exprSpan, name: fieldTok.text });
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (tokens[idx]?.kind === 'lbrack') {
|
|
279
|
+
idx++;
|
|
280
|
+
const inner = parseExpr(1);
|
|
281
|
+
if (!inner)
|
|
282
|
+
return undefined;
|
|
283
|
+
if (tokens[idx]?.kind !== 'rbrack')
|
|
284
|
+
return undefined;
|
|
285
|
+
idx++;
|
|
286
|
+
path.steps.push({ kind: 'OffsetIndex', span: exprSpan, expr: inner });
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
return path;
|
|
292
|
+
}
|
|
293
|
+
function parseExpr(minPrec) {
|
|
294
|
+
let left = parsePrimary();
|
|
295
|
+
if (!left)
|
|
296
|
+
return undefined;
|
|
297
|
+
while (true) {
|
|
298
|
+
const t = tokens[idx];
|
|
299
|
+
if (!t || t.kind !== 'op')
|
|
300
|
+
break;
|
|
301
|
+
const prec = IMM_BINARY_OPERATOR_PRECEDENCE.get(t.text) ?? 0;
|
|
302
|
+
if (prec < minPrec)
|
|
303
|
+
break;
|
|
304
|
+
if (!isImmBinaryOp(t.text))
|
|
305
|
+
break;
|
|
306
|
+
idx++;
|
|
307
|
+
const right = parseExpr(prec + 1);
|
|
308
|
+
if (!right)
|
|
309
|
+
return undefined;
|
|
310
|
+
left = { kind: 'ImmBinary', span: exprSpan, op: t.text, left, right };
|
|
311
|
+
}
|
|
312
|
+
return left;
|
|
313
|
+
}
|
|
314
|
+
function parsePrimary() {
|
|
315
|
+
const t = tokens[idx];
|
|
316
|
+
if (!t)
|
|
317
|
+
return undefined;
|
|
318
|
+
if (t.kind === 'num') {
|
|
319
|
+
idx++;
|
|
320
|
+
const n = parseNumberLiteral(t.text);
|
|
321
|
+
if (n === undefined)
|
|
322
|
+
return undefined;
|
|
323
|
+
return immLiteral(filePath, exprSpan, n);
|
|
324
|
+
}
|
|
325
|
+
if (t.kind === 'current') {
|
|
326
|
+
idx++;
|
|
327
|
+
return { kind: 'ImmCurrentLocation', span: { ...exprSpan, file: filePath } };
|
|
328
|
+
}
|
|
329
|
+
if (t.kind === 'ident') {
|
|
330
|
+
if (t.text === 'sizeof' && tokens[idx + 1]?.kind === 'lparen') {
|
|
331
|
+
idx += 2;
|
|
332
|
+
const typeExpr = parseBuiltinTypeExprArg();
|
|
333
|
+
if (!typeExpr)
|
|
334
|
+
return undefined;
|
|
335
|
+
if (tokens[idx]?.kind !== 'rparen')
|
|
336
|
+
return undefined;
|
|
337
|
+
idx++;
|
|
338
|
+
return { kind: 'ImmSizeof', span: exprSpan, typeExpr };
|
|
339
|
+
}
|
|
340
|
+
if (t.text === 'offset' && tokens[idx + 1]?.kind === 'lparen') {
|
|
341
|
+
idx += 2;
|
|
342
|
+
const typeExpr = parseBuiltinTypeExprArg();
|
|
343
|
+
if (!typeExpr)
|
|
344
|
+
return undefined;
|
|
345
|
+
if (tokens[idx]?.kind !== 'comma')
|
|
346
|
+
return undefined;
|
|
347
|
+
idx++;
|
|
348
|
+
const path = parseOffsetPathArg();
|
|
349
|
+
if (!path)
|
|
350
|
+
return undefined;
|
|
351
|
+
if (tokens[idx]?.kind !== 'rparen')
|
|
352
|
+
return undefined;
|
|
353
|
+
idx++;
|
|
354
|
+
return { kind: 'ImmOffset', span: exprSpan, typeExpr, path };
|
|
355
|
+
}
|
|
356
|
+
const name = parseDottedIdentName();
|
|
357
|
+
return name ? immName(filePath, exprSpan, name) : undefined;
|
|
358
|
+
}
|
|
359
|
+
if (t.kind === 'dot') {
|
|
360
|
+
const next = tokens[idx + 1];
|
|
361
|
+
if (!next || next.kind !== 'ident')
|
|
362
|
+
return undefined;
|
|
363
|
+
const name = next.text;
|
|
364
|
+
idx += 2;
|
|
365
|
+
return immName(filePath, exprSpan, `.${name}`);
|
|
366
|
+
}
|
|
367
|
+
if (t.kind === 'op' && isImmUnaryOp(t.text)) {
|
|
368
|
+
idx++;
|
|
369
|
+
const inner = parsePrimary();
|
|
370
|
+
if (!inner)
|
|
371
|
+
return undefined;
|
|
372
|
+
return { kind: 'ImmUnary', span: exprSpan, op: t.text, expr: inner };
|
|
373
|
+
}
|
|
374
|
+
if (t.kind === 'lparen') {
|
|
375
|
+
idx++;
|
|
376
|
+
const inner = parseExpr(1);
|
|
377
|
+
if (!inner)
|
|
378
|
+
return undefined;
|
|
379
|
+
if (tokens[idx]?.kind !== 'rparen')
|
|
380
|
+
return undefined;
|
|
381
|
+
idx++;
|
|
382
|
+
return inner;
|
|
383
|
+
}
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
const root = parseExpr(1);
|
|
387
|
+
if (!root || idx !== tokens.length) {
|
|
388
|
+
if (emitDiagnostics) {
|
|
389
|
+
diag(diagnostics, filePath, `Invalid imm expression: ${exprText}`, {
|
|
390
|
+
line: exprSpan.start.line,
|
|
391
|
+
column: exprSpan.start.column,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return undefined;
|
|
395
|
+
}
|
|
396
|
+
return root;
|
|
397
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Diagnostic } from '../diagnosticTypes.js';
|
|
2
|
+
import type { SourceFile } from './source.js';
|
|
3
|
+
export type LogicalLine = {
|
|
4
|
+
raw: string;
|
|
5
|
+
startOffset: number;
|
|
6
|
+
endOffset: number;
|
|
7
|
+
lineNo: number;
|
|
8
|
+
filePath: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function buildLogicalLines(file: SourceFile, sourcePath: string, diagnostics: Diagnostic[]): LogicalLine[];
|
|
11
|
+
export declare function getLogicalLine(logicalLines: LogicalLine[], lineIndex: number, sourcePath: string): LogicalLine;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { parseDiag as diag } from './parseDiagnostics.js';
|
|
2
|
+
export function buildLogicalLines(file, sourcePath, diagnostics) {
|
|
3
|
+
const logicalLines = [];
|
|
4
|
+
for (let i = 0; i < file.lineStarts.length; i++) {
|
|
5
|
+
const startOffset = file.lineStarts[i] ?? 0;
|
|
6
|
+
const nextStart = file.lineStarts[i + 1] ?? file.text.length;
|
|
7
|
+
let rawWithEol = file.text.slice(startOffset, nextStart);
|
|
8
|
+
if (rawWithEol.endsWith('\n'))
|
|
9
|
+
rawWithEol = rawWithEol.slice(0, -1);
|
|
10
|
+
if (rawWithEol.endsWith('\r'))
|
|
11
|
+
rawWithEol = rawWithEol.slice(0, -1);
|
|
12
|
+
const raw = rawWithEol;
|
|
13
|
+
const lineNo = file.lineBaseLines?.[i] ?? i + 1;
|
|
14
|
+
const filePath = file.lineFiles?.[i] ?? sourcePath;
|
|
15
|
+
let segmentStart = 0;
|
|
16
|
+
let inChar = false;
|
|
17
|
+
let inString = false;
|
|
18
|
+
let escaped = false;
|
|
19
|
+
for (let j = 0; j < raw.length; j++) {
|
|
20
|
+
const ch = raw[j];
|
|
21
|
+
if (inChar || inString) {
|
|
22
|
+
if (escaped) {
|
|
23
|
+
escaped = false;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (ch === '\\') {
|
|
27
|
+
escaped = true;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (inChar && ch === "'") {
|
|
31
|
+
inChar = false;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (inString && ch === '"') {
|
|
35
|
+
inString = false;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (ch === ';') {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
if (ch === "'") {
|
|
44
|
+
inChar = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (ch === '"') {
|
|
48
|
+
inString = true;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (ch === '\\') {
|
|
52
|
+
const rest = raw.slice(j + 1);
|
|
53
|
+
const hasWhitespace = rest.length > 0 && /[ \t]/.test(rest[0]);
|
|
54
|
+
if (!hasWhitespace && rest.length > 0)
|
|
55
|
+
continue;
|
|
56
|
+
const nonSpaceIndex = rest.search(/[^\s]/);
|
|
57
|
+
const nextToken = nonSpaceIndex >= 0 ? rest[nonSpaceIndex] : '';
|
|
58
|
+
if (nonSpaceIndex === -1 || nextToken === ';') {
|
|
59
|
+
diag(diagnostics, filePath, 'Trailing backslash must be followed by another statement.', {
|
|
60
|
+
line: lineNo,
|
|
61
|
+
column: j + 1,
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const segment = raw.slice(segmentStart, j);
|
|
66
|
+
logicalLines.push({
|
|
67
|
+
raw: segment,
|
|
68
|
+
startOffset: startOffset + segmentStart,
|
|
69
|
+
endOffset: startOffset + j,
|
|
70
|
+
lineNo,
|
|
71
|
+
filePath,
|
|
72
|
+
});
|
|
73
|
+
segmentStart = j + 1;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
logicalLines.push({
|
|
77
|
+
raw: raw.slice(segmentStart),
|
|
78
|
+
startOffset: startOffset + segmentStart,
|
|
79
|
+
endOffset: startOffset + raw.length,
|
|
80
|
+
lineNo,
|
|
81
|
+
filePath,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return logicalLines;
|
|
85
|
+
}
|
|
86
|
+
export function getLogicalLine(logicalLines, lineIndex, sourcePath) {
|
|
87
|
+
return (logicalLines[lineIndex] ?? {
|
|
88
|
+
raw: '',
|
|
89
|
+
startOffset: 0,
|
|
90
|
+
endOffset: 0,
|
|
91
|
+
lineNo: 1,
|
|
92
|
+
filePath: sourcePath,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { OpDeclNode, OpParamNode, SourceSpan } from './ast.js';
|
|
2
|
+
import type { SourceFile } from './source.js';
|
|
3
|
+
import type { Diagnostic } from '../diagnosticTypes.js';
|
|
4
|
+
import type { ParseParamsContext } from './parseParams.js';
|
|
5
|
+
type RawLine = {
|
|
6
|
+
raw: string;
|
|
7
|
+
startOffset: number;
|
|
8
|
+
endOffset: number;
|
|
9
|
+
lineNo: number;
|
|
10
|
+
filePath: string;
|
|
11
|
+
};
|
|
12
|
+
type ParseOpContext = {
|
|
13
|
+
file: SourceFile;
|
|
14
|
+
lineCount: number;
|
|
15
|
+
diagnostics: Diagnostic[];
|
|
16
|
+
sourcePath: string;
|
|
17
|
+
getRawLine: (lineIndex: number) => RawLine;
|
|
18
|
+
parseOpParamsFromText: (filePath: string, paramsText: string, paramsSpan: SourceSpan, diagnostics: Diagnostic[], ctx: ParseParamsContext) => OpParamNode[] | undefined;
|
|
19
|
+
} & ParseParamsContext;
|
|
20
|
+
type ParsedOpDecl = {
|
|
21
|
+
node: OpDeclNode;
|
|
22
|
+
nextIndex: number;
|
|
23
|
+
};
|
|
24
|
+
export declare function parseTopLevelOpDecl(opTail: string, stmtText: string, stmtSpan: SourceSpan, lineNo: number, startIndex: number, ctx: ParseOpContext): ParsedOpDecl | undefined;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { span } from './source.js';
|
|
2
|
+
import { parseDiag as diag } from './parseDiagnostics.js';
|
|
3
|
+
import { appendParsedAsmStatement, parseAsmStatement } from './parseAsmStatements.js';
|
|
4
|
+
import { topLevelStartKeyword } from './parseTopLevelCommon.js';
|
|
5
|
+
import { stripLineComment as stripComment } from './parseParserShared.js';
|
|
6
|
+
import { parseOpHeader } from './parseOpHeader.js';
|
|
7
|
+
export function parseTopLevelOpDecl(opTail, stmtText, stmtSpan, lineNo, startIndex, ctx) {
|
|
8
|
+
const { file, lineCount, diagnostics, sourcePath, getRawLine, isReservedTopLevelName, parseOpParamsFromText, } = ctx;
|
|
9
|
+
const parsedHeader = parseOpHeader({
|
|
10
|
+
header: opTail,
|
|
11
|
+
stmtText,
|
|
12
|
+
stmtSpan,
|
|
13
|
+
lineNo,
|
|
14
|
+
diagnostics,
|
|
15
|
+
sourcePath,
|
|
16
|
+
expectedHeader: '<name>(...)',
|
|
17
|
+
isReservedTopLevelName,
|
|
18
|
+
parseParams: (paramsText) => parseOpParamsFromText(sourcePath, paramsText, stmtSpan, diagnostics, {
|
|
19
|
+
isReservedTopLevelName,
|
|
20
|
+
}),
|
|
21
|
+
});
|
|
22
|
+
if (!parsedHeader) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const name = parsedHeader.name;
|
|
26
|
+
const params = parsedHeader.params;
|
|
27
|
+
const trailing = parsedHeader.trailing.trim();
|
|
28
|
+
if (trailing.length > 0) {
|
|
29
|
+
diag(diagnostics, sourcePath, `Invalid op header: unexpected trailing tokens`, {
|
|
30
|
+
line: lineNo,
|
|
31
|
+
column: 1,
|
|
32
|
+
});
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const opStartOffset = stmtSpan.start.offset;
|
|
36
|
+
let index = startIndex + 1;
|
|
37
|
+
const bodyItems = [];
|
|
38
|
+
let terminated = false;
|
|
39
|
+
let interruptedByKeyword;
|
|
40
|
+
let interruptedByLine;
|
|
41
|
+
let interruptedByFilePath;
|
|
42
|
+
let opEndOffset = file.text.length;
|
|
43
|
+
while (index < lineCount) {
|
|
44
|
+
const { raw: rawLine, startOffset: so, endOffset: eo, lineNo: bodyLineNo, filePath: bodyFilePath, } = getRawLine(index);
|
|
45
|
+
const rawNoComment = stripComment(rawLine);
|
|
46
|
+
const content = rawNoComment.trim();
|
|
47
|
+
const contentLower = content.toLowerCase();
|
|
48
|
+
if (content.length === 0) {
|
|
49
|
+
index++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (bodyItems.length === 0 && contentLower === 'asm') {
|
|
53
|
+
diag(diagnostics, bodyFilePath, `Unexpected "asm" in op body (op bodies are implicit)`, {
|
|
54
|
+
line: bodyLineNo,
|
|
55
|
+
column: 1,
|
|
56
|
+
});
|
|
57
|
+
index++;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (contentLower === 'end') {
|
|
61
|
+
terminated = true;
|
|
62
|
+
opEndOffset = eo;
|
|
63
|
+
index++;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
const topKeyword = topLevelStartKeyword(content);
|
|
67
|
+
if (topKeyword !== undefined) {
|
|
68
|
+
interruptedByKeyword = topKeyword;
|
|
69
|
+
interruptedByLine = bodyLineNo;
|
|
70
|
+
interruptedByFilePath = bodyFilePath;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
const fullSpan = span(file, so, eo);
|
|
74
|
+
const contentStart = rawNoComment.indexOf(content);
|
|
75
|
+
const contentSpan = contentStart >= 0 ? span(file, so + contentStart, so + rawNoComment.length) : fullSpan;
|
|
76
|
+
const labelMatch = /^([A-Za-z_][A-Za-z0-9_]*)\s*:(?!\=)\s*(.*)$/.exec(content);
|
|
77
|
+
if (labelMatch) {
|
|
78
|
+
const label = labelMatch[1];
|
|
79
|
+
const remainder = labelMatch[2] ?? '';
|
|
80
|
+
bodyItems.push({ kind: 'AsmLabel', span: fullSpan, name: label });
|
|
81
|
+
if (remainder.trim().length > 0) {
|
|
82
|
+
const stmt = parseAsmStatement(bodyFilePath, remainder, contentSpan, diagnostics);
|
|
83
|
+
appendParsedAsmStatement(bodyItems, stmt);
|
|
84
|
+
}
|
|
85
|
+
index++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const stmt = parseAsmStatement(bodyFilePath, content, contentSpan, diagnostics);
|
|
89
|
+
appendParsedAsmStatement(bodyItems, stmt);
|
|
90
|
+
index++;
|
|
91
|
+
}
|
|
92
|
+
if (!terminated) {
|
|
93
|
+
if (interruptedByKeyword !== undefined && interruptedByLine !== undefined) {
|
|
94
|
+
diag(diagnostics, interruptedByFilePath ?? sourcePath, `Unterminated op "${name}": expected "end" before "${interruptedByKeyword}"`, {
|
|
95
|
+
line: interruptedByLine,
|
|
96
|
+
column: 1,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
diag(diagnostics, sourcePath, `Unterminated op "${name}": missing "end"`, {
|
|
101
|
+
line: lineNo,
|
|
102
|
+
column: 1,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
node: {
|
|
108
|
+
kind: 'OpDecl',
|
|
109
|
+
span: span(file, opStartOffset, opEndOffset),
|
|
110
|
+
name,
|
|
111
|
+
params,
|
|
112
|
+
body: {
|
|
113
|
+
kind: 'AsmBlock',
|
|
114
|
+
span: span(file, opStartOffset, opEndOffset),
|
|
115
|
+
items: bodyItems,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
nextIndex: index,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SourceSpan } from './ast.js';
|
|
2
|
+
import type { Diagnostic } from '../diagnosticTypes.js';
|
|
3
|
+
type ParsedOpHeader<TParam> = {
|
|
4
|
+
name: string;
|
|
5
|
+
params: TParam[];
|
|
6
|
+
trailing: string;
|
|
7
|
+
};
|
|
8
|
+
type ParseOpHeaderOptions<TParam> = {
|
|
9
|
+
header: string;
|
|
10
|
+
stmtText: string;
|
|
11
|
+
stmtSpan: SourceSpan;
|
|
12
|
+
lineNo: number;
|
|
13
|
+
diagnostics: Diagnostic[];
|
|
14
|
+
sourcePath: string;
|
|
15
|
+
expectedHeader: string;
|
|
16
|
+
isReservedTopLevelName: (name: string) => boolean;
|
|
17
|
+
parseParams: (paramsText: string) => TParam[] | undefined;
|
|
18
|
+
};
|
|
19
|
+
export declare function parseOpHeader<TParam>(options: ParseOpHeaderOptions<TParam>): ParsedOpHeader<TParam> | undefined;
|
|
20
|
+
export {};
|