firefly-compiler 0.5.46 → 0.5.48
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/.vscode/settings.json +1 -1
- package/compiler/Builder.ff +9 -1
- package/compiler/Dependencies.ff +11 -7
- package/compiler/JsEmitter.ff +75 -58
- package/core/Buffer.ff +1 -1
- package/core/Map.ff +8 -0
- package/core/RbMap.ff +16 -0
- package/core/Set.ff +3 -1
- package/experimental/IfBug.ff +8 -0
- package/experimental/site/.firefly/package.ff +3 -0
- package/experimental/site/ChatRoute.ff +26 -0
- package/experimental/site/Main.ff +40 -0
- package/experimental/site/RouteTools.ff +70 -0
- package/experimental/site/Routes.ff +13 -0
- package/experimental/site2/.firefly/package.ff +3 -0
- package/experimental/site2/ChatRoomRoute.ff +27 -0
- package/experimental/site2/Html.ff +49 -0
- package/experimental/site2/Main.ff +37 -0
- package/experimental/site2/Router.ff +23 -0
- package/lsp/LanguageServer.ff +3 -0
- package/output/js/ff/compiler/Builder.mjs +44 -2
- package/output/js/ff/compiler/Dependencies.mjs +26 -12
- package/output/js/ff/compiler/JsEmitter.mjs +698 -598
- package/output/js/ff/core/Buffer.mjs +2 -2
- package/output/js/ff/core/Map.mjs +16 -0
- package/output/js/ff/core/Path.mjs +2 -8
- package/output/js/ff/core/RbMap.mjs +112 -0
- package/output/js/ff/core/Set.mjs +24 -0
- package/package.json +1 -1
- package/vscode/package.json +1 -1
- package/webserver/WebRoute.ff +150 -0
|
@@ -140,7 +140,7 @@ return (new DataView(arrayBuffer_))
|
|
|
140
140
|
export function fromBase64_(base64_) {
|
|
141
141
|
const binaryString_ = atob(base64_);
|
|
142
142
|
const bytes_ = Uint8Array.from(binaryString_, ((char_) => {
|
|
143
|
-
return char_.
|
|
143
|
+
return char_.charCodeAt(0)
|
|
144
144
|
}));
|
|
145
145
|
return (new DataView(bytes_.buffer))
|
|
146
146
|
}
|
|
@@ -186,7 +186,7 @@ return (new DataView(arrayBuffer_))
|
|
|
186
186
|
export async function fromBase64_$(base64_, $task) {
|
|
187
187
|
const binaryString_ = atob(base64_);
|
|
188
188
|
const bytes_ = Uint8Array.from(binaryString_, ((char_) => {
|
|
189
|
-
return char_.
|
|
189
|
+
return char_.charCodeAt(0)
|
|
190
190
|
}));
|
|
191
191
|
return (new DataView(bytes_.buffer))
|
|
192
192
|
}
|
|
@@ -137,6 +137,14 @@ export function Map_get(self_, key_, ff_core_Ordering_Order$K) {
|
|
|
137
137
|
return ff_core_RbMap.RB_get(self_, key_, ff_core_Ordering_Order$K)
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
export function Map_lastBefore(self_, key_, ff_core_Ordering_Order$K) {
|
|
141
|
+
return ff_core_RbMap.RB_lastBefore(self_, key_, ff_core_Ordering_Order$K)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function Map_firstAfter(self_, key_, ff_core_Ordering_Order$K) {
|
|
145
|
+
return ff_core_RbMap.RB_firstAfter(self_, key_, ff_core_Ordering_Order$K)
|
|
146
|
+
}
|
|
147
|
+
|
|
140
148
|
export function Map_remove(self_, key_, ff_core_Ordering_Order$K) {
|
|
141
149
|
return ff_core_RbMap.delete_(key_, self_, ff_core_Ordering_Order$K)
|
|
142
150
|
}
|
|
@@ -256,6 +264,14 @@ export async function Map_get$(self_, key_, ff_core_Ordering_Order$K, $task) {
|
|
|
256
264
|
return ff_core_RbMap.RB_get(self_, key_, ff_core_Ordering_Order$K)
|
|
257
265
|
}
|
|
258
266
|
|
|
267
|
+
export async function Map_lastBefore$(self_, key_, ff_core_Ordering_Order$K, $task) {
|
|
268
|
+
return ff_core_RbMap.RB_lastBefore(self_, key_, ff_core_Ordering_Order$K)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export async function Map_firstAfter$(self_, key_, ff_core_Ordering_Order$K, $task) {
|
|
272
|
+
return ff_core_RbMap.RB_firstAfter(self_, key_, ff_core_Ordering_Order$K)
|
|
273
|
+
}
|
|
274
|
+
|
|
259
275
|
export async function Map_remove$(self_, key_, ff_core_Ordering_Order$K, $task) {
|
|
260
276
|
return ff_core_RbMap.delete_(key_, self_, ff_core_Ordering_Order$K)
|
|
261
277
|
}
|
|
@@ -428,10 +428,7 @@ dir_ = fsPromises_.opendir(self_.absolutePath_, {bufferSize: 128})
|
|
|
428
428
|
};
|
|
429
429
|
const entry_ = dir_.read();
|
|
430
430
|
if((!ff_core_JsValue.JsValue_isNull(entry_))) {
|
|
431
|
-
return ff_core_Option.Some((
|
|
432
|
-
entry_.ffPath = self_.absolutePath_;
|
|
433
|
-
return entry_
|
|
434
|
-
})())
|
|
431
|
+
return ff_core_Option.Some((entry_.ffPath = self_.absolutePath_, entry_))
|
|
435
432
|
} else return ff_core_Option.None()
|
|
436
433
|
}), (() => {
|
|
437
434
|
if((!ff_core_JsValue.JsValue_isNull(dir_))) {
|
|
@@ -729,10 +726,7 @@ dir_ = (await fsPromises_.opendir(self_.absolutePath_, {bufferSize: 128}))
|
|
|
729
726
|
};
|
|
730
727
|
const entry_ = (await dir_.read());
|
|
731
728
|
if((!ff_core_JsValue.JsValue_isNull(entry_))) {
|
|
732
|
-
return ff_core_Option.Some((
|
|
733
|
-
entry_.ffPath = self_.absolutePath_;
|
|
734
|
-
return entry_
|
|
735
|
-
})()))
|
|
729
|
+
return ff_core_Option.Some((entry_.ffPath = self_.absolutePath_, entry_))
|
|
736
730
|
} else return ff_core_Option.None()
|
|
737
731
|
}), (async ($task) => {
|
|
738
732
|
if((!ff_core_JsValue.JsValue_isNull(dir_))) {
|
|
@@ -995,6 +995,62 @@ return
|
|
|
995
995
|
}
|
|
996
996
|
}
|
|
997
997
|
|
|
998
|
+
export function RB_lastBefore(self_, key_, ff_core_Ordering_Order$K) {
|
|
999
|
+
{
|
|
1000
|
+
const _1 = self_;
|
|
1001
|
+
if(_1.E) {
|
|
1002
|
+
return ff_core_Option.None()
|
|
1003
|
+
}
|
|
1004
|
+
if(_1.T) {
|
|
1005
|
+
const l_ = _1.left_;
|
|
1006
|
+
const k_ = _1.key_;
|
|
1007
|
+
const v_ = _1.value_;
|
|
1008
|
+
const r_ = _1.right_;
|
|
1009
|
+
if(ff_core_Ordering.notBefore_(k_, key_, ff_core_Ordering_Order$K)) {
|
|
1010
|
+
return ff_core_RbMap.RB_lastBefore(l_, key_, ff_core_Ordering_Order$K)
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
{
|
|
1014
|
+
const l_ = _1.left_;
|
|
1015
|
+
const k_ = _1.key_;
|
|
1016
|
+
const v_ = _1.value_;
|
|
1017
|
+
const r_ = _1.right_;
|
|
1018
|
+
return ff_core_Option.Option_orElse(ff_core_RbMap.RB_lastBefore(r_, key_, ff_core_Ordering_Order$K), (() => {
|
|
1019
|
+
return ff_core_Option.Some(ff_core_Pair.Pair(k_, v_))
|
|
1020
|
+
}))
|
|
1021
|
+
return
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
export function RB_firstAfter(self_, key_, ff_core_Ordering_Order$K) {
|
|
1027
|
+
{
|
|
1028
|
+
const _1 = self_;
|
|
1029
|
+
if(_1.E) {
|
|
1030
|
+
return ff_core_Option.None()
|
|
1031
|
+
}
|
|
1032
|
+
if(_1.T) {
|
|
1033
|
+
const l_ = _1.left_;
|
|
1034
|
+
const k_ = _1.key_;
|
|
1035
|
+
const v_ = _1.value_;
|
|
1036
|
+
const r_ = _1.right_;
|
|
1037
|
+
if(ff_core_Ordering.notAfter_(k_, key_, ff_core_Ordering_Order$K)) {
|
|
1038
|
+
return ff_core_RbMap.RB_firstAfter(r_, key_, ff_core_Ordering_Order$K)
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
{
|
|
1042
|
+
const l_ = _1.left_;
|
|
1043
|
+
const k_ = _1.key_;
|
|
1044
|
+
const v_ = _1.value_;
|
|
1045
|
+
const r_ = _1.right_;
|
|
1046
|
+
return ff_core_Option.Option_orElse(ff_core_RbMap.RB_firstAfter(l_, key_, ff_core_Ordering_Order$K), (() => {
|
|
1047
|
+
return ff_core_Option.Some(ff_core_Pair.Pair(k_, v_))
|
|
1048
|
+
}))
|
|
1049
|
+
return
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
998
1054
|
export function RB_size(self_, ff_core_Ordering_Order$K) {
|
|
999
1055
|
{
|
|
1000
1056
|
const _1 = self_;
|
|
@@ -1188,6 +1244,62 @@ return
|
|
|
1188
1244
|
}
|
|
1189
1245
|
}
|
|
1190
1246
|
|
|
1247
|
+
export async function RB_lastBefore$(self_, key_, ff_core_Ordering_Order$K, $task) {
|
|
1248
|
+
{
|
|
1249
|
+
const _1 = self_;
|
|
1250
|
+
if(_1.E) {
|
|
1251
|
+
return ff_core_Option.None()
|
|
1252
|
+
}
|
|
1253
|
+
if(_1.T) {
|
|
1254
|
+
const l_ = _1.left_;
|
|
1255
|
+
const k_ = _1.key_;
|
|
1256
|
+
const v_ = _1.value_;
|
|
1257
|
+
const r_ = _1.right_;
|
|
1258
|
+
if(ff_core_Ordering.notBefore_(k_, key_, ff_core_Ordering_Order$K)) {
|
|
1259
|
+
return ff_core_RbMap.RB_lastBefore(l_, key_, ff_core_Ordering_Order$K)
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
{
|
|
1263
|
+
const l_ = _1.left_;
|
|
1264
|
+
const k_ = _1.key_;
|
|
1265
|
+
const v_ = _1.value_;
|
|
1266
|
+
const r_ = _1.right_;
|
|
1267
|
+
return ff_core_Option.Option_orElse(ff_core_RbMap.RB_lastBefore(r_, key_, ff_core_Ordering_Order$K), (() => {
|
|
1268
|
+
return ff_core_Option.Some(ff_core_Pair.Pair(k_, v_))
|
|
1269
|
+
}))
|
|
1270
|
+
return
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
export async function RB_firstAfter$(self_, key_, ff_core_Ordering_Order$K, $task) {
|
|
1276
|
+
{
|
|
1277
|
+
const _1 = self_;
|
|
1278
|
+
if(_1.E) {
|
|
1279
|
+
return ff_core_Option.None()
|
|
1280
|
+
}
|
|
1281
|
+
if(_1.T) {
|
|
1282
|
+
const l_ = _1.left_;
|
|
1283
|
+
const k_ = _1.key_;
|
|
1284
|
+
const v_ = _1.value_;
|
|
1285
|
+
const r_ = _1.right_;
|
|
1286
|
+
if(ff_core_Ordering.notAfter_(k_, key_, ff_core_Ordering_Order$K)) {
|
|
1287
|
+
return ff_core_RbMap.RB_firstAfter(r_, key_, ff_core_Ordering_Order$K)
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
{
|
|
1291
|
+
const l_ = _1.left_;
|
|
1292
|
+
const k_ = _1.key_;
|
|
1293
|
+
const v_ = _1.value_;
|
|
1294
|
+
const r_ = _1.right_;
|
|
1295
|
+
return ff_core_Option.Option_orElse(ff_core_RbMap.RB_firstAfter(l_, key_, ff_core_Ordering_Order$K), (() => {
|
|
1296
|
+
return ff_core_Option.Some(ff_core_Pair.Pair(k_, v_))
|
|
1297
|
+
}))
|
|
1298
|
+
return
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1191
1303
|
export async function RB_size$(self_, ff_core_Ordering_Order$K, $task) {
|
|
1192
1304
|
{
|
|
1193
1305
|
const _1 = self_;
|
|
@@ -135,6 +135,18 @@ export function Set_contains(self_, value_, ff_core_Ordering_Order$T) {
|
|
|
135
135
|
return ff_core_Map.Map_contains(self_, value_, ff_core_Ordering_Order$T)
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
export function Set_lastBefore(self_, key_, ff_core_Ordering_Order$T) {
|
|
139
|
+
return ff_core_Option.Option_map(ff_core_Map.Map_lastBefore(self_, key_, ff_core_Ordering_Order$T), ((_w1) => {
|
|
140
|
+
return _w1.first_
|
|
141
|
+
}))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function Set_firstAfter(self_, key_, ff_core_Ordering_Order$T) {
|
|
145
|
+
return ff_core_Option.Option_map(ff_core_Map.Map_firstAfter(self_, key_, ff_core_Ordering_Order$T), ((_w1) => {
|
|
146
|
+
return _w1.first_
|
|
147
|
+
}))
|
|
148
|
+
}
|
|
149
|
+
|
|
138
150
|
export function Set_size(self_, ff_core_Ordering_Order$T) {
|
|
139
151
|
return ff_core_Map.Map_size(self_, ff_core_Ordering_Order$T)
|
|
140
152
|
}
|
|
@@ -200,6 +212,18 @@ export async function Set_contains$(self_, value_, ff_core_Ordering_Order$T, $ta
|
|
|
200
212
|
return ff_core_Map.Map_contains(self_, value_, ff_core_Ordering_Order$T)
|
|
201
213
|
}
|
|
202
214
|
|
|
215
|
+
export async function Set_lastBefore$(self_, key_, ff_core_Ordering_Order$T, $task) {
|
|
216
|
+
return ff_core_Option.Option_map(ff_core_Map.Map_lastBefore(self_, key_, ff_core_Ordering_Order$T), ((_w1) => {
|
|
217
|
+
return _w1.first_
|
|
218
|
+
}))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export async function Set_firstAfter$(self_, key_, ff_core_Ordering_Order$T, $task) {
|
|
222
|
+
return ff_core_Option.Option_map(ff_core_Map.Map_firstAfter(self_, key_, ff_core_Ordering_Order$T), ((_w1) => {
|
|
223
|
+
return _w1.first_
|
|
224
|
+
}))
|
|
225
|
+
}
|
|
226
|
+
|
|
203
227
|
export async function Set_size$(self_, ff_core_Ordering_Order$T, $task) {
|
|
204
228
|
return ff_core_Map.Map_size(self_, ff_core_Ordering_Order$T)
|
|
205
229
|
}
|
package/package.json
CHANGED
package/vscode/package.json
CHANGED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import WebServer
|
|
2
|
+
|
|
3
|
+
trait P: WebParameter {
|
|
4
|
+
toRouteParameter(text: String): Option[P]
|
|
5
|
+
fromRouteParameter(value: P): String
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
instance String: WebParameter {
|
|
9
|
+
toRouteParameter(text: String): Option[String] {Some(text)} // TODO: Unescape
|
|
10
|
+
fromRouteParameter(value: String): String {value} // TODO: Escape
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
instance Int: WebParameter {
|
|
14
|
+
toRouteParameter(text: String): Option[Int] {text.getInt()}
|
|
15
|
+
fromRouteParameter(value: Int): String {"" + value}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
data WebRoute0(urlPattern: String, segments: List[String])
|
|
19
|
+
data WebRoute1[P1](urlPattern: String, segments: List[String])
|
|
20
|
+
data WebRoute2[P1, P2](urlPattern: String, segments: List[String])
|
|
21
|
+
|
|
22
|
+
new0(urlPattern: String): WebRoute0 {
|
|
23
|
+
WebRoute0(urlPattern, urlPattern.split('/').filter {s => s != ""})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
new1[P1](urlPattern: String): WebRoute1[P1] {
|
|
27
|
+
WebRoute1(urlPattern, urlPattern.split('/').filter {s => s != ""})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
new2[P1, P2](urlPattern: String): WebRoute2[P1, P2] {
|
|
31
|
+
WebRoute2(urlPattern, urlPattern.split('/').filter {s => s != ""})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
extend self: WebRoute0 {
|
|
35
|
+
toUrl(): String {
|
|
36
|
+
self.urlPattern
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
extend self[P1: WebParameter]: WebRoute1[P1] {
|
|
41
|
+
toUrl(p1: P1): String {
|
|
42
|
+
mutable result = ""
|
|
43
|
+
mutable parameter = 1
|
|
44
|
+
self.segments.each {r =>
|
|
45
|
+
result += "/"
|
|
46
|
+
if(r.startsWith("{")) {
|
|
47
|
+
if(parameter == 1) {result += fromRouteParameter(p1)}
|
|
48
|
+
parameter += 1
|
|
49
|
+
} else {
|
|
50
|
+
result += r
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if(self.urlPattern.endsWith("/")) {result += "/"}
|
|
54
|
+
result
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
extend self[P1: WebParameter, P2: WebParameter]: WebRoute2[P1, P2] {
|
|
59
|
+
toUrl(p1: P1, p2: P2): String {
|
|
60
|
+
mutable result = ""
|
|
61
|
+
mutable parameter = 0
|
|
62
|
+
self.segments.each {r =>
|
|
63
|
+
result += "/"
|
|
64
|
+
if(r.startsWith("{")) {
|
|
65
|
+
if(parameter == 1) {result += fromRouteParameter(p1)}
|
|
66
|
+
if(parameter == 2) {result += fromRouteParameter(p2)}
|
|
67
|
+
parameter += 1
|
|
68
|
+
} else {
|
|
69
|
+
result += r
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if(self.urlPattern.endsWith("/")) {result += "/"}
|
|
73
|
+
result
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
capability WebRouteHandler[C](handlers: Array[(WebRequest[WebResponse], List[String], C) => Bool])
|
|
78
|
+
|
|
79
|
+
extend self[C]: WebRouteHandler[C] {
|
|
80
|
+
|
|
81
|
+
add0(route: WebRoute0, handle: (WebRequest[WebResponse], C) => Unit) {
|
|
82
|
+
self.handlers.push {request, segments, context =>
|
|
83
|
+
if(segments != route.segments) {False} else:
|
|
84
|
+
handle(request, context)
|
|
85
|
+
True
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
add1[P1: WebParameter](route: WebRoute1[P1], handle: (WebRequest[WebResponse], C, P1) => Unit) {
|
|
90
|
+
self.handlers.push {request, segments, context =>
|
|
91
|
+
if(segments.size() != route.segments.size()) {False} else:
|
|
92
|
+
let matching = True
|
|
93
|
+
mutable p1 = None
|
|
94
|
+
segments.zip(route.segments).eachWhile {| Pair(s, r) =>
|
|
95
|
+
if(r.startsWith("{")) {
|
|
96
|
+
if(p1.isEmpty()) {
|
|
97
|
+
p1 = toRouteParameter(s)
|
|
98
|
+
!p1.isEmpty()
|
|
99
|
+
} else {
|
|
100
|
+
False
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
r == s
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if(!matching) {False} else:
|
|
107
|
+
handle(request, context, p1.grab())
|
|
108
|
+
True
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
add2[P1: WebParameter, P2: WebParameter](route: WebRoute2[P1, P2], handle: (WebRequest[WebResponse], C, P1, P2) => Unit) {
|
|
113
|
+
self.handlers.push {request, segments, context =>
|
|
114
|
+
if(segments.size() != route.segments.size()) {False} else:
|
|
115
|
+
mutable p1 = None
|
|
116
|
+
mutable p2 = None
|
|
117
|
+
mutable matching = True
|
|
118
|
+
segments.zip(route.segments).eachWhile {| Pair(s, r) =>
|
|
119
|
+
matching = if(r.startsWith("{")) {
|
|
120
|
+
if(p1.isEmpty()) {
|
|
121
|
+
p1 = toRouteParameter(s)
|
|
122
|
+
!p1.isEmpty()
|
|
123
|
+
} elseIf {p2.isEmpty()} {
|
|
124
|
+
p2 = toRouteParameter(s)
|
|
125
|
+
!p2.isEmpty()
|
|
126
|
+
} else {
|
|
127
|
+
False
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
r == s
|
|
131
|
+
}
|
|
132
|
+
matching
|
|
133
|
+
}
|
|
134
|
+
if(!matching) {False} else:
|
|
135
|
+
handle(request, context, p1.grab(), p2.grab())
|
|
136
|
+
True
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
handle(request: WebRequest[WebResponse], context: C): Bool {
|
|
141
|
+
let segments = request.readPath().split('/').filter {s => s != ""}
|
|
142
|
+
mutable handled = False
|
|
143
|
+
self.handlers.eachWhile {| handler =>
|
|
144
|
+
handled = handler(request, segments, context)
|
|
145
|
+
!handled
|
|
146
|
+
}
|
|
147
|
+
handled
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
}
|