firefly-compiler 0.4.6 → 0.4.8

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 +2 -0
  2. package/compiler/Deriver.ff +7 -0
  3. package/core/Array.ff +17 -4
  4. package/core/AssetSystem.ff +1 -1
  5. package/core/BrowserSystem.ff +27 -0
  6. package/core/List.ff +4 -0
  7. package/core/Lock.ff +2 -2
  8. package/core/Random.ff +148 -0
  9. package/core/SourceLocation.ff +27 -0
  10. package/core/Task.ff +3 -0
  11. package/core/WebSocket.ff +127 -0
  12. package/httpserver/HttpServer.ff +1 -1
  13. package/lux/Css.ff +648 -0
  14. package/lux/CssTest.ff +48 -0
  15. package/lux/Lux.ff +33 -18
  16. package/lux/Main.ff +4 -1
  17. package/output/js/ff/compiler/Builder.mjs +448 -444
  18. package/output/js/ff/compiler/Compiler.mjs +420 -416
  19. package/output/js/ff/compiler/Dependencies.mjs +393 -389
  20. package/output/js/ff/compiler/Deriver.mjs +1178 -1170
  21. package/output/js/ff/compiler/Dictionaries.mjs +1315 -1309
  22. package/output/js/ff/compiler/Environment.mjs +1025 -1015
  23. package/output/js/ff/compiler/Inference.mjs +4272 -4268
  24. package/output/js/ff/compiler/JsEmitter.mjs +5405 -5391
  25. package/output/js/ff/compiler/JsImporter.mjs +270 -266
  26. package/output/js/ff/compiler/LspHook.mjs +799 -793
  27. package/output/js/ff/compiler/Main.mjs +1691 -1675
  28. package/output/js/ff/compiler/Parser.mjs +4016 -4008
  29. package/output/js/ff/compiler/Patterns.mjs +935 -927
  30. package/output/js/ff/compiler/Resolver.mjs +2311 -2307
  31. package/output/js/ff/compiler/Substitution.mjs +1154 -1150
  32. package/output/js/ff/compiler/Syntax.mjs +12566 -12434
  33. package/output/js/ff/compiler/Token.mjs +3152 -3096
  34. package/output/js/ff/compiler/Tokenizer.mjs +597 -593
  35. package/output/js/ff/compiler/Unification.mjs +1762 -1752
  36. package/output/js/ff/compiler/Wildcards.mjs +612 -608
  37. package/output/js/ff/compiler/Workspace.mjs +695 -687
  38. package/output/js/ff/core/Any.mjs +147 -143
  39. package/output/js/ff/core/Array.mjs +573 -547
  40. package/output/js/ff/core/AssetSystem.mjs +278 -274
  41. package/output/js/ff/core/Atomic.mjs +158 -154
  42. package/output/js/ff/core/Bool.mjs +156 -152
  43. package/output/js/ff/core/Box.mjs +116 -112
  44. package/output/js/ff/core/BrowserSystem.mjs +181 -126
  45. package/output/js/ff/core/Buffer.mjs +399 -395
  46. package/output/js/ff/core/BuildSystem.mjs +300 -296
  47. package/output/js/ff/core/Channel.mjs +193 -189
  48. package/output/js/ff/core/Char.mjs +153 -149
  49. package/output/js/ff/core/Core.mjs +304 -300
  50. package/output/js/ff/core/Duration.mjs +120 -116
  51. package/output/js/ff/core/Equal.mjs +183 -179
  52. package/output/js/ff/core/Error.mjs +146 -142
  53. package/output/js/ff/core/FileHandle.mjs +154 -150
  54. package/output/js/ff/core/Float.mjs +229 -225
  55. package/output/js/ff/core/HttpClient.mjs +195 -191
  56. package/output/js/ff/core/Instant.mjs +113 -109
  57. package/output/js/ff/core/Int.mjs +269 -265
  58. package/output/js/ff/core/IntMap.mjs +284 -280
  59. package/output/js/ff/core/JsSystem.mjs +242 -238
  60. package/output/js/ff/core/JsValue.mjs +712 -708
  61. package/output/js/ff/core/List.mjs +2346 -2334
  62. package/output/js/ff/core/Lock.mjs +235 -231
  63. package/output/js/ff/core/Log.mjs +167 -163
  64. package/output/js/ff/core/Map.mjs +366 -362
  65. package/output/js/ff/core/NodeSystem.mjs +298 -294
  66. package/output/js/ff/core/Nothing.mjs +108 -104
  67. package/output/js/ff/core/Option.mjs +1023 -1015
  68. package/output/js/ff/core/Ordering.mjs +734 -730
  69. package/output/js/ff/core/Pair.mjs +337 -331
  70. package/output/js/ff/core/Path.mjs +549 -545
  71. package/output/js/ff/core/Random.mjs +340 -0
  72. package/output/js/ff/core/RbMap.mjs +1944 -1940
  73. package/output/js/ff/core/Serializable.mjs +432 -428
  74. package/output/js/ff/core/Set.mjs +258 -254
  75. package/output/js/ff/core/Show.mjs +209 -205
  76. package/output/js/ff/core/SourceLocation.mjs +273 -229
  77. package/output/js/ff/core/Stack.mjs +533 -529
  78. package/output/js/ff/core/Stream.mjs +1308 -1304
  79. package/output/js/ff/core/String.mjs +369 -365
  80. package/output/js/ff/core/StringMap.mjs +284 -280
  81. package/output/js/ff/core/Task.mjs +325 -319
  82. package/output/js/ff/core/Try.mjs +511 -507
  83. package/output/js/ff/core/Unit.mjs +155 -151
  84. package/output/js/ff/core/WebSocket.mjs +198 -0
  85. package/package.json +1 -1
  86. package/vscode/package.json +1 -1
  87. package/webserver/.firefly/include/package-lock.json +16 -0
  88. package/webserver/.firefly/include/package.json +5 -0
  89. package/webserver/.firefly/package.ff +2 -0
  90. package/webserver/WebServer.ff +608 -0
