firefly-compiler 0.4.18 → 0.4.20
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/compiler/Builder.ff +1 -1
- package/compiler/Compiler.ff +6 -5
- package/compiler/Inference.ff +31 -19
- package/compiler/JsEmitter.ff +98 -71
- package/compiler/JsImporter.ff +1 -1
- package/compiler/LspHook.ff +17 -5
- package/compiler/Main.ff +6 -6
- package/compiler/Parser.ff +50 -52
- package/compiler/Patterns.ff +2 -0
- package/compiler/Syntax.ff +1 -1
- package/compiler/Tokenizer.ff +2 -2
- package/compiler/Workspace.ff +2 -2
- package/core/Array.ff +135 -294
- package/core/Buffer.ff +3 -3
- package/core/BuildSystem.ff +1 -1
- package/core/Equal.ff +36 -52
- package/core/HttpClient.ff +1 -1
- package/core/IntMap.ff +14 -18
- package/core/JsSystem.ff +1 -1
- package/core/JsValue.ff +6 -12
- package/core/Json.ff +21 -30
- package/core/List.ff +281 -312
- package/core/Map.ff +4 -8
- package/core/NodeSystem.ff +2 -2
- package/core/Option.ff +0 -4
- package/core/Ordering.ff +10 -6
- package/core/Pair.ff +0 -4
- package/core/Random.ff +12 -26
- package/core/RbMap.ff +216 -216
- package/core/Serializable.ff +9 -18
- package/core/Set.ff +0 -1
- package/core/SourceLocation.ff +1 -1
- package/core/Stream.ff +10 -14
- package/core/String.ff +24 -6
- package/core/StringMap.ff +15 -19
- package/guide/Main.ff +20 -2
- package/lsp/CompletionHandler.ff +18 -18
- package/lsp/Handler.ff +45 -34
- package/lsp/HoverHandler.ff +2 -2
- package/lsp/LanguageServer.ff +2 -2
- package/lsp/SignatureHelpHandler.ff +1 -1
- package/lsp/SymbolHandler.ff +19 -5
- package/lux/Lux.ff +3 -3
- package/output/js/ff/compiler/Builder.mjs +19 -21
- package/output/js/ff/compiler/Compiler.mjs +18 -20
- package/output/js/ff/compiler/Dependencies.mjs +8 -10
- package/output/js/ff/compiler/Deriver.mjs +234 -236
- package/output/js/ff/compiler/Dictionaries.mjs +6 -8
- package/output/js/ff/compiler/Environment.mjs +42 -44
- package/output/js/ff/compiler/Inference.mjs +346 -304
- package/output/js/ff/compiler/JsEmitter.mjs +907 -833
- package/output/js/ff/compiler/JsImporter.mjs +0 -2
- package/output/js/ff/compiler/LspHook.mjs +872 -51
- package/output/js/ff/compiler/Main.mjs +109 -111
- package/output/js/ff/compiler/Parser.mjs +427 -441
- package/output/js/ff/compiler/Patterns.mjs +64 -50
- package/output/js/ff/compiler/Resolver.mjs +36 -38
- package/output/js/ff/compiler/Substitution.mjs +4 -6
- package/output/js/ff/compiler/Syntax.mjs +160 -162
- package/output/js/ff/compiler/Token.mjs +52 -54
- package/output/js/ff/compiler/Tokenizer.mjs +16 -18
- package/output/js/ff/compiler/Unification.mjs +24 -26
- package/output/js/ff/compiler/Wildcards.mjs +0 -2
- package/output/js/ff/compiler/Workspace.mjs +18 -20
- package/output/js/ff/core/Any.mjs +0 -2
- package/output/js/ff/core/Array.mjs +216 -613
- package/output/js/ff/core/AssetSystem.mjs +2 -4
- package/output/js/ff/core/Atomic.mjs +0 -2
- package/output/js/ff/core/Bool.mjs +0 -2
- package/output/js/ff/core/Box.mjs +0 -2
- package/output/js/ff/core/BrowserSystem.mjs +0 -2
- package/output/js/ff/core/Buffer.mjs +0 -2
- package/output/js/ff/core/BuildSystem.mjs +12 -14
- package/output/js/ff/core/Channel.mjs +0 -2
- package/output/js/ff/core/Char.mjs +0 -2
- package/output/js/ff/core/Core.mjs +0 -2
- package/output/js/ff/core/Duration.mjs +0 -2
- package/output/js/ff/core/Equal.mjs +0 -22
- package/output/js/ff/core/Error.mjs +0 -2
- package/output/js/ff/core/FileHandle.mjs +0 -2
- package/output/js/ff/core/Float.mjs +0 -2
- package/output/js/ff/core/HttpClient.mjs +2 -4
- package/output/js/ff/core/Instant.mjs +0 -2
- package/output/js/ff/core/Int.mjs +8 -10
- package/output/js/ff/core/IntMap.mjs +32 -42
- package/output/js/ff/core/JsSystem.mjs +1 -3
- package/output/js/ff/core/JsValue.mjs +5 -12
- package/output/js/ff/core/Json.mjs +25 -58
- package/output/js/ff/core/List.mjs +648 -1989
- package/output/js/ff/core/Lock.mjs +0 -2
- package/output/js/ff/core/Log.mjs +0 -2
- package/output/js/ff/core/Map.mjs +10 -20
- package/output/js/ff/core/NodeSystem.mjs +6 -8
- package/output/js/ff/core/Nothing.mjs +0 -2
- package/output/js/ff/core/Option.mjs +8 -18
- package/output/js/ff/core/Ordering.mjs +20 -98
- package/output/js/ff/core/Pair.mjs +6 -16
- package/output/js/ff/core/Path.mjs +12 -14
- package/output/js/ff/core/Random.mjs +24 -54
- package/output/js/ff/core/RbMap.mjs +54 -56
- package/output/js/ff/core/Serializable.mjs +19 -36
- package/output/js/ff/core/Set.mjs +0 -14
- package/output/js/ff/core/Show.mjs +0 -2
- package/output/js/ff/core/SourceLocation.mjs +0 -2
- package/output/js/ff/core/Stream.mjs +34 -44
- package/output/js/ff/core/String.mjs +31 -5
- package/output/js/ff/core/StringMap.mjs +32 -42
- package/output/js/ff/core/Task.mjs +0 -2
- package/output/js/ff/core/Try.mjs +0 -2
- package/output/js/ff/core/Unit.mjs +0 -2
- package/package.json +1 -1
- package/vscode/client/src/extension.ts +30 -2
- package/vscode/package.json +17 -1
- package/webserver/WebServer.ff +8 -8
- package/core/Stack.ff +0 -263
- package/output/js/ff/core/Stack.mjs +0 -603
package/core/Stream.ff
CHANGED
|
@@ -337,18 +337,14 @@ extend self[T]: Stream[T] {
|
|
|
337
337
|
result
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
toStack(): Stack[T] {
|
|
341
|
-
let stack = Stack.make()
|
|
342
|
-
self.each {stack.push(_)}
|
|
343
|
-
stack
|
|
344
|
-
}
|
|
345
|
-
|
|
346
340
|
toArray(): Array[T] {
|
|
347
|
-
|
|
341
|
+
let array = Array.make()
|
|
342
|
+
self.each {array.push(_)}
|
|
343
|
+
array
|
|
348
344
|
}
|
|
349
345
|
|
|
350
346
|
toList(): List[T] {
|
|
351
|
-
self.
|
|
347
|
+
self.toArray().drain()
|
|
352
348
|
}
|
|
353
349
|
|
|
354
350
|
}
|
|
@@ -361,20 +357,20 @@ extend self[T]: Stream[Stream[T]] {
|
|
|
361
357
|
|
|
362
358
|
extend self[T: Order]: Stream[T] {
|
|
363
359
|
toSet(): Set[T] {
|
|
364
|
-
self.
|
|
360
|
+
self.toList().toSet()
|
|
365
361
|
}
|
|
366
362
|
}
|
|
367
363
|
|
|
368
364
|
extend self[K: Order, V]: Stream[Pair[K, V]] {
|
|
369
365
|
toMap(): Map[K, V] {
|
|
370
|
-
self.
|
|
366
|
+
self.toList().toMap()
|
|
371
367
|
}
|
|
372
368
|
}
|
|
373
369
|
|
|
374
370
|
extend self: Stream[Buffer] {
|
|
375
371
|
|
|
376
372
|
toBuffer(): Buffer {
|
|
377
|
-
let builder =
|
|
373
|
+
let builder = Array.make()
|
|
378
374
|
self.each {builder.push(_)}
|
|
379
375
|
Buffer.fromBufferArray(builder.drain())
|
|
380
376
|
}
|
|
@@ -383,9 +379,9 @@ extend self: Stream[Buffer] {
|
|
|
383
379
|
self.toBuffer().toString(encoding)
|
|
384
380
|
}
|
|
385
381
|
|
|
386
|
-
readBytes(bytes: Int): Pair[
|
|
387
|
-
if(bytes <= 0) {Pair([]
|
|
388
|
-
let buffers =
|
|
382
|
+
readBytes(bytes: Int): Pair[List[Buffer], Stream[Buffer]] {
|
|
383
|
+
if(bytes <= 0) {Pair([], self)} else:
|
|
384
|
+
let buffers = Array.make()
|
|
389
385
|
mutable buffer = self.next().grab()
|
|
390
386
|
mutable taken = 0
|
|
391
387
|
mutable remainder = None
|
package/core/String.ff
CHANGED
|
@@ -67,7 +67,7 @@ extend self: String {
|
|
|
67
67
|
slice(from: Int, until: Int): String
|
|
68
68
|
target js sync "return self_.slice(from_, until_)"
|
|
69
69
|
|
|
70
|
-
split(char: Char):
|
|
70
|
+
split(char: Char): List[String]
|
|
71
71
|
target js sync "return self_.split(String.fromCharCode(char_))"
|
|
72
72
|
|
|
73
73
|
splitFirst(char: Char): Option[Pair[String, String]]
|
|
@@ -80,9 +80,9 @@ extend self: String {
|
|
|
80
80
|
|
|
81
81
|
lines(): List[String]
|
|
82
82
|
target js sync """
|
|
83
|
-
return
|
|
83
|
+
return self_.split(
|
|
84
84
|
new RegExp("[" + String.fromCharCode(13) + "]?[" + String.fromCharCode(10) + "]", "g")
|
|
85
|
-
)
|
|
85
|
+
)
|
|
86
86
|
"""
|
|
87
87
|
|
|
88
88
|
dropFirst(count: Int = 1): String
|
|
@@ -98,10 +98,19 @@ extend self: String {
|
|
|
98
98
|
}
|
|
99
99
|
for(let i = 0; i < self_.length; i++) {
|
|
100
100
|
const c = self_.codePointAt(i)
|
|
101
|
-
if(c < 48 || c > 57) ff_core_Option.None()
|
|
101
|
+
if(c < 48 || c > 57) return ff_core_Option.None()
|
|
102
102
|
}
|
|
103
103
|
return ff_core_Option.Some(parseInt(self_, 10));
|
|
104
104
|
"""
|
|
105
|
+
|
|
106
|
+
getFloat(): Float
|
|
107
|
+
target js sync """
|
|
108
|
+
const result = parseFloat(self_, 10);
|
|
109
|
+
if(!isFinite(result)) {
|
|
110
|
+
return ff_core_Option.None()
|
|
111
|
+
}
|
|
112
|
+
return ff_core_Option.Some(result);
|
|
113
|
+
"""
|
|
105
114
|
|
|
106
115
|
grabInt(): Int
|
|
107
116
|
target js sync """
|
|
@@ -114,6 +123,15 @@ extend self: String {
|
|
|
114
123
|
}
|
|
115
124
|
return parseInt(self_, 10);
|
|
116
125
|
"""
|
|
126
|
+
|
|
127
|
+
grabFloat(): Float
|
|
128
|
+
target js sync """
|
|
129
|
+
const result = parseFloat(self_, 10);
|
|
130
|
+
if(!isFinite(result)) {
|
|
131
|
+
ff_core_Try.internalThrowGrabException_()
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
"""
|
|
117
135
|
|
|
118
136
|
first(): Option[Char]
|
|
119
137
|
target js sync """
|
|
@@ -129,9 +147,9 @@ extend self: String {
|
|
|
129
147
|
: ff_core_Option.None()
|
|
130
148
|
"""
|
|
131
149
|
|
|
132
|
-
grabFirst(): Char {
|
|
150
|
+
grabFirst(): Char {self.first().else {Try.internalThrowGrabException()}}
|
|
133
151
|
|
|
134
|
-
grabLast(): Char {
|
|
152
|
+
grabLast(): Char {self.last().else {Try.internalThrowGrabException()}}
|
|
135
153
|
|
|
136
154
|
contains(substring: String): Bool
|
|
137
155
|
target js sync "return self_.includes(substring_)"
|
package/core/StringMap.ff
CHANGED
|
@@ -40,38 +40,34 @@ extend self[V]: StringMap[V] {
|
|
|
40
40
|
target js sync "for(const [k, v] of self_) if(!body_(k, v)) break"
|
|
41
41
|
target js async "for(const [k, v] of self_) if(!await body_(k, v)) break"
|
|
42
42
|
|
|
43
|
-
toStack(): Stack[Pair[String, V]] {
|
|
44
|
-
let stack = Stack.make()
|
|
45
|
-
self.each {k, v => stack.push(Pair(k, v))}
|
|
46
|
-
stack
|
|
47
|
-
}
|
|
48
|
-
|
|
49
43
|
toArray(): Array[Pair[String, V]] {
|
|
50
|
-
|
|
44
|
+
let array = Array.make()
|
|
45
|
+
self.each {k, v => array.push(Pair(k, v))}
|
|
46
|
+
array
|
|
51
47
|
}
|
|
52
48
|
|
|
53
49
|
toList(): List[Pair[String, V]] {
|
|
54
|
-
self.toArray().
|
|
50
|
+
self.toArray().drain()
|
|
55
51
|
}
|
|
56
52
|
|
|
57
53
|
toStream(): Stream[Pair[String, V]] {
|
|
58
|
-
self.
|
|
54
|
+
self.toList().toStream()
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
toMap(): Map[String, V] {
|
|
62
|
-
self.
|
|
58
|
+
self.toList().toMap()
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
keys(): List[String] {
|
|
66
|
-
let
|
|
67
|
-
self.each {k, v =>
|
|
68
|
-
|
|
62
|
+
let array = Array.make()
|
|
63
|
+
self.each {k, v => array.push(k)}
|
|
64
|
+
array.toList()
|
|
69
65
|
}
|
|
70
66
|
|
|
71
67
|
values(): List[V] {
|
|
72
|
-
let
|
|
73
|
-
self.each {k, v =>
|
|
74
|
-
|
|
68
|
+
let array = Array.make()
|
|
69
|
+
self.each {k, v => array.push(v)}
|
|
70
|
+
array.toList()
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
copy(): StringMap[V]
|
|
@@ -84,12 +80,12 @@ extend self[V]: StringMap[V] {
|
|
|
84
80
|
|
|
85
81
|
}
|
|
86
82
|
|
|
87
|
-
extend self[V]: StringMap[
|
|
83
|
+
extend self[V]: StringMap[Array[V]] {
|
|
88
84
|
|
|
89
85
|
push(key: String, value: V) {
|
|
90
86
|
self.get(key).{
|
|
91
|
-
| None => self.set(key, [value].
|
|
92
|
-
| Some(
|
|
87
|
+
| None => self.set(key, [value].toArray())
|
|
88
|
+
| Some(array) => array.push(value)
|
|
93
89
|
}
|
|
94
90
|
}
|
|
95
91
|
|
package/guide/Main.ff
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
nodeMain(system: NodeSystem) {
|
|
2
|
-
|
|
3
|
-
system.
|
|
2
|
+
|
|
3
|
+
//let lines = system.path("data.txt").readText().lines()
|
|
4
|
+
let lines = [
|
|
5
|
+
"Monday: 22.5"
|
|
6
|
+
"Tuesday: 25.7"
|
|
7
|
+
"Wednesday: 23.9"
|
|
8
|
+
"Thursday: 22.4"
|
|
9
|
+
"Friday: 20.3"
|
|
10
|
+
""
|
|
11
|
+
"Saturday: 16.2"
|
|
12
|
+
"Sunday: 21.1 "
|
|
13
|
+
]
|
|
14
|
+
let pairs = lines.map {_.split(':')}.collect {
|
|
15
|
+
| [day, temp] => Some(Pair(day.trim(), temp.trim().grabFloat()))
|
|
16
|
+
| _ => None
|
|
17
|
+
}
|
|
18
|
+
let remaining = pairs.map {_.second}.sort().dropFirst().dropLast()
|
|
19
|
+
let average = remaining.foldLeft(0.0) {_ + _} / remaining.size()
|
|
20
|
+
system.writeLine("Average temperature: " + average)
|
|
21
|
+
|
|
4
22
|
}
|
package/lsp/CompletionHandler.ff
CHANGED
|
@@ -72,7 +72,7 @@ handleCompletion(lspHook: LspHook, toplevel: Bool, followedByOpenBracket: Bool):
|
|
|
72
72
|
completion(h.unification, h.environment, typePrefix, qualifiedByAlias, expected)
|
|
73
73
|
}
|
|
74
74
|
| InferRecordFieldHook h {h.unification.substitute(h.recordType) | TConstructor(_, n, ts)} =>
|
|
75
|
-
let fieldNames = n.split('$').
|
|
75
|
+
let fieldNames = n.split('$').dropFirst(1)
|
|
76
76
|
let fieldCompletions = fieldNames.zip(ts).map {| Pair(name, t) =>
|
|
77
77
|
let t2 = h.unification.substitute(t)
|
|
78
78
|
CompletionInfo(name, "", name, True, t2, "(\n ...\n " + name + ": " + t2.show([]) + "\n ...\n)", Some(h.expected))
|
|
@@ -162,7 +162,7 @@ handleCompletion(lspHook: LspHook, toplevel: Bool, followedByOpenBracket: Bool):
|
|
|
162
162
|
completionsToJson(completions: List[CompletionInfo]): Json {
|
|
163
163
|
Json.object()
|
|
164
164
|
.with("isIncomplete", False)
|
|
165
|
-
.with("items", completions.distinct().
|
|
165
|
+
.with("items", completions.distinct().map {| CompletionInfo i =>
|
|
166
166
|
let shownType = i.type.show([])
|
|
167
167
|
let isAlpha = i.label.first().any {_.isAsciiLetter()}
|
|
168
168
|
let isLower = i.label.first().any {_.isAsciiLower()}
|
|
@@ -228,7 +228,7 @@ completion(
|
|
|
228
228
|
|
|
229
229
|
let member = prefix.contains("_")
|
|
230
230
|
|
|
231
|
-
let members =
|
|
231
|
+
let members = Array.make()
|
|
232
232
|
|
|
233
233
|
let symbols = if(prefix == "") {
|
|
234
234
|
environment.symbols.toList().collect {
|
|
@@ -258,7 +258,7 @@ completion(
|
|
|
258
258
|
None
|
|
259
259
|
}.toMap()
|
|
260
260
|
} else {
|
|
261
|
-
members.
|
|
261
|
+
members.pushArray(exhaustiveMatchCompletion(environment, prefix, False).toArray())
|
|
262
262
|
let shorterPrefix = prefix.dropLast()
|
|
263
263
|
let recordFields = shorterPrefix.split('$').dropFirst().toSet()
|
|
264
264
|
environment.symbols.each {
|
|
@@ -748,8 +748,8 @@ toplevelCompletion(lspHook: LspHook): List[CompletionInfo] {
|
|
|
748
748
|
label = "webapp",
|
|
749
749
|
extra = " with frontend and backend",
|
|
750
750
|
snippet = [
|
|
751
|
-
"dependency ff:
|
|
752
|
-
"import
|
|
751
|
+
"dependency ff:webserver:0.0.0"
|
|
752
|
+
"import WebServer from ff:webserver"
|
|
753
753
|
""
|
|
754
754
|
"browserMain(system: BrowserSystem): Unit {"
|
|
755
755
|
" let response = system.httpClient().fetch(\"http://localhost:8080/hello\")"
|
|
@@ -758,19 +758,19 @@ toplevelCompletion(lspHook: LspHook): List[CompletionInfo] {
|
|
|
758
758
|
"}"
|
|
759
759
|
""
|
|
760
760
|
"nodeMain(system: NodeSystem): Unit {"
|
|
761
|
-
"
|
|
762
|
-
" if(request.
|
|
763
|
-
"
|
|
764
|
-
"
|
|
765
|
-
"
|
|
766
|
-
" } elseIf {request.
|
|
767
|
-
"
|
|
768
|
-
"
|
|
769
|
-
" } elseIf {request.
|
|
770
|
-
"
|
|
771
|
-
"
|
|
761
|
+
" WebServer.make(system, \"localhost\", 8080).listen {request =>"
|
|
762
|
+
" if(request.readPath() == \"/\") {"
|
|
763
|
+
" request.writeHeader(\"Content-Type\", \"text/html; charset=UTF-8\")"
|
|
764
|
+
" request.writeText(\"<!doctype html>\")"
|
|
765
|
+
" request.writeText(\"<script type='module' src='/js/script/script/WebApp.mjs'></script>\")"
|
|
766
|
+
" } elseIf {request.readPath() == \"/hello\"} {"
|
|
767
|
+
" request.writeHeader(\"Content-Type\", \"text/plain; charset=UTF-8\")"
|
|
768
|
+
" request.writeText(\"Hello from server!\")"
|
|
769
|
+
" } elseIf {request.readPath().startsWith(\"/js/\") && !request.readPath().contains(\"..\")} {"
|
|
770
|
+
" request.writeHeader(\"Content-Type\", \"text/javascript; charset=UTF-8\")"
|
|
771
|
+
" request.writeText(system.assets().readText(request.readPath()))"
|
|
772
772
|
" } else {"
|
|
773
|
-
"
|
|
773
|
+
" request.writeStatus(\"404 Not found\")"
|
|
774
774
|
" }"
|
|
775
775
|
" }"
|
|
776
776
|
"}"
|
package/lsp/Handler.ff
CHANGED
|
@@ -17,10 +17,16 @@ capability Handler(
|
|
|
17
17
|
mutable rootPath: Option[Path]
|
|
18
18
|
mutable virtualFiles: Map[String, String]
|
|
19
19
|
mutable cancelledRequests: Set[MessageId]
|
|
20
|
-
mutable responseCache: Map[
|
|
20
|
+
mutable responseCache: Map[TokenRequestCacheKey, ResultOrError]
|
|
21
21
|
mutable fileSymbolsCache: Map[String, List[DocumentSymbol]]
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
+
data TokenRequestCacheKey(
|
|
25
|
+
method: String
|
|
26
|
+
targetAt: Location
|
|
27
|
+
includeDeclaration: Bool
|
|
28
|
+
)
|
|
29
|
+
|
|
24
30
|
data MessageId {
|
|
25
31
|
MessageIdInt(id: Int)
|
|
26
32
|
MessageIdString(id: String)
|
|
@@ -77,21 +83,21 @@ extend self: Handler {
|
|
|
77
83
|
| "textDocument/completion" => self.handleCompletion(system, parameters)
|
|
78
84
|
| "textDocument/signatureHelp" => self.handleSignatureHelp(system, parameters)
|
|
79
85
|
| "textDocument/hover" =>
|
|
80
|
-
self.handleTokenRequestWithCache(system, method, parameters) {
|
|
81
|
-
self.handleHover(system, targetAt, goToDefinition = False)
|
|
86
|
+
self.handleTokenRequestWithCache(system, method, parameters) {key =>
|
|
87
|
+
self.handleHover(system, key.targetAt, goToDefinition = False)
|
|
82
88
|
}
|
|
83
89
|
| "textDocument/definition" =>
|
|
84
|
-
self.handleTokenRequestWithCache(system, method, parameters) {
|
|
85
|
-
self.handleHover(system, targetAt, goToDefinition = True)
|
|
90
|
+
self.handleTokenRequestWithCache(system, method, parameters) {key =>
|
|
91
|
+
self.handleHover(system, key.targetAt, goToDefinition = True)
|
|
86
92
|
}
|
|
87
93
|
| "textDocument/references" =>
|
|
88
|
-
self.handleTokenRequestWithCache(system, method, parameters) {
|
|
89
|
-
self.handleReferences(system, targetAt, local = False)
|
|
94
|
+
self.handleTokenRequestWithCache(system, method, parameters) {key =>
|
|
95
|
+
self.handleReferences(system, key.targetAt, key.includeDeclaration, local = False)
|
|
90
96
|
}
|
|
91
97
|
| "textDocument/rename" => self.handleRename(system, parameters)
|
|
92
98
|
| "textDocument/documentHighlight" =>
|
|
93
|
-
self.handleTokenRequestWithCache(system, method, parameters) {
|
|
94
|
-
self.handleReferences(system, targetAt, local = True)
|
|
99
|
+
self.handleTokenRequestWithCache(system, method, parameters) {key =>
|
|
100
|
+
self.handleReferences(system, key.targetAt, includeDeclaration = True, local = True)
|
|
95
101
|
}
|
|
96
102
|
| "workspace/symbol" =>
|
|
97
103
|
self.printTime(system.mainTask(), "handleWorkspaceSymbol") {
|
|
@@ -106,17 +112,21 @@ extend self: Handler {
|
|
|
106
112
|
system: NodeSystem
|
|
107
113
|
method: String
|
|
108
114
|
parameters: Map[String, Json]
|
|
109
|
-
handle:
|
|
115
|
+
handle: TokenRequestCacheKey => ResultOrError
|
|
110
116
|
): ResultOrError {
|
|
111
117
|
let targetAt = self.findTokenFromParameters(system, parameters)
|
|
112
|
-
let
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
let includeDeclaration = parameters.get("context").{
|
|
119
|
+
| Some(context) {context.field("includeDeclaration") | includeDeclaration} {includeDeclaration.getBool() | Some(b)} => b
|
|
120
|
+
| _ => True
|
|
121
|
+
}
|
|
122
|
+
let cacheKey = TokenRequestCacheKey(method, targetAt, includeDeclaration)
|
|
123
|
+
self.responseCache.get(cacheKey).{
|
|
124
|
+
| Some(hit) => hit
|
|
125
|
+
| None =>
|
|
126
|
+
let result = handle(cacheKey)
|
|
127
|
+
self.responseCache = self.responseCache.add(cacheKey, result)
|
|
128
|
+
result
|
|
129
|
+
}
|
|
120
130
|
}
|
|
121
131
|
|
|
122
132
|
handleUnsupported(): ResultOrError {
|
|
@@ -230,7 +240,7 @@ extend self: Handler {
|
|
|
230
240
|
let path = system.pathFromUrl(uri)
|
|
231
241
|
let symbols = self.getDocumentSymbolsWithCache(system, path)
|
|
232
242
|
let lspSymbols = symbols.map {SymbolHandler.documentSymbolToLsp(_)}
|
|
233
|
-
Result(Json.
|
|
243
|
+
Result(Json.array(lspSymbols).write())
|
|
234
244
|
}
|
|
235
245
|
|
|
236
246
|
getDocumentSymbols(system: NodeSystem, path: Path): List[DocumentSymbol] {
|
|
@@ -270,14 +280,14 @@ extend self: Handler {
|
|
|
270
280
|
let documentSymbols = self.getDocumentSymbolsWithCache(system, file)
|
|
271
281
|
let workspaceSymbols = documentSymbols.flatMap {SymbolHandler.documentToWorkspaceSymbols(_, None)}
|
|
272
282
|
if(query == "") {
|
|
273
|
-
workspaceSymbols.filter {_.kind ==
|
|
283
|
+
workspaceSymbols.filter {_.kind == SType}
|
|
274
284
|
} else {
|
|
275
285
|
workspaceSymbols.filter {SymbolHandler.symbolFilter(_, query)}
|
|
276
286
|
}
|
|
277
287
|
}
|
|
278
288
|
let limitedSymbols = symbols.sortBy {_.name.size()}.takeFirst(100)
|
|
279
289
|
let jsSymbols = limitedSymbols.map {SymbolHandler.workspaceSymbolToLsp(self.rootPath.grab(), _)}
|
|
280
|
-
Result(Json.
|
|
290
|
+
Result(Json.array(jsSymbols).write())
|
|
281
291
|
}
|
|
282
292
|
|
|
283
293
|
handleDidChange(system: NodeSystem, parameters: Map[String, Json]): Unit {
|
|
@@ -322,7 +332,7 @@ extend self: Handler {
|
|
|
322
332
|
line = token.startLine
|
|
323
333
|
column = token.startColumn
|
|
324
334
|
)
|
|
325
|
-
Log.show(token.followedByLeftBracket)
|
|
335
|
+
//Log.show(token.followedByLeftBracket)
|
|
326
336
|
let lspHook = LspHook.make(at = Some(completionAt), definedAt = None, insertIdentifier = True, trackSymbols = False)
|
|
327
337
|
try {
|
|
328
338
|
Builder.check(system, self.fireflyPath, system.path(completionAt.file), self.virtualFiles, lspHook, True)
|
|
@@ -373,13 +383,13 @@ extend self: Handler {
|
|
|
373
383
|
Result((o.else {Json.null()}).write())
|
|
374
384
|
}
|
|
375
385
|
|
|
376
|
-
handleReferences(system: NodeSystem, targetAt: Location, local: Bool): ResultOrError {
|
|
377
|
-
let tokens = self.findReferences(system, targetAt, local)
|
|
386
|
+
handleReferences(system: NodeSystem, targetAt: Location, includeDeclaration: Bool, local: Bool): ResultOrError {
|
|
387
|
+
let tokens = self.findReferences(system, targetAt, local, includeDeclaration)
|
|
378
388
|
let o = tokens.{
|
|
379
389
|
| None => Json.null()
|
|
380
390
|
| Some(tokens) =>
|
|
381
391
|
let lspTokens = tokens.map {self.tokenLocationToLspLocation(system, _)}
|
|
382
|
-
Json.
|
|
392
|
+
Json.array(lspTokens)
|
|
383
393
|
}
|
|
384
394
|
Result(o.write())
|
|
385
395
|
}
|
|
@@ -387,11 +397,11 @@ extend self: Handler {
|
|
|
387
397
|
handleRename(system: NodeSystem, parameters: Map[String, Json]): ResultOrError {
|
|
388
398
|
let newName = parameters.grab("newName").grabString()
|
|
389
399
|
let targetAt = self.findTokenFromParameters(system, parameters)
|
|
390
|
-
let tokens = self.findReferences(system, targetAt, False)
|
|
400
|
+
let tokens = self.findReferences(system, targetAt, local = False, includeDeclaration = True)
|
|
391
401
|
tokens.{
|
|
392
402
|
| None => Error(-32602, "Token definition not found") // InvalidParams
|
|
393
403
|
| Some([]) => Result(Json.null().write())
|
|
394
|
-
| Some([first, ...
|
|
404
|
+
| Some([first, ...] @ tokens) =>
|
|
395
405
|
let oldName = first.raw
|
|
396
406
|
Log.trace("Rename '" + oldName + "' to '" + newName + "'")
|
|
397
407
|
|
|
@@ -415,7 +425,7 @@ extend self: Handler {
|
|
|
415
425
|
}
|
|
416
426
|
}
|
|
417
427
|
|
|
418
|
-
findReferences(system: NodeSystem, targetAt: Location, local: Bool): Option[List[TokenLocation]] {
|
|
428
|
+
findReferences(system: NodeSystem, targetAt: Location, local: Bool, includeDeclaration: Bool): Option[List[TokenLocation]] {
|
|
419
429
|
let temporaryLspHook = LspHook.make(at = Some(targetAt), definedAt = None, insertIdentifier = False, trackSymbols = False)
|
|
420
430
|
try {
|
|
421
431
|
Builder.check(system, self.fireflyPath, system.path(targetAt.file), self.virtualFiles, temporaryLspHook, True)
|
|
@@ -440,8 +450,6 @@ extend self: Handler {
|
|
|
440
450
|
| _ => None
|
|
441
451
|
}.filter {at => !at.file.endsWith(">")}
|
|
442
452
|
|
|
443
|
-
//Log.trace("definedAtList: " + Show.show(definedAtList))
|
|
444
|
-
|
|
445
453
|
definedAtList.first().{
|
|
446
454
|
| Some(definedAt) =>
|
|
447
455
|
//Log.trace("handleReferences definedAt: " + Show.show(definedAt))
|
|
@@ -465,11 +473,14 @@ extend self: Handler {
|
|
|
465
473
|
h.parameters.find {_.name == n}.map {_ => a.at}
|
|
466
474
|
| InferLookupHook h => Some(h.symbol.value.usageAt)
|
|
467
475
|
| _ => None
|
|
468
|
-
}.filter {at =>
|
|
469
|
-
|
|
470
|
-
|
|
476
|
+
}.filter {at =>
|
|
477
|
+
!at.file.endsWith(">") &&
|
|
478
|
+
(includeDeclaration || at != definedAt)
|
|
479
|
+
}
|
|
471
480
|
|
|
472
|
-
let clientLocations = referencesResult.addAll(
|
|
481
|
+
let clientLocations = referencesResult.addAll(
|
|
482
|
+
if(includeDeclaration) {[definedAt]} else {[]}
|
|
483
|
+
).distinct().filter {
|
|
473
484
|
!local || _.file == targetAt.file
|
|
474
485
|
}.map {at =>
|
|
475
486
|
self.findToken(system, at)
|
package/lsp/HoverHandler.ff
CHANGED
|
@@ -18,7 +18,7 @@ handleGoToDefinition(system: NodeSystem, handler: Handler, lspHook: LspHook): Js
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
| InferRecordFieldHook h {h.unification.substitute(h.recordType) | TConstructor(_, n, ts)} =>
|
|
21
|
-
let fieldNames = n.split('$').
|
|
21
|
+
let fieldNames = n.split('$').dropFirst(1)
|
|
22
22
|
fieldNames.zip(ts).collectFirst {| Pair(name, t) =>
|
|
23
23
|
if(h.fieldName == name) {
|
|
24
24
|
h.unification.substitute(t).at // TODO: This points to the field type rather than the field name
|
|
@@ -55,7 +55,7 @@ handleHover(system: NodeSystem, handler: Handler, lspHook: LspHook): Json {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
| InferRecordFieldHook h {h.unification.substitute(h.recordType) | TConstructor(_, n, ts)} =>
|
|
58
|
-
let fieldNames = n.split('$').
|
|
58
|
+
let fieldNames = n.split('$').dropFirst(1)
|
|
59
59
|
fieldNames.zip(ts).collectFirst {| Pair(name, t) =>
|
|
60
60
|
if(h.fieldName == name) {
|
|
61
61
|
let noEffect = TConstructor(t.at, "ff:core/Nothing.Nothing", [])
|
package/lsp/LanguageServer.ff
CHANGED
|
@@ -105,13 +105,13 @@ parseRequest(system: NodeSystem, input: Stream[Buffer]): Pair[Request, Stream[Bu
|
|
|
105
105
|
let headers = headersPair.first
|
|
106
106
|
let contentLength = headers
|
|
107
107
|
.get("content-length").else {throw(BadRequestException("'content-length' header is missing"))}
|
|
108
|
-
.getInt().else {throw(BadRequestException("Value for 'content-length' is not an integer"))}
|
|
108
|
+
.trim().getInt().else {throw(BadRequestException("Value for 'content-length' is not an integer"))}
|
|
109
109
|
let bodyPair = parseRequestBody(contentLength, headersPair.second)
|
|
110
110
|
bodyPair.mapFirst {body => Request(headers, body)}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
parseRequestHeaders(input: Stream[Buffer]): Pair[Map[String, String], Stream[Buffer]] {
|
|
114
|
-
let buffers =
|
|
114
|
+
let buffers = Array.make()
|
|
115
115
|
mutable buffer = input.next().else {
|
|
116
116
|
throw(BadRequestException("End of input while parsing request headers"))
|
|
117
117
|
}
|
|
@@ -44,7 +44,7 @@ handleSignatureHelp(system: NodeSystem, lspHook: LspHook): Json {
|
|
|
44
44
|
|
|
45
45
|
pickActiveParameter(help: Json, argumentIndex: Int, parameterName: Option[String]): Json {
|
|
46
46
|
parameterName.flatMap {name =>
|
|
47
|
-
let parameters = help.field("signatures").index(0).field("parameters").grabArray()
|
|
47
|
+
let parameters = help.field("signatures").index(0).field("parameters").grabArray()
|
|
48
48
|
parameters.pairs().collectFirst {| Pair(i, p) =>
|
|
49
49
|
if(name == p.field("label").grabString().takeWhile {_.isAsciiLetterOrDigit()}) {
|
|
50
50
|
help.with("activeParameter", i)
|
package/lsp/SymbolHandler.ff
CHANGED
|
@@ -3,7 +3,7 @@ import Syntax from ff:compiler
|
|
|
3
3
|
|
|
4
4
|
data DocumentSymbol(
|
|
5
5
|
name: String
|
|
6
|
-
kind:
|
|
6
|
+
kind: DocumentSymbolKind
|
|
7
7
|
selectionStart: Location
|
|
8
8
|
selectionEnd: Location
|
|
9
9
|
start: Location
|
|
@@ -13,7 +13,7 @@ data DocumentSymbol(
|
|
|
13
13
|
|
|
14
14
|
data WorkspaceSymbol(
|
|
15
15
|
name: String
|
|
16
|
-
kind:
|
|
16
|
+
kind: DocumentSymbolKind
|
|
17
17
|
containerName: Option[String]
|
|
18
18
|
selectionStart: Location
|
|
19
19
|
selectionEnd: Location
|
|
@@ -93,16 +93,30 @@ showPosition(at: Location): String {
|
|
|
93
93
|
documentSymbolToLsp(symbol: DocumentSymbol): Json {
|
|
94
94
|
Json.object()
|
|
95
95
|
.with("name", symbol.name)
|
|
96
|
-
.with("kind", symbol.kind)
|
|
96
|
+
.with("kind", documentSymbolNumber(symbol.kind))
|
|
97
97
|
.with("range", locationsToLspRange(symbol.start, symbol.end))
|
|
98
98
|
.with("selectionRange", locationsToLspRange(symbol.selectionStart, symbol.selectionEnd))
|
|
99
|
-
.with("children", symbol.children.
|
|
99
|
+
.with("children", symbol.children.map {documentSymbolToLsp(_)})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
documentSymbolNumber(kind: DocumentSymbolKind): Int {
|
|
103
|
+
| SExtend => 3 // Namespace
|
|
104
|
+
| SFunction(True) => 6
|
|
105
|
+
| SFunction(False) => 12
|
|
106
|
+
| SInstance => 19 // Object
|
|
107
|
+
| SLet(True) => 13
|
|
108
|
+
| SLet(False) => 14
|
|
109
|
+
| SParameter => 7 // Property
|
|
110
|
+
| STrait => 11 // Interface
|
|
111
|
+
| STraitFunction => 12 // Function
|
|
112
|
+
| SType => 5
|
|
113
|
+
| SVariant => 10 // Enum
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
workspaceSymbolToLsp(rootPath: Path, symbol: WorkspaceSymbol): Json {
|
|
103
117
|
let o = Json.object()
|
|
104
118
|
.with("name", symbol.name)
|
|
105
|
-
.with("kind", symbol.kind)
|
|
119
|
+
.with("kind", documentSymbolNumber(symbol.kind))
|
|
106
120
|
.with("location", Json.object()
|
|
107
121
|
.with("uri", rootPath.path(symbol.selectionStart.file).url())
|
|
108
122
|
.with("range", locationsToLspRange(symbol.selectionStart, symbol.selectionEnd))
|
package/lux/Lux.ff
CHANGED
|
@@ -8,7 +8,7 @@ capability Lux(
|
|
|
8
8
|
mutable cssClasses: StringMap[CssClass]
|
|
9
9
|
mutable renderLock: Lock
|
|
10
10
|
mutable task: Task
|
|
11
|
-
mutable renderQueue:
|
|
11
|
+
mutable renderQueue: Array[RenderQueueItem]
|
|
12
12
|
mutable element: LuxElement
|
|
13
13
|
mutable depth: Int
|
|
14
14
|
mutable keys: Option[StringMap[JsValue]]
|
|
@@ -294,7 +294,7 @@ extend self: Lux {
|
|
|
294
294
|
let lux = luxCopy.Lux(
|
|
295
295
|
task = task
|
|
296
296
|
renderLock = task.lock()
|
|
297
|
-
renderQueue =
|
|
297
|
+
renderQueue = Array.make()
|
|
298
298
|
element = luxCopy.element.LuxElement(element = fragment)
|
|
299
299
|
)
|
|
300
300
|
try {
|
|
@@ -475,7 +475,7 @@ render(browserSystem: BrowserSystem, element: JsValue, body: Lux => Unit) {
|
|
|
475
475
|
keys = None
|
|
476
476
|
key = ""
|
|
477
477
|
attributes = None
|
|
478
|
-
renderQueue =
|
|
478
|
+
renderQueue = Array.make()
|
|
479
479
|
)
|
|
480
480
|
lux.renderLock.do(reentrant = False) {
|
|
481
481
|
body(lux)
|