@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
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { stripLineComment } from '../source/strip-line-comment.js';
|
|
2
|
+
import { parseTypeExpr } from './parse-expression.js';
|
|
3
|
+
export function parseLayoutDeclarationAt(lines, index) {
|
|
4
|
+
const line = lines[index];
|
|
5
|
+
if (line === undefined)
|
|
6
|
+
return undefined;
|
|
7
|
+
const text = stripLineComment(line.text).trim();
|
|
8
|
+
const typeAlias = parseTypeAlias(line, text);
|
|
9
|
+
if (typeAlias !== undefined) {
|
|
10
|
+
return { consumedUntilIndex: index, ...typeAlias };
|
|
11
|
+
}
|
|
12
|
+
const prefixLayoutHeader = /^\.(type|union)\s+([A-Za-z_][A-Za-z0-9_]*)\s*$/.exec(text);
|
|
13
|
+
if (prefixLayoutHeader) {
|
|
14
|
+
const directive = prefixLayoutHeader[1] ?? 'type';
|
|
15
|
+
return {
|
|
16
|
+
consumedUntilIndex: skipToLayoutEnd(lines, index, directive),
|
|
17
|
+
diagnostics: [
|
|
18
|
+
parseDiagnostic(line, `Use "${prefixLayoutHeader[2] ?? ''} .${directive}" for layouts.`),
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const layoutHeader = parseNameLeftLayoutHeader(text);
|
|
23
|
+
if (layoutHeader === undefined) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return parseLayoutBlock(lines, index, layoutHeader);
|
|
27
|
+
}
|
|
28
|
+
function parseTypeAlias(line, text) {
|
|
29
|
+
const nameLeftTypeAlias = /^([A-Za-z_][A-Za-z0-9_]*)(?::\s*|\s+)\.typealias\s+(.+)$/.exec(text);
|
|
30
|
+
if (nameLeftTypeAlias) {
|
|
31
|
+
const typeExprText = nameLeftTypeAlias[2] ?? '';
|
|
32
|
+
const typeExpr = parseTypeExpr(typeExprText);
|
|
33
|
+
if (!typeExpr) {
|
|
34
|
+
return { diagnostics: [parseDiagnostic(line, `invalid .typealias target: ${typeExprText}`)] };
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
item: {
|
|
38
|
+
kind: 'type-alias',
|
|
39
|
+
name: nameLeftTypeAlias[1] ?? '',
|
|
40
|
+
typeExpr,
|
|
41
|
+
span: { sourceName: line.sourceName, line: line.line, column: firstColumn(line.text) },
|
|
42
|
+
},
|
|
43
|
+
diagnostics: [],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const oldTypeAlias = /^\.type\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+)$/.exec(text);
|
|
47
|
+
if (oldTypeAlias) {
|
|
48
|
+
return {
|
|
49
|
+
diagnostics: [
|
|
50
|
+
parseDiagnostic(line, `Use "${oldTypeAlias[1] ?? ''} .typealias ..." for type aliases.`),
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
function parseNameLeftLayoutHeader(text) {
|
|
57
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)(?::\s*|\s+)\.(type|union)\s*$/.exec(text);
|
|
58
|
+
return match
|
|
59
|
+
? {
|
|
60
|
+
directive: match[2] ?? '',
|
|
61
|
+
name: match[1] ?? '',
|
|
62
|
+
}
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
65
|
+
function parseLayoutBlock(lines, index, header) {
|
|
66
|
+
const line = lines[index];
|
|
67
|
+
const layoutKind = header.directive === 'union' ? 'union' : 'record';
|
|
68
|
+
const endDirective = layoutKind === 'union' ? '.endunion' : '.endtype';
|
|
69
|
+
const fields = [];
|
|
70
|
+
const diagnostics = [];
|
|
71
|
+
let consumedUntilIndex = index;
|
|
72
|
+
let terminated = false;
|
|
73
|
+
for (let fieldIndex = index + 1; fieldIndex < lines.length; fieldIndex += 1) {
|
|
74
|
+
consumedUntilIndex = fieldIndex;
|
|
75
|
+
const fieldLine = lines[fieldIndex];
|
|
76
|
+
const fieldText = stripLineComment(fieldLine.text).trim();
|
|
77
|
+
if (fieldText.length === 0) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (fieldText === endDirective) {
|
|
81
|
+
terminated = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
const field = parseLayoutField(fieldText);
|
|
85
|
+
if (!field) {
|
|
86
|
+
diagnostics.push(parseDiagnostic(fieldLine, `invalid .${header.directive} field declaration`));
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
fields.push(field);
|
|
90
|
+
}
|
|
91
|
+
if (!terminated) {
|
|
92
|
+
diagnostics.push(parseDiagnostic(line, `.${header.directive} ${header.name} missing ${endDirective}`));
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
consumedUntilIndex,
|
|
96
|
+
diagnostics,
|
|
97
|
+
item: {
|
|
98
|
+
kind: 'type',
|
|
99
|
+
name: header.name,
|
|
100
|
+
layoutKind,
|
|
101
|
+
fields,
|
|
102
|
+
span: { sourceName: line.sourceName, line: line.line, column: firstColumn(line.text) },
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function skipToLayoutEnd(lines, index, directive) {
|
|
107
|
+
const endDirective = directive === 'union' ? '.endunion' : '.endtype';
|
|
108
|
+
for (let next = index + 1; next < lines.length; next += 1) {
|
|
109
|
+
if (stripLineComment(lines[next].text).trim() === endDirective) {
|
|
110
|
+
return next;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return index;
|
|
114
|
+
}
|
|
115
|
+
function parseLayoutField(text) {
|
|
116
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)\s+(\.(?:field|byte|word|addr))(?:\s+(.+))?$/.exec(text);
|
|
117
|
+
if (!match) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
const name = match[1] ?? '';
|
|
121
|
+
const directive = (match[2] ?? '').toLowerCase();
|
|
122
|
+
const operand = match[3]?.trim();
|
|
123
|
+
return directive === '.field'
|
|
124
|
+
? parseNamedField(name, operand)
|
|
125
|
+
: parseScalarDirectiveField(name, directive, operand);
|
|
126
|
+
}
|
|
127
|
+
function parseNamedField(name, operand) {
|
|
128
|
+
return operand === undefined ? undefined : parseFieldOperand(name, operand);
|
|
129
|
+
}
|
|
130
|
+
function parseScalarDirectiveField(name, directive, operand) {
|
|
131
|
+
if (operand !== undefined) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
const size = scalarDirectiveSize(directive);
|
|
135
|
+
return size === undefined ? undefined : { name, size };
|
|
136
|
+
}
|
|
137
|
+
function scalarDirectiveSize(directive) {
|
|
138
|
+
if (directive === '.byte')
|
|
139
|
+
return 1;
|
|
140
|
+
if (directive === '.word' || directive === '.addr')
|
|
141
|
+
return 2;
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
function parseFieldOperand(name, operand) {
|
|
145
|
+
const size = /^[0-9]+$/.test(operand) ? Number.parseInt(operand, 10) : undefined;
|
|
146
|
+
if (size !== undefined) {
|
|
147
|
+
return size > 0 ? { name, size } : undefined;
|
|
148
|
+
}
|
|
149
|
+
const scalar = scalarFieldSize(operand);
|
|
150
|
+
if (scalar !== undefined) {
|
|
151
|
+
return { name, size: scalar };
|
|
152
|
+
}
|
|
153
|
+
const typeExpr = parseTypeExpr(operand);
|
|
154
|
+
return typeExpr ? { name, size: 0, typeExpr } : undefined;
|
|
155
|
+
}
|
|
156
|
+
function scalarFieldSize(typeName) {
|
|
157
|
+
switch (typeName.toLowerCase()) {
|
|
158
|
+
case 'byte':
|
|
159
|
+
return 1;
|
|
160
|
+
case 'word':
|
|
161
|
+
case 'addr':
|
|
162
|
+
return 2;
|
|
163
|
+
default:
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function parseDiagnostic(line, message) {
|
|
168
|
+
return {
|
|
169
|
+
severity: 'error',
|
|
170
|
+
code: 'AZMN_PARSE',
|
|
171
|
+
message,
|
|
172
|
+
sourceName: line.sourceName,
|
|
173
|
+
line: line.line,
|
|
174
|
+
column: firstColumn(line.text),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function firstColumn(text) {
|
|
178
|
+
const match = /\S/.exec(text);
|
|
179
|
+
return match ? match.index + 1 : 1;
|
|
180
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Expression, TypeExpr } from '../model/expression.js';
|
|
2
|
+
export type ParseNestedExpression = (text: string) => Expression | undefined;
|
|
3
|
+
export declare function parseTypeExpr(text: string): TypeExpr | undefined;
|
|
4
|
+
export declare function parseLayoutExpression(text: string, parseNestedExpression: ParseNestedExpression): Expression | undefined;
|
|
5
|
+
export declare function findMatchingBracket(text: string): number | undefined;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
export function parseTypeExpr(text) {
|
|
2
|
+
const trimmed = text.trim();
|
|
3
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)(?:\[\s*([0-9]+)\s*\])?$/.exec(trimmed);
|
|
4
|
+
if (!match) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
const name = match[1] ?? '';
|
|
8
|
+
const lengthText = match[2];
|
|
9
|
+
if (lengthText === undefined) {
|
|
10
|
+
return { name };
|
|
11
|
+
}
|
|
12
|
+
const length = Number.parseInt(lengthText, 10);
|
|
13
|
+
return length >= 0 ? { name, length } : undefined;
|
|
14
|
+
}
|
|
15
|
+
export function parseLayoutExpression(text, parseNestedExpression) {
|
|
16
|
+
const trimmed = text.trim();
|
|
17
|
+
const layoutCast = parseLayoutCast(trimmed, parseNestedExpression);
|
|
18
|
+
if (layoutCast) {
|
|
19
|
+
return layoutCast;
|
|
20
|
+
}
|
|
21
|
+
const sizeof = /^sizeof\s*\((.*)\)$/.exec(trimmed);
|
|
22
|
+
if (sizeof) {
|
|
23
|
+
const typeExpr = parseTypeExpr(sizeof[1] ?? '');
|
|
24
|
+
return typeExpr ? { kind: 'sizeof', typeExpr } : undefined;
|
|
25
|
+
}
|
|
26
|
+
const offset = /^offset\s*\((.*),(.*)\)$/.exec(trimmed);
|
|
27
|
+
if (offset) {
|
|
28
|
+
const typeExpr = parseTypeExpr(offset[1] ?? '');
|
|
29
|
+
const path = parseOffsetPath(offset[2] ?? '');
|
|
30
|
+
return typeExpr && path ? { kind: 'offset', typeExpr, path } : undefined;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
export function findMatchingBracket(text) {
|
|
35
|
+
let state = { depth: 0, quote: undefined, escaped: false };
|
|
36
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
37
|
+
const char = text[index] ?? '';
|
|
38
|
+
if (state.quote !== undefined) {
|
|
39
|
+
state = scanQuotedBracketChar(char, state);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const quotedState = startBracketQuote(char, state);
|
|
43
|
+
if (quotedState) {
|
|
44
|
+
state = quotedState;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
state = scanBracketDepth(char, state);
|
|
48
|
+
if (char === ']') {
|
|
49
|
+
if (state.depth === 0) {
|
|
50
|
+
return index;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
function scanQuotedBracketChar(char, state) {
|
|
57
|
+
if (state.escaped)
|
|
58
|
+
return { ...state, escaped: false };
|
|
59
|
+
if (char === '\\')
|
|
60
|
+
return { ...state, escaped: true };
|
|
61
|
+
if (char === state.quote)
|
|
62
|
+
return { ...state, quote: undefined };
|
|
63
|
+
return state;
|
|
64
|
+
}
|
|
65
|
+
function startBracketQuote(char, state) {
|
|
66
|
+
return char === '"' || char === "'" ? { ...state, quote: char } : undefined;
|
|
67
|
+
}
|
|
68
|
+
function scanBracketDepth(char, state) {
|
|
69
|
+
if (char === '[')
|
|
70
|
+
return { ...state, depth: state.depth + 1 };
|
|
71
|
+
if (char === ']')
|
|
72
|
+
return { ...state, depth: state.depth - 1 };
|
|
73
|
+
return state;
|
|
74
|
+
}
|
|
75
|
+
function parseLayoutCast(text, parseNestedExpression) {
|
|
76
|
+
if (!text.startsWith('<')) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const close = text.indexOf('>');
|
|
80
|
+
if (close <= 1) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const typeExpr = parseTypeExpr(text.slice(1, close));
|
|
84
|
+
if (!typeExpr) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
const rest = text.slice(close + 1);
|
|
88
|
+
const base = /^(?:[A-Za-z_$][A-Za-z0-9_$?]*|\?[A-Za-z0-9_$?]+)/.exec(rest);
|
|
89
|
+
if (!base) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
const path = parseLayoutCastPath(rest.slice(base[0].length), parseNestedExpression);
|
|
93
|
+
if (!path) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
kind: 'layout-cast',
|
|
98
|
+
typeExpr,
|
|
99
|
+
base: { kind: 'symbol', name: base[0] },
|
|
100
|
+
path,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function parseLayoutCastPath(text, parseNestedExpression) {
|
|
104
|
+
const parts = [];
|
|
105
|
+
let rest = text.trim();
|
|
106
|
+
while (rest.length > 0) {
|
|
107
|
+
const parsed = parseLayoutCastPathPart(rest, parseNestedExpression);
|
|
108
|
+
if (!parsed)
|
|
109
|
+
return undefined;
|
|
110
|
+
parts.push(parsed.part);
|
|
111
|
+
rest = parsed.rest.trim();
|
|
112
|
+
}
|
|
113
|
+
return parts.length > 0 ? parts : undefined;
|
|
114
|
+
}
|
|
115
|
+
function parseLayoutCastPathPart(text, parseNestedExpression) {
|
|
116
|
+
return text.startsWith('.')
|
|
117
|
+
? parseLayoutCastField(text)
|
|
118
|
+
: parseLayoutCastIndex(text, parseNestedExpression);
|
|
119
|
+
}
|
|
120
|
+
function parseLayoutCastField(text) {
|
|
121
|
+
const field = /^\.([A-Za-z_][A-Za-z0-9_]*)/.exec(text);
|
|
122
|
+
return field ? { part: { kind: 'field', name: field[1] ?? '' }, rest: text.slice(field[0].length) } : undefined;
|
|
123
|
+
}
|
|
124
|
+
function parseLayoutCastIndex(text, parseNestedExpression) {
|
|
125
|
+
if (!text.startsWith('['))
|
|
126
|
+
return undefined;
|
|
127
|
+
const close = findMatchingBracket(text);
|
|
128
|
+
if (close === undefined)
|
|
129
|
+
return undefined;
|
|
130
|
+
const expression = parseNestedExpression(text.slice(1, close));
|
|
131
|
+
return expression
|
|
132
|
+
? { part: { kind: 'index', expression }, rest: text.slice(close + 1) }
|
|
133
|
+
: undefined;
|
|
134
|
+
}
|
|
135
|
+
function parseOffsetPath(text) {
|
|
136
|
+
const trimmed = text.trim();
|
|
137
|
+
if (trimmed.length === 0) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
const parts = [];
|
|
141
|
+
let rest = trimmed;
|
|
142
|
+
while (rest.length > 0) {
|
|
143
|
+
const parsed = parseOffsetPathPart(rest);
|
|
144
|
+
if (!parsed)
|
|
145
|
+
return undefined;
|
|
146
|
+
parts.push(parsed.part);
|
|
147
|
+
rest = parsed.rest;
|
|
148
|
+
if (rest.length === 0) {
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
if (!rest.startsWith('.')) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
rest = rest.slice(1);
|
|
155
|
+
}
|
|
156
|
+
return parts.length > 0 ? parts : undefined;
|
|
157
|
+
}
|
|
158
|
+
function parseOffsetPathPart(text) {
|
|
159
|
+
return text.startsWith('[') ? parseOffsetIndex(text) : parseOffsetField(text);
|
|
160
|
+
}
|
|
161
|
+
function parseOffsetIndex(text) {
|
|
162
|
+
const index = /^\[\s*([0-9]+)\s*\]/.exec(text);
|
|
163
|
+
return index
|
|
164
|
+
? {
|
|
165
|
+
part: { kind: 'index', index: Number.parseInt(index[1] ?? '', 10) },
|
|
166
|
+
rest: text.slice(index[0].length),
|
|
167
|
+
}
|
|
168
|
+
: undefined;
|
|
169
|
+
}
|
|
170
|
+
function parseOffsetField(text) {
|
|
171
|
+
const field = /^[A-Za-z_][A-Za-z0-9_]*/.exec(text);
|
|
172
|
+
return field
|
|
173
|
+
? { part: { kind: 'field', name: field[0] }, rest: text.slice(field[0].length) }
|
|
174
|
+
: undefined;
|
|
175
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { extractLineComment, stripLineComment } from '../source/strip-line-comment.js';
|
|
2
2
|
import { normalizeDirectiveAlias } from './directive-aliases.js';
|
|
3
|
-
import {
|
|
3
|
+
import { parseColonDeclaration, parseDirectiveStatement } from './parse-directive-statement.js';
|
|
4
4
|
import { parseZ80Instruction } from '../z80/parse-instruction.js';
|
|
5
5
|
export function parseLogicalLine(line, options = {}) {
|
|
6
6
|
const text = normalizeDirectiveAlias(stripLineComment(line.text), options.directiveAliasPolicy).trim();
|
|
@@ -84,149 +84,10 @@ function withLineComment(line, result) {
|
|
|
84
84
|
diagnostics: result.diagnostics,
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
|
-
function parseEquItem(line, name, expressionText, span) {
|
|
88
|
-
const stringValue = parseWholeQuotedString(expressionText.trim());
|
|
89
|
-
const expression = stringValue !== undefined && stringValue.length > 1
|
|
90
|
-
? { kind: 'number', value: 0 }
|
|
91
|
-
: parseExpression(expressionText);
|
|
92
|
-
if (!expression) {
|
|
93
|
-
return {
|
|
94
|
-
items: [],
|
|
95
|
-
diagnostics: [parseError(line, `invalid .equ expression: ${expressionText}`)],
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
items: [
|
|
100
|
-
{
|
|
101
|
-
kind: 'equ',
|
|
102
|
-
name,
|
|
103
|
-
expression,
|
|
104
|
-
...(stringValue !== undefined && stringValue.length > 1 ? { stringValue } : {}),
|
|
105
|
-
span,
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
diagnostics: [],
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
87
|
function parseCanonicalStatement(line, text, span) {
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
const org = /^\.org\s+(.+)$/.exec(text);
|
|
117
|
-
if (org) {
|
|
118
|
-
const expressionText = org[1] ?? '';
|
|
119
|
-
const expression = parseExpression(expressionText);
|
|
120
|
-
if (!expression) {
|
|
121
|
-
return {
|
|
122
|
-
items: [],
|
|
123
|
-
diagnostics: [parseError(line, `invalid .org expression: ${expressionText}`)],
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
return { items: [{ kind: 'org', expression, span }], diagnostics: [] };
|
|
127
|
-
}
|
|
128
|
-
const enumDecl = /^enum\s+([A-Za-z_][A-Za-z0-9_]*)\s+(.+)$/.exec(text);
|
|
129
|
-
if (enumDecl) {
|
|
130
|
-
return {
|
|
131
|
-
items: [],
|
|
132
|
-
diagnostics: [parseError(line, `Use "${enumDecl[1] ?? ''} .enum ..." for enums.`)],
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
const nameLeftEnum = /^([A-Za-z_][A-Za-z0-9_]*)\s+\.enum\s+(.+)$/.exec(text);
|
|
136
|
-
if (nameLeftEnum) {
|
|
137
|
-
return parseEnumItem(line, nameLeftEnum[1] ?? '', nameLeftEnum[2] ?? '', span);
|
|
138
|
-
}
|
|
139
|
-
const data = /^(\.db|\.dw)\s+(.+)$/.exec(text);
|
|
140
|
-
if (data) {
|
|
141
|
-
const directive = (data[1] ?? '').slice(1).toLowerCase();
|
|
142
|
-
const valueText = data[2] ?? '';
|
|
143
|
-
const parts = splitValueList(valueText);
|
|
144
|
-
const values = directive === 'db'
|
|
145
|
-
? parts.map(parseDataValue).filter((value) => value !== undefined)
|
|
146
|
-
: parts.map(parseExpression).filter((value) => value !== undefined);
|
|
147
|
-
if (values.length !== parts.length) {
|
|
148
|
-
return {
|
|
149
|
-
items: [],
|
|
150
|
-
diagnostics: [parseError(line, `invalid .${directive} value list`)],
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
return {
|
|
154
|
-
items: directive === 'db'
|
|
155
|
-
? [{ kind: 'db', values: values, span }]
|
|
156
|
-
: [{ kind: 'dw', values: values, span }],
|
|
157
|
-
diagnostics: [],
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
const ds = /^\.ds\s+(.+)$/.exec(text);
|
|
161
|
-
if (ds) {
|
|
162
|
-
const parts = splitValueList(ds[1] ?? '');
|
|
163
|
-
if (parts.length < 1 || parts.length > 2) {
|
|
164
|
-
return {
|
|
165
|
-
items: [],
|
|
166
|
-
diagnostics: [parseError(line, `invalid .ds value list`)],
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
const sizeText = parts[0] ?? '';
|
|
170
|
-
const size = parseTypeSizeExpression(sizeText) ?? parseExpression(sizeText);
|
|
171
|
-
if (!size) {
|
|
172
|
-
return {
|
|
173
|
-
items: [],
|
|
174
|
-
diagnostics: [parseError(line, `invalid .ds size: ${sizeText}`)],
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
const fillText = parts[1];
|
|
178
|
-
const fill = fillText === undefined ? undefined : parseExpression(fillText);
|
|
179
|
-
if (fillText !== undefined && !fill) {
|
|
180
|
-
return {
|
|
181
|
-
items: [],
|
|
182
|
-
diagnostics: [parseError(line, `invalid .ds fill: ${fillText}`)],
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
return {
|
|
186
|
-
items: [fill === undefined ? { kind: 'ds', size, span } : { kind: 'ds', size, fill, span }],
|
|
187
|
-
diagnostics: [],
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
const align = /^\.align\s+(.+)$/.exec(text);
|
|
191
|
-
if (align) {
|
|
192
|
-
const expressionText = align[1] ?? '';
|
|
193
|
-
const alignment = parseExpression(expressionText);
|
|
194
|
-
if (!alignment) {
|
|
195
|
-
return {
|
|
196
|
-
items: [],
|
|
197
|
-
diagnostics: [parseError(line, `invalid .align expression: ${expressionText}`)],
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
return { items: [{ kind: 'align', alignment, span }], diagnostics: [] };
|
|
201
|
-
}
|
|
202
|
-
if (/^\.end\s*$/.test(text)) {
|
|
203
|
-
return { items: [{ kind: 'end', span }], diagnostics: [] };
|
|
204
|
-
}
|
|
205
|
-
const rangeControl = /^(\.binfrom|\.binto)\s+(.+)$/.exec(text);
|
|
206
|
-
if (rangeControl) {
|
|
207
|
-
const kind = (rangeControl[1] ?? '').slice(1).toLowerCase();
|
|
208
|
-
const expressionText = rangeControl[2] ?? '';
|
|
209
|
-
const expression = parseExpression(expressionText);
|
|
210
|
-
if (!expression) {
|
|
211
|
-
return {
|
|
212
|
-
items: [],
|
|
213
|
-
diagnostics: [parseError(line, `invalid .${kind} expression: ${expressionText}`)],
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
return { items: [{ kind, expression, span }], diagnostics: [] };
|
|
217
|
-
}
|
|
218
|
-
const stringData = /^(\.cstr|\.pstr|\.istr)\s+(.+)$/.exec(text);
|
|
219
|
-
if (stringData) {
|
|
220
|
-
const directive = (stringData[1] ?? '').slice(1).toLowerCase();
|
|
221
|
-
const valueText = stringData[2] ?? '';
|
|
222
|
-
const value = parseQuotedString(valueText);
|
|
223
|
-
if (value === undefined) {
|
|
224
|
-
return {
|
|
225
|
-
items: [],
|
|
226
|
-
diagnostics: [parseError(line, `.${directive} expects one double-quoted string`)],
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
return { items: [{ kind: 'string-data', directive, value, span }], diagnostics: [] };
|
|
88
|
+
const directive = parseDirectiveStatement(line, text, span);
|
|
89
|
+
if (directive) {
|
|
90
|
+
return directive;
|
|
230
91
|
}
|
|
231
92
|
const instruction = parseZ80Instruction(text);
|
|
232
93
|
if (instruction?.instruction) {
|
|
@@ -246,135 +107,6 @@ function parseCanonicalStatement(line, text, span) {
|
|
|
246
107
|
}
|
|
247
108
|
return { items: [], diagnostics: [parseError(line, `unsupported source line: ${text}`)] };
|
|
248
109
|
}
|
|
249
|
-
function parseColonDeclaration(line, name, statementText, span) {
|
|
250
|
-
const equ = /^\.equ\s+(.+)$/.exec(statementText);
|
|
251
|
-
if (equ) {
|
|
252
|
-
return parseEquItem(line, name, equ[1] ?? '', span);
|
|
253
|
-
}
|
|
254
|
-
const enumDecl = /^\.enum\s+(.+)$/.exec(statementText);
|
|
255
|
-
if (enumDecl) {
|
|
256
|
-
return parseEnumItem(line, name, enumDecl[1] ?? '', span);
|
|
257
|
-
}
|
|
258
|
-
return undefined;
|
|
259
|
-
}
|
|
260
|
-
function parseEnumItem(line, name, membersText, span) {
|
|
261
|
-
const rawMembers = membersText.split(',').map((member) => member.trim());
|
|
262
|
-
if (membersText.trim().length === 0 || rawMembers.some((member) => member.length === 0)) {
|
|
263
|
-
return {
|
|
264
|
-
items: [],
|
|
265
|
-
diagnostics: [parseError(line, `invalid enum member list`)],
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
const members = [];
|
|
269
|
-
const diagnostics = [];
|
|
270
|
-
for (const member of rawMembers) {
|
|
271
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(member)) {
|
|
272
|
-
diagnostics.push(parseError(line, `Invalid enum member name "${member}": expected <identifier>.`));
|
|
273
|
-
continue;
|
|
274
|
-
}
|
|
275
|
-
members.push(member);
|
|
276
|
-
}
|
|
277
|
-
if (diagnostics.length > 0) {
|
|
278
|
-
return { items: [], diagnostics };
|
|
279
|
-
}
|
|
280
|
-
return { items: [{ kind: 'enum', name, members, span }], diagnostics: [] };
|
|
281
|
-
}
|
|
282
|
-
function parseTypeSizeExpression(text) {
|
|
283
|
-
const typeExpr = parseTypeExpr(text);
|
|
284
|
-
return typeExpr ? { kind: 'type-size', typeExpr } : undefined;
|
|
285
|
-
}
|
|
286
|
-
function splitValueList(text) {
|
|
287
|
-
const values = [];
|
|
288
|
-
let quote;
|
|
289
|
-
let escaped = false;
|
|
290
|
-
let parenDepth = 0;
|
|
291
|
-
let start = 0;
|
|
292
|
-
for (let index = 0; index < text.length; index += 1) {
|
|
293
|
-
const char = text[index];
|
|
294
|
-
if (escaped) {
|
|
295
|
-
escaped = false;
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
if (char === '\\' && quote) {
|
|
299
|
-
escaped = true;
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
if (char === '"' || char === "'") {
|
|
303
|
-
quote = quote === char ? undefined : (quote ?? char);
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
306
|
-
if (!quote && char === '(') {
|
|
307
|
-
parenDepth += 1;
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
if (!quote && char === ')') {
|
|
311
|
-
parenDepth = Math.max(0, parenDepth - 1);
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
if (char === ',' && !quote && parenDepth === 0) {
|
|
315
|
-
values.push(text.slice(start, index));
|
|
316
|
-
start = index + 1;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
values.push(text.slice(start));
|
|
320
|
-
return values;
|
|
321
|
-
}
|
|
322
|
-
function parseQuotedString(text) {
|
|
323
|
-
const input = text.trim();
|
|
324
|
-
const quote = input[0];
|
|
325
|
-
if (quote !== '"' || input[input.length - 1] !== quote) {
|
|
326
|
-
return undefined;
|
|
327
|
-
}
|
|
328
|
-
let value = '';
|
|
329
|
-
for (let index = 1; index < input.length - 1; index += 1) {
|
|
330
|
-
const char = input[index] ?? '';
|
|
331
|
-
if (char === '\\') {
|
|
332
|
-
if (index + 1 >= input.length - 1) {
|
|
333
|
-
return undefined;
|
|
334
|
-
}
|
|
335
|
-
value += input[index + 1] ?? '';
|
|
336
|
-
index += 1;
|
|
337
|
-
continue;
|
|
338
|
-
}
|
|
339
|
-
if (char === quote) {
|
|
340
|
-
return undefined;
|
|
341
|
-
}
|
|
342
|
-
value += char;
|
|
343
|
-
}
|
|
344
|
-
return value;
|
|
345
|
-
}
|
|
346
|
-
function parseDataValue(text) {
|
|
347
|
-
const expression = parseExpression(text);
|
|
348
|
-
if (expression) {
|
|
349
|
-
return expression;
|
|
350
|
-
}
|
|
351
|
-
const value = parseWholeQuotedString(text);
|
|
352
|
-
return value === undefined ? undefined : { kind: 'string-fragment', value };
|
|
353
|
-
}
|
|
354
|
-
function parseWholeQuotedString(text) {
|
|
355
|
-
const input = text.trim();
|
|
356
|
-
const quote = input[0];
|
|
357
|
-
if ((quote !== '"' && quote !== "'") || input[input.length - 1] !== quote) {
|
|
358
|
-
return undefined;
|
|
359
|
-
}
|
|
360
|
-
let value = '';
|
|
361
|
-
for (let index = 1; index < input.length - 1; index += 1) {
|
|
362
|
-
const char = input[index] ?? '';
|
|
363
|
-
if (char === '\\') {
|
|
364
|
-
if (index + 1 >= input.length - 1) {
|
|
365
|
-
return undefined;
|
|
366
|
-
}
|
|
367
|
-
value += input[index + 1] ?? '';
|
|
368
|
-
index += 1;
|
|
369
|
-
continue;
|
|
370
|
-
}
|
|
371
|
-
if (char === quote) {
|
|
372
|
-
return undefined;
|
|
373
|
-
}
|
|
374
|
-
value += char;
|
|
375
|
-
}
|
|
376
|
-
return value;
|
|
377
|
-
}
|
|
378
110
|
function normalizeEntryLabelName(raw) {
|
|
379
111
|
return raw.startsWith('@') ? raw.slice(1) : raw;
|
|
380
112
|
}
|