@jhlagado/azm 0.2.11 → 0.2.12
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/dist/src/assembly/import-visibility.js +108 -33
- package/dist/src/core/compile.js +1 -0
- package/dist/src/expansion/op-expand-selected.js +8 -1
- package/dist/src/expansion/op-expansion.d.ts +3 -0
- package/dist/src/node/source-host.js +5 -2
- package/dist/src/source/logical-lines.d.ts +1 -0
- package/dist/src/source/source-span.d.ts +1 -0
- package/dist/src/syntax/parse-layout-declarations.js +1 -0
- package/dist/src/syntax/parse-line.js +1 -0
- package/package.json +1 -1
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { diagnostic } from '../semantics/diagnostics.js';
|
|
2
2
|
export function validateImportVisibility(items, diagnostics) {
|
|
3
|
-
const
|
|
3
|
+
const symbols = collectSymbolVisibility(items);
|
|
4
4
|
for (const item of items) {
|
|
5
|
-
validateItemReferences(item,
|
|
5
|
+
validateItemReferences(item, symbols, diagnostics);
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
-
function
|
|
8
|
+
function collectSymbolVisibility(items) {
|
|
9
9
|
const labels = new Map();
|
|
10
|
+
const exactSymbols = new Set();
|
|
10
11
|
const importedSourceUnits = importedUnitNames(items);
|
|
12
|
+
const symbolConflicts = buildSymbolConflictIndex(items);
|
|
11
13
|
for (const item of items) {
|
|
14
|
+
for (const name of exactSymbolNames(item)) {
|
|
15
|
+
exactSymbols.add(name);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
19
|
+
const item = items[index];
|
|
12
20
|
if (item.kind !== 'label')
|
|
13
21
|
continue;
|
|
14
22
|
labels.set(item.name, {
|
|
@@ -16,14 +24,75 @@ function collectLabelVisibility(items) {
|
|
|
16
24
|
definingSourceUnit: item.span.sourceUnit,
|
|
17
25
|
definingSourceName: item.span.sourceName,
|
|
18
26
|
public: isPublicLabel(item, importedSourceUnits),
|
|
27
|
+
duplicateName: hasAddressPlanningNameConflict(item.name, symbolConflicts, items, index),
|
|
19
28
|
});
|
|
20
29
|
}
|
|
21
|
-
return labels;
|
|
30
|
+
return { labels, exactSymbols };
|
|
31
|
+
}
|
|
32
|
+
function buildSymbolConflictIndex(items) {
|
|
33
|
+
const exact = new Map();
|
|
34
|
+
const declarationLower = new Map();
|
|
35
|
+
for (const item of items) {
|
|
36
|
+
for (const name of exactSymbolNames(item)) {
|
|
37
|
+
exact.set(name, (exact.get(name) ?? 0) + 1);
|
|
38
|
+
}
|
|
39
|
+
const declarationName = caseInsensitiveDeclarationName(item);
|
|
40
|
+
if (declarationName !== undefined) {
|
|
41
|
+
const key = declarationName.toLowerCase();
|
|
42
|
+
declarationLower.set(key, (declarationLower.get(key) ?? 0) + 1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { exact, declarationLower };
|
|
46
|
+
}
|
|
47
|
+
function hasAddressPlanningNameConflict(labelName, conflicts, items, labelIndex) {
|
|
48
|
+
return ((conflicts.exact.get(labelName) ?? 0) > 1 ||
|
|
49
|
+
(conflicts.declarationLower.get(labelName.toLowerCase()) ?? 0) > 0 ||
|
|
50
|
+
hasReportedEnumMemberConflict(labelName, items, labelIndex));
|
|
51
|
+
}
|
|
52
|
+
function hasReportedEnumMemberConflict(labelName, items, labelIndex) {
|
|
53
|
+
const lowerName = labelName.toLowerCase();
|
|
54
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
55
|
+
const item = items[index];
|
|
56
|
+
if (item.kind !== 'enum')
|
|
57
|
+
continue;
|
|
58
|
+
for (const memberName of qualifiedEnumMemberNames(item)) {
|
|
59
|
+
if (memberName === labelName)
|
|
60
|
+
return true;
|
|
61
|
+
if (index > labelIndex && memberName.toLowerCase() === lowerName)
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
function exactSymbolNames(item) {
|
|
68
|
+
switch (item.kind) {
|
|
69
|
+
case 'label':
|
|
70
|
+
case 'equ':
|
|
71
|
+
return [item.name];
|
|
72
|
+
case 'enum':
|
|
73
|
+
return qualifiedEnumMemberNames(item);
|
|
74
|
+
default:
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function qualifiedEnumMemberNames(item) {
|
|
79
|
+
return item.kind === 'enum' ? item.members.map((member) => `${item.name}.${member}`) : [];
|
|
80
|
+
}
|
|
81
|
+
function caseInsensitiveDeclarationName(item) {
|
|
82
|
+
switch (item.kind) {
|
|
83
|
+
case 'enum':
|
|
84
|
+
case 'type':
|
|
85
|
+
case 'type-alias':
|
|
86
|
+
return item.name;
|
|
87
|
+
default:
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
22
90
|
}
|
|
23
91
|
function importedUnitNames(items) {
|
|
24
92
|
const units = new Set();
|
|
25
93
|
for (const item of items) {
|
|
26
|
-
if (item.span.
|
|
94
|
+
if (item.span.sourceUnitRelation === 'import' &&
|
|
95
|
+
item.span.sourceUnit !== undefined) {
|
|
27
96
|
units.add(item.span.sourceUnit);
|
|
28
97
|
}
|
|
29
98
|
}
|
|
@@ -34,39 +103,39 @@ function isPublicLabel(item, importedSourceUnits) {
|
|
|
34
103
|
item.span.sourceUnit === undefined ||
|
|
35
104
|
!importedSourceUnits.has(item.span.sourceUnit));
|
|
36
105
|
}
|
|
37
|
-
function validateItemReferences(item,
|
|
106
|
+
function validateItemReferences(item, symbols, diagnostics) {
|
|
38
107
|
switch (item.kind) {
|
|
39
108
|
case 'org':
|
|
40
|
-
validateExpression(item.expression, item.span,
|
|
109
|
+
validateExpression(item.expression, item.span, symbols, diagnostics);
|
|
41
110
|
return;
|
|
42
111
|
case 'equ':
|
|
43
|
-
validateExpression(item.expression, item.span,
|
|
112
|
+
validateExpression(item.expression, item.span, symbols, diagnostics);
|
|
44
113
|
return;
|
|
45
114
|
case 'db':
|
|
46
115
|
for (const value of item.values) {
|
|
47
|
-
validateDataValue(value, item.span,
|
|
116
|
+
validateDataValue(value, item.span, symbols, diagnostics);
|
|
48
117
|
}
|
|
49
118
|
return;
|
|
50
119
|
case 'dw':
|
|
51
120
|
for (const value of item.values) {
|
|
52
|
-
validateExpression(value, item.span,
|
|
121
|
+
validateExpression(value, item.span, symbols, diagnostics);
|
|
53
122
|
}
|
|
54
123
|
return;
|
|
55
124
|
case 'ds':
|
|
56
|
-
validateExpression(item.size, item.span,
|
|
125
|
+
validateExpression(item.size, item.span, symbols, diagnostics);
|
|
57
126
|
if (item.fill !== undefined) {
|
|
58
|
-
validateExpression(item.fill, item.span,
|
|
127
|
+
validateExpression(item.fill, item.span, symbols, diagnostics);
|
|
59
128
|
}
|
|
60
129
|
return;
|
|
61
130
|
case 'align':
|
|
62
|
-
validateExpression(item.alignment, item.span,
|
|
131
|
+
validateExpression(item.alignment, item.span, symbols, diagnostics);
|
|
63
132
|
return;
|
|
64
133
|
case 'binfrom':
|
|
65
134
|
case 'binto':
|
|
66
|
-
validateExpression(item.expression, item.span,
|
|
135
|
+
validateExpression(item.expression, item.span, symbols, diagnostics);
|
|
67
136
|
return;
|
|
68
137
|
case 'instruction':
|
|
69
|
-
validateInstruction(item.instruction, item.span,
|
|
138
|
+
validateInstruction(item.instruction, item.span, symbols, diagnostics);
|
|
70
139
|
return;
|
|
71
140
|
case 'label':
|
|
72
141
|
case 'comment':
|
|
@@ -78,14 +147,14 @@ function validateItemReferences(item, labels, diagnostics) {
|
|
|
78
147
|
return;
|
|
79
148
|
}
|
|
80
149
|
}
|
|
81
|
-
function validateDataValue(value, span,
|
|
150
|
+
function validateDataValue(value, span, symbols, diagnostics) {
|
|
82
151
|
if ('kind' in value && value.kind === 'string-fragment')
|
|
83
152
|
return;
|
|
84
|
-
validateExpression(value, span,
|
|
153
|
+
validateExpression(value, span, symbols, diagnostics);
|
|
85
154
|
}
|
|
86
|
-
function validateInstruction(instruction, span,
|
|
155
|
+
function validateInstruction(instruction, span, symbols, diagnostics) {
|
|
87
156
|
for (const expression of instructionExpressions(instruction)) {
|
|
88
|
-
validateExpression(expression, span,
|
|
157
|
+
validateExpression(expression, span, symbols, diagnostics);
|
|
89
158
|
}
|
|
90
159
|
}
|
|
91
160
|
function instructionExpressions(instruction) {
|
|
@@ -154,49 +223,55 @@ function operandExpressions(operand) {
|
|
|
154
223
|
return [];
|
|
155
224
|
}
|
|
156
225
|
}
|
|
157
|
-
function validateExpression(expression, span,
|
|
226
|
+
function validateExpression(expression, span, symbols, diagnostics) {
|
|
158
227
|
switch (expression.kind) {
|
|
159
228
|
case 'symbol':
|
|
160
|
-
validateSymbolReference(expression.name, span,
|
|
229
|
+
validateSymbolReference(expression.name, span, symbols, diagnostics);
|
|
161
230
|
return;
|
|
162
231
|
case 'byte-function':
|
|
163
232
|
case 'unary':
|
|
164
|
-
validateExpression(expression.expression, span,
|
|
233
|
+
validateExpression(expression.expression, span, symbols, diagnostics);
|
|
165
234
|
return;
|
|
166
235
|
case 'binary':
|
|
167
|
-
validateExpression(expression.left, span,
|
|
168
|
-
validateExpression(expression.right, span,
|
|
236
|
+
validateExpression(expression.left, span, symbols, diagnostics);
|
|
237
|
+
validateExpression(expression.right, span, symbols, diagnostics);
|
|
169
238
|
return;
|
|
170
239
|
case 'layout-cast':
|
|
171
|
-
validateExpression(expression.base, span,
|
|
240
|
+
validateExpression(expression.base, span, symbols, diagnostics);
|
|
172
241
|
for (const part of expression.path) {
|
|
173
242
|
if (part.kind === 'index') {
|
|
174
|
-
validateExpression(part.expression, span,
|
|
243
|
+
validateExpression(part.expression, span, symbols, diagnostics);
|
|
175
244
|
}
|
|
176
245
|
}
|
|
177
246
|
return;
|
|
178
247
|
case 'number':
|
|
179
248
|
case 'current-location':
|
|
180
|
-
case 'type-size':
|
|
181
249
|
case 'sizeof':
|
|
182
250
|
case 'offset':
|
|
183
251
|
return;
|
|
252
|
+
case 'type-size':
|
|
253
|
+
if (expression.typeExpr.length === undefined) {
|
|
254
|
+
validateSymbolReference(expression.typeExpr.name, span, symbols, diagnostics);
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
184
257
|
}
|
|
185
258
|
}
|
|
186
|
-
function validateSymbolReference(name, referenceSpan,
|
|
187
|
-
const label = lookupLabel(
|
|
188
|
-
if (!label || label.public)
|
|
259
|
+
function validateSymbolReference(name, referenceSpan, symbols, diagnostics) {
|
|
260
|
+
const label = lookupLabel(symbols, name);
|
|
261
|
+
if (!label || label.duplicateName || label.public)
|
|
189
262
|
return;
|
|
190
263
|
if (referenceSpan.sourceUnit === label.definingSourceUnit)
|
|
191
264
|
return;
|
|
192
265
|
diagnostics.push(diagnostic(referenceSpan, `symbol "${name}" is private to ${label.definingSourceName}; export it with @${label.name} or keep the reference inside that file`));
|
|
193
266
|
}
|
|
194
|
-
function lookupLabel(
|
|
195
|
-
const direct = labels.get(name);
|
|
267
|
+
function lookupLabel(symbols, name) {
|
|
268
|
+
const direct = symbols.labels.get(name);
|
|
196
269
|
if (direct)
|
|
197
270
|
return direct;
|
|
271
|
+
if (symbols.exactSymbols.has(name))
|
|
272
|
+
return undefined;
|
|
198
273
|
const lowerName = name.toLowerCase();
|
|
199
|
-
for (const [key, label] of labels) {
|
|
274
|
+
for (const [key, label] of symbols.labels) {
|
|
200
275
|
if (key.toLowerCase() === lowerName)
|
|
201
276
|
return label;
|
|
202
277
|
}
|
package/dist/src/core/compile.js
CHANGED
|
@@ -158,6 +158,7 @@ function spanAt(line, column) {
|
|
|
158
158
|
column,
|
|
159
159
|
...(line.sourceUnit !== undefined ? { sourceUnit: line.sourceUnit } : {}),
|
|
160
160
|
...(line.sourceRelation !== undefined ? { sourceRelation: line.sourceRelation } : {}),
|
|
161
|
+
...(line.sourceUnitRelation !== undefined ? { sourceUnitRelation: line.sourceUnitRelation } : {}),
|
|
161
162
|
};
|
|
162
163
|
}
|
|
163
164
|
function firstColumn(text) {
|
|
@@ -60,7 +60,14 @@ function expandTemplateItem(ops, item, bindings, line, diagnostics, overload, ex
|
|
|
60
60
|
}
|
|
61
61
|
function opEmittedSource(line) {
|
|
62
62
|
return {
|
|
63
|
-
span: {
|
|
63
|
+
span: {
|
|
64
|
+
sourceName: line.sourceName,
|
|
65
|
+
line: line.line,
|
|
66
|
+
column: firstColumn(line.text),
|
|
67
|
+
...(line.sourceUnit !== undefined ? { sourceUnit: line.sourceUnit } : {}),
|
|
68
|
+
...(line.sourceRelation !== undefined ? { sourceRelation: line.sourceRelation } : {}),
|
|
69
|
+
...(line.sourceUnitRelation !== undefined ? { sourceUnitRelation: line.sourceUnitRelation } : {}),
|
|
70
|
+
},
|
|
64
71
|
kind: 'macro',
|
|
65
72
|
};
|
|
66
73
|
}
|
|
@@ -6,6 +6,9 @@ export type LogicalLineLike = {
|
|
|
6
6
|
readonly sourceName: string;
|
|
7
7
|
readonly line: number;
|
|
8
8
|
readonly text: string;
|
|
9
|
+
readonly sourceUnit?: string;
|
|
10
|
+
readonly sourceRelation?: 'entry' | 'include' | 'import';
|
|
11
|
+
readonly sourceUnitRelation?: 'entry' | 'include' | 'import';
|
|
9
12
|
};
|
|
10
13
|
interface OpParam {
|
|
11
14
|
readonly name: string;
|
|
@@ -30,6 +30,7 @@ export async function expandSourceForTooling(options) {
|
|
|
30
30
|
sourceStack: [],
|
|
31
31
|
sourceUnit: entryFile,
|
|
32
32
|
sourceRelation: 'entry',
|
|
33
|
+
sourceUnitRelation: 'entry',
|
|
33
34
|
...(options.preloadedText !== undefined ? { preloadedText: options.preloadedText } : {}),
|
|
34
35
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
35
36
|
});
|
|
@@ -60,7 +61,7 @@ async function expandFile(options) {
|
|
|
60
61
|
recordLineComment(options.sourceLineComments, line);
|
|
61
62
|
const directive = parseSourceLoadDirective(line.text);
|
|
62
63
|
if (!directive) {
|
|
63
|
-
output.push(withSourceOwnership(line, options.sourceUnit, options.sourceRelation));
|
|
64
|
+
output.push(withSourceOwnership(line, options.sourceUnit, options.sourceRelation, options.sourceUnitRelation));
|
|
64
65
|
continue;
|
|
65
66
|
}
|
|
66
67
|
const result = await resolveSourcePath(sourcePath, directive.path, options.includeDirs);
|
|
@@ -88,6 +89,7 @@ async function expandFile(options) {
|
|
|
88
89
|
sourceStack: [...options.sourceStack, { sourcePath }],
|
|
89
90
|
sourceUnit: directive.kind === 'import' ? result.resolved : options.sourceUnit,
|
|
90
91
|
sourceRelation: directive.kind,
|
|
92
|
+
sourceUnitRelation: directive.kind === 'import' ? 'import' : options.sourceUnitRelation,
|
|
91
93
|
});
|
|
92
94
|
if (included !== undefined) {
|
|
93
95
|
output.push(...included);
|
|
@@ -95,11 +97,12 @@ async function expandFile(options) {
|
|
|
95
97
|
}
|
|
96
98
|
return output;
|
|
97
99
|
}
|
|
98
|
-
function withSourceOwnership(line, sourceUnit, sourceRelation) {
|
|
100
|
+
function withSourceOwnership(line, sourceUnit, sourceRelation, sourceUnitRelation) {
|
|
99
101
|
return {
|
|
100
102
|
...line,
|
|
101
103
|
sourceUnit,
|
|
102
104
|
sourceRelation,
|
|
105
|
+
sourceUnitRelation,
|
|
103
106
|
};
|
|
104
107
|
}
|
|
105
108
|
function recordLineComment(comments, line) {
|
|
@@ -5,6 +5,7 @@ export interface LogicalLine {
|
|
|
5
5
|
readonly text: string;
|
|
6
6
|
readonly sourceUnit?: string;
|
|
7
7
|
readonly sourceRelation?: SourceRelation;
|
|
8
|
+
readonly sourceUnitRelation?: SourceRelation;
|
|
8
9
|
}
|
|
9
10
|
export type SourceRelation = 'entry' | 'include' | 'import';
|
|
10
11
|
export declare function scanLogicalLines(source: SourceFile): LogicalLine[];
|
|
@@ -112,6 +112,7 @@ function spanForLine(line) {
|
|
|
112
112
|
column: firstNonWhitespaceColumn(line.text),
|
|
113
113
|
...(line.sourceUnit !== undefined ? { sourceUnit: line.sourceUnit } : {}),
|
|
114
114
|
...(line.sourceRelation !== undefined ? { sourceRelation: line.sourceRelation } : {}),
|
|
115
|
+
...(line.sourceUnitRelation !== undefined ? { sourceUnitRelation: line.sourceUnitRelation } : {}),
|
|
115
116
|
};
|
|
116
117
|
}
|
|
117
118
|
function skipToLayoutEnd(lines, index, directive) {
|
|
@@ -127,5 +127,6 @@ function spanForLine(line) {
|
|
|
127
127
|
column: firstNonWhitespaceColumn(line.text),
|
|
128
128
|
...(line.sourceUnit !== undefined ? { sourceUnit: line.sourceUnit } : {}),
|
|
129
129
|
...(line.sourceRelation !== undefined ? { sourceRelation: line.sourceRelation } : {}),
|
|
130
|
+
...(line.sourceUnitRelation !== undefined ? { sourceUnitRelation: line.sourceUnitRelation } : {}),
|
|
130
131
|
};
|
|
131
132
|
}
|