Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/zenscript/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ZenScriptTypeComputer } from './typing/type-computer'
import { registerValidationChecks, ZenScriptValidator } from './validation/validator'
import { ZenScriptBracketManager } from './workspace/bracket-manager'
import { ZenScriptConfigurationManager } from './workspace/configuration-manager'
import { ZenScriptDescriptionIndex } from './workspace/description-index'
import { ZenScriptPackageManager } from './workspace/package-manager'
import { ZenScriptWorkspaceManager } from './workspace/workspace-manager'

Expand All @@ -37,6 +38,7 @@ export interface ZenScriptAddedServices {
workspace: {
PackageManager: ZenScriptPackageManager
BracketManager: ZenScriptBracketManager
DescriptionIndex: ZenScriptDescriptionIndex
}
}

Expand Down Expand Up @@ -74,6 +76,7 @@ export const ZenScriptModule: Module<ZenScriptServices, PartialLangiumServices &
workspace: {
PackageManager: services => new ZenScriptPackageManager(services),
BracketManager: services => new ZenScriptBracketManager(services),
DescriptionIndex: services => new ZenScriptDescriptionIndex(services),
},
parser: {
TokenBuilder: () => new CustomTokenBuilder(),
Expand Down
13 changes: 7 additions & 6 deletions packages/zenscript/src/reference/dynamic-provider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { AstNode, AstNodeDescription, AstNodeDescriptionProvider } from 'langium'
import type { AstNode, AstNodeDescription } from 'langium'
import type { ZenScriptAstType } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import type { TypeComputer } from '../typing/type-computer'
import type { DescriptionIndex } from '../workspace/description-index'
import type { MemberProvider } from './member-provider'
import { AstUtils, stream } from 'langium'
import { isCallExpression, isClassDeclaration, isFunctionDeclaration, isOperatorFunctionDeclaration } from '../generated/ast'
Expand All @@ -15,12 +16,12 @@ type SourceMap = ZenScriptAstType
type RuleMap = { [K in keyof SourceMap]?: (source: SourceMap[K]) => AstNodeDescription[] }

export class ZenScriptDynamicProvider implements DynamicProvider {
private readonly descriptions: AstNodeDescriptionProvider
private readonly descriptionIndex: DescriptionIndex
private readonly typeComputer: TypeComputer
private readonly memberProvider: MemberProvider

constructor(services: ZenScriptServices) {
this.descriptions = services.workspace.AstNodeDescriptionProvider
this.descriptionIndex = services.workspace.DescriptionIndex
this.typeComputer = services.typing.TypeComputer
this.memberProvider = services.references.MemberProvider
}
Expand All @@ -37,7 +38,7 @@ export class ZenScriptDynamicProvider implements DynamicProvider {
// dynamic this
const classDecl = AstUtils.getContainerOfType(source, isClassDeclaration)
if (classDecl) {
dynamics.push(this.descriptions.createDescription(classDecl, 'this'))
dynamics.push(this.descriptionIndex.getThisDescription(classDecl))
}

// dynamic arguments
Expand All @@ -52,7 +53,7 @@ export class ZenScriptDynamicProvider implements DynamicProvider {
.filter(it => isFunctionDeclaration(it))
.filter(it => it.prefix === 'static')
.filter(it => it.parameters.length === 0)
.forEach(it => dynamics.push(this.descriptions.createDescription(it, it.name)))
.forEach(it => dynamics.push(this.descriptionIndex.getDescription(it)))
}
}
}
Expand All @@ -70,7 +71,7 @@ export class ZenScriptDynamicProvider implements DynamicProvider {
.filter(it => it.parameters.length === 1)
.find(it => it.op === '.')
if (operatorDecl) {
dynamics.push(this.descriptions.createDescription(operatorDecl.parameters[0], source.target.$refText))
dynamics.push(this.descriptionIndex.createDynamicDescription(operatorDecl.parameters[0], source.target.$refText))
}

return dynamics
Expand Down
19 changes: 10 additions & 9 deletions packages/zenscript/src/reference/member-provider.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import type { AstNode, AstNodeDescription, AstNodeDescriptionProvider } from 'langium'
import type { AstNode, AstNodeDescription } from 'langium'
import type { ZenScriptAstType } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import type { TypeComputer } from '../typing/type-computer'
import type { DescriptionIndex } from '../workspace/description-index'
import type { ZenScriptSyntheticAstType } from './synthetic'
import { stream } from 'langium'
import { isClassDeclaration, isVariableDeclaration } from '../generated/ast'
import { ClassType, isAnyType, isClassType, isFunctionType, type Type, type ZenScriptType } from '../typing/type-description'
import { getClassChain, isStatic } from '../utils/ast'
import { createSyntheticAstNodeDescription, isSyntheticAstNode } from './synthetic'
import { isSyntheticAstNode } from './synthetic'

export interface MemberProvider {
getMembers: (source: AstNode | Type | undefined) => AstNodeDescription[]
Expand All @@ -17,11 +18,11 @@ type SourceMap = ZenScriptAstType & ZenScriptType & ZenScriptSyntheticAstType
type RuleMap = { [K in keyof SourceMap]?: (source: SourceMap[K]) => AstNodeDescription[] }

export class ZenScriptMemberProvider implements MemberProvider {
private readonly descriptions: AstNodeDescriptionProvider
private readonly descriptionIndex: DescriptionIndex
private readonly typeComputer: TypeComputer

constructor(services: ZenScriptServices) {
this.descriptions = services.workspace.AstNodeDescriptionProvider
this.descriptionIndex = services.workspace.DescriptionIndex
this.typeComputer = services.typing.TypeComputer
}

Expand All @@ -35,10 +36,10 @@ export class ZenScriptMemberProvider implements MemberProvider {
const declarations = stream(source.children.values())
.filter(it => it.isDataNode())
.flatMap(it => it.data)
.map(it => this.descriptions.createDescription(it, undefined))
.map(it => this.descriptionIndex.getDescription(it))
const packages = stream(source.children.values())
.filter(it => it.isInternalNode())
.map(it => createSyntheticAstNodeDescription('SyntheticHierarchyNode', it.name, it))
.map(it => this.descriptionIndex.getPackageDescription(it))
return stream(declarations, packages).toArray()
},

Expand All @@ -49,7 +50,7 @@ export class ZenScriptMemberProvider implements MemberProvider {
source.statements.filter(it => isVariableDeclaration(it))
.filter(it => it.prefix === 'static')
.forEach(it => members.push(it))
return members.map(it => this.descriptions.createDescription(it, undefined))
return members.map(it => this.descriptionIndex.getDescription(it))
},

ImportDeclaration: (source) => {
Expand All @@ -60,7 +61,7 @@ export class ZenScriptMemberProvider implements MemberProvider {
return getClassChain(source)
.flatMap(it => it.members)
.filter(it => isStatic(it))
.map(it => this.descriptions.createDescription(it, undefined))
.map(it => this.descriptionIndex.getDescription(it))
},

VariableDeclaration: (source) => {
Expand Down Expand Up @@ -162,7 +163,7 @@ export class ZenScriptMemberProvider implements MemberProvider {
return getClassChain(source.declaration)
.flatMap(it => it.members)
.filter(it => !isStatic(it))
.map(it => this.descriptions.createDescription(it, undefined))
.map(it => this.descriptionIndex.getDescription(it))
},
}
}
18 changes: 17 additions & 1 deletion packages/zenscript/src/reference/scope-computation.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import type { AstNode, AstNodeDescription, LangiumDocument } from 'langium'
import type { AstNode, AstNodeDescription, LangiumDocument, PrecomputedScopes } from 'langium'
import type { Script } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import type { ZenScriptDescriptionIndex } from '../workspace/description-index'
import { DefaultScopeComputation } from 'langium'
import { isGlobal } from '../utils/ast'

export class ZenScriptScopeComputation extends DefaultScopeComputation {
private readonly descriptionIndex: ZenScriptDescriptionIndex

constructor(services: ZenScriptServices) {
super(services)
this.descriptionIndex = services.workspace.DescriptionIndex
}

protected override exportNode(node: AstNode, exports: AstNodeDescription[], document: LangiumDocument<Script>): void {
if (isGlobal(node)) {
exports.push(this.descriptions.createDescription(node, undefined, document))
}
}

protected override processNode(node: AstNode, document: LangiumDocument, scopes: PrecomputedScopes): void {
const container = node.$container
if (container) {
const name = this.nameProvider.getName(node)
if (name) {
const description = this.descriptions.createDescription(node, name, document)
this.descriptionIndex.astDescriptions.set(node, description)
scopes.add(container, description)
}
}
}
}
20 changes: 9 additions & 11 deletions packages/zenscript/src/reference/scope-provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AstNode, AstNodeDescription, ReferenceInfo, Scope } from 'langium'
import type { ZenScriptAstType } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import type { ZenScriptDescriptionIndex } from '../workspace/description-index'
import type { PackageManager } from '../workspace/package-manager'
import type { DynamicProvider } from './dynamic-provider'
import type { MemberProvider } from './member-provider'
Expand All @@ -9,7 +10,6 @@ import { AstUtils, DefaultScopeProvider, EMPTY_SCOPE, stream } from 'langium'
import { ClassDeclaration, ImportDeclaration, isClassDeclaration, TypeParameter } from '../generated/ast'
import { getPathAsString } from '../utils/ast'
import { generateStream } from '../utils/stream'
import { createSyntheticAstNodeDescription } from './synthetic'

type SourceMap = ZenScriptAstType
type RuleMap = { [K in keyof SourceMap]?: (source: ReferenceInfo & { container: SourceMap[K] }) => Scope }
Expand All @@ -18,12 +18,14 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
private readonly packageManager: PackageManager
private readonly memberProvider: MemberProvider
private readonly dynamicProvider: DynamicProvider
private readonly descriptionIndex: ZenScriptDescriptionIndex

constructor(services: ZenScriptServices) {
super(services)
this.packageManager = services.workspace.PackageManager
this.memberProvider = services.references.MemberProvider
this.dynamicProvider = services.references.DynamicProvider
this.descriptionIndex = services.workspace.DescriptionIndex
}

override getScope(context: ReferenceInfo): Scope {
Expand Down Expand Up @@ -55,7 +57,7 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
private packageScope(outside?: Scope) {
const packages = stream(this.packageManager.root.children.values())
.filter(it => it.isInternalNode())
.map(it => createSyntheticAstNodeDescription('SyntheticHierarchyNode', it.name, it))
.map(it => this.descriptionIndex.getPackageDescription(it))
return this.createScope(packages, outside)
}

Expand All @@ -64,7 +66,7 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
.filter(it => it.isDataNode())
.flatMap(it => it.data)
.filter(isClassDeclaration)
.map(it => this.descriptions.createDescription(it, it.name))
.map(it => this.descriptionIndex.getDescription(it))
return this.createScope(classes, outside)
}

Expand All @@ -80,10 +82,10 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
const elements: AstNodeDescription[] = []
for (const sibling of siblings) {
if (sibling.isDataNode()) {
sibling.data.forEach(it => elements.push(this.descriptions.createDescription(it, sibling.name)))
sibling.data.forEach(it => elements.push(this.descriptionIndex.getDescription(it)))
}
else {
elements.push(createSyntheticAstNodeDescription('SyntheticHierarchyNode', sibling.name, sibling))
elements.push(this.descriptionIndex.getPackageDescription(sibling))
}
}
return this.createScope(elements)
Expand All @@ -100,9 +102,7 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
case TypeParameter:
return
case ImportDeclaration: {
const importDecl = desc.node as ImportDeclaration
const ref = importDecl.path.at(-1)?.ref ?? importDecl
return this.descriptions.createDescription(ref, this.nameProvider.getName(importDecl))
return this.descriptionIndex.createImportedDescription(desc.node as ImportDeclaration)
}
default:
return desc
Expand All @@ -126,9 +126,7 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
case ClassDeclaration:
return desc
case ImportDeclaration: {
const importDecl = desc.node as ImportDeclaration
const ref = importDecl.path.at(-1)?.ref ?? importDecl
return this.descriptions.createDescription(ref, this.nameProvider.getName(importDecl))
return this.descriptionIndex.createImportedDescription(desc.node as ImportDeclaration)
}
}
}
Expand Down
63 changes: 63 additions & 0 deletions packages/zenscript/src/workspace/description-index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { HierarchyNode } from '@intellizen/shared'
import type { AstNode, AstNodeDescription, AstNodeDescriptionProvider, NameProvider } from 'langium'
import type { ClassDeclaration, ImportDeclaration } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import { createSyntheticAstNodeDescription } from '../reference/synthetic'

export interface DescriptionIndex {
getDescription: (astNode: AstNode) => AstNodeDescription
getPackageDescription: (pkgNode: HierarchyNode<AstNode>) => AstNodeDescription
getThisDescription: (classDecl: ClassDeclaration) => AstNodeDescription
createDynamicDescription: (astNode: AstNode, name: string) => AstNodeDescription
createImportedDescription: (importDecl: ImportDeclaration) => AstNodeDescription
}

export class ZenScriptDescriptionIndex implements DescriptionIndex {
private readonly descriptions: AstNodeDescriptionProvider
private readonly nameProvider: NameProvider

readonly astDescriptions: WeakMap<AstNode, AstNodeDescription>
readonly pkgDescriptions: WeakMap<HierarchyNode<AstNode>, AstNodeDescription>
readonly thisDescriptions: WeakMap<ClassDeclaration, AstNodeDescription>

constructor(services: ZenScriptServices) {
this.descriptions = services.workspace.AstNodeDescriptionProvider
this.nameProvider = services.references.NameProvider
this.astDescriptions = new WeakMap()
this.pkgDescriptions = new WeakMap()
this.thisDescriptions = new WeakMap()
}

getDescription(astNode: AstNode): AstNodeDescription {
if (!this.astDescriptions.has(astNode)) {
this.astDescriptions.set(astNode, this.descriptions.createDescription(astNode, undefined))
}
return this.astDescriptions.get(astNode)!
}

getPackageDescription(pkgNode: HierarchyNode<AstNode>): AstNodeDescription {
if (pkgNode.isDataNode()) {
throw new Error(`Expected a package node, but received a data node: ${pkgNode}`)
}
if (!this.pkgDescriptions.has(pkgNode)) {
this.pkgDescriptions.set(pkgNode, createSyntheticAstNodeDescription('SyntheticHierarchyNode', pkgNode.name, pkgNode))
}
return this.pkgDescriptions.get(pkgNode)!
}

getThisDescription(classDecl: ClassDeclaration): AstNodeDescription {
if (!this.thisDescriptions.has(classDecl)) {
this.thisDescriptions.set(classDecl, this.descriptions.createDescription(classDecl, 'this'))
}
return this.thisDescriptions.get(classDecl)!
}

createDynamicDescription(astNode: AstNode, name: string): AstNodeDescription {
return this.descriptions.createDescription(astNode, name)
}

createImportedDescription(importDecl: ImportDeclaration): AstNodeDescription {
const ref = importDecl.path.at(-1)?.ref ?? importDecl
return this.descriptions.createDescription(ref, this.nameProvider.getName(importDecl))
}
}