firefly-compiler 0.4.9 → 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.
Files changed (90) hide show
  1. package/compiler/Compiler.ff +1 -0
  2. package/compiler/JsEmitter.ff +5 -3
  3. package/core/Array.ff +8 -0
  4. package/core/FileHandle.ff +6 -0
  5. package/core/Int.ff +4 -0
  6. package/core/JsSystem.ff +3 -0
  7. package/core/JsValue.ff +5 -0
  8. package/core/Json.ff +325 -0
  9. package/core/String.ff +22 -0
  10. package/lsp/Handler.ff +79 -88
  11. package/lsp/HoverHandler.ff +7 -10
  12. package/lsp/LanguageServer.ff +30 -33
  13. package/lsp/SignatureHelpHandler.ff +12 -13
  14. package/lsp/SymbolHandler.ff +17 -17
  15. package/output/js/ff/compiler/Builder.mjs +2 -0
  16. package/output/js/ff/compiler/Compiler.mjs +3 -1
  17. package/output/js/ff/compiler/Dependencies.mjs +2 -0
  18. package/output/js/ff/compiler/Deriver.mjs +2 -0
  19. package/output/js/ff/compiler/Dictionaries.mjs +2 -0
  20. package/output/js/ff/compiler/Environment.mjs +2 -0
  21. package/output/js/ff/compiler/Inference.mjs +2 -0
  22. package/output/js/ff/compiler/JsEmitter.mjs +12 -2
  23. package/output/js/ff/compiler/JsImporter.mjs +2 -0
  24. package/output/js/ff/compiler/LspHook.mjs +2 -0
  25. package/output/js/ff/compiler/Main.mjs +2 -0
  26. package/output/js/ff/compiler/Parser.mjs +2 -0
  27. package/output/js/ff/compiler/Patterns.mjs +2 -0
  28. package/output/js/ff/compiler/Resolver.mjs +2 -0
  29. package/output/js/ff/compiler/Substitution.mjs +2 -0
  30. package/output/js/ff/compiler/Syntax.mjs +2 -0
  31. package/output/js/ff/compiler/Token.mjs +2 -0
  32. package/output/js/ff/compiler/Tokenizer.mjs +2 -0
  33. package/output/js/ff/compiler/Unification.mjs +2 -0
  34. package/output/js/ff/compiler/Wildcards.mjs +2 -0
  35. package/output/js/ff/compiler/Workspace.mjs +2 -0
  36. package/output/js/ff/core/Any.mjs +2 -0
  37. package/output/js/ff/core/Array.mjs +18 -0
  38. package/output/js/ff/core/AssetSystem.mjs +2 -0
  39. package/output/js/ff/core/Atomic.mjs +2 -0
  40. package/output/js/ff/core/Bool.mjs +2 -0
  41. package/output/js/ff/core/Box.mjs +2 -0
  42. package/output/js/ff/core/BrowserSystem.mjs +2 -0
  43. package/output/js/ff/core/Buffer.mjs +2 -0
  44. package/output/js/ff/core/BuildSystem.mjs +2 -0
  45. package/output/js/ff/core/Channel.mjs +2 -0
  46. package/output/js/ff/core/Char.mjs +2 -0
  47. package/output/js/ff/core/Core.mjs +2 -0
  48. package/output/js/ff/core/Duration.mjs +2 -0
  49. package/output/js/ff/core/Equal.mjs +2 -0
  50. package/output/js/ff/core/Error.mjs +2 -0
  51. package/output/js/ff/core/FileHandle.mjs +14 -0
  52. package/output/js/ff/core/Float.mjs +2 -0
  53. package/output/js/ff/core/HttpClient.mjs +2 -0
  54. package/output/js/ff/core/Instant.mjs +2 -0
  55. package/output/js/ff/core/Int.mjs +10 -0
  56. package/output/js/ff/core/IntMap.mjs +2 -0
  57. package/output/js/ff/core/JsSystem.mjs +10 -0
  58. package/output/js/ff/core/JsValue.mjs +12 -0
  59. package/output/js/ff/core/Json.mjs +869 -0
  60. package/output/js/ff/core/List.mjs +2 -0
  61. package/output/js/ff/core/Lock.mjs +2 -0
  62. package/output/js/ff/core/Log.mjs +2 -0
  63. package/output/js/ff/core/Map.mjs +2 -0
  64. package/output/js/ff/core/NodeSystem.mjs +2 -0
  65. package/output/js/ff/core/Nothing.mjs +2 -0
  66. package/output/js/ff/core/Option.mjs +2 -0
  67. package/output/js/ff/core/Ordering.mjs +2 -0
  68. package/output/js/ff/core/Pair.mjs +2 -0
  69. package/output/js/ff/core/Path.mjs +2 -0
  70. package/output/js/ff/core/Random.mjs +2 -0
  71. package/output/js/ff/core/RbMap.mjs +2 -0
  72. package/output/js/ff/core/Serializable.mjs +2 -0
  73. package/output/js/ff/core/Set.mjs +2 -0
  74. package/output/js/ff/core/Show.mjs +2 -0
  75. package/output/js/ff/core/SourceLocation.mjs +2 -0
  76. package/output/js/ff/core/Stack.mjs +2 -0
  77. package/output/js/ff/core/Stream.mjs +2 -0
  78. package/output/js/ff/core/String.mjs +54 -0
  79. package/output/js/ff/core/StringMap.mjs +2 -0
  80. package/output/js/ff/core/Task.mjs +2 -0
  81. package/output/js/ff/core/Try.mjs +2 -0
  82. package/output/js/ff/core/Unit.mjs +2 -0
  83. package/output/js/ff/core/WebSocket.mjs +2 -0
  84. package/package.json +2 -2
  85. package/postgresql/Pg.ff +13 -13
  86. package/rpc/.firefly/package.ff +1 -0
  87. package/rpc/Rpc.ff +69 -0
  88. package/vscode/package.json +1 -1
  89. package/webserver/WebServer.ff +165 -88
  90. package/meetup/AutoCompletion.ff +0 -6
