firefly-compiler 0.4.78 → 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 (67) hide show
  1. package/compiler/Builder.ff +2 -2
  2. package/compiler/Compiler.ff +1 -1
  3. package/compiler/Inference.ff +2 -1
  4. package/compiler/JsEmitter.ff +11 -17
  5. package/compiler/Main.ff +3 -3
  6. package/compiler/ModuleCache.ff +1 -1
  7. package/compiler/Tokenizer.ff +1 -1
  8. package/compiler/Unification.ff +1 -1
  9. package/core/.firefly/include/package-lock.json +267 -97
  10. package/core/.firefly/include/package.json +1 -1
  11. package/core/Float.ff +25 -0
  12. package/core/Lock.ff +1 -1
  13. package/core/NodeSystem.ff +1 -1
  14. package/core/Stream.ff +9 -9
  15. package/core/Task.ff +3 -3
  16. package/core/Try.ff +25 -4
  17. package/experimental/s3/S3TestAuthorizationHeader.ff +2 -1
  18. package/experimental/s3/S3TestPut.ff +2 -1
  19. package/fireflysite/CommunityOverview.ff +2 -2
  20. package/fireflysite/CountingButtonDemo.ff +1 -1
  21. package/fireflysite/DocumentParser.ff +332 -0
  22. package/fireflysite/ExamplesOverview.ff +11 -2
  23. package/fireflysite/FrontPage.ff +344 -0
  24. package/fireflysite/{GuideIntroduction.ff → GettingStarted.ff} +1 -25
  25. package/fireflysite/Guide.ff +239 -104
  26. package/fireflysite/Main.ff +100 -51
  27. package/fireflysite/MatchingPasswordsDemo.ff +13 -17
  28. package/fireflysite/PackagesOverview.ff +1 -1
  29. package/fireflysite/PostgresqlDemo.ff +34 -0
  30. package/fireflysite/ReferenceAll.ff +19 -0
  31. package/fireflysite/ReferenceIntroduction.ff +11 -0
  32. package/fireflysite/Styles.ff +358 -97
  33. package/fireflysite/Test.ff +38 -0
  34. package/fireflysite/assets/font/NotoSansMono-Regular.ttf +0 -0
  35. package/fireflysite/assets/font/NunitoSans-VariableFont_YTLC,opsz,wdth,wght.ttf +0 -0
  36. package/fireflysite/assets/image/autocomplete-small.png +0 -0
  37. package/fireflysite/assets/image/autocomplete.png +0 -0
  38. package/fireflysite/assets/image/edit-time-error.png +0 -0
  39. package/fireflysite/assets/image/firefly-logo-yellow.png +0 -0
  40. package/fireflysite/assets/markdown/reference/BaseTypes.md +209 -0
  41. package/fireflysite/assets/markdown/reference/FunctionsAndMethods.md +208 -0
  42. package/fireflysite/assets/markdown/reference/ModulesAndPackages.md +168 -0
  43. package/fireflysite/assets/markdown/reference/PatternMatching.md +224 -0
  44. package/fireflysite/assets/markdown/reference/StatementsAndExpressions.md +86 -0
  45. package/fireflysite/assets/markdown/reference/TraitsAndInstances.md +100 -0
  46. package/fireflysite/assets/markdown/reference/UserDefinedTypes.md +184 -0
  47. package/fireflysite/assets/markdown/scratch/ControlFlow.md +136 -0
  48. package/fireflysite/assets/markdown/scratch/Toc.md +41 -0
  49. package/lsp/Handler.ff +4 -4
  50. package/lsp/LanguageServer.ff +5 -5
  51. package/lux/Lux.ff +9 -9
  52. package/lux/Main2.ff +1 -1
  53. package/output/js/ff/compiler/Builder.mjs +4 -4
  54. package/output/js/ff/compiler/Inference.mjs +2 -2
  55. package/output/js/ff/compiler/JsEmitter.mjs +18 -72
  56. package/output/js/ff/compiler/Main.mjs +4 -4
  57. package/output/js/ff/compiler/ModuleCache.mjs +4 -4
  58. package/output/js/ff/core/Float.mjs +50 -0
  59. package/output/js/ff/core/NodeSystem.mjs +4 -4
  60. package/output/js/ff/core/Task.mjs +8 -8
  61. package/output/js/ff/core/Try.mjs +98 -4
  62. package/package.json +1 -1
  63. package/postgresql/Pg.ff +1 -1
  64. package/vscode/package.json +15 -1
  65. package/vscode/syntaxes/firefly-markdown-injection.json +45 -0
  66. package/webserver/.firefly/include/package-lock.json +7 -1
  67. /package/fireflysite/{firefly-logo-notext.png → assets/image/firefly-logo-notext.png} +0 -0
