firefly-compiler 0.4.79 → 0.4.81
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 +153 -153
- package/bin/firefly.mjs +1 -1
- package/compiler/Builder.ff +257 -257
- package/compiler/Compiler.ff +227 -227
- package/compiler/Dependencies.ff +187 -187
- package/compiler/DependencyLock.ff +17 -17
- package/compiler/Inference.ff +2 -1
- package/compiler/JsEmitter.ff +940 -946
- package/compiler/LspHook.ff +202 -202
- package/compiler/Main.ff +3 -3
- package/compiler/ModuleCache.ff +178 -178
- package/compiler/Tokenizer.ff +1 -1
- package/compiler/Unification.ff +1 -1
- package/compiler/Workspace.ff +88 -88
- package/core/.firefly/include/package-lock.json +564 -564
- package/core/.firefly/include/package.json +5 -5
- package/core/.firefly/include/prepare.sh +1 -1
- package/core/.firefly/package.ff +2 -2
- package/core/Array.ff +265 -265
- package/core/Atomic.ff +64 -64
- package/core/Box.ff +7 -7
- package/core/BrowserSystem.ff +40 -40
- package/core/BuildSystem.ff +148 -148
- package/core/Crypto.ff +96 -96
- package/core/Equal.ff +36 -36
- package/core/Float.ff +25 -0
- package/core/HttpClient.ff +148 -148
- package/core/JsSystem.ff +69 -69
- package/core/Json.ff +434 -434
- package/core/List.ff +486 -486
- package/core/Lock.ff +144 -144
- package/core/NodeSystem.ff +216 -216
- package/core/Ordering.ff +161 -161
- package/core/Path.ff +401 -401
- package/core/Random.ff +134 -134
- package/core/RbMap.ff +216 -216
- package/core/Show.ff +43 -43
- package/core/SourceLocation.ff +68 -68
- package/core/Stream.ff +9 -9
- package/core/Task.ff +149 -141
- package/core/Try.ff +25 -4
- 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/random/Index.ff +53 -53
- package/experimental/random/Process.ff +120 -120
- 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 +331 -217
- package/fireflysite/ExamplesOverview.ff +40 -40
- package/fireflysite/FrontPage.ff +344 -360
- package/fireflysite/{GuideIntroduction.ff → GettingStarted.ff} +45 -52
- package/fireflysite/Guide.ff +442 -411
- package/fireflysite/Main.ff +151 -137
- package/fireflysite/MatchingPasswordsDemo.ff +82 -82
- package/fireflysite/PackagesOverview.ff +49 -49
- package/fireflysite/PostgresqlDemo.ff +34 -34
- package/fireflysite/ReferenceAll.ff +18 -0
- package/fireflysite/ReferenceIntroduction.ff +11 -0
- package/fireflysite/Styles.ff +567 -495
- package/fireflysite/Test.ff +46 -0
- package/fireflysite/assets/markdown/reference/BaseTypes.md +209 -0
- package/fireflysite/assets/markdown/reference/EmittedJavascript.md +66 -0
- package/fireflysite/assets/markdown/reference/Exceptions.md +101 -0
- package/fireflysite/assets/markdown/reference/FunctionsAndMethods.md +338 -0
- package/fireflysite/assets/markdown/reference/JavascriptInterop.md +134 -0
- package/fireflysite/assets/markdown/reference/ModulesAndPackages.md +162 -0
- package/fireflysite/assets/markdown/reference/OldStructuredConcurrency.md +48 -0
- package/fireflysite/assets/markdown/reference/PatternMatching.md +224 -0
- package/fireflysite/assets/markdown/reference/StatementsAndExpressions.md +86 -0
- package/fireflysite/assets/markdown/reference/StructuredConcurrency.md +99 -0
- package/fireflysite/assets/markdown/reference/TraitsAndInstances.md +100 -0
- package/fireflysite/assets/markdown/reference/UserDefinedTypes.md +184 -0
- package/fireflysite/assets/markdown/{ControlFlow.md → scratch/ControlFlow.md} +136 -136
- package/fireflysite/assets/markdown/scratch/Toc.md +41 -0
- package/lsp/.firefly/package.ff +1 -1
- package/lsp/CompletionHandler.ff +828 -828
- 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 +593 -487
- package/lux/LuxEvent.ff +116 -116
- package/lux/Main.ff +123 -123
- package/lux/Main2.ff +143 -143
- package/lux/TestDry.ff +27 -0
- package/output/js/ff/compiler/Builder.mjs +47 -47
- package/output/js/ff/compiler/Dependencies.mjs +3 -3
- package/output/js/ff/compiler/Inference.mjs +2 -2
- package/output/js/ff/compiler/JsEmitter.mjs +18 -72
- package/output/js/ff/compiler/Main.mjs +4 -4
- package/output/js/ff/compiler/ModuleCache.mjs +4 -4
- package/output/js/ff/core/Array.mjs +59 -59
- package/output/js/ff/core/Atomic.mjs +36 -36
- package/output/js/ff/core/BrowserSystem.mjs +11 -11
- package/output/js/ff/core/BuildSystem.mjs +30 -30
- package/output/js/ff/core/Crypto.mjs +40 -40
- package/output/js/ff/core/Float.mjs +50 -0
- package/output/js/ff/core/HttpClient.mjs +56 -56
- package/output/js/ff/core/Json.mjs +147 -147
- package/output/js/ff/core/List.mjs +50 -50
- package/output/js/ff/core/Lock.mjs +97 -97
- package/output/js/ff/core/NodeSystem.mjs +87 -87
- package/output/js/ff/core/Ordering.mjs +8 -8
- package/output/js/ff/core/Path.mjs +231 -231
- package/output/js/ff/core/Random.mjs +56 -56
- package/output/js/ff/core/Task.mjs +71 -39
- package/output/js/ff/core/Try.mjs +98 -4
- package/package.json +1 -1
- package/postgresql/Pg.ff +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 +94 -94
- package/unsafejs/UnsafeJs.ff +19 -19
- package/vscode/LICENSE.txt +21 -21
- package/vscode/Prepublish.ff +15 -15
- package/vscode/README.md +16 -16
- 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-lock.json +22 -22
- package/webserver/.firefly/include/package.json +5 -5
- package/webserver/.firefly/package.ff +2 -2
- package/webserver/WebServer.ff +685 -685
- package/websocket/.firefly/package.ff +1 -1
- package/websocket/WebSocket.ff +131 -131
- package/fireflysite/GuideAll.ff +0 -21
- package/fireflysite/GuideBaseTypes.ff +0 -168
- package/fireflysite/GuideControlFlow.ff +0 -212
- package/fireflysite/assets/markdown/Example.md +0 -78
- /package/fireflysite/assets/{NotoSansMono-Regular.ttf → font/NotoSansMono-Regular.ttf} +0 -0
- /package/fireflysite/assets/{NunitoSans-VariableFont_YTLC,opsz,wdth,wght.ttf → font/NunitoSans-VariableFont_YTLC,opsz,wdth,wght.ttf} +0 -0
- /package/fireflysite/assets/{autocomplete-small.png → image/autocomplete-small.png} +0 -0
- /package/fireflysite/assets/{autocomplete.png → image/autocomplete.png} +0 -0
- /package/fireflysite/assets/{edit-time-error.png → image/edit-time-error.png} +0 -0
- /package/fireflysite/assets/{firefly-logo-notext.png → image/firefly-logo-notext.png} +0 -0
- /package/fireflysite/assets/{firefly-logo-yellow.png → image/firefly-logo-yellow.png} +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import WebServer from ff:webserver // This is required to run the file.
|
|
2
|
+
|
|
3
|
+
nodeMain(system: NodeSystem) {
|
|
4
|
+
let f = {x, y => Pair(x, y)}
|
|
5
|
+
let g = {Pair(_, _)}
|
|
6
|
+
Log.show(f(1, 2))
|
|
7
|
+
Log.show(g(1, 2))
|
|
8
|
+
Log.show(factorial(5))
|
|
9
|
+
Log.show(factorialTail(5))
|
|
10
|
+
Log.show([1, 2].map({x => x + x}))
|
|
11
|
+
|
|
12
|
+
let x = {a, b => Pair(a, b)}(1, 2)
|
|
13
|
+
let f0: () => Unit = {42}
|
|
14
|
+
let p = {Pair(1, _)}
|
|
15
|
+
let p2 = {Pair(_, _)}
|
|
16
|
+
|
|
17
|
+
let increment: Int => Int = {i => i + 1}
|
|
18
|
+
let plus: (Int, Int) => Int = {a, b => a + b}
|
|
19
|
+
|
|
20
|
+
Log.show([1, 2].map(increment))
|
|
21
|
+
|
|
22
|
+
Log.show(p(42))
|
|
23
|
+
let f2 = {42}
|
|
24
|
+
Log.show(f2())
|
|
25
|
+
let pairs = {Pair(_, {_})}
|
|
26
|
+
let pp = pairs(42)
|
|
27
|
+
let foo = {{_ + 1}(_)}
|
|
28
|
+
Log.show(foo(1))
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
factorial(n: Int): Int {
|
|
33
|
+
if(n == 0) {
|
|
34
|
+
1
|
|
35
|
+
} else {
|
|
36
|
+
n * factorial(n - 1)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
factorialTail(n: Int, acc: Int = 1): Int {
|
|
41
|
+
if(n == 0) {
|
|
42
|
+
acc
|
|
43
|
+
} else {
|
|
44
|
+
tailcall factorialTail(n - 1, n * acc)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Base types
|
|
2
|
+
|
|
3
|
+
In Firefly, all named types are defined in a `.ff` file somewhere.
|
|
4
|
+
However, some of the types in the `ff:core` package have dedicated syntax.
|
|
5
|
+
These are considered base types and are documented in the following sections.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Bool
|
|
9
|
+
|
|
10
|
+
Values of the `Bool` type represent truth values. They are either `False` or `True`.
|
|
11
|
+
|
|
12
|
+
The type is defined in `ff:core` as follows:
|
|
13
|
+
|
|
14
|
+
```firefly
|
|
15
|
+
data Bool {
|
|
16
|
+
False
|
|
17
|
+
True
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Logical negation is an operator on booleans:
|
|
22
|
+
|
|
23
|
+
```firefly
|
|
24
|
+
!True == False
|
|
25
|
+
!False == True
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Logical and is an operator on booleans. The right hand side is only evaluated when the left hand side is `True`:
|
|
29
|
+
|
|
30
|
+
```firefly
|
|
31
|
+
True && True == True
|
|
32
|
+
True && False == False
|
|
33
|
+
False && True == False
|
|
34
|
+
False && False == False
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Logical or is an operator on booleans. The right hand side is only evaluated when the left hand side is `False`:
|
|
38
|
+
|
|
39
|
+
```firefly
|
|
40
|
+
True || True == True
|
|
41
|
+
True || False == True
|
|
42
|
+
False || True == True
|
|
43
|
+
False || False == False
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The comparison operators are supported for `Bool`:
|
|
47
|
+
|
|
48
|
+
```firefly
|
|
49
|
+
True == True // Equality
|
|
50
|
+
True != False // Inequality
|
|
51
|
+
False < True // Less than
|
|
52
|
+
False <= True // Less than or equal
|
|
53
|
+
True > False // Greater than
|
|
54
|
+
True >= True // Greater than or equal
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
In addition, the standard library defines `if`, `while`, etc. as a functions with a `Bool` condition.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Int
|
|
61
|
+
|
|
62
|
+
Values of the `Int` type represent whole numbers in the range `-9,007,199,254,740,991` to `9,007,199,254,740,991`. This range is specifically chosen to work inside the safe integer range of the `Number` type in JavaScript. Outside of this range, `Int` values may act like `Float` values.
|
|
63
|
+
|
|
64
|
+
They can be constructed using the following literal syntax:
|
|
65
|
+
|
|
66
|
+
```firefly
|
|
67
|
+
42 // Fourty two
|
|
68
|
+
0 // Zero
|
|
69
|
+
-1 // Minus one
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Basic arithmetic operators are supported:
|
|
73
|
+
|
|
74
|
+
```firefly
|
|
75
|
+
3 + 5 // Addition, == 8
|
|
76
|
+
3 - 5 // Subtraction, == -2
|
|
77
|
+
3 * 5 // Multiplication, == 15
|
|
78
|
+
-(3 + 5) // Negation, == -8
|
|
79
|
+
3 / 5 // Division, == 0.6
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
As are the comparison operators.
|
|
83
|
+
|
|
84
|
+
Note that the division `3 / 5` does not return an `Int`, but rather a `Float` value `0.6`. If you want integer division, which rounds towards zero, you can do `3.div(5) == 0`.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# Float
|
|
88
|
+
|
|
89
|
+
Values of the `Float` type are floating point numbers with the semantics of the `Number` type in JavaScript.
|
|
90
|
+
|
|
91
|
+
They be constructed using following literal syntax:
|
|
92
|
+
|
|
93
|
+
```firefly
|
|
94
|
+
42.0 // Fourty two point zero
|
|
95
|
+
0.0 // Zero point zero
|
|
96
|
+
-1.0 // Minus one point zero
|
|
97
|
+
1.0e3 // == 1000.0
|
|
98
|
+
1.0e-3 // == 0.001
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Like `Number` values in JavaScript, `Float` values may also be `Float.nan()`, `Float.infinity()` or `-Float.infinity()`.
|
|
102
|
+
|
|
103
|
+
Basic arithmetic operators are supported:
|
|
104
|
+
|
|
105
|
+
```firefly
|
|
106
|
+
3.5 + 5.75 // Addition, == 9.25
|
|
107
|
+
3.0 - 5.0 // Subtraction, == -2.0
|
|
108
|
+
3.0 * 5.0 // Multiplication, == 15.0
|
|
109
|
+
-(3.0 + 5.0) // Negation, == -8.0
|
|
110
|
+
3.0 / 5.0 // Division, == 0.6
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
As are the comparison operators.
|
|
114
|
+
However, as with `Number` values in JavaScript, comparing `Float.nan()` with any floating point value, including `Float.nan()` will return `False`.
|
|
115
|
+
To test whether a number is `Float.nan()`, use the `isNan()` method, e.g. `x.isNan()`.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Char
|
|
119
|
+
|
|
120
|
+
Values of the `Char` type represent UTF-16 code units.
|
|
121
|
+
Graphemes outside of the Unicode Basic Multilingual Plane may consist of multiple UTF-16 code units and thus require multiple `Char` values.
|
|
122
|
+
|
|
123
|
+
They can be constructed using following literal syntax, where `\` (backslash) is used to escape characters:
|
|
124
|
+
|
|
125
|
+
```firefly
|
|
126
|
+
' ' // A space
|
|
127
|
+
'\'' // Single quote
|
|
128
|
+
'\r' // Carriage return
|
|
129
|
+
'\n' // Line feed (Unix newline)
|
|
130
|
+
'\t' // Horizontal tab
|
|
131
|
+
'\\' // Backslash
|
|
132
|
+
'A' // Capital A
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The comparison operators also works for `Char` values, but note that they compare the code unit rather than compare by any language-specific character ordering.
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# String
|
|
139
|
+
|
|
140
|
+
Values of the `String` type are immutable sequences of `Char` values, representing Unicode strings.
|
|
141
|
+
|
|
142
|
+
Single line strings must be contained within a single line, and can be constructed using following literal syntax:
|
|
143
|
+
|
|
144
|
+
```firefly
|
|
145
|
+
"Hello, World!"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Multiline string literals begin and end with three double quotes, and may contain newlines:
|
|
149
|
+
|
|
150
|
+
```firefly
|
|
151
|
+
"""
|
|
152
|
+
Once upon a time,
|
|
153
|
+
in a land far, far away...
|
|
154
|
+
"""
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
There's an operator for string concatenation:
|
|
158
|
+
|
|
159
|
+
```firefly
|
|
160
|
+
"ban" + "ana" == "banana"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The comparison operators are supported, but note that they compare the string as a sequence of `Char` values rather than by any language-specific ordering.
|
|
164
|
+
|
|
165
|
+
The escape mechanism is the same as with the `Char` type.
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# List
|
|
169
|
+
|
|
170
|
+
Values of the `List[T]` types are immutable sequences of `T` values, where `T` is a type of your choice.
|
|
171
|
+
|
|
172
|
+
They can be constructed using list literals:
|
|
173
|
+
|
|
174
|
+
```firefly
|
|
175
|
+
[1, 2, 3] // A List[Int] with three elements
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Note that commas can be omitted when they would occur before a newline:
|
|
179
|
+
|
|
180
|
+
```firefly
|
|
181
|
+
[
|
|
182
|
+
1
|
|
183
|
+
2
|
|
184
|
+
3
|
|
185
|
+
]
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Lists can be flattened into other lists using the spread syntax:
|
|
189
|
+
|
|
190
|
+
```firefly
|
|
191
|
+
[1, ...[2, 3], 4, 5] == [1, 2, 3, 4, 5]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The comparison operators are available for values of type `List[T]` when they're available for values of type `T`.
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# Unit
|
|
198
|
+
|
|
199
|
+
The `Unit` type has just one possible value, and is used as the return type for functions that have no interesting return value.
|
|
200
|
+
|
|
201
|
+
The type is defined in `ff:core` as follows:
|
|
202
|
+
|
|
203
|
+
```firefly
|
|
204
|
+
data Unit {
|
|
205
|
+
Unit
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If you omit the return type, the `Unit` type is assumed. If you don't end a function with an expression, the `Unit` value is returned.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Emitted JavaScript
|
|
2
|
+
|
|
3
|
+
While most Firefly code maps directly to the JavaScript equivalent, there are two notable exceptions:
|
|
4
|
+
|
|
5
|
+
* I/O appears to be blocking, but compiles down to JavaScript `async`/`await`.
|
|
6
|
+
* Methods are resolved statically in Firefly and become top level functions in JavaScript.
|
|
7
|
+
|
|
8
|
+
In addition, pattern matching doesn't have a direct equivalent in JavaScript, and neither does traits.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Example
|
|
12
|
+
|
|
13
|
+
Consider the following main function:
|
|
14
|
+
|
|
15
|
+
```firefly
|
|
16
|
+
nodeMain(system: NodeSystem) {
|
|
17
|
+
|
|
18
|
+
let files = ["a.txt", "b.txt"]
|
|
19
|
+
|
|
20
|
+
let contents = files.map {file =>
|
|
21
|
+
system.path(file).readText()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let upper = contents.map {content =>
|
|
25
|
+
content.upper()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
system.writeLine("Result: " + upper.join(""))
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The JavaScript that's emitted looks roughly like this:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
export async function nodeMain$(system) {
|
|
37
|
+
|
|
38
|
+
const files = ["a.txt", "b.txt"]
|
|
39
|
+
|
|
40
|
+
const contents = await List_map$(files, async file => {
|
|
41
|
+
return await Path_readText$(await NodeSystem_path$(system, file))
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const upper = List_map(contents, content => {
|
|
45
|
+
return String_upper(content)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
NodeSystem_writeLine$("Result: " + String_join(upper, ""))
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
In JavaScript, `nodeMain` becomes an `async` function and gets the `$` suffix to distinguish it from a synchronous function.
|
|
54
|
+
|
|
55
|
+
The `let` keyword in Firefly corresponds to the `const` keyword in JavaScript, and Firefly list literals become JavaScript array literals.
|
|
56
|
+
|
|
57
|
+
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`.
|
|
58
|
+
A static analysis is performed to decide which version to call.
|
|
59
|
+
|
|
60
|
+
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,
|
|
61
|
+
the analysis picks the asynchronous version `List_map$` and uses the `await` keyword.
|
|
62
|
+
|
|
63
|
+
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`.
|
|
64
|
+
|
|
65
|
+
This static analysis is necessarily conservative, and may occasionally call the asynchronous version of a function where the synchrhonous version would suffice.
|
|
66
|
+
When using the VSCode extension, the hover information for a call will note if the call is asynchronous.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Exceptions
|
|
2
|
+
|
|
3
|
+
Exceptions allow a program to transfer control from the point of error to a designated exception handler, separating error-handling logic from regular program flow.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Throwing exceptions
|
|
7
|
+
|
|
8
|
+
Exceptions are thrown using the `throw` function. Example:
|
|
9
|
+
|
|
10
|
+
```firefly
|
|
11
|
+
grabOption[T](option: Option[T]): T {
|
|
12
|
+
| Some(v) => v
|
|
13
|
+
| None => throw(GrabException())
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
In this example, if the argument is `Some(v)`, then `v` is returned. Otherwise, a `GrabException` is thrown.
|
|
18
|
+
|
|
19
|
+
Any type declared with the `data` or `newtype` keyword can be thrown as an exception, since the type will have an instance for the `HasAnyTag` trait.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Catching exceptions
|
|
23
|
+
|
|
24
|
+
When an exception is thrown, it propagates up the call chain to the nearest `try`, where it can be caught:
|
|
25
|
+
|
|
26
|
+
```firefly
|
|
27
|
+
try {
|
|
28
|
+
grabOption(None)
|
|
29
|
+
} catch {| GrabException, error =>
|
|
30
|
+
Log.trace("A GrabException occurred")
|
|
31
|
+
error.rethrow()
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The first argument passed to `catch` is the thrown value, and the second parameter contains the stack trace.
|
|
36
|
+
The `rethrow()` method throws the exception again without altering the stack trace.
|
|
37
|
+
It is used when the exception is caught where it can't be fully handled.
|
|
38
|
+
|
|
39
|
+
If the exception reaches the top of the call stack, the exception value and the stack trace will be printed.
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Catching any exception
|
|
43
|
+
|
|
44
|
+
It is also posssible to catch any exception, regardless of its type, using the `catchAny` method:
|
|
45
|
+
|
|
46
|
+
```firefly
|
|
47
|
+
try {
|
|
48
|
+
let result = fragileOperation()
|
|
49
|
+
Some(result)
|
|
50
|
+
} catchAny {error =>
|
|
51
|
+
None
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Cleaning up
|
|
57
|
+
|
|
58
|
+
Cleanup often needs to happen whether or not an exception is thrown.
|
|
59
|
+
This is what the `finally` method guarantees:
|
|
60
|
+
|
|
61
|
+
```firefly
|
|
62
|
+
let fileHandle = path.readHandle()
|
|
63
|
+
try {
|
|
64
|
+
process(fileHandle)
|
|
65
|
+
} finally {
|
|
66
|
+
fileHandle.close()
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
If the program is terminated abnormally (force closed, power is lost, etc.) there is no guarantee that `finally` will get called.
|
|
71
|
+
In most environments, the operating system will occasionally terminate the program abnormally, so programs should be designed such that they can recover from abnormal termination.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Catching multiple exceptions
|
|
75
|
+
|
|
76
|
+
The `try` function returns a value of type `Try[T]` that is defined as follows:
|
|
77
|
+
|
|
78
|
+
```firefly
|
|
79
|
+
data Try[T] {
|
|
80
|
+
Success(value: T)
|
|
81
|
+
Failure(error: Error)
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The `catch`, `catchAny` and `finally` methods are defined on this type. However, since they don't return a `Try[T]` value, they can't be chained.
|
|
86
|
+
|
|
87
|
+
However, the alternative `tryCatch`, `tryCatchAny` and `tryFinally` methods do return a `Try[T]` value, and can thus be chained:
|
|
88
|
+
|
|
89
|
+
```firefly
|
|
90
|
+
try {
|
|
91
|
+
doSomething()
|
|
92
|
+
} tryCatch {| GrabException, error =>
|
|
93
|
+
reportSpecificError()
|
|
94
|
+
} tryCatchAny {error =>
|
|
95
|
+
reportGeneralError()
|
|
96
|
+
} finally {
|
|
97
|
+
performCleanup()
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The last method in the chain here is `finally`. If it was `tryFinally`, a value of type `Try[T]` would be returned.
|