firefly-compiler 0.5.35 → 0.5.36

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 (225) hide show
  1. package/.hintrc +4 -4
  2. package/.vscode/settings.json +4 -4
  3. package/bin/Release.ff +157 -154
  4. package/bin/firefly.mjs +1 -1
  5. package/compiler/Builder.ff +275 -277
  6. package/compiler/Compiler.ff +234 -233
  7. package/compiler/Dependencies.ff +186 -187
  8. package/compiler/DependencyLock.ff +17 -17
  9. package/compiler/Deriver.ff +23 -31
  10. package/compiler/Dictionaries.ff +1 -1
  11. package/compiler/Inference.ff +43 -20
  12. package/compiler/JsEmitter.ff +1437 -1282
  13. package/compiler/LspHook.ff +202 -202
  14. package/compiler/Main.ff +25 -24
  15. package/compiler/ModuleCache.ff +178 -178
  16. package/compiler/Parser.ff +36 -109
  17. package/compiler/Resolver.ff +5 -8
  18. package/compiler/Substitution.ff +1 -1
  19. package/compiler/Syntax.ff +1 -16
  20. package/compiler/Token.ff +9 -0
  21. package/compiler/Tokenizer.ff +4 -0
  22. package/compiler/Workspace.ff +88 -88
  23. package/core/.firefly/include/package.json +5 -5
  24. package/core/.firefly/package.ff +2 -2
  25. package/core/Any.ff +26 -30
  26. package/core/Array.ff +298 -265
  27. package/core/Atomic.ff +63 -64
  28. package/core/Box.ff +7 -7
  29. package/core/BrowserSystem.ff +40 -40
  30. package/core/Buffer.ff +185 -152
  31. package/core/BuildSystem.ff +156 -148
  32. package/core/Channel.ff +95 -92
  33. package/core/Char.ff +3 -2
  34. package/core/Core.ff +16 -23
  35. package/core/Crypto.ff +94 -96
  36. package/core/Equal.ff +41 -36
  37. package/core/Error.ff +15 -10
  38. package/core/FileHandle.ff +45 -37
  39. package/core/Float.ff +176 -200
  40. package/core/HttpClient.ff +142 -148
  41. package/core/Instant.ff +6 -8
  42. package/core/Int.ff +40 -24
  43. package/core/IntMap.ff +61 -39
  44. package/core/Js.ff +305 -0
  45. package/core/JsSystem.ff +135 -114
  46. package/core/JsValue.ff +303 -159
  47. package/core/Json.ff +423 -443
  48. package/core/List.ff +482 -486
  49. package/core/Lock.ff +108 -144
  50. package/core/Log.ff +25 -14
  51. package/core/NodeSystem.ff +198 -191
  52. package/core/Ordering.ff +160 -161
  53. package/core/Path.ff +377 -409
  54. package/core/Queue.ff +90 -0
  55. package/core/Random.ff +140 -134
  56. package/core/RbMap.ff +216 -216
  57. package/core/Serializable.ff +16 -13
  58. package/core/Show.ff +44 -43
  59. package/core/SourceLocation.ff +68 -68
  60. package/core/Stream.ff +1 -1
  61. package/core/String.ff +224 -202
  62. package/core/StringMap.ff +58 -36
  63. package/core/Task.ff +165 -149
  64. package/experimental/benchmarks/ListGrab.ff +23 -23
  65. package/experimental/benchmarks/ListGrab.java +55 -55
  66. package/experimental/benchmarks/Pyrotek45.ff +30 -30
  67. package/experimental/benchmarks/Pyrotek45.java +64 -64
  68. package/experimental/bidirectional/Bidi.ff +88 -88
  69. package/experimental/lines/Main.ff +40 -0
  70. package/experimental/random/Index.ff +53 -53
  71. package/experimental/random/Process.ff +120 -120
  72. package/experimental/random/RunLength.ff +65 -65
  73. package/experimental/random/Scrape.ff +51 -51
  74. package/experimental/random/Symbols.ff +73 -73
  75. package/experimental/random/Tensor.ff +52 -52
  76. package/experimental/random/Units.ff +36 -36
  77. package/experimental/s3/S3TestAuthorizationHeader.ff +39 -39
  78. package/experimental/s3/S3TestPut.ff +16 -16
  79. package/experimental/tests/TestJson.ff +26 -26
  80. package/firefly.sh +0 -0
  81. package/fireflysite/.firefly/package.ff +4 -4
  82. package/fireflysite/CommunityOverview.ff +20 -20
  83. package/fireflysite/CountingButtonDemo.ff +58 -58
  84. package/fireflysite/DocumentParser.ff +325 -331
  85. package/fireflysite/ExamplesOverview.ff +40 -40
  86. package/fireflysite/FrontPage.ff +344 -344
  87. package/fireflysite/GettingStarted.ff +45 -45
  88. package/fireflysite/Guide.ff +456 -456
  89. package/fireflysite/Main.ff +163 -152
  90. package/fireflysite/MatchingPasswordsDemo.ff +82 -82
  91. package/fireflysite/PackagesOverview.ff +49 -49
  92. package/fireflysite/PostgresqlDemo.ff +34 -34
  93. package/fireflysite/ReferenceAll.ff +18 -18
  94. package/fireflysite/ReferenceIntroduction.ff +11 -11
  95. package/fireflysite/Styles.ff +567 -567
  96. package/fireflysite/Test.ff +121 -62
  97. package/fireflysite/assets/markdown/reference/BaseTypes.md +209 -209
  98. package/fireflysite/assets/markdown/reference/EmittedJavascript.md +65 -65
  99. package/fireflysite/assets/markdown/reference/Exceptions.md +101 -101
  100. package/fireflysite/assets/markdown/reference/FunctionsAndMethods.md +364 -364
  101. package/fireflysite/assets/markdown/reference/JavascriptInterop.md +235 -172
  102. package/fireflysite/assets/markdown/reference/ModulesAndPackages.md +162 -162
  103. package/fireflysite/assets/markdown/reference/OldStructuredConcurrency.md +48 -48
  104. package/fireflysite/assets/markdown/reference/PatternMatching.md +224 -224
  105. package/fireflysite/assets/markdown/reference/StatementsAndExpressions.md +86 -86
  106. package/fireflysite/assets/markdown/reference/StructuredConcurrency.md +99 -99
  107. package/fireflysite/assets/markdown/reference/TraitsAndInstances.md +100 -100
  108. package/fireflysite/assets/markdown/reference/UserDefinedTypes.md +184 -184
  109. package/fireflysite/assets/markdown/scratch/ControlFlow.md +136 -136
  110. package/fireflysite/assets/markdown/scratch/Toc.md +40 -40
  111. package/lsp/.firefly/package.ff +1 -1
  112. package/lsp/CompletionHandler.ff +827 -827
  113. package/lsp/Handler.ff +714 -714
  114. package/lsp/HoverHandler.ff +79 -79
  115. package/lsp/LanguageServer.ff +272 -272
  116. package/lsp/SignatureHelpHandler.ff +55 -55
  117. package/lsp/SymbolHandler.ff +181 -181
  118. package/lsp/TestReferences.ff +17 -17
  119. package/lsp/TestReferencesCase.ff +7 -7
  120. package/lsp/stderr.txt +1 -1
  121. package/lsp/stdout.txt +34 -34
  122. package/lux/.firefly/package.ff +1 -1
  123. package/lux/Css.ff +648 -648
  124. package/lux/CssTest.ff +48 -48
  125. package/lux/Lux.ff +608 -617
  126. package/lux/LuxEvent.ff +79 -116
  127. package/lux/Main.ff +123 -123
  128. package/lux/Main2.ff +143 -143
  129. package/lux/TestDry.ff +28 -28
  130. package/output/js/ff/compiler/Builder.mjs +72 -71
  131. package/output/js/ff/compiler/Compiler.mjs +19 -13
  132. package/output/js/ff/compiler/Dependencies.mjs +8 -7
  133. package/output/js/ff/compiler/DependencyLock.mjs +6 -4
  134. package/output/js/ff/compiler/Deriver.mjs +26 -24
  135. package/output/js/ff/compiler/Dictionaries.mjs +14 -18
  136. package/output/js/ff/compiler/Environment.mjs +6 -4
  137. package/output/js/ff/compiler/Inference.mjs +238 -164
  138. package/output/js/ff/compiler/JsEmitter.mjs +1160 -350
  139. package/output/js/ff/compiler/JsImporter.mjs +20 -18
  140. package/output/js/ff/compiler/LspHook.mjs +12 -10
  141. package/output/js/ff/compiler/Main.mjs +61 -41
  142. package/output/js/ff/compiler/ModuleCache.mjs +10 -8
  143. package/output/js/ff/compiler/Parser.mjs +153 -669
  144. package/output/js/ff/compiler/Patterns.mjs +12 -10
  145. package/output/js/ff/compiler/Resolver.mjs +52 -78
  146. package/output/js/ff/compiler/Substitution.mjs +12 -16
  147. package/output/js/ff/compiler/Syntax.mjs +50 -341
  148. package/output/js/ff/compiler/Token.mjs +126 -4
  149. package/output/js/ff/compiler/Tokenizer.mjs +62 -52
  150. package/output/js/ff/compiler/Unification.mjs +74 -90
  151. package/output/js/ff/compiler/Wildcards.mjs +4 -2
  152. package/output/js/ff/compiler/Workspace.mjs +26 -20
  153. package/output/js/ff/core/Any.mjs +20 -20
  154. package/output/js/ff/core/Array.mjs +268 -175
  155. package/output/js/ff/core/AssetSystem.mjs +8 -6
  156. package/output/js/ff/core/Atomic.mjs +84 -52
  157. package/output/js/ff/core/Bool.mjs +6 -4
  158. package/output/js/ff/core/BrowserSystem.mjs +38 -29
  159. package/output/js/ff/core/Buffer.mjs +285 -133
  160. package/output/js/ff/core/BuildSystem.mjs +36 -56
  161. package/output/js/ff/core/Channel.mjs +250 -97
  162. package/output/js/ff/core/Char.mjs +5 -3
  163. package/output/js/ff/core/Core.mjs +28 -34
  164. package/output/js/ff/core/Crypto.mjs +30 -52
  165. package/output/js/ff/core/Duration.mjs +4 -2
  166. package/output/js/ff/core/Equal.mjs +14 -12
  167. package/output/js/ff/core/Error.mjs +17 -11
  168. package/output/js/ff/core/FileHandle.mjs +76 -38
  169. package/output/js/ff/core/Float.mjs +92 -160
  170. package/output/js/ff/core/HttpClient.mjs +208 -76
  171. package/output/js/ff/core/Instant.mjs +8 -10
  172. package/output/js/ff/core/Int.mjs +36 -26
  173. package/output/js/ff/core/IntMap.mjs +79 -33
  174. package/output/js/ff/core/Js.mjs +751 -0
  175. package/output/js/ff/core/JsSystem.mjs +54 -60
  176. package/output/js/ff/core/JsValue.mjs +294 -143
  177. package/output/js/ff/core/Json.mjs +443 -253
  178. package/output/js/ff/core/List.mjs +262 -214
  179. package/output/js/ff/core/Lock.mjs +156 -125
  180. package/output/js/ff/core/Log.mjs +20 -10
  181. package/output/js/ff/core/Map.mjs +10 -8
  182. package/output/js/ff/core/NodeSystem.mjs +189 -123
  183. package/output/js/ff/core/Nothing.mjs +4 -2
  184. package/output/js/ff/core/Option.mjs +40 -38
  185. package/output/js/ff/core/Ordering.mjs +26 -20
  186. package/output/js/ff/core/Pair.mjs +4 -2
  187. package/output/js/ff/core/Path.mjs +517 -315
  188. package/output/js/ff/core/Queue.mjs +306 -0
  189. package/output/js/ff/core/Random.mjs +141 -77
  190. package/output/js/ff/core/RbMap.mjs +36 -34
  191. package/output/js/ff/core/Serializable.mjs +44 -28
  192. package/output/js/ff/core/Set.mjs +6 -4
  193. package/output/js/ff/core/Show.mjs +8 -6
  194. package/output/js/ff/core/SourceLocation.mjs +4 -2
  195. package/output/js/ff/core/Stream.mjs +30 -50
  196. package/output/js/ff/core/String.mjs +263 -172
  197. package/output/js/ff/core/StringMap.mjs +77 -31
  198. package/output/js/ff/core/Task.mjs +91 -76
  199. package/output/js/ff/core/Try.mjs +20 -18
  200. package/output/js/ff/core/Unit.mjs +4 -2
  201. package/package.json +1 -1
  202. package/postgresql/Pg.ff +53 -59
  203. package/rpc/.firefly/package.ff +1 -1
  204. package/rpc/Rpc.ff +70 -70
  205. package/s3/.firefly/package.ff +1 -1
  206. package/s3/S3.ff +92 -94
  207. package/vscode/LICENSE.txt +21 -21
  208. package/vscode/Prepublish.ff +15 -15
  209. package/vscode/README.md +16 -16
  210. package/vscode/client/package-lock.json +544 -544
  211. package/vscode/client/package.json +22 -22
  212. package/vscode/client/src/extension.ts +104 -104
  213. package/vscode/icons/firefly-icon.svg +10 -10
  214. package/vscode/language-configuration.json +61 -61
  215. package/vscode/package-lock.json +3623 -3623
  216. package/vscode/package.json +1 -1
  217. package/vscode/snippets.json +241 -241
  218. package/vscode/syntaxes/firefly-markdown-injection.json +45 -45
  219. package/webserver/.firefly/include/package.json +5 -5
  220. package/webserver/.firefly/package.ff +2 -2
  221. package/webserver/WebServer.ff +647 -685
  222. package/websocket/.firefly/package.ff +1 -1
  223. package/websocket/WebSocket.ff +100 -131
  224. package/core/UnsafeJs.ff +0 -42
  225. package/output/js/ff/core/UnsafeJs.mjs +0 -191
@@ -1,344 +1,344 @@
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.webp")
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.webp")
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
- }
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.webp")
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.webp")
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
+ }