firefly-compiler 0.4.10 → 0.4.12

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 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(_))}
@@ -78,6 +78,9 @@ extend self: FetchResponse {
78
78
  readText(): String
79
79
  target js async "return await self_.text()"
80
80
 
81
+ readJson(): Json
82
+ target js async "return await self_.json()"
83
+
81
84
  readBuffer(): Buffer
82
85
  target js async "return new DataView(await self_.arrayBuffer())"
83
86
 
package/core/JsValue.ff CHANGED
@@ -213,9 +213,6 @@ extend self: JsValue {
213
213
  target js sync "return new self_(a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_)"
214
214
 
215
215
 
216
- toJson(space: Option[String] = None): String
217
- target js sync "return JSON.stringify(self_, null, space_.value_)"
218
-
219
216
  grabPairs(): List[Pair[String, JsValue]]
220
217
  target js sync """
221
218
  if(!(self_ instanceof Object)) throw new Error('Expected object, got '+ typeof self_);;
package/core/Json.ff CHANGED
@@ -9,11 +9,6 @@ read(json: String): Option[Json]
9
9
  }
10
10
  """
11
11
 
12
- write(json: Json, space: Option[String] = None): String
13
- target js sync """
14
- return JSON.stringify(json_, null, space_.value_);
15
- """
16
-
17
12
  string(json: String): Json
18
13
  target js sync """
19
14
  return json_;
@@ -53,17 +48,30 @@ object(): Json
53
48
  return {};
54
49
  """
55
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
+
56
63
  extend self: Json {
57
64
 
58
- with(field: String, value: Json)
65
+ write(indentation: Option[String] = None): String
59
66
  target js sync """
60
- if(typeof self_ !== 'object' || self_ === null || Array.isArray(self_)) {
61
- throw new Error('Not an object: ' + JSON.stringify(self_));
62
- }
63
- return {...self_, [field_]: value_};
67
+ return JSON.stringify(self_, null, space_.value_);
64
68
  """
69
+
70
+ with[T: JsonLike](field: String, value: T): Json {
71
+ internalWith(self, field, toJson(value))
72
+ }
65
73
 
66
- merge(that: Json)
74
+ merge(that: Json): Json
67
75
  target js sync """
68
76
  if(typeof self_ !== 'object' || self_ === null || Array.isArray(self_)) {
69
77
  throw new Error('Not an object: ' + JSON.stringify(self_));
@@ -104,6 +112,38 @@ extend self: Json {
104
112
  if(!Array.isArray(self_)) throw new Error('Not an array: ' + JSON.stringify(self_));
105
113
  return self_;
106
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
+ }
107
147
 
108
148
  isString(): Bool
109
149
  target js sync """
@@ -151,6 +191,11 @@ extend self: Json {
151
191
  return typeof self_ === 'array' ? self_[key] ?? null : null;
152
192
  """
153
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
+
154
199
  getField(key: String): Option[Json]
155
200
  target js sync """
156
201
  return typeof self_ === 'object' && self_ !== null && !Array.isArray(self_) && Object.hasOwn(self_, key_)
@@ -191,6 +236,12 @@ extend self: Json {
191
236
  self.each {field, value => stack.push(body(field, value))}
192
237
  stack.drain()
193
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
+ }
194
245
 
195
246
  each(body: (String, Json) => Unit) {
196
247
  if(!self.isObject()) {throw(GrabException())}
@@ -204,6 +255,14 @@ extend self: Json {
204
255
 
205
256
  }
206
257
 
258
+ internalWith(self: Json, 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
+
207
266
  internalEach(self: Json, body: (String, Json) => Unit): Unit
208
267
  target js sync "for(const [key, value] of Object.entries(self_)) body_(key, value)"
209
268
  target js async "for(const [key, value] of Object.entries(self_)) await body_(key, value, $task)"
@@ -211,3 +270,174 @@ internalEach(self: Json, body: (String, Json) => Unit): Unit
211
270
  internalEachWhile(self: Json, body: (String, Json) => Bool): Unit
212
271
  target js sync "for(const [key, value] of Object.entries(self_)) if(!body_(key, value)) break"
213
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
+ }
326
+
327
+ instance StringMap[T: JsonLike]: JsonLike {
328
+ toJson(value: StringMap[T]): Json {
329
+ Json.fields {setField =>
330
+ value.each {key, value => setField(key, toJson(value))}
331
+ }
332
+ }
333
+ fromJson(json: Json): Option[StringMap[T]] {
334
+ if(json.isObject()) {
335
+ let map = StringMap.make()
336
+ mutable convertible = True
337
+ json.eachWhile {key, value =>
338
+ fromJson(value).{
339
+ | None => convertible = False
340
+ | Some(v) => map.set(key, v)
341
+ }
342
+ convertible
343
+ }
344
+ if(convertible) {map}
345
+ }.flatten()
346
+ }
347
+ }
348
+
349
+
350
+ instance Json: HasAnyTag {
351
+ anyTag(): AnyTag[Json] {Any.internalAnyTag("ff:core/Json.Json[]")}
352
+ }
353
+
354
+ instance Json: Show {
355
+ show(value: Json): String {value.write(Some(" "))}
356
+ }
357
+
358
+ instance Json: Equal {
359
+ equals(a: Json, b: Json): Bool {
360
+ internalEquals(a, b)
361
+ }
362
+ }
363
+
364
+ instance Json: Order {
365
+ compare(a: Json, b: Json): Ordering {
366
+ Ordering.fromInt(internalCompare(a, b))
367
+ }
368
+ }
369
+
370
+ instance Json: Serializable {
371
+ serializeUsing(serialization: Serialization, value: Json): Unit {
372
+ Serializable.serializeUsing(serialization, value.write())
373
+ }
374
+ deserializeUsing(serialization: Serialization): Json {
375
+ Json.read(Serializable.deserializeUsing[String](serialization)).grab()
376
+ }
377
+ }
378
+
379
+
380
+ internalEquals(a: Json, b: Json): Bool
381
+ target js sync """
382
+ if(a_ === b_) {
383
+ return true;
384
+ } else if(Array.isArray(a_) || Array.isArray(b_)) {
385
+ if(!Array.isArray(a_) || !Array.isArray(b_)) return false;
386
+ if(a_.length !== b_.length) return false;
387
+ for(let i = 0; i < a_.length; i++) {
388
+ if(!internalEquals_(a_[i], b_[i])) return false;
389
+ }
390
+ return true;
391
+ } else if(typeof a_ === 'object' && typeof b_ === 'object' && a_ !== null && b_ !== null) {
392
+ const aKeys = Object.keys(a_);
393
+ const bKeys = Object.keys(b_);
394
+ if(aKeys.length !== bKeys.length) return false;
395
+ for(const key of aKeys) {
396
+ if(!Object.hasOwn(b_, key) || !internalEquals_(a_[key], b_[key])) return false;
397
+ }
398
+ return true;
399
+ } else {
400
+ return false;
401
+ }
402
+ """
403
+
404
+ internalCompare(a: Json, b: Json): Int
405
+ target js sync """
406
+ if(a_ === b_) {
407
+ return 0;
408
+ } else if (a_ === null || b_ === null) {
409
+ return a_ === null ? -1 : 1;
410
+ } else if (typeof a_ === 'boolean' || typeof b_ === 'boolean') {
411
+ if(typeof b_ !== 'boolean') return -1;
412
+ if(typeof a_ !== 'boolean') return 1;
413
+ return a_ < b_ ? -1 : 1;
414
+ } else if (typeof a_ === 'number' || typeof b_ === 'number') {
415
+ if(typeof b_ !== 'number') return -1;
416
+ if(typeof a_ !== 'number') return 1;
417
+ if(isNaB(a_)) return isNaB(b_) ? 0 : -1;
418
+ if(isNaB(b_)) return 1;
419
+ return a_ < b_ ? -1 : 1;
420
+ } else if (typeof a_ === 'string' || typeof b_ === 'string') {
421
+ if(typeof b_ !== 'string') return -1;
422
+ if(typeof a_ !== 'string') return 1;
423
+ return a_.localeCompare(b_, 'en');
424
+ } else if(Array.isArray(a_) || Array.isArray(b_)) {
425
+ if(!Array.isArray(a_) || !Array.isArray(b_)) return a_ < b_ ? -1 : 1;
426
+ const length = Math.min(a_.length, b_.length);
427
+ for(let i = 0; i < length; i++) {
428
+ const cmp = internalCompare_(a_[i], b_[i]);
429
+ if(cmp !== 0) return cmp;
430
+ }
431
+ return a_.length - b_.length;
432
+ } else {
433
+ const aKeys = Object.keys(a_).sort();
434
+ const bKeys = Object.keys(b_).sort();
435
+ const keyResult = internalCompare_(aKeys, bKeys);
436
+ if(keyResult !== 0) return keyResult;
437
+ for(const key of aKeys) {
438
+ const result = internalCompare_(a_[key], b_[key]);
439
+ if(result !== 0) return result;
440
+ }
441
+ return 0;
442
+ }
443
+ """
@@ -15,7 +15,7 @@ data CompletionInfo(
15
15
  secondarySort: Int = 5
16
16
  )
17
17
 
18
- handleCompletion(system: NodeSystem, lspHook: LspHook, toplevel: Bool, followedByOpenBracket: Bool): JsValue {
18
+ handleCompletion(lspHook: LspHook, toplevel: Bool, followedByOpenBracket: Bool): Json {
19
19
  let topLevelCompletions = if(!toplevel) {[]} else {toplevelCompletion(lspHook)}
20
20
  let patternCompletions = lspHook.results().collectFirst {
21
21
  | InferPatternHook h =>
@@ -156,11 +156,11 @@ handleCompletion(system: NodeSystem, lspHook: LspHook, toplevel: Bool, followedB
156
156
  } else {c}
157
157
  }
158
158
  }
159
- completionsToJson(system.js(), [...fixedCompletions, ...fixedTypeCompletions, ...topLevelCompletions])
159
+ completionsToJson([...fixedCompletions, ...fixedTypeCompletions, ...topLevelCompletions])
160
160
  }
161
161
 
162
- completionsToJson(js: JsSystem, completions: List[CompletionInfo]): JsValue {
163
- js.object()
162
+ completionsToJson(completions: List[CompletionInfo]): Json {
163
+ Json.object()
164
164
  .with("isIncomplete", False)
165
165
  .with("items", completions.distinct().toArray().map {| CompletionInfo i =>
166
166
  let shownType = i.type.show([])
@@ -179,7 +179,7 @@ completionsToJson(js: JsSystem, completions: List[CompletionInfo]): JsValue {
179
179
  | Pair(TConstructor(_, n1, _), Some(TConstructor(_, n2, _))) => n1 == n2
180
180
  | _ => False
181
181
  }
182
- js.object()
182
+ Json.object()
183
183
  // Namespace or Property or Constructor or EnumMember or Constructor or Method/Function or Field/Variable
184
184
  .with("kind"
185
185
  if(shownType == "") {3} else:
@@ -192,12 +192,12 @@ completionsToJson(js: JsSystem, completions: List[CompletionInfo]): JsValue {
192
192
  .with("sortText", sortText)
193
193
  .with("preselect", preselect)
194
194
  .with("label", i.label)
195
- .with("labelDetails", js.object()
195
+ .with("labelDetails", Json.object()
196
196
  .with("detail", i.extra + if(shownType == "") {""} else {": " + shownType})
197
197
  )
198
198
  .with("insertText", i.snippet)
199
199
  .with("insertTextFormat", 2 /* Snippet */)
200
- .with("documentation", js.object()
200
+ .with("documentation", Json.object()
201
201
  .with("kind", "markdown")
202
202
  .with("value", "```\n" + i.documentation + "\n```")
203
203
  )