Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
54ee4d2
refactor(semantic): make mutable classes non-data
mjossdev May 20, 2023
f804758
feat(semantic): process annotations
mjossdev May 20, 2023
470559b
feat(semantic): allow deprecation messages
mjossdev May 20, 2023
a1883e5
test(semantic): test AnnotationProcessor
mjossdev May 20, 2023
6d38de8
refactor(annotations): add interfaces for nodes/types which support a…
mjossdev May 20, 2023
8f0942b
feat(annotations): add duplicate annotation check
mjossdev May 20, 2023
eec07d1
feat(ls): support deprecations in semantic tokens
mjossdev May 21, 2023
a5629c1
feat(ls): add semantic highlighting to namespaces
mjossdev May 21, 2023
cf95ab9
feat(ls): display description on hover
mjossdev May 21, 2023
710cd67
refactor(ls): pass userMetadata by constructor
mjossdev May 22, 2023
e81e670
refactor(parser): change sealed classes to sealed interfaces
mjossdev May 22, 2023
8dbc7da
refactor(semantic): let Annotated extend UserDeclared
mjossdev May 22, 2023
8004155
feat(semantic): specify allowed annotations in unknown annotation err…
mjossdev May 22, 2023
118d271
style(semantic): add convenience property for accessing annotations
mjossdev May 22, 2023
d9b3d15
refactor(ls): rename samtPackage parameter to filePackage for clarity
mjossdev May 22, 2023
0d6f18a
feat(ls): show code excerpt on hover
mjossdev May 22, 2023
3f16738
test(ls): test semantic highlighting of fully qualified names
mjossdev May 22, 2023
6f328f0
style(ls): return null instead of empty hover object
mjossdev May 22, 2023
a044846
fix(ls): fix broken markdown
mjossdev May 22, 2023
931ebae
fix(ls): show async keyword on hover
mjossdev May 24, 2023
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
6 changes: 3 additions & 3 deletions cli/src/main/kotlin/tools/samt/cli/CliCompiler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import tools.samt.common.DiagnosticController
import tools.samt.common.DiagnosticException
import tools.samt.lexer.Lexer
import tools.samt.parser.Parser
import tools.samt.semantic.SemanticModelBuilder
import tools.samt.semantic.SemanticModel

internal fun compile(command: CompileCommand, controller: DiagnosticController) {
val sourceFiles = command.files.readSamtSourceFiles(controller)
Expand Down Expand Up @@ -40,7 +40,7 @@ internal fun compile(command: CompileCommand, controller: DiagnosticController)
}

// build up the semantic model from the AST
SemanticModelBuilder.build(fileNodes, controller)
SemanticModel.build(fileNodes, controller)

// Code Generators will be called here
}
}
4 changes: 2 additions & 2 deletions cli/src/main/kotlin/tools/samt/cli/CliDumper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import tools.samt.common.DiagnosticController
import tools.samt.common.DiagnosticException
import tools.samt.lexer.Lexer
import tools.samt.parser.Parser
import tools.samt.semantic.SemanticModelBuilder
import tools.samt.semantic.SemanticModel

