Compare commits

...

4 Commits

Author SHA1 Message Date
Irmen de Jong
357be82446 first setup of LSP languageserver 2025-08-01 23:39:10 +02:00
Irmen de Jong
7ea80babfc todo 2025-08-01 23:38:49 +02:00
Irmen de Jong
67fb45a55b don't produce invalid boolean initalization error. Fixes #173 2025-07-26 12:35:23 +02:00
Irmen de Jong
11186f1dbe make sure that the virtual target -emu (vm) only runs the actual .p8ir file (fixes #172)
added emudbg.console_nl()
2025-07-26 11:19:01 +02:00
22 changed files with 430 additions and 109 deletions

1
.idea/modules.xml generated
View File

@@ -15,6 +15,7 @@
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" /> <module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" /> <module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
<module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" /> <module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
<module fileurl="file://$PROJECT_DIR$/languageServer/languageServer.iml" filepath="$PROJECT_DIR$/languageServer/languageServer.iml" />
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" /> <module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/prog8.iml" filepath="$PROJECT_DIR$/.idea/modules/prog8.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/modules/prog8.iml" filepath="$PROJECT_DIR$/.idea/modules/prog8.iml" />
<module fileurl="file://$PROJECT_DIR$/simpleAst/simpleAst.iml" filepath="$PROJECT_DIR$/simpleAst/simpleAst.iml" /> <module fileurl="file://$PROJECT_DIR$/simpleAst/simpleAst.iml" filepath="$PROJECT_DIR$/simpleAst/simpleAst.iml" />

View File

@@ -3,6 +3,7 @@ package prog8.code.target
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.encodings.Encoder import prog8.code.target.encodings.Encoder
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.extension
import kotlin.io.path.isReadable import kotlin.io.path.isReadable
import kotlin.io.path.name import kotlin.io.path.name
import kotlin.io.path.readText import kotlin.io.path.readText
@@ -73,16 +74,11 @@ class VMTarget: ICompilationTarget,
// to not have external module dependencies in our own module, we launch the virtual machine via reflection // to not have external module dependencies in our own module, we launch the virtual machine via reflection
val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner
val filename = programNameWithPath.name val withExt = if(programNameWithPath.extension=="p8ir") programNameWithPath else programNameWithPath.resolveSibling("${programNameWithPath.name}.p8ir")
if(programNameWithPath.isReadable()) { if(withExt.isReadable())
vm.runProgram(programNameWithPath.readText(), quiet) vm.runProgram(withExt.readText(), quiet)
} else { else
val withExt = programNameWithPath.resolveSibling("$filename.p8ir") throw java.nio.file.NoSuchFileException(withExt.name, null, "not a .p8ir file")
if(withExt.isReadable())
vm.runProgram(withExt.readText(), quiet)
else
throw java.nio.file.NoSuchFileException(withExt.name, null, "not a .p8ir file")
}
} }
override fun isIOAddress(address: UInt): Boolean = false override fun isIOAddress(address: UInt): Boolean = false

View File

@@ -70,12 +70,12 @@ class IRCodeGen(
val initValue = initialization?.value val initValue = initialization?.value
when(initValue){ when(initValue){
is PtBool -> { is PtBool -> {
require(initValue.asInt()!=0) { "boolean var should not be initialized with false, it wil be set to false as part of BSS clear, initializer=$initialization" } require(initValue.asInt()!=0 || variable.zpwish!=ZeropageWish.NOT_IN_ZEROPAGE) { "non-zp variable should not be initialized with 0, it will already be zeroed as part of BSS clear, initializer=$initialization" }
variable.setOnetimeInitNumeric(initValue.asInt().toDouble()) variable.setOnetimeInitNumeric(initValue.asInt().toDouble())
initsToRemove += block to initialization initsToRemove += block to initialization
} }
is PtNumber -> { is PtNumber -> {
require(initValue.number!=0.0 || variable.zpwish!=ZeropageWish.NOT_IN_ZEROPAGE) {"non-zp variable should not be initialized with 0, it will already be zeroed as part of BSS clear, initializer=$initialization" } require(initValue.number!=0.0 || variable.zpwish!=ZeropageWish.NOT_IN_ZEROPAGE) { "non-zp variable should not be initialized with 0, it will already be zeroed as part of BSS clear, initializer=$initialization" }
variable.setOnetimeInitNumeric(initValue.number) variable.setOnetimeInitNumeric(initValue.number)
initsToRemove += block to initialization initsToRemove += block to initialization
} }

View File

@@ -47,6 +47,12 @@ emudbg {
} }
} }
sub console_nl() {
; write a newline to the debug output console.
; because '\n' gets encoded in the x16 value for it (13) which is different than what the shell expects (10).
console_chrout(10)
}
sub console_chrout(ubyte char) { sub console_chrout(ubyte char) {
; note: make sure the character is in Iso encoding. ; note: make sure the character is in Iso encoding.
if is_emulator() if is_emulator()

View File

@@ -11,9 +11,11 @@ import prog8.ast.statements.AssignmentOrigin
import prog8.ast.statements.ForLoop import prog8.ast.statements.ForLoop
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.code.ast.PtAssignment import prog8.code.ast.PtAssignment
import prog8.code.ast.PtBool
import prog8.code.ast.PtNumber import prog8.code.ast.PtNumber
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.Cx16Target import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText import prog8tests.helpers.compileText
@@ -229,27 +231,40 @@ main {
val src=""" val src="""
main { main {
ubyte @shared @requirezp zpvar ubyte @shared @requirezp zpvar
bool @shared @requirezp zpbool
ubyte @shared @requirezp @dirty dirtyzpvar ubyte @shared @requirezp @dirty dirtyzpvar
bool @shared @requirezp @dirty dirtyzpbool
sub start() { sub start() {
ubyte @shared @requirezp zpvar2 ubyte @shared @requirezp zpvar2
bool @shared @requirezp zpbool2
ubyte @shared @requirezp @dirty dirtyzpvar2 ubyte @shared @requirezp @dirty dirtyzpvar2
bool @shared @requirezp @dirty dirtyzpbool2
} }
}""" }"""
val result = compileText(Cx16Target(), false, src, outputDir, writeAssembly = true)!!.codegenAst val result = compileText(Cx16Target(), false, src, outputDir, writeAssembly = true)!!.codegenAst
val main = result!!.allBlocks().first { it.name=="p8b_main" } val main = result!!.allBlocks().first { it.name=="p8b_main" }
main.children.size shouldBe 4 main.children.size shouldBe 7
val zeroassignlobal = main.children.single { it is PtAssignment } as PtAssignment val zeroassignsglobal = main.children.filterIsInstance<PtAssignment>()
(zeroassignlobal.value as PtNumber).number shouldBe 0.0 zeroassignsglobal.size shouldBe 2
zeroassignlobal.target.identifier!!.name shouldBe "p8b_main.p8v_zpvar" (zeroassignsglobal[0].value as PtNumber).number shouldBe 0.0
zeroassignsglobal[0].target.identifier!!.name shouldBe "p8b_main.p8v_zpvar"
(zeroassignsglobal[1].value as PtBool).value shouldBe false
zeroassignsglobal[1].target.identifier!!.name shouldBe "p8b_main.p8v_zpbool"
val st = result.entrypoint()!!.children val st = result.entrypoint()!!.children
st.size shouldBe 4 st.size shouldBe 7
val zeroassign = st.single { it is PtAssignment } as PtAssignment val zeroassigns = st.filterIsInstance<PtAssignment>()
(zeroassign.value as PtNumber).number shouldBe 0.0 zeroassigns.size shouldBe 2
zeroassign.target.identifier!!.name shouldBe "p8b_main.p8s_start.p8v_zpvar2" (zeroassigns[0].value as PtNumber).number shouldBe 0.0
zeroassigns[0].target.identifier!!.name shouldBe "p8b_main.p8s_start.p8v_zpvar2"
(zeroassigns[1].value as PtBool).value shouldBe false
zeroassigns[1].target.identifier!!.name shouldBe "p8b_main.p8s_start.p8v_zpbool2"
compileText(VMTarget(), false, src, outputDir, writeAssembly = true) shouldNotBe null
} }
test("nondirty non zp variables in block scope should not be explicitly initialized to 0 (bss clear takes care of it)") { test("nondirty non zp variables in block scope should not be explicitly initialized to 0 (bss clear takes care of it)") {

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c128.p8 Compiling program import-all-c128.p8

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c64.p8 Compiling program import-all-c64.p8

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-cx16.p8 Compiling program import-all-cx16.p8
@@ -262,6 +263,7 @@ emudbg {
&ubyte EMU_RECORD_WAV &ubyte EMU_RECORD_WAV
&ubyte EMU_SAVE_ON_EXIT &ubyte EMU_SAVE_ON_EXIT
console_chrout (ubyte char) console_chrout (ubyte char)
console_nl ()
console_value1 (ubyte value) console_value1 (ubyte value)
console_value2 (ubyte value) console_value2 (ubyte value)
console_write (str isoString) console_write (str isoString)

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-pet32.p8 Compiling program import-all-pet32.p8

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4.1 by Irmen de Jong (irmen@razorvine.net) Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-virtual.p8 Compiling program import-all-virtual.p8

View File

@@ -488,7 +488,17 @@ emudbg (cx16 only)
X16Emu Emulator debug routines, for Cx16 only. X16Emu Emulator debug routines, for Cx16 only.
Allows you to interface with the emulator's debug routines/registers. Allows you to interface with the emulator's debug routines/registers.
There's stuff like ``is_emulator`` to detect if running in the emulator, There's stuff like ``is_emulator`` to detect if running in the emulator,
and ``console_write`` to write a (iso) string to the emulator's console (stdout) etc. and ``console_write`` to write a (iso) string to the emulator's console (stdout), etc.
*EOL (end of line) character handling:*
Writing ``iso:'\n'`` to the console doesn't produce a proper new line there, because prog8 encodes
the newline to character 13 on the X16 (this is what the X16 uses to print a newline on the screen).
You have to explicitly output a character 10 on the console to see a newline there. You can do that in several ways::
emudbg.console_nl()
emudbg.console_chrout(10)
emudbg.console_write(iso:"hello\x0a")
Read the `emudbg source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/emudbg.p8>`_ Read the `emudbg source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/emudbg.p8>`_
to see what's in there. to see what's in there.

View File

@@ -1,8 +1,7 @@
TODO TODO
==== ====
Since fixing the missing zp-var initialization, programs grew in size again (assem) Port benchmarks from https://thred.github.io/c-bench-64/ to prog8 and see how it stacks up.
Are there any redundant block-level variable initializations to 0 that we can remove in peephole optimization for example?
STRUCTS: are being developed in their own separate branch for now, called "structs". STRUCTS: are being developed in their own separate branch for now, called "structs".
@@ -72,6 +71,7 @@ Libraries
Optimizations Optimizations
------------- -------------
- Since fixing the missing zp-var initialization, programs grew in size again because STZ's reappered. Can we add more intelligent (and correct!) optimizations to remove those STZs that might be redundant again?
- in Identifier: use typedarray of strings instead of listOf? Other places? - in Identifier: use typedarray of strings instead of listOf? Other places?
- Compilation speed: try to join multiple modifications in 1 result in the AST processors instead of returning it straight away every time - Compilation speed: try to join multiple modifications in 1 result in the AST processors instead of returning it straight away every time
- Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples) - Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples)

View File

@@ -1,84 +1,13 @@
%option no_sysinit
%zeropage kernalsafe
%import textio
%zpallowed 224,255
main { main {
uword @shared @requirezp zpvar1 ubyte @shared @requirezp zpvar
uword @shared @requirezp zpvar2 bool @shared @requirezp zpbool
uword @shared @requirezp zpvar3 ubyte @shared @requirezp @dirty dirtyzpvar
uword @shared @requirezp zpvar4 bool @shared @requirezp @dirty dirtyzpbool
uword @shared @requirezp zpvar5
uword @shared @requirezp @dirty dzpvar1
uword @shared @requirezp @dirty dzpvar2
uword @shared @requirezp @dirty dzpvar3
uword @shared @requirezp @dirty dzpvar4
uword @shared @requirezp @dirty dzpvar5
uword @shared @nozp var1
uword @shared @nozp var2
uword @shared @nozp var3
uword @shared @nozp var4
uword @shared @nozp var5
uword @shared @nozp @dirty dvar1
uword @shared @nozp @dirty dvar2
uword @shared @nozp @dirty dvar3
uword @shared @nozp @dirty dvar4
uword @shared @nozp @dirty dvar5
sub start() { sub start() {
txt.print("address start of zpvars: ") ubyte @shared @requirezp zpvar2
txt.print_uw(&zpvar1) bool @shared @requirezp zpbool2
txt.nl() ubyte @shared @requirezp @dirty dirtyzpvar2
txt.print("address start of normal vars: ") bool @shared @requirezp @dirty dirtyzpbool2
txt.print_uw(&var1)
txt.nl()
txt.print("non-dirty zp should all be 0: ")
txt.print_uw(zpvar1)
txt.spc()
txt.print_uw(zpvar2)
txt.spc()
txt.print_uw(zpvar3)
txt.spc()
txt.print_uw(zpvar4)
txt.spc()
txt.print_uw(zpvar5)
txt.nl()
txt.print("non-dirty should all be 0: ")
txt.print_uw(var1)
txt.spc()
txt.print_uw(var2)
txt.spc()
txt.print_uw(var3)
txt.spc()
txt.print_uw(var4)
txt.spc()
txt.print_uw(var5)
txt.nl()
txt.print("dirty zp may be random: ")
txt.print_uw(dzpvar1)
txt.spc()
txt.print_uw(dzpvar2)
txt.spc()
txt.print_uw(dzpvar3)
txt.spc()
txt.print_uw(dzpvar4)
txt.spc()
txt.print_uw(dzpvar5)
txt.nl()
txt.print("dirty may be random: ")
txt.print_uw(dvar1)
txt.spc()
txt.print_uw(dvar2)
txt.spc()
txt.print_uw(dvar3)
txt.spc()
txt.print_uw(dvar4)
txt.spc()
txt.print_uw(dvar5)
txt.nl()
repeat {}
} }
} }

View File

@@ -3,4 +3,4 @@ org.gradle.console=rich
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.daemon=true org.gradle.daemon=true
kotlin.code.style=official kotlin.code.style=official
version=11.4.1 version=11.5-SNAPSHOT

View File

@@ -0,0 +1,103 @@
plugins {
kotlin("jvm")
id("application")
}
val debugPort = 8000
val debugArgs = "-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n,quiet=y"
val serverMainClassName = "prog8lsp.MainKt"
val applicationName = "prog8-language-server"
application {
mainClass.set(serverMainClassName)
description = "Code completions, diagnostics and more for Prog8"
// applicationDefaultJvmArgs = listOf("-DkotlinLanguageServer.version=$version")
applicationDistribution.into("bin") {
filePermissions {
user {
read=true
execute=true
write=true
}
other.execute = true
group.execute = true
}
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.eclipse.lsp4j:org.eclipse.lsp4j:0.24.0")
implementation("org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:0.24.0")
}
configurations.forEach { config ->
config.resolutionStrategy {
preferProjectModules()
}
}
sourceSets.main {
java.srcDir("src")
resources.srcDir("resources")
}
sourceSets.test {
java.srcDir("src")
resources.srcDir("resources")
}
tasks.startScripts {
applicationName = "prog8-language-server"
}
tasks.register<Exec>("fixFilePermissions") {
// When running on macOS or Linux the start script
// needs executable permissions to run.
onlyIf { !System.getProperty("os.name").lowercase().contains("windows") }
commandLine("chmod", "+x", "${tasks.installDist.get().destinationDir}/bin/prog8-language-server")
}
tasks.register<JavaExec>("debugRun") {
mainClass.set(serverMainClassName)
classpath(sourceSets.main.get().runtimeClasspath)
standardInput = System.`in`
jvmArgs(debugArgs)
doLast {
println("Using debug port $debugPort")
}
}
tasks.register<CreateStartScripts>("debugStartScripts") {
applicationName = "prog8-language-server"
mainClass.set(serverMainClassName)
outputDir = tasks.installDist.get().destinationDir.toPath().resolve("bin").toFile()
classpath = tasks.startScripts.get().classpath
defaultJvmOpts = listOf(debugArgs)
}
tasks.register<Sync>("installDebugDist") {
dependsOn("installDist")
finalizedBy("debugStartScripts")
}
tasks.withType<Test>() {
testLogging {
events("failed")
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}
tasks.installDist {
finalizedBy("fixFilePermissions")
}
tasks.build {
finalizedBy("installDist")
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="eclipse.lsp4j" level="project" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
</component>
</module>

View File

@@ -0,0 +1,34 @@
package prog8lsp
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.function.Supplier
private var threadCount = 0
class AsyncExecutor {
private val workerThread = Executors.newSingleThreadExecutor { Thread(it, "async${threadCount++}") }
fun execute(task: () -> Unit) =
CompletableFuture.runAsync(Runnable(task), workerThread)
fun <R> compute(task: () -> R) =
CompletableFuture.supplyAsync(Supplier(task), workerThread)
fun <R> computeOr(defaultValue: R, task: () -> R?) =
CompletableFuture.supplyAsync(Supplier {
try {
task() ?: defaultValue
} catch (e: Exception) {
defaultValue
}
}, workerThread)
fun shutdown(awaitTermination: Boolean) {
workerThread.shutdown()
if (awaitTermination) {
workerThread.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS)
}
}
}

View File

@@ -0,0 +1,19 @@
package prog8lsp
import org.eclipse.lsp4j.launch.LSPLauncher
import java.util.concurrent.Executors
import java.util.logging.Level
import java.util.logging.Logger
fun main(args: Array<String>) {
Logger.getLogger("").level = Level.INFO
val inStream = System.`in`
val outStream = System.out
val server = Prog8LanguageServer()
val threads = Executors.newSingleThreadExecutor { Thread(it, "client") }
val launcher = LSPLauncher.createServerLauncher(server, inStream, outStream, threads) { it }
server.connect(launcher.remoteProxy)
launcher.startListening()
}

View File

@@ -0,0 +1,46 @@
package prog8lsp
import org.eclipse.lsp4j.InitializeParams
import org.eclipse.lsp4j.InitializeResult
import org.eclipse.lsp4j.services.*
import java.io.Closeable
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletableFuture.completedFuture
import java.util.logging.Logger
class Prog8LanguageServer: LanguageServer, LanguageClientAware, Closeable {
private lateinit var client: LanguageClient
private val textDocuments = Prog8TextDocumentService()
private val workspaces = Prog8WorkspaceService()
private val async = AsyncExecutor()
private val logger = Logger.getLogger(Prog8LanguageServer::class.simpleName)
override fun initialize(params: InitializeParams): CompletableFuture<InitializeResult> = async.compute {
logger.info("Initializing LanguageServer")
InitializeResult()
}
override fun shutdown(): CompletableFuture<Any> {
close()
return completedFuture(null)
}
override fun exit() { }
override fun getTextDocumentService(): TextDocumentService = textDocuments
override fun getWorkspaceService(): WorkspaceService = workspaces
override fun connect(client: LanguageClient) {
logger.info("connecting to language client")
this.client = client
workspaces.connect(client)
textDocuments.connect(client)
}
override fun close() {
logger.info("closing down")
async.shutdown(awaitTermination = true)
}
}

View File

@@ -0,0 +1,62 @@
package prog8lsp
import org.eclipse.lsp4j.*
import org.eclipse.lsp4j.jsonrpc.messages.Either
import org.eclipse.lsp4j.services.LanguageClient
import org.eclipse.lsp4j.services.TextDocumentService
import java.util.concurrent.CompletableFuture
import java.util.logging.Logger
import kotlin.system.measureTimeMillis
class Prog8TextDocumentService: TextDocumentService {
private var client: LanguageClient? = null
private val async = AsyncExecutor()
private val logger = Logger.getLogger(Prog8TextDocumentService::class.simpleName)
fun connect(client: LanguageClient) {
this.client = client
}
override fun didOpen(params: DidOpenTextDocumentParams) {
logger.info("didOpen: $params")
}
override fun didChange(params: DidChangeTextDocumentParams) {
logger.info("didChange: $params")
}
override fun didClose(params: DidCloseTextDocumentParams) {
logger.info("didClose: $params")
}
override fun didSave(params: DidSaveTextDocumentParams) {
logger.info("didSave: $params")
}
override fun documentSymbol(params: DocumentSymbolParams): CompletableFuture<MutableList<Either<SymbolInformation, DocumentSymbol>>> = async.compute {
logger.info("Find symbols in ${params.textDocument.uri}")
val result: MutableList<Either<SymbolInformation, DocumentSymbol>>
val time = measureTimeMillis {
result = mutableListOf()
val range = Range(Position(1,1), Position(1,5))
val selectionRange = Range(Position(1,2), Position(1,10))
val symbol = DocumentSymbol("test-symbolName", SymbolKind.Constant, range, selectionRange)
result.add(Either.forRight(symbol))
}
logger.info("Finished in $time ms")
result
}
override fun completion(position: CompletionParams): CompletableFuture<Either<MutableList<CompletionItem>, CompletionList>> = async.compute{
logger.info("Completion for ${position}")
val result: Either<MutableList<CompletionItem>, CompletionList>
val time = measureTimeMillis {
val list = CompletionList(false, listOf(CompletionItem("test-completionItem")))
result = Either.forRight(list)
}
logger.info("Finished in $time ms")
result
}
// TODO add all other methods that get called.... :P
}

View File

@@ -0,0 +1,80 @@
package prog8lsp
import org.eclipse.lsp4j.*
import org.eclipse.lsp4j.jsonrpc.messages.Either
import org.eclipse.lsp4j.services.LanguageClient
import org.eclipse.lsp4j.services.WorkspaceService
import java.util.concurrent.CompletableFuture
import java.util.logging.Logger
class Prog8WorkspaceService: WorkspaceService {
private var client: LanguageClient? = null
private val logger = Logger.getLogger(Prog8WorkspaceService::class.simpleName)
fun connect(client: LanguageClient) {
this.client = client
}
override fun executeCommand(params: ExecuteCommandParams): CompletableFuture<Any> {
logger.info("executeCommand $params")
return super.executeCommand(params)
}
override fun symbol(params: WorkspaceSymbolParams): CompletableFuture<Either<MutableList<out SymbolInformation>, MutableList<out WorkspaceSymbol>>> {
logger.info("symbol $params")
return super.symbol(params)
}
override fun resolveWorkspaceSymbol(workspaceSymbol: WorkspaceSymbol): CompletableFuture<WorkspaceSymbol> {
logger.info("resolveWorkspaceSymbol $workspaceSymbol")
return super.resolveWorkspaceSymbol(workspaceSymbol)
}
override fun didChangeConfiguration(params: DidChangeConfigurationParams) {
logger.info("didChangeConfiguration: $params")
}
override fun didChangeWatchedFiles(params: DidChangeWatchedFilesParams) {
logger.info("didChangeWatchedFiles: $params")
}
override fun didChangeWorkspaceFolders(params: DidChangeWorkspaceFoldersParams) {
logger.info("didChangeWorkspaceFolders $params")
super.didChangeWorkspaceFolders(params)
}
override fun willCreateFiles(params: CreateFilesParams): CompletableFuture<WorkspaceEdit> {
logger.info("willCreateFiles $params")
return super.willCreateFiles(params)
}
override fun didCreateFiles(params: CreateFilesParams) {
logger.info("didCreateFiles $params")
super.didCreateFiles(params)
}
override fun willRenameFiles(params: RenameFilesParams): CompletableFuture<WorkspaceEdit> {
logger.info("willRenameFiles $params")
return super.willRenameFiles(params)
}
override fun didRenameFiles(params: RenameFilesParams) {
logger.info("didRenameFiles $params")
super.didRenameFiles(params)
}
override fun willDeleteFiles(params: DeleteFilesParams): CompletableFuture<WorkspaceEdit> {
logger.info("willDeleteFiles $params")
return super.willDeleteFiles(params)
}
override fun didDeleteFiles(params: DeleteFilesParams) {
logger.info("didDeleteFiles $params")
super.didDeleteFiles(params)
}
override fun diagnostic(params: WorkspaceDiagnosticParams): CompletableFuture<WorkspaceDiagnosticReport> {
logger.info("diagnostic $params")
return super.diagnostic(params)
}
}

View File

@@ -10,5 +10,6 @@ include(
':codeGenCpu6502', ':codeGenCpu6502',
':codeGenExperimental', ':codeGenExperimental',
':compiler', ':compiler',
':beanshell' ':beanshell',
':languageServer'
) )