firefly-compiler 0.5.35 → 0.5.37
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 -154
- package/bin/firefly.mjs +1 -1
- package/compiler/Builder.ff +275 -277
- package/compiler/Compiler.ff +234 -233
- package/compiler/Dependencies.ff +186 -187
- package/compiler/DependencyLock.ff +17 -17
- package/compiler/Deriver.ff +23 -31
- package/compiler/Dictionaries.ff +1 -1
- package/compiler/Inference.ff +43 -20
- package/compiler/JsEmitter.ff +1437 -1282
- package/compiler/LspHook.ff +202 -202
- package/compiler/Main.ff +25 -24
- package/compiler/ModuleCache.ff +178 -178
- package/compiler/Parser.ff +36 -109
- package/compiler/Resolver.ff +5 -8
- package/compiler/Substitution.ff +1 -1
- package/compiler/Syntax.ff +1 -16
- package/compiler/Token.ff +9 -0
- package/compiler/Tokenizer.ff +4 -0
- 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 +26 -30
- package/core/Array.ff +298 -265
- package/core/Atomic.ff +63 -64
- package/core/Box.ff +7 -7
- package/core/BrowserSystem.ff +40 -40
- package/core/Buffer.ff +185 -152
- package/core/BuildSystem.ff +156 -148
- package/core/Channel.ff +95 -92
- package/core/Char.ff +3 -2
- package/core/Core.ff +16 -23
- package/core/Crypto.ff +94 -96
- package/core/Equal.ff +41 -36
- package/core/Error.ff +15 -10
- package/core/FileHandle.ff +45 -37
- package/core/Float.ff +176 -200
- package/core/HttpClient.ff +142 -148
- package/core/Instant.ff +6 -8
- package/core/Int.ff +40 -24
- package/core/IntMap.ff +61 -39
- package/core/Js.ff +305 -0
- package/core/JsSystem.ff +135 -114
- package/core/JsValue.ff +303 -159
- package/core/Json.ff +423 -443
- package/core/List.ff +482 -486
- package/core/Lock.ff +108 -144
- package/core/Log.ff +25 -14
- package/core/NodeSystem.ff +198 -191
- package/core/Ordering.ff +160 -161
- package/core/Path.ff +377 -409
- package/core/Queue.ff +90 -0
- package/core/Random.ff +140 -134
- package/core/RbMap.ff +216 -216
- package/core/Serializable.ff +16 -13
- package/core/Show.ff +44 -43
- package/core/SourceLocation.ff +68 -68
- package/core/Stream.ff +1 -1
- package/core/String.ff +224 -202
- package/core/StringMap.ff +58 -36
- package/core/Task.ff +165 -149
- 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 -0
- 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 -331
- 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 -152
- 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 -62
- 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 -172
- 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 -617
- package/lux/LuxEvent.ff +79 -116
- 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 +72 -71
- package/output/js/ff/compiler/Compiler.mjs +19 -13
- package/output/js/ff/compiler/Dependencies.mjs +8 -7
- package/output/js/ff/compiler/DependencyLock.mjs +6 -4
- package/output/js/ff/compiler/Deriver.mjs +26 -24
- package/output/js/ff/compiler/Dictionaries.mjs +14 -18
- package/output/js/ff/compiler/Environment.mjs +6 -4
- package/output/js/ff/compiler/Inference.mjs +238 -164
- package/output/js/ff/compiler/JsEmitter.mjs +1160 -350
- package/output/js/ff/compiler/JsImporter.mjs +20 -18
- package/output/js/ff/compiler/LspHook.mjs +12 -10
- package/output/js/ff/compiler/Main.mjs +61 -41
- package/output/js/ff/compiler/ModuleCache.mjs +10 -8
- package/output/js/ff/compiler/Parser.mjs +153 -669
- package/output/js/ff/compiler/Patterns.mjs +12 -10
- package/output/js/ff/compiler/Resolver.mjs +52 -78
- package/output/js/ff/compiler/Substitution.mjs +12 -16
- package/output/js/ff/compiler/Syntax.mjs +50 -341
- package/output/js/ff/compiler/Token.mjs +126 -4
- package/output/js/ff/compiler/Tokenizer.mjs +62 -52
- package/output/js/ff/compiler/Unification.mjs +74 -90
- package/output/js/ff/compiler/Wildcards.mjs +4 -2
- package/output/js/ff/compiler/Workspace.mjs +26 -20
- package/output/js/ff/core/Any.mjs +20 -20
- package/output/js/ff/core/Array.mjs +268 -175
- package/output/js/ff/core/AssetSystem.mjs +8 -6
- package/output/js/ff/core/Atomic.mjs +84 -52
- package/output/js/ff/core/Bool.mjs +6 -4
- package/output/js/ff/core/BrowserSystem.mjs +38 -29
- package/output/js/ff/core/Buffer.mjs +285 -133
- package/output/js/ff/core/BuildSystem.mjs +36 -56
- package/output/js/ff/core/Channel.mjs +250 -97
- package/output/js/ff/core/Char.mjs +5 -3
- package/output/js/ff/core/Core.mjs +28 -34
- package/output/js/ff/core/Crypto.mjs +30 -52
- package/output/js/ff/core/Duration.mjs +4 -2
- package/output/js/ff/core/Equal.mjs +14 -12
- package/output/js/ff/core/Error.mjs +17 -11
- package/output/js/ff/core/FileHandle.mjs +76 -38
- package/output/js/ff/core/Float.mjs +92 -160
- package/output/js/ff/core/HttpClient.mjs +208 -76
- package/output/js/ff/core/Instant.mjs +8 -10
- package/output/js/ff/core/Int.mjs +36 -26
- package/output/js/ff/core/IntMap.mjs +79 -33
- package/output/js/ff/core/Js.mjs +751 -0
- package/output/js/ff/core/JsSystem.mjs +54 -60
- package/output/js/ff/core/JsValue.mjs +294 -143
- package/output/js/ff/core/Json.mjs +443 -253
- package/output/js/ff/core/List.mjs +262 -214
- package/output/js/ff/core/Lock.mjs +156 -125
- package/output/js/ff/core/Log.mjs +20 -10
- package/output/js/ff/core/Map.mjs +10 -8
- package/output/js/ff/core/NodeSystem.mjs +189 -123
- package/output/js/ff/core/Nothing.mjs +4 -2
- package/output/js/ff/core/Option.mjs +40 -38
- package/output/js/ff/core/Ordering.mjs +26 -20
- package/output/js/ff/core/Pair.mjs +4 -2
- package/output/js/ff/core/Path.mjs +517 -315
- package/output/js/ff/core/Queue.mjs +306 -0
- package/output/js/ff/core/Random.mjs +141 -77
- package/output/js/ff/core/RbMap.mjs +36 -34
- package/output/js/ff/core/Serializable.mjs +44 -28
- package/output/js/ff/core/Set.mjs +6 -4
- package/output/js/ff/core/Show.mjs +8 -6
- package/output/js/ff/core/SourceLocation.mjs +4 -2
- package/output/js/ff/core/Stream.mjs +30 -50
- package/output/js/ff/core/String.mjs +263 -172
- package/output/js/ff/core/StringMap.mjs +77 -31
- package/output/js/ff/core/Task.mjs +91 -76
- package/output/js/ff/core/Try.mjs +20 -18
- package/output/js/ff/core/Unit.mjs +4 -2
- package/package.json +1 -1
- package/postgresql/Pg.ff +53 -59
- 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 -94
- 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 -685
- package/websocket/.firefly/package.ff +1 -1
- package/websocket/WebSocket.ff +100 -131
- package/core/UnsafeJs.ff +0 -42
- package/output/js/ff/core/UnsafeJs.mjs +0 -191
|
@@ -1,224 +1,224 @@
|
|
|
1
|
-
# Pattern matching
|
|
2
|
-
|
|
3
|
-
Every function lets you pattern match on its arguments. Pattern matching lets you branch on the structure of arguments and extract nested values.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
# In anonymous functions
|
|
7
|
-
|
|
8
|
-
In the following example, `map` is passed an anonymous function, which pattern matches on its argument:
|
|
9
|
-
|
|
10
|
-
```firefly
|
|
11
|
-
blockElements.map {
|
|
12
|
-
| Paragraph(text) =>
|
|
13
|
-
renderParagraph(text)
|
|
14
|
-
| Code(code, Some(type)) =>
|
|
15
|
-
renderHighlighted(code, type)
|
|
16
|
-
| Code(code, None) =>
|
|
17
|
-
renderCode(code)
|
|
18
|
-
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
19
|
-
renderVimeo(id)
|
|
20
|
-
| Video(url) =>
|
|
21
|
-
renderVideo(url)
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
In this example there are five cases, and `blockElements: List[BlockElement]` with the following type definition:
|
|
26
|
-
|
|
27
|
-
```firefly
|
|
28
|
-
data BlockElement {
|
|
29
|
-
Paragraph(text: String)
|
|
30
|
-
Code(code: String, type: Option[String])
|
|
31
|
-
Video(url: String)
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
If you have multiple arguments, you need to provide a pattern for each argument, separated by commas.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# Cases
|
|
39
|
-
|
|
40
|
-
Each case must have one or more patterns, zero or more guards, and zero or more statements.
|
|
41
|
-
|
|
42
|
-
The first case starts with a pattern that matches when the argument is `Paragraph`, and extracts its `text` field into a variable named `text`:
|
|
43
|
-
|
|
44
|
-
```firefly
|
|
45
|
-
| Paragraph(text) =>
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
The variable is in scope in the statements of the case following the `=>`.
|
|
49
|
-
The field name and the variable name do not have to be the same.
|
|
50
|
-
The variable could be named `t` or `foo`, even though the type defines a field named `text`.
|
|
51
|
-
|
|
52
|
-
The second case starts with a pattern that matches when the argument is `Code`, and the second field of that is `Some`:
|
|
53
|
-
|
|
54
|
-
```firefly
|
|
55
|
-
| Code(code, Some(type)) =>
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
The third case starts with a pattern that matches when the argument is `Code`, and the second field of that is `None`:
|
|
59
|
-
|
|
60
|
-
```firefly
|
|
61
|
-
| Code(code, None) =>
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Together with the case above, it covers all the values that can be constructed using the `Code` variant.
|
|
65
|
-
|
|
66
|
-
The fourth case starts with a pattern that matches when the argument is `Video`, and then uses a guard:
|
|
67
|
-
|
|
68
|
-
```firefly
|
|
69
|
-
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
The guard calls a function on the extracted field, and matches the result against the pattern `Some(id)`.
|
|
73
|
-
|
|
74
|
-
The fifth and final case starts with a pattern that matches when the argument is `Video`, and has no guard:
|
|
75
|
-
|
|
76
|
-
```firefly
|
|
77
|
-
| Video(url) =>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Together with the case above, it convers all the values that can be constructed using the `Video` variant.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
# Exhaustiveness
|
|
84
|
-
|
|
85
|
-
Since all the ways to construct a `BlockElement` has been covered by the cases, the pattern match is exhaustive.
|
|
86
|
-
Exhaustiveness is enforced in Firefly, so it's never possible to end up in a situation at runtime where no case matches the arguments.
|
|
87
|
-
|
|
88
|
-
Cases are tried in order until one of them matches. When a case matches, its statements will be run.
|
|
89
|
-
In this case a return value is expected, and thus the last statement must be an expression, whose value will be returned.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# Alias patterns
|
|
93
|
-
|
|
94
|
-
To extract all the fields of a variant as an anonymous record, use the a pattern like this:
|
|
95
|
-
|
|
96
|
-
```firefly
|
|
97
|
-
| Code c =>
|
|
98
|
-
renderCode(c.code)
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Here `c: (code: String, type: Option[String])` - that is, it's an anonymous record with the fields of the variant.
|
|
102
|
-
|
|
103
|
-
To pattern match on a value while also extracting that value into a variable, use a pattern like this:
|
|
104
|
-
|
|
105
|
-
```firefly
|
|
106
|
-
| Code(code, Some(_) @ typeOption) =>
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
This ensures that the case only matches if the type field is `Some`, but binds the whole option into a variable `typeOption: Option[String]`.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# In pipes
|
|
113
|
-
|
|
114
|
-
Another way to write the above is to pipe the argument into an anonymous function that pattern matches on it:
|
|
115
|
-
|
|
116
|
-
```firefly
|
|
117
|
-
blockElements.map {blockElement =>
|
|
118
|
-
blockElement.{
|
|
119
|
-
| Paragraph(text) =>
|
|
120
|
-
renderParagraph(text)
|
|
121
|
-
| Code(code, Some(type)) =>
|
|
122
|
-
renderHighlighted(code, type)
|
|
123
|
-
| Code(code, None) =>
|
|
124
|
-
renderCode(code)
|
|
125
|
-
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
126
|
-
renderVimeo(id)
|
|
127
|
-
| Video(url) =>
|
|
128
|
-
renderVideo(url)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
This is also a way to pattern match on one of many arguments, a local variable or an expression.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
# In named functions
|
|
137
|
-
|
|
138
|
-
Pattern matching may also be used for the arguments of named functions and methods. Here's an example of pattern matching in a local function:
|
|
139
|
-
|
|
140
|
-
```firefly
|
|
141
|
-
function render(element: BlockElement) {
|
|
142
|
-
| Paragraph(text) =>
|
|
143
|
-
renderParagraph(text)
|
|
144
|
-
| Code(code, Some(type)) =>
|
|
145
|
-
renderHighlighted(code, type)
|
|
146
|
-
| Code(code, None) =>
|
|
147
|
-
renderCode(code)
|
|
148
|
-
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
149
|
-
renderVimeo(id)
|
|
150
|
-
| Video(url) =>
|
|
151
|
-
renderVideo(url)
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Here's an example of pattern matching in a method:
|
|
156
|
-
|
|
157
|
-
```firefly
|
|
158
|
-
extend self: Renderer {
|
|
159
|
-
render(element: BlockElement) {
|
|
160
|
-
| Paragraph(text) =>
|
|
161
|
-
self.renderParagraph(text)
|
|
162
|
-
| Code(code, Some(type)) =>
|
|
163
|
-
self.renderHighlighted(code, type)
|
|
164
|
-
| Code(code, None) =>
|
|
165
|
-
self.renderCode(code)
|
|
166
|
-
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
167
|
-
self.renderVimeo(id)
|
|
168
|
-
| Video(url) =>
|
|
169
|
-
self.renderVideo(url)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
# Literals and wildcards
|
|
176
|
-
|
|
177
|
-
It's also possible to match on `Int`, `Char`, `String`, and `List[T]` values.
|
|
178
|
-
|
|
179
|
-
Here's an example that matches on `Int`:
|
|
180
|
-
|
|
181
|
-
```firefly
|
|
182
|
-
fib(n: Int): Int {
|
|
183
|
-
| 0 => 0
|
|
184
|
-
| 1 => 1
|
|
185
|
-
| _ => fib(n - 1) + fib(n - 2)
|
|
186
|
-
}
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
The wildcard pattern `_` matches any value without binding it to a variable.
|
|
190
|
-
|
|
191
|
-
Here's an example that matches on `Char`:
|
|
192
|
-
|
|
193
|
-
```firefly
|
|
194
|
-
extend self: Player {
|
|
195
|
-
go(key: Char) {
|
|
196
|
-
| 'w' => self.goUp()
|
|
197
|
-
| 'a' => self.goLeft()
|
|
198
|
-
| 's' => self.goDown()
|
|
199
|
-
| 'd' => self.goRight()
|
|
200
|
-
| _ =>
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
Here's an example that matches on `String`:
|
|
206
|
-
|
|
207
|
-
```firefly
|
|
208
|
-
name.{
|
|
209
|
-
| "" => "Hello, there!"
|
|
210
|
-
| _ => "Hello, " + name + "!"
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Here's an example that matches on `List[Int]`:
|
|
215
|
-
|
|
216
|
-
```firefly
|
|
217
|
-
numbers.{
|
|
218
|
-
| [] => "No numbers!"
|
|
219
|
-
| [n] => "One number, " + n + "!"
|
|
220
|
-
| [n, ...ns] => "A number, " + n + ", and " + ns.size() + " more numbers!"
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
In patterns, the spread syntax `...` matches the rest of a list.
|
|
1
|
+
# Pattern matching
|
|
2
|
+
|
|
3
|
+
Every function lets you pattern match on its arguments. Pattern matching lets you branch on the structure of arguments and extract nested values.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# In anonymous functions
|
|
7
|
+
|
|
8
|
+
In the following example, `map` is passed an anonymous function, which pattern matches on its argument:
|
|
9
|
+
|
|
10
|
+
```firefly
|
|
11
|
+
blockElements.map {
|
|
12
|
+
| Paragraph(text) =>
|
|
13
|
+
renderParagraph(text)
|
|
14
|
+
| Code(code, Some(type)) =>
|
|
15
|
+
renderHighlighted(code, type)
|
|
16
|
+
| Code(code, None) =>
|
|
17
|
+
renderCode(code)
|
|
18
|
+
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
19
|
+
renderVimeo(id)
|
|
20
|
+
| Video(url) =>
|
|
21
|
+
renderVideo(url)
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
In this example there are five cases, and `blockElements: List[BlockElement]` with the following type definition:
|
|
26
|
+
|
|
27
|
+
```firefly
|
|
28
|
+
data BlockElement {
|
|
29
|
+
Paragraph(text: String)
|
|
30
|
+
Code(code: String, type: Option[String])
|
|
31
|
+
Video(url: String)
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If you have multiple arguments, you need to provide a pattern for each argument, separated by commas.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Cases
|
|
39
|
+
|
|
40
|
+
Each case must have one or more patterns, zero or more guards, and zero or more statements.
|
|
41
|
+
|
|
42
|
+
The first case starts with a pattern that matches when the argument is `Paragraph`, and extracts its `text` field into a variable named `text`:
|
|
43
|
+
|
|
44
|
+
```firefly
|
|
45
|
+
| Paragraph(text) =>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The variable is in scope in the statements of the case following the `=>`.
|
|
49
|
+
The field name and the variable name do not have to be the same.
|
|
50
|
+
The variable could be named `t` or `foo`, even though the type defines a field named `text`.
|
|
51
|
+
|
|
52
|
+
The second case starts with a pattern that matches when the argument is `Code`, and the second field of that is `Some`:
|
|
53
|
+
|
|
54
|
+
```firefly
|
|
55
|
+
| Code(code, Some(type)) =>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The third case starts with a pattern that matches when the argument is `Code`, and the second field of that is `None`:
|
|
59
|
+
|
|
60
|
+
```firefly
|
|
61
|
+
| Code(code, None) =>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Together with the case above, it covers all the values that can be constructed using the `Code` variant.
|
|
65
|
+
|
|
66
|
+
The fourth case starts with a pattern that matches when the argument is `Video`, and then uses a guard:
|
|
67
|
+
|
|
68
|
+
```firefly
|
|
69
|
+
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The guard calls a function on the extracted field, and matches the result against the pattern `Some(id)`.
|
|
73
|
+
|
|
74
|
+
The fifth and final case starts with a pattern that matches when the argument is `Video`, and has no guard:
|
|
75
|
+
|
|
76
|
+
```firefly
|
|
77
|
+
| Video(url) =>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Together with the case above, it convers all the values that can be constructed using the `Video` variant.
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Exhaustiveness
|
|
84
|
+
|
|
85
|
+
Since all the ways to construct a `BlockElement` has been covered by the cases, the pattern match is exhaustive.
|
|
86
|
+
Exhaustiveness is enforced in Firefly, so it's never possible to end up in a situation at runtime where no case matches the arguments.
|
|
87
|
+
|
|
88
|
+
Cases are tried in order until one of them matches. When a case matches, its statements will be run.
|
|
89
|
+
In this case a return value is expected, and thus the last statement must be an expression, whose value will be returned.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# Alias patterns
|
|
93
|
+
|
|
94
|
+
To extract all the fields of a variant as an anonymous record, use the a pattern like this:
|
|
95
|
+
|
|
96
|
+
```firefly
|
|
97
|
+
| Code c =>
|
|
98
|
+
renderCode(c.code)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Here `c: (code: String, type: Option[String])` - that is, it's an anonymous record with the fields of the variant.
|
|
102
|
+
|
|
103
|
+
To pattern match on a value while also extracting that value into a variable, use a pattern like this:
|
|
104
|
+
|
|
105
|
+
```firefly
|
|
106
|
+
| Code(code, Some(_) @ typeOption) =>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
This ensures that the case only matches if the type field is `Some`, but binds the whole option into a variable `typeOption: Option[String]`.
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# In pipes
|
|
113
|
+
|
|
114
|
+
Another way to write the above is to pipe the argument into an anonymous function that pattern matches on it:
|
|
115
|
+
|
|
116
|
+
```firefly
|
|
117
|
+
blockElements.map {blockElement =>
|
|
118
|
+
blockElement.{
|
|
119
|
+
| Paragraph(text) =>
|
|
120
|
+
renderParagraph(text)
|
|
121
|
+
| Code(code, Some(type)) =>
|
|
122
|
+
renderHighlighted(code, type)
|
|
123
|
+
| Code(code, None) =>
|
|
124
|
+
renderCode(code)
|
|
125
|
+
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
126
|
+
renderVimeo(id)
|
|
127
|
+
| Video(url) =>
|
|
128
|
+
renderVideo(url)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This is also a way to pattern match on one of many arguments, a local variable or an expression.
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# In named functions
|
|
137
|
+
|
|
138
|
+
Pattern matching may also be used for the arguments of named functions and methods. Here's an example of pattern matching in a local function:
|
|
139
|
+
|
|
140
|
+
```firefly
|
|
141
|
+
function render(element: BlockElement) {
|
|
142
|
+
| Paragraph(text) =>
|
|
143
|
+
renderParagraph(text)
|
|
144
|
+
| Code(code, Some(type)) =>
|
|
145
|
+
renderHighlighted(code, type)
|
|
146
|
+
| Code(code, None) =>
|
|
147
|
+
renderCode(code)
|
|
148
|
+
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
149
|
+
renderVimeo(id)
|
|
150
|
+
| Video(url) =>
|
|
151
|
+
renderVideo(url)
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Here's an example of pattern matching in a method:
|
|
156
|
+
|
|
157
|
+
```firefly
|
|
158
|
+
extend self: Renderer {
|
|
159
|
+
render(element: BlockElement) {
|
|
160
|
+
| Paragraph(text) =>
|
|
161
|
+
self.renderParagraph(text)
|
|
162
|
+
| Code(code, Some(type)) =>
|
|
163
|
+
self.renderHighlighted(code, type)
|
|
164
|
+
| Code(code, None) =>
|
|
165
|
+
self.renderCode(code)
|
|
166
|
+
| Video(url) {vimeoId(url) | Some(id)} =>
|
|
167
|
+
self.renderVimeo(id)
|
|
168
|
+
| Video(url) =>
|
|
169
|
+
self.renderVideo(url)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# Literals and wildcards
|
|
176
|
+
|
|
177
|
+
It's also possible to match on `Int`, `Char`, `String`, and `List[T]` values.
|
|
178
|
+
|
|
179
|
+
Here's an example that matches on `Int`:
|
|
180
|
+
|
|
181
|
+
```firefly
|
|
182
|
+
fib(n: Int): Int {
|
|
183
|
+
| 0 => 0
|
|
184
|
+
| 1 => 1
|
|
185
|
+
| _ => fib(n - 1) + fib(n - 2)
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The wildcard pattern `_` matches any value without binding it to a variable.
|
|
190
|
+
|
|
191
|
+
Here's an example that matches on `Char`:
|
|
192
|
+
|
|
193
|
+
```firefly
|
|
194
|
+
extend self: Player {
|
|
195
|
+
go(key: Char) {
|
|
196
|
+
| 'w' => self.goUp()
|
|
197
|
+
| 'a' => self.goLeft()
|
|
198
|
+
| 's' => self.goDown()
|
|
199
|
+
| 'd' => self.goRight()
|
|
200
|
+
| _ =>
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Here's an example that matches on `String`:
|
|
206
|
+
|
|
207
|
+
```firefly
|
|
208
|
+
name.{
|
|
209
|
+
| "" => "Hello, there!"
|
|
210
|
+
| _ => "Hello, " + name + "!"
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Here's an example that matches on `List[Int]`:
|
|
215
|
+
|
|
216
|
+
```firefly
|
|
217
|
+
numbers.{
|
|
218
|
+
| [] => "No numbers!"
|
|
219
|
+
| [n] => "One number, " + n + "!"
|
|
220
|
+
| [n, ...ns] => "A number, " + n + ", and " + ns.size() + " more numbers!"
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
In patterns, the spread syntax `...` matches the rest of a list.
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
# Statements and expressions
|
|
2
|
-
|
|
3
|
-
In Firefly, the body of functions and methods consist of zero or more statements, separated by `;`.
|
|
4
|
-
|
|
5
|
-
When `;` is the last token on a line, it can be omitted.
|
|
6
|
-
|
|
7
|
-
A statement is either a [local function definition](functions-and-methods), a local variable definition, an assignment or an expression.
|
|
8
|
-
|
|
9
|
-
Field assignments were covered in [user defined types](user-defined types).
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# Local variables
|
|
13
|
-
|
|
14
|
-
Local variables need an initial value:
|
|
15
|
-
|
|
16
|
-
```firefly
|
|
17
|
-
let x = 42
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
This defines immutable local variable `x: Int` with the value `42`.
|
|
21
|
-
|
|
22
|
-
Variables can be reffered to by name:
|
|
23
|
-
|
|
24
|
-
```firefly
|
|
25
|
-
x + x // Returns 84
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
The type of a variable can be stated explicitly:
|
|
29
|
-
|
|
30
|
-
```firefly
|
|
31
|
-
let y: String = "Hello"
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Mutable variables are introduced using the `mutable` keyword:
|
|
35
|
-
|
|
36
|
-
```firefly
|
|
37
|
-
mutable z = 1
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
This works like `let`, except that you're allowed to update mutable variables by assigning to them:
|
|
41
|
-
|
|
42
|
-
```firefly
|
|
43
|
-
z = 2 // z is now 2
|
|
44
|
-
z += 2 // z is now 4
|
|
45
|
-
z -= 1 // z is now 3
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# Expressions
|
|
50
|
-
|
|
51
|
-
Expressions can be one of the following syntactic constructs:
|
|
52
|
-
|
|
53
|
-
```firefly
|
|
54
|
-
42 // Int literal
|
|
55
|
-
42.0 // Float literal
|
|
56
|
-
'a' // Char literal
|
|
57
|
-
"foo" // String literal
|
|
58
|
-
[] // List literal
|
|
59
|
-
{} // Function literal
|
|
60
|
-
() // Record literal
|
|
61
|
-
True // Variant construction
|
|
62
|
-
x // Variable
|
|
63
|
-
_ // Anonymous parameter
|
|
64
|
-
f() // Function call
|
|
65
|
-
x.y // Field access
|
|
66
|
-
x.V() // Copy construction
|
|
67
|
-
x.{_} // Piping
|
|
68
|
-
!x // Unary operator
|
|
69
|
-
a + b // Binary operator
|
|
70
|
-
(a + b) * c // Grouping parenthesis
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Binary operators are left associative and the operator precedence is as follows, lowest to highest:
|
|
74
|
-
|
|
75
|
-
* `||`
|
|
76
|
-
* `&&`
|
|
77
|
-
* `!=` `==`
|
|
78
|
-
* `<=` `>=` `<` `>`
|
|
79
|
-
* `+` `-`
|
|
80
|
-
* `*` `/` `%`
|
|
81
|
-
* `^`
|
|
82
|
-
* `f()`
|
|
83
|
-
* `x.y` `x.V()` `x.{_}`
|
|
84
|
-
|
|
85
|
-
Unary operators `!` and `-` have higher precedence than `^` and lower precedence than `f()`.
|
|
86
|
-
|
|
1
|
+
# Statements and expressions
|
|
2
|
+
|
|
3
|
+
In Firefly, the body of functions and methods consist of zero or more statements, separated by `;`.
|
|
4
|
+
|
|
5
|
+
When `;` is the last token on a line, it can be omitted.
|
|
6
|
+
|
|
7
|
+
A statement is either a [local function definition](functions-and-methods), a local variable definition, an assignment or an expression.
|
|
8
|
+
|
|
9
|
+
Field assignments were covered in [user defined types](user-defined types).
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Local variables
|
|
13
|
+
|
|
14
|
+
Local variables need an initial value:
|
|
15
|
+
|
|
16
|
+
```firefly
|
|
17
|
+
let x = 42
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This defines immutable local variable `x: Int` with the value `42`.
|
|
21
|
+
|
|
22
|
+
Variables can be reffered to by name:
|
|
23
|
+
|
|
24
|
+
```firefly
|
|
25
|
+
x + x // Returns 84
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The type of a variable can be stated explicitly:
|
|
29
|
+
|
|
30
|
+
```firefly
|
|
31
|
+
let y: String = "Hello"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Mutable variables are introduced using the `mutable` keyword:
|
|
35
|
+
|
|
36
|
+
```firefly
|
|
37
|
+
mutable z = 1
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This works like `let`, except that you're allowed to update mutable variables by assigning to them:
|
|
41
|
+
|
|
42
|
+
```firefly
|
|
43
|
+
z = 2 // z is now 2
|
|
44
|
+
z += 2 // z is now 4
|
|
45
|
+
z -= 1 // z is now 3
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Expressions
|
|
50
|
+
|
|
51
|
+
Expressions can be one of the following syntactic constructs:
|
|
52
|
+
|
|
53
|
+
```firefly
|
|
54
|
+
42 // Int literal
|
|
55
|
+
42.0 // Float literal
|
|
56
|
+
'a' // Char literal
|
|
57
|
+
"foo" // String literal
|
|
58
|
+
[] // List literal
|
|
59
|
+
{} // Function literal
|
|
60
|
+
() // Record literal
|
|
61
|
+
True // Variant construction
|
|
62
|
+
x // Variable
|
|
63
|
+
_ // Anonymous parameter
|
|
64
|
+
f() // Function call
|
|
65
|
+
x.y // Field access
|
|
66
|
+
x.V() // Copy construction
|
|
67
|
+
x.{_} // Piping
|
|
68
|
+
!x // Unary operator
|
|
69
|
+
a + b // Binary operator
|
|
70
|
+
(a + b) * c // Grouping parenthesis
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Binary operators are left associative and the operator precedence is as follows, lowest to highest:
|
|
74
|
+
|
|
75
|
+
* `||`
|
|
76
|
+
* `&&`
|
|
77
|
+
* `!=` `==`
|
|
78
|
+
* `<=` `>=` `<` `>`
|
|
79
|
+
* `+` `-`
|
|
80
|
+
* `*` `/` `%`
|
|
81
|
+
* `^`
|
|
82
|
+
* `f()`
|
|
83
|
+
* `x.y` `x.V()` `x.{_}`
|
|
84
|
+
|
|
85
|
+
Unary operators `!` and `-` have higher precedence than `^` and lower precedence than `f()`.
|
|
86
|
+
|