firefly-compiler 0.5.39 → 0.5.40
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/.hintrc +4 -4
- package/.vscode/settings.json +4 -4
- package/bin/Release.ff +157 -157
- package/bin/firefly.mjs +1 -1
- package/compiler/Builder.ff +275 -275
- package/compiler/Compiler.ff +234 -234
- package/compiler/Dependencies.ff +186 -186
- package/compiler/DependencyLock.ff +17 -17
- package/compiler/JsEmitter.ff +1437 -1437
- package/compiler/LspHook.ff +202 -202
- package/compiler/ModuleCache.ff +178 -178
- package/compiler/Workspace.ff +88 -88
- package/core/.firefly/include/package.json +5 -5
- package/core/.firefly/package.ff +2 -2
- package/core/Any.ff +25 -25
- package/core/Array.ff +298 -298
- package/core/Atomic.ff +63 -63
- package/core/Box.ff +7 -7
- package/core/BrowserSystem.ff +40 -40
- package/core/BuildSystem.ff +156 -156
- package/core/Crypto.ff +94 -94
- package/core/Equal.ff +41 -41
- package/core/Error.ff +25 -25
- package/core/HttpClient.ff +142 -142
- package/core/Instant.ff +24 -24
- package/core/Js.ff +305 -305
- package/core/JsSystem.ff +135 -135
- package/core/Json.ff +423 -423
- package/core/List.ff +482 -482
- package/core/Lock.ff +108 -108
- package/core/NodeSystem.ff +198 -198
- package/core/Ordering.ff +160 -160
- package/core/Path.ff +377 -378
- package/core/Queue.ff +90 -90
- package/core/Random.ff +140 -140
- package/core/RbMap.ff +216 -216
- package/core/Show.ff +44 -44
- package/core/SourceLocation.ff +68 -68
- package/core/Task.ff +165 -165
- package/experimental/benchmarks/ListGrab.ff +23 -23
- package/experimental/benchmarks/ListGrab.java +55 -55
- package/experimental/benchmarks/Pyrotek45.ff +30 -30
- package/experimental/benchmarks/Pyrotek45.java +64 -64
- package/experimental/bidirectional/Bidi.ff +88 -88
- package/experimental/lines/Main.ff +40 -40
- package/experimental/random/Index.ff +53 -53
- package/experimental/random/Process.ff +120 -120
- package/experimental/random/RunLength.ff +65 -65
- package/experimental/random/Scrape.ff +51 -51
- package/experimental/random/Symbols.ff +73 -73
- package/experimental/random/Tensor.ff +52 -52
- package/experimental/random/Units.ff +36 -36
- package/experimental/s3/S3TestAuthorizationHeader.ff +39 -39
- package/experimental/s3/S3TestPut.ff +16 -16
- package/experimental/tests/TestJson.ff +26 -26
- package/firefly.sh +0 -0
- package/fireflysite/.firefly/package.ff +4 -4
- package/fireflysite/CommunityOverview.ff +20 -20
- package/fireflysite/CountingButtonDemo.ff +58 -58
- package/fireflysite/DocumentParser.ff +325 -325
- package/fireflysite/ExamplesOverview.ff +40 -40
- package/fireflysite/FrontPage.ff +344 -344
- package/fireflysite/GettingStarted.ff +45 -45
- package/fireflysite/Guide.ff +456 -456
- package/fireflysite/Main.ff +163 -163
- package/fireflysite/MatchingPasswordsDemo.ff +82 -82
- package/fireflysite/PackagesOverview.ff +49 -49
- package/fireflysite/PostgresqlDemo.ff +34 -34
- package/fireflysite/ReferenceAll.ff +18 -18
- package/fireflysite/ReferenceIntroduction.ff +11 -11
- package/fireflysite/Styles.ff +567 -567
- package/fireflysite/Test.ff +121 -121
- package/fireflysite/assets/markdown/reference/BaseTypes.md +209 -209
- package/fireflysite/assets/markdown/reference/EmittedJavascript.md +65 -65
- package/fireflysite/assets/markdown/reference/Exceptions.md +101 -101
- package/fireflysite/assets/markdown/reference/FunctionsAndMethods.md +364 -364
- package/fireflysite/assets/markdown/reference/JavascriptInterop.md +235 -235
- package/fireflysite/assets/markdown/reference/ModulesAndPackages.md +162 -162
- package/fireflysite/assets/markdown/reference/OldStructuredConcurrency.md +48 -48
- package/fireflysite/assets/markdown/reference/PatternMatching.md +224 -224
- package/fireflysite/assets/markdown/reference/StatementsAndExpressions.md +86 -86
- package/fireflysite/assets/markdown/reference/StructuredConcurrency.md +99 -99
- package/fireflysite/assets/markdown/reference/TraitsAndInstances.md +100 -100
- package/fireflysite/assets/markdown/reference/UserDefinedTypes.md +184 -184
- package/fireflysite/assets/markdown/scratch/ControlFlow.md +136 -136
- package/fireflysite/assets/markdown/scratch/Toc.md +40 -40
- package/lsp/.firefly/package.ff +1 -1
- package/lsp/CompletionHandler.ff +827 -827
- package/lsp/Handler.ff +714 -714
- package/lsp/HoverHandler.ff +79 -79
- package/lsp/LanguageServer.ff +272 -272
- package/lsp/SignatureHelpHandler.ff +55 -55
- package/lsp/SymbolHandler.ff +181 -181
- package/lsp/TestReferences.ff +17 -17
- package/lsp/TestReferencesCase.ff +7 -7
- package/lsp/stderr.txt +1 -1
- package/lsp/stdout.txt +34 -34
- package/lux/.firefly/package.ff +1 -1
- package/lux/Css.ff +648 -648
- package/lux/CssTest.ff +48 -48
- package/lux/Lux.ff +608 -608
- package/lux/LuxEvent.ff +79 -79
- package/lux/Main.ff +123 -123
- package/lux/Main2.ff +143 -143
- package/lux/TestDry.ff +28 -28
- package/output/js/ff/compiler/Builder.mjs +36 -36
- package/output/js/ff/core/Path.mjs +0 -2
- package/package.json +1 -1
- package/rpc/.firefly/package.ff +1 -1
- package/rpc/Rpc.ff +70 -70
- package/s3/.firefly/package.ff +1 -1
- package/s3/S3.ff +92 -92
- package/vscode/LICENSE.txt +21 -21
- package/vscode/Prepublish.ff +15 -15
- package/vscode/README.md +16 -16
- package/vscode/client/package-lock.json +544 -544
- package/vscode/client/package.json +22 -22
- package/vscode/client/src/extension.ts +104 -104
- package/vscode/icons/firefly-icon.svg +10 -10
- package/vscode/language-configuration.json +61 -61
- package/vscode/package-lock.json +3623 -3623
- package/vscode/package.json +1 -1
- package/vscode/snippets.json +241 -241
- package/vscode/syntaxes/firefly-markdown-injection.json +45 -45
- package/webserver/.firefly/include/package.json +5 -5
- package/webserver/.firefly/package.ff +2 -2
- package/webserver/WebServer.ff +647 -647
- package/websocket/.firefly/package.ff +1 -1
- package/websocket/WebSocket.ff +100 -100
|
@@ -1,235 +1,235 @@
|
|
|
1
|
-
# JavaScript interop
|
|
2
|
-
|
|
3
|
-
Firefly compiles to JavaScript, which enables it to run in the browser.
|
|
4
|
-
It uses Node.js as its server side and desktop runtime.
|
|
5
|
-
|
|
6
|
-
The JavaScript interop features enable the wrapping of libraries that are written in JavaScript so that they can be used in Firefly.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# The JsSystem
|
|
10
|
-
|
|
11
|
-
Most JavaScript functionality can be accessed via the `JsSystem` object.
|
|
12
|
-
|
|
13
|
-
```firefly
|
|
14
|
-
browserMain(system: BrowserSystem): Unit {
|
|
15
|
-
let js = system.js()
|
|
16
|
-
js->document->onclick = js->{
|
|
17
|
-
js->Notification->requestPermission()->then(js->{
|
|
18
|
-
js->Notification->(
|
|
19
|
-
"Hi!"
|
|
20
|
-
js->(body = "From the Firefly JS FFI")
|
|
21
|
-
)
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
This is equivalent to the following JavaScript:
|
|
28
|
-
|
|
29
|
-
```js
|
|
30
|
-
document.onclick = () =>
|
|
31
|
-
Notification.requestPermission().then(() =>
|
|
32
|
-
new Notification(
|
|
33
|
-
"Hi!",
|
|
34
|
-
{body: "From the Firefly JS FFI"}
|
|
35
|
-
)
|
|
36
|
-
)
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
The `->` is shorthand for calling the methods `get`, `set`, `increment`, `decrement`, `object`, `call1`, `new1` and `function1` (substitute 0 to 9 for 1).
|
|
40
|
-
|
|
41
|
-
The `js` variable is of the type `JsSystem` and the rest of the expressions return `JsValue`, which represents an arbitrary JavaScript value.
|
|
42
|
-
|
|
43
|
-
In addition, the `!` and `?` postfix operators can be used as shorthand for `Js.value(...)` and `Js.fromValue(...)`.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
# The Js module
|
|
47
|
-
|
|
48
|
-
This module provides access to unsafe JavaScript features:
|
|
49
|
-
|
|
50
|
-
```firefly
|
|
51
|
-
// Returns a JsSystem.
|
|
52
|
-
jsSystem(): JsSystem
|
|
53
|
-
|
|
54
|
-
// A static JS import that works anywhere but the browser target.
|
|
55
|
-
import(module: String): JsValue
|
|
56
|
-
|
|
57
|
-
// A static JS import that works in the browser target.
|
|
58
|
-
browserImport(module: String): JsValue
|
|
59
|
-
|
|
60
|
-
// A dynamic JS import.
|
|
61
|
-
dynamicImport(module: String): JsValue
|
|
62
|
-
|
|
63
|
-
// Creates an async JS function. Goes up to 9.
|
|
64
|
-
async0[R](body: () => JsValue): JsValue
|
|
65
|
-
|
|
66
|
-
// Returns True if the current target is async
|
|
67
|
-
inAsync(): Bool
|
|
68
|
-
|
|
69
|
-
// Returns True if the current target is browser
|
|
70
|
-
inBrowser(): Bool
|
|
71
|
-
|
|
72
|
-
// Returns True if the current target is node
|
|
73
|
-
inNode(): Bool
|
|
74
|
-
|
|
75
|
-
// Returns True if the current target is build
|
|
76
|
-
inBuild(): Bool
|
|
77
|
-
|
|
78
|
-
// Returns the current task.
|
|
79
|
-
currentTask(): Task
|
|
80
|
-
|
|
81
|
-
// Throws if the current task is cancelled.
|
|
82
|
-
throwIfCancelled(): Unit
|
|
83
|
-
|
|
84
|
-
// Returns True if the current task is cancelled.
|
|
85
|
-
cancelled(): Bool
|
|
86
|
-
|
|
87
|
-
// Returns the AbortController of the current task.
|
|
88
|
-
controller(): JsValue {
|
|
89
|
-
currentTask().controller
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Sets the AbortController of the current task.
|
|
93
|
-
setController(controller: JsValue)
|
|
94
|
-
|
|
95
|
-
// Gives access to the AbortSignal of the current task and resets it if needed after use.
|
|
96
|
-
withSignal[T](body: JsValue => T): T
|
|
97
|
-
|
|
98
|
-
// Awaits a JS promise.
|
|
99
|
-
await(promise: JsValue): JsValue
|
|
100
|
-
|
|
101
|
-
// Creates a promise and awaits it, while handling cancellation and cleanup. Used like:
|
|
102
|
-
// awaitCancellablePromise {resolve, reject, onSettle => ... onSettle {fulfilled => cleanup()} ...}
|
|
103
|
-
awaitCancellablePromise[T](body: (T => Unit, Error => Unit, (Bool => Unit) => Unit) => Unit): T
|
|
104
|
-
|
|
105
|
-
// Casts a Firefly value to a JS value.
|
|
106
|
-
value[T](value: T): JsValue
|
|
107
|
-
|
|
108
|
-
// Casts a JS value to a Firefly value.
|
|
109
|
-
fromValue[T](value: JsValue): T
|
|
110
|
-
|
|
111
|
-
// Throw a JS value (preferably a JS Error).
|
|
112
|
-
throw[T](value: JsValue): T
|
|
113
|
-
|
|
114
|
-
// JS operators like !
|
|
115
|
-
unaryOperator[T1: IsJsValue](operator: String, a1: T1): JsValue
|
|
116
|
-
|
|
117
|
-
// JS operators like + - *
|
|
118
|
-
binaryOperator[T1: IsJsValue, T2: IsJsValue](operator: String, a1: T1, a2: T2): JsValue
|
|
119
|
-
|
|
120
|
-
// JS operators like || && ??
|
|
121
|
-
shortCircuitingOperator[T1: IsJsValue, T2: IsJsValue](operator: String, a1: T1, a2: () => T2): JsValue
|
|
122
|
-
|
|
123
|
-
// Access a raw JS identifier.
|
|
124
|
-
rawIdentifier(operator: String): JsValue
|
|
125
|
-
|
|
126
|
-
// Returns the JS globalThis object.
|
|
127
|
-
globalThis(): JsValue
|
|
128
|
-
|
|
129
|
-
// Gets the value of a JS variable.
|
|
130
|
-
get(key: String): JsValue
|
|
131
|
-
|
|
132
|
-
// Sets the value of a JS variable.
|
|
133
|
-
set[V: IsJsValue](key: String, value: V): Unit
|
|
134
|
-
|
|
135
|
-
// Increments the value of a JS variable.
|
|
136
|
-
increment[V: IsJsValue](key: String, value: V): Unit
|
|
137
|
-
|
|
138
|
-
// Decrements the value of a JS variable.
|
|
139
|
-
decrement[V: IsJsValue](key: String, value: V): Unit
|
|
140
|
-
|
|
141
|
-
// Calls a JS variable with zero arguments. Goes up to 9.
|
|
142
|
-
call0(name: String): JsValue
|
|
143
|
-
|
|
144
|
-
// Returns JS null
|
|
145
|
-
null(): JsValue
|
|
146
|
-
|
|
147
|
-
// Returns JS undefined
|
|
148
|
-
undefined(): JsValue
|
|
149
|
-
|
|
150
|
-
// Returns JS undefined if None, and casts the value otherwise
|
|
151
|
-
orUndefined[T: IsJsValue](value: Option[T]): JsValue
|
|
152
|
-
|
|
153
|
-
// Creates an empty JS object
|
|
154
|
-
object(): JsValue
|
|
155
|
-
|
|
156
|
-
// Same as Js.object()
|
|
157
|
-
new0(): JsValue
|
|
158
|
-
|
|
159
|
-
// Cast a List to a JsValue
|
|
160
|
-
array(values: List[JsValue]): JsValue
|
|
161
|
-
|
|
162
|
-
// Cast a Json value to a JsValue
|
|
163
|
-
json(value: Json): JsValue
|
|
164
|
-
|
|
165
|
-
// A JS function of 0 parameters. Goes up to 9.
|
|
166
|
-
function0[R](body: () => R): JsValue
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
In the future, it may be possible to provide a whitelist of dependencies that are allowed to use this module.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
# Emitted JavaScript
|
|
173
|
-
|
|
174
|
-
While most Firefly code maps directly to the JavaScript equivalent, there are two notable exceptions:
|
|
175
|
-
|
|
176
|
-
* I/O appears to be blocking, but compiles down to JavaScript `async`/`await`.
|
|
177
|
-
* Methods are resolved statically in Firefly and become top level functions in JavaScript.
|
|
178
|
-
|
|
179
|
-
In addition, pattern matching doesn't have a direct equivalent in JavaScript, and neither does traits.
|
|
180
|
-
|
|
181
|
-
Consider the following main function:
|
|
182
|
-
|
|
183
|
-
```firefly
|
|
184
|
-
nodeMain(system: NodeSystem) {
|
|
185
|
-
|
|
186
|
-
let files = ["a.txt", "b.txt"]
|
|
187
|
-
|
|
188
|
-
let contents = files.map {file =>
|
|
189
|
-
system.path(file).readText()
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
let upper = contents.map {content =>
|
|
193
|
-
content.upper()
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
system.writeLine("Result: " + upper.join(""))
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
The JavaScript that's emitted looks roughly like this:
|
|
202
|
-
|
|
203
|
-
```js
|
|
204
|
-
export async function nodeMain$(system) {
|
|
205
|
-
|
|
206
|
-
const files = ["a.txt", "b.txt"]
|
|
207
|
-
|
|
208
|
-
const contents = await List_map$(files, async file => {
|
|
209
|
-
return await Path_readText$(await NodeSystem_path$(system, file))
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
const upper = List_map(contents, content => {
|
|
213
|
-
return String_upper(content)
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
NodeSystem_writeLine$("Result: " + String_join(upper, ""))
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
In JavaScript, `nodeMain` becomes an `async` function and gets the `$` suffix to distinguish it from a synchronous function.
|
|
222
|
-
|
|
223
|
-
The `let` keyword in Firefly corresponds to the `const` keyword in JavaScript, and Firefly list literals become JavaScript array literals.
|
|
224
|
-
|
|
225
|
-
The `map` method becomes a top level function, or rather, one `async` top level function named `List_map$` and another synchronous function named `List_map`.
|
|
226
|
-
A static analysis is performed to decide which version to call.
|
|
227
|
-
|
|
228
|
-
Because the first call to `map` is passed an anonymous function that calls a method on `system`, which is a capability, and the current top level function is asynchronous,
|
|
229
|
-
the analysis picks the asynchronous version `List_map$` and uses the `await` keyword.
|
|
230
|
-
|
|
231
|
-
The second call to `map` is passed an anonymous function that doesn't involve any other capabilities, the analysis picks the synchronous version `List_map`.
|
|
232
|
-
|
|
233
|
-
This static analysis is necessarily conservative, and may occasionally call the asynchronous version of a function where the synchrhonous version would suffice.
|
|
234
|
-
When using the VSCode extension, the hover information for a call will note if the call is asynchronous.
|
|
235
|
-
|
|
1
|
+
# JavaScript interop
|
|
2
|
+
|
|
3
|
+
Firefly compiles to JavaScript, which enables it to run in the browser.
|
|
4
|
+
It uses Node.js as its server side and desktop runtime.
|
|
5
|
+
|
|
6
|
+
The JavaScript interop features enable the wrapping of libraries that are written in JavaScript so that they can be used in Firefly.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# The JsSystem
|
|
10
|
+
|
|
11
|
+
Most JavaScript functionality can be accessed via the `JsSystem` object.
|
|
12
|
+
|
|
13
|
+
```firefly
|
|
14
|
+
browserMain(system: BrowserSystem): Unit {
|
|
15
|
+
let js = system.js()
|
|
16
|
+
js->document->onclick = js->{
|
|
17
|
+
js->Notification->requestPermission()->then(js->{
|
|
18
|
+
js->Notification->(
|
|
19
|
+
"Hi!"
|
|
20
|
+
js->(body = "From the Firefly JS FFI")
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This is equivalent to the following JavaScript:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
document.onclick = () =>
|
|
31
|
+
Notification.requestPermission().then(() =>
|
|
32
|
+
new Notification(
|
|
33
|
+
"Hi!",
|
|
34
|
+
{body: "From the Firefly JS FFI"}
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The `->` is shorthand for calling the methods `get`, `set`, `increment`, `decrement`, `object`, `call1`, `new1` and `function1` (substitute 0 to 9 for 1).
|
|
40
|
+
|
|
41
|
+
The `js` variable is of the type `JsSystem` and the rest of the expressions return `JsValue`, which represents an arbitrary JavaScript value.
|
|
42
|
+
|
|
43
|
+
In addition, the `!` and `?` postfix operators can be used as shorthand for `Js.value(...)` and `Js.fromValue(...)`.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# The Js module
|
|
47
|
+
|
|
48
|
+
This module provides access to unsafe JavaScript features:
|
|
49
|
+
|
|
50
|
+
```firefly
|
|
51
|
+
// Returns a JsSystem.
|
|
52
|
+
jsSystem(): JsSystem
|
|
53
|
+
|
|
54
|
+
// A static JS import that works anywhere but the browser target.
|
|
55
|
+
import(module: String): JsValue
|
|
56
|
+
|
|
57
|
+
// A static JS import that works in the browser target.
|
|
58
|
+
browserImport(module: String): JsValue
|
|
59
|
+
|
|
60
|
+
// A dynamic JS import.
|
|
61
|
+
dynamicImport(module: String): JsValue
|
|
62
|
+
|
|
63
|
+
// Creates an async JS function. Goes up to 9.
|
|
64
|
+
async0[R](body: () => JsValue): JsValue
|
|
65
|
+
|
|
66
|
+
// Returns True if the current target is async
|
|
67
|
+
inAsync(): Bool
|
|
68
|
+
|
|
69
|
+
// Returns True if the current target is browser
|
|
70
|
+
inBrowser(): Bool
|
|
71
|
+
|
|
72
|
+
// Returns True if the current target is node
|
|
73
|
+
inNode(): Bool
|
|
74
|
+
|
|
75
|
+
// Returns True if the current target is build
|
|
76
|
+
inBuild(): Bool
|
|
77
|
+
|
|
78
|
+
// Returns the current task.
|
|
79
|
+
currentTask(): Task
|
|
80
|
+
|
|
81
|
+
// Throws if the current task is cancelled.
|
|
82
|
+
throwIfCancelled(): Unit
|
|
83
|
+
|
|
84
|
+
// Returns True if the current task is cancelled.
|
|
85
|
+
cancelled(): Bool
|
|
86
|
+
|
|
87
|
+
// Returns the AbortController of the current task.
|
|
88
|
+
controller(): JsValue {
|
|
89
|
+
currentTask().controller
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Sets the AbortController of the current task.
|
|
93
|
+
setController(controller: JsValue)
|
|
94
|
+
|
|
95
|
+
// Gives access to the AbortSignal of the current task and resets it if needed after use.
|
|
96
|
+
withSignal[T](body: JsValue => T): T
|
|
97
|
+
|
|
98
|
+
// Awaits a JS promise.
|
|
99
|
+
await(promise: JsValue): JsValue
|
|
100
|
+
|
|
101
|
+
// Creates a promise and awaits it, while handling cancellation and cleanup. Used like:
|
|
102
|
+
// awaitCancellablePromise {resolve, reject, onSettle => ... onSettle {fulfilled => cleanup()} ...}
|
|
103
|
+
awaitCancellablePromise[T](body: (T => Unit, Error => Unit, (Bool => Unit) => Unit) => Unit): T
|
|
104
|
+
|
|
105
|
+
// Casts a Firefly value to a JS value.
|
|
106
|
+
value[T](value: T): JsValue
|
|
107
|
+
|
|
108
|
+
// Casts a JS value to a Firefly value.
|
|
109
|
+
fromValue[T](value: JsValue): T
|
|
110
|
+
|
|
111
|
+
// Throw a JS value (preferably a JS Error).
|
|
112
|
+
throw[T](value: JsValue): T
|
|
113
|
+
|
|
114
|
+
// JS operators like !
|
|
115
|
+
unaryOperator[T1: IsJsValue](operator: String, a1: T1): JsValue
|
|
116
|
+
|
|
117
|
+
// JS operators like + - *
|
|
118
|
+
binaryOperator[T1: IsJsValue, T2: IsJsValue](operator: String, a1: T1, a2: T2): JsValue
|
|
119
|
+
|
|
120
|
+
// JS operators like || && ??
|
|
121
|
+
shortCircuitingOperator[T1: IsJsValue, T2: IsJsValue](operator: String, a1: T1, a2: () => T2): JsValue
|
|
122
|
+
|
|
123
|
+
// Access a raw JS identifier.
|
|
124
|
+
rawIdentifier(operator: String): JsValue
|
|
125
|
+
|
|
126
|
+
// Returns the JS globalThis object.
|
|
127
|
+
globalThis(): JsValue
|
|
128
|
+
|
|
129
|
+
// Gets the value of a JS variable.
|
|
130
|
+
get(key: String): JsValue
|
|
131
|
+
|
|
132
|
+
// Sets the value of a JS variable.
|
|
133
|
+
set[V: IsJsValue](key: String, value: V): Unit
|
|
134
|
+
|
|
135
|
+
// Increments the value of a JS variable.
|
|
136
|
+
increment[V: IsJsValue](key: String, value: V): Unit
|
|
137
|
+
|
|
138
|
+
// Decrements the value of a JS variable.
|
|
139
|
+
decrement[V: IsJsValue](key: String, value: V): Unit
|
|
140
|
+
|
|
141
|
+
// Calls a JS variable with zero arguments. Goes up to 9.
|
|
142
|
+
call0(name: String): JsValue
|
|
143
|
+
|
|
144
|
+
// Returns JS null
|
|
145
|
+
null(): JsValue
|
|
146
|
+
|
|
147
|
+
// Returns JS undefined
|
|
148
|
+
undefined(): JsValue
|
|
149
|
+
|
|
150
|
+
// Returns JS undefined if None, and casts the value otherwise
|
|
151
|
+
orUndefined[T: IsJsValue](value: Option[T]): JsValue
|
|
152
|
+
|
|
153
|
+
// Creates an empty JS object
|
|
154
|
+
object(): JsValue
|
|
155
|
+
|
|
156
|
+
// Same as Js.object()
|
|
157
|
+
new0(): JsValue
|
|
158
|
+
|
|
159
|
+
// Cast a List to a JsValue
|
|
160
|
+
array(values: List[JsValue]): JsValue
|
|
161
|
+
|
|
162
|
+
// Cast a Json value to a JsValue
|
|
163
|
+
json(value: Json): JsValue
|
|
164
|
+
|
|
165
|
+
// A JS function of 0 parameters. Goes up to 9.
|
|
166
|
+
function0[R](body: () => R): JsValue
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
In the future, it may be possible to provide a whitelist of dependencies that are allowed to use this module.
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# Emitted JavaScript
|
|
173
|
+
|
|
174
|
+
While most Firefly code maps directly to the JavaScript equivalent, there are two notable exceptions:
|
|
175
|
+
|
|
176
|
+
* I/O appears to be blocking, but compiles down to JavaScript `async`/`await`.
|
|
177
|
+
* Methods are resolved statically in Firefly and become top level functions in JavaScript.
|
|
178
|
+
|
|
179
|
+
In addition, pattern matching doesn't have a direct equivalent in JavaScript, and neither does traits.
|
|
180
|
+
|
|
181
|
+
Consider the following main function:
|
|
182
|
+
|
|
183
|
+
```firefly
|
|
184
|
+
nodeMain(system: NodeSystem) {
|
|
185
|
+
|
|
186
|
+
let files = ["a.txt", "b.txt"]
|
|
187
|
+
|
|
188
|
+
let contents = files.map {file =>
|
|
189
|
+
system.path(file).readText()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let upper = contents.map {content =>
|
|
193
|
+
content.upper()
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
system.writeLine("Result: " + upper.join(""))
|
|
197
|
+
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The JavaScript that's emitted looks roughly like this:
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
export async function nodeMain$(system) {
|
|
205
|
+
|
|
206
|
+
const files = ["a.txt", "b.txt"]
|
|
207
|
+
|
|
208
|
+
const contents = await List_map$(files, async file => {
|
|
209
|
+
return await Path_readText$(await NodeSystem_path$(system, file))
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
const upper = List_map(contents, content => {
|
|
213
|
+
return String_upper(content)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
NodeSystem_writeLine$("Result: " + String_join(upper, ""))
|
|
217
|
+
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
In JavaScript, `nodeMain` becomes an `async` function and gets the `$` suffix to distinguish it from a synchronous function.
|
|
222
|
+
|
|
223
|
+
The `let` keyword in Firefly corresponds to the `const` keyword in JavaScript, and Firefly list literals become JavaScript array literals.
|
|
224
|
+
|
|
225
|
+
The `map` method becomes a top level function, or rather, one `async` top level function named `List_map$` and another synchronous function named `List_map`.
|
|
226
|
+
A static analysis is performed to decide which version to call.
|
|
227
|
+
|
|
228
|
+
Because the first call to `map` is passed an anonymous function that calls a method on `system`, which is a capability, and the current top level function is asynchronous,
|
|
229
|
+
the analysis picks the asynchronous version `List_map$` and uses the `await` keyword.
|
|
230
|
+
|
|
231
|
+
The second call to `map` is passed an anonymous function that doesn't involve any other capabilities, the analysis picks the synchronous version `List_map`.
|
|
232
|
+
|
|
233
|
+
This static analysis is necessarily conservative, and may occasionally call the asynchronous version of a function where the synchrhonous version would suffice.
|
|
234
|
+
When using the VSCode extension, the hover information for a call will note if the call is asynchronous.
|
|
235
|
+
|