internal fun dump(command: DumpCommand, terminal: Terminal, controller: DiagnosticController) {
val sourceFiles = command.files.readSamtSourceFiles(controller)
Expand Down Expand Up @@ -61,7 +61,7 @@ internal fun dump(command: DumpCommand, terminal: Terminal, controller: Diagnost
}

// build up the semantic model from the AST
val samtPackage = SemanticModelBuilder.build(fileNodes, controller)
val samtPackage = SemanticModel.build(fileNodes, controller).global

if (dumpAll || command.dumpTypes) {
terminal.println(TypePrinter.dump(samtPackage))
Expand Down
4 changes: 2 additions & 2 deletions cli/src/test/kotlin/tools/samt/cli/TypePrinterTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import tools.samt.common.SourceFile
import tools.samt.lexer.Lexer
import tools.samt.parser.FileNode
import tools.samt.parser.Parser
import tools.samt.semantic.SemanticModelBuilder
import tools.samt.semantic.SemanticModel
import java.net.URI
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -47,7 +47,7 @@ class TypePrinterTest {
""".trimIndent())

val controller = DiagnosticController(URI("file:///tmp"))
val samtPackage = SemanticModelBuilder.build(listOf(stuffPackage, consumerPackage), controller)
val samtPackage = SemanticModel.build(listOf(stuffPackage, consumerPackage), controller).global
assertFalse(controller.hasErrors())

val dump = TypePrinter.dump(samtPackage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import tools.samt.parser.FileNode
import tools.samt.parser.IdentifierNode
import tools.samt.semantic.*

class SamtDeclarationLookup private constructor() : SamtSemanticLookup<Location, UserDeclared>() {
class SamtDeclarationLookup private constructor(userMetadata: UserMetadata) : SamtSemanticLookup<Location, UserDeclared>(userMetadata) {
override fun markType(node: ExpressionNode, type: Type) {
super.markType(node, type)

Expand Down Expand Up @@ -56,7 +56,7 @@ class SamtDeclarationLookup private constructor() : SamtSemanticLookup<Location,
}

companion object {
fun analyze(fileNode: FileNode, samtPackage: Package) =
SamtDeclarationLookup().also { it.analyze(fileNode, samtPackage) }
fun analyze(fileNode: FileNode, filePackage: Package, userMetadata: UserMetadata) =
SamtDeclarationLookup(userMetadata).also { it.analyze(fileNode, filePackage) }
}
}
7 changes: 3 additions & 4 deletions language-server/src/main/kotlin/tools/samt/ls/SamtFolder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import tools.samt.common.DiagnosticController
import tools.samt.common.DiagnosticMessage
import tools.samt.common.collectSamtFiles
import tools.samt.common.readSamtSource
import tools.samt.semantic.Package
import tools.samt.semantic.SemanticModelBuilder
import tools.samt.semantic.SemanticModel
import java.net.URI

class SamtFolder(val path: URI) : Iterable<FileInfo> {
private val files = mutableMapOf<URI, FileInfo>()
var globalPackage: Package? = null
var semanticModel: SemanticModel? = null
private set
private var semanticController: DiagnosticController = DiagnosticController(path)

Expand All @@ -34,7 +33,7 @@ class SamtFolder(val path: URI) : Iterable<FileInfo> {

fun buildSemanticModel() {
semanticController = DiagnosticController(path)
globalPackage = SemanticModelBuilder.build(mapNotNull { it.fileNode }, semanticController)
semanticModel = SemanticModel.build(mapNotNull { it.fileNode }, semanticController)
}

private fun getMessages(path: URI): List<DiagnosticMessage> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class SamtLanguageServer : LanguageServer, LanguageClientAware, Closeable {
}
definitionProvider = Either.forLeft(true)
referencesProvider = Either.forLeft(true)
hoverProvider = Either.forLeft(true)
}
InitializeResult(capabilities)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ import tools.samt.parser.BundleIdentifierNode
import tools.samt.parser.ExpressionNode
import tools.samt.parser.FileNode
import tools.samt.parser.IdentifierNode
import tools.samt.semantic.Package
import tools.samt.semantic.ServiceType
import tools.samt.semantic.Type
import tools.samt.semantic.UserDeclared
import tools.samt.semantic.*

class SamtReferencesLookup private constructor() : SamtSemanticLookup<UserDeclared, List<Location>>() {
class SamtReferencesLookup private constructor(userMetadata: UserMetadata) : SamtSemanticLookup<UserDeclared, List<Location>>(userMetadata) {
private fun addUsage(declaration: UserDeclared, usage: Location) {
if (this[declaration] == null) {
this[declaration] = mutableListOf()
Expand All @@ -36,10 +33,10 @@ class SamtReferencesLookup private constructor() : SamtSemanticLookup<UserDeclar
}

companion object {
fun analyze(filesAndPackages: List<Pair<FileNode, Package>>): SamtReferencesLookup {
val lookup = SamtReferencesLookup()
for ((fileInfo, samtPackage) in filesAndPackages) {
lookup.analyze(fileInfo, samtPackage)
fun analyze(filesAndPackages: List<Pair<FileNode, Package>>, userMetadata: UserMetadata): SamtReferencesLookup {
val lookup = SamtReferencesLookup(userMetadata)
for ((fileInfo, filePackage) in filesAndPackages) {
lookup.analyze(fileInfo, filePackage)
}
return lookup
}
Expand Down
24 changes: 12 additions & 12 deletions language-server/src/main/kotlin/tools/samt/ls/SamtSemanticLookup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ package tools.samt.ls
import tools.samt.parser.*
import tools.samt.semantic.*

abstract class SamtSemanticLookup<TKey, TValue> protected constructor() {
protected fun analyze(fileNode: FileNode, samtPackage: Package) {
abstract class SamtSemanticLookup<TKey, TValue> protected constructor(protected val userMetadata: UserMetadata) {
protected fun analyze(fileNode: FileNode, filePackage: Package) {
for (import in fileNode.imports) {
markStatement(samtPackage, import)
markStatement(filePackage, import)
}
markStatement(samtPackage, fileNode.packageDeclaration)
markStatement(filePackage, fileNode.packageDeclaration)
for (statement in fileNode.statements) {
markStatement(samtPackage, statement)
markStatement(filePackage, statement)
}
}

Expand Down Expand Up @@ -69,19 +69,19 @@ abstract class SamtSemanticLookup<TKey, TValue> protected constructor() {
}

protected open fun markTypeAliasDeclaration(aliasType: AliasType) {
markAnnotations(aliasType.declaration.annotations)
markAnnotations(aliasType.annotations)
markTypeReference(aliasType.aliasedType)
}

protected open fun markServiceDeclaration(serviceType: ServiceType) {
markAnnotations(serviceType.declaration.annotations)
markAnnotations(serviceType.annotations)
for (operation in serviceType.operations) {
markOperationDeclaration(operation)
}
}

protected open fun markOperationDeclaration(operation: ServiceType.Operation) {
markAnnotations(operation.declaration.annotations)
markAnnotations(operation.annotations)
for (parameter in operation.parameters) {
markOperationParameterDeclaration(parameter)
}
Expand All @@ -95,24 +95,24 @@ abstract class SamtSemanticLookup<TKey, TValue> protected constructor() {
}

protected open fun markOperationParameterDeclaration(parameter: ServiceType.Operation.Parameter) {
markAnnotations(parameter.declaration.annotations)
markAnnotations(parameter.annotations)
markTypeReference(parameter.type)
}

protected open fun markRecordDeclaration(recordType: RecordType) {
markAnnotations(recordType.declaration.annotations)
markAnnotations(recordType.annotations)
for (field in recordType.fields) {
markRecordFieldDeclaration(field)
}
}

protected open fun markRecordFieldDeclaration(field: RecordType.Field) {
markAnnotations(field.declaration.annotations)
markAnnotations(field.annotations)
markTypeReference(field.type)
}

protected open fun markEnumDeclaration(enumType: EnumType) {
markAnnotations(enumType.declaration.annotations)
markAnnotations(enumType.annotations)
}

protected open fun markProviderDeclaration(providerType: ProviderType) {
Expand Down
92 changes: 59 additions & 33 deletions language-server/src/main/kotlin/tools/samt/ls/SamtSemanticTokens.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,43 @@ import tools.samt.common.Location
import tools.samt.parser.*
import tools.samt.semantic.*

class SamtSemanticTokens private constructor() : SamtSemanticLookup<Location, SamtSemanticTokens.Metadata>() {
class SamtSemanticTokens private constructor(userMetadata: UserMetadata) : SamtSemanticLookup<Location, SamtSemanticTokens.Metadata>(userMetadata) {
override fun markType(node: ExpressionNode, type: Type) {
super.markType(node, type)
val location = if (node is BundleIdentifierNode) {
node.components.last().location
val location: Location
if (node is BundleIdentifierNode) {
location = node.components.last().location
node.components.dropLast(1).forEach {
this[it.location] = Metadata(TokenType.namespace)
}
} else {
node.location
location = node.location
}
val modifier = (type as? UserDeclared)?.getDeprecationModifier() ?: TokenModifier.none
when (type) {
is ConsumerType -> this[location] = Metadata(TokenType.type)
is ConsumerType -> this[location] = Metadata(TokenType.type, modifier)

is EnumType -> this[location] = Metadata(TokenType.enum)
is EnumType -> this[location] = Metadata(TokenType.enum, modifier)

is ListType -> {
this[type.node.base.location] =
Metadata(TokenType.type, TokenModifier.defaultLibrary)
Metadata(TokenType.type, modifier and TokenModifier.defaultLibrary)
}

is MapType -> {
this[type.node.base.location] =
Metadata(TokenType.type, TokenModifier.defaultLibrary)
Metadata(TokenType.type, modifier and TokenModifier.defaultLibrary)
}

is AliasType -> this[location] = Metadata(TokenType.type)
is ProviderType -> this[location] = Metadata(TokenType.type)
is RecordType -> this[location] = Metadata(TokenType.`class`)
is ServiceType -> this[location] = Metadata(TokenType.`interface`)
is AliasType -> this[location] = Metadata(getAliasTokenType(type), modifier)
is ProviderType -> this[location] = Metadata(TokenType.type, modifier)
is RecordType -> this[location] = Metadata(TokenType.`class`, modifier)
is ServiceType -> this[location] = Metadata(TokenType.`interface`, modifier)
is LiteralType -> this[location] =
Metadata(TokenType.type, TokenModifier.defaultLibrary)
Metadata(TokenType.type, modifier and TokenModifier.defaultLibrary)

is PackageType -> this[location] = Metadata(TokenType.namespace)
UnknownType -> this[location] = Metadata(TokenType.type)
is PackageType -> this[location] = Metadata(TokenType.namespace, modifier)
UnknownType -> this[location] = Metadata(TokenType.type, modifier)
}
}

Expand All @@ -56,39 +61,39 @@ class SamtSemanticTokens private constructor() : SamtSemanticLookup<Location, Sa

override fun markServiceDeclaration(serviceType: ServiceType) {
super.markServiceDeclaration(serviceType)
this[serviceType.declaration.name.location] = Metadata(TokenType.`interface`, TokenModifier.declaration)
this[serviceType.declaration.name.location] = Metadata(TokenType.`interface`, serviceType.getDeprecationModifier() and TokenModifier.declaration)
}

override fun markOperationDeclaration(operation: ServiceType.Operation) {
super.markOperationDeclaration(operation)
var modifier = TokenModifier.declaration and operation.getDeprecationModifier()
if (operation is ServiceType.RequestResponseOperation && operation.isAsync) {
modifier = modifier and TokenModifier.async
}
this[operation.declaration.name.location] = Metadata(
type = TokenType.method,
modifier = if (operation is ServiceType.RequestResponseOperation && operation.isAsync) {
TokenModifier.declaration and TokenModifier.async
} else {
TokenModifier.declaration
}
modifier = modifier
)
}

override fun markOperationParameterDeclaration(parameter: ServiceType.Operation.Parameter) {
super.markOperationParameterDeclaration(parameter)
this[parameter.declaration.name.location] = Metadata(TokenType.parameter, TokenModifier.declaration)
this[parameter.declaration.name.location] = Metadata(TokenType.parameter, parameter.getDeprecationModifier() and TokenModifier.declaration)
}

override fun markRecordDeclaration(recordType: RecordType) {
super.markRecordDeclaration(recordType)
this[recordType.declaration.name.location] = Metadata(TokenType.`class`, TokenModifier.declaration)
this[recordType.declaration.name.location] = Metadata(TokenType.`class`, recordType.getDeprecationModifier() and TokenModifier.declaration)
}

override fun markRecordFieldDeclaration(field: RecordType.Field) {
super.markRecordFieldDeclaration(field)
this[field.declaration.name.location] = Metadata(TokenType.property, TokenModifier.declaration)
this[field.declaration.name.location] = Metadata(TokenType.property, field.getDeprecationModifier() and TokenModifier.declaration)
}

override fun markEnumDeclaration(enumType: EnumType) {
super.markEnumDeclaration(enumType)
this[enumType.declaration.name.location] = Metadata(TokenType.enum, TokenModifier.declaration)
this[enumType.declaration.name.location] = Metadata(TokenType.enum, enumType.getDeprecationModifier() and TokenModifier.declaration)
for (enumMember in enumType.declaration.values) {
this[enumMember.location] = Metadata(TokenType.enumMember, TokenModifier.declaration)
}
Expand All @@ -101,13 +106,13 @@ class SamtSemanticTokens private constructor() : SamtSemanticLookup<Location, Sa

override fun markOperationReference(operation: ServiceType.Operation, reference: IdentifierNode) {
super.markOperationReference(operation, reference)
var modifier = operation.getDeprecationModifier()
if (operation is ServiceType.RequestResponseOperation && operation.isAsync) {
modifier = modifier and TokenModifier.async
}
this[reference.location] = Metadata(
type = TokenType.method,
modifier = if (operation is ServiceType.RequestResponseOperation && operation.isAsync) {
TokenModifier.async
} else {
TokenModifier.none
}
modifier = modifier
)
}

Expand All @@ -126,6 +131,26 @@ class SamtSemanticTokens private constructor() : SamtSemanticLookup<Location, Sa
}
}

override fun markTypeAliasDeclaration(aliasType: AliasType) {
super.markTypeAliasDeclaration(aliasType)
this[aliasType.declaration.name.location] = Metadata(getAliasTokenType(aliasType), aliasType.getDeprecationModifier() and TokenModifier.declaration)
}

private fun getAliasTokenType(aliasType: AliasType): TokenType = when (aliasType.fullyResolvedType?.type) {
is EnumType -> TokenType.enum
is RecordType -> TokenType.`class`
is ServiceType -> TokenType.`interface`
else -> TokenType.type
}

private fun UserDeclared.getDeprecationModifier() =
if (userMetadata.getDeprecation(this) != null) {
TokenModifier.deprecated
} else {
TokenModifier.none
}


data class Metadata(val type: TokenType, val modifier: TokenModifier = TokenModifier.none)

@Suppress("EnumEntryName")
Expand Down Expand Up @@ -171,7 +196,8 @@ class SamtSemanticTokens private constructor() : SamtSemanticLookup<Location, Sa
val declaration = TokenModifier(1 shl 0)
val async = TokenModifier(1 shl 1)
val defaultLibrary = TokenModifier(1 shl 2)
fun values() = arrayOf(::declaration, ::async, ::defaultLibrary)
val deprecated = TokenModifier(1 shl 3)
fun values() = arrayOf(::declaration, ::async, ::defaultLibrary, ::deprecated)
}
}

Expand All @@ -181,7 +207,7 @@ class SamtSemanticTokens private constructor() : SamtSemanticLookup<Location, Sa
TokenModifier.values().map { it.name },
)

fun analyze(fileNode: FileNode, samtPackage: Package) =
SamtSemanticTokens().also { it.analyze(fileNode, samtPackage) }
fun analyze(fileNode: FileNode, filePackage: Package, userMetadata: UserMetadata) =
SamtSemanticTokens(userMetadata).also { it.analyze(fileNode, filePackage) }
}
}
Loading