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
package/core/Task.ff
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
capability Task {}
|
|
2
|
+
|
|
3
|
+
extend self: Task {
|
|
4
|
+
// Spawns a task running body. The return value as well as the argument to body is the task handle.
|
|
5
|
+
// Automatically aborts and then joins subtasks when body returns or throws an unhandled exception.
|
|
6
|
+
// If body throws, the parent task is also aborted with the dueToSubtask flag set to true.
|
|
7
|
+
spawn(body: Task => Unit): Task
|
|
8
|
+
target js async """
|
|
9
|
+
return ff_core_Task.Task_spawn(self_, body_)
|
|
10
|
+
"""
|
|
11
|
+
target js sync """
|
|
12
|
+
ff_core_Task.Task_throwIfAborted(self_)
|
|
13
|
+
const task = {controller: new AbortController(), subtasks: new Set(), started: performance.now() * 0.001}
|
|
14
|
+
self_.subtasks.add(task)
|
|
15
|
+
task.promise = Promise.resolve(task).then(async () => {
|
|
16
|
+
try {
|
|
17
|
+
await body_(task, task)
|
|
18
|
+
} catch(e) {
|
|
19
|
+
await ff_core_Task.Task_abort$(self_)
|
|
20
|
+
throw e
|
|
21
|
+
} finally {
|
|
22
|
+
for(const subtask of task.subtasks) subtask.controller.abort()
|
|
23
|
+
await Promise.allSettled([...task.subtasks].map(subtask => subtask.promise))
|
|
24
|
+
self_.subtasks.delete(task)
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
return task
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
// If the aborted flag is set for the current task, clears it and throws TaskAbortedException.
|
|
31
|
+
// You don't normally need to call this, but you might want to before doing an expensive computation.
|
|
32
|
+
throwIfAborted(): Unit
|
|
33
|
+
target js async """
|
|
34
|
+
ff_core_Task.Task_throwIfAborted(self_)
|
|
35
|
+
"""
|
|
36
|
+
target js sync """
|
|
37
|
+
if(self_.controller.signal.aborted) {
|
|
38
|
+
const signal = self_.controller.signal
|
|
39
|
+
self_.controller = new AbortController()
|
|
40
|
+
signal.throwIfAborted()
|
|
41
|
+
}
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
// Sets the tasks aborted flag, which causes the ongoing/next async call to throw TaskAbortedException.
|
|
45
|
+
abort(): Unit
|
|
46
|
+
target js async """
|
|
47
|
+
self_.controller.abort()
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
// Create a blocking channel with the specified capacity. The channel is not tied to the task.
|
|
51
|
+
channel[T](capacity: Int = 0): Channel[T]
|
|
52
|
+
target js async """return ff_core_Task.Task_channel(capacity_)"""
|
|
53
|
+
target js sync """return {capacity: capacity_, buffer: [], readers: new Set(), writers: new Set()}"""
|
|
54
|
+
|
|
55
|
+
// Create a mutex. The mutex is not tied to the task.
|
|
56
|
+
lock(): Lock
|
|
57
|
+
target js async """return {owner: null, level: 0, stack: [], queue: []}"""
|
|
58
|
+
|
|
59
|
+
now(): Instant
|
|
60
|
+
target js sync "return Date.now() * 0.001"
|
|
61
|
+
target js async "return Date.now() * 0.001" // TODO: Mark now() as sync and remove async version
|
|
62
|
+
|
|
63
|
+
elapsed(): Duration
|
|
64
|
+
target js sync "return performance.now() * 0.001 - self_.started"
|
|
65
|
+
target js async "return performance.now() * 0.001 - self_.started" // TODO: Mark sync and remove async version
|
|
66
|
+
|
|
67
|
+
time[R](body: () => R): Pair[R, Duration] {
|
|
68
|
+
let start = self.elapsed()
|
|
69
|
+
let result = body()
|
|
70
|
+
let stop = self.elapsed()
|
|
71
|
+
let duration = Duration(stop.seconds - start.seconds)
|
|
72
|
+
Pair(result, duration)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Convenience methods
|
|
78
|
+
extend self: Task {
|
|
79
|
+
|
|
80
|
+
sleep(duration: Duration): Unit {
|
|
81
|
+
Channel.
|
|
82
|
+
readOr(self.channel()) {_ => }.
|
|
83
|
+
timeout(duration) {}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
all[T](tasks: List[() => T]): List[T] {
|
|
87
|
+
let successChannel = self.channel()
|
|
88
|
+
let failureChannel = self.channel()
|
|
89
|
+
self.spawn {t =>
|
|
90
|
+
let channel = t.channel()
|
|
91
|
+
try {
|
|
92
|
+
tasks.pairs().each {| Pair(i, task) =>
|
|
93
|
+
t.spawn {_ =>
|
|
94
|
+
channel.write(Pair(i, task()))
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
let result = tasks.map {_ =>
|
|
98
|
+
channel.read()
|
|
99
|
+
}.sortBy {_.first}.map {_.second}
|
|
100
|
+
successChannel.write(result)
|
|
101
|
+
} catchAny {error =>
|
|
102
|
+
failureChannel.write(error)
|
|
103
|
+
t.abort()
|
|
104
|
+
} grab()
|
|
105
|
+
}
|
|
106
|
+
Channel.
|
|
107
|
+
readOr(successChannel, {_}).
|
|
108
|
+
readOr(failureChannel, {_.rethrow()}).
|
|
109
|
+
wait()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
race[T](tasks: List[() => T]): T {
|
|
113
|
+
let successChannel = self.channel()
|
|
114
|
+
let failureChannel = self.channel()
|
|
115
|
+
mutable live = tasks.size()
|
|
116
|
+
let started = tasks.map {task =>
|
|
117
|
+
self.spawn {_ =>
|
|
118
|
+
try {
|
|
119
|
+
successChannel.write(task())
|
|
120
|
+
} catchAny {e =>
|
|
121
|
+
live -= 1 // Not thread safe (but OK in JS)
|
|
122
|
+
if(live == 0) {
|
|
123
|
+
failureChannel.write(e)
|
|
124
|
+
}
|
|
125
|
+
} grab()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
Channel.
|
|
130
|
+
readOr(successChannel, {_}).
|
|
131
|
+
readOr(failureChannel, {_.rethrow()}).
|
|
132
|
+
wait()
|
|
133
|
+
} finally {
|
|
134
|
+
started.each {_.abort()}
|
|
135
|
+
} grab()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
}
|
package/core/Try.ff
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
data Try[T] {
|
|
2
|
+
Success(value: T)
|
|
3
|
+
Failure(error: Error)
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
extend self[T]: Try[T] {
|
|
7
|
+
|
|
8
|
+
map[S](body: T => S): Try[S] {
|
|
9
|
+
self.{
|
|
10
|
+
| Success(value) => try {body(value)}
|
|
11
|
+
| Failure(error) => Failure(error)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
flatMap[S](body: T => Try[S]): Try[S] {
|
|
16
|
+
self.map(body).flatten()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
catch[E: HasAnyTag](body: (E, Error) => T): Try[T] {
|
|
20
|
+
self.{
|
|
21
|
+
| Failure(error) {error.exception().flatMap(Any.fromAny) | Some(e)} => try {body(e, error)}
|
|
22
|
+
| _ => self
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
catchAny(body: Error => T): Try[T] {
|
|
27
|
+
self.{
|
|
28
|
+
| Failure(error) => try {body(error)}
|
|
29
|
+
| _ => self
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
finally(body: () => Unit): Try[T] {
|
|
34
|
+
self.{
|
|
35
|
+
| Success(value) => try {body(); value}
|
|
36
|
+
| Failure(_) =>
|
|
37
|
+
try {body()}.{
|
|
38
|
+
| Success(_) => self
|
|
39
|
+
| Failure(error) => Failure(error)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
else(body: () => T): T {
|
|
45
|
+
self.{
|
|
46
|
+
| Success(value) => value
|
|
47
|
+
| Failure(_) => body()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
grab(): T {
|
|
52
|
+
self.{
|
|
53
|
+
| Success(value) => value
|
|
54
|
+
| Failure(error) => error.rethrow()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
toOption(): Option[T] {
|
|
59
|
+
self.{
|
|
60
|
+
| Success(value) => Some(value)
|
|
61
|
+
| Failure(_) => None
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
extend self[T]: Try[Try[T]] {
|
|
68
|
+
|
|
69
|
+
flatten(): Try[T] {
|
|
70
|
+
self.{
|
|
71
|
+
| Success(Success(_)@t) => t
|
|
72
|
+
| Success(Failure(_)@t) => t
|
|
73
|
+
| Failure(error) => Failure(error)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
internalThrowGrabException[T](): T {
|
|
80
|
+
throw(GrabException())
|
|
81
|
+
}
|
package/core/Unit.ff
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Two fields, zero fields and a particular field
|
|
2
|
+
|
|
3
|
+
data GFields[A, B](
|
|
4
|
+
first: A
|
|
5
|
+
second: B
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
data GNoFields()
|
|
9
|
+
|
|
10
|
+
data GField[S, V](value: V)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// Two constructors, zero constructors and a particular constructor
|
|
14
|
+
|
|
15
|
+
data GConstructors[L, R] {
|
|
16
|
+
GLeft(value: L)
|
|
17
|
+
GRight(value: R)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
data GNoConstructors {}
|
|
21
|
+
|
|
22
|
+
data GConstructor[S, V](value: V)
|
|
23
|
+
|
|
24
|
+
trait T: Generic[R] {
|
|
25
|
+
toGeneric(value: T): R
|
|
26
|
+
fromGeneric(generic: R): T
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
data Person(name : String, age : Int)
|
|
30
|
+
|
|
31
|
+
// Mål: Show på Person
|
|
32
|
+
// Vej: Person -> R -> String
|
|
33
|
+
|
|
34
|
+
// instance Person: Generic[GType[_, GConstructor[_, GFields[GField[_, String], GField[_, Int]]]]]
|
|
35
|
+
|
|
36
|
+
trait T: Show {
|
|
37
|
+
show(value: T): String
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
instance GFields[A: Show, B: Show]: Show {
|
|
41
|
+
show(v) { show(v.first) + ", " + show(v.second) }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
person_show_GFields[A: Show, B: Show](a : A, b : B) = show(a) + ", " + show(b)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import Syntax
|
|
2
|
+
|
|
3
|
+
data Async()
|
|
4
|
+
|
|
5
|
+
make(): Async {
|
|
6
|
+
Async()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
extend self: Async {
|
|
10
|
+
|
|
11
|
+
groupRecursive(functions: List[DFunction]) : List[List[DFunction]] {
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
checkRecursive(functions: List[List[DFunction]]) : List[DFunction] {
|
|
16
|
+
// function f(x) {}
|
|
17
|
+
f : $1 -> $2
|
|
18
|
+
--
|
|
19
|
+
f : forall a. a -> Unit
|
|
20
|
+
|
|
21
|
+
// function g() { f(42); h(False) }
|
|
22
|
+
// function h(y) { if(y) g() }
|
|
23
|
+
g : () -> $3
|
|
24
|
+
h : $4 -> $5
|
|
25
|
+
--
|
|
26
|
+
g : () -> Unit
|
|
27
|
+
h : Bool -> Unit
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type Quux[A, B, s](f: A =s> B)
|
|
31
|
+
type Baz[s1, s2](quux: Quux[String, Int =s1> Bool, s2])
|
|
32
|
+
|
|
33
|
+
type Foo[s](f: Int =s> String)
|
|
34
|
+
type Bar[s](foo: Foo[s])
|
|
35
|
+
|
|
36
|
+
process(term: Term): Term {
|
|
37
|
+
| ELet e => e.ELet(value = self.fixWildcards(e.value), body = self.fixWildcards(e.body))
|
|
38
|
+
| ESequential e => e.ESequential(before = self.fixWildcards(e.before), after = self.fixWildcards(e.after))
|
|
39
|
+
| EAssign e => e.EAssign(value = self.fixWildcards(e.value))
|
|
40
|
+
| EAssignField e => e.EAssignField(record = self.fixWildcards(e.record), value = self.fixWildcards(e.value))
|
|
41
|
+
| EPipe e => e.EPipe(value = self.fixWildcards(e.value), function = self.fixWildcards(e.function))
|
|
42
|
+
| ECall e =>
|
|
43
|
+
e.ECall(
|
|
44
|
+
function = self.fixWildcards(e.function),
|
|
45
|
+
arguments = e.arguments.map { a => a.Argument(value = self.fixWildcards(a.value)) }
|
|
46
|
+
)
|
|
47
|
+
| EList e =>
|
|
48
|
+
e.EList(items = e.items.map { | Pair(item, spread) =>
|
|
49
|
+
Pair(self.fixWildcards(item), spread)
|
|
50
|
+
})
|
|
51
|
+
| ECopy e =>
|
|
52
|
+
e.ECopy(
|
|
53
|
+
record = self.fixWildcards(e.record),
|
|
54
|
+
arguments = e.arguments.map { a => a.Field(value = self.fixWildcards(a.value)) }
|
|
55
|
+
)
|
|
56
|
+
| EVariant e =>
|
|
57
|
+
e.EVariant(arguments = e.arguments.map { _.map { a =>
|
|
58
|
+
a.Argument(value = self.fixWildcards(a.value))
|
|
59
|
+
}})
|
|
60
|
+
| ERecord e => e.ERecord(fields = e.fields.map { a => a.Field(value = self.fixWildcards(a.value)) })
|
|
61
|
+
| EField e => e.EField(record = self.fixWildcards(e.record))
|
|
62
|
+
| EWildcard e =>
|
|
63
|
+
self.seenWildcards += 1
|
|
64
|
+
e.EWildcard(index = self.seenWildcards)
|
|
65
|
+
| _ => term
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
data DataView {}
|
|
2
|
+
|
|
3
|
+
make(size: Int, shared: Bool = False): Buffer2
|
|
4
|
+
target js sync "return new DataView(shared_ ? new SharedArrayBuffer(size_) : new ArrayBuffer(size_))"
|
|
5
|
+
|
|
6
|
+
extend self: Buffer2 {
|
|
7
|
+
|
|
8
|
+
size(): Int
|
|
9
|
+
target js sync "return self_.byteLength"
|
|
10
|
+
|
|
11
|
+
shared(): Bool
|
|
12
|
+
target js sync "return typeof SharedArrayBuffer !== 'undefined' && self_.buffer instanceof SharedArrayBuffer"
|
|
13
|
+
|
|
14
|
+
grabBigInt64(byteOffset: Int, littleEndian: Bool = False): BigInt
|
|
15
|
+
target js sync "return self_.getBigInt64(byteOffset_, littleEndian_)"
|
|
16
|
+
|
|
17
|
+
grabBigUint64(byteOffset: Int, littleEndian: Bool = False): BigInt
|
|
18
|
+
target js sync "return self_.getBigUint64(byteOffset_, littleEndian_)"
|
|
19
|
+
|
|
20
|
+
grabFloat32(byteOffset: Int, littleEndian: Bool = False): Float
|
|
21
|
+
target js sync "return self_.getFloat32(byteOffset_, littleEndian_)"
|
|
22
|
+
|
|
23
|
+
grabFloat64(byteOffset: Int, littleEndian: Bool = False): Float
|
|
24
|
+
target js sync "return self_.getFloat64(byteOffset_, littleEndian_)"
|
|
25
|
+
|
|
26
|
+
grabInt16(byteOffset: Int, littleEndian: Bool = False): Int
|
|
27
|
+
target js sync "return self_.getInt16(byteOffset_, littleEndian_)"
|
|
28
|
+
|
|
29
|
+
grabInt32(byteOffset: Int, littleEndian: Bool = False): Int
|
|
30
|
+
target js sync "return self_.getInt32(byteOffset_, littleEndian_)"
|
|
31
|
+
|
|
32
|
+
grabInt8(byteOffset: Int, littleEndian: Bool = False): Int
|
|
33
|
+
target js sync "return self_.getInt8(byteOffset_, littleEndian_)"
|
|
34
|
+
|
|
35
|
+
grabUint16(byteOffset: Int, littleEndian: Bool = False): Int
|
|
36
|
+
target js sync "return self_.getUint16(byteOffset_, littleEndian_)"
|
|
37
|
+
|
|
38
|
+
grabUint32(byteOffset: Int, littleEndian: Bool = False): Int
|
|
39
|
+
target js sync "return self_.getUint32(byteOffset_, littleEndian_)"
|
|
40
|
+
|
|
41
|
+
grabUint8(byteOffset: Int, littleEndian: Bool = False): Int
|
|
42
|
+
target js sync "return self_.getUint8(byteOffset_, littleEndian_)"
|
|
43
|
+
|
|
44
|
+
setBigInt64(byteOffset: Int, value: BigInt, littleEndian: Bool = False): Unit
|
|
45
|
+
target js sync "self_.setBigInt64(byteOffset_, littleEndian_)"
|
|
46
|
+
|
|
47
|
+
setBigUint64(byteOffset: Int, value: BigInt, littleEndian: Bool = False): Unit
|
|
48
|
+
target js sync "self_.setBigUint64(byteOffset_, littleEndian_)"
|
|
49
|
+
|
|
50
|
+
setFloat32(byteOffset: Int, value: Float, littleEndian: Bool = False): Unit
|
|
51
|
+
target js sync "self_.setFloat32(byteOffset_, littleEndian_)"
|
|
52
|
+
|
|
53
|
+
setFloat64(byteOffset: Int, value: Float, littleEndian: Bool = False): Unit
|
|
54
|
+
target js sync "self_.setFloat64(byteOffset_, littleEndian_)"
|
|
55
|
+
|
|
56
|
+
setInt16(byteOffset: Int, value: Int, littleEndian: Bool = False): Unit
|
|
57
|
+
target js sync "self_.setInt16(byteOffset_, littleEndian_)"
|
|
58
|
+
|
|
59
|
+
setInt32(byteOffset: Int, value: Int, littleEndian: Bool = False): Unit
|
|
60
|
+
target js sync "self_.setInt32(byteOffset_, littleEndian_)"
|
|
61
|
+
|
|
62
|
+
setInt8(byteOffset: Int, value: Int, littleEndian: Bool = False): Unit
|
|
63
|
+
target js sync "self_.setInt8(byteOffset_, littleEndian_)"
|
|
64
|
+
|
|
65
|
+
setUint16(byteOffset: Int, value: Int, littleEndian: Bool = False): Unit
|
|
66
|
+
target js sync "self_.setUint16(byteOffset_, littleEndian_)"
|
|
67
|
+
|
|
68
|
+
setUint32(byteOffset: Int, value: Int, littleEndian: Bool = False): Unit
|
|
69
|
+
target js sync "self_.setUint32(byteOffset_, littleEndian_)"
|
|
70
|
+
|
|
71
|
+
setUint8(byteOffset: Int, value: Int, littleEndian: Bool = False): Unit
|
|
72
|
+
target js sync "self_.setUint8(byteOffset_, littleEndian_)"
|
|
73
|
+
|
|
74
|
+
slice(begin: Int, end: Int): Buffer2
|
|
75
|
+
target js sync "return new DataView(self_.buffer.slice(begin, end))"
|
|
76
|
+
|
|
77
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
main(system: NodeSystem) {
|
|
2
|
+
let outputFileName = system.arguments().grabFirst()
|
|
3
|
+
let fileNames = system.arguments().dropFirst()
|
|
4
|
+
let result = cat(system.files(), fileNames)
|
|
5
|
+
system.files().writeStream(outputFileName, result)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
cat(fs: FileSystem, fileNames: Array[String]): Stream[Buffer] {
|
|
9
|
+
fileNames.toStream().flatMap {fileName =>
|
|
10
|
+
fs.readStream(fileName)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
data JsValue {}
|
|
2
|
+
|
|
3
|
+
data Dictionary[K, V] {}
|
|
4
|
+
|
|
5
|
+
trait K: DictionaryKey {
|
|
6
|
+
add[V](js: JsValue, key: K, value: V): Unit
|
|
7
|
+
has(js: JsValue, key: K): Bool
|
|
8
|
+
grab[V](js: JsValue, key: K): V
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
instance Int: DictionaryKey {
|
|
12
|
+
add[V](js: JsValue, key: Int, value: V): Unit
|
|
13
|
+
target js sync "js_.set(key_, value_)"
|
|
14
|
+
has(js: JsValue, key: Int): Bool
|
|
15
|
+
target js sync "return js_.has(key_)"
|
|
16
|
+
get[V](js: JsValue, key: Int): Option[V]
|
|
17
|
+
target js sync "return js_.has(key_) ? ff_core_Option.Some(js_.get(key_)) : ff_core_Option.None()"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
instance String: DictionaryKey {
|
|
21
|
+
add[V](js: JsValue, key: String, value: V): Unit
|
|
22
|
+
target js sync "js_.set(key_, value_)"
|
|
23
|
+
has(js: JsValue, key: String): Bool
|
|
24
|
+
target js sync "return js_.has(key_)"
|
|
25
|
+
get[V](js: JsValue, key: String): Option[V]
|
|
26
|
+
target js sync "return js_.has(key_) ? ff_core_Option.Some(js_.get(key_)) : ff_core_Option.None()"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
instance Pair[A: DictionaryKey, B: DictionaryKey]: DictionaryKey {
|
|
30
|
+
add[V](basic: JsDictionary, key: Pair[A, B], value: V): Unit
|
|
31
|
+
javascript """
|
|
32
|
+
let inner = basic_.get(key_.first_)
|
|
33
|
+
if(inner === undefined) {
|
|
34
|
+
inner = new Map()
|
|
35
|
+
}
|
|
36
|
+
basic_.set(key_.first_, )
|
|
37
|
+
"""
|
|
38
|
+
has(basic: JsDictionary, key: Pair[A, B]): Bool
|
|
39
|
+
javascript """
|
|
40
|
+
return basic_.has(key_)
|
|
41
|
+
"""
|
|
42
|
+
get[V](basic: JsDictionary, key: Pair[A, B]): Option[V]
|
|
43
|
+
javascript """
|
|
44
|
+
return basic_.has(key_) ? ff_core_Option.Some(basic_.get(key_)) : ff_core_Option.None()
|
|
45
|
+
"""
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
extend self[K: DictionaryKey, V]: Dictionary[K, V] {
|
|
49
|
+
add(key: K, value: V): Unit {
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
trait Show[T] {
|
|
2
|
+
show(value: T): String
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
instance Show[List[T: Show]] {
|
|
6
|
+
show(value: List[T]) {
|
|
7
|
+
value.map { show(_) }.join(", ")
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
map[A, B](list: List[A], body: A => B): List[B] {
|
|
12
|
+
| Empty, _ => Empty
|
|
13
|
+
| Link(head, tail), _ => Link(body(head), map(tail, body))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
data Stack {
|
|
17
|
+
EmptyStack
|
|
18
|
+
PushStack(value: Int, stack: Stack)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
extend stack: Stack {
|
|
22
|
+
map(body: Int => Int): Stack {
|
|
23
|
+
switch(stack) {
|
|
24
|
+
| EmptyStack => EmptyStack
|
|
25
|
+
| PushStack s => PushStack(body(s.value), s.stack.map(body))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
user: (name: String, email: String) = (name = "Joe", email = "jj@example.com")
|
|
31
|
+
|
|
32
|
+
load(files: FileSystem, file1: String, file2: String): String {
|
|
33
|
+
try {
|
|
34
|
+
files.readText(file1) ++
|
|
35
|
+
files.readText(file2)
|
|
36
|
+
} catch(FileNotFound?) { e =>
|
|
37
|
+
""
|
|
38
|
+
} grab
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
data FileException(file: String) {
|
|
42
|
+
FileNotFound
|
|
43
|
+
AccessDenied
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
instance Exceptional[FileException]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Haskell-like Generic programming. Thanks to nathanf for instructions.
|
|
2
|
+
|
|
3
|
+
// Two fields, zero fields and a particular field
|
|
4
|
+
|
|
5
|
+
data GFields[A, B](
|
|
6
|
+
first: A
|
|
7
|
+
second: B
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
data GNoFields()
|
|
11
|
+
|
|
12
|
+
data GField[S, V](value: V)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// Two constructors, zero constructors and a particular constructor
|
|
16
|
+
|
|
17
|
+
data GConstructors[L, R] {
|
|
18
|
+
GLeft(value: L)
|
|
19
|
+
GRight(value: R)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
data GNoConstructors {}
|
|
23
|
+
|
|
24
|
+
data GConstructor[S, V](value: V)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
// Type declarations
|
|
28
|
+
|
|
29
|
+
data GType[S, C](constructors: C)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// Names and such
|
|
33
|
+
|
|
34
|
+
trait S: GFieldSymbol {
|
|
35
|
+
fieldName(): String
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
trait S: GConstructorSymbol {
|
|
39
|
+
constructorName(): String
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
trait S: GTypeSymbol {
|
|
43
|
+
typeName(): String
|
|
44
|
+
packageName(): String
|
|
45
|
+
moduleName(): String
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// The type class that converts from/to the generic representation
|
|
50
|
+
|
|
51
|
+
trait T: Generic[R] {
|
|
52
|
+
toGeneric(value: T): R
|
|
53
|
+
fromGeneric(generic: R): T
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
// Example of implementing a generic instance of Show
|
|
58
|
+
|
|
59
|
+
instance GFields[A: Show, B: Show]: Show {
|
|
60
|
+
show(v) { show(v.first) + ", " + show(v.second) }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
instance GNoFields: Show {
|
|
64
|
+
show(v) { "" }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
instance GField[S: GFieldSymbol, V: Show]: Show {
|
|
68
|
+
show(v) { fieldName[S]() + " = " + show(v.value) }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
instance GConstructors[A: Show, B: Show]: Show {
|
|
72
|
+
show(v) {
|
|
73
|
+
| GLeft(v) => show(v)
|
|
74
|
+
| GRight(v) => show(v)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
instance GConstructor[S: GConstructorSymbol, V: Show]: Show {
|
|
79
|
+
show(v) { constructorName[S]() + "(" + show(v.value) + ")" }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
instance GType[S, C: Show]: Show {
|
|
83
|
+
show(v) {
|
|
84
|
+
show(v.constructors)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
// Example of using the generic instance of Show above
|
|
90
|
+
|
|
91
|
+
trait T: Show {
|
|
92
|
+
show(value: T): String {
|
|
93
|
+
show(toGeneric(value)) // Type checked at each instance, not in the trait (to allow T: Generic[R])
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
data User(id: Int, email: String)
|
|
98
|
+
|
|
99
|
+
instance User: Show
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
// Perhaps Generic is automatic, and the instance is only in scope where the constructors of the type are accessible.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// https://datatracker.ietf.org/doc/html/rfc8305#section-5
|
|
2
|
+
|
|
3
|
+
data Ip(ipAddress: String, seconds: Duration, succeed: Bool)
|
|
4
|
+
|
|
5
|
+
main(system: NodeSystem): Unit {
|
|
6
|
+
let ips = [
|
|
7
|
+
Ip("1.1.1.1", Duration(1.7), False)
|
|
8
|
+
Ip("2.2.2.2", Duration(0.4), False)
|
|
9
|
+
Ip("3.3.3.3", Duration(1.5), True)
|
|
10
|
+
Ip("4.4.4.4", Duration(0.6), True)
|
|
11
|
+
]
|
|
12
|
+
let channel = system.tasks().channel(capacity = 2)
|
|
13
|
+
channel.write(Unit)
|
|
14
|
+
channel.write(Unit)
|
|
15
|
+
let winner = happyEyeballs(system.tasks(), channel, ips)
|
|
16
|
+
Log.debug(winner)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
happyEyeballs(taskSystem: TaskSystem, channel: Channel[Unit], ips: List[Ip]): String {
|
|
20
|
+
let ip = ips.grabFirst()
|
|
21
|
+
let nextChannel = taskSystem.channel(capacity = 2)
|
|
22
|
+
taskSystem.race([
|
|
23
|
+
{
|
|
24
|
+
channel.read()
|
|
25
|
+
Channel.readOr(channel, {_}).timeout(Duration(0.5), {})
|
|
26
|
+
nextChannel.write(Unit)
|
|
27
|
+
try {
|
|
28
|
+
taskSystem.sleep(ip.seconds)
|
|
29
|
+
if(!ip.succeed) { panic("Network error") }
|
|
30
|
+
ip.ipAddress
|
|
31
|
+
} catchAny { error =>
|
|
32
|
+
nextChannel.write(Unit)
|
|
33
|
+
error.rethrow()
|
|
34
|
+
} grab()
|
|
35
|
+
}
|
|
36
|
+
{
|
|
37
|
+
happyEyeballs(taskSystem, nextChannel, ips.dropFirst())
|
|
38
|
+
}
|
|
39
|
+
])
|
|
40
|
+
}
|