@@ -94,6 +94,7 @@ coreImports: List[DImport] =
94
94
  "Ordering"
95
95
  "Pair"
96
96
  "Path"
97
+ "Random"
97
98
  "Serializable"
98
99
  "Set"
99
100
  "Show"
@@ -105,6 +106,7 @@ coreImports: List[DImport] =
105
106
  "Task"
106
107
  "Try"
107
108
  "Unit"
109
+ "WebSocket"
108
110
  ].map {moduleName =>
109
111
  DImport(
110
112
  at = Location("<prelude>", 1, 1)
@@ -516,6 +516,12 @@ extend self: Deriver {
516
516
  let variantName = modulePrefix + "." + variant.name
517
517
  let fields = [...declaration.commonFields, ...variant.fields]
518
518
  let updateChecksum = self.makeUpdateChecksum(at, variantName, declaration, variant)
519
+ let autoResize = self.makeMethodCall(
520
+ at = at
521
+ target = EVariable(at, "serialization")
522
+ methodName = "autoResize"
523
+ arguments = [EInt(at, "1")]
524
+ )
519
525
  let setVariantIndex = self.makeMethodCall(
520
526
  at = at
521
527
  target = EField(at, False, EVariable(at, "serialization"), "buffer")
@@ -533,6 +539,7 @@ extend self: Deriver {
533
539
  patterns = [wildcardPattern, PVariantAs(at, variantName, at, Some("v"))]
534
540
  guards = []
535
541
  body = [
542
+ autoResize
536
543
  setVariantIndex
537
544
  EAssignField(at, "+", EVariable(at, "serialization"), "offset", EInt(at, "1"))
538
545
  ...fieldSerializations
package/core/Array.ff CHANGED
@@ -14,6 +14,13 @@ fillBy[T](size: Int, body: Int => T): Array[T]
14
14
  target js sync """
15
15
  return Array.from({length: size_}, (_, i) => body_(i));
16
16
  """
17
+ target js async """
18
+ const array = new Array(size_);
19
+ for(let i = 0; i < size_; i++) {
20
+ array[i] = await(body_(_i));
21
+ }
22
+ return array;
23
+ """
17
24
 
18
25
  range(size: Int): Array[Int]
19
26
  target js sync """
@@ -46,13 +53,19 @@ extend self[T]: Array[T] {
46
53
  return self_[index_]
47
54
  """
48
55
 
49
- first(): Option[T] { self.get(0) }
56
+ first(): Option[T] {self.get(0)}
57
+
58
+ last(): Option[T] {self.get(self.size() - 1)}
59
+
60
+ grabFirst(): T {self.grab(0)}
50
61
 
51
- last(): Option[T] { self.get(self.size() - 1) }
62
+ grabLast(): T {self.grab(self.size() - 1)}
52
63
 
53
- grabFirst(): T { self.grab(0) }
64
+ takeFirst(count: Int = 1): Array[T]
65
+ target js sync "return self_.slice(0, count_)"
54
66
 
55
- grabLast(): T { self.grab(self.size() - 1) }
67
+ takeLast(count: Int = 1): Array[T]
68
+ target js sync "return self_.slice(-count_)"
56
69
 
57
70
  dropFirst(count: Int = 1): Array[T]
58
71
  target js sync "return self_.slice(count_)"
@@ -22,7 +22,7 @@ extend self: AssetSystem {
22
22
  assets(path: String): AssetSystem {
23
23
  let prefix = if(path.endsWith("/")) {path} else {path + "/"}
24
24
  let streams = self.files.pairs().collect {
25
- | Pair(p, s) {p.startsWith(prefix)} => Some(Pair(p.dropFirst(prefix.size()), s))
25
+ | Pair(p, s) {p.startsWith(prefix)} => Some(Pair(p.dropFirst(prefix.size() - 1), s))
26
26
  | _ => None
27
27
  }
28
28
  AssetSystem(streams.toMap())
@@ -5,10 +5,37 @@ extend self: BrowserSystem {
5
5
  httpClient(): HttpClient
6
6
  target js async "return null"
7
7
 
8
+ webSocket(url: String): WebSocket {
9
+ WebSocket.internalOpenBrowserWebSocket(self, url)
10
+ }
11
+
8
12
  mainTask(): Task
9
13
  target js async "return self_.task_"
10
14
 
11
15
  js(): JsSystem
12
16
  target js async "return typeof globalThis !== 'undefined' ? globalThis : window"
17
+
18
+ url(): String
19
+ target js async """
20
+ return location.href;
21
+ """
22
+
23
+ urlPath(): String
24
+ target js async """
25
+ return location.pathname;
26
+ """
13
27
 
28
+ urlQuery(name: String): Option[String]
29
+ target js async """
30
+ const param = new URLSearchParams(location.search).get(name_)
31
+ if(param == null) return ff_core_Option.None();
32
+ return ff_core_Option.Some(param);
33
+ """
34
+
35
+ urlFragment(): Option[String]
36
+ target js async """
37
+ if(!location.hash.startsWith('#')) return ff_core_Option.None();
38
+ return ff_core_Option.Some(location.hash.slice(1));
39
+ """
40
+
14
41
  }
package/core/List.ff CHANGED
@@ -142,6 +142,10 @@ extend self[T]: List[T] {
142
142
  tailcall tail.each(body)
143
143
  }
144
144
  }
145
+
146
+ eachWhile(body: T => Bool): Bool {
147
+ self.all(body)
148
+ }
145
149
 
146
150
  all(body: T => Bool): Bool {
147
151
  self.{
package/core/Lock.ff CHANGED
@@ -76,7 +76,7 @@ extend self: LockCondition {
76
76
  }
77
77
  const level = self_.lock.level
78
78
  self_.lock.level = 1
79
- await ff_core.Lock_release$(self_.lock)
79
+ await ff_core_Lock.Lock_release$(self_.lock)
80
80
  try {
81
81
  await new Promise((resolve, reject) => {
82
82
  $task.controller.signal.addEventListener('abort', reject)
@@ -92,7 +92,7 @@ extend self: LockCondition {
92
92
  let acquired = false
93
93
  while(!acquired) {
94
94
  try {
95
- await ff_core.Lock_acquire$(self_.lock)
95
+ await ff_core_Lock.Lock_acquire$(self_.lock)
96
96
  self_.lock.level = level
97
97
  acquired = true
98
98
  } catch(e) {
package/core/Random.ff ADDED
@@ -0,0 +1,148 @@
1
+ class Random {}
2
+
3
+ // Using Alea PRNG by Johannes Baagøe <baagoe@baagoe.com>, 2010
4
+ // Typical use: Random.seedInstant(system.task().now())
5
+
6
+ seedInt(seed: Int): Random {
7
+ seedFloat(seed.toFloat())
8
+ }
9
+
10
+ seedFloat(seed: Float): Random {
11
+ let buffer = Buffer.make(8)
12
+ buffer.setFloat64(0, seed)
13
+ seedBuffer(buffer)
14
+ }
15
+
16
+ seedInstant(seed: Instant): Random {
17
+ seedFloat(seed.since1970.seconds)
18
+ }
19
+
20
+ seedBuffer(buffer: Buffer): Random
21
+ target js sync """
22
+ var n = 0xefc8249d;
23
+ function mash(data) {
24
+ for(var i = 0; i < data.byteLength; i++) {
25
+ n += data.getUint8(i);
26
+ var h = 0.02519603282416938 * n;
27
+ n = h >>> 0;
28
+ h -= n;
29
+ h *= n;
30
+ n = h >>> 0;
31
+ h -= n;
32
+ n += h * 0x100000000; // 2^32
33
+ }
34
+ return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
35
+ }
36
+ var space = new DataView(new Uint8Array([32]).buffer);
37
+ var r = {
38
+ s0: mash(space),
39
+ s1: mash(space),
40
+ s2: mash(space),
41
+ c: 1,
42
+ spareGauss: NaN
43
+ };
44
+ r.s0 -= mash(buffer_);
45
+ if(r.s0 < 0) r.s0 += 1;
46
+ r.s1 -= mash(buffer_);
47
+ if(r.s1 < 0) r.s1 += 1;
48
+ r.s2 -= mash(buffer_);
49
+ if(r.s2 < 0) r.s2 += 1;
50
+ return r;
51
+ """
52
+
53
+ extend self: Random {
54
+
55
+ copy(): Random
56
+ target js sync """
57
+ return {...self_};
58
+ """
59
+
60
+ nextInt(from: Int, until: Int): Int
61
+ target js sync """
62
+ return Random_nextFloat(self_, from_, until_) | 0;
63
+ """
64
+
65
+ nextFloat(from: Float, until: Float): Float
66
+ target js sync """
67
+ var t = 2091639 * self_.s0 + self_.c * 2.3283064365386963e-10; // 2^-32
68
+ self_.s0 = self_.s1;
69
+ self_.s1 = self_.s2;
70
+ var uniform = self_.s2 = t - (self_.c = t | 0);
71
+ return from_ + uniform * (until_ - from_);
72
+ """
73
+
74
+ nextBool(): Bool {
75
+ self.nextInt(0, 2) == 0
76
+ }
77
+
78
+ nextBytes(buffer: Buffer, start: Int, stop: Int): Unit {
79
+ start.until(stop).each {i =>
80
+ buffer.setUint8(i, self.nextInt(0, 256))
81
+ }
82
+ }
83
+
84
+ nextGauss(mean: Float, standardDeviation: Float): Float
85
+ target js sync """
86
+ if(!isNaN(self_.spareGauss)) {
87
+ const result = self_.spareGauss * standardDeviation_ + mean_;
88
+ self_.spareGauss = NaN;
89
+ return result;
90
+ } else {
91
+ let u = 0.5, v = 0.5, s = 0.5;
92
+ do {
93
+ u = Random_nextFloat(self_, 0.0, 1.0) * 2 - 1;
94
+ v = Random_nextFloat(self_, 0.0, 1.0) * 2 - 1;
95
+ s = u * u + v * v;
96
+ } while(s >= 1 || s == 0);
97
+ s = Math.sqrt(-2.0 * Math.log(s) / s);
98
+ self_.spareGauss = v * s;
99
+ return mean_ + standardDeviation_ * u * s;
100
+ }
101
+ """
102
+
103
+ shuffleStack[T](stack: Stack[T]): Unit {
104
+ 0.until(stack.size() - 1).each {i =>
105
+ let j = self.nextInt(0, stack.size() - i) + i
106
+ let value = stack.grab(i)
107
+ stack.set(i, stack.grab(j))
108
+ stack.set(j, value)
109
+ }
110
+ }
111
+
112
+ shuffleArray[T](array: Array[T]): Array[T] {
113
+ let stack = array.toStack()
114
+ self.shuffleStack(array.toStack())
115
+ stack.drain()
116
+ }
117
+
118
+ shuffleList[T](list: List[T]): List[T] {
119
+ let stack = list.toStack()
120
+ self.shuffleStack(list.toStack())
121
+ stack.toList()
122
+ }
123
+
124
+ sampleStack[T](count: Int, stack: Stack[T], body: T => Unit): Unit {
125
+ self.shuffleArray(stack.toArray()).takeFirst(count).each {body(_)}
126
+ }
127
+
128
+ sampleArray[T](count: Int, array: Array[T]): Array[T] {
129
+ self.shuffleArray(array).takeFirst(count)
130
+ }
131
+
132
+ sampleList[T](count: Int, list: List[T]): List[T] {
133
+ self.shuffleList(list).takeFirst(count)
134
+ }
135
+
136
+ grabStack[T](stack: Stack[T]): T {
137
+ stack.grab(self.nextInt(0, stack.size()))
138
+ }
139
+
140
+ grabArray[T](array: Array[T]): T {
141
+ array.grab(self.nextInt(0, array.size()))
142
+ }
143
+
144
+ grabList[T](list: Stack[T]): T {
145
+ list.grab(self.nextInt(0, list.size()))
146
+ }
147
+
148
+ }
@@ -39,3 +39,30 @@ extend self: SourceLocation {
39
39
  }
40
40
 
41
41
  }
42
+
43
+ instance SourceLocation: Show {
44
+ show(self: SourceLocation): String {
45
+ self.location
46
+ }
47
+ }
48
+
49
+ instance SourceLocation: Equal {
50
+ equals(a: SourceLocation, b: SourceLocation): Bool {
51
+ a.location == b.location
52
+ }
53
+ }
54
+
55
+ instance SourceLocation: Order {
56
+ compare(a: SourceLocation, b: SourceLocation): Ordering {
57
+ Ordering.compare(a.location, b.location)
58
+ }
59
+ }
60
+
61
+ instance SourceLocation: Serializable {
62
+ serializeUsing(serialization: Serialization, self: SourceLocation) {
63
+ Serializable.serializeUsing(serialization, self.location)
64
+ }
65
+ deserializeUsing(serialization: Serialization): SourceLocation {
66
+ SourceLocation(Serializable.deserializeUsing(serialization))
67
+ }
68
+ }
package/core/Task.ff CHANGED
@@ -46,6 +46,9 @@ extend self: Task {
46
46
  target js async """
47
47
  self_.controller.abort()
48
48
  """
49
+ target js sync """
50
+ self_.controller.abort()
51
+ """
49
52
 
50
53
  // Create a blocking channel with the specified capacity. The channel is not tied to the task.
51
54
  channel[T](capacity: Int = 0): Channel[T]
@@ -0,0 +1,127 @@
1
+ capability WebSocket {}
2
+
3
+ extend self: WebSocket {
4
+
5
+ readText(encoding: String = "utf8"): Option[String] {
6
+ self.readAny {_} {_.toString(encoding)}
7
+ }
8
+
9
+ readBuffer(): Option[Buffer] {
10
+ self.readAny {_.toBuffer()} {_}
11
+ }
12
+
13
+ readAny[T](fromText: String => T, fromBuffer: Buffer => T): Option[T]
14
+ target browser async """
15
+ ff_core_Task.Task_throwIfAborted($task);
16
+ while(self_.ffFront.length === 0) {
17
+ while(self_.ffBack.length !== 0) {
18
+ self_.ffFront.push(self_.ffBack.pop());
19
+ }
20
+ if(self_.ffFront.length !== 0) break;
21
+ if(self_.readyState === 3) return ff_core_Option.None();
22
+ let abort = null;
23
+ try {
24
+ await new Promise((resolve, reject) => {
25
+ self_.ffListeners.push(resolve);
26
+ if($task !== self_.ffTask) {
27
+ abort = () => {
28
+ self_.ffListeners = self_.ffListeners.filter(l => l != resolve);
29
+ reject();
30
+ };
31
+ $task.controller.signal.addEventListener('abort', abort);
32
+ }
33
+ });
34
+ } finally {
35
+ if($task !== self_.ffTask) {
36
+ $task.controller.signal.removeEventListener('abort', abort);
37
+ }
38
+ }
39
+ }
40
+ const message = self_.ffFront.pop();
41
+ if(!(message instanceof MessageEvent)) throw new Error("WebSocket error");
42
+ const data = message.data;
43
+ if(typeof data === 'string') return ff_core_Option.Some(await fromText_(data));
44
+ return ff_core_Option.Some(await fromBuffer_(new DataView(data)));
45
+ """
46
+
47
+ writeBuffer(data: Buffer): Unit
48
+ target browser async """
49
+ ff_core_Task.Task_throwIfAborted($task);
50
+ self_.send(data_);
51
+ """
52
+
53
+ writeText(data: String): Unit
54
+ target browser async """
55
+ ff_core_Task.Task_throwIfAborted($task);
56
+ self_.send(data_);
57
+ """
58
+
59
+ close(code: Int = 1000, reason: String = ""): Unit
60
+ target browser async """
61
+ if(self_.readyState === 2 || self_.readyState === 3) return;
62
+ await new Promise((resolve, reject) => {
63
+ self_.addEventListener('close', resolve);
64
+ self_.close(code_, reason !== "" ? reason : void 0);
65
+ });
66
+ return;
67
+ """
68
+
69
+ isOpen(): Bool
70
+ target browser async """
71
+ return self_.readyState === 1;
72
+ """
73
+
74
+ isClosing(): Bool
75
+ target browser async """
76
+ return self_.readyState === 2;
77
+ """
78
+
79
+ isClosed(): Bool
80
+ target browser async """
81
+ return self_.readyState === 3;
82
+ """
83
+
84
+ }
85
+
86
+ internalOpenBrowserWebSocket(browserSystem: BrowserSystem, url: String): WebSocket
87
+ target browser async """
88
+ if(typeof location !== 'undefined' && !url_.includes("://")) {
89
+ if(location.href && location.href.startsWith("http")) {
90
+ url_ = new URL(url_, location.href).href.replace(/^http/, 'ws');
91
+ }
92
+ }
93
+ const socket = new WebSocket(url_);
94
+ socket.binaryType = "arraybuffer";
95
+ socket.ffFront = [];
96
+ socket.ffBack = [];
97
+ socket.ffListeners = [];
98
+ socket.ffTask = $task;
99
+ $task.controller.signal.addEventListener('message', m => socket.ffBack.push(m));
100
+ const abort = () => socket.close();
101
+ try {
102
+ await new Promise((resolve, reject) => {
103
+ socket.onopen = resolve;
104
+ socket.onerror = reject;
105
+ $task.controller.signal.addEventListener('abort', abort);
106
+ });
107
+ } finally {
108
+ socket.onopen = null;
109
+ socket.onerror = null;
110
+ }
111
+ socket.addEventListener('close', () => {
112
+ $task.controller.signal.removeEventListener('abort', abort);
113
+ for(let i = 0; i < socket.ffListeners.length; i++) socket.ffListeners[i]();
114
+ socket.ffListeners.length = 0;
115
+ });
116
+ socket.addEventListener('message', m => {
117
+ socket.ffBack.push(m);
118
+ for(let i = 0; i < socket.ffListeners.length; i++) socket.ffListeners[i]();
119
+ socket.ffListeners.length = 0;
120
+ });
121
+ socket.addEventListener('error', e => {
122
+ socket.ffBack.push(e);
123
+ for(let i = 0; i < socket.ffListeners.length; i++) socket.ffListeners[i]();
124
+ socket.ffListeners.length = 0;
125
+ });
126
+ return socket;
127
+ """
@@ -146,7 +146,7 @@ extend self: HttpResponse {
146
146
  target node async """
147
147
  import * as http from 'http'
148
148
  ff_core_Task.Task_throwIfAborted($task)
149
- if(!self_.write(buffer_)) {
149
+ if(!self_.write(Buffer.from(buffer_.buffer))) {
150
150
  let reject = null;
151
151
  await new Promise((resolve, reject) => {
152
152
  const abort = () => {