firefly-compiler 0.4.10 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/Array.ff +8 -0
- package/core/Json.ff +123 -11
- package/lsp/Handler.ff +79 -88
- package/lsp/HoverHandler.ff +7 -10
- package/lsp/LanguageServer.ff +30 -33
- package/lsp/SignatureHelpHandler.ff +12 -13
- package/lsp/SymbolHandler.ff +17 -17
- package/output/js/ff/core/Array.mjs +16 -0
- package/output/js/ff/core/Json.mjs +376 -17
- package/package.json +2 -2
- package/vscode/package.json +1 -1
package/lsp/LanguageServer.ff
CHANGED
|
@@ -8,13 +8,13 @@ data BadRequestException(reason: String)
|
|
|
8
8
|
|
|
9
9
|
capability Request(
|
|
10
10
|
headers: Map[String, String]
|
|
11
|
-
object:
|
|
11
|
+
object: Json
|
|
12
12
|
)
|
|
13
13
|
|
|
14
14
|
capability RequestMessage(
|
|
15
15
|
id: Option[MessageId] // None when the request is a Notification Message
|
|
16
16
|
method: String
|
|
17
|
-
parameters: Map[String,
|
|
17
|
+
parameters: Map[String, Json]
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
logMessages = False
|
|
@@ -31,11 +31,11 @@ main(system: NodeSystem) {
|
|
|
31
31
|
let handler = Handler(fireflyPath, None, Map.empty(), [].toSet(), Map.empty(), Map.empty())
|
|
32
32
|
try {
|
|
33
33
|
mutable input = system.readStream()
|
|
34
|
-
let responseChannel: Channel[Pair[
|
|
34
|
+
let responseChannel: Channel[Pair[Json, String]] = system.mainTask().channel()
|
|
35
35
|
system.mainTask().spawn {_ =>
|
|
36
36
|
while {True} {
|
|
37
37
|
let body = responseChannel.read()
|
|
38
|
-
let json = body.first.
|
|
38
|
+
let json = body.first.write(Some(" ")).toBuffer()
|
|
39
39
|
logDirectory.each {logMessage(_, "response", body.first, body.second)}
|
|
40
40
|
system.writeText("Content-Length: " + json.size() + "\r\n\r\n")
|
|
41
41
|
system.writeBuffer(json)
|
|
@@ -65,7 +65,7 @@ main(system: NodeSystem) {
|
|
|
65
65
|
Error(-32603, "Internal error")
|
|
66
66
|
}
|
|
67
67
|
message.id.each {id =>
|
|
68
|
-
let body = makeResponseMessage(
|
|
68
|
+
let body = makeResponseMessage(id, problem)
|
|
69
69
|
responseChannel.write(Pair(body, message.method))
|
|
70
70
|
}
|
|
71
71
|
} grab()
|
|
@@ -106,7 +106,7 @@ parseRequest(system: NodeSystem, input: Stream[Buffer]): Pair[Request, Stream[Bu
|
|
|
106
106
|
let contentLength = headers
|
|
107
107
|
.get("content-length").else {throw(BadRequestException("'content-length' header is missing"))}
|
|
108
108
|
.getInt().else {throw(BadRequestException("Value for 'content-length' is not an integer"))}
|
|
109
|
-
let bodyPair = parseRequestBody(
|
|
109
|
+
let bodyPair = parseRequestBody(contentLength, headersPair.second)
|
|
110
110
|
bodyPair.mapFirst {body => Request(headers, body)}
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -153,31 +153,29 @@ parseRequestHeaders(input: Stream[Buffer]): Pair[Map[String, String], Stream[Buf
|
|
|
153
153
|
Pair(map, [buffer.view(offset, buffer.size())].toStream().addAll(input))
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
parseRequestBody(
|
|
156
|
+
parseRequestBody(contentLength: Int, input: Stream[Buffer]): Pair[Json, Stream[Buffer]] {
|
|
157
157
|
let bodyPair = try {
|
|
158
158
|
input.readBytes(contentLength) // Should Stream.readBytes return an option?
|
|
159
159
|
} catchAny {error =>
|
|
160
160
|
throw(BadRequestException("End of input while parsing request body"))
|
|
161
161
|
} grab()
|
|
162
162
|
let body = Buffer.fromBufferArray(bodyPair.first).toString()
|
|
163
|
-
let json =
|
|
164
|
-
js.parseJson(body)
|
|
165
|
-
} catchAny {error =>
|
|
163
|
+
let json = Json.read(body).else {
|
|
166
164
|
throw(BadRequestException("Invalid JSON in request body: " + body))
|
|
167
|
-
}
|
|
165
|
+
}
|
|
168
166
|
Pair(json, bodyPair.second)
|
|
169
167
|
}
|
|
170
168
|
|
|
171
|
-
parseRequestMessage(object:
|
|
172
|
-
let id = object.
|
|
169
|
+
parseRequestMessage(object: Json): RequestMessage {
|
|
170
|
+
let id = object.getField("id").map {parseMessageId(_)}
|
|
173
171
|
|
|
174
|
-
let method = object.
|
|
172
|
+
let method = object.getField("method").{
|
|
175
173
|
| None => throw(BadRequestException("Bad JSON-RPC, missing method"))
|
|
176
174
|
| Some(m) {!m.isString()} => throw(BadRequestException("Bad JSON-RPC method, string expected"))
|
|
177
175
|
| Some(m) => m.grabString()
|
|
178
176
|
}
|
|
179
177
|
|
|
180
|
-
let parameters = object.
|
|
178
|
+
let parameters = object.getField("params").{
|
|
181
179
|
| None => [].toMap()
|
|
182
180
|
| Some(o) {!o.isObject()} => throw(BadRequestException("Bad JSON-RPC params, object expected"))
|
|
183
181
|
| Some(o) => o.grabMap()
|
|
@@ -186,7 +184,7 @@ parseRequestMessage(object: JsValue): RequestMessage {
|
|
|
186
184
|
RequestMessage(id, method, parameters)
|
|
187
185
|
}
|
|
188
186
|
|
|
189
|
-
parseMessageId(id:
|
|
187
|
+
parseMessageId(id: Json): MessageId {
|
|
190
188
|
if(id.isInt()) {
|
|
191
189
|
MessageIdInt(id.grabInt())
|
|
192
190
|
} elseIf {id.isString()} {
|
|
@@ -196,7 +194,7 @@ parseMessageId(id: JsValue): MessageId {
|
|
|
196
194
|
}
|
|
197
195
|
}
|
|
198
196
|
|
|
199
|
-
handleRequestMessage(system: NodeSystem, handler: Handler, message: RequestMessage): Option[
|
|
197
|
+
handleRequestMessage(system: NodeSystem, handler: Handler, message: RequestMessage): Option[Json] {
|
|
200
198
|
try {
|
|
201
199
|
message.id.{
|
|
202
200
|
| None {message.method == "$/cancelRequest"} => // TODO: Needs to read ahead to cancel anything
|
|
@@ -209,10 +207,10 @@ handleRequestMessage(system: NodeSystem, handler: Handler, message: RequestMessa
|
|
|
209
207
|
None
|
|
210
208
|
| Some(id) {handler.cancelledRequests.contains(id)} =>
|
|
211
209
|
handler.cancelledRequests = handler.cancelledRequests.remove(id)
|
|
212
|
-
Some(makeResponseMessage(
|
|
210
|
+
Some(makeResponseMessage(id, Error(-32800, "Request cancelled")))
|
|
213
211
|
| Some(id) =>
|
|
214
212
|
let result = handler.handleRequest(system, message.method, message.parameters)
|
|
215
|
-
Some(makeResponseMessage(
|
|
213
|
+
Some(makeResponseMessage(id, result))
|
|
216
214
|
}
|
|
217
215
|
} catchAny {error =>
|
|
218
216
|
//system.files().writeText("lsp-failure.txt", error.name() + ": " + error.message())
|
|
@@ -220,35 +218,34 @@ handleRequestMessage(system: NodeSystem, handler: Handler, message: RequestMessa
|
|
|
220
218
|
} grab()
|
|
221
219
|
}
|
|
222
220
|
|
|
223
|
-
makeResponseMessage(
|
|
224
|
-
|
|
225
|
-
o.set("jsonrpc", "2.0")
|
|
221
|
+
makeResponseMessage(id: MessageId, result: ResultOrError): Json {
|
|
222
|
+
mutable o = Json.object().with("jsonrpc", "2.0")
|
|
226
223
|
id.{
|
|
227
|
-
| MessageIdInt(id) => o.
|
|
228
|
-
| MessageIdString(id) => o.
|
|
224
|
+
| MessageIdInt(id) => o = o.with("id", id)
|
|
225
|
+
| MessageIdString(id) => o = o.with("id", id)
|
|
229
226
|
}
|
|
230
227
|
result.{
|
|
231
228
|
| Result(result) =>
|
|
232
|
-
o.
|
|
229
|
+
o = o.with("result", Json.read(result).grab())
|
|
233
230
|
| Error(code, message) =>
|
|
234
|
-
let e =
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
o.
|
|
231
|
+
let e = Json.object()
|
|
232
|
+
.with("code", code)
|
|
233
|
+
.with("message", message)
|
|
234
|
+
o = o.with("error", e)
|
|
238
235
|
}
|
|
239
236
|
o
|
|
240
237
|
}
|
|
241
238
|
|
|
242
|
-
logMessage(directory: Path, messageType: String, body:
|
|
239
|
+
logMessage(directory: Path, messageType: String, body: Json, method: String) {
|
|
243
240
|
let id = if(method == "$/cancelRequest") {
|
|
244
|
-
Some(body.
|
|
241
|
+
Some(body.field("params").field("id").grabInt())
|
|
245
242
|
} else {
|
|
246
|
-
body.
|
|
243
|
+
body.field("id").getInt()
|
|
247
244
|
}
|
|
248
245
|
let number = directory.entries().toList().size()
|
|
249
246
|
let idName = id.map {_ + ""}.else {"_"}
|
|
250
247
|
let methodName = method.replace("$", "notification").replace("/", "_")
|
|
251
248
|
let fileName = number + "-id-" + idName + "-" + messageType + "-" + methodName + ".json"
|
|
252
249
|
let path = directory.slash(fileName)
|
|
253
|
-
path.writeText(body.
|
|
250
|
+
path.writeText(body.write(Some(" ")))
|
|
254
251
|
}
|
|
@@ -5,7 +5,7 @@ import Syntax from ff:compiler
|
|
|
5
5
|
import Handler
|
|
6
6
|
import CompletionHandler
|
|
7
7
|
|
|
8
|
-
handleSignatureHelp(system: NodeSystem, lspHook: LspHook):
|
|
8
|
+
handleSignatureHelp(system: NodeSystem, lspHook: LspHook): Json {
|
|
9
9
|
let signatureAndUnification = lspHook.results().collectFirst {
|
|
10
10
|
| InferLookupHook h =>
|
|
11
11
|
let isMember = h.symbol.value.qualifiedName.contains("_")
|
|
@@ -17,7 +17,6 @@ handleSignatureHelp(system: NodeSystem, lspHook: LspHook): JsValue {
|
|
|
17
17
|
}
|
|
18
18
|
| _ => None
|
|
19
19
|
}
|
|
20
|
-
let js = system.js()
|
|
21
20
|
signatureAndUnification.map {| Pair(s, unification) =>
|
|
22
21
|
let shownTypes = [...s.parameters.map {_.valueType}, s.returnType].map {unification.substitute(_)}
|
|
23
22
|
let realGenerics = s.generics.filter {_ != "Q$"}
|
|
@@ -28,26 +27,26 @@ handleSignatureHelp(system: NodeSystem, lspHook: LspHook): JsValue {
|
|
|
28
27
|
}
|
|
29
28
|
let label =
|
|
30
29
|
s.name + generics + "(" + parameters.join(", ") + "): " + unification.substitute(s.returnType).show(shownTypes)
|
|
31
|
-
|
|
32
|
-
.with("signatures",
|
|
30
|
+
Json.object()
|
|
31
|
+
.with("signatures", [Json.object()
|
|
33
32
|
.with("label", label)
|
|
34
|
-
.with("parameters",
|
|
33
|
+
.with("parameters", [
|
|
35
34
|
...parameters.map {p =>
|
|
36
|
-
|
|
35
|
+
Json.object().with("label", p)
|
|
37
36
|
}
|
|
38
37
|
// Fake parameter to trick the client into remembering the call position
|
|
39
|
-
|
|
40
|
-
])
|
|
41
|
-
])
|
|
38
|
+
Json.object().with("label", "/* Call " + lspHook.at.show() + " */")
|
|
39
|
+
])
|
|
40
|
+
])
|
|
42
41
|
.with("activeSignature", 0)
|
|
43
|
-
}.else {
|
|
42
|
+
}.else {Json.null()}
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
pickActiveParameter(help:
|
|
45
|
+
pickActiveParameter(help: Json, argumentIndex: Int, parameterName: Option[String]): Json {
|
|
47
46
|
parameterName.flatMap {name =>
|
|
48
|
-
let parameters = help.
|
|
47
|
+
let parameters = help.field("signatures").index(0).field("parameters").grabArray().toList()
|
|
49
48
|
parameters.pairs().collectFirst {| Pair(i, p) =>
|
|
50
|
-
if(name == p.
|
|
49
|
+
if(name == p.field("label").grabString().takeWhile {_.isAsciiLetterOrDigit()}) {
|
|
51
50
|
help.with("activeParameter", i)
|
|
52
51
|
}
|
|
53
52
|
}
|
package/lsp/SymbolHandler.ff
CHANGED
|
@@ -50,18 +50,18 @@ readSymbol(hooks: List[ResultHook]): Result[DocumentSymbol] {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
handleDocumentSymbol(system: NodeSystem, resultHooks: List[ResultHook]): List[
|
|
53
|
+
handleDocumentSymbol(system: NodeSystem, resultHooks: List[ResultHook]): List[Json] {
|
|
54
54
|
let symbols = readAllSymbols(resultHooks)
|
|
55
|
-
symbols.map {documentSymbolToLsp(
|
|
55
|
+
symbols.map {documentSymbolToLsp(_)}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
handleWorkspaceSymbol(system: NodeSystem, resultHooks: List[ResultHook], query: String): List[
|
|
58
|
+
handleWorkspaceSymbol(system: NodeSystem, resultHooks: List[ResultHook], query: String): List[Json] {
|
|
59
59
|
let documentSymbols = readAllSymbols(resultHooks)
|
|
60
60
|
let workspaceSymbols = documentSymbols.flatMap {documentToWorkspaceSymbols(_, None)}
|
|
61
61
|
let foundSymbols = workspaceSymbols.filter {_.name.startsWith(query)}
|
|
62
62
|
//Log.trace("handleWorkspaceSymbol")
|
|
63
63
|
//workspaceSymbols.each {Log.show(_)}
|
|
64
|
-
let jsSymbols = foundSymbols.map {workspaceSymbolToLsp(system.
|
|
64
|
+
let jsSymbols = foundSymbols.map {workspaceSymbolToLsp(system.path("."), _)}
|
|
65
65
|
//workspaceSymbolsJs.each {Log.trace(_.toJson(None))}
|
|
66
66
|
jsSymbols
|
|
67
67
|
}
|
|
@@ -90,22 +90,22 @@ showPosition(at: Location): String {
|
|
|
90
90
|
at.line + ":" + at.column
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
documentSymbolToLsp(
|
|
94
|
-
|
|
93
|
+
documentSymbolToLsp(symbol: DocumentSymbol): Json {
|
|
94
|
+
Json.object()
|
|
95
95
|
.with("name", symbol.name)
|
|
96
96
|
.with("kind", symbol.kind)
|
|
97
|
-
.with("range", locationsToLspRange(
|
|
98
|
-
.with("selectionRange", locationsToLspRange(
|
|
99
|
-
.with("children",
|
|
97
|
+
.with("range", locationsToLspRange(symbol.start, symbol.end))
|
|
98
|
+
.with("selectionRange", locationsToLspRange(symbol.selectionStart, symbol.selectionEnd))
|
|
99
|
+
.with("children", symbol.children.toArray().map {documentSymbolToLsp(_)})
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
workspaceSymbolToLsp(
|
|
103
|
-
let o =
|
|
102
|
+
workspaceSymbolToLsp(rootPath: Path, symbol: WorkspaceSymbol): Json {
|
|
103
|
+
let o = Json.object()
|
|
104
104
|
.with("name", symbol.name)
|
|
105
105
|
.with("kind", symbol.kind)
|
|
106
|
-
.with("location",
|
|
106
|
+
.with("location", Json.object()
|
|
107
107
|
.with("uri", rootPath.path(symbol.selectionStart.file).url())
|
|
108
|
-
.with("range", locationsToLspRange(
|
|
108
|
+
.with("range", locationsToLspRange(symbol.selectionStart, symbol.selectionEnd))
|
|
109
109
|
)
|
|
110
110
|
symbol.containerName.{
|
|
111
111
|
| Some(n) => o.with("containerName", n)
|
|
@@ -113,13 +113,13 @@ workspaceSymbolToLsp(js: JsSystem, rootPath: Path, symbol: WorkspaceSymbol): JsV
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
locationsToLspRange(
|
|
117
|
-
|
|
118
|
-
.with("start",
|
|
116
|
+
locationsToLspRange(start: Location, end: Location): Json {
|
|
117
|
+
Json.object()
|
|
118
|
+
.with("start", Json.object()
|
|
119
119
|
.with("line", start.line - 1)
|
|
120
120
|
.with("character", start.column - 1)
|
|
121
121
|
)
|
|
122
|
-
.with("end",
|
|
122
|
+
.with("end", Json.object()
|
|
123
123
|
.with("line", end.line - 1)
|
|
124
124
|
.with("character", end.column - 1)
|
|
125
125
|
)
|
|
@@ -313,6 +313,14 @@ export function Array_map(self_, body_) {
|
|
|
313
313
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
export function Array_flatMap(self_, body_) {
|
|
317
|
+
const results_ = ff_core_Stack.make_();
|
|
318
|
+
ff_core_Array.Array_each(self_, ((x_) => {
|
|
319
|
+
ff_core_Stack.Stack_pushArray(results_, body_(x_))
|
|
320
|
+
}));
|
|
321
|
+
return ff_core_Stack.Stack_drain(results_)
|
|
322
|
+
}
|
|
323
|
+
|
|
316
324
|
export function Array_sortBy(self_, body_, ff_core_Ordering_Order$S) {
|
|
317
325
|
return ff_core_Array.Array_sortWith(self_, ((_w1, _w2) => {
|
|
318
326
|
return ff_core_Ordering_Order$S.compare_(body_(_w1), body_(_w2))
|
|
@@ -476,6 +484,14 @@ export async function Array_map$(self_, body_, $task) {
|
|
|
476
484
|
|
|
477
485
|
}
|
|
478
486
|
|
|
487
|
+
export async function Array_flatMap$(self_, body_, $task) {
|
|
488
|
+
const results_ = ff_core_Stack.make_();
|
|
489
|
+
(await ff_core_Array.Array_each$(self_, (async (x_, $task) => {
|
|
490
|
+
ff_core_Stack.Stack_pushArray(results_, (await body_(x_, $task)))
|
|
491
|
+
}), $task));
|
|
492
|
+
return ff_core_Stack.Stack_drain(results_)
|
|
493
|
+
}
|
|
494
|
+
|
|
479
495
|
export async function Array_sortBy$(self_, body_, ff_core_Ordering_Order$S, $task) {
|
|
480
496
|
return (await ff_core_Array.Array_sortWith$(self_, (async (_w1, _w2, $task) => {
|
|
481
497
|
return ff_core_Ordering_Order$S.compare_((await body_(_w1, $task)), (await body_(_w2, $task)))
|