diff --git a/packages/ide/vscode/package.json b/packages/ide/vscode/package.json index 00efbd79..ac3667af 100644 --- a/packages/ide/vscode/package.json +++ b/packages/ide/vscode/package.json @@ -1,7 +1,7 @@ { "name": "zenstack-v3", "publisher": "zenstack", - "version": "3.0.8", + "version": "3.0.9", "displayName": "ZenStack V3 Language Tools", "description": "VSCode extension for ZenStack (v3) ZModel language", "private": true, diff --git a/packages/language/src/index.ts b/packages/language/src/index.ts index 6b2cb56a..4b578f31 100644 --- a/packages/language/src/index.ts +++ b/packages/language/src/index.ts @@ -70,7 +70,11 @@ export async function loadDocument( // build the document together with standard library, plugin modules, and imported documents await services.shared.workspace.DocumentBuilder.build([stdLib, ...pluginDocs, document, ...importedDocuments], { - validation: true, + validation: { + stopAfterLexingErrors: true, + stopAfterParsingErrors: true, + stopAfterLinkingErrors: true, + }, }); const diagnostics = langiumDocuments.all diff --git a/packages/language/src/zmodel-document-builder.ts b/packages/language/src/zmodel-document-builder.ts index 8e55e267..cddfc80b 100644 --- a/packages/language/src/zmodel-document-builder.ts +++ b/packages/language/src/zmodel-document-builder.ts @@ -1,22 +1,26 @@ -import { DefaultDocumentBuilder, type BuildOptions, type LangiumDocument } from 'langium'; +import { DefaultDocumentBuilder, type LangiumSharedCoreServices } from 'langium'; export class ZModelDocumentBuilder extends DefaultDocumentBuilder { - override buildDocuments(documents: LangiumDocument[], options: BuildOptions, cancelToken: any): Promise { - return super.buildDocuments( - documents, - { - ...options, - validation: - // force overriding validation options - options.validation === false || options.validation === undefined - ? options.validation - : { - stopAfterLexingErrors: true, - stopAfterParsingErrors: true, - stopAfterLinkingErrors: true, - }, - }, - cancelToken, - ); + constructor(services: LangiumSharedCoreServices) { + super(services); + + // override update build options to skip validation when there are + // errors in the previous stages + let validationOptions = this.updateBuildOptions.validation; + const stopFlags = { + stopAfterLinkingErrors: true, + stopAfterLexingErrors: true, + stopAfterParsingErrors: true, + }; + if (validationOptions === true) { + validationOptions = stopFlags; + } else if (typeof validationOptions === 'object') { + validationOptions = { ...validationOptions, ...stopFlags }; + } + + this.updateBuildOptions = { + ...this.updateBuildOptions, + validation: validationOptions, + }; } } diff --git a/packages/language/src/zmodel-linker.ts b/packages/language/src/zmodel-linker.ts index 65a2cb84..9b045283 100644 --- a/packages/language/src/zmodel-linker.ts +++ b/packages/language/src/zmodel-linker.ts @@ -10,8 +10,8 @@ import { type LangiumDocument, type LinkingError, type Reference, + type ReferenceInfo, interruptAndCheck, - isReference, } from 'langium'; import { match } from 'ts-pattern'; import { @@ -94,18 +94,18 @@ export class ZModelLinker extends DefaultLinker { document.state = DocumentState.Linked; } - private linkReference( - container: AstNode, - property: string, - document: LangiumDocument, - extraScopes: ScopeProvider[], - ) { - if (this.resolveFromScopeProviders(container, property, document, extraScopes)) { + private linkReference(refInfo: ReferenceInfo, document: LangiumDocument, extraScopes: ScopeProvider[]) { + const defaultRef = refInfo.reference as DefaultReference; + if (defaultRef._ref) { + // already linked return; } - - const reference: DefaultReference = (container as any)[property]; - this.doLink({ reference, container, property }, document); + if (this.resolveFromScopeProviders(refInfo.reference, document, extraScopes)) { + // resolved from additional scope provider + return; + } + // default linking + this.doLink(refInfo, document); } //#endregion @@ -113,12 +113,10 @@ export class ZModelLinker extends DefaultLinker { //#region Expression type resolving private resolveFromScopeProviders( - node: AstNode, - property: string, + reference: DefaultReference, document: LangiumDocument, providers: ScopeProvider[], ) { - const reference: DefaultReference = (node as any)[property]; for (const provider of providers) { const target = provider(reference.$refText); if (target) { @@ -276,7 +274,7 @@ export class ZModelLinker extends DefaultLinker { } private resolveInvocation(node: InvocationExpr, document: LangiumDocument, extraScopes: ScopeProvider[]) { - this.linkReference(node, 'function', document, extraScopes); + this.linkReference({ reference: node.function, container: node, property: 'function' }, document, extraScopes); node.args.forEach((arg) => this.resolve(arg, document, extraScopes)); if (node.function.ref) { const funcDecl = node.function.ref as FunctionDecl; @@ -401,7 +399,7 @@ export class ZModelLinker extends DefaultLinker { if (isArrayExpr(node.value)) { node.value.items.forEach((item) => { if (isReferenceExpr(item)) { - const resolved = this.resolveFromScopeProviders(item, 'target', document, [scopeProvider]); + const resolved = this.resolveFromScopeProviders(item.target, document, [scopeProvider]); if (resolved) { this.resolveToDeclaredType(item, (resolved as DataField).type); } else { @@ -414,7 +412,7 @@ export class ZModelLinker extends DefaultLinker { this.resolveToBuiltinTypeOrDecl(node.value, node.value.items[0].$resolvedType.decl, true); } } else if (isReferenceExpr(node.value)) { - const resolved = this.resolveFromScopeProviders(node.value, 'target', document, [scopeProvider]); + const resolved = this.resolveFromScopeProviders(node.value.target, document, [scopeProvider]); if (resolved) { this.resolveToDeclaredType(node.value, (resolved as DataField).type); } else { @@ -495,13 +493,9 @@ export class ZModelLinker extends DefaultLinker { } private resolveDefault(node: AstNode, document: LangiumDocument, extraScopes: ScopeProvider[]) { - for (const [property, value] of Object.entries(node)) { - if (!property.startsWith('$')) { - if (isReference(value)) { - this.linkReference(node, property, document, extraScopes); - } - } - } + AstUtils.streamReferences(node).forEach((ref) => { + this.linkReference(ref, document, extraScopes); + }); for (const child of AstUtils.streamContents(node)) { this.resolve(child, document, extraScopes); }