@@ -4,19 +4,48 @@ import org.eclipse.lsp4j.*
44import org.eclipse.lsp4j.services.LanguageClient
55import org.eclipse.lsp4j.services.LanguageClientAware
66import org.eclipse.lsp4j.services.TextDocumentService
7- import java.util.concurrent.CompletableFuture
7+ import tools.samt.common.DiagnosticController
8+ import tools.samt.common.DiagnosticException
9+ import tools.samt.common.DiagnosticMessage
10+ import tools.samt.common.SourceFile
11+ import tools.samt.lexer.Lexer
12+ import tools.samt.parser.Parser
13+ import tools.samt.semantic.SemanticModelBuilder
814import java.util.logging.Logger
15+ import kotlin.io.path.Path
16+ import kotlin.io.path.readText
17+ import tools.samt.common.DiagnosticSeverity as SamtSeverity
18+ import tools.samt.common.Location as SamtLocation
919
1020class SamtTextDocumentService : TextDocumentService , LanguageClientAware {
1121 private lateinit var client: LanguageClient
1222 private val logger = Logger .getLogger(" SamtTextDocumentService" )
1323
1424 override fun didOpen (params : DidOpenTextDocumentParams ) {
1525 logger.info(" Opened document ${params.textDocument.uri} " )
26+
27+ val uri = params.textDocument.uri.removePrefix(" file://" )
28+ val messages = compile(uri, Path (uri).readText())
29+
30+ client.publishDiagnostics(
31+ PublishDiagnosticsParams (
32+ params.textDocument.uri,
33+ messages.mapNotNull { it.toDiagnostic() })
34+ )
1635 }
1736
1837 override fun didChange (params : DidChangeTextDocumentParams ) {
1938 logger.info(" Changed document ${params.textDocument.uri} " )
39+
40+ val uri = params.textDocument.uri.removePrefix(" file://" )
41+ val newText = params.contentChanges.firstOrNull()?.text ? : Path (uri).readText()
42+ val messages = compile(uri, newText)
43+
44+ client.publishDiagnostics(
45+ PublishDiagnosticsParams (
46+ params.textDocument.uri,
47+ messages.mapNotNull { it.toDiagnostic() })
48+ )
2049 }
2150
2251 override fun didClose (params : DidCloseTextDocumentParams ) {
@@ -27,9 +56,59 @@ class SamtTextDocumentService : TextDocumentService, LanguageClientAware {
2756 logger.info(" Saved document ${params.textDocument.uri} " )
2857 }
2958
30- override fun diagnostic (params : DocumentDiagnosticParams ): CompletableFuture <DocumentDiagnosticReport > = CompletableFuture .supplyAsync {
31- logger.info(" Diagnostics for document ${params.textDocument.uri} " )
32- DocumentDiagnosticReport (RelatedFullDocumentDiagnosticReport ())
59+ private fun SamtLocation.toRange (): Range {
60+ return Range (
61+ Position (start.row, start.col),
62+ Position (start.row, end.col)
63+ )
64+ }
65+
66+ private fun DiagnosticMessage.toDiagnostic (): Diagnostic ? {
67+ val diagnostic = Diagnostic ()
68+ val primaryHighlight = this .highlights.firstOrNull()
69+ if (primaryHighlight == null ) {
70+ logger.warning(" Diagnostic message without location, how do I convert this???" )
71+ return null
72+ }
73+ // TODO consider highlightBeginningOnly
74+ diagnostic.range = primaryHighlight.location.toRange()
75+ diagnostic.severity = when (severity) {
76+ SamtSeverity .Error -> DiagnosticSeverity .Error
77+ SamtSeverity .Warning -> DiagnosticSeverity .Warning
78+ SamtSeverity .Info -> DiagnosticSeverity .Information
79+ }
80+ diagnostic.source = " samt"
81+ diagnostic.message = message
82+ diagnostic.relatedInformation = highlights.filter { it.message != null }.map {
83+ DiagnosticRelatedInformation (
84+ Location (" file://${it.location.source.absolutePath} " , it.location.toRange()),
85+ it.message
86+ )
87+ }
88+ return diagnostic
89+ }
90+
91+ private fun compile (uri : String , content : String ): List <DiagnosticMessage > {
92+ val source = SourceFile (uri, content)
93+ val controller = DiagnosticController (" todo" )
94+ val context = controller.createContext(source)
95+
96+ val tokenStream = Lexer .scan(source.content.reader(), context)
97+
98+ if (context.hasErrors()) {
99+ return context.messages
100+ }
101+
102+ val fileNode = try {
103+ Parser .parse(source, tokenStream, context)
104+ } catch (e: DiagnosticException ) {
105+ // error message is added to the diagnostic console, so it can be ignored here
106+ return context.messages
107+ }
108+
109+ SemanticModelBuilder .build(listOf (fileNode), controller)
110+
111+ return context.messages
33112 }
34113
35114 override fun connect (client : LanguageClient ) {
0 commit comments