@spyglassmc/mcdoc 0.3.0 → 0.3.2
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/lib/binder/index.d.ts +7 -0
- package/lib/binder/index.js +268 -175
- package/lib/colorizer/index.js +2 -2
- package/lib/node/index.d.ts +21 -7
- package/lib/node/index.js +64 -28
- package/lib/parser/index.d.ts +1 -1
- package/lib/parser/index.js +162 -147
- package/lib/type/index.d.ts +39 -23
- package/lib/type/index.js +138 -56
- package/lib/uri_processors.js +5 -5
- package/package.json +3 -3
package/lib/binder/index.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { AsyncBinder, atArray, Dev, Range, ResourceLocationNode, SymbolUtil, traversePreOrder } from '@spyglassmc/core';
|
|
1
|
+
import { AsyncBinder, atArray, Dev, Range, ResourceLocationNode, SymbolUtil, traversePreOrder, } from '@spyglassmc/core';
|
|
2
2
|
import { localeQuote, localize } from '@spyglassmc/locales';
|
|
3
|
-
import { AttributeNode, AttributeTreeNamedValuesNode, AttributeTreeNode, AttributeTreePosValuesNode, DispatcherTypeNode, DispatchStatementNode, DocCommentsNode, DynamicIndexNode, EnumBlockNode, EnumFieldNode, EnumInjectionNode, EnumNode, FloatRangeNode, IndexBodyNode, InjectionNode, IntRangeNode, ListTypeNode, LiteralNode, LiteralTypeNode, NumericTypeNode, PathNode, PrimitiveArrayTypeNode, ReferenceTypeNode, StaticIndexNode, StringTypeNode, StructBlockNode, StructMapKeyNode, StructNode, StructPairFieldNode, StructSpreadFieldNode, TopLevelNode, TupleTypeNode, TypeAliasNode, TypeBaseNode, TypedNumberNode, TypeParamBlockNode, TypeParamNode, UnionTypeNode, UseStatementNode } from '../node/index.js';
|
|
3
|
+
import { AttributeNode, AttributeTreeNamedValuesNode, AttributeTreeNode, AttributeTreePosValuesNode, DispatcherTypeNode, DispatchStatementNode, DocCommentsNode, DynamicIndexNode, EnumBlockNode, EnumFieldNode, EnumInjectionNode, EnumNode, FloatRangeNode, IndexBodyNode, InjectionNode, IntRangeNode, ListTypeNode, LiteralNode, LiteralTypeNode, NumericTypeNode, PathNode, PrimitiveArrayTypeNode, ReferenceTypeNode, StaticIndexNode, StringTypeNode, StructBlockNode, StructMapKeyNode, StructNode, StructPairFieldNode, StructSpreadFieldNode, TopLevelNode, TupleTypeNode, TypeAliasNode, TypeArgBlockNode, TypeBaseNode, TypedNumberNode, TypeParamBlockNode, TypeParamNode, UnionTypeNode, UseStatementNode, } from '../node/index.js';
|
|
4
4
|
const ModuleSymbolData = Object.freeze({
|
|
5
5
|
is(data) {
|
|
6
|
-
return !!data &&
|
|
6
|
+
return (!!data &&
|
|
7
|
+
typeof data === 'object' &&
|
|
8
|
+
typeof data.nextAnonymousIndex === 'number');
|
|
7
9
|
},
|
|
8
10
|
});
|
|
9
|
-
const TypeDefSymbolData = Object.freeze({
|
|
11
|
+
export const TypeDefSymbolData = Object.freeze({
|
|
10
12
|
is(data) {
|
|
11
|
-
return !!data &&
|
|
13
|
+
return (!!data &&
|
|
14
|
+
typeof data === 'object' &&
|
|
15
|
+
typeof data.typeDef === 'object');
|
|
12
16
|
},
|
|
13
17
|
});
|
|
14
18
|
export const fileModule = AsyncBinder.create(async (node, ctx) => {
|
|
@@ -56,7 +60,7 @@ export async function module_(node, ctx) {
|
|
|
56
60
|
* Hoist enums, structs, type aliases, and use statements under the module scope.
|
|
57
61
|
*/
|
|
58
62
|
function hoist(node, ctx) {
|
|
59
|
-
traversePreOrder(node, () => true, TopLevelNode.is, child => {
|
|
63
|
+
traversePreOrder(node, () => true, TopLevelNode.is, (child) => {
|
|
60
64
|
switch (child.type) {
|
|
61
65
|
case 'mcdoc:enum':
|
|
62
66
|
hoistEnum(child);
|
|
@@ -73,18 +77,27 @@ function hoist(node, ctx) {
|
|
|
73
77
|
}
|
|
74
78
|
});
|
|
75
79
|
function hoistEnum(node) {
|
|
76
|
-
hoistFor('enum', node, EnumNode.destruct, n => ({
|
|
80
|
+
hoistFor('enum', node, EnumNode.destruct, (n) => ({
|
|
81
|
+
typeDef: convertEnum(n, ctx),
|
|
82
|
+
}));
|
|
77
83
|
}
|
|
78
84
|
function hoistStruct(node) {
|
|
79
|
-
hoistFor('struct', node, StructNode.destruct, n => ({
|
|
85
|
+
hoistFor('struct', node, StructNode.destruct, (n) => ({
|
|
86
|
+
typeDef: convertStruct(n, ctx),
|
|
87
|
+
}));
|
|
80
88
|
}
|
|
81
89
|
function hoistTypeAlias(node) {
|
|
82
|
-
hoistFor('type_alias', node, TypeAliasNode.destruct, n => {
|
|
83
|
-
const { rhs } = TypeAliasNode.destruct(n);
|
|
90
|
+
hoistFor('type_alias', node, TypeAliasNode.destruct, (n) => {
|
|
91
|
+
const { attributes, rhs, typeParams } = TypeAliasNode.destruct(n);
|
|
84
92
|
if (!rhs) {
|
|
85
93
|
return undefined;
|
|
86
94
|
}
|
|
87
|
-
|
|
95
|
+
const ans = { typeDef: convertType(rhs, ctx) };
|
|
96
|
+
if (typeParams) {
|
|
97
|
+
bindTypeParamBlock(node, typeParams, ans, ctx);
|
|
98
|
+
}
|
|
99
|
+
ans.typeDef = attributeType(ans.typeDef, attributes, ctx);
|
|
100
|
+
return ans;
|
|
88
101
|
});
|
|
89
102
|
}
|
|
90
103
|
function hoistUseStatement(node) {
|
|
@@ -103,23 +116,34 @@ function hoist(node, ctx) {
|
|
|
103
116
|
// they will go to the definition in the imported file.
|
|
104
117
|
ctx.symbols
|
|
105
118
|
.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${identifier.value}`)
|
|
106
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier))
|
|
119
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, identifier))
|
|
107
120
|
.elseEnter({
|
|
108
|
-
data: {
|
|
121
|
+
data: {
|
|
122
|
+
subcategory: 'use_statement_binding',
|
|
123
|
+
visibility: 1 /* SymbolVisibility.File */,
|
|
124
|
+
},
|
|
109
125
|
usage: { type: 'definition', node: identifier, fullRange: node },
|
|
110
126
|
});
|
|
111
127
|
}
|
|
112
128
|
function hoistFor(subcategory, node, destructor, getData) {
|
|
113
|
-
const { docComments, identifier } = destructor(node);
|
|
129
|
+
const { docComments, identifier, keyword } = destructor(node);
|
|
114
130
|
const name = identifier?.value ?? nextAnonymousIdentifier(node, ctx);
|
|
115
131
|
ctx.symbols
|
|
116
132
|
.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${name}`)
|
|
117
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier ?? node))
|
|
133
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, identifier ?? node))
|
|
118
134
|
.elseEnter({
|
|
119
|
-
data: {
|
|
135
|
+
data: {
|
|
136
|
+
data: getData(node),
|
|
137
|
+
desc: DocCommentsNode.asText(docComments),
|
|
138
|
+
subcategory,
|
|
139
|
+
},
|
|
120
140
|
// If the current syntax structure is named, then the identifier node is entered as a definition;
|
|
121
|
-
// otherwise, an anonymous identifier is generated for the symbol and the
|
|
122
|
-
usage: {
|
|
141
|
+
// otherwise, an anonymous identifier is generated for the symbol and the keyword node is entered as a definition.
|
|
142
|
+
usage: {
|
|
143
|
+
type: 'definition',
|
|
144
|
+
node: identifier ?? keyword,
|
|
145
|
+
fullRange: identifier && node,
|
|
146
|
+
},
|
|
123
147
|
});
|
|
124
148
|
}
|
|
125
149
|
function nextAnonymousIndex(node, ctx) {
|
|
@@ -135,41 +159,83 @@ function hoist(node, ctx) {
|
|
|
135
159
|
return `<anonymous ${nextAnonymousIndex(node, ctx)}>`;
|
|
136
160
|
}
|
|
137
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Bind the type param block of a parent node, and modifies the `data` argument in-place to change its `typeDef` to be of template kind.
|
|
164
|
+
*/
|
|
165
|
+
function bindTypeParamBlock(node, typeParams, data, ctx) {
|
|
166
|
+
// Type parameters are added as local symbols on the type alias AST node.
|
|
167
|
+
// Thus we create a new local scope on the type alias statement node first.
|
|
168
|
+
node.locals = Object.create(null);
|
|
169
|
+
// They are also added to the type definition.
|
|
170
|
+
data.typeDef = {
|
|
171
|
+
kind: 'template',
|
|
172
|
+
child: data.typeDef,
|
|
173
|
+
typeParams: [],
|
|
174
|
+
};
|
|
175
|
+
const { params } = TypeParamBlockNode.destruct(typeParams);
|
|
176
|
+
for (const param of params) {
|
|
177
|
+
const { identifier: paramIdentifier } = TypeParamNode.destruct(param);
|
|
178
|
+
if (paramIdentifier.value) {
|
|
179
|
+
// Add the type parameter as a local symbol.
|
|
180
|
+
const paramPath = `${ctx.moduleIdentifier}::${paramIdentifier.value}`;
|
|
181
|
+
ctx.symbols
|
|
182
|
+
.query({ doc: ctx.doc, node }, 'mcdoc', paramPath)
|
|
183
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, paramIdentifier))
|
|
184
|
+
.elseEnter({
|
|
185
|
+
data: { visibility: 0 /* SymbolVisibility.Block */ },
|
|
186
|
+
usage: {
|
|
187
|
+
type: 'declaration',
|
|
188
|
+
node: paramIdentifier,
|
|
189
|
+
fullRange: param,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
// Also add it to the type definition.
|
|
193
|
+
data.typeDef.typeParams.push({ path: paramPath });
|
|
194
|
+
}
|
|
195
|
+
// if (constraint) {
|
|
196
|
+
// await bindPath(constraint, ctx)
|
|
197
|
+
// }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
138
200
|
async function bindDispatchStatement(node, ctx) {
|
|
139
|
-
const { attributes, location, index, target } = DispatchStatementNode.destruct(node);
|
|
201
|
+
const { attributes, location, index, target, typeParams } = DispatchStatementNode.destruct(node);
|
|
140
202
|
if (!(location && index && target)) {
|
|
141
203
|
return;
|
|
142
204
|
}
|
|
143
205
|
const locationStr = ResourceLocationNode.toString(location, 'full');
|
|
144
|
-
ctx.symbols
|
|
145
|
-
.query(ctx.doc, 'mcdoc/dispatcher', locationStr)
|
|
146
|
-
.enter({
|
|
206
|
+
ctx.symbols.query(ctx.doc, 'mcdoc/dispatcher', locationStr).enter({
|
|
147
207
|
usage: { type: 'reference', node: location, fullRange: node },
|
|
148
208
|
});
|
|
149
209
|
const { parallelIndices } = IndexBodyNode.destruct(index);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
210
|
+
if (parallelIndices.length) {
|
|
211
|
+
const data = {
|
|
212
|
+
typeDef: convertType(target, ctx),
|
|
213
|
+
};
|
|
214
|
+
if (typeParams) {
|
|
215
|
+
bindTypeParamBlock(node, typeParams, data, ctx);
|
|
216
|
+
}
|
|
217
|
+
data.typeDef = attributeType(data.typeDef, attributes, ctx);
|
|
218
|
+
for (const key of parallelIndices) {
|
|
219
|
+
if (DynamicIndexNode.is(key)) {
|
|
220
|
+
// Ignore dynamic indices in dispatch statements.
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
ctx.symbols
|
|
224
|
+
.query(ctx.doc, 'mcdoc/dispatcher', locationStr, asString(key))
|
|
225
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, key, {
|
|
226
|
+
localeString: 'mcdoc.binder.dispatcher-statement.duplicated-key',
|
|
227
|
+
}))
|
|
228
|
+
.elseEnter({
|
|
229
|
+
data: { data },
|
|
230
|
+
usage: { type: 'definition', node: key, fullRange: node },
|
|
231
|
+
});
|
|
154
232
|
}
|
|
155
|
-
ctx.symbols
|
|
156
|
-
.query(ctx.doc, 'mcdoc/dispatcher', locationStr, asString(key))
|
|
157
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, key, { localeString: 'mcdoc.binder.dispatcher-statement.duplicated-key.related' }))
|
|
158
|
-
.elseEnter({
|
|
159
|
-
data: {
|
|
160
|
-
data: {
|
|
161
|
-
attributes: convertAttributes(attributes, ctx),
|
|
162
|
-
typeDef: convertType(target, ctx),
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
usage: { type: 'definition', node: key, fullRange: node },
|
|
166
|
-
});
|
|
167
233
|
}
|
|
168
234
|
await bindType(target, ctx);
|
|
169
235
|
}
|
|
170
236
|
async function bindType(node, ctx) {
|
|
171
237
|
if (DispatcherTypeNode.is(node)) {
|
|
172
|
-
bindDispatcherType(node, ctx);
|
|
238
|
+
await bindDispatcherType(node, ctx);
|
|
173
239
|
}
|
|
174
240
|
else if (EnumNode.is(node)) {
|
|
175
241
|
bindEnum(node, ctx);
|
|
@@ -179,11 +245,8 @@ async function bindType(node, ctx) {
|
|
|
179
245
|
await bindType(item, ctx);
|
|
180
246
|
}
|
|
181
247
|
else if (ReferenceTypeNode.is(node)) {
|
|
182
|
-
const { path
|
|
248
|
+
const { path } = ReferenceTypeNode.destruct(node);
|
|
183
249
|
await bindPath(path, ctx);
|
|
184
|
-
for (const param of typeParameters) {
|
|
185
|
-
await bindType(param, ctx);
|
|
186
|
-
}
|
|
187
250
|
}
|
|
188
251
|
else if (StructNode.is(node)) {
|
|
189
252
|
await bindStruct(node, ctx);
|
|
@@ -200,10 +263,22 @@ async function bindType(node, ctx) {
|
|
|
200
263
|
await bindType(member, ctx);
|
|
201
264
|
}
|
|
202
265
|
}
|
|
266
|
+
const { appendixes } = TypeBaseNode.destruct(node);
|
|
267
|
+
for (const appendix of appendixes) {
|
|
268
|
+
if (TypeArgBlockNode.is(appendix)) {
|
|
269
|
+
const { args } = TypeArgBlockNode.destruct(appendix);
|
|
270
|
+
for (const arg of args) {
|
|
271
|
+
await bindType(arg, ctx);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
203
275
|
}
|
|
204
|
-
function bindDispatcherType(node, ctx) {
|
|
276
|
+
async function bindDispatcherType(node, ctx) {
|
|
205
277
|
const { index, location } = DispatcherTypeNode.destruct(node);
|
|
206
278
|
const locationStr = ResourceLocationNode.toString(location, 'full');
|
|
279
|
+
ctx.symbols
|
|
280
|
+
.query(ctx.doc, 'mcdoc/dispatcher', locationStr)
|
|
281
|
+
.enter({ usage: { type: 'reference', node: location, fullRange: node } });
|
|
207
282
|
const { parallelIndices } = IndexBodyNode.destruct(index);
|
|
208
283
|
for (const key of parallelIndices) {
|
|
209
284
|
if (DynamicIndexNode.is(key)) {
|
|
@@ -226,7 +301,7 @@ async function bindPath(node, ctx) {
|
|
|
226
301
|
const referencedModuleFile = pathArrayToString(identifiers);
|
|
227
302
|
const referencedModuleUri = identifierToUri(referencedModuleFile, ctx);
|
|
228
303
|
if (!referencedModuleUri) {
|
|
229
|
-
ctx.err.report(localize('mcdoc.binder.path.unknown-module', localeQuote(referencedModuleFile)), node);
|
|
304
|
+
ctx.err.report(localize('mcdoc.binder.path.unknown-module', localeQuote(referencedModuleFile)), node, 2 /* ErrorSeverity.Warning */);
|
|
230
305
|
return;
|
|
231
306
|
}
|
|
232
307
|
await ctx.ensureBindingStarted(referencedModuleUri);
|
|
@@ -234,18 +309,23 @@ async function bindPath(node, ctx) {
|
|
|
234
309
|
ctx.symbols
|
|
235
310
|
.query({ doc: ctx.doc, node: identNode }, 'mcdoc', pathArrayToString(identifiers))
|
|
236
311
|
.ifDeclared((_, query) => query.enter({
|
|
237
|
-
usage: {
|
|
312
|
+
usage: {
|
|
313
|
+
type: 'reference',
|
|
314
|
+
node: identNode,
|
|
315
|
+
fullRange: node,
|
|
316
|
+
skipRenaming: LiteralNode.is(identNode),
|
|
317
|
+
},
|
|
238
318
|
}))
|
|
239
319
|
.else(() => {
|
|
240
320
|
if (indexRight === 0) {
|
|
241
|
-
ctx.err.report(localize('mcdoc.binder.path.unknown-identifier', localeQuote(atArray(identifiers, -1)), localeQuote(pathArrayToString(identifiers.slice(0, -1)))), node);
|
|
321
|
+
ctx.err.report(localize('mcdoc.binder.path.unknown-identifier', localeQuote(atArray(identifiers, -1)), localeQuote(pathArrayToString(identifiers.slice(0, -1)))), node, 2 /* ErrorSeverity.Warning */);
|
|
242
322
|
}
|
|
243
323
|
});
|
|
244
324
|
}
|
|
245
325
|
}
|
|
246
326
|
function bindEnum(node, ctx) {
|
|
247
|
-
const { block, identifier } = EnumNode.destruct(node);
|
|
248
|
-
const symbol = identifier?.symbol ??
|
|
327
|
+
const { block, identifier, keyword } = EnumNode.destruct(node);
|
|
328
|
+
const symbol = identifier?.symbol ?? keyword.symbol;
|
|
249
329
|
if (symbol?.subcategory !== 'enum') {
|
|
250
330
|
return;
|
|
251
331
|
}
|
|
@@ -257,9 +337,11 @@ function bindEnumBlock(node, ctx, query, options = {}) {
|
|
|
257
337
|
const { fields } = EnumBlockNode.destruct(node);
|
|
258
338
|
for (const field of fields) {
|
|
259
339
|
const { identifier } = EnumFieldNode.destruct(field);
|
|
260
|
-
query.member(identifier.value, fieldQuery => fieldQuery
|
|
261
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier))
|
|
262
|
-
.elseEnter({
|
|
340
|
+
query.member(identifier.value, (fieldQuery) => fieldQuery
|
|
341
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, identifier))
|
|
342
|
+
.elseEnter({
|
|
343
|
+
usage: { type: 'definition', node: identifier, fullRange: field },
|
|
344
|
+
}));
|
|
263
345
|
}
|
|
264
346
|
}
|
|
265
347
|
async function bindInjection(node, ctx) {
|
|
@@ -271,8 +353,8 @@ async function bindInjection(node, ctx) {
|
|
|
271
353
|
}
|
|
272
354
|
}
|
|
273
355
|
async function bindStruct(node, ctx) {
|
|
274
|
-
const { block, identifier } = StructNode.destruct(node);
|
|
275
|
-
const symbol = identifier?.symbol ??
|
|
356
|
+
const { block, identifier, keyword } = StructNode.destruct(node);
|
|
357
|
+
const symbol = identifier?.symbol ?? keyword.symbol;
|
|
276
358
|
if (symbol?.subcategory !== 'struct') {
|
|
277
359
|
return;
|
|
278
360
|
}
|
|
@@ -286,9 +368,11 @@ async function bindStructBlock(node, ctx, query, options = {}) {
|
|
|
286
368
|
if (StructPairFieldNode.is(field)) {
|
|
287
369
|
const { key, type } = StructPairFieldNode.destruct(field);
|
|
288
370
|
if (!StructMapKeyNode.is(key)) {
|
|
289
|
-
query.member(key.value, fieldQuery => fieldQuery
|
|
290
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, key))
|
|
291
|
-
.elseEnter({
|
|
371
|
+
query.member(key.value, (fieldQuery) => fieldQuery
|
|
372
|
+
.ifDeclared((symbol) => reportDuplicatedDeclaration(ctx, symbol, key))
|
|
373
|
+
.elseEnter({
|
|
374
|
+
usage: { type: 'definition', node: key, fullRange: field },
|
|
375
|
+
}));
|
|
292
376
|
}
|
|
293
377
|
await bindType(type, ctx);
|
|
294
378
|
}
|
|
@@ -303,39 +387,6 @@ async function bindTypeAlias(node, ctx) {
|
|
|
303
387
|
if (!identifier?.value) {
|
|
304
388
|
return;
|
|
305
389
|
}
|
|
306
|
-
if (typeParams) {
|
|
307
|
-
// Type parameters are added as local symbols on the type alias AST node.
|
|
308
|
-
node.locals = Object.create(null);
|
|
309
|
-
const { params } = TypeParamBlockNode.destruct(typeParams);
|
|
310
|
-
const query = ctx.symbols.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${identifier.value}`);
|
|
311
|
-
if (query.symbol?.subcategory === 'type_alias') {
|
|
312
|
-
// Type parameters are also added to the symbol data.
|
|
313
|
-
const oldData = query.symbol.data;
|
|
314
|
-
if (!TypeDefSymbolData.is(oldData)) {
|
|
315
|
-
throw new Error('Failed to locate the typeDef data associated with a supposedly hoisted type alias symbol');
|
|
316
|
-
}
|
|
317
|
-
const data = {
|
|
318
|
-
...oldData,
|
|
319
|
-
typeParams: [],
|
|
320
|
-
};
|
|
321
|
-
query.symbol.data = data;
|
|
322
|
-
for (const param of params) {
|
|
323
|
-
const { identifier: paramIdentifier } = TypeParamNode.destruct(param);
|
|
324
|
-
if (paramIdentifier.value) {
|
|
325
|
-
// Add the type parameter as a local symbol.
|
|
326
|
-
ctx.symbols
|
|
327
|
-
.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${paramIdentifier.value}`)
|
|
328
|
-
.ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, paramIdentifier))
|
|
329
|
-
.elseEnter({ data: { visibility: 0 /* SymbolVisibility.Block */ }, usage: { type: 'declaration', node: paramIdentifier, fullRange: param } });
|
|
330
|
-
// Also add it to the symbol data.
|
|
331
|
-
data.typeParams.push({ identifier: paramIdentifier.value });
|
|
332
|
-
}
|
|
333
|
-
// if (constraint) {
|
|
334
|
-
// await bindPath(constraint, ctx)
|
|
335
|
-
// }
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
390
|
if (rhs) {
|
|
340
391
|
await bindType(rhs, ctx);
|
|
341
392
|
}
|
|
@@ -352,10 +403,12 @@ export function registerMcdocBinders(meta) {
|
|
|
352
403
|
}
|
|
353
404
|
function reportDuplicatedDeclaration(ctx, symbol, range, options = { localeString: 'mcdoc.binder.duplicated-declaration' }) {
|
|
354
405
|
ctx.err.report(localize(options.localeString, localeQuote(symbol.identifier)), range, 2 /* ErrorSeverity.Warning */, {
|
|
355
|
-
related: [
|
|
406
|
+
related: [
|
|
407
|
+
{
|
|
356
408
|
location: SymbolUtil.getDeclaredLocation(symbol),
|
|
357
409
|
message: localize(`${options.localeString}.related`, localeQuote(symbol.identifier)),
|
|
358
|
-
}
|
|
410
|
+
},
|
|
411
|
+
],
|
|
359
412
|
});
|
|
360
413
|
}
|
|
361
414
|
function* resolvePathByStep(path, ctx, options = {}) {
|
|
@@ -381,7 +434,12 @@ function* resolvePathByStep(path, ctx, options = {}) {
|
|
|
381
434
|
default:
|
|
382
435
|
Dev.assertNever(child);
|
|
383
436
|
}
|
|
384
|
-
yield {
|
|
437
|
+
yield {
|
|
438
|
+
identifiers,
|
|
439
|
+
node: child,
|
|
440
|
+
index: i,
|
|
441
|
+
indexRight: children.length - 1 - i,
|
|
442
|
+
};
|
|
385
443
|
}
|
|
386
444
|
}
|
|
387
445
|
function resolvePath(path, ctx, options = {}) {
|
|
@@ -391,43 +449,84 @@ function identifierToUri(module, ctx) {
|
|
|
391
449
|
return ctx.symbols.global.mcdoc?.[module]?.definition?.[0]?.uri;
|
|
392
450
|
}
|
|
393
451
|
function uriToIdentifier(uri, ctx) {
|
|
394
|
-
return Object
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
})
|
|
399
|
-
?.identifier;
|
|
452
|
+
return Object.values(ctx.symbols.global.mcdoc ?? {}).find((symbol) => {
|
|
453
|
+
return (symbol.subcategory === 'module' &&
|
|
454
|
+
symbol.definition?.some((loc) => loc.uri === uri));
|
|
455
|
+
})?.identifier;
|
|
400
456
|
}
|
|
401
457
|
function pathArrayToString(path) {
|
|
402
458
|
return path ? `::${path.join('::')}` : undefined;
|
|
403
459
|
}
|
|
404
460
|
function convertType(node, ctx) {
|
|
405
461
|
switch (node.type) {
|
|
406
|
-
case 'mcdoc:enum':
|
|
407
|
-
|
|
408
|
-
case 'mcdoc:
|
|
409
|
-
|
|
410
|
-
case 'mcdoc:type/
|
|
411
|
-
|
|
412
|
-
case 'mcdoc:type/
|
|
413
|
-
|
|
414
|
-
case 'mcdoc:type/
|
|
415
|
-
|
|
416
|
-
case 'mcdoc:type/
|
|
417
|
-
|
|
418
|
-
case 'mcdoc:type/
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
462
|
+
case 'mcdoc:enum':
|
|
463
|
+
return convertEnum(node, ctx);
|
|
464
|
+
case 'mcdoc:struct':
|
|
465
|
+
return convertStruct(node, ctx);
|
|
466
|
+
case 'mcdoc:type/any':
|
|
467
|
+
return convertAny(node, ctx);
|
|
468
|
+
case 'mcdoc:type/boolean':
|
|
469
|
+
return convertBoolean(node, ctx);
|
|
470
|
+
case 'mcdoc:type/dispatcher':
|
|
471
|
+
return convertDispatcher(node, ctx);
|
|
472
|
+
case 'mcdoc:type/list':
|
|
473
|
+
return convertList(node, ctx);
|
|
474
|
+
case 'mcdoc:type/literal':
|
|
475
|
+
return convertLiteral(node, ctx);
|
|
476
|
+
case 'mcdoc:type/numeric_type':
|
|
477
|
+
return convertNumericType(node, ctx);
|
|
478
|
+
case 'mcdoc:type/primitive_array':
|
|
479
|
+
return convertPrimitiveArray(node, ctx);
|
|
480
|
+
case 'mcdoc:type/string':
|
|
481
|
+
return convertString(node, ctx);
|
|
482
|
+
case 'mcdoc:type/reference':
|
|
483
|
+
return convertReference(node, ctx);
|
|
484
|
+
case 'mcdoc:type/tuple':
|
|
485
|
+
return convertTuple(node, ctx);
|
|
486
|
+
case 'mcdoc:type/union':
|
|
487
|
+
return convertUnion(node, ctx);
|
|
488
|
+
default:
|
|
489
|
+
return Dev.assertNever(node);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function wrapType(node, type, ctx, options = {}) {
|
|
493
|
+
const { attributes, appendixes } = TypeBaseNode.destruct(node);
|
|
494
|
+
let ans = type;
|
|
495
|
+
for (const appendix of appendixes) {
|
|
496
|
+
if (IndexBodyNode.is(appendix)) {
|
|
497
|
+
if (options.skipFirstIndexBody) {
|
|
498
|
+
options.skipFirstIndexBody = false;
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
ans = {
|
|
502
|
+
kind: 'indexed',
|
|
503
|
+
child: ans,
|
|
504
|
+
parallelIndices: convertIndexBody(appendix, ctx),
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
ans = {
|
|
509
|
+
kind: 'concrete',
|
|
510
|
+
child: ans,
|
|
511
|
+
typeArgs: convertTypeArgBlock(appendix, ctx),
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
ans = attributeType(ans, attributes, ctx);
|
|
516
|
+
return ans;
|
|
517
|
+
}
|
|
518
|
+
function attributeType(type, attributes, ctx) {
|
|
519
|
+
for (const attribute of attributes) {
|
|
520
|
+
type = {
|
|
521
|
+
kind: 'attributed',
|
|
522
|
+
attribute: convertAttribute(attribute, ctx),
|
|
523
|
+
child: type,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
return type;
|
|
428
527
|
}
|
|
429
528
|
function convertAttributes(nodes, ctx) {
|
|
430
|
-
return undefineEmptyArray(nodes.map(n => convertAttribute(n, ctx)));
|
|
529
|
+
return undefineEmptyArray(nodes.map((n) => convertAttribute(n, ctx)));
|
|
431
530
|
}
|
|
432
531
|
function undefineEmptyArray(array) {
|
|
433
532
|
return array.length ? array : undefined;
|
|
@@ -468,11 +567,11 @@ function convertAttributeTree(node, ctx) {
|
|
|
468
567
|
return ans;
|
|
469
568
|
}
|
|
470
569
|
function convertIndexBodies(nodes, ctx) {
|
|
471
|
-
return undefineEmptyArray(nodes.map(n => convertIndexBody(n, ctx)));
|
|
570
|
+
return undefineEmptyArray(nodes.map((n) => convertIndexBody(n, ctx)));
|
|
472
571
|
}
|
|
473
572
|
function convertIndexBody(node, ctx) {
|
|
474
573
|
const { parallelIndices } = IndexBodyNode.destruct(node);
|
|
475
|
-
return parallelIndices.map(n => convertIndex(n, ctx));
|
|
574
|
+
return parallelIndices.map((n) => convertIndex(n, ctx));
|
|
476
575
|
}
|
|
477
576
|
function convertIndex(node, ctx) {
|
|
478
577
|
return StaticIndexNode.is(node)
|
|
@@ -492,23 +591,28 @@ function convertDynamicIndex(node, ctx) {
|
|
|
492
591
|
accessor: keys.map(asString),
|
|
493
592
|
};
|
|
494
593
|
}
|
|
594
|
+
function convertTypeArgBlock(node, ctx) {
|
|
595
|
+
const { args } = TypeArgBlockNode.destruct(node);
|
|
596
|
+
return args.map((a) => convertType(a, ctx));
|
|
597
|
+
}
|
|
495
598
|
function convertEnum(node, ctx) {
|
|
496
599
|
const { block, enumKind, identifier } = EnumNode.destruct(node);
|
|
497
600
|
// Shortcut if the typeDef has been added to the enum symbol.
|
|
498
601
|
const symbol = identifier?.symbol ?? node.symbol;
|
|
499
|
-
if (symbol &&
|
|
602
|
+
if (symbol &&
|
|
603
|
+
TypeDefSymbolData.is(symbol.data) &&
|
|
604
|
+
symbol.data.typeDef.kind === 'enum') {
|
|
500
605
|
return symbol.data.typeDef;
|
|
501
606
|
}
|
|
502
|
-
return {
|
|
503
|
-
...convertBase(node, ctx),
|
|
607
|
+
return wrapType(node, {
|
|
504
608
|
kind: 'enum',
|
|
505
609
|
enumKind,
|
|
506
610
|
values: convertEnumBlock(block, ctx),
|
|
507
|
-
};
|
|
611
|
+
}, ctx);
|
|
508
612
|
}
|
|
509
613
|
function convertEnumBlock(node, ctx) {
|
|
510
614
|
const { fields } = EnumBlockNode.destruct(node);
|
|
511
|
-
return fields.map(n => convertEnumField(n, ctx));
|
|
615
|
+
return fields.map((n) => convertEnumField(n, ctx));
|
|
512
616
|
}
|
|
513
617
|
function convertEnumField(node, ctx) {
|
|
514
618
|
const { attributes, identifier, value } = EnumFieldNode.destruct(node);
|
|
@@ -529,18 +633,19 @@ function convertStruct(node, ctx) {
|
|
|
529
633
|
const { block, identifier } = StructNode.destruct(node);
|
|
530
634
|
// Shortcut if the typeDef has been added to the struct symbol.
|
|
531
635
|
const symbol = identifier?.symbol ?? node.symbol;
|
|
532
|
-
if (symbol &&
|
|
636
|
+
if (symbol &&
|
|
637
|
+
TypeDefSymbolData.is(symbol.data) &&
|
|
638
|
+
symbol.data.typeDef.kind === 'struct') {
|
|
533
639
|
return symbol.data.typeDef;
|
|
534
640
|
}
|
|
535
|
-
return {
|
|
536
|
-
...convertBase(node, ctx),
|
|
641
|
+
return wrapType(node, {
|
|
537
642
|
kind: 'struct',
|
|
538
643
|
fields: convertStructBlock(block, ctx),
|
|
539
|
-
};
|
|
644
|
+
}, ctx);
|
|
540
645
|
}
|
|
541
646
|
function convertStructBlock(node, ctx) {
|
|
542
647
|
const { fields } = StructBlockNode.destruct(node);
|
|
543
|
-
return fields.map(n => convertStructField(n, ctx));
|
|
648
|
+
return fields.map((n) => convertStructField(n, ctx));
|
|
544
649
|
}
|
|
545
650
|
function convertStructField(node, ctx) {
|
|
546
651
|
return StructPairFieldNode.is(node)
|
|
@@ -575,51 +680,46 @@ function convertStructSpreadField(node, ctx) {
|
|
|
575
680
|
};
|
|
576
681
|
}
|
|
577
682
|
function convertAny(node, ctx) {
|
|
578
|
-
return {
|
|
579
|
-
...convertBase(node, ctx),
|
|
683
|
+
return wrapType(node, {
|
|
580
684
|
kind: 'any',
|
|
581
|
-
};
|
|
685
|
+
}, ctx);
|
|
582
686
|
}
|
|
583
687
|
function convertBoolean(node, ctx) {
|
|
584
|
-
return {
|
|
585
|
-
...convertBase(node, ctx),
|
|
688
|
+
return wrapType(node, {
|
|
586
689
|
kind: 'boolean',
|
|
587
|
-
};
|
|
690
|
+
}, ctx);
|
|
588
691
|
}
|
|
589
692
|
function convertDispatcher(node, ctx) {
|
|
590
693
|
const { index, location } = DispatcherTypeNode.destruct(node);
|
|
591
|
-
return {
|
|
592
|
-
...convertBase(node, ctx, {
|
|
593
|
-
skipFirstIndexBody: true,
|
|
594
|
-
}),
|
|
694
|
+
return wrapType(node, {
|
|
595
695
|
kind: 'dispatcher',
|
|
596
|
-
|
|
696
|
+
parallelIndices: convertIndexBody(index, ctx),
|
|
597
697
|
registry: ResourceLocationNode.toString(location, 'full'),
|
|
598
|
-
};
|
|
698
|
+
}, ctx, { skipFirstIndexBody: true });
|
|
599
699
|
}
|
|
600
700
|
function convertList(node, ctx) {
|
|
601
701
|
const { item, lengthRange } = ListTypeNode.destruct(node);
|
|
602
|
-
return {
|
|
603
|
-
...convertBase(node, ctx),
|
|
702
|
+
return wrapType(node, {
|
|
604
703
|
kind: 'list',
|
|
605
704
|
item: convertType(item, ctx),
|
|
606
705
|
lengthRange: convertRange(lengthRange, ctx),
|
|
607
|
-
};
|
|
706
|
+
}, ctx);
|
|
608
707
|
}
|
|
609
708
|
function convertRange(node, ctx) {
|
|
610
709
|
if (!node) {
|
|
611
710
|
return undefined;
|
|
612
711
|
}
|
|
613
|
-
const { kind, min, max } = FloatRangeNode.is(node)
|
|
712
|
+
const { kind, min, max } = FloatRangeNode.is(node)
|
|
713
|
+
? FloatRangeNode.destruct(node)
|
|
714
|
+
: IntRangeNode.destruct(node);
|
|
614
715
|
return { kind, min: min?.value, max: max?.value };
|
|
615
716
|
}
|
|
616
717
|
function convertLiteral(node, ctx) {
|
|
617
718
|
const { value } = LiteralTypeNode.destruct(node);
|
|
618
|
-
return {
|
|
619
|
-
...convertBase(node, ctx),
|
|
719
|
+
return wrapType(node, {
|
|
620
720
|
kind: 'literal',
|
|
621
721
|
value: convertLiteralValue(value, ctx),
|
|
622
|
-
};
|
|
722
|
+
}, ctx);
|
|
623
723
|
}
|
|
624
724
|
function convertLiteralValue(node, ctx) {
|
|
625
725
|
if (LiteralNode.is(node)) {
|
|
@@ -649,53 +749,46 @@ function convertLiteralNumberSuffix(node, ctx) {
|
|
|
649
749
|
}
|
|
650
750
|
function convertNumericType(node, ctx) {
|
|
651
751
|
const { numericKind, valueRange } = NumericTypeNode.destruct(node);
|
|
652
|
-
return {
|
|
653
|
-
...convertBase(node, ctx),
|
|
752
|
+
return wrapType(node, {
|
|
654
753
|
kind: numericKind.value,
|
|
655
754
|
valueRange: convertRange(valueRange, ctx),
|
|
656
|
-
};
|
|
755
|
+
}, ctx);
|
|
657
756
|
}
|
|
658
757
|
function convertPrimitiveArray(node, ctx) {
|
|
659
758
|
const { arrayKind, lengthRange, valueRange } = PrimitiveArrayTypeNode.destruct(node);
|
|
660
|
-
return {
|
|
661
|
-
...convertBase(node, ctx),
|
|
759
|
+
return wrapType(node, {
|
|
662
760
|
kind: `${arrayKind.value}_array`,
|
|
663
761
|
lengthRange: convertRange(lengthRange, ctx),
|
|
664
762
|
valueRange: convertRange(valueRange, ctx),
|
|
665
|
-
};
|
|
763
|
+
}, ctx);
|
|
666
764
|
}
|
|
667
765
|
function convertString(node, ctx) {
|
|
668
766
|
const { lengthRange } = StringTypeNode.destruct(node);
|
|
669
|
-
return {
|
|
670
|
-
...convertBase(node, ctx),
|
|
767
|
+
return wrapType(node, {
|
|
671
768
|
kind: 'string',
|
|
672
769
|
lengthRange: convertRange(lengthRange, ctx),
|
|
673
|
-
};
|
|
770
|
+
}, ctx);
|
|
674
771
|
}
|
|
675
772
|
function convertReference(node, ctx) {
|
|
676
|
-
const { path
|
|
677
|
-
return {
|
|
678
|
-
...convertBase(node, ctx),
|
|
773
|
+
const { path } = ReferenceTypeNode.destruct(node);
|
|
774
|
+
return wrapType(node, {
|
|
679
775
|
kind: 'reference',
|
|
680
776
|
path: pathArrayToString(resolvePath(path, ctx)),
|
|
681
|
-
|
|
682
|
-
};
|
|
777
|
+
}, ctx);
|
|
683
778
|
}
|
|
684
779
|
function convertTuple(node, ctx) {
|
|
685
780
|
const { items } = TupleTypeNode.destruct(node);
|
|
686
|
-
return {
|
|
687
|
-
...convertBase(node, ctx),
|
|
781
|
+
return wrapType(node, {
|
|
688
782
|
kind: 'tuple',
|
|
689
|
-
items: items.map(n => convertType(n, ctx)),
|
|
690
|
-
};
|
|
783
|
+
items: items.map((n) => convertType(n, ctx)),
|
|
784
|
+
}, ctx);
|
|
691
785
|
}
|
|
692
786
|
function convertUnion(node, ctx) {
|
|
693
787
|
const { members } = UnionTypeNode.destruct(node);
|
|
694
|
-
return {
|
|
695
|
-
...convertBase(node, ctx),
|
|
788
|
+
return wrapType(node, {
|
|
696
789
|
kind: 'union',
|
|
697
|
-
members: members.map(n => convertType(n, ctx)),
|
|
698
|
-
};
|
|
790
|
+
members: members.map((n) => convertType(n, ctx)),
|
|
791
|
+
}, ctx);
|
|
699
792
|
}
|
|
700
793
|
function asString(node) {
|
|
701
794
|
if (ResourceLocationNode.is(node)) {
|