@jhlagado/azm 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +239 -76
- package/dist/src/api-artifacts.d.ts +20 -0
- package/dist/src/api-artifacts.js +165 -0
- package/dist/src/api-compile.d.ts +8 -2
- package/dist/src/api-compile.js +55 -227
- package/dist/src/api-register-contracts.d.ts +9 -0
- package/dist/src/api-register-contracts.js +77 -0
- package/dist/src/api-tooling.d.ts +2 -2
- package/dist/src/api-tooling.js +1 -1
- package/dist/src/assembly/address-planning.d.ts +1 -2
- package/dist/src/assembly/address-planning.js +119 -218
- package/dist/src/assembly/address-symbols.d.ts +12 -0
- package/dist/src/assembly/address-symbols.js +118 -0
- package/dist/src/assembly/assemble-program.js +5 -0
- package/dist/src/assembly/fixup-emission.js +30 -48
- package/dist/src/assembly/import-visibility.d.ts +3 -0
- package/dist/src/assembly/import-visibility.js +204 -0
- package/dist/src/assembly/program-emission.js +163 -164
- package/dist/src/cli/artifact-files.d.ts +15 -0
- package/dist/src/cli/artifact-files.js +86 -0
- package/dist/src/cli/parse-args.d.ts +6 -5
- package/dist/src/cli/parse-args.js +162 -136
- package/dist/src/cli/run.js +4 -1
- package/dist/src/cli/usage.d.ts +1 -0
- package/dist/src/cli/usage.js +33 -0
- package/dist/src/cli/write-artifacts.js +18 -91
- package/dist/src/core/compile.js +51 -274
- package/dist/src/core/conditional-assembly.d.ts +6 -0
- package/dist/src/core/conditional-assembly.js +181 -0
- package/dist/src/expansion/op-constant-expression.d.ts +3 -0
- package/dist/src/expansion/op-constant-expression.js +52 -0
- package/dist/src/expansion/op-expand-selected.d.ts +5 -0
- package/dist/src/expansion/op-expand-selected.js +143 -0
- package/dist/src/expansion/op-expansion.d.ts +5 -53
- package/dist/src/expansion/op-expansion.js +85 -815
- package/dist/src/expansion/op-instruction-instantiation.d.ts +3 -0
- package/dist/src/expansion/op-instruction-instantiation.js +194 -0
- package/dist/src/expansion/op-local-labels.d.ts +8 -0
- package/dist/src/expansion/op-local-labels.js +166 -0
- package/dist/src/expansion/op-operand-splitting.d.ts +1 -0
- package/dist/src/expansion/op-operand-splitting.js +44 -0
- package/dist/src/expansion/op-operands.d.ts +53 -0
- package/dist/src/expansion/op-operands.js +66 -0
- package/dist/src/expansion/op-selection.d.ts +18 -0
- package/dist/src/expansion/op-selection.js +172 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/model/diagnostic.d.ts +4 -0
- package/dist/src/model/diagnostic.js +4 -0
- package/dist/src/node/source-host.js +40 -13
- package/dist/src/outputs/asm80-expression-evaluation.d.ts +10 -0
- package/dist/src/outputs/asm80-expression-evaluation.js +75 -0
- package/dist/src/outputs/asm80-expressions.d.ts +5 -0
- package/dist/src/outputs/asm80-expressions.js +47 -0
- package/dist/src/outputs/asm80-instruction-operands.d.ts +16 -0
- package/dist/src/outputs/asm80-instruction-operands.js +38 -0
- package/dist/src/outputs/asm80-instructions.d.ts +5 -0
- package/dist/src/outputs/asm80-instructions.js +272 -0
- package/dist/src/outputs/asm80-ld-operands.d.ts +10 -0
- package/dist/src/outputs/asm80-ld-operands.js +157 -0
- package/dist/src/outputs/asm80-strings.d.ts +4 -0
- package/dist/src/outputs/asm80-strings.js +14 -0
- package/dist/src/outputs/d8-files.d.ts +10 -0
- package/dist/src/outputs/d8-files.js +103 -0
- package/dist/src/outputs/d8-helpers.d.ts +21 -0
- package/dist/src/outputs/d8-helpers.js +136 -0
- package/dist/src/outputs/hex.js +26 -18
- package/dist/src/outputs/types.d.ts +16 -10
- package/dist/src/outputs/write-asm80.js +72 -597
- package/dist/src/outputs/write-d8.js +6 -216
- package/dist/src/register-contracts/accept-output.d.ts +2 -0
- package/dist/src/register-contracts/analyze-helpers.d.ts +29 -0
- package/dist/src/register-contracts/analyze-helpers.js +162 -0
- package/dist/src/{register-care → register-contracts}/analyze.d.ts +6 -6
- package/dist/src/register-contracts/analyze.js +73 -0
- package/dist/src/register-contracts/annotate.d.ts +11 -0
- package/dist/src/{register-care → register-contracts}/annotate.js +3 -3
- package/dist/src/register-contracts/annotations.d.ts +8 -0
- package/dist/src/{register-care → register-contracts}/annotations.js +3 -3
- package/dist/src/register-contracts/boundaryHints.d.ts +3 -0
- package/dist/src/register-contracts/boundaryHints.js +24 -0
- package/dist/src/register-contracts/carriers.d.ts +2 -0
- package/dist/src/register-contracts/constants.d.ts +4 -0
- package/dist/src/register-contracts/constants.js +51 -0
- package/dist/src/register-contracts/controlFlow.d.ts +5 -0
- package/dist/src/register-contracts/controlFlow.js +55 -0
- package/dist/src/register-contracts/fix.d.ts +11 -0
- package/dist/src/{register-care → register-contracts}/fix.js +47 -30
- package/dist/src/register-contracts/instruction-head.d.ts +2 -0
- package/dist/src/register-contracts/instruction-head.js +3 -0
- package/dist/src/register-contracts/instruction-operands.d.ts +3 -0
- package/dist/src/register-contracts/instruction-operands.js +101 -0
- package/dist/src/register-contracts/instruction-predicates.d.ts +6 -0
- package/dist/src/register-contracts/instruction-predicates.js +44 -0
- package/dist/src/register-contracts/interfaceContracts.d.ts +2 -0
- package/dist/src/register-contracts/interfaceContracts.js +68 -0
- package/dist/src/register-contracts/liveness.d.ts +3 -0
- package/dist/src/{register-care → register-contracts}/liveness.js +111 -79
- package/dist/src/register-contracts/operand-register-name.d.ts +2 -0
- package/dist/src/register-contracts/operand-register-name.js +13 -0
- package/dist/src/{register-care → register-contracts}/profiles.d.ts +5 -5
- package/dist/src/{register-care → register-contracts}/profiles.js +2 -2
- package/dist/src/register-contracts/programModel-boundaries.d.ts +6 -0
- package/dist/src/register-contracts/programModel-boundaries.js +64 -0
- package/dist/src/register-contracts/programModel-routines.d.ts +7 -0
- package/dist/src/register-contracts/programModel-routines.js +144 -0
- package/dist/src/register-contracts/programModel.d.ts +3 -0
- package/dist/src/register-contracts/programModel.js +14 -0
- package/dist/src/register-contracts/report.d.ts +5 -0
- package/dist/src/{register-care → register-contracts}/report.js +34 -17
- package/dist/src/register-contracts/routine-summaries.d.ts +6 -0
- package/dist/src/{register-care → register-contracts}/routine-summaries.js +11 -1
- package/dist/src/register-contracts/smartCommentBlocks.d.ts +5 -0
- package/dist/src/register-contracts/smartCommentBlocks.js +30 -0
- package/dist/src/register-contracts/smartCommentParsing.d.ts +3 -0
- package/dist/src/register-contracts/smartCommentParsing.js +80 -0
- package/dist/src/register-contracts/smartComments.d.ts +5 -0
- package/dist/src/register-contracts/smartComments.js +92 -0
- package/dist/src/register-contracts/summaries.d.ts +12 -0
- package/dist/src/{register-care → register-contracts}/summaries.js +7 -7
- package/dist/src/register-contracts/summary-boundary.d.ts +2 -0
- package/dist/src/register-contracts/summary-boundary.js +40 -0
- package/dist/src/register-contracts/summary-contract.d.ts +2 -0
- package/dist/src/register-contracts/summary-contract.js +45 -0
- package/dist/src/register-contracts/summary-result.d.ts +7 -0
- package/dist/src/register-contracts/summary-result.js +122 -0
- package/dist/src/register-contracts/summary-state.d.ts +23 -0
- package/dist/src/register-contracts/summary-state.js +88 -0
- package/dist/src/register-contracts/summary-token-transfer.d.ts +3 -0
- package/dist/src/register-contracts/summary-token-transfer.js +67 -0
- package/dist/src/register-contracts/summary.d.ts +3 -0
- package/dist/src/register-contracts/summary.js +266 -0
- package/dist/src/register-contracts/tooling.d.ts +57 -0
- package/dist/src/{register-care → register-contracts}/tooling.js +8 -6
- package/dist/src/register-contracts/types.d.ts +188 -0
- package/dist/src/semantics/binary-operators.d.ts +2 -0
- package/dist/src/semantics/binary-operators.js +15 -0
- package/dist/src/semantics/byte-functions.d.ts +2 -0
- package/dist/src/semantics/byte-functions.js +7 -0
- package/dist/src/semantics/constant-operator-types.d.ts +10 -0
- package/dist/src/semantics/constant-operator-types.js +1 -0
- package/dist/src/semantics/constant-operators.d.ts +3 -0
- package/dist/src/semantics/constant-operators.js +3 -0
- package/dist/src/semantics/diagnostics.d.ts +3 -0
- package/dist/src/semantics/diagnostics.js +10 -0
- package/dist/src/semantics/expression-evaluation.d.ts +11 -19
- package/dist/src/semantics/expression-evaluation.js +22 -334
- package/dist/src/semantics/layout-evaluation.d.ts +23 -0
- package/dist/src/semantics/layout-evaluation.js +202 -0
- package/dist/src/semantics/layout-format.d.ts +5 -0
- package/dist/src/semantics/layout-format.js +31 -0
- package/dist/src/semantics/layout-path.d.ts +24 -0
- package/dist/src/semantics/layout-path.js +58 -0
- package/dist/src/semantics/unary-operators.d.ts +2 -0
- package/dist/src/semantics/unary-operators.js +8 -0
- package/dist/src/source/line-comment-scanner.d.ts +1 -0
- package/dist/src/source/line-comment-scanner.js +51 -0
- package/dist/src/source/logical-lines.d.ts +3 -0
- package/dist/src/source/source-span.d.ts +2 -0
- package/dist/src/source/strip-line-comment.js +8 -44
- package/dist/src/syntax/directive-aliases.js +36 -22
- package/dist/src/syntax/expression-tokenizer.d.ts +30 -0
- package/dist/src/syntax/expression-tokenizer.js +310 -0
- package/dist/src/syntax/parse-directive-statement.d.ts +9 -0
- package/dist/src/syntax/parse-directive-statement.js +309 -0
- package/dist/src/syntax/parse-expression.d.ts +2 -2
- package/dist/src/syntax/parse-expression.js +7 -568
- package/dist/src/syntax/parse-layout-declarations.d.ts +9 -0
- package/dist/src/syntax/parse-layout-declarations.js +189 -0
- package/dist/src/syntax/parse-layout-expression.d.ts +5 -0
- package/dist/src/syntax/parse-layout-expression.js +175 -0
- package/dist/src/syntax/parse-line.js +21 -273
- package/dist/src/syntax/parse-token-expression.d.ts +3 -0
- package/dist/src/syntax/parse-token-expression.js +133 -0
- package/dist/src/tooling/api.js +1 -1
- package/dist/src/tooling/case-style.js +47 -30
- package/dist/src/z80/effect-groups.d.ts +38 -0
- package/dist/src/z80/effect-groups.js +265 -0
- package/dist/src/z80/effect-units.d.ts +18 -0
- package/dist/src/z80/effect-units.js +165 -0
- package/dist/src/z80/effects.d.ts +1 -1
- package/dist/src/z80/effects.js +94 -557
- package/dist/src/z80/encode-core.d.ts +2 -0
- package/dist/src/z80/encode-core.js +42 -0
- package/dist/src/z80/encode-ld-helpers.d.ts +25 -0
- package/dist/src/z80/encode-ld-helpers.js +172 -0
- package/dist/src/z80/encode-ld.d.ts +2 -0
- package/dist/src/z80/encode-ld.js +285 -0
- package/dist/src/z80/encode.js +190 -542
- package/dist/src/z80/ld-support.d.ts +3 -0
- package/dist/src/z80/ld-support.js +146 -0
- package/dist/src/z80/operand-split-state.d.ts +8 -0
- package/dist/src/z80/operand-split-state.js +46 -0
- package/dist/src/z80/operand-split.d.ts +1 -0
- package/dist/src/z80/operand-split.js +13 -0
- package/dist/src/z80/parse-basic.d.ts +4 -0
- package/dist/src/z80/parse-basic.js +39 -0
- package/dist/src/z80/parse-branch.d.ts +4 -0
- package/dist/src/z80/parse-branch.js +218 -0
- package/dist/src/z80/parse-conditions.d.ts +6 -0
- package/dist/src/z80/parse-conditions.js +10 -0
- package/dist/src/z80/parse-exchange.d.ts +2 -0
- package/dist/src/z80/parse-exchange.js +30 -0
- package/dist/src/z80/parse-instruction.js +224 -1010
- package/dist/src/z80/parse-io-control.d.ts +5 -0
- package/dist/src/z80/parse-io-control.js +108 -0
- package/dist/src/z80/parse-ld.d.ts +2 -0
- package/dist/src/z80/parse-ld.js +83 -0
- package/dist/src/z80/parse-operands.d.ts +41 -0
- package/dist/src/z80/parse-operands.js +259 -0
- package/docs/codebase/01-orientation-and-repository-layout.md +192 -0
- package/docs/codebase/02-source-loading-and-parsing.md +263 -0
- package/docs/codebase/03-assembly-and-z80-emission.md +251 -0
- package/docs/codebase/04-ops-and-register-contracts.md +237 -0
- package/docs/codebase/05-interfaces-and-output-artifacts.md +253 -0
- package/docs/codebase/06-verification-and-maintenance.md +202 -0
- package/docs/codebase/appendices/a-directory-file-reference.md +253 -0
- package/docs/codebase/appendices/b-compile-flow-reference.md +103 -0
- package/docs/codebase/appendices/c-public-surface-reference.md +106 -0
- package/docs/codebase/appendices/index.md +16 -0
- package/docs/codebase/index.md +46 -0
- package/package.json +2 -3
- package/dist/src/register-care/accept-output.d.ts +0 -2
- package/dist/src/register-care/analyze.js +0 -166
- package/dist/src/register-care/annotate.d.ts +0 -11
- package/dist/src/register-care/annotations.d.ts +0 -8
- package/dist/src/register-care/boundaryHints.d.ts +0 -3
- package/dist/src/register-care/boundaryHints.js +0 -80
- package/dist/src/register-care/carriers.d.ts +0 -2
- package/dist/src/register-care/controlFlow.d.ts +0 -5
- package/dist/src/register-care/controlFlow.js +0 -38
- package/dist/src/register-care/fix.d.ts +0 -11
- package/dist/src/register-care/instruction-shape.d.ts +0 -11
- package/dist/src/register-care/instruction-shape.js +0 -129
- package/dist/src/register-care/liveness.d.ts +0 -3
- package/dist/src/register-care/programModel.d.ts +0 -3
- package/dist/src/register-care/programModel.js +0 -266
- package/dist/src/register-care/report.d.ts +0 -5
- package/dist/src/register-care/routine-summaries.d.ts +0 -6
- package/dist/src/register-care/smartComments.d.ts +0 -5
- package/dist/src/register-care/smartComments.js +0 -243
- package/dist/src/register-care/summaries.d.ts +0 -12
- package/dist/src/register-care/summary.d.ts +0 -3
- package/dist/src/register-care/summary.js +0 -474
- package/dist/src/register-care/tooling.d.ts +0 -43
- package/dist/src/register-care/types.d.ts +0 -172
- package/docs/reference/cli.md +0 -151
- package/docs/reference/tooling-api.md +0 -316
- /package/dist/src/{register-care → register-contracts}/accept-output.js +0 -0
- /package/dist/src/{register-care → register-contracts}/carriers.js +0 -0
- /package/dist/src/{register-care → register-contracts}/sourceText.d.ts +0 -0
- /package/dist/src/{register-care → register-contracts}/sourceText.js +0 -0
- /package/dist/src/{register-care → register-contracts}/types.js +0 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { findMatchingBracket, parseLayoutExpression, } from './parse-layout-expression.js';
|
|
2
|
+
const TOKEN_SCANNERS = [
|
|
3
|
+
scanPunctuationToken,
|
|
4
|
+
scanShiftOperatorToken,
|
|
5
|
+
scanCurrentLocationOrHexToken,
|
|
6
|
+
scanQuotedByteToken,
|
|
7
|
+
scanSpecialTermToken,
|
|
8
|
+
scanNumberToken,
|
|
9
|
+
scanOperatorToken,
|
|
10
|
+
scanSymbolToken,
|
|
11
|
+
];
|
|
12
|
+
export function tokenizeExpression(text, parseNestedExpression) {
|
|
13
|
+
const tokens = [];
|
|
14
|
+
const input = text.trim();
|
|
15
|
+
let index = 0;
|
|
16
|
+
while (index < input.length) {
|
|
17
|
+
const char = input[index] ?? '';
|
|
18
|
+
if (/\s/.test(char)) {
|
|
19
|
+
index += 1;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const scanned = scanToken(input, index, parseNestedExpression);
|
|
23
|
+
if (!scanned)
|
|
24
|
+
return undefined;
|
|
25
|
+
tokens.push(scanned.token);
|
|
26
|
+
index = scanned.end;
|
|
27
|
+
}
|
|
28
|
+
return tokens.length > 0 ? tokens : undefined;
|
|
29
|
+
}
|
|
30
|
+
function scanToken(input, index, parseNestedExpression) {
|
|
31
|
+
for (const scanner of TOKEN_SCANNERS) {
|
|
32
|
+
const scanned = scanner(input, index, parseNestedExpression);
|
|
33
|
+
if (scanned)
|
|
34
|
+
return scanned;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
function scanPunctuationToken(input, index) {
|
|
39
|
+
const char = input[index];
|
|
40
|
+
if (char === '(')
|
|
41
|
+
return { token: { kind: 'left-paren' }, end: index + 1 };
|
|
42
|
+
if (char === ')')
|
|
43
|
+
return { token: { kind: 'right-paren' }, end: index + 1 };
|
|
44
|
+
if (char === ',')
|
|
45
|
+
return { token: { kind: 'comma' }, end: index + 1 };
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
function scanShiftOperatorToken(input, index) {
|
|
49
|
+
const two = input.slice(index, index + 2);
|
|
50
|
+
return two === '<<' || two === '>>'
|
|
51
|
+
? { token: { kind: 'operator', text: two }, end: index + 2 }
|
|
52
|
+
: undefined;
|
|
53
|
+
}
|
|
54
|
+
function scanCurrentLocationOrHexToken(input, index) {
|
|
55
|
+
if (input[index] !== '$')
|
|
56
|
+
return undefined;
|
|
57
|
+
const prefixedHex = /^\$[0-9A-Fa-f]+/.exec(input.slice(index));
|
|
58
|
+
if (prefixedHex) {
|
|
59
|
+
return {
|
|
60
|
+
token: { kind: 'number', value: Number.parseInt(prefixedHex[0].slice(1), 16) },
|
|
61
|
+
end: index + prefixedHex[0].length,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (/^[A-Za-z_]/.test(input[index + 1] ?? '')) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
return { token: { kind: 'current-location' }, end: index + 1 };
|
|
68
|
+
}
|
|
69
|
+
function scanQuotedByteToken(input, index) {
|
|
70
|
+
const quote = input[index];
|
|
71
|
+
if (quote !== '"' && quote !== "'")
|
|
72
|
+
return undefined;
|
|
73
|
+
const quoted = scanQuotedByte(input, index, quote);
|
|
74
|
+
return quoted ? { token: { kind: 'number', value: quoted.value }, end: quoted.end } : undefined;
|
|
75
|
+
}
|
|
76
|
+
function scanSpecialTermToken(input, index, parseNestedExpression) {
|
|
77
|
+
const term = scanSpecialTerm(input, index, parseNestedExpression);
|
|
78
|
+
return term ? { token: { kind: 'expression', expression: term.expression }, end: term.end } : undefined;
|
|
79
|
+
}
|
|
80
|
+
function scanNumberToken(input, index) {
|
|
81
|
+
const number = scanNumber(input.slice(index));
|
|
82
|
+
return number
|
|
83
|
+
? { token: { kind: 'number', value: number.value }, end: index + number.length }
|
|
84
|
+
: undefined;
|
|
85
|
+
}
|
|
86
|
+
function scanOperatorToken(input, index) {
|
|
87
|
+
const char = input[index] ?? '';
|
|
88
|
+
return isOperatorChar(char) ? { token: { kind: 'operator', text: char }, end: index + 1 } : undefined;
|
|
89
|
+
}
|
|
90
|
+
function scanSymbolToken(input, index) {
|
|
91
|
+
const symbol = /^(?:[A-Za-z_.][A-Za-z0-9_.?]*|\?[A-Za-z0-9_.?]+)/.exec(input.slice(index));
|
|
92
|
+
return symbol ? { token: { kind: 'symbol', text: symbol[0] }, end: index + symbol[0].length } : undefined;
|
|
93
|
+
}
|
|
94
|
+
function isOperatorChar(char) {
|
|
95
|
+
return ['*', '/', '%', '+', '-', '&', '^', '|', '~'].includes(char);
|
|
96
|
+
}
|
|
97
|
+
function scanSpecialTerm(input, start, parseNestedExpression) {
|
|
98
|
+
const byteFunction = scanByteFunction(input, start, parseNestedExpression);
|
|
99
|
+
if (byteFunction) {
|
|
100
|
+
return byteFunction;
|
|
101
|
+
}
|
|
102
|
+
return scanLayoutTerm(input, start, parseNestedExpression);
|
|
103
|
+
}
|
|
104
|
+
function scanByteFunction(input, start, parseNestedExpression) {
|
|
105
|
+
const head = /^(LSB|MSB)\s*\(/.exec(input.slice(start));
|
|
106
|
+
if (!head) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const name = head[1];
|
|
110
|
+
const open = input.indexOf('(', start + name.length);
|
|
111
|
+
if (open === -1 || input.slice(start + name.length, open).trim().length > 0) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
const close = findMatchingParen(input, open);
|
|
115
|
+
if (close === undefined) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
const expression = parseNestedExpression(input.slice(open + 1, close));
|
|
119
|
+
return expression
|
|
120
|
+
? { expression: { kind: 'byte-function', function: name, expression }, end: close + 1 }
|
|
121
|
+
: undefined;
|
|
122
|
+
}
|
|
123
|
+
function scanLayoutTerm(input, start, parseNestedExpression) {
|
|
124
|
+
const layoutCall = scanLayoutCallTerm(input, start, parseNestedExpression);
|
|
125
|
+
if (layoutCall)
|
|
126
|
+
return layoutCall;
|
|
127
|
+
if ((input[start] ?? '') !== '<') {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
const end = scanLayoutCastEnd(input, start);
|
|
131
|
+
if (end === undefined) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
const expression = parseLayoutExpression(input.slice(start, end), parseNestedExpression);
|
|
135
|
+
return expression ? { expression, end } : undefined;
|
|
136
|
+
}
|
|
137
|
+
function scanLayoutCallTerm(input, start, parseNestedExpression) {
|
|
138
|
+
const head = scanLayoutCallHead(input, start);
|
|
139
|
+
if (!head)
|
|
140
|
+
return undefined;
|
|
141
|
+
const close = findMatchingParen(input, head.open);
|
|
142
|
+
if (close === undefined)
|
|
143
|
+
return undefined;
|
|
144
|
+
const expression = parseLayoutExpression(input.slice(start, close + 1), parseNestedExpression);
|
|
145
|
+
return expression ? { expression, end: close + 1 } : undefined;
|
|
146
|
+
}
|
|
147
|
+
function scanLayoutCallHead(input, start) {
|
|
148
|
+
const name = layoutCallNameAt(input, start);
|
|
149
|
+
if (!name)
|
|
150
|
+
return undefined;
|
|
151
|
+
const open = input.indexOf('(', start + name.length);
|
|
152
|
+
return open !== -1 && input.slice(start + name.length, open).trim().length === 0
|
|
153
|
+
? { open }
|
|
154
|
+
: undefined;
|
|
155
|
+
}
|
|
156
|
+
function layoutCallNameAt(input, start) {
|
|
157
|
+
if (input.slice(start).startsWith('sizeof'))
|
|
158
|
+
return 'sizeof';
|
|
159
|
+
if (input.slice(start).startsWith('offset'))
|
|
160
|
+
return 'offset';
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
function findMatchingParen(text, open) {
|
|
164
|
+
let depth = 0;
|
|
165
|
+
let quote;
|
|
166
|
+
for (let index = open; index < text.length; index += 1) {
|
|
167
|
+
const char = text[index];
|
|
168
|
+
if (quote) {
|
|
169
|
+
if (char === quote) {
|
|
170
|
+
quote = undefined;
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (char === '"' || char === "'") {
|
|
175
|
+
quote = char;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (char === '(') {
|
|
179
|
+
depth += 1;
|
|
180
|
+
}
|
|
181
|
+
else if (char === ')') {
|
|
182
|
+
depth -= 1;
|
|
183
|
+
if (depth === 0) {
|
|
184
|
+
return index;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
function scanLayoutCastEnd(input, start) {
|
|
191
|
+
const closeType = input.indexOf('>', start + 1);
|
|
192
|
+
if (closeType === -1) {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
let index = closeType + 1;
|
|
196
|
+
const base = /^(?:[A-Za-z_$][A-Za-z0-9_$?]*|\?[A-Za-z0-9_$?]+)/.exec(input.slice(index));
|
|
197
|
+
if (!base) {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
index += base[0].length;
|
|
201
|
+
let sawPath = false;
|
|
202
|
+
while (index < input.length) {
|
|
203
|
+
const char = input[index];
|
|
204
|
+
if (char === '.') {
|
|
205
|
+
const field = /^\.([A-Za-z_][A-Za-z0-9_]*)/.exec(input.slice(index));
|
|
206
|
+
if (!field) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
sawPath = true;
|
|
210
|
+
index += field[0].length;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (char === '[') {
|
|
214
|
+
const close = findMatchingBracket(input.slice(index));
|
|
215
|
+
if (close === undefined) {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
sawPath = true;
|
|
219
|
+
index += close + 1;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
return sawPath ? index : undefined;
|
|
225
|
+
}
|
|
226
|
+
function scanNumber(text) {
|
|
227
|
+
const trailingHex = /^[0-9][0-9A-Fa-f]*[Hh]\b/.exec(text);
|
|
228
|
+
if (trailingHex) {
|
|
229
|
+
return {
|
|
230
|
+
value: Number.parseInt(trailingHex[0].slice(0, -1), 16),
|
|
231
|
+
length: trailingHex[0].length,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const trailingBinary = /^[01]+[Bb]\b/.exec(text);
|
|
235
|
+
if (trailingBinary) {
|
|
236
|
+
return {
|
|
237
|
+
value: Number.parseInt(trailingBinary[0].slice(0, -1), 2),
|
|
238
|
+
length: trailingBinary[0].length,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const percentBinary = /^%[01]+/.exec(text);
|
|
242
|
+
if (percentBinary) {
|
|
243
|
+
return {
|
|
244
|
+
value: Number.parseInt(percentBinary[0].slice(1), 2),
|
|
245
|
+
length: percentBinary[0].length,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const prefixedBinary = /^0b[01]+/i.exec(text);
|
|
249
|
+
if (prefixedBinary) {
|
|
250
|
+
return {
|
|
251
|
+
value: Number.parseInt(prefixedBinary[0].slice(2), 2),
|
|
252
|
+
length: prefixedBinary[0].length,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
const prefixedHex = /^0x[0-9A-Fa-f]+/i.exec(text);
|
|
256
|
+
if (prefixedHex) {
|
|
257
|
+
return { value: Number.parseInt(prefixedHex[0].slice(2), 16), length: prefixedHex[0].length };
|
|
258
|
+
}
|
|
259
|
+
const decimal = /^[0-9]+/.exec(text);
|
|
260
|
+
if (decimal) {
|
|
261
|
+
return { value: Number.parseInt(decimal[0], 10), length: decimal[0].length };
|
|
262
|
+
}
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
function scanQuotedByte(text, start, quote) {
|
|
266
|
+
const valueIndex = start + 1;
|
|
267
|
+
const value = text[valueIndex];
|
|
268
|
+
if (!isQuotedByteValueStart(value, quote))
|
|
269
|
+
return undefined;
|
|
270
|
+
const scanned = value === '\\' ? scanEscapedQuotedByte(text, valueIndex) : scanLiteralQuotedByte(value, valueIndex);
|
|
271
|
+
if (!scanned)
|
|
272
|
+
return undefined;
|
|
273
|
+
return text[scanned.end] === quote
|
|
274
|
+
? { value: scanned.value, end: scanned.end + 1 }
|
|
275
|
+
: undefined;
|
|
276
|
+
}
|
|
277
|
+
function isQuotedByteValueStart(value, quote) {
|
|
278
|
+
return value !== undefined && value !== quote && value !== '\n' && value !== '\r';
|
|
279
|
+
}
|
|
280
|
+
function scanEscapedQuotedByte(text, valueIndex) {
|
|
281
|
+
const escaped = text[valueIndex + 1];
|
|
282
|
+
if (escaped === undefined)
|
|
283
|
+
return undefined;
|
|
284
|
+
const value = escapeByteValue(escaped);
|
|
285
|
+
return value === undefined ? undefined : { value, end: valueIndex + 2 };
|
|
286
|
+
}
|
|
287
|
+
function scanLiteralQuotedByte(value, valueIndex) {
|
|
288
|
+
const byte = value.codePointAt(0) ?? 0;
|
|
289
|
+
return { value: byte, end: valueIndex + (byte > 0xffff ? 2 : 1) };
|
|
290
|
+
}
|
|
291
|
+
function escapeByteValue(char) {
|
|
292
|
+
switch (char) {
|
|
293
|
+
case '0':
|
|
294
|
+
return 0;
|
|
295
|
+
case 'n':
|
|
296
|
+
return 10;
|
|
297
|
+
case 'r':
|
|
298
|
+
return 13;
|
|
299
|
+
case 't':
|
|
300
|
+
return 9;
|
|
301
|
+
case "'":
|
|
302
|
+
return 39;
|
|
303
|
+
case '"':
|
|
304
|
+
return 34;
|
|
305
|
+
case '\\':
|
|
306
|
+
return 92;
|
|
307
|
+
default:
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LogicalLine } from '../source/logical-lines.js';
|
|
2
|
+
import type { SourceSpan } from '../source/source-span.js';
|
|
3
|
+
import type { ParseLineResult } from './parse-line.js';
|
|
4
|
+
export declare function parseDirectiveStatement(line: LogicalLine, text: string, span: SourceSpan): ParseLineResult | undefined;
|
|
5
|
+
export declare function parseColonDeclaration(line: LogicalLine, name: string, statementText: string, span: {
|
|
6
|
+
readonly sourceName: string;
|
|
7
|
+
readonly line: number;
|
|
8
|
+
readonly column: number;
|
|
9
|
+
}): ParseLineResult | undefined;
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { parseExpression, parseTypeExpr } from './parse-expression.js';
|
|
2
|
+
const DIRECTIVE_PARSERS = [
|
|
3
|
+
{
|
|
4
|
+
pattern: /^([A-Za-z_.$?][A-Za-z0-9_.$?]*)\s+\.equ\s+(.+)$/,
|
|
5
|
+
parse: (line, match, span) => parseEquItem(line, match[1] ?? '', match[2] ?? '', span),
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
pattern: /^\.org\s+(.+)$/,
|
|
9
|
+
parse: (line, match, span) => parseExpressionDirective(line, 'org', match[1] ?? '', span),
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
pattern: /^enum\s+([A-Za-z_][A-Za-z0-9_]*)\s+(.+)$/,
|
|
13
|
+
parse: (line, match) => ({
|
|
14
|
+
items: [],
|
|
15
|
+
diagnostics: [parseError(line, `Use "${match[1] ?? ''} .enum ..." for enums.`)],
|
|
16
|
+
}),
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
pattern: /^([A-Za-z_][A-Za-z0-9_]*)\s+\.enum\s+(.+)$/,
|
|
20
|
+
parse: (line, match, span) => parseEnumItem(line, match[1] ?? '', match[2] ?? '', span),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pattern: /^(\.db|\.dw)\s+(.+)$/,
|
|
24
|
+
parse: (line, match, span) => parseDataDirective(line, match[1] ?? '', match[2] ?? '', span),
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
pattern: /^\.ds\s+(.+)$/,
|
|
28
|
+
parse: (line, match, span) => parseDsDirective(line, match[1] ?? '', span),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
pattern: /^\.align\s+(.+)$/,
|
|
32
|
+
parse: (line, match, span) => parseExpressionDirective(line, 'align', match[1] ?? '', span),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
pattern: /^\.end\s*$/,
|
|
36
|
+
parse: (_line, _match, span) => ({ items: [{ kind: 'end', span }], diagnostics: [] }),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
pattern: /^(\.binfrom|\.binto)\s+(.+)$/,
|
|
40
|
+
parse: (line, match, span) => parseExpressionDirective(line, (match[1] ?? '').slice(1).toLowerCase(), match[2] ?? '', span),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pattern: /^(\.cstr|\.pstr|\.istr)\s+(.+)$/,
|
|
44
|
+
parse: (line, match, span) => parseStringDataDirective(line, (match[1] ?? '').slice(1).toLowerCase(), match[2] ?? '', span),
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
export function parseDirectiveStatement(line, text, span) {
|
|
48
|
+
for (const parser of DIRECTIVE_PARSERS) {
|
|
49
|
+
const match = parser.pattern.exec(text);
|
|
50
|
+
if (match) {
|
|
51
|
+
return parser.parse(line, match, span);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
export function parseColonDeclaration(line, name, statementText, span) {
|
|
57
|
+
const equ = /^\.equ\s+(.+)$/.exec(statementText);
|
|
58
|
+
if (equ) {
|
|
59
|
+
return parseEquItem(line, name, equ[1] ?? '', span);
|
|
60
|
+
}
|
|
61
|
+
const enumDecl = /^\.enum\s+(.+)$/.exec(statementText);
|
|
62
|
+
if (enumDecl) {
|
|
63
|
+
return parseEnumItem(line, name, enumDecl[1] ?? '', span);
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
function parseEquItem(line, name, expressionText, span) {
|
|
68
|
+
const stringValue = parseWholeQuotedString(expressionText.trim());
|
|
69
|
+
const expression = stringValue !== undefined && stringValue.length > 1
|
|
70
|
+
? { kind: 'number', value: 0 }
|
|
71
|
+
: parseExpression(expressionText);
|
|
72
|
+
if (!expression) {
|
|
73
|
+
return {
|
|
74
|
+
items: [],
|
|
75
|
+
diagnostics: [parseError(line, `invalid .equ expression: ${expressionText}`)],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
items: [
|
|
80
|
+
{
|
|
81
|
+
kind: 'equ',
|
|
82
|
+
name,
|
|
83
|
+
expression,
|
|
84
|
+
...(stringValue !== undefined && stringValue.length > 1 ? { stringValue } : {}),
|
|
85
|
+
span,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
diagnostics: [],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function parseExpressionDirective(line, kind, expressionText, span) {
|
|
92
|
+
const expression = parseExpression(expressionText);
|
|
93
|
+
if (!expression) {
|
|
94
|
+
return {
|
|
95
|
+
items: [],
|
|
96
|
+
diagnostics: [parseError(line, `invalid .${kind} expression: ${expressionText}`)],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (kind === 'align') {
|
|
100
|
+
return { items: [{ kind, alignment: expression, span }], diagnostics: [] };
|
|
101
|
+
}
|
|
102
|
+
return { items: [{ kind, expression, span }], diagnostics: [] };
|
|
103
|
+
}
|
|
104
|
+
function parseDataDirective(line, directiveText, valueText, span) {
|
|
105
|
+
const directive = directiveText.slice(1).toLowerCase();
|
|
106
|
+
const parts = splitValueList(valueText);
|
|
107
|
+
const values = directive === 'db'
|
|
108
|
+
? parts.map(parseDataValue).filter((value) => value !== undefined)
|
|
109
|
+
: parts.map(parseExpression).filter((value) => value !== undefined);
|
|
110
|
+
if (values.length !== parts.length) {
|
|
111
|
+
return {
|
|
112
|
+
items: [],
|
|
113
|
+
diagnostics: [parseError(line, `invalid .${directive} value list`)],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
items: directive === 'db'
|
|
118
|
+
? [{ kind: 'db', values: values, span }]
|
|
119
|
+
: [{ kind: 'dw', values: values, span }],
|
|
120
|
+
diagnostics: [],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function parseDsDirective(line, valueText, span) {
|
|
124
|
+
const parts = splitValueList(valueText);
|
|
125
|
+
const listDiagnostic = validateDsValueList(line, parts);
|
|
126
|
+
if (listDiagnostic) {
|
|
127
|
+
return { items: [], diagnostics: [listDiagnostic] };
|
|
128
|
+
}
|
|
129
|
+
const sizeResult = parseDsSize(line, parts[0] ?? '');
|
|
130
|
+
if (sizeResult.diagnostic) {
|
|
131
|
+
return { items: [], diagnostics: [sizeResult.diagnostic] };
|
|
132
|
+
}
|
|
133
|
+
const fillResult = parseDsFill(line, parts[1]);
|
|
134
|
+
if (fillResult.diagnostic) {
|
|
135
|
+
return { items: [], diagnostics: [fillResult.diagnostic] };
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
items: [
|
|
139
|
+
fillResult.fill === undefined
|
|
140
|
+
? { kind: 'ds', size: sizeResult.size, span }
|
|
141
|
+
: { kind: 'ds', size: sizeResult.size, fill: fillResult.fill, span },
|
|
142
|
+
],
|
|
143
|
+
diagnostics: [],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function validateDsValueList(line, parts) {
|
|
147
|
+
return parts.length < 1 || parts.length > 2
|
|
148
|
+
? parseError(line, `invalid .ds value list`)
|
|
149
|
+
: undefined;
|
|
150
|
+
}
|
|
151
|
+
function parseDsSize(line, sizeText) {
|
|
152
|
+
const size = parseTypeSizeExpression(sizeText) ?? parseExpression(sizeText);
|
|
153
|
+
if (!size) {
|
|
154
|
+
return {
|
|
155
|
+
diagnostic: parseError(line, `invalid .ds size: ${sizeText}`),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return { size };
|
|
159
|
+
}
|
|
160
|
+
function parseDsFill(line, fillText) {
|
|
161
|
+
if (fillText === undefined)
|
|
162
|
+
return { fill: undefined };
|
|
163
|
+
const fill = parseExpression(fillText);
|
|
164
|
+
if (!fill) {
|
|
165
|
+
return {
|
|
166
|
+
diagnostic: parseError(line, `invalid .ds fill: ${fillText}`),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return { fill };
|
|
170
|
+
}
|
|
171
|
+
function parseStringDataDirective(line, directive, valueText, span) {
|
|
172
|
+
const value = parseQuotedString(valueText);
|
|
173
|
+
if (value === undefined) {
|
|
174
|
+
return {
|
|
175
|
+
items: [],
|
|
176
|
+
diagnostics: [parseError(line, `.${directive} expects one double-quoted string`)],
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return { items: [{ kind: 'string-data', directive, value, span }], diagnostics: [] };
|
|
180
|
+
}
|
|
181
|
+
function parseEnumItem(line, name, membersText, span) {
|
|
182
|
+
const rawMembers = membersText.split(',').map((member) => member.trim());
|
|
183
|
+
if (membersText.trim().length === 0 || rawMembers.some((member) => member.length === 0)) {
|
|
184
|
+
return {
|
|
185
|
+
items: [],
|
|
186
|
+
diagnostics: [parseError(line, `invalid enum member list`)],
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
const members = [];
|
|
190
|
+
const diagnostics = [];
|
|
191
|
+
for (const member of rawMembers) {
|
|
192
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(member)) {
|
|
193
|
+
diagnostics.push(parseError(line, `Invalid enum member name "${member}": expected <identifier>.`));
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
members.push(member);
|
|
197
|
+
}
|
|
198
|
+
if (diagnostics.length > 0) {
|
|
199
|
+
return { items: [], diagnostics };
|
|
200
|
+
}
|
|
201
|
+
return { items: [{ kind: 'enum', name, members, span }], diagnostics: [] };
|
|
202
|
+
}
|
|
203
|
+
function parseTypeSizeExpression(text) {
|
|
204
|
+
const typeExpr = parseTypeExpr(text);
|
|
205
|
+
return typeExpr ? { kind: 'type-size', typeExpr } : undefined;
|
|
206
|
+
}
|
|
207
|
+
function splitValueList(text) {
|
|
208
|
+
const values = [];
|
|
209
|
+
let state = { quote: undefined, escaped: false, parenDepth: 0 };
|
|
210
|
+
let start = 0;
|
|
211
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
212
|
+
if (isValueSeparator(text[index] ?? '', state)) {
|
|
213
|
+
values.push(text.slice(start, index));
|
|
214
|
+
start = index + 1;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
state = scanValueListChar(text[index] ?? '', state);
|
|
218
|
+
}
|
|
219
|
+
values.push(text.slice(start));
|
|
220
|
+
return values;
|
|
221
|
+
}
|
|
222
|
+
function isValueSeparator(char, state) {
|
|
223
|
+
return char === ',' && state.quote === undefined && state.parenDepth === 0;
|
|
224
|
+
}
|
|
225
|
+
function scanValueListChar(char, state) {
|
|
226
|
+
const escapedState = scanEscapedValueListChar(char, state);
|
|
227
|
+
if (escapedState)
|
|
228
|
+
return escapedState;
|
|
229
|
+
const quotedState = scanQuotedValueListChar(char, state);
|
|
230
|
+
if (quotedState)
|
|
231
|
+
return quotedState;
|
|
232
|
+
return scanParenthesizedValueListChar(char, state);
|
|
233
|
+
}
|
|
234
|
+
function scanEscapedValueListChar(char, state) {
|
|
235
|
+
if (state.escaped)
|
|
236
|
+
return { ...state, escaped: false };
|
|
237
|
+
if (char === '\\' && state.quote !== undefined)
|
|
238
|
+
return { ...state, escaped: true };
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
function scanQuotedValueListChar(char, state) {
|
|
242
|
+
if (char !== '"' && char !== "'")
|
|
243
|
+
return undefined;
|
|
244
|
+
return { ...state, quote: state.quote === char ? undefined : (state.quote ?? char) };
|
|
245
|
+
}
|
|
246
|
+
function scanParenthesizedValueListChar(char, state) {
|
|
247
|
+
if (state.quote !== undefined)
|
|
248
|
+
return state;
|
|
249
|
+
if (char === '(')
|
|
250
|
+
return { ...state, parenDepth: state.parenDepth + 1 };
|
|
251
|
+
if (char === ')')
|
|
252
|
+
return { ...state, parenDepth: Math.max(0, state.parenDepth - 1) };
|
|
253
|
+
return state;
|
|
254
|
+
}
|
|
255
|
+
function parseQuotedString(text) {
|
|
256
|
+
return parseQuotedStringWithQuotes(text, new Set(['"']));
|
|
257
|
+
}
|
|
258
|
+
function parseWholeQuotedString(text) {
|
|
259
|
+
return parseQuotedStringWithQuotes(text, new Set(['"', "'"]));
|
|
260
|
+
}
|
|
261
|
+
function parseQuotedStringWithQuotes(text, allowedQuotes) {
|
|
262
|
+
const input = text.trim();
|
|
263
|
+
const quote = input[0];
|
|
264
|
+
if (!quote || !allowedQuotes.has(quote) || input[input.length - 1] !== quote) {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
return parseQuotedStringContent(input, quote);
|
|
268
|
+
}
|
|
269
|
+
function parseQuotedStringContent(input, quote) {
|
|
270
|
+
let value = '';
|
|
271
|
+
for (let index = 1; index < input.length - 1; index += 1) {
|
|
272
|
+
const char = input[index] ?? '';
|
|
273
|
+
if (char === '\\') {
|
|
274
|
+
if (index + 1 >= input.length - 1) {
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
value += input[index + 1] ?? '';
|
|
278
|
+
index += 1;
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (char === quote) {
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
284
|
+
value += char;
|
|
285
|
+
}
|
|
286
|
+
return value;
|
|
287
|
+
}
|
|
288
|
+
function parseDataValue(text) {
|
|
289
|
+
const expression = parseExpression(text);
|
|
290
|
+
if (expression) {
|
|
291
|
+
return expression;
|
|
292
|
+
}
|
|
293
|
+
const value = parseWholeQuotedString(text);
|
|
294
|
+
return value === undefined ? undefined : { kind: 'string-fragment', value };
|
|
295
|
+
}
|
|
296
|
+
function firstColumn(text) {
|
|
297
|
+
const match = /\S/.exec(text);
|
|
298
|
+
return match ? match.index + 1 : 1;
|
|
299
|
+
}
|
|
300
|
+
function parseError(line, message) {
|
|
301
|
+
return {
|
|
302
|
+
severity: 'error',
|
|
303
|
+
code: 'AZMN_PARSE',
|
|
304
|
+
message,
|
|
305
|
+
sourceName: line.sourceName,
|
|
306
|
+
line: line.line,
|
|
307
|
+
column: firstColumn(line.text),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { Expression
|
|
1
|
+
import type { Expression } from '../model/expression.js';
|
|
2
|
+
export { parseTypeExpr } from './parse-layout-expression.js';
|
|
2
3
|
export declare function parseExpression(text: string): Expression | undefined;
|
|
3
|
-
export declare function parseTypeExpr(text: string): TypeExpr | undefined;
|