Skip to content
Open
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
1 change: 1 addition & 0 deletions packages/shared/src/tree/hierarchy-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class HierarchyNode<V> {
readonly parent?: HierarchyNode<V>
readonly children: Map<string, HierarchyNode<V>>
readonly data: Set<V>
syntehticData: V | undefined

constructor(name: string, parent?: HierarchyNode<V>) {
this.name = name
Expand Down
3 changes: 3 additions & 0 deletions packages/zenscript/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ZenScriptScopeProvider } from './reference/scope-provider'
import { ZenScriptTypeComputer } from './typing/type-computer'
import { registerValidationChecks, ZenScriptValidator } from './validation/validator'
import { ZenScriptBracketManager } from './workspace/bracket-manager'
import { ZenScriptClassIndex } from './workspace/class-index'
import { ZenScriptConfigurationManager } from './workspace/configuration-manager'
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
ClassIndex: ZenScriptClassIndex
}
}

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),
ClassIndex: services => new ZenScriptClassIndex(services),
},
parser: {
TokenBuilder: () => new CustomTokenBuilder(),
Expand Down
32 changes: 17 additions & 15 deletions packages/zenscript/src/reference/dynamic-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import type { AstNode, AstNodeDescription, AstNodeDescriptionProvider } from 'la
import type { ZenScriptAstType } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import type { TypeComputer } from '../typing/type-computer'
import type { ZenScriptClassIndex } from '../workspace/class-index'
import type { MemberProvider } from './member-provider'
import { AstUtils, stream } from 'langium'
import { isCallExpression, isClassDeclaration, isFunctionDeclaration, isOperatorFunctionDeclaration } from '../generated/ast'
import { isCallExpression, isClassDeclaration, isFunctionDeclaration } from '../generated/ast'
import { isClassType, isFunctionType } from '../typing/type-description'

export interface DynamicProvider {
Expand All @@ -18,11 +19,13 @@ export class ZenScriptDynamicProvider implements DynamicProvider {
private readonly descriptions: AstNodeDescriptionProvider
private readonly typeComputer: TypeComputer
private readonly memberProvider: MemberProvider
private readonly classIndex: ZenScriptClassIndex

constructor(services: ZenScriptServices) {
this.descriptions = services.workspace.AstNodeDescriptionProvider
this.typeComputer = services.typing.TypeComputer
this.memberProvider = services.references.MemberProvider
this.classIndex = services.workspace.ClassIndex
}

getDynamics(source: AstNode): AstNodeDescription[] {
Expand All @@ -37,7 +40,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.classIndex.get(classDecl).thisSymbol)
}

// dynamic arguments
Expand All @@ -48,11 +51,10 @@ export class ZenScriptDynamicProvider implements DynamicProvider {
const paramType = receiverType.paramTypes[index]
if (isClassType(paramType)) {
stream(this.memberProvider.getMembers(paramType.declaration))
.map(it => it.node)
.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)))
.filter(it => isFunctionDeclaration(it.node)
&& it.node.prefix === 'static'
&& it.node.parameters.length === 0)
.forEach(it => dynamics.push(it))
}
}
}
Expand All @@ -63,14 +65,14 @@ export class ZenScriptDynamicProvider implements DynamicProvider {
MemberAccess: (source) => {
const dynamics: AstNodeDescription[] = []

// dynamic member
const operatorDecl = stream(this.memberProvider.getMembers(source.receiver))
.map(it => it.node)
.filter(it => isOperatorFunctionDeclaration(it))
.filter(it => it.parameters.length === 1)
.find(it => it.op === '.')
if (operatorDecl) {
dynamics.push(this.descriptions.createDescription(operatorDecl.parameters[0], source.target.$refText))
const receiverType = this.typeComputer.inferType(source.receiver)

if (isClassType(receiverType)) {
// dynamic member
const operatorDecl = this.classIndex.findOperators(receiverType.declaration, '.').at(0)
if (operatorDecl) {
dynamics.push(this.descriptions.createDescription(operatorDecl.parameters[0], source.target.$refText))
}
}

return dynamics
Expand Down
54 changes: 32 additions & 22 deletions packages/zenscript/src/reference/member-provider.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,54 @@
import type { AstNode, AstNodeDescription, AstNodeDescriptionProvider } from 'langium'
import type { AstNode, AstNodeDescription, AstNodeDescriptionProvider, Stream } from 'langium'
import type { ZenScriptAstType } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import type { TypeComputer } from '../typing/type-computer'
import type { ZenScriptClassIndex } from '../workspace/class-index'
import type { PackageManager } from '../workspace/package-manager'
import type { ZenScriptSyntheticAstType } from './synthetic'
import { stream } from 'langium'
import { AstUtils, 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 { getPrecomputedDescription } from '../utils/document'
import { isSyntheticAstNode } from './synthetic'

export interface MemberProvider {
getMembers: (source: AstNode | Type | undefined) => AstNodeDescription[]
getMembers: (source: AstNode | Type | undefined) => Stream<AstNodeDescription>
}

type SourceMap = ZenScriptAstType & ZenScriptType & ZenScriptSyntheticAstType
type RuleMap = { [K in keyof SourceMap]?: (source: SourceMap[K]) => AstNodeDescription[] }
type RuleMap = { [K in keyof SourceMap]?: (source: SourceMap[K]) => Stream<AstNodeDescription> }

export class ZenScriptMemberProvider implements MemberProvider {
private readonly descriptions: AstNodeDescriptionProvider
private readonly typeComputer: TypeComputer
private readonly classIndex: ZenScriptClassIndex
private readonly packageManager: PackageManager

constructor(services: ZenScriptServices) {
this.descriptions = services.workspace.AstNodeDescriptionProvider
this.typeComputer = services.typing.TypeComputer
this.classIndex = services.workspace.ClassIndex
this.packageManager = services.workspace.PackageManager
}

getMembers(source: AstNode | Type | undefined): AstNodeDescription[] {
getMembers(source: AstNode | Type | undefined): Stream<AstNodeDescription> {
// @ts-expect-error allowed index type
return this.rules[source?.$type]?.call(this, source) ?? []
return this.rules[source?.$type]?.call(this, source) ?? stream()
}

private readonly rules: RuleMap = {
SyntheticHierarchyNode: (source) => {
const declarations = stream(source.children.values())
.filter(it => it.isDataNode())
.flatMap(it => it.data)
.map(it => this.descriptions.createDescription(it, undefined))
.map((it) => {
const document = AstUtils.getDocument(it)
return getPrecomputedDescription(document, it)
})
const packages = stream(source.children.values())
.filter(it => it.isInternalNode())
.map(it => createSyntheticAstNodeDescription('SyntheticHierarchyNode', it.name, it))
return stream(declarations, packages).toArray()
.map(it => this.packageManager.syntheticDescriptionOf(it))
return stream(declarations, packages)
},

Script: (source) => {
Expand All @@ -49,18 +58,21 @@ 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 stream(members
.map((it) => {
const document = AstUtils.getDocument(it)
return getPrecomputedDescription(document, it)
}))
},

ImportDeclaration: (source) => {
return this.getMembers(source.path.at(-1)?.ref)
},

ClassDeclaration: (source) => {
return getClassChain(source)
.flatMap(it => it.members)
.filter(it => isStatic(it))
.map(it => this.descriptions.createDescription(it, undefined))
const index = this.classIndex.get(source)

return index.streamDescriptions(true)
},

VariableDeclaration: (source) => {
Expand All @@ -81,7 +93,7 @@ export class ZenScriptMemberProvider implements MemberProvider {
MemberAccess: (source) => {
const target = source.target.ref
if (!target) {
return []
return stream()
}

if (isSyntheticAstNode(target)) {
Expand Down Expand Up @@ -120,7 +132,7 @@ export class ZenScriptMemberProvider implements MemberProvider {
if (isAnyType(receiverType)) {
return this.getMembers(receiverType)
}
return []
return stream()
},

BracketExpression: (source) => {
Expand Down Expand Up @@ -159,10 +171,8 @@ export class ZenScriptMemberProvider implements MemberProvider {
},

ClassType: (source) => {
return getClassChain(source.declaration)
.flatMap(it => it.members)
.filter(it => !isStatic(it))
.map(it => this.descriptions.createDescription(it, undefined))
const index = this.classIndex.get(source.declaration)
return index.streamDescriptions(false)
},
}
}
Loading