@@ -82,6 +82,7 @@ coreImports: List[DImport] =
82
82
  "Instant"
83
83
  "Int"
84
84
  "IntMap"
85
+ "Json"
85
86
  "JsValue"
86
87
  "JsSystem"
87
88
  "List"
@@ -395,11 +395,13 @@ extend self: JsEmitter {
395
395
  !effectTypeIsAsync(effect)
396
396
  } =>
397
397
  let n = name.map {escapeResolved(_)}.else {"i"}
398
- "((() => {\n" +
399
- "const size = " + self.emitArgument(at, size, async) + ";\n" +
398
+ let newAsync = self.emittingAsync && effectTypeIsAsync(effect)
399
+ let await = if(newAsync) {"await "} else {""}
400
+ await + "((() => {\n" +
401
+ "const size = " + self.emitArgument(at, size, async) + ";\n" + // Not correct if async and body isn't
400
402
  "const result = [];\n" +
401
403
  "for(let " + n + " = 0; " + n + " < size; " + n + "++) {\n" +
402
- "result.push(" + self.emitTerm(body, async) + ");\n" +
404
+ "result.push(" + self.emitTerm(body, newAsync) + ");\n" +
403
405
  "}\n" +
404
406
  "return result;\n" +
405
407
  "})())"
package/core/Array.ff CHANGED
@@ -180,6 +180,14 @@ extend self[T]: Array[T] {
180
180
  }
181
181
  return result;
182
182
  """
183
+
184
+ flatMap[S](body: T => Array[S]): Array[S] {
185
+ let results = Stack.make()
186
+ self.each {x =>
187
+ results.pushArray(body(x))
188
+ }
189
+ results.drain()
190
+ }
183
191
 
184
192
  sortBy[S: Order](body: T => S): Array[T] {
185
193
  self.sortWith {Ordering.compare(body(_), body(_))}
@@ -25,6 +25,12 @@ extend self: FileHandle {
25
25
  await self_.write(text, position.value_, encoding_)
26
26
  """
27
27
 
28
+ writeLine(text: String, position: Option[Int] = None, encoding: String = "utf8"): Unit
29
+ target js async """
30
+ ff_core_Task.Task_throwIfAborted($task)
31
+ await self_.write(text + "\\n", position.value_, encoding_)
32
+ """
33
+
28
34
  truncate(length: Int = 0): Unit
29
35
  target js async """
30
36
  ff_core_Task.Task_throwIfAborted($task)
package/core/Int.ff CHANGED
@@ -57,5 +57,9 @@ extend self: Int {
57
57
  clamp(from: Int, to: Int): Int {
58
58
  if(self <= from) {from} elseIf {self >= to} {to} else {self}
59
59
  }
60
+
61
+ pad(padding: String): String {
62
+ ("" + self).padStart(padding.size(), padding)
63
+ }
60
64
 
61
65
  }
package/core/JsSystem.ff CHANGED
@@ -22,6 +22,9 @@ extend self: JsSystem {
22
22
 
23
23
  array(values: List[JsValue]): JsValue
24
24
  target js sync "return ff_core_List.List_toArray(values_)"
25
+
26
+ json(value: Json): JsValue
27
+ target js sync "return value_"
25
28
 
26
29
  function0[R](body: () => R): JsValue
27
30
  target js sync "return body_"
package/core/JsValue.ff CHANGED
@@ -25,6 +25,11 @@ extend self: JsValue {
25
25
  if(!(self_ instanceof DataView)) throw new Error('Expected buffer, got '+ typeof self_);
26
26
  return self_
27
27
  """
28
+
29
+ grabJson(): Json
30
+ target js sync """
31
+ return self_
32
+ """
28
33
 
29
34
  equals[V: IsJsValue](value: V): Bool
30
35
  target js sync "return self_ === value_"
package/core/Json.ff ADDED
@@ -0,0 +1,325 @@
1
+ data Json {}
2
+
3
+ read(json: String): Option[Json]
4
+ target js sync """
5
+ try {
6
+ return ff_core_Option.Some(JSON.parse(json_));
7
+ } catch(e) {
8
+ return ff_core_Option.None();
9
+ }
10
+ """
11
+
12
+ string(json: String): Json
13
+ target js sync """
14
+ return json_;
15
+ """
16
+
17
+ int(json: Int): Json
18
+ target js sync """
19
+ return json_;
20
+ """
21
+
22
+ float(json: Float): Json
23
+ target js sync """
24
+ return json_;
25
+ """
26
+
27
+ bool(json: Bool): Json
28
+ target js sync """
29
+ return json_;
30
+ """
31
+
32
+ null(): Json
33
+ target js sync """
34
+ return null;
35
+ """
36
+
37
+ array(json: Array[Json]): Json
38
+ target js sync """
39
+ return json_;
40
+ """
41
+
42
+ list(json: List[Json]): Json {
43
+ array(json.toArray())
44
+ }
45
+
46
+ object(): Json
47
+ target js sync """
48
+ return {};
49
+ """
50
+
51
+ fields(body: ((String, Json) => Unit) => Unit): Json
52
+ target js sync """
53
+ const result = {};
54
+ body_((k, v) => {result[k] = v});
55
+ return result;
56
+ """
57
+ target js async """
58
+ const result = {};
59
+ await body_((k, v) => {result[k] = v}, $task);
60
+ return result;
61
+ """
62
+
63
+ extend self: Json {
64
+
65
+ write(space: Option[String] = None): String
66
+ target js sync """
67
+ return JSON.stringify(self_, null, space_.value_);
68
+ """
69
+
70
+ with[T: JsonLike](field: String, value: T): Json {
71
+ internalWith(field, toJson(value))
72
+ }
73
+
74
+ merge(that: Json): Json
75
+ target js sync """
76
+ if(typeof self_ !== 'object' || self_ === null || Array.isArray(self_)) {
77
+ throw new Error('Not an object: ' + JSON.stringify(self_));
78
+ }
79
+ if(typeof that_ !== 'object' || that_ === null || Array.isArray(that_)) {
80
+ throw new Error('Not an object: ' + JSON.stringify(that_));
81
+ }
82
+ return {...self_, ...that_};
83
+ """
84
+
85
+ grabString(): String
86
+ target js sync """
87
+ if(typeof self_ !== 'string') throw new Error('Not a string: ' + JSON.stringify(self_));
88
+ return self_;
89
+ """
90
+
91
+ grabInt(): Int
92
+ target js sync """
93
+ if(!Number.isSafeInteger(self_)) throw new Error('Not an int: ' + JSON.stringify(self_));
94
+ return Math.trunc(self_);
95
+ """
96
+
97
+ grabFloat(): Float
98
+ target js sync """
99
+ if(typeof self_ !== 'number') throw new Error('Not a float: ' + JSON.stringify(self_));
100
+ return self_;
101
+ """
102
+
103
+ grabBool(): Bool
104
+ target js sync """
105
+ if(self_ === true) return true;
106
+ if(self_ === false) return false;
107
+ throw new Error('Not a bool: ' + JSON.stringify(self_));
108
+ """
109
+
110
+ grabArray(): Array[Json]
111
+ target js sync """
112
+ if(!Array.isArray(self_)) throw new Error('Not an array: ' + JSON.stringify(self_));
113
+ return self_;
114
+ """
115
+
116
+ grabMap(): Map[String, Json] {
117
+ mutable map = Map.empty()
118
+ self.each {key, value =>
119
+ map = map.add(key, value)
120
+ }
121
+ map
122
+ }
123
+
124
+ getString(): Option[String] {
125
+ if(self.isString()) {self.grabString()}
126
+ }
127
+
128
+ getInt(): Option[Int] {
129
+ if(self.isInt()) {self.grabInt()}
130
+ }
131
+
132
+ getFloat(): Option[Float] {
133
+ if(self.isFloat()) {self.grabFloat()}
134
+ }
135
+
136
+ getBool(): Option[Bool] {
137
+ if(self.isBool()) {self.grabBool()}
138
+ }
139
+
140
+ getArray(): Option[Array[Json]] {
141
+ if(self.isArray()) {self.grabArray()}
142
+ }
143
+
144
+ getMap(): Option[Map[String, Json]] {
145
+ if(self.isObject()) {self.grabMap()}
146
+ }
147
+
148
+ isString(): Bool
149
+ target js sync """
150
+ return typeof self_ === 'string';
151
+ """
152
+
153
+ isInt(): Bool
154
+ target js sync """
155
+ return Number.isSafeInteger(self_);
156
+ """
157
+
158
+ isFloat(): Bool
159
+ target js sync """
160
+ return typeof self_ === 'number';
161
+ """
162
+
163
+ isBool(): Bool
164
+ target js sync """
165
+ return typeof self_ === 'boolean';
166
+ """
167
+
168
+ isArray(): Bool
169
+ target js sync """
170
+ return Array.isArray(self_);
171
+ """
172
+
173
+ isObject(): Bool
174
+ target js sync """
175
+ return typeof self_ === 'object' && self_ !== null && !Array.isArray(self_);
176
+ """
177
+
178
+ isNull(): Bool
179
+ target js sync """
180
+ return typeof self_ === null;
181
+ """
182
+
183
+ field(key: String): Json
184
+ target js sync """
185
+ return typeof self_ === 'object' && self_ !== null && !Array.isArray(self_) && Object.hasOwn(self_, key_)
186
+ ? self_[key_] : null;
187
+ """
188
+
189
+ index(key: Int): Json
190
+ target js sync """
191
+ return typeof self_ === 'array' ? self_[key] ?? null : null;
192
+ """
193
+
194
+ hasField(key: String): Bool
195
+ target js sync """
196
+ return typeof self_ === 'object' && self_ !== null && !Array.isArray(self_) && Object.hasOwn(self_, key_);
197
+ """
198
+
199
+ getField(key: String): Option[Json]
200
+ target js sync """
201
+ return typeof self_ === 'object' && self_ !== null && !Array.isArray(self_) && Object.hasOwn(self_, key_)
202
+ ? ff_core_Option.Some(self_[key_]) : ff_core_Option.None();
203
+ """
204
+
205
+ getIndex(key: Int): Option[Json]
206
+ target js sync """
207
+ return typeof self_ === 'array' ? ff_core_Option.Some(self_[key_] ?? null) : ff_core_Option.None();
208
+ """
209
+
210
+ getFields(): Option[Array[String]]
211
+ target js sync """
212
+ return typeof self_ === 'object' && self_ !== null && !Array.isArray(self_)
213
+ ? ff_core_Option.Some(Object.keys(self_)) : ff_core_Option.None();
214
+ """
215
+
216
+ grabField(key: String): Json {
217
+ self.getField(key).else {
218
+ throw(GrabException())
219
+ }
220
+ }
221
+
222
+ grabIndex(key: Int): Json {
223
+ self.getIndex(key).else {
224
+ throw(GrabException())
225
+ }
226
+ }
227
+
228
+ grabFields(): Array[String] {
229
+ self.getFields().else {
230
+ throw(GrabException())
231
+ }
232
+ }
233
+
234
+ map[T](body: (String, Json) => T): Array[T] {
235
+ let stack = Stack.make()
236
+ self.each {field, value => stack.push(body(field, value))}
237
+ stack.drain()
238
+ }
239
+
240
+ flatMap[T](body: (String, Json) => Array[T]): Array[T] {
241
+ let stack = Stack.make()
242
+ self.each {field, value => stack.pushArray(body(field, value))}
243
+ stack.drain()
244
+ }
245
+
246
+ each(body: (String, Json) => Unit) {
247
+ if(!self.isObject()) {throw(GrabException())}
248
+ internalEach(self, body)
249
+ }
250
+
251
+ eachWhile(body: (String, Json) => Bool) {
252
+ if(!self.isObject()) {throw(GrabException())}
253
+ internalEachWhile(self, body)
254
+ }
255
+
256
+ }
257
+
258
+ internalWith(field: String, json: Json): Json
259
+ target js sync """
260
+ if(typeof self_ !== 'object' || self_ === null || Array.isArray(self_)) {
261
+ throw new Error('Not an object: ' + JSON.stringify(self_));
262
+ }
263
+ return {...self_, [field_]: value_};
264
+ """
265
+
266
+ internalEach(self: Json, body: (String, Json) => Unit): Unit
267
+ target js sync "for(const [key, value] of Object.entries(self_)) body_(key, value)"
268
+ target js async "for(const [key, value] of Object.entries(self_)) await body_(key, value, $task)"
269
+
270
+ internalEachWhile(self: Json, body: (String, Json) => Bool): Unit
271
+ target js sync "for(const [key, value] of Object.entries(self_)) if(!body_(key, value)) break"
272
+ target js async "for(const [key, value] of Object.entries(self_)) if(!await body_(key, value, $task)) break"
273
+
274
+ trait T: JsonLike {
275
+ toJson(value: T): Json
276
+ fromJson(json: Json): Option[T]
277
+ }
278
+
279
+ instance Json: JsonLike {
280
+ toJson(value: Json): Json {value}
281
+ fromJson(json: Json): Option[Json] {Some(json)}
282
+ }
283
+
284
+ instance String: JsonLike {
285
+ toJson(value: String): Json {string(value)}
286
+ fromJson(json: Json): Option[String] {_.getString()}
287
+ }
288
+
289
+ instance Int: JsonLike {
290
+ toJson(value: Int): Json {int(value)}
291
+ fromJson(json: Json): Option[Int] {_.getInt()}
292
+ }
293
+
294
+ instance Float: JsonLike {
295
+ toJson(value: Float): Json {float(value)}
296
+ fromJson(json: Json): Option[Float] {_.getFloat()}
297
+ }
298
+
299
+ instance Bool: JsonLike {
300
+ toJson(value: Bool): Json {bool(value)}
301
+ fromJson(json: Json): Option[Bool] {_.getBool()}
302
+ }
303
+
304
+ instance Array[T: JsonLike]: JsonLike {
305
+ toJson(value: Array[T]): Json {array(value.map(toJson))}
306
+ fromJson(json: Json): Option[Array[T]] {
307
+ json.getArray().flatMap {array =>
308
+ mutable convertible = True
309
+ let stack = Stack.make()
310
+ array.eachWhile {item =>
311
+ fromJson(item).{
312
+ | None => convertible = False
313
+ | Some(value) => stack.push(value)
314
+ }
315
+ convertible
316
+ }
317
+ if(convertible) {stack.drain()}
318
+ }
319
+ }
320
+ }
321
+
322
+ instance List[T: JsonLike]: JsonLike {
323
+ toJson(value: List[T]): Json {list(value.map(toJson))}
324
+ fromJson(json: Json): Option[List[T]] {fromJson[Array[T]](json).map {_.toList()}}
325
+ }
package/core/String.ff CHANGED
@@ -22,6 +22,18 @@ extend self: String {
22
22
  reverse(): String
23
23
  target js sync "return [...self_].reverse().join('')"
24
24
 
25
+ repeat(count: Int): String
26
+ target js sync "return self_.repeat(count_)"
27
+
28
+ trim(): String
29
+ target js sync "return self_.trim()"
30
+
31
+ trimStart(): String
32
+ target js sync "return self_.trimStart()"
33
+
34
+ trimEnd(): String
35
+ target js sync "return self_.trimEnd()"
36
+
25
37
  lower(): String
26
38
  target js sync "return self_.toLowerCase()"
27
39
 
@@ -137,6 +149,16 @@ extend self: String {
137
149
  removeLast(suffix: String): Option[String] {
138
150
  if(self.endsWith(suffix)) {Some(self.dropLast(suffix.size()))} else {None}
139
151
  }
152
+
153
+ padStart(length: Int, padding: String = " "): String
154
+ target js sync """
155
+ return self_.padStart(length_, padding_);
156
+ """
157
+
158
+ padEnd(length: Int, padding: String = " "): String
159
+ target js sync """
160
+ return self_.padEnd(length_, padding_);
161
+ """
140
162
 
141
163
  any(body: Char => Bool): Bool
142
164
  target js sync """