firefly-compiler 0.4.79 → 0.4.80

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.
Files changed (158) hide show
  1. package/.hintrc +4 -4
  2. package/.vscode/settings.json +4 -4
  3. package/bin/Release.ff +153 -153
  4. package/bin/firefly.mjs +1 -1
  5. package/compiler/Builder.ff +257 -257
  6. package/compiler/Compiler.ff +227 -227
  7. package/compiler/Dependencies.ff +187 -187
  8. package/compiler/DependencyLock.ff +17 -17
  9. package/compiler/Inference.ff +2 -1
  10. package/compiler/JsEmitter.ff +940 -946
  11. package/compiler/LspHook.ff +202 -202
  12. package/compiler/Main.ff +3 -3
  13. package/compiler/ModuleCache.ff +178 -178
  14. package/compiler/Tokenizer.ff +1 -1
  15. package/compiler/Unification.ff +1 -1
  16. package/compiler/Workspace.ff +88 -88
  17. package/core/.firefly/include/package-lock.json +564 -564
  18. package/core/.firefly/include/package.json +5 -5
  19. package/core/.firefly/include/prepare.sh +1 -1
  20. package/core/.firefly/package.ff +2 -2
  21. package/core/Array.ff +265 -265
  22. package/core/Atomic.ff +64 -64
  23. package/core/Box.ff +7 -7
  24. package/core/BrowserSystem.ff +40 -40
  25. package/core/BuildSystem.ff +148 -148
  26. package/core/Crypto.ff +96 -96
  27. package/core/Equal.ff +36 -36
  28. package/core/Float.ff +25 -0
  29. package/core/HttpClient.ff +148 -148
  30. package/core/JsSystem.ff +69 -69
  31. package/core/Json.ff +434 -434
  32. package/core/List.ff +486 -486
  33. package/core/Lock.ff +144 -144
  34. package/core/NodeSystem.ff +216 -216
  35. package/core/Ordering.ff +161 -161
  36. package/core/Path.ff +401 -401
  37. package/core/Random.ff +134 -134
  38. package/core/RbMap.ff +216 -216
  39. package/core/Show.ff +43 -43
  40. package/core/SourceLocation.ff +68 -68
  41. package/core/Stream.ff +9 -9
  42. package/core/Task.ff +141 -141
  43. package/core/Try.ff +25 -4
  44. package/experimental/benchmarks/ListGrab.ff +23 -23
  45. package/experimental/benchmarks/ListGrab.java +55 -55
  46. package/experimental/benchmarks/Pyrotek45.ff +30 -30
  47. package/experimental/benchmarks/Pyrotek45.java +64 -64
  48. package/experimental/bidirectional/Bidi.ff +88 -88
  49. package/experimental/random/Index.ff +53 -53
  50. package/experimental/random/Process.ff +120 -120
  51. package/experimental/random/Scrape.ff +51 -51
  52. package/experimental/random/Symbols.ff +73 -73
  53. package/experimental/random/Tensor.ff +52 -52
  54. package/experimental/random/Units.ff +36 -36
  55. package/experimental/s3/S3TestAuthorizationHeader.ff +39 -39
  56. package/experimental/s3/S3TestPut.ff +16 -16
  57. package/experimental/tests/TestJson.ff +26 -26
  58. package/firefly.sh +0 -0
  59. package/fireflysite/.firefly/package.ff +4 -4
  60. package/fireflysite/CommunityOverview.ff +20 -20
  61. package/fireflysite/CountingButtonDemo.ff +58 -58
  62. package/fireflysite/DocumentParser.ff +331 -217
  63. package/fireflysite/ExamplesOverview.ff +40 -40
  64. package/fireflysite/FrontPage.ff +344 -360
  65. package/fireflysite/{GuideIntroduction.ff → GettingStarted.ff} +45 -52
  66. package/fireflysite/Guide.ff +443 -411
  67. package/fireflysite/Main.ff +141 -137
  68. package/fireflysite/MatchingPasswordsDemo.ff +82 -82
  69. package/fireflysite/PackagesOverview.ff +49 -49
  70. package/fireflysite/PostgresqlDemo.ff +34 -34
  71. package/fireflysite/ReferenceAll.ff +19 -0
  72. package/fireflysite/ReferenceIntroduction.ff +11 -0
  73. package/fireflysite/Styles.ff +567 -495
  74. package/fireflysite/Test.ff +38 -0
  75. package/fireflysite/assets/markdown/reference/BaseTypes.md +209 -0
  76. package/fireflysite/assets/markdown/reference/FunctionsAndMethods.md +208 -0
  77. package/fireflysite/assets/markdown/reference/ModulesAndPackages.md +168 -0
  78. package/fireflysite/assets/markdown/reference/PatternMatching.md +224 -0
  79. package/fireflysite/assets/markdown/reference/StatementsAndExpressions.md +86 -0
  80. package/fireflysite/assets/markdown/reference/TraitsAndInstances.md +100 -0
  81. package/fireflysite/assets/markdown/reference/UserDefinedTypes.md +184 -0
  82. package/fireflysite/assets/markdown/{ControlFlow.md → scratch/ControlFlow.md} +136 -136
  83. package/fireflysite/assets/markdown/scratch/Toc.md +41 -0
  84. package/lsp/.firefly/package.ff +1 -1
  85. package/lsp/CompletionHandler.ff +828 -828
  86. package/lsp/Handler.ff +714 -714
  87. package/lsp/HoverHandler.ff +79 -79
  88. package/lsp/LanguageServer.ff +272 -272
  89. package/lsp/SignatureHelpHandler.ff +55 -55
  90. package/lsp/SymbolHandler.ff +181 -181
  91. package/lsp/TestReferences.ff +17 -17
  92. package/lsp/TestReferencesCase.ff +7 -7
  93. package/lsp/stderr.txt +1 -1
  94. package/lsp/stdout.txt +34 -34
  95. package/lux/.firefly/package.ff +1 -1
  96. package/lux/Css.ff +648 -648
  97. package/lux/CssTest.ff +48 -48
  98. package/lux/Lux.ff +487 -487
  99. package/lux/LuxEvent.ff +116 -116
  100. package/lux/Main.ff +123 -123
  101. package/lux/Main2.ff +143 -143
  102. package/output/js/ff/compiler/Builder.mjs +47 -47
  103. package/output/js/ff/compiler/Dependencies.mjs +3 -3
  104. package/output/js/ff/compiler/Inference.mjs +2 -2
  105. package/output/js/ff/compiler/JsEmitter.mjs +18 -72
  106. package/output/js/ff/compiler/Main.mjs +4 -4
  107. package/output/js/ff/compiler/ModuleCache.mjs +4 -4
  108. package/output/js/ff/core/Array.mjs +59 -59
  109. package/output/js/ff/core/Atomic.mjs +36 -36
  110. package/output/js/ff/core/BrowserSystem.mjs +11 -11
  111. package/output/js/ff/core/BuildSystem.mjs +30 -30
  112. package/output/js/ff/core/Crypto.mjs +40 -40
  113. package/output/js/ff/core/Float.mjs +50 -0
  114. package/output/js/ff/core/HttpClient.mjs +56 -56
  115. package/output/js/ff/core/Json.mjs +147 -147
  116. package/output/js/ff/core/List.mjs +50 -50
  117. package/output/js/ff/core/Lock.mjs +97 -97
  118. package/output/js/ff/core/NodeSystem.mjs +87 -87
  119. package/output/js/ff/core/Ordering.mjs +8 -8
  120. package/output/js/ff/core/Path.mjs +231 -231
  121. package/output/js/ff/core/Random.mjs +56 -56
  122. package/output/js/ff/core/Task.mjs +39 -39
  123. package/output/js/ff/core/Try.mjs +98 -4
  124. package/package.json +1 -1
  125. package/postgresql/Pg.ff +1 -1
  126. package/rpc/.firefly/package.ff +1 -1
  127. package/rpc/Rpc.ff +70 -70
  128. package/s3/.firefly/package.ff +1 -1
  129. package/s3/S3.ff +94 -94
  130. package/unsafejs/UnsafeJs.ff +19 -19
  131. package/vscode/LICENSE.txt +21 -21
  132. package/vscode/Prepublish.ff +15 -15
  133. package/vscode/README.md +16 -16
  134. package/vscode/client/package.json +22 -22
  135. package/vscode/client/src/extension.ts +104 -104
  136. package/vscode/icons/firefly-icon.svg +10 -10
  137. package/vscode/language-configuration.json +61 -61
  138. package/vscode/package-lock.json +3623 -3623
  139. package/vscode/package.json +1 -1
  140. package/vscode/snippets.json +241 -241
  141. package/vscode/syntaxes/firefly-markdown-injection.json +45 -45
  142. package/webserver/.firefly/include/package-lock.json +22 -22
  143. package/webserver/.firefly/include/package.json +5 -5
  144. package/webserver/.firefly/package.ff +2 -2
  145. package/webserver/WebServer.ff +685 -685
  146. package/websocket/.firefly/package.ff +1 -1
  147. package/websocket/WebSocket.ff +131 -131
  148. package/fireflysite/GuideAll.ff +0 -21
  149. package/fireflysite/GuideBaseTypes.ff +0 -168
  150. package/fireflysite/GuideControlFlow.ff +0 -212
  151. package/fireflysite/assets/markdown/Example.md +0 -78
  152. /package/fireflysite/assets/{NotoSansMono-Regular.ttf → font/NotoSansMono-Regular.ttf} +0 -0
  153. /package/fireflysite/assets/{NunitoSans-VariableFont_YTLC,opsz,wdth,wght.ttf → font/NunitoSans-VariableFont_YTLC,opsz,wdth,wght.ttf} +0 -0
  154. /package/fireflysite/assets/{autocomplete-small.png → image/autocomplete-small.png} +0 -0
  155. /package/fireflysite/assets/{autocomplete.png → image/autocomplete.png} +0 -0
  156. /package/fireflysite/assets/{edit-time-error.png → image/edit-time-error.png} +0 -0
  157. /package/fireflysite/assets/{firefly-logo-notext.png → image/firefly-logo-notext.png} +0 -0
  158. /package/fireflysite/assets/{firefly-logo-yellow.png → image/firefly-logo-yellow.png} +0 -0
@@ -1,360 +1,344 @@
1
- import Guide
2
- import CountingButtonDemo
3
- import MatchingPasswordsDemo
4
-
5
- new(): Document {
6
- ReadyDocument([
7
- /*Section("Is DX an add-on feature?", [
8
- Paragraph([
9
- Bold("We don't think so.")
10
- Text("Firefly is designed from the ground up as a full stack language with great developer experience.")
11
- ])
12
- Image("/assets/autocomplete.png")
13
- Paragraph([
14
- Italic("Firefly in VSCode, showcasing instant type driven autocompletion and edit time error detection.")
15
- Italic("An example of DX that's only possible for a certain class of languages. Read on for more Firefly DX.")
16
- ])
17
- ])*/
18
- Section("The full stack programming language", [
19
- Paragraph([
20
- Text("Firefly doesn't just run in the browser and on the server,")
21
- Text("it comes with a complete stack that allows you to implement full webapps.")
22
- Text("Everything in the stack is designed to fit together nicely, all with excellent IDE support.")
23
- Text("It's really easy to ")
24
- Link("get started", "/guide/")
25
- Text("and there's no magic.")
26
- ])
27
- ])
28
- SplitSection(
29
- "Single file webapps"
30
- Paragraph([
31
- Text("Firefly code runs in the browser and on the server, or even at build time.")
32
- Text("When starting out, you can put everything in a single")
33
- Code(".ff")
34
- Text("file, including your dependency list.")
35
- Text("As the code base grows, you can split it into multiple files or packages.")
36
- ])
37
- CodeBlock("""
38
- dependency ff:webserver:0.0.0
39
-
40
- // Runs on the server
41
- nodeMain(system: NodeSystem) {...}
42
-
43
- // Runs in the browser
44
- browserMain(system: BrowserSystem) {...}
45
-
46
- // Runs at build time
47
- buildMain(system: BuildSystem) {...}
48
- """, firefly = True)
49
- )
50
- SplitSection(
51
- "Concise type definitions"
52
- Paragraph([
53
- Text("Model your types in a brief format that fits multiple definitions on one screen.")
54
- Text("Be precise about whether things can be missing with")
55
- Code("Option[T]", firefly = True)
56
- Text("and make invalid states unrepresentable with variants and type parameters.")
57
- ])
58
- CodeBlock("""
59
- data User(
60
- id: UserId
61
- name: String
62
- email: Option[String]
63
- )
64
-
65
- data Tree[T] {
66
- Leaf(value: T)
67
- Branch(left: Tree[T], right: Tree[T])
68
- }
69
- """, firefly = True)
70
- )
71
- SplitSection(
72
- "Convenient collections"
73
- Paragraph([
74
- Text("Immutable and mutable collections are part of the standard library.")
75
- Text("Maps, sets, arrays, lists and streams come with a rich set of methods that you can use to write code that's instantly clear to the reader.")
76
- ])
77
- CodeBlock("""
78
- let emails = houses
79
- .flatMap {_.owners}
80
- .map {_.email}
81
- .filter {!_.endsWith("example.com")}
82
- .toSet()
83
-
84
- emails.each {email =>
85
- sendNeighborhoodNewsletter(email)
86
- }
87
- """, firefly = True)
88
- )
89
- SplitSection(
90
- "Deep pattern matching"
91
- Paragraph([
92
- Text("You can directly pattern match on function arguments, even in lambda functions.")
93
- Text("The compiler checks for exhaustiveness, ensuring that all possible cases are covered.")
94
- Text("Pattern guards are supported, so you can extract things with arbitrary logic.")
95
- ])
96
- CodeBlock("""
97
- blockElements.map {
98
- | Paragraph(inlines) =>
99
- renderParagraph(inlines)
100
- | Code(code, Some(language)) =>
101
- renderHighlighted(code, language)
102
- | Code(code, None) =>
103
- renderCode(code)
104
- | Video(url) {vimeoId(url) | Some(id)} =>
105
- renderVimeo(id)
106
- | Video(url) =>
107
- renderVideo(url)
108
- }
109
- """, firefly = True)
110
- )
111
- SplitSection(
112
- "Edit time error detection"
113
- Paragraph([
114
- Text("In Firefly, a large class of errors is detected by the IDE as you type.")
115
- Text("You can usually fix these without even reading the error message.")
116
- Text("And when you need to read the error messages, they're short and to the point.")
117
- ])
118
- Image("/assets/edit-time-error.png")
119
- )
120
- SplitSection(
121
- "Type driven autocompletion"
122
- Paragraph([
123
- Text("The language server comes with type driven autocompletion.")
124
- Text("It instantly presents a very precise list of completions, and the expected type is used to preselect a likely completion.")
125
- ])
126
- Image("/assets/autocomplete-small.png")
127
- )
128
- SplitSection(
129
- "No async dilemma"
130
- Paragraph([
131
- Text("In Firefly, there's no")
132
- Code("async")
133
- Text("or")
134
- Code("await")
135
- Text("syntax.")
136
- Text("Instead, the compiler infers which calls are asynchronous and automatically generates the appropriate code.")
137
- Text("A method like")
138
- Code(".map")
139
- Text("on lists is called asynchronously only when the lambda function you pass is asynchronous.")
140
- ])
141
- CodeBlock("""
142
- let files = ["a.txt", "b.txt"]
143
- // async .map call
144
- let contents = files.map {file =>
145
- system.path(file).readText()
146
- }
147
- // sync .map call
148
- let upper = contents.map {content =>
149
- content.upper()
150
- }
151
- """, firefly = True)
152
- )
153
- SplitSection(
154
- "No hidden I/O"
155
- Paragraph([
156
- Text("The main function is passed a")
157
- Code("system")
158
- Text("argument that represents all the I/O you can do.")
159
- Text("It's a plain object, and you can simply wrap it to create a new")
160
- Text("object with less capabilities. You can tell what effects a top level function")
161
- Text("can have simply by looking at what arguments it receives.")
162
- ])
163
- CodeBlock("""
164
- nodeMain(system: NodeSytem) {
165
- let html = fetchSite(system.httpClient())
166
- system.writeLine(html)
167
- }
168
-
169
- // this function can only do HTTP requests
170
- fetchSite(httpClient: HttpClient): String {
171
- let url = "https://www.example.com/"
172
- httpClient.get(url, []) {_.readText()}
173
- }
174
- """, firefly = True)
175
- )
176
- SplitSection(
177
- "Structural equality"
178
- Paragraph([
179
- Text("Traits are used for equality, ordering etc., and the core traits are automatically implemented for")
180
- Code("data")
181
- Text("types if you don't supply your own implementation.")
182
- Text("They make")
183
- Code("==")
184
- Text("and")
185
- Code("<")
186
- Text("type safe, unlike in most languages, and")
187
- Text("they're a lot simpler than the traits you find in Rust.")
188
- ])
189
- CodeBlock("""
190
- trait T: Order {
191
- compare(x: T, y: T): Ordering
192
- }
193
-
194
- instance Bool: Order {
195
- compare(x: Bool, y: Bool): Ordering {
196
- | False, True => OrderingBefore
197
- | True, False => OrderingAfter
198
- | _, _ => OrderingSame
199
- }
200
- }
201
- """, firefly = True)
202
- )
203
- /*
204
- SplitSection(
205
- "Batteries included"
206
- Paragraph([
207
- Text("The standard library contains functionality that's required by most applications.")
208
- Text("Apart from what you've seen above, there's also the following modules.")
209
- ])
210
- Bullets([
211
- [Bold("Random:"), Text("Pseudorandom numbers")]
212
- [Bold("Instant:"), Text("UTC timestamps")]
213
- [Bold("Json:"), Text("JSON support")]
214
- [Bold("Buffer:"), Text("Binary data")]
215
- [Bold("Stream:"), Text("Streams (sync or async)")]
216
- [Bold("Task:"), Text("Structured concurrency")]
217
- [Bold("Log:"), Text("Simple logging")]
218
- ])
219
- )
220
- */
221
- Section("The Firefly Stack", [
222
- Paragraph([
223
- Bold("The Firefly Stack is a set of packages for building webapps.")
224
- Text("The packages are maintained by the developers of Firefly.")
225
- Text("You can use them individually or together.")
226
- Italic("Here's what you can do with that.")
227
- ])
228
- ])
229
- SplitSection(
230
- "Interactive webapps"
231
- Paragraph([
232
- Text("The")
233
- Code("ff:lux")
234
- Text("package provides a declarative DOM framework for building highly interactive webapps.")
235
- Text("Tasks that belong to removed nodes are automatically cancelled.")
236
- Text("All without any virtual DOM.")
237
- ])
238
- CodeBlock("""
239
- lux.useState(0): count, setCount =>
240
- lux.button {
241
- lux.text("Clicked " + count + " times")
242
- lux.onClick {event =>
243
- event.preventDefault()
244
- setCount(count + 1)
245
- }
246
- }
247
- """, firefly = True)
248
- )
249
- SplitSection(
250
- "Type safe RPC"
251
- Paragraph([
252
- Text("All your custom")
253
- Code("data")
254
- Text("types are automatically serializable in Firefly.")
255
- Text("With ")
256
- Code("ff:rpc")
257
- Text("you can set up type safe remote procedure calls from the browser to the webserver or between services.")
258
- Text("You can even")
259
- Italic("go to definition")
260
- Text("across RPC boundaries.")
261
- ])
262
- CodeBlock("""
263
- data Message(text: String)
264
- instance Message: Rpc[Int]
265
-
266
- // the browser sends a Message
267
- let client = Rpc.newClient(...)
268
- let messageId = client.call(Message("Hello"))
269
-
270
- // the webserver replies with an Int
271
- let server = Rpc.newServer(...)
272
- server.add {| context, Message(text) => 42 }
273
- """, firefly = True)
274
- )
275
- SplitSection(
276
- "WebSocket server & client"
277
- Paragraph([
278
- Text("The ")
279
- Code("ff:webserver")
280
- Text("package comes with WebSocket support.")
281
- Text("In just a few lines of code, you can start serving WebSockets.")
282
- Text("The ")
283
- Code("ff:websocket")
284
- Text("package allows you to connect to any WebSocket server.")
285
- Text("If both ends are running Firefly, you can use the built-in binary serialization.")
286
- ])
287
- CodeBlock("""
288
- let server = WebServer.new(system, host, port)
289
- server.enableWebSockets()
290
-
291
- server.listen {request =>
292
- let ws = request.openWebSocket()
293
- ws.subscribe("chat")
294
- while {True} {
295
- let message = ws.readText().grab()
296
- ws.publishText("chat", message)
297
- }
298
- }
299
- """.replace("'''", "\"\"\""), firefly = True)
300
- )
301
- SplitSection(
302
- "Database pooling"
303
- Paragraph([
304
- Text("The")
305
- Code("ff:postgresql")
306
- Text("package lets you create a connection pool for a PostgreSQL database.")
307
- Text("You can then execute transactions and build stateful applications.")
308
- ])
309
- CodeBlock("""
310
- let pool = Pg.newPool(...)
311
-
312
- let emails = pool.transaction {connection =>
313
- connection
314
- .statement('''
315
- select email from users
316
- where id <= $maxId
317
- ''')
318
- .withInt("maxId", 100)
319
- .map {_.getString("email").grab()}
320
- }
321
- """.replace("'''", "\"\"\""), firefly = True)
322
- )
323
- Section("What Firefly doesn't have", [
324
- Bullets([
325
- [
326
- Bold("No function overloading.")
327
- Text("Overloading leads to uninformative \"No matching overload\" errors.")
328
- ]
329
- [
330
- Bold("No implicit casts.")
331
- Text("Ever recieved an email addressed to \"Dear None\"? Static types fail to prevent this if you can implicitly cast an Option[T] to a String.")
332
- ]
333
- [
334
- Bold("No dynamic typing.")
335
- Text("Dynamic typing causes runtime errors and encourages hidden and underspecified contracts that makes refactoring harder than it needs to be.")
336
- ]
337
- [
338
- Bold("No nulls.")
339
- Text("Eliminating null ensures types accurately represent known values, reducing runtime errors and redundant checks.")
340
- ]
341
- [
342
- Bold("No subtyping.")
343
- Text("Subtyping introduces complexity via type bounds and variance. It also allows mixing loosely related types, promoting incomplete runtime type checks.")
344
- ]
345
- [
346
- Bold("No inheritance.")
347
- Text("Inheritance can lead to overgeneralization and scattering of business logic, making it hard to get the full picture at any level.")
348
- ]
349
- [
350
- Bold("No macros.")
351
- Text("Macros let you define whole new languages, that are typically wildly undertooled compared to the base language.")
352
- ]
353
- [
354
- Bold("No type level programming.")
355
- Text("Type level programming leads to inscrutable function signatures and hard to understand error messages.")
356
- ]
357
- ])
358
- ])
359
- ])
360
- }
1
+ import Guide
2
+ import CountingButtonDemo
3
+ import MatchingPasswordsDemo
4
+
5
+ new(): Document {
6
+ ReadyDocument([
7
+ Section("The full-stack programming language", [
8
+ Paragraph([
9
+ Text("Firefly code runs in the browser and on the server, or even at build time. ")
10
+ Text("You can implement highly interactive webapps without resorting to JavaScript. ")
11
+ Text("The basic skeleton of a webapp looks like this: ")
12
+ ])
13
+ CodeBlock("""
14
+ dependency ff:webserver:0.0.0
15
+
16
+ // Runs on the server
17
+ nodeMain(system: NodeSystem) {...}
18
+
19
+ // Runs in the browser
20
+ browserMain(system: BrowserSystem) {...}
21
+
22
+ // Runs at build time
23
+ buildMain(system: BuildSystem) {...}
24
+ """, firefly = True)
25
+ Paragraph([
26
+ Text("When starting out, you can put everything in a single ")
27
+ Code(".ff")
28
+ Text(" file, including your dependency list. ")
29
+ Text("As the code base grows, you can split it into multiple files and packages. ")
30
+ Text("Read on for a tour of the language. ")
31
+ ])
32
+ ])
33
+ SplitSection(
34
+ "Concise type definitions"
35
+ Paragraph([
36
+ Text("Model your types in a brief format that fits multiple definitions on one screen.")
37
+ Text("Be precise about whether things can be missing with")
38
+ Code("Option[T]", firefly = True)
39
+ Text("and make invalid states unrepresentable with variants and type parameters.")
40
+ ])
41
+ CodeBlock("""
42
+ data User(
43
+ id: UserId
44
+ name: String
45
+ email: Option[String]
46
+ )
47
+
48
+ data BlockElement {
49
+ Paragraph(text: String)
50
+ Code(code: String, type: Option[String])
51
+ Video(url: String)
52
+ }
53
+ """, firefly = True)
54
+ )
55
+ SplitSection(
56
+ "Deep pattern matching"
57
+ Paragraph([
58
+ Text("You can directly pattern match on function arguments, even in lambda functions.")
59
+ Text("The compiler checks for exhaustiveness, ensuring that all possible cases are covered.")
60
+ Text("Pattern guards are supported, so you can extract things with arbitrary logic.")
61
+ ])
62
+ CodeBlock("""
63
+ blockElements.map {
64
+ | Paragraph(text) =>
65
+ renderParagraph(text)
66
+ | Code(code, Some(type)) =>
67
+ renderHighlighted(code, type)
68
+ | Code(code, None) =>
69
+ renderCode(code)
70
+ | Video(url) {vimeoId(url) | Some(id)} =>
71
+ renderVimeo(id)
72
+ | Video(url) =>
73
+ renderVideo(url)
74
+ }
75
+ """, firefly = True)
76
+ )
77
+ SplitSection(
78
+ "Convenient collections"
79
+ Paragraph([
80
+ Text("Immutable and mutable collections are part of the standard library.")
81
+ Text("Maps, sets, arrays, lists and streams come with a rich set of methods that you can use to write code that's instantly clear to the reader.")
82
+ ])
83
+ CodeBlock("""
84
+ let emails = houses
85
+ .flatMap {_.owners}
86
+ .map {_.email}
87
+ .filter {!_.endsWith("example.com")}
88
+ .toSet()
89
+
90
+ emails.each {email =>
91
+ sendNeighborhoodNewsletter(email)
92
+ }
93
+ """, firefly = True)
94
+ )
95
+ SplitSection(
96
+ "Edit time error detection"
97
+ Paragraph([
98
+ Text("In Firefly, a large class of errors is detected by the IDE as you type.")
99
+ Text("You can usually fix these without even reading the error message.")
100
+ Text("And when you need to read the error messages, they're short and to the point.")
101
+ ])
102
+ Image("/assets/image/edit-time-error.png")
103
+ )
104
+ SplitSection(
105
+ "Type driven autocompletion"
106
+ Paragraph([
107
+ Text("The language server comes with type driven autocompletion.")
108
+ Text("It instantly presents a very precise list of completions, and the expected type is used to preselect a likely completion.")
109
+ ])
110
+ Image("/assets/image/autocomplete-small.png")
111
+ )
112
+ SplitSection(
113
+ "No async dilemma"
114
+ Paragraph([
115
+ Text("In Firefly, there's no")
116
+ Code("async")
117
+ Text("or")
118
+ Code("await")
119
+ Text("syntax.")
120
+ Text("Instead, the compiler infers which calls are asynchronous and automatically generates the appropriate code.")
121
+ Text("A method like")
122
+ Code(".map")
123
+ Text("on lists is called asynchronously only when the lambda function you pass is asynchronous.")
124
+ ])
125
+ CodeBlock("""
126
+ let files = ["a.txt", "b.txt"]
127
+ // async .map call
128
+ let contents = files.map {file =>
129
+ system.path(file).readText()
130
+ }
131
+ // sync .map call
132
+ let upper = contents.map {content =>
133
+ content.upper()
134
+ }
135
+ """, firefly = True)
136
+ )
137
+ SplitSection(
138
+ "No hidden I/O"
139
+ Paragraph([
140
+ Text("The main function is passed a")
141
+ Code("system")
142
+ Text("argument that represents all the I/O you can do.")
143
+ Text("It's a plain object, and you can simply wrap it to create a new")
144
+ Text("object with less capabilities. You can tell what effects a top level function")
145
+ Text("can have simply by looking at what arguments it receives.")
146
+ ])
147
+ CodeBlock("""
148
+ nodeMain(system: NodeSytem) {
149
+ let html = fetchSite(system.httpClient())
150
+ system.writeLine(html)
151
+ }
152
+
153
+ // this function can only do HTTP requests
154
+ fetchSite(httpClient: HttpClient): String {
155
+ let url = "https://www.example.com/"
156
+ httpClient.get(url, []) {_.readText()}
157
+ }
158
+ """, firefly = True)
159
+ )
160
+ SplitSection(
161
+ "Structural equality"
162
+ Paragraph([
163
+ Text("Traits are used for equality, ordering etc., and the core traits are automatically implemented for")
164
+ Code("data")
165
+ Text("types if you don't supply your own implementation.")
166
+ Text("They make")
167
+ Code("==")
168
+ Text("and")
169
+ Code("<")
170
+ Text("type safe, unlike in most languages, and")
171
+ Text("they're a lot simpler than the traits you find in Rust.")
172
+ ])
173
+ CodeBlock("""
174
+ trait T: Order {
175
+ compare(x: T, y: T): Ordering
176
+ }
177
+
178
+ instance Bool: Order {
179
+ compare(x: Bool, y: Bool): Ordering {
180
+ | False, True => OrderingBefore
181
+ | True, False => OrderingAfter
182
+ | _, _ => OrderingSame
183
+ }
184
+ }
185
+ """, firefly = True)
186
+ )
187
+ /*
188
+ SplitSection(
189
+ "Batteries included"
190
+ Paragraph([
191
+ Text("The standard library contains functionality that's required by most applications.")
192
+ Text("Apart from what you've seen above, there's also the following modules.")
193
+ ])
194
+ Bullets([
195
+ [Bold("Random:"), Text("Pseudorandom numbers")]
196
+ [Bold("Instant:"), Text("UTC timestamps")]
197
+ [Bold("Json:"), Text("JSON support")]
198
+ [Bold("Buffer:"), Text("Binary data")]
199
+ [Bold("Stream:"), Text("Streams (sync or async)")]
200
+ [Bold("Task:"), Text("Structured concurrency")]
201
+ [Bold("Log:"), Text("Simple logging")]
202
+ ])
203
+ )
204
+ */
205
+ Section("The Firefly Stack", [
206
+ Paragraph([
207
+ Bold("The Firefly Stack is a set of packages for building webapps.")
208
+ Text("The packages are maintained by the developers of Firefly.")
209
+ Text("You can use them individually or together.")
210
+ Italic("Here's what you can do with that.")
211
+ ])
212
+ ])
213
+ SplitSection(
214
+ "Interactive webapps"
215
+ Paragraph([
216
+ Text("The")
217
+ Code("ff:lux")
218
+ Text("package provides a declarative DOM framework for building highly interactive webapps.")
219
+ Text("Tasks that belong to removed nodes are automatically cancelled.")
220
+ Text("All without any virtual DOM.")
221
+ ])
222
+ CodeBlock("""
223
+ lux.useState(0): count, setCount =>
224
+ lux.button {
225
+ lux.text("Clicked " + count + " times")
226
+ lux.onClick {event =>
227
+ event.preventDefault()
228
+ setCount(count + 1)
229
+ }
230
+ }
231
+ """, firefly = True)
232
+ )
233
+ SplitSection(
234
+ "Type safe RPC"
235
+ Paragraph([
236
+ Text("All your custom")
237
+ Code("data")
238
+ Text("types are automatically serializable in Firefly.")
239
+ Text("With ")
240
+ Code("ff:rpc")
241
+ Text("you can set up type safe remote procedure calls from the browser to the webserver or between services.")
242
+ Text("You can even")
243
+ Italic("go to definition")
244
+ Text("across RPC boundaries.")
245
+ ])
246
+ CodeBlock("""
247
+ data Message(text: String)
248
+ instance Message: Rpc[Int]
249
+
250
+ // the browser sends a Message
251
+ let client = Rpc.newClient(...)
252
+ let messageId = client.call(Message("Hello"))
253
+
254
+ // the webserver replies with an Int
255
+ let server = Rpc.newServer(...)
256
+ server.add {| context, Message(text) => 42 }
257
+ """, firefly = True)
258
+ )
259
+ SplitSection(
260
+ "WebSocket server & client"
261
+ Paragraph([
262
+ Text("The ")
263
+ Code("ff:webserver")
264
+ Text("package comes with WebSocket support.")
265
+ Text("In just a few lines of code, you can start serving WebSockets.")
266
+ Text("The ")
267
+ Code("ff:websocket")
268
+ Text("package allows you to connect to any WebSocket server.")
269
+ Text("If both ends are running Firefly, you can use the built-in binary serialization.")
270
+ ])
271
+ CodeBlock("""
272
+ let server = WebServer.new(system, host, port)
273
+ server.enableWebSockets()
274
+
275
+ server.listen {request =>
276
+ let ws = request.openWebSocket()
277
+ ws.subscribe("chat")
278
+ while {True} {
279
+ let message = ws.readText().grab()
280
+ ws.publishText("chat", message)
281
+ }
282
+ }
283
+ """.replace("'''", "\"\"\""), firefly = True)
284
+ )
285
+ SplitSection(
286
+ "Database pooling"
287
+ Paragraph([
288
+ Text("The")
289
+ Code("ff:postgresql")
290
+ Text("package lets you create a connection pool for a PostgreSQL database.")
291
+ Text("You can then execute transactions and build stateful applications.")
292
+ ])
293
+ CodeBlock("""
294
+ let pool = Pg.newPool(...)
295
+
296
+ let emails = pool.transaction {connection =>
297
+ connection
298
+ .statement('''
299
+ select email from users
300
+ where id <= $maxId
301
+ ''')
302
+ .withInt("maxId", 100)
303
+ .map {_.getString("email").grab()}
304
+ }
305
+ """.replace("'''", "\"\"\""), firefly = True)
306
+ )
307
+ Section("What Firefly doesn't have", [
308
+ Bullets([
309
+ [
310
+ Bold("No function overloading.")
311
+ Text("Overloading leads to uninformative \"No matching overload\" errors.")
312
+ ]
313
+ [
314
+ Bold("No implicit casts.")
315
+ Text("Ever recieved an email addressed to \"Dear None\"? Static types fail to prevent this if you can implicitly cast an Option[T] to a String.")
316
+ ]
317
+ [
318
+ Bold("No dynamic typing.")
319
+ Text("Dynamic typing causes runtime errors and encourages hidden and underspecified contracts that makes refactoring harder than it needs to be.")
320
+ ]
321
+ [
322
+ Bold("No nulls.")
323
+ Text("Eliminating null ensures types accurately represent known values, reducing runtime errors and redundant checks.")
324
+ ]
325
+ [
326
+ Bold("No subtyping.")
327
+ Text("Subtyping introduces complexity via type bounds and variance. It also allows mixing loosely related types, promoting incomplete runtime type checks.")
328
+ ]
329
+ [
330
+ Bold("No inheritance.")
331
+ Text("Inheritance can lead to overgeneralization and scattering of business logic, making it hard to get the full picture at any level.")
332
+ ]
333
+ [
334
+ Bold("No macros.")
335
+ Text("Macros let you define whole new languages, that are typically wildly undertooled compared to the base language.")
336
+ ]
337
+ [
338
+ Bold("No type level programming.")
339
+ Text("Type level programming leads to inscrutable function signatures and hard to understand error messages.")
340
+ ]
341
+ ])
342
+ ])
343
+ ])
344
+ }