firefly-compiler 0.4.4
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/.firefly-workspace +1 -0
- package/.vscode/settings.json +5 -0
- package/LICENSE.txt +21 -0
- package/README.md +96 -0
- package/bin/firefly.mjs +2 -0
- package/compiler/.firefly/package.ff +1 -0
- package/compiler/Builder.ff +218 -0
- package/compiler/Compiler.ff +241 -0
- package/compiler/Dependencies.ff +179 -0
- package/compiler/Deriver.ff +647 -0
- package/compiler/Dictionaries.ff +205 -0
- package/compiler/Environment.ff +166 -0
- package/compiler/Inference.ff +1117 -0
- package/compiler/JsEmitter.ff +861 -0
- package/compiler/JsImporter.ff +56 -0
- package/compiler/LspHook.ff +188 -0
- package/compiler/Main.ff +237 -0
- package/compiler/Parser.ff +1383 -0
- package/compiler/Patterns.ff +111 -0
- package/compiler/Resolver.ff +620 -0
- package/compiler/Substitution.ff +178 -0
- package/compiler/Syntax.ff +299 -0
- package/compiler/Token.ff +180 -0
- package/compiler/Tokenizer.ff +278 -0
- package/compiler/Unification.ff +220 -0
- package/compiler/Wildcards.ff +50 -0
- package/compiler/Workspace.ff +88 -0
- package/core/.firefly/package.ff +2 -0
- package/core/Any.ff +30 -0
- package/core/Array.ff +249 -0
- package/core/AssetSystem.ff +61 -0
- package/core/Atomic.ff +64 -0
- package/core/Bool.ff +13 -0
- package/core/BrowserSystem.ff +14 -0
- package/core/Buffer.ff +211 -0
- package/core/BuildSystem.ff +144 -0
- package/core/Channel.ff +131 -0
- package/core/Char.ff +18 -0
- package/core/Core.ff +58 -0
- package/core/Duration.ff +15 -0
- package/core/Equal.ff +52 -0
- package/core/Error.ff +20 -0
- package/core/FileHandle.ff +41 -0
- package/core/Float.ff +41 -0
- package/core/HttpClient.ff +84 -0
- package/core/Instant.ff +9 -0
- package/core/Int.ff +61 -0
- package/core/IntMap.ff +85 -0
- package/core/JsSystem.ff +66 -0
- package/core/JsValue.ff +240 -0
- package/core/List.ff +440 -0
- package/core/Lock.ff +144 -0
- package/core/Log.ff +24 -0
- package/core/Map.ff +126 -0
- package/core/NodeSystem.ff +88 -0
- package/core/Nothing.ff +1 -0
- package/core/Option.ff +133 -0
- package/core/Ordering.ff +157 -0
- package/core/Pair.ff +55 -0
- package/core/Path.ff +393 -0
- package/core/RbMap.ff +216 -0
- package/core/Serializable.ff +173 -0
- package/core/Set.ff +38 -0
- package/core/Show.ff +43 -0
- package/core/Stack.ff +263 -0
- package/core/Stream.ff +406 -0
- package/core/String.ff +175 -0
- package/core/StringMap.ff +85 -0
- package/core/Task.ff +138 -0
- package/core/Try.ff +81 -0
- package/core/Unit.ff +3 -0
- package/experimental/random/AltGeneric.ff +44 -0
- package/experimental/random/Async.ff +68 -0
- package/experimental/random/Buffer2.ff +77 -0
- package/experimental/random/Cat.ff +12 -0
- package/experimental/random/Dictionary.ff +52 -0
- package/experimental/random/Example.ff +46 -0
- package/experimental/random/Generic.ff +102 -0
- package/experimental/random/HappyEyeballs.ff +40 -0
- package/experimental/random/HashMap.ff +72 -0
- package/experimental/random/IfElseUnit.ff +9 -0
- package/experimental/random/InputOutput.ff +23 -0
- package/experimental/random/ListVsArray.ff +45 -0
- package/experimental/random/Main.ff +44 -0
- package/experimental/random/MapTest.ff +67 -0
- package/experimental/random/OldTaskSystem.ff +210 -0
- package/experimental/random/PatternTest.ff +39 -0
- package/experimental/random/Patterns.ff +226 -0
- package/experimental/random/ReadBytesTest.ff +10 -0
- package/experimental/random/RunLength.ff +65 -0
- package/experimental/random/Scrape.ff +51 -0
- package/experimental/random/Serialization.ff +217 -0
- package/experimental/random/SerializationTest.ff +46 -0
- package/experimental/random/Serializer.ff +36 -0
- package/experimental/random/StdInOutErr.ff +4 -0
- package/experimental/random/Symbols.ff +74 -0
- package/experimental/random/Tag.ff +49 -0
- package/experimental/random/Tensor.ff +52 -0
- package/experimental/random/Try.ff +56 -0
- package/experimental/random/Tsv.ff +9 -0
- package/experimental/random/TypesAreModules.ff +87 -0
- package/experimental/random/blueprints/Blueprint.ff +52 -0
- package/experimental/random/blueprints/Main.ff +11 -0
- package/experimental/random/blueprints/Pretty.ff +58 -0
- package/experimental/random/blueprints/User.ff +64 -0
- package/experimental/random/blueprintsystem/BlueprintSystem.ff +48 -0
- package/experimental/random/blueprintsystem/Deserialize.ff +53 -0
- package/experimental/random/blueprintsystem/ReadJs.ff +13 -0
- package/experimental/random/blueprintsystem/User.ff +2 -0
- package/experimental/random/kahrs/Kahrs.ff +112 -0
- package/experimental/random/kahrs/TestKahrs.ff +22 -0
- package/experimental/random/kahrs/TestMap.ff +18 -0
- package/experimental/random/streaming/Gzip.ff +3 -0
- package/experimental/random/streaming/Main.ff +34 -0
- package/experimental/random/streaming/S3Bucket.ff +11 -0
- package/experimental/random/streaming/Tar.ff +5 -0
- package/experimental/rhymeapp/Main.ff +81 -0
- package/experimental/rhymeapp/index.html +14 -0
- package/firefly.sh +5 -0
- package/fireflysite/Main.ff +13 -0
- package/httpserver/.firefly/package.ff +1 -0
- package/httpserver/HttpServer.ff +184 -0
- package/lsp/.firefly/package.ff +1 -0
- package/lsp/CompletionHandler.ff +814 -0
- package/lsp/Handler.ff +551 -0
- package/lsp/HoverHandler.ff +82 -0
- package/lsp/LanguageServer.ff +229 -0
- package/lsp/SignatureHelpHandler.ff +55 -0
- package/lsp/SymbolHandler.ff +167 -0
- package/output/js/ff/compiler/Builder.mjs +483 -0
- package/output/js/ff/compiler/Compiler.mjs +410 -0
- package/output/js/ff/compiler/Dependencies.mjs +388 -0
- package/output/js/ff/compiler/Deriver.mjs +1166 -0
- package/output/js/ff/compiler/Dictionaries.mjs +1305 -0
- package/output/js/ff/compiler/Environment.mjs +1005 -0
- package/output/js/ff/compiler/Inference.mjs +4264 -0
- package/output/js/ff/compiler/JsEmitter.mjs +5353 -0
- package/output/js/ff/compiler/JsImporter.mjs +262 -0
- package/output/js/ff/compiler/LspHook.mjs +789 -0
- package/output/js/ff/compiler/Main.mjs +1695 -0
- package/output/js/ff/compiler/Parser.mjs +4004 -0
- package/output/js/ff/compiler/Patterns.mjs +923 -0
- package/output/js/ff/compiler/Resolver.mjs +2303 -0
- package/output/js/ff/compiler/Substitution.mjs +1146 -0
- package/output/js/ff/compiler/Syntax.mjs +12430 -0
- package/output/js/ff/compiler/Token.mjs +3092 -0
- package/output/js/ff/compiler/Tokenizer.mjs +589 -0
- package/output/js/ff/compiler/Unification.mjs +1748 -0
- package/output/js/ff/compiler/Wildcards.mjs +604 -0
- package/output/js/ff/compiler/Workspace.mjs +683 -0
- package/output/js/ff/core/Any.mjs +139 -0
- package/output/js/ff/core/Array.mjs +594 -0
- package/output/js/ff/core/AssetSystem.mjs +270 -0
- package/output/js/ff/core/Atomic.mjs +186 -0
- package/output/js/ff/core/Bool.mjs +141 -0
- package/output/js/ff/core/BrowserSystem.mjs +122 -0
- package/output/js/ff/core/Buffer.mjs +467 -0
- package/output/js/ff/core/BuildSystem.mjs +320 -0
- package/output/js/ff/core/Channel.mjs +268 -0
- package/output/js/ff/core/Char.mjs +145 -0
- package/output/js/ff/core/Core.mjs +300 -0
- package/output/js/ff/core/Duration.mjs +112 -0
- package/output/js/ff/core/Equal.mjs +175 -0
- package/output/js/ff/core/Error.mjs +138 -0
- package/output/js/ff/core/FileHandle.mjs +164 -0
- package/output/js/ff/core/Float.mjs +214 -0
- package/output/js/ff/core/HttpClient.mjs +210 -0
- package/output/js/ff/core/Instant.mjs +105 -0
- package/output/js/ff/core/Int.mjs +254 -0
- package/output/js/ff/core/IntMap.mjs +282 -0
- package/output/js/ff/core/JsSystem.mjs +234 -0
- package/output/js/ff/core/JsValue.mjs +678 -0
- package/output/js/ff/core/List.mjs +2335 -0
- package/output/js/ff/core/Lock.mjs +322 -0
- package/output/js/ff/core/Log.mjs +159 -0
- package/output/js/ff/core/Map.mjs +358 -0
- package/output/js/ff/core/NodeSystem.mjs +288 -0
- package/output/js/ff/core/Nothing.mjs +100 -0
- package/output/js/ff/core/Option.mjs +1002 -0
- package/output/js/ff/core/Ordering.mjs +734 -0
- package/output/js/ff/core/Pair.mjs +318 -0
- package/output/js/ff/core/Path.mjs +768 -0
- package/output/js/ff/core/RbMap.mjs +1936 -0
- package/output/js/ff/core/Serializable.mjs +434 -0
- package/output/js/ff/core/Set.mjs +250 -0
- package/output/js/ff/core/Show.mjs +201 -0
- package/output/js/ff/core/Stack.mjs +595 -0
- package/output/js/ff/core/Stream.mjs +1300 -0
- package/output/js/ff/core/String.mjs +433 -0
- package/output/js/ff/core/StringMap.mjs +282 -0
- package/output/js/ff/core/Task.mjs +345 -0
- package/output/js/ff/core/Try.mjs +503 -0
- package/output/js/ff/core/Unit.mjs +103 -0
- package/package.json +29 -0
- package/postgresql/.firefly/include/package-lock.json +250 -0
- package/postgresql/.firefly/include/package.json +5 -0
- package/postgresql/.firefly/include/prepare.sh +2 -0
- package/postgresql/.firefly/package.ff +3 -0
- package/postgresql/Pg.ff +530 -0
- package/unsafejs/.firefly/package.ff +1 -0
- package/unsafejs/UnsafeJs.ff +19 -0
- package/vscode/.vscode/launch.json +18 -0
- package/vscode/.vscode/tasks.json +33 -0
- package/vscode/LICENSE.txt +21 -0
- package/vscode/Prepublish.ff +15 -0
- package/vscode/README.md +17 -0
- package/vscode/client/package-lock.json +544 -0
- package/vscode/client/package.json +22 -0
- package/vscode/client/src/extension.ts +64 -0
- package/vscode/client/tsconfig.json +12 -0
- package/vscode/icons/firefly-icon.png +0 -0
- package/vscode/icons/firefly-icon.svg +10 -0
- package/vscode/icons/firefly-logo-notext.png +0 -0
- package/vscode/icons/firefly-logo.png +0 -0
- package/vscode/language-configuration.json +39 -0
- package/vscode/package-lock.json +3623 -0
- package/vscode/package.json +144 -0
- package/vscode/snippets-none.json +1 -0
- package/vscode/snippets.json +241 -0
- package/vscode/syntaxes/firefly.tmLanguage.json +294 -0
- package/vscode/tsconfig.json +20 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
capability BuildSystem {}
|
|
2
|
+
capability BrowserCode(packageGroup: String, packageName: String, mainFile: Path, assetSystem: AssetSystem)
|
|
3
|
+
capability BrowserBundle(assetSystem: AssetSystem)
|
|
4
|
+
|
|
5
|
+
extend self: BuildSystem {
|
|
6
|
+
|
|
7
|
+
compileForBrowser(mainFile: String): BrowserCode {
|
|
8
|
+
// TODO: Check that the mainFile is in the current package directory
|
|
9
|
+
internalCompile(self, internalPath(self, mainFile), "browser")
|
|
10
|
+
let streams = internalListDirectory(internalPath(self, ".firefly/output/browser"))
|
|
11
|
+
let mainPackagePair = internalMainPackagePair(self)
|
|
12
|
+
BrowserCode(
|
|
13
|
+
packageGroup = mainPackagePair.first
|
|
14
|
+
packageName = mainPackagePair.second
|
|
15
|
+
mainFile = internalPath(self, mainFile)
|
|
16
|
+
assetSystem = AssetSystem(streams.toMap())
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
buildMode(): Bool
|
|
21
|
+
target node async "return !!self_.buildMode_"
|
|
22
|
+
|
|
23
|
+
setAssets(assetSystem: AssetSystem): Unit
|
|
24
|
+
target node async "self_.assets_ = assetSystem_"
|
|
25
|
+
|
|
26
|
+
packageAssets(): AssetSystem {
|
|
27
|
+
let streams = internalListDirectory(internalPath(self, "."))
|
|
28
|
+
AssetSystem(streams.toMap())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
dependencyAssets(user: String, package: String): AssetSystem {
|
|
32
|
+
panic("dependencyAssets not yet implemented")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
arguments(): Array[String]
|
|
36
|
+
target node async "return self_.array_"
|
|
37
|
+
|
|
38
|
+
mainTask(): Task
|
|
39
|
+
target js async "return self_.task_"
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
extend self: BrowserCode {
|
|
44
|
+
|
|
45
|
+
assets(): AssetSystem {
|
|
46
|
+
self.assetSystem
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
bundle(minify: Bool = True, sourceMap: Bool = False): BrowserBundle {
|
|
50
|
+
let prefix = ".firefly/output/browser"
|
|
51
|
+
let mainJsBaseFile = self.mainFile.absolute().removeLast(".ff").grab() + ".mjs"
|
|
52
|
+
let mainJsFile = prefix + "/" + self.packageGroup + "/" + self.packageName + "/" + mainJsBaseFile
|
|
53
|
+
let file = prefix + "/Main.bundle.js"
|
|
54
|
+
internalCallEsBuild(self, mainJsFile = mainJsFile, outputPath = file, minify = minify, sourceMap = sourceMap)
|
|
55
|
+
let assets = AssetSystem([
|
|
56
|
+
Pair(file.dropFirst(prefix.size()), {self.mainFile.path(file).readStream()})
|
|
57
|
+
...if(sourceMap) {[
|
|
58
|
+
Pair(file.dropFirst(prefix.size()) + ".map", {self.mainFile.path(file + ".map").readStream()})
|
|
59
|
+
]} else {[]}
|
|
60
|
+
].toMap())
|
|
61
|
+
BrowserBundle(assets)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
extend self: BrowserBundle {
|
|
67
|
+
|
|
68
|
+
assets(): AssetSystem {
|
|
69
|
+
self.assetSystem
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
internalCallEsBuild(
|
|
76
|
+
self: BrowserCode
|
|
77
|
+
mainJsFile: String
|
|
78
|
+
outputPath: String
|
|
79
|
+
minify: Bool
|
|
80
|
+
sourceMap: Bool
|
|
81
|
+
): Unit
|
|
82
|
+
target node async """
|
|
83
|
+
import * as esbuild from 'esbuild'
|
|
84
|
+
return await esbuild.build({
|
|
85
|
+
entryPoints: [mainJsFile_],
|
|
86
|
+
bundle: true,
|
|
87
|
+
minify: minify_,
|
|
88
|
+
sourcemap: sourceMap_,
|
|
89
|
+
platform: 'browser',
|
|
90
|
+
target: 'es6',
|
|
91
|
+
external: ['../../../node_modules/*'], // TODO
|
|
92
|
+
outfile: outputPath_
|
|
93
|
+
})
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
internalNodeCallEsBuild(
|
|
97
|
+
self: NodeSystem
|
|
98
|
+
mainJsFile: String
|
|
99
|
+
outputPath: String
|
|
100
|
+
minify: Bool
|
|
101
|
+
): Unit
|
|
102
|
+
target node async """
|
|
103
|
+
import * as esbuild from 'esbuild'
|
|
104
|
+
return await esbuild.build({
|
|
105
|
+
entryPoints: [mainJsFile_],
|
|
106
|
+
bundle: true,
|
|
107
|
+
minify: minify_,
|
|
108
|
+
sourcemap: true,
|
|
109
|
+
platform: 'node',
|
|
110
|
+
target: 'es6',
|
|
111
|
+
external: ['../../../node_modules/*'], // TODO
|
|
112
|
+
outfile: outputPath_
|
|
113
|
+
})
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
internalListDirectory(path: Path): List[Pair[String, () => Stream[Buffer]]] {
|
|
117
|
+
function go(currentPath: Path): Stream[Path] {
|
|
118
|
+
currentPath.entries().flatMap {file =>
|
|
119
|
+
if(file.isDirectory()) {
|
|
120
|
+
go(file.path())
|
|
121
|
+
} else {
|
|
122
|
+
[file.path()].toStream()
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
go(path).map {file =>
|
|
127
|
+
Pair("/" + file.relativeTo(path), {file.readStream()})
|
|
128
|
+
}.toList()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
internalPath(buildSystem: BuildSystem, absoluteOrRelative: String): Path
|
|
132
|
+
target node async """
|
|
133
|
+
return absoluteOrRelative_
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
internalCompile(buildSystem: BuildSystem, mainFile: Path, target: String): Unit
|
|
137
|
+
target node async """
|
|
138
|
+
return await $firefly_compiler.buildViaBuildSystem_$(buildSystem_, buildSystem_.fireflyPath_, mainFile_, target_, $task)
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
internalMainPackagePair(buildSystem: BuildSystem): Pair[String, String]
|
|
142
|
+
target node async """
|
|
143
|
+
return {first_: buildSystem_.mainPackagePair_.group_, second_: buildSystem_.mainPackagePair_.name_}
|
|
144
|
+
"""
|
package/core/Channel.ff
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
capability Channel[T] {}
|
|
2
|
+
|
|
3
|
+
extend self[T]: Channel[T] {
|
|
4
|
+
|
|
5
|
+
read(): T {
|
|
6
|
+
readOr(self, {_}).wait()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
write(message: T): Unit {
|
|
10
|
+
writeOr(self, message, {}).wait()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
capability ChannelAction[T] {}
|
|
17
|
+
|
|
18
|
+
extend self[T]: ChannelAction[T] {
|
|
19
|
+
|
|
20
|
+
readOr[M](channel: Channel[M], body: M => T): ChannelAction[T]
|
|
21
|
+
target js async "return {channel: channel_, body: body_, previous: self_}"
|
|
22
|
+
|
|
23
|
+
writeOr[M](channel: Channel[M], message: M, body: () => T): ChannelAction[T]
|
|
24
|
+
target js async "return {channel: channel_, body: body_, message: message_, previous: self_}"
|
|
25
|
+
|
|
26
|
+
wait(): T {
|
|
27
|
+
internalRunChannelAction(self, None)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
timeout(duration: Duration, body: () => T): T {
|
|
31
|
+
internalRunChannelAction(self, Some(Pair(body, Some(duration))))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
immediately(body: () => T): T {
|
|
35
|
+
internalRunChannelAction(self, Some(Pair(body, None)))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
readOr[M, T](channel: Channel[M], body: M => T): ChannelAction[T]
|
|
41
|
+
target js async "return {channel: channel_, body: body_, previous: null}"
|
|
42
|
+
|
|
43
|
+
writeOr[M, T](channel: Channel[M], message: M, body: () => T): ChannelAction[T]
|
|
44
|
+
target js async "return {channel: channel_, body: body_, message: message_, previous: null}"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
internalRunChannelAction[T](action: ChannelAction[T], mode: Option[Pair[() => T, Option[Duration]]]): T
|
|
48
|
+
target js async """
|
|
49
|
+
ff_core_Task.Task_throwIfAborted($task)
|
|
50
|
+
|
|
51
|
+
// Convert the linked actions into an array.
|
|
52
|
+
let actions = []
|
|
53
|
+
while(action_ != null) {
|
|
54
|
+
actions.push(action_)
|
|
55
|
+
action_ = action_.previous
|
|
56
|
+
}
|
|
57
|
+
actions.reverse()
|
|
58
|
+
|
|
59
|
+
// If any reads or writes can be done immediately, do the first one and return.
|
|
60
|
+
for(let action of actions) {
|
|
61
|
+
if(action.hasOwnProperty("message")) {
|
|
62
|
+
if(action.channel.readers.size != 0) {
|
|
63
|
+
let reader = action.channel.readers.values().next().value
|
|
64
|
+
action.channel.readers.delete(reader)
|
|
65
|
+
reader.resolve(action.message)
|
|
66
|
+
return await action.body($task)
|
|
67
|
+
} else if(action.channel.buffer.length < action.channel.capacity) {
|
|
68
|
+
action.channel.buffer.push(action.message)
|
|
69
|
+
return await action.body($task)
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
if(action.channel.buffer.length != 0) {
|
|
73
|
+
return await action.body(action.channel.buffer.shift(), $task)
|
|
74
|
+
} else if(action.channel.writers.size != 0) {
|
|
75
|
+
let writer = action.channel.writers.values().next().value
|
|
76
|
+
action.channel.writers.delete(writer)
|
|
77
|
+
writer.resolve()
|
|
78
|
+
return await action.body(writer.message, $task)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// If there's an "immediately(body)" action, do that now.
|
|
84
|
+
if(mode_.value_ && mode_.value_.second_.value_ == null) return await mode_.value_.first_($task)
|
|
85
|
+
|
|
86
|
+
// Otherwise, start waiting for one of the readers or writers (or timeout(body), or cancellation) to happen.
|
|
87
|
+
let abort = null
|
|
88
|
+
let finish = null
|
|
89
|
+
let cleanups = []
|
|
90
|
+
function doCleanup() {
|
|
91
|
+
for(let cleanup of cleanups) cleanup()
|
|
92
|
+
}
|
|
93
|
+
let promise = new Promise((resolve, reject) => {
|
|
94
|
+
if(mode_.value_) finish = () => {doCleanup(); resolve(() => mode_.value_.first_($task))}
|
|
95
|
+
abort = () => {doCleanup(); reject($task.controller.signal.reason)}
|
|
96
|
+
for(let action of actions) {
|
|
97
|
+
if(action.hasOwnProperty("message")) {
|
|
98
|
+
let writer = {
|
|
99
|
+
resolve: () => {
|
|
100
|
+
doCleanup()
|
|
101
|
+
resolve(() => action.body($task))
|
|
102
|
+
},
|
|
103
|
+
message: action.message
|
|
104
|
+
}
|
|
105
|
+
cleanups.push(() => action.channel.writers.delete(writer))
|
|
106
|
+
action.channel.writers.add(writer)
|
|
107
|
+
} else {
|
|
108
|
+
let reader = {
|
|
109
|
+
resolve: m => {
|
|
110
|
+
doCleanup()
|
|
111
|
+
resolve(() => action.body(m, $task))
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
cleanups.push(() => action.channel.readers.delete(reader))
|
|
115
|
+
action.channel.readers.add(reader)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
let timeout = null
|
|
120
|
+
try {
|
|
121
|
+
$task.controller.signal.addEventListener('abort', abort)
|
|
122
|
+
if(finish != null) timeout = setTimeout(finish, mode_.value_.second_.value_ * 1000)
|
|
123
|
+
let body = await promise
|
|
124
|
+
if(timeout != null) { clearTimeout(timeout); timeout = null }
|
|
125
|
+
return await body()
|
|
126
|
+
} finally {
|
|
127
|
+
if(timeout != null) clearTimeout(timeout)
|
|
128
|
+
$task.controller.signal.removeEventListener('abort', abort)
|
|
129
|
+
if($task.controller.signal.aborted) $task.controller = new AbortController()
|
|
130
|
+
}
|
|
131
|
+
"""
|
package/core/Char.ff
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
newtype Char(codeUnit: Int)
|
|
2
|
+
|
|
3
|
+
extend self: Char {
|
|
4
|
+
|
|
5
|
+
isAsciiLetter(): Bool {self.isAsciiUpper() || self.isAsciiLower()}
|
|
6
|
+
|
|
7
|
+
isAsciiLetterOrDigit(): Bool {self.isAsciiLetter() || self.isAsciiDigit()}
|
|
8
|
+
|
|
9
|
+
isAsciiUpper(): Bool {self >= 'A' && self <= 'Z'}
|
|
10
|
+
|
|
11
|
+
isAsciiLower(): Bool {self >= 'a' && self <= 'z'}
|
|
12
|
+
|
|
13
|
+
isAsciiDigit(): Bool {self >= '0' && self <= '9'}
|
|
14
|
+
|
|
15
|
+
toString(): String
|
|
16
|
+
target js sync "return String.fromCharCode(self_)"
|
|
17
|
+
|
|
18
|
+
}
|
package/core/Core.ff
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
if[T](condition: Bool, body: () => T): Option[T] {
|
|
2
|
+
condition.{
|
|
3
|
+
| False => None
|
|
4
|
+
| True => Some(body())
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
while(condition: () => Bool, body: () => Unit): Unit {
|
|
9
|
+
condition().{
|
|
10
|
+
| False =>
|
|
11
|
+
| True =>
|
|
12
|
+
body()
|
|
13
|
+
tailcall while(condition, body)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
doWhile(body: () => Bool): Unit {
|
|
18
|
+
while {body()} {}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
doUntil[T](body: () => Option[T]): T {
|
|
22
|
+
body().{
|
|
23
|
+
| Some(v) => v
|
|
24
|
+
| None => tailcall doUntil(body)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
do[T](body: () => T): T {
|
|
29
|
+
body()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try[T](body: () => T): Try[T]
|
|
33
|
+
target js sync """
|
|
34
|
+
try {
|
|
35
|
+
return {Success: true, value_: body_()}
|
|
36
|
+
} catch(e) {
|
|
37
|
+
return {Failure: true, error_: e}
|
|
38
|
+
}
|
|
39
|
+
"""
|
|
40
|
+
target js async """
|
|
41
|
+
try {
|
|
42
|
+
return {Success: true, value_: await body_($task)}
|
|
43
|
+
} catch(e) {
|
|
44
|
+
return {Failure: true, error_: e}
|
|
45
|
+
}
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
throw[E: HasAnyTag, T](exception: E): T {
|
|
49
|
+
throwAny(Any.toAny(exception))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
throwAny[T](exception: Any): T
|
|
53
|
+
target js sync "throw Object.assign(new Error(), {ffException: exception_})"
|
|
54
|
+
|
|
55
|
+
panic[T](message: String): T
|
|
56
|
+
target js sync "throw new Error(message_)"
|
|
57
|
+
|
|
58
|
+
data GrabException()
|
package/core/Duration.ff
ADDED
package/core/Equal.ff
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
trait T: Equal {
|
|
2
|
+
equals(x: T, y: T): Bool
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
notEquals[T: Equal](x: T, y: T): Bool {
|
|
6
|
+
!equals(x, y)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
instance Nothing: Equal {
|
|
10
|
+
equals(x: Nothing, y: Nothing): Bool {True}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
instance Bool: Equal {
|
|
14
|
+
equals(x: Bool, y: Bool): Bool
|
|
15
|
+
target js sync """return x_ === y_"""
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
instance Char: Equal {
|
|
19
|
+
equals(x: Char, y: Char): Bool
|
|
20
|
+
target js sync """return x_ === y_"""
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
instance Int: Equal {
|
|
24
|
+
equals(x: Int, y: Int): Bool
|
|
25
|
+
target js sync """return x_ === y_"""
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
instance Float: Equal {
|
|
29
|
+
equals(x: Float, y: Float): Bool
|
|
30
|
+
target js sync """return x_ === y_"""
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
instance String: Equal {
|
|
34
|
+
equals(x: String, y: String): Bool
|
|
35
|
+
target js sync """return x_ === y_"""
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
instance List[T]: Equal {
|
|
39
|
+
equals(x: List[T], y: List[T]): Bool
|
|
40
|
+
target js sync """
|
|
41
|
+
let a = x_
|
|
42
|
+
let b = y_
|
|
43
|
+
if(a === b) return true
|
|
44
|
+
while(a.Link && b.Link) {
|
|
45
|
+
if(a === b) return true
|
|
46
|
+
if(!ff_core_Equal_Equal$T.equals_(a.head_, b.head_)) return false
|
|
47
|
+
a = a.tail_
|
|
48
|
+
b = b.tail_
|
|
49
|
+
}
|
|
50
|
+
return a.Empty && b.Empty
|
|
51
|
+
"""
|
|
52
|
+
}
|
package/core/Error.ff
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
data Error {}
|
|
2
|
+
|
|
3
|
+
extend self: Error {
|
|
4
|
+
|
|
5
|
+
rethrow[T](): T
|
|
6
|
+
target js sync "throw self_"
|
|
7
|
+
|
|
8
|
+
name(): String
|
|
9
|
+
target js sync "return self_.name || ''"
|
|
10
|
+
|
|
11
|
+
message(): String
|
|
12
|
+
target js sync "return self_.message || ''"
|
|
13
|
+
|
|
14
|
+
stack(): String
|
|
15
|
+
target js sync "return self_.stack || ''"
|
|
16
|
+
|
|
17
|
+
exception(): Option[Any]
|
|
18
|
+
target js sync "return self_.ffException ? ff_core_Option.Some(self_.ffException) : ff_core_Option.None()"
|
|
19
|
+
|
|
20
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
capability FileHandle {}
|
|
2
|
+
|
|
3
|
+
extend self: FileHandle {
|
|
4
|
+
|
|
5
|
+
close(): Unit
|
|
6
|
+
target js async """
|
|
7
|
+
await self_.close()
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
read(buffer: Buffer, offset: Int = 0, length: Option[Int] = None, position: Option[Int] = None): Unit
|
|
11
|
+
target js async """
|
|
12
|
+
ff_core_Task.Task_throwIfAborted($task)
|
|
13
|
+
await self_.read(buffer_, {offset: offset_, length: length.value_, position: position.value_})
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
write(buffer: Buffer, offset: Int = 0, length: Option[Int] = None, position: Option[Int] = None): Unit
|
|
17
|
+
target js async """
|
|
18
|
+
ff_core_Task.Task_throwIfAborted($task)
|
|
19
|
+
await self_.write(buffer_, offset_, length.value_, position.value_)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
writeText(text: String, position: Option[Int] = None, encoding: String = "utf8"): Unit
|
|
23
|
+
target js async """
|
|
24
|
+
ff_core_Task.Task_throwIfAborted($task)
|
|
25
|
+
await self_.write(text, position.value_, encoding_)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
truncate(length: Int = 0): Unit
|
|
29
|
+
target js async """
|
|
30
|
+
ff_core_Task.Task_throwIfAborted($task)
|
|
31
|
+
await self_.truncate(length_)
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
sync(dataOnly: Bool = False): Unit
|
|
35
|
+
target js async """
|
|
36
|
+
ff_core_Task.Task_throwIfAborted($task)
|
|
37
|
+
if(dataOnly_) await self_.datasync()
|
|
38
|
+
else await self_.sync()
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
}
|
package/core/Float.ff
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
data Float {}
|
|
2
|
+
|
|
3
|
+
extend self: Float {
|
|
4
|
+
|
|
5
|
+
toInt(): Int
|
|
6
|
+
target js sync "return Math.trunc(Math.abs(self_))"
|
|
7
|
+
|
|
8
|
+
round(): Float
|
|
9
|
+
target js sync "return Math.round(self_)"
|
|
10
|
+
|
|
11
|
+
floor(): Float
|
|
12
|
+
target js sync "return Math.floor(self_)"
|
|
13
|
+
|
|
14
|
+
ceil(): Float
|
|
15
|
+
target js sync "return Math.ceil(self_)"
|
|
16
|
+
|
|
17
|
+
truncate(): Float
|
|
18
|
+
target js sync "return Math.trunc(self_)"
|
|
19
|
+
|
|
20
|
+
sign(): Float
|
|
21
|
+
target js sync "return Math.sign(self_)"
|
|
22
|
+
|
|
23
|
+
abs(): Float
|
|
24
|
+
target js sync "return Math.abs(self_)"
|
|
25
|
+
|
|
26
|
+
toFixed(digits: Int): String
|
|
27
|
+
target js sync "return self_.toFixed(digits_)"
|
|
28
|
+
|
|
29
|
+
min(that: Float): Float {
|
|
30
|
+
if(self < that) {self} else {that}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
max(that: Float): Float {
|
|
34
|
+
if(self > that) {self} else {that}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
clamp(from: Float, to: Float): Float {
|
|
38
|
+
if(self <= from) {from} elseIf {self >= to} {to} else {self}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
capability HttpClient {}
|
|
2
|
+
capability FetchBody {}
|
|
3
|
+
capability FetchResponse {}
|
|
4
|
+
data FetchRedirect {
|
|
5
|
+
RedirectFollow
|
|
6
|
+
RedirectError
|
|
7
|
+
RedirectManual
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
extend self: HttpClient {
|
|
11
|
+
|
|
12
|
+
fetch(
|
|
13
|
+
url: String
|
|
14
|
+
method: String = "GET"
|
|
15
|
+
headers: List[Pair[String, String]] = emptyList
|
|
16
|
+
body: Option[FetchBody] = None
|
|
17
|
+
redirect: FetchRedirect = RedirectFollow
|
|
18
|
+
// The rest of the options are only respected by browsers - see the MDN fetch() documentation
|
|
19
|
+
referrer: Option[String] = None
|
|
20
|
+
integrity: Option[String] = None
|
|
21
|
+
mode: Option[String] = None
|
|
22
|
+
credentials: Option[String] = None
|
|
23
|
+
cache: Option[String] = None
|
|
24
|
+
throw: Bool = True
|
|
25
|
+
): FetchResponse
|
|
26
|
+
target js async """
|
|
27
|
+
try {
|
|
28
|
+
const options = {headers: {}, signal: $task.controller.signal}
|
|
29
|
+
options.method = method_
|
|
30
|
+
ff_core_List.List_each(headers_, pair => {options.headers[pair.key_] = pair.value_})
|
|
31
|
+
if(body_.value_) options.body = body_.value_
|
|
32
|
+
if(redirect_.RedirectError) options.redirect = "error"
|
|
33
|
+
else if(redirect_.RedirectManual) options.redirect = "manual"
|
|
34
|
+
if(referrer_.value_) options.referrer = referrer_.value_
|
|
35
|
+
if(integrity_.value_) options.integrity = integrity_.value_
|
|
36
|
+
if(mode_.value_) options.mode = mode_.value_
|
|
37
|
+
if(credentials_.value_) options.credentials = credentials_.value_
|
|
38
|
+
if(cache_.value_) options.cache = cache_.value_
|
|
39
|
+
let result = await fetch(url_, options)
|
|
40
|
+
if(throw_ && !result.ok) throw new Error("Unexpected HTTP status code: " + result.status)
|
|
41
|
+
return result
|
|
42
|
+
} finally {
|
|
43
|
+
if($task.controller.signal.aborted) $task.controller = new AbortController()
|
|
44
|
+
}
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
emptyList: List[Pair[String, String]] = [] // TODO: Why won't this type check when inlined? Probably some dangling unification variable?
|
|
50
|
+
|
|
51
|
+
bodyText(body: String): FetchBody
|
|
52
|
+
target js sync "return body_"
|
|
53
|
+
target js async "return body_"
|
|
54
|
+
|
|
55
|
+
bodyBuffer(body: Buffer): FetchBody
|
|
56
|
+
target js sync "return body_"
|
|
57
|
+
target js async "return body_"
|
|
58
|
+
|
|
59
|
+
extend self: FetchResponse {
|
|
60
|
+
|
|
61
|
+
ok(): Bool
|
|
62
|
+
target js async "return self_.ok"
|
|
63
|
+
|
|
64
|
+
status(): Int
|
|
65
|
+
target js async "return self_.status"
|
|
66
|
+
|
|
67
|
+
statusText(): String
|
|
68
|
+
target js async "return self_.statusText"
|
|
69
|
+
|
|
70
|
+
header(name: String): Option[String]
|
|
71
|
+
target js async """
|
|
72
|
+
const header = self_.headers.get(name_)
|
|
73
|
+
return header != null
|
|
74
|
+
? ff_core_Option.Some(header)
|
|
75
|
+
: ff_core_Option.None()
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
readText(): String
|
|
79
|
+
target js async "return await self_.text()"
|
|
80
|
+
|
|
81
|
+
readBuffer(): Buffer
|
|
82
|
+
target js async "return new DataView(await self_.arrayBuffer())"
|
|
83
|
+
|
|
84
|
+
}
|
package/core/Instant.ff
ADDED
package/core/Int.ff
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
data Int {}
|
|
2
|
+
|
|
3
|
+
extend self: Int {
|
|
4
|
+
|
|
5
|
+
abs(): Int
|
|
6
|
+
target js sync "return Math.abs(self_)"
|
|
7
|
+
|
|
8
|
+
toFloat(): Float
|
|
9
|
+
target js sync "return self_"
|
|
10
|
+
|
|
11
|
+
bitNot(): Int
|
|
12
|
+
target js sync "return ~self_;"
|
|
13
|
+
|
|
14
|
+
bitOr(that: Int): Int
|
|
15
|
+
target js sync "return self_ | that_;"
|
|
16
|
+
|
|
17
|
+
bitAnd(that: Int): Int
|
|
18
|
+
target js sync "return self_ & that_;"
|
|
19
|
+
|
|
20
|
+
bitXor(that: Int): Int
|
|
21
|
+
target js sync "return self_ ^ that_;"
|
|
22
|
+
|
|
23
|
+
bitLeft(bits: Int = 1): Int
|
|
24
|
+
target js sync "return self_ << bits_;"
|
|
25
|
+
|
|
26
|
+
bitRight(bits: Int = 1, signed: Bool = True): Int
|
|
27
|
+
target js sync "return signed_ ? self_ >> bits_ : self_ >>> bits_;"
|
|
28
|
+
|
|
29
|
+
to(inclusiveEnd: Int): List[Int] {
|
|
30
|
+
mutable result = []
|
|
31
|
+
mutable n = inclusiveEnd
|
|
32
|
+
while {self <= n} {
|
|
33
|
+
result = [n, ...result]
|
|
34
|
+
n -= 1
|
|
35
|
+
}
|
|
36
|
+
result
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
until(exclusiveEnd: Int): List[Int] {
|
|
40
|
+
mutable result = []
|
|
41
|
+
mutable n = exclusiveEnd
|
|
42
|
+
while {self < n} {
|
|
43
|
+
result = [n - 1, ...result]
|
|
44
|
+
n -= 1
|
|
45
|
+
}
|
|
46
|
+
result
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
min(that: Int): Int {
|
|
50
|
+
if(self < that) {self} else {that}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
max(that: Int): Int {
|
|
54
|
+
if(self > that) {self} else {that}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
clamp(from: Int, to: Int): Int {
|
|
58
|
+
if(self <= from) {from} elseIf {self >= to} {to} else {self}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
}
|