package/core/Stream.ff CHANGED
@@ -42,7 +42,7 @@ extend self[T]: Stream[T] {
42
42
  self.close()
43
43
  } finally {
44
44
  that.close()
45
- } grab()
45
+ }
46
46
  }
47
47
  }
48
48
 
@@ -76,7 +76,7 @@ extend self[T]: Stream[T] {
76
76
  inner.close()
77
77
  } finally {
78
78
  self.close()
79
- } grab()
79
+ }
80
80
  }
81
81
  }
82
82
 
@@ -111,7 +111,7 @@ extend self[T]: Stream[T] {
111
111
  self.close()
112
112
  } finally {
113
113
  that.close()
114
- } grab()
114
+ }
115
115
  }
116
116
  }
117
117
 
@@ -224,7 +224,7 @@ extend self[T]: Stream[T] {
224
224
  body(self)
225
225
  } finally {
226
226
  self.close()
227
- } grab()
227
+ }
228
228
  }
229
229
 
230
230
  each(body: T => Unit): Unit {
@@ -238,7 +238,7 @@ extend self[T]: Stream[T] {
238
238
  }
239
239
  } finally {
240
240
  self.close()
241
- } grab()
241
+ }
242
242
  }
243
243
 
244
244
  eachWhile(body: T => Bool): Unit {
@@ -252,7 +252,7 @@ extend self[T]: Stream[T] {
252
252
  }
253
253
  } finally {
254
254
  self.close()
255
- } grab()
255
+ }
256
256
  }
257
257
 
258
258
  all(body: T => Bool): Bool {
@@ -278,7 +278,7 @@ extend self[T]: Stream[T] {
278
278
  self.next()
279
279
  } finally {
280
280
  self.close()
281
- } grab()
281
+ }
282
282
  }
283
283
 
284
284
  last(): Option[T] {
@@ -294,7 +294,7 @@ extend self[T]: Stream[T] {
294
294
  result
295
295
  } finally {
296
296
  self.close()
297
- } grab()
297
+ }
298
298
  }
299
299
 
300
300
  grabFirst(): T {
@@ -324,7 +324,7 @@ extend self[T]: Stream[T] {
324
324
  result
325
325
  } finally {
326
326
  self.close()
327
- } grab()
327
+ }
328
328
  }
329
329
 
330
330
  find(body: T => Bool): Option[T] {
package/core/Task.ff CHANGED
@@ -104,7 +104,7 @@ extend self: Task {
104
104
  } catchAny {error =>
105
105
  failureChannel.write(error)
106
106
  t.abort()
107
- } grab()
107
+ }
108
108
  }
109
109
  Channel.
110
110
  readOr(successChannel, {_}).
@@ -125,7 +125,7 @@ extend self: Task {
125
125
  if(live == 0) {
126
126
  failureChannel.write(e)
127
127
  }
128
- } grab()
128
+ }
129
129
  }
130
130
  }
131
131
  try {
@@ -135,7 +135,7 @@ extend self: Task {
135
135
  wait()
136
136
  } finally {
137
137
  started.each {_.abort()}
138
- } grab()
138
+ }
139
139
  }
140
140
 
141
141
  }
package/core/Try.ff CHANGED
@@ -16,21 +16,42 @@ extend self[T]: Try[T] {
16
16
  self.map(body).flatten()
17
17
  }
18
18
 
19
- catch[E: HasAnyTag](body: (E, Error) => T): Try[T] {
19
+ catch[E: HasAnyTag](body: (E, Error) => T): T {
20
+ self.{
21
+ | Failure(error) {error.exception().flatMap(Any.fromAny) | Some(e)} => body(e, error)
22
+ | _ => self.grab()
23
+ }
24
+ }
25
+
26
+ catchAny(body: Error => T): T {
27
+ self.{
28
+ | Failure(error) => body(error)
29
+ | _ => self.grab()
30
+ }
31
+ }
32
+
33
+ finally(body: () => Unit): T {
34
+ self.{
35
+ | Success(value) => body(); value
36
+ | Failure(_) => body(); self.grab()
37
+ }
38
+ }
39
+
40
+ tryCatch[E: HasAnyTag](body: (E, Error) => T): Try[T] {
20
41
  self.{
21
42
  | Failure(error) {error.exception().flatMap(Any.fromAny) | Some(e)} => try {body(e, error)}
22
43
  | _ => self
23
44
  }
24
45
  }
25
46
 
26
- catchAny(body: Error => T): Try[T] {
47
+ tryCatchAny(body: Error => T): Try[T] {
27
48
  self.{
28
49
  | Failure(error) => try {body(error)}
29
50
  | _ => self
30
51
  }
31
52
  }
32
53
 
33
- finally(body: () => Unit): Try[T] {
54
+ tryFinally(body: () => Unit): Try[T] {
34
55
  self.{
35
56
  | Success(value) => try {body(); value}
36
57
  | Failure(_) =>
@@ -40,7 +61,7 @@ extend self[T]: Try[T] {
40
61
  }
41
62
  }
42
63
  }
43
-
64
+
44
65
  else(body: () => T): T {
45
66
  self.{
46
67
  | Success(value) => value
@@ -1,4 +1,5 @@
1
- import S3
1
+ dependency ff:s3:0.0.0
2
+ import S3 from ff:s3
2
3
 
3
4
  nodeMain(system: NodeSystem) {
4
5
  // Trying to reproduce the result from an example here
@@ -1,4 +1,5 @@
1
- import S3
1
+ dependency ff:s3:0.0.0
2
+ import S3 from ff:s3
2
3
 
3
4
  nodeMain(system: NodeSystem) {
4
5
  S3.put(system,
@@ -3,13 +3,13 @@ import CountingButtonDemo
3
3
  import MatchingPasswordsDemo
4
4
 
5
5
  new(): Document {
6
- Document([
6
+ ReadyDocument([
7
7
  Section("Community", [
8
8
  Paragraph([
9
9
  Text("The developers of Firefly hang out in")
10
10
  Code("#firefly")
11
11
  Text("on the")
12
- Link("r/ProgrammingLanguages", "https://discord.gg/yQ9mSk7CJ5")
12
+ Link("Programming Languages", "https://discord.gg/yQ9mSk7CJ5")
13
13
  Text("Discord.")
14
14
  ])
15
15
  Paragraph([
@@ -25,7 +25,7 @@ render(lux: Lux): Unit {
25
25
  }
26
26
 
27
27
  newDocument(): Document {
28
- Document([
28
+ ReadyDocument([
29
29
  Section(name, [
30
30
  Paragraph([Text("A button that counts how many times it's been clicked.")])
31
31
  ])
@@ -0,0 +1,332 @@
1
+ import WebServer from ff:webserver // This is required to run the file.
2
+ import Guide
3
+
4
+ nodeMain(system: NodeSystem) {
5
+
6
+ function logDuration[T](label: String, body: () => T): T {
7
+ let started = system.mainTask().elapsed()
8
+ let result = body()
9
+ Log.debug(label + ": " + Show.show(Duration(system.mainTask().elapsed().seconds - started.seconds)))
10
+ result
11
+ }
12
+
13
+ let file = system.path("assets/markdown/reference/FunctionsAndMethods.md")
14
+
15
+ /*
16
+ logDuration("parse " + file.base()) {
17
+ mutable i = 0
18
+ while {i < 10000} {
19
+ parse(file)
20
+ i += 1
21
+ }
22
+ }
23
+ */
24
+ let document = parse(file)
25
+ printSections(system, document)
26
+ }
27
+
28
+
29
+
30
+ parse(file: Path): List[Section] {
31
+ let content = file.readText()
32
+ let lines = content.split('\n')
33
+ let parser = DocumentParser(file.absolute(), lines, 0)
34
+ parser.parseDocument()
35
+ }
36
+
37
+ class DocumentParser(
38
+ fileName: String
39
+ lines: List[String]
40
+ mutable i: Int
41
+ )
42
+
43
+ extend self: DocumentParser {
44
+
45
+ parseDocument(): List[Section] {
46
+ iterate {self.parseSection()}
47
+ }
48
+
49
+ parseSection(): Option[Section] {
50
+ self.skipWhile {_.trim() == ""}
51
+ self.first().{
52
+ | Some(line) {line.trim().removeFirst("#") | Some(heading)} =>
53
+ self.skip(1)
54
+ let blocks = iterate {self.parseBlock()}
55
+ Some(Section(heading.trim(), blocks))
56
+ | _ => None
57
+ }
58
+ }
59
+
60
+ parseBlock(): Option[Block] {
61
+ self.skipWhile {_.trim() == ""}
62
+ let first = self.first().map {_.trimStart()}
63
+ first.{
64
+ | Some(line) {line.removeFirst("```") | Some(l)} =>
65
+ self.skip(1)
66
+ let isFirefly = l.startsWith("firefly")
67
+ let block = self.parseRemainingCodeBlock(isFirefly)
68
+ Some(block)
69
+ | Some(line) {line.removeFirst("* ") | Some(l)} =>
70
+ self.skip(1)
71
+ Some(Bullets(self.parseBullets(l)))
72
+ | Some(line) {line.first().any {_ != '#'}} =>
73
+ Some(self.parseParagraph())
74
+ | _ => None
75
+ }
76
+ }
77
+
78
+ parseParagraph(): Block {
79
+ let lines = self.consumeWhile {_.trim() != ""}
80
+ Paragraph(self.parseInlines(lines))
81
+ }
82
+
83
+ parseInlines(lines: List[String]): List[Inline] {
84
+ let parser = InlineParser(self.fileName, lines.join("\n"), 0)
85
+ let inlines = parser.parseInlines()
86
+ inlines
87
+ }
88
+
89
+ parseBullets(firstLine: String): List[List[Inline]] {
90
+ let pair = self.consumeToSome {line =>
91
+ let trimmed = line.trim()
92
+ let endWithNextLine = trimmed.{
93
+ | "" => Some(None)
94
+ | t {t.removeFirst("* ") | Some(nextLine)} => Some(Some(nextLine))
95
+ | _ => None
96
+ }
97
+ endWithNextLine
98
+ }
99
+ let bulletLines = [firstLine, ...pair.first]
100
+ let bullet = self.parseInlines(bulletLines)
101
+ pair.second.{
102
+ | None => [bullet]
103
+ | Some(None) => [bullet]
104
+ | Some(Some(nextLine)) => [bullet, ...self.parseBullets(nextLine)]
105
+ }
106
+ }
107
+
108
+ parseRemainingCodeBlock(isFirefly: Bool): Block {
109
+ let code = self.consumeWhile {!_.trimStart().startsWith("```")}
110
+ self.skip(1)
111
+ CodeBlock(code.join("\n"), isFirefly)
112
+ }
113
+
114
+ first(): Option[String] {
115
+ if(self.i < self.lines.size()) {
116
+ self.lines.grab(self.i)
117
+ }
118
+ }
119
+
120
+ skip(count: Int): Unit {
121
+ self.i += count
122
+ }
123
+
124
+ skipWhile(body: String => Bool): Unit {
125
+ while {self.i < self.lines.size() && body(self.lines.grab(self.i))} {
126
+ self.i += 1
127
+ }
128
+ }
129
+
130
+ consumeWhile(body: String => Bool): List[String] {
131
+ let oldI = self.i
132
+ self.skipWhile(body)
133
+ self.lines.slice(oldI, self.i)
134
+ }
135
+
136
+ consumeToSome[T](body: String => Option[T]): Pair[List[String], Option[T]] {
137
+ let oldI = self.i
138
+ mutable end = None
139
+ while {self.i < self.lines.size() && end.isEmpty()} {
140
+ end = body(self.lines.grab(self.i))
141
+ self.i += 1
142
+ }
143
+ let endI = if(end.isEmpty()) {self.i} else {self.i - 1}
144
+ Pair(self.lines.slice(oldI, endI), end)
145
+ }
146
+ }
147
+
148
+ class InlineParser(
149
+ fileName: String
150
+ line: String
151
+ mutable i: Int
152
+ )
153
+
154
+ extend self: InlineParser {
155
+
156
+ parseInlines(): List[Inline] {
157
+ iterateLists {self.parseInline()}
158
+ }
159
+
160
+ parseInline(): List[Inline] {
161
+ mutable inline = []
162
+ mutable j = 0
163
+
164
+ doWhile {
165
+ let remaining = self.size() - j
166
+ if(remaining >= 3) {
167
+ self.grab(j).{
168
+ | '_' => inline = self.parseNextInline(j, {self.parseItalic()})
169
+ | '`' => inline = self.parseNextInline(j, {self.parseCode()})
170
+ | '[' => inline = self.parseNextInline(j, {self.parseLink()})
171
+ | '*' {self.grab(j + 1) == '*'} => inline = self.parseNextInline(j, {self.parseBold()})
172
+ | _ =>
173
+ }
174
+ }
175
+ j += 1
176
+ remaining > 0 && inline.isEmpty()
177
+ }
178
+
179
+ inline.{
180
+ | [] {j == 1} => []
181
+ | [] => [Text(self.consume(j - 1))]
182
+ | inlines => inlines
183
+ }
184
+ }
185
+
186
+ parseNextInline(offset: Int, parseNext: () => Option[Inline]): List[Inline] {
187
+ if(offset == 0) {parseNext().toList()} else:
188
+
189
+ let oldI = self.i
190
+ self.i += offset
191
+ parseNext().{
192
+ | None =>
193
+ self.i = oldI
194
+ []
195
+ | Some(nextInline) =>
196
+ let text = self.line.slice(oldI, oldI + offset)
197
+ let textInline = Text(text)
198
+ [textInline, nextInline]
199
+ }
200
+ }
201
+
202
+ parseLink(): Option[Inline] {
203
+ let oldI = self.i
204
+ self.parseEnclosed("[", "]").flatMap {text =>
205
+ self.parseEnclosed("(", ")").{
206
+ | None =>
207
+ self.i = oldI
208
+ None
209
+ | Some(url) => Some(Link(text, url))
210
+ }
211
+ }
212
+ }
213
+
214
+ parseBold(): Option[Inline] {
215
+ self.parseEnclosed("**", "**").map {Bold(_)}
216
+ }
217
+
218
+ parseItalic(): Option[Inline] {
219
+ self.parseEnclosed("_", "_").map {Italic(_)}
220
+ }
221
+
222
+ parseCode(): Option[Inline] {
223
+ self.parseEnclosed("`", "`").map {Code(_)}
224
+ }
225
+
226
+ parseEnclosed(left: String, right: String): Option[String] {
227
+ if(self.startsWith(left)) {
228
+ indexOf(self.line, right, self.i + left.size()).map {end =>
229
+ let text = self.line.slice(self.i + left.size(), end)
230
+ self.i = end + right.size()
231
+ text
232
+ }
233
+ }.flatten()
234
+ }
235
+
236
+ grab(index: Int): Char {
237
+ self.line.grab(self.i + index)
238
+ }
239
+
240
+ size(): Int {
241
+ self.line.size() - self.i
242
+ }
243
+
244
+ startsWith(text: String): Bool {
245
+ self.size() >= text.size() && self.line.slice(self.i, self.i + text.size()) == text
246
+ }
247
+
248
+ consume(count: Int): String {
249
+ let text = self.line.slice(self.i, self.i + count)
250
+ self.i += count
251
+ text
252
+ }
253
+ }
254
+
255
+ iterate[T](body: () => Option[T]): List[T] {
256
+ let array = Array.new()
257
+ doWhile {
258
+ body().{
259
+ | None => False
260
+ | Some(s) =>
261
+ array.push(s)
262
+ True
263
+ }
264
+ }
265
+ array.drain()
266
+ }
267
+
268
+ iterateLists[T](body: () => List[T]): List[T] {
269
+ let array = Array.new()
270
+ doWhile {
271
+ body().{
272
+ | [] => False
273
+ | list =>
274
+ array.pushList(list)
275
+ True
276
+ }
277
+ }
278
+ array.drain()
279
+ }
280
+
281
+ indexOf(string: String, searchString: String, position: Int = 0): Option[Int]
282
+ target js sync """
283
+ const i = string_.indexOf(searchString_, position_);
284
+ return i == -1 ? ff_core_Option.None() : ff_core_Option.Some(i);
285
+ """
286
+
287
+ printSections(system: NodeSystem, sections: List[Section]) {
288
+ sections.each {
289
+ | Section(heading, blocks) =>
290
+ system.writeLine("# " + heading)
291
+ blocks.each {
292
+ | Bullets(items) =>
293
+ system.writeLine(" Bullets:")
294
+ system.writeLine(" " + Show.show(items))
295
+ | CodeBlock(code, True) =>
296
+ system.writeLine(" Code (Firefly):")
297
+ system.writeLine(" " + Show.show(code))
298
+ | CodeBlock(code, False) =>
299
+ system.writeLine(" Code:")
300
+ system.writeLine(" " + Show.show(code))
301
+ | Image(url) =>
302
+ system.writeLine(" Image:")
303
+ system.writeLine(" " + Show.show(url))
304
+ | LuxDemo(demo) =>
305
+ system.writeLine(" Lux:")
306
+ system.writeLine(" " + Show.show(demo))
307
+ | Paragraph(inlines) =>
308
+ system.writeLine(" Paragraph:")
309
+ inlines.each {
310
+ | Anchor(heading, title) =>
311
+ system.writeLine(" Anchor: " + Show.show(heading) + ", " + Show.show(title))
312
+ | Bold(text) =>
313
+ system.writeLine(" Bold: " + Show.show(text))
314
+ | Code(code, True) =>
315
+ system.writeLine(" Code (firefly): " + Show.show(code))
316
+ | Code(code, False) =>
317
+ system.writeLine(" Code: " + Show.show(code))
318
+ | Italic(text) =>
319
+ system.writeLine(" Italic: " + Show.show(text))
320
+ | Link(text, url) =>
321
+ system.writeLine(" Link: " + Show.show(text) + ", " + Show.show(url))
322
+ | Text(text) =>
323
+ system.writeLine(" Text: " + Show.show(text))
324
+ }
325
+ | Video(url) =>
326
+ system.writeLine(" Video:")
327
+ system.writeLine(" " + Show.show(url))
328
+ }
329
+ | SplitSection(heading, first, second) =>
330
+ system.writeLine("SPLIT")
331
+ }
332
+ }
@@ -1,18 +1,27 @@
1
1
  import Guide
2
2
  import CountingButtonDemo
3
3
  import MatchingPasswordsDemo
4
+ import PostgresqlDemo
4
5
 
5
6
  mock(): List[Document] {
6
7
  [
7
8
  new()
8
9
  CountingButtonDemo.newDocument()
9
10
  MatchingPasswordsDemo.newDocument()
11
+ PostgresqlDemo.newDocument()
12
+ ]
13
+ }
14
+
15
+ demos(): List[Demo] {
16
+ [
17
+ CountingButtonDemo.new()
18
+ MatchingPasswordsDemo.new()
10
19
  ]
11
20
  }
12
21
 
13
22
  new(): Document {
14
- Document([
15
- Section("Overview", [
23
+ ReadyDocument([
24
+ Section("Examples", [
16
25
  Paragraph([
17
26
  Text("Here you'll find examples that demonstrate what you can do with Firefly.")
18
27
  Text("In fact, you're looking at an example right now - this site is")