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
4 changes: 3 additions & 1 deletion packages/zenscript/src/builtins/bool.dzs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
zenClass bool
zenClass bool {
operator as() as string
}
4 changes: 3 additions & 1 deletion packages/zenscript/src/builtins/byte.dzs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
zenClass byte
zenClass byte {
operator as() as short, int, long, float, double, string
}
4 changes: 3 additions & 1 deletion packages/zenscript/src/builtins/double.dzs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
zenClass double
zenClass double {
operator as() as byte, short, int, long, float, string
}
4 changes: 3 additions & 1 deletion packages/zenscript/src/builtins/float.dzs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
zenClass float
zenClass float {
operator as() as byte, short, int, long, double, string
}
4 changes: 3 additions & 1 deletion packages/zenscript/src/builtins/int.dzs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
zenClass int
zenClass int {
operator as() as byte, short, long, float, double, string
}
4 changes: 3 additions & 1 deletion packages/zenscript/src/builtins/long.dzs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
zenClass long
zenClass long {
operator as() as byte, short, int, float, double, string
}
4 changes: 3 additions & 1 deletion packages/zenscript/src/builtins/short.dzs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
zenClass short
zenClass short {
operator as() as byte, int, long, float, double, string
}
2 changes: 2 additions & 0 deletions packages/zenscript/src/builtins/string.dzs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,6 @@ zenClass string {
function lastIndexOf(needle as string, fromIndex as int) as int;

function split(separator as string, maximum as int = 0) as [string];

operator as() as bool, byte, int, short, long, float, double
}
30 changes: 27 additions & 3 deletions packages/zenscript/src/lsp/semantic-token-provider.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import type { AstNode, LangiumDocument } from 'langium'
import type { SemanticTokenAcceptor } from 'langium/lsp'
import type { CancellationToken } from 'vscode-languageserver'
import type { ZenScriptAstType } from '../generated/ast'
import type { ZenScriptServices } from '../module'

import type { TypeComputer } from '../typing/type-computer'
import { type AstNode, CstUtils, stream } from 'langium'

import { AstUtils, CstUtils, interruptAndCheck, stream } from 'langium'
import { AbstractSemanticTokenProvider } from 'langium/lsp'
import { SemanticTokenModifiers, SemanticTokenTypes } from 'vscode-languageserver'
import { LSPErrorCodes, ResponseError, SemanticTokenModifiers, SemanticTokenTypes } from 'vscode-languageserver'
import { isLocation } from '../generated/ast'
import { isStringType } from '../typing/type-description'

Expand All @@ -21,7 +25,27 @@ export class ZenScriptSemanticTokenProvider extends AbstractSemanticTokenProvide
this.typeComputer = services.typing.TypeComputer
}

override highlightElement(node: AstNode, acceptor: SemanticTokenAcceptor): void {
protected async computeHighlighting(document: LangiumDocument, acceptor: SemanticTokenAcceptor, cancelToken: CancellationToken): Promise<void> {
const root = document.parseResult.value
const treeIterator = AstUtils.streamAst(root, { range: this.currentRange }).iterator()
let result: IteratorResult<AstNode>
do {
result = treeIterator.next()
if (!result.done) {
const prevState = document.state
await interruptAndCheck(cancelToken)
if (prevState > document.state) {
throw new ResponseError(LSPErrorCodes.ContentModified, 'Document was modified during semantic token computation')
}
const node = result.value
if (this.highlightElement(node, acceptor) === 'prune') {
treeIterator.prune()
}
}
} while (!result.done)
}

override highlightElement(node: AstNode, acceptor: SemanticTokenAcceptor): void | 'prune' {
// @ts-expect-error allowed index type
this.rules[node.$type]?.call(this, node, acceptor)
}
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 @@ -13,6 +13,7 @@ import { ZenScriptMemberProvider } from './reference/member-provider'
import { ZenScriptNameProvider } from './reference/name-provider'
import { ZenScriptScopeComputation } from './reference/scope-computation'
import { ZenScriptScopeProvider } from './reference/scope-provider'
import { ZenScriptOverloadResolver } from './typing/overload-resolver'
import { ZenScriptTypeComputer } from './typing/type-computer'
import { registerValidationChecks, ZenScriptValidator } from './validation/validator'
import { ZenScriptBracketManager } from './workspace/bracket-manager'
Expand All @@ -34,6 +35,7 @@ export interface ZenScriptAddedServices {
}
typing: {
TypeComputer: ZenScriptTypeComputer
OverloadResolver: ZenScriptOverloadResolver
}
workspace: {
PackageManager: ZenScriptPackageManager
Expand Down Expand Up @@ -84,6 +86,7 @@ export const ZenScriptModule: Module<ZenScriptServices, PartialLangiumServices &
},
typing: {
TypeComputer: services => new ZenScriptTypeComputer(services),
OverloadResolver: services => new ZenScriptOverloadResolver(services),
},
lsp: {
CompletionProvider: services => new ZenScriptCompletionProvider(services),
Expand Down
12 changes: 9 additions & 3 deletions packages/zenscript/src/reference/dynamic-provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AstNode, AstNodeDescription } from 'langium'
import type { ZenScriptAstType } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import type { ZenScriptOverloadResolver } from '../typing/overload-resolver'
import type { TypeComputer } from '../typing/type-computer'
import type { DescriptionIndex } from '../workspace/description-index'
import type { MemberProvider } from './member-provider'
Expand All @@ -19,11 +20,13 @@ export class ZenScriptDynamicProvider implements DynamicProvider {
private readonly descriptionIndex: DescriptionIndex
private readonly typeComputer: TypeComputer
private readonly memberProvider: MemberProvider
private readonly overloadResolver: ZenScriptOverloadResolver

constructor(services: ZenScriptServices) {
this.descriptionIndex = services.workspace.DescriptionIndex
this.typeComputer = services.typing.TypeComputer
this.memberProvider = services.references.MemberProvider
this.overloadResolver = services.typing.OverloadResolver
}

getDynamics(source: AstNode): AstNodeDescription[] {
Expand All @@ -44,9 +47,12 @@ export class ZenScriptDynamicProvider implements DynamicProvider {
// dynamic arguments
if (isCallExpression(source.$container) && source.$containerProperty === 'arguments') {
const index = source.$containerIndex!
const receiverType = this.typeComputer.inferType(source.$container.receiver)
if (isFunctionType(receiverType)) {
const paramType = receiverType.paramTypes[index]

// prevent circular ref resolve, manually infer type

const callType = this.overloadResolver.predictCallType(source.$container)
if (isFunctionType(callType)) {
const paramType = callType.paramTypes[index]
if (isClassType(paramType)) {
stream(this.memberProvider.getMembers(paramType.declaration))
.map(it => it.node)
Expand Down
4 changes: 2 additions & 2 deletions packages/zenscript/src/reference/name-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ export class ZenScriptNameProvider extends DefaultNameProvider {
Script: source => source.$document ? getName(source.$document) : undefined,
ImportDeclaration: source => source.alias || source.path.at(-1)?.$refText,
FunctionDeclaration: source => source.name || 'lambda function',
ConstructorDeclaration: _ => 'zenConstructor',
ConstructorDeclaration: source => isClassDeclaration(source.$container) ? source.$container.name : 'constructor',
OperatorFunctionDeclaration: source => source.op,
}

private readonly nameNodeRules: NameNodeRuleMap = {
ImportDeclaration: source => GrammarUtils.findNodeForProperty(source.$cstNode, 'alias'),
ConstructorDeclaration: source => GrammarUtils.findNodeForProperty(source.$cstNode, 'zenConstructor'),
ConstructorDeclaration: source => GrammarUtils.findNodeForKeyword(source.$cstNode, 'zenConstructor'),
OperatorFunctionDeclaration: source => GrammarUtils.findNodeForProperty(source.$cstNode, 'op'),
}
}
Expand Down
52 changes: 47 additions & 5 deletions packages/zenscript/src/reference/scope-provider.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import type { AstNode, AstNodeDescription, ReferenceInfo, Scope } from 'langium'
import type { ZenScriptAstType } from '../generated/ast'
import type { CallExpression, ZenScriptAstType } from '../generated/ast'
import type { ZenScriptServices } from '../module'
import type { ZenScriptOverloadResolver } from '../typing/overload-resolver'
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'
import { substringBeforeLast } from '@intellizen/shared'
import { AstUtils, DefaultScopeProvider, EMPTY_SCOPE, stream } from 'langium'
import { ClassDeclaration, ImportDeclaration, isClassDeclaration, TypeParameter } from '../generated/ast'
import { ClassDeclaration, ImportDeclaration, isCallExpression, isClassDeclaration, isScript, TypeParameter } from '../generated/ast'
import { getPathAsString } from '../utils/ast'
import { generateStream } from '../utils/stream'

Expand All @@ -19,13 +20,15 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
private readonly memberProvider: MemberProvider
private readonly dynamicProvider: DynamicProvider
private readonly descriptionIndex: ZenScriptDescriptionIndex
private readonly overloadResolver: ZenScriptOverloadResolver

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
this.overloadResolver = services.typing.OverloadResolver
}

override getScope(context: ReferenceInfo): Scope {
Expand All @@ -46,6 +49,26 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
.reduce((outer, descriptions) => this.createScope(descriptions, outer), outside as Scope)
}

private importScope(source: ReferenceInfo, outer?: Scope) {
const script = AstUtils.findRootNode(source.container)
if (!isScript(script)) {
return EMPTY_SCOPE
}

const imports = stream(script.imports)
.flatMap(it => this.descriptionIndex.createImportedDescription(it))

if (source.reference.$refText === '' || !isCallExpression(source.container.$container) || source.container.$containerProperty !== 'receiver') {
return this.createScope(imports, outer)
}

const overload = this.overloadResolver.findOverloadMethod(imports, source.container.$container, source.reference.$refText)
if (!overload) {
return outer || EMPTY_SCOPE
}
return this.createScope([overload], outer)
}

private dynamicScope(astNode: AstNode, outside?: Scope) {
return this.createScope(this.dynamicProvider.getDynamics(astNode), outside)
}
Expand Down Expand Up @@ -97,12 +120,22 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
outer = this.globalScope(outer)
outer = this.dynamicScope(source.container, outer)

outer = this.importScope(source, outer)

const processOverload = source.reference.$refText !== '' && isCallExpression(source.container.$container) && source.container.$containerProperty === 'receiver'

const processor = (desc: AstNodeDescription) => {
switch (desc.type) {
case TypeParameter:
return
case ImportDeclaration: {
return this.descriptionIndex.createImportedDescription(desc.node as ImportDeclaration)
return
}
case ClassDeclaration: {
if (processOverload) {
return this.overloadResolver.findOverlaodConstructor(desc.node as ClassDeclaration, source.container.$container as CallExpression)
}
return desc
}
default:
return desc
Expand All @@ -114,7 +147,16 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
MemberAccess: (source) => {
const outer = this.dynamicScope(source.container)
const members = this.memberProvider.getMembers(source.container.receiver)
return this.createScope(members, outer)

if (source.reference.$refText === '' || !isCallExpression(source.container.$container) || source.container.$containerProperty !== 'receiver') {
return this.createScope(members, outer)
}

const overload = this.overloadResolver.findOverloadMethod(members, source.container.$container, source.reference.$refText)
if (!overload) {
return outer
}
return this.createScope([overload], outer)
},

NamedTypeReference: (source) => {
Expand All @@ -126,7 +168,7 @@ export class ZenScriptScopeProvider extends DefaultScopeProvider {
case ClassDeclaration:
return desc
case ImportDeclaration: {
return this.descriptionIndex.createImportedDescription(desc.node as ImportDeclaration)
return this.descriptionIndex.createImportedDescription(desc.node as ImportDeclaration).at(0) || desc
}
}
}
Expand Down
Loading