firefly-compiler 0.4.19 → 0.4.21

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 (68) hide show
  1. package/compiler/Builder.ff +23 -13
  2. package/compiler/JsEmitter.ff +120 -76
  3. package/compiler/LspHook.ff +17 -3
  4. package/compiler/Main.ff +13 -7
  5. package/compiler/Parser.ff +11 -13
  6. package/compiler/Resolver.ff +15 -15
  7. package/compiler/Syntax.ff +1 -0
  8. package/core/Array.ff +6 -4
  9. package/core/Int.ff +12 -12
  10. package/core/Json.ff +2 -2
  11. package/core/List.ff +6 -4
  12. package/experimental/benchmarks/ListGrab.ff +23 -0
  13. package/experimental/benchmarks/ListGrab.java +55 -0
  14. package/experimental/benchmarks/Pyrotek45.ff +30 -0
  15. package/experimental/benchmarks/Pyrotek45.java +64 -0
  16. package/experimental/tests/TestJson.ff +26 -0
  17. package/lsp/CompletionHandler.ff +14 -14
  18. package/lsp/Handler.ff +56 -60
  19. package/lsp/SignatureHelpHandler.ff +5 -4
  20. package/lsp/SymbolHandler.ff +18 -4
  21. package/lsp/TestReferences.ff +15 -0
  22. package/lsp/TestReferencesCase.ff +8 -0
  23. package/output/js/ff/compiler/Builder.mjs +50 -44
  24. package/output/js/ff/compiler/Dependencies.mjs +0 -2
  25. package/output/js/ff/compiler/Deriver.mjs +16 -140
  26. package/output/js/ff/compiler/Dictionaries.mjs +8 -222
  27. package/output/js/ff/compiler/Environment.mjs +12 -154
  28. package/output/js/ff/compiler/Inference.mjs +127 -1013
  29. package/output/js/ff/compiler/JsEmitter.mjs +434 -2344
  30. package/output/js/ff/compiler/JsImporter.mjs +0 -12
  31. package/output/js/ff/compiler/LspHook.mjs +548 -151
  32. package/output/js/ff/compiler/Main.mjs +96 -550
  33. package/output/js/ff/compiler/Parser.mjs +58 -390
  34. package/output/js/ff/compiler/Patterns.mjs +20 -200
  35. package/output/js/ff/compiler/Resolver.mjs +26 -340
  36. package/output/js/ff/compiler/Substitution.mjs +2 -160
  37. package/output/js/ff/compiler/Syntax.mjs +449 -3293
  38. package/output/js/ff/compiler/Token.mjs +9 -1095
  39. package/output/js/ff/compiler/Tokenizer.mjs +4 -2
  40. package/output/js/ff/compiler/Unification.mjs +26 -360
  41. package/output/js/ff/compiler/Wildcards.mjs +0 -86
  42. package/output/js/ff/compiler/Workspace.mjs +8 -96
  43. package/output/js/ff/core/Array.mjs +15 -8
  44. package/output/js/ff/core/AssetSystem.mjs +4 -14
  45. package/output/js/ff/core/Bool.mjs +0 -12
  46. package/output/js/ff/core/Core.mjs +0 -30
  47. package/output/js/ff/core/Int.mjs +24 -24
  48. package/output/js/ff/core/IntMap.mjs +0 -8
  49. package/output/js/ff/core/Json.mjs +2 -42
  50. package/output/js/ff/core/List.mjs +23 -32
  51. package/output/js/ff/core/Lock.mjs +0 -10
  52. package/output/js/ff/core/Map.mjs +0 -24
  53. package/output/js/ff/core/Option.mjs +10 -286
  54. package/output/js/ff/core/Ordering.mjs +16 -158
  55. package/output/js/ff/core/Pair.mjs +2 -34
  56. package/output/js/ff/core/Path.mjs +2 -28
  57. package/output/js/ff/core/Random.mjs +4 -4
  58. package/output/js/ff/core/RbMap.mjs +56 -644
  59. package/output/js/ff/core/Show.mjs +0 -16
  60. package/output/js/ff/core/Stream.mjs +14 -144
  61. package/output/js/ff/core/StringMap.mjs +0 -8
  62. package/output/js/ff/core/Try.mjs +4 -108
  63. package/output/js/ff/core/Unit.mjs +2 -16
  64. package/package.json +1 -1
  65. package/postgresql/Pg.ff +23 -23
  66. package/vscode/client/src/extension.ts +30 -2
  67. package/vscode/package.json +17 -1
  68. package/core/Stack.ff +0 -250
@@ -88,15 +88,17 @@ check(
88
88
  system: NodeSystem
89
89
  fireflyPath: Path
90
90
  path: Path
91
+ mustContain: Option[String]
91
92
  virtualFiles: Map[String, String]
92
93
  lspHook: LspHook
93
94
  infer: Bool
94
- ) {
95
+ ): List[CompileError] {
95
96
  let packages = path.isDirectory().{
96
- | True => findPackageFiles(path)
97
+ | True => findPackageFiles(path, mustContain)
97
98
  | False {path.endsWith([".firefly", "package.ff"])} => [PackageFiles(path.parent().grab(), Some(path), [])]
98
99
  | False => [PackageFiles(path.parent().grab(), None, [path])]
99
100
  }
101
+ let errors = Array.make()
100
102
 
101
103
  packages.filter {!_.files.isEmpty()}.each {package =>
102
104
  let firstFile = package.files.grabFirst()
@@ -118,13 +120,19 @@ check(
118
120
  )
119
121
  package.files.each {file =>
120
122
  let localFile = file.base()
121
- if(infer) {
122
- compiler.infer(resolvedDependencies.mainPackagePair, localFile.dropLast(".ff".size()))
123
- } else {
124
- compiler.resolve(resolvedDependencies.mainPackagePair, localFile.dropLast(".ff".size()))
125
- }
123
+ try {
124
+ if(infer) {
125
+ compiler.infer(resolvedDependencies.mainPackagePair, localFile.dropLast(".ff".size()))
126
+ } else {
127
+ compiler.resolve(resolvedDependencies.mainPackagePair, localFile.dropLast(".ff".size()))
128
+ }
129
+ Unit
130
+ } catch {| CompileError(_, _) @ c, error =>
131
+ errors.push(c)
132
+ } grab()
126
133
  }
127
134
  }
135
+ errors.drain()
128
136
 
129
137
  }
130
138
 
@@ -135,8 +143,8 @@ capability PackageFiles(
135
143
  )
136
144
 
137
145
 
138
- findPackageFiles(path: Path): List[PackageFiles] {
139
- let files = findFireflyFiles(path)
146
+ findPackageFiles(path: Path, mustContain: Option[String]): List[PackageFiles] {
147
+ let files = findFireflyFiles(path, mustContain)
140
148
  let split = files.partition {_.endsWith([".firefly", "package.ff"])}
141
149
  let packageFiles = split.first
142
150
  mutable singleFiles = split.second
@@ -153,15 +161,17 @@ findPackageFiles(path: Path): List[PackageFiles] {
153
161
  [...multiFileProjects, ...singleFileProjects]
154
162
  }
155
163
 
156
- findFireflyFiles(path: Path): List[Path] {
164
+ findFireflyFiles(path: Path, mustContain: Option[String]): List[Path] {
157
165
  let split = path.entries().toList().partition {_.isDirectory()}
158
166
  let directories = split.first.map {_.path()}.filter {_.base().all {c =>
159
167
  c == '.' || c.isAsciiLower() || c.isAsciiDigit()
160
168
  }}
161
- let fireflyFiles = split.second.map {_.path()}.filter {
162
- _.extension() == ".ff"
169
+ let fireflyFiles = split.second.map {_.path()}.filter {file =>
170
+ file.extension() == ".ff" && mustContain.all {s =>
171
+ file.readText().contains(s)
172
+ }
163
173
  }
164
- [...fireflyFiles, ...directories.flatMap {findFireflyFiles(_)}]
174
+ [...fireflyFiles, ...directories.flatMap {findFireflyFiles(_, mustContain)}]
165
175
  }
166
176
 
167
177
  internalCreateExecutable(
@@ -223,9 +223,9 @@ extend self: JsEmitter {
223
223
  }.join("\n")
224
224
  let body = self.emitTailCall {
225
225
  let casesString = cases.map {
226
- "{\n" + self.emitCase(escapedArguments, _, True, True, async) + "\n}"
226
+ self.emitCase(escapedArguments, _, [], [], True, True, async)
227
227
  }.join("\n")
228
- "{\n" + shadowingWorkaround + "\n" + casesString + "\n}"
228
+ shadowingWorkaround + "\n" + casesString
229
229
  }
230
230
  signature + " {\n" + body + "\n}"
231
231
  }
@@ -343,7 +343,7 @@ extend self: JsEmitter {
343
343
  Patterns.convertAndCheck(self.otherModules, cases)
344
344
  let arguments = cases.grab(0).patterns.pairs().map {"_" + (_.first + 1)}
345
345
  let escapedArguments = arguments.map(escapeKeyword) // emitCase arguments must be preescaped
346
- let caseStrings = cases.map {"{\n" + self.emitCase(escapedArguments, _, True, True, newAsync) + "\n}"}
346
+ let caseStrings = cases.map {self.emitCase(escapedArguments, _, [], [], True, True, newAsync)}
347
347
  let prefix = if(newAsync) {"async "} else {""}
348
348
  "(" + prefix + "(" + [...escapedArguments, ...controller].join(", ") + ") => " +
349
349
  "{\n" + caseStrings.join("\n") + "\n})"
@@ -356,6 +356,12 @@ extend self: JsEmitter {
356
356
  "(" + operator + self.emitArgument(at, value, async) + ")"
357
357
  | ECall(at, StaticCall(operator, _, _), _, [], [left, right], _) {!operator.grabFirst().isAsciiLetter()} =>
358
358
  "(" + self.emitArgument(at, left, async) + " " + operator + " " + self.emitArgument(at, right, async) + ")"
359
+ | ECall(at, StaticCall("ff:core/List.List_grab", _, _), _, _, [Argument(_, _, EVariable(_, x1)), Argument(_, _, EVariable(_, x2))], _) =>
360
+ "(" + escapeResolved(x1) + "[" + escapeResolved(x2) + "] ?? " +
361
+ "ff_core_List.internalGrab_(" + escapeResolved(x1) + ", " + escapeResolved(x2) + "))"
362
+ | ECall(at, StaticCall("ff:core/Array.Array_grab", _, _), _, _, [Argument(_, _, EVariable(_, x1)), Argument(_, _, EVariable(_, x2))], _) =>
363
+ "(" + escapeResolved(x1) + ".array[" + escapeResolved(x2) + "] ?? " +
364
+ "ff_core_Array.internalGrab_(" + escapeResolved(x1) + ", " + escapeResolved(x2) + "))"
359
365
  | ECall(at, StaticCall("ff:unsafejs/UnsafeJs.import", _, _), _, _, [Argument(_, _, EString(_, url))], _) =>
360
366
  self.jsImporter.add(url.replace("\"", ""))
361
367
  | ECall(at, StaticCall("ff:unsafejs/UnsafeJs.await", _, _), _, _, [Argument(_, _, body)], _) =>
@@ -490,9 +496,9 @@ extend self: JsEmitter {
490
496
  self.emitStatements(body, last, async)
491
497
  | EVariant(at, "ff:core/Unit.Unit", _, _) =>
492
498
  ""
493
- | ESequential(at, EVariant(at, "ff:core/Unit.Unit", _, _), after) =>
499
+ | ESequential(_, EVariant(_, "ff:core/Unit.Unit", _, _), after) =>
494
500
  self.emitStatements(after, last, async)
495
- | ESequential(at, before, EVariant(at, "ff:core/Unit.Unit", _, _)) =>
501
+ | ESequential(_, before, EVariant(_, "ff:core/Unit.Unit", _, _)) =>
496
502
  self.emitStatements(before, False, async)
497
503
  | ESequential(at, before, after) =>
498
504
  self.emitStatements(before, False, async) + ";\n" + self.emitStatements(after, last, async)
@@ -561,7 +567,7 @@ extend self: JsEmitter {
561
567
  Patterns.convertAndCheck(self.otherModules, cases)
562
568
  if(!last) {"do "}.else {""} +
563
569
  "{\nconst _1 = " + self.emitTerm(value, async) + ";\n" +
564
- cases.map {"{\n" + self.emitCase(["_1"], _, True, last, async) + "\n}"}.join("\n") +
570
+ cases.map {self.emitCase(["_1"], _, [], [], True, last, async)}.join("\n") +
565
571
  "\n}" + if(!last) {" while(false)"}.else {""}
566
572
  | _ =>
567
573
  detectIfElse(term).{
@@ -594,16 +600,16 @@ extend self: JsEmitter {
594
600
  let arguments = ["_exception.value_", "_error"]
595
601
  cases.{
596
602
  | [case] =>
597
- self.emitCase(arguments, case, False, last, catchAsync)
603
+ self.emitCase(arguments, case, [], [], False, last, catchAsync)
598
604
  | cs =>
599
605
  let caseStrings =
600
- cases.map {"{\n" + self.emitCase(arguments, _, True, last, catchAsync) + "\n}"}
606
+ cases.map {self.emitCase(arguments, _, [], [], True, last, catchAsync)}
601
607
  if(last) {caseStrings.join("\n")} else {"do {\n" + caseStrings.join("\n") + "\n} while(false)"}
602
608
  }
603
609
  }
604
610
  term.{
605
- | ECall(at, StaticCall("ff:core/Try.Try_finally", _, _), _, _, [
606
- Argument(_, _, ECall(at, StaticCall("ff:core/Core.try", _, _), _, _, [
611
+ | ECall(_, StaticCall("ff:core/Try.Try_finally", _, _), _, _, [
612
+ Argument(_, _, ECall(_, StaticCall("ff:core/Core.try", _, _), _, _, [
607
613
  Argument(_, _, ELambda(_, Lambda(_, tryEffect, [MatchCase(_, [], [], tryBody)])))
608
614
  ], _))
609
615
  Argument(_, _, ELambda(_, Lambda(_, finallyEffect, [MatchCase(_, [], [], finallyBody)])))
@@ -614,8 +620,8 @@ extend self: JsEmitter {
614
620
  "try {\n" + self.emitStatements(tryBody, last, tryAsync) +
615
621
  "\n} finally {\n" + self.emitStatements(finallyBody, last, finallyAsync) + "\n}"
616
622
  )
617
- | ECall(at, StaticCall("ff:core/Try.Try_catch", _, _), _, _, [
618
- Argument(_, _, ECall(at, StaticCall("ff:core/Core.try", _, _), _, _, [
623
+ | ECall(_, StaticCall("ff:core/Try.Try_catch", _, _), _, _, [
624
+ Argument(_, _, ECall(_, StaticCall("ff:core/Core.try", _, _), _, _, [
619
625
  Argument(_, _, ELambda(_, Lambda(_, tryEffect, [MatchCase(_, [], [], tryBody)])))
620
626
  ], _))
621
627
  Argument(_, _, ELambda(_, Lambda(_, catchEffect, cases)))
@@ -631,9 +637,9 @@ extend self: JsEmitter {
631
637
  emitCatch(catchEffect, cases) +
632
638
  "\n}"
633
639
  )
634
- | ECall(at, StaticCall("ff:core/Try.Try_finally", _, _), _, _, [
635
- Argument(_, _, ECall(at, StaticCall("ff:core/Try.Try_catch", _, _), _, _, [
636
- Argument(_, _, ECall(at, StaticCall("ff:core/Core.try", _, _), _, _, [
640
+ | ECall(_, StaticCall("ff:core/Try.Try_finally", _, _), _, _, [
641
+ Argument(_, _, ECall(_, StaticCall("ff:core/Try.Try_catch", _, _), _, _, [
642
+ Argument(_, _, ECall(_, StaticCall("ff:core/Core.try", _, _), _, _, [
637
643
  Argument(_, _, ELambda(_, Lambda(_, tryEffect, [MatchCase(_, [], [], tryBody)])))
638
644
  ], _))
639
645
  Argument(_, _, ELambda(_, Lambda(_, catchEffect, cases)))
@@ -657,7 +663,23 @@ extend self: JsEmitter {
657
663
  }
658
664
  }
659
665
 
660
- emitCase(arguments: List[String], matchCase: MatchCase, jump: Bool, last: Bool, async: Bool): String {
666
+ emitCase(
667
+ arguments: List[String]
668
+ matchCase: MatchCase
669
+ conditions: List[String]
670
+ variables: List[String]
671
+ jump: Bool
672
+ last: Bool
673
+ async: Bool
674
+ ): String {
675
+ function emitWrapper(code: String): String {
676
+ if(conditions.isEmpty()) {"{\n"} else {
677
+ "if(" + conditions.join(" && ") + ") {\n"
678
+ } +
679
+ variables.join() +
680
+ code +
681
+ "\n}"
682
+ }
661
683
  Pair(matchCase.patterns, matchCase.guards).{
662
684
  | Pair([p, ...ps], _) =>
663
685
  self.emitPattern(
@@ -665,18 +687,45 @@ extend self: JsEmitter {
665
687
  p
666
688
  arguments.dropFirst()
667
689
  matchCase.MatchCase(patterns = ps)
690
+ conditions
691
+ variables
668
692
  jump
669
693
  last
670
694
  async
671
695
  )
696
+ | Pair([], [MatchGuard(_, e, PVariant(_, "ff:core/Bool.True", _))]) {variables.isEmpty()} =>
697
+ let newCase = matchCase.MatchCase(patterns = [], guards = [])
698
+ self.emitCase([], newCase, [...conditions, self.emitTerm(e, async)], [], jump, last, async)
699
+ | Pair([], [MatchGuard(_, e, PVariant(_, "ff:core/Bool.True", _))]) =>
700
+ let newCase = matchCase.MatchCase(patterns = [], guards = [])
701
+ let code = self.emitCase([], newCase, [self.emitTerm(e, async)], [], jump, last, async)
702
+ emitWrapper(code)
672
703
  | Pair([], [guard, ...guards]) =>
673
704
  let guardName = "_guard" + (guards.size() + 1)
674
705
  let newCase = matchCase.MatchCase(patterns = [guard.pattern], guards = guards)
675
- "const " + guardName + " = " + self.emitTerm(guard.term, async) + ";\n" +
676
- self.emitCase([guardName], newCase, jump, last, async)
706
+ let code =
707
+ "const " + guardName + " = " + self.emitTerm(guard.term, async) + ";\n" +
708
+ self.emitCase([guardName], newCase, [], [], jump, last, async)
709
+ emitWrapper(code)
677
710
  | Pair([], []) =>
678
- self.emitStatements(matchCase.body, last, async) +
679
- if(jump && last) {"\nreturn"} elseIf {jump} {"\nbreak"} else {""}
711
+ let statementsCode = self.emitStatements(matchCase.body, last, async)
712
+ let lastLine = statementsCode.reverse().takeWhile {_ != '\n'}.reverse()
713
+ let returns =
714
+ lastLine.startsWith("return ") ||
715
+ lastLine.startsWith("break ") ||
716
+ lastLine.startsWith("continue ") ||
717
+ lastLine.startsWith("return;") ||
718
+ lastLine.startsWith("break;") ||
719
+ lastLine.startsWith("continue;") ||
720
+ lastLine.startsWith("throw ")
721
+ let code = statementsCode + if(jump && last && !returns) {
722
+ "\nreturn"
723
+ } elseIf {jump && !returns} {
724
+ "\nbreak"
725
+ } else {
726
+ ""
727
+ }
728
+ emitWrapper(code)
680
729
  }
681
730
  }
682
731
 
@@ -685,81 +734,78 @@ extend self: JsEmitter {
685
734
  pattern: MatchPattern
686
735
  arguments: List[String]
687
736
  matchCase: MatchCase
737
+ conditions: List[String]
738
+ variables: List[String]
688
739
  jump: Bool
689
740
  last: Bool
690
741
  async: Bool
691
742
  ): String {
692
743
  pattern.{
693
744
  | PString(_, value) =>
694
- "if(" + argument + " === " + value + ") {\n" +
695
- self.emitCase(arguments, matchCase, jump, last, async) +
696
- "\n}"
745
+ let newConditions = [...conditions, argument + " === " + value]
746
+ self.emitCase(arguments, matchCase, newConditions, variables, jump, last, async)
697
747
  | PInt(_, value) =>
698
- "if(" + argument + " === " + value + ") {\n" +
699
- self.emitCase(arguments, matchCase, jump, last, async) +
700
- "\n}"
748
+ let newConditions = [...conditions, argument + " === " + value]
749
+ self.emitCase(arguments, matchCase, newConditions, variables, jump, last, async)
701
750
  | PChar(_, value) =>
702
- "if(" + argument + " === " + charLiteralToNumber(value) + ") {\n" +
703
- self.emitCase(arguments, matchCase, jump, last, async) +
704
- "\n}"
751
+ let newConditions = [...conditions, argument + " === " + charLiteralToNumber(value)]
752
+ self.emitCase(arguments, matchCase, newConditions, variables, jump, last, async)
705
753
  | PVariable(_, None) =>
706
- self.emitCase(arguments, matchCase, jump, last, async)
754
+ self.emitCase(arguments, matchCase, conditions, variables, jump, last, async)
707
755
  | PVariable(_, Some(name)) =>
708
756
  let escaped = escapeKeyword(name)
709
- if(escaped != argument) {"const " + escaped + " = " + argument + ";\n"} else {""} +
710
- self.emitCase(arguments, matchCase, jump, last, async)
757
+ let newVariables = if(escaped != argument) {
758
+ [...variables, "const " + escaped + " = " + argument + ";\n"]
759
+ } else {variables}
760
+ self.emitCase(arguments, matchCase, conditions, newVariables, jump, last, async)
711
761
  | PVariant(_, "ff:core/Bool.False", []) =>
712
- "if(!" + argument + ") {\n" +
713
- self.emitCase(arguments, matchCase, jump, last, async) +
714
- "\n}"
762
+ self.emitCase(arguments, matchCase, [...conditions, "!" + argument], variables, jump, last, async)
715
763
  | PVariant(_, "ff:core/Bool.True", []) =>
716
- "if(" + argument + ") {\n" +
717
- self.emitCase(arguments, matchCase, jump, last, async) +
718
- "\n}"
719
- | PVariant(_, "List$Empty", []) =>
720
- mutable shortArgument = argument
721
- mutable shortCount = 0
722
- while {shortArgument.endsWith(".slice(1)")} {
723
- shortArgument = shortArgument.dropLast(".slice(1)".size())
724
- shortCount += 1
725
- }
726
- "if(" + shortArgument + ".length === " + shortCount + ") {\n" +
727
- self.emitCase(arguments, matchCase, jump, last, async) +
728
- "\n}"
729
- | PVariant(_, "List$Link", [head, tail]) =>
730
- mutable shortArgument = argument
731
- mutable shortCount = 0
732
- while {shortArgument.endsWith(".slice(1)")} {
733
- shortArgument = shortArgument.dropLast(".slice(1)".size())
734
- shortCount += 1
764
+ self.emitCase(arguments, matchCase, [...conditions, argument], variables, jump, last, async)
765
+ | PVariant(_, emptyOrLink, _) {emptyOrLink == "List$Empty" || emptyOrLink == "List$Link"} =>
766
+ mutable restPattern = None
767
+ function listPatterns(matchPattern: MatchPattern): List[MatchPattern] {
768
+ | PVariant(_, "List$Empty", []) =>
769
+ []
770
+ | PVariant(_, "List$Link", [head, tail]) =>
771
+ [head, ...listPatterns(tail)]
772
+ | p =>
773
+ restPattern = Some(p)
774
+ []
735
775
  }
736
- let newArguments = [shortArgument + "[" + shortCount + "]", argument + ".slice(1)", ...arguments]
737
- let newMatchCase = matchCase.MatchCase(patterns = [head, tail, ...matchCase.patterns])
738
- "if(" + shortArgument + ".length > " + shortCount + ") {\n" +
739
- self.emitCase(newArguments, newMatchCase, jump, last, async) +
740
- "\n}"
776
+ let patterns = listPatterns(pattern)
777
+ let itemArguments = patterns.pairs().map {| Pair(i, _) => argument + "[" + i + "]"}
778
+ let restArgument = restPattern.map {_ => argument + ".slice(" + patterns.size() + ")"}
779
+ let newArguments = [...itemArguments, ...restArgument.toList(), ...arguments]
780
+ let newMatchCase = matchCase.MatchCase(
781
+ patterns = [...patterns, ...restPattern.toList(), ...matchCase.patterns]
782
+ )
783
+ let operator = restPattern.map {_ => ">="}.else {"==="}
784
+ let newConditions = [...conditions, argument + ".length " + operator + " " + patterns.size()]
785
+ self.emitCase(newArguments, newMatchCase, newConditions, variables, jump, last, async)
741
786
  | PVariant(_, name, patterns) =>
742
787
  let processed = self.processVariantCase(name, argument)
743
788
  let newMatchCase = matchCase.MatchCase(patterns = [...patterns, ...matchCase.patterns])
744
- if(processed.loneVariant) {""} else {
745
- "if(" + argument + "." + processed.variantName + ") {\n"
746
- } +
747
- self.emitCase([...processed.arguments, ...arguments], newMatchCase, jump, last, async) +
748
- if(processed.loneVariant) {""} else {"\n}"}
789
+ let newConditions = if(processed.loneVariant) {conditions} else {
790
+ [...conditions, argument + "." + processed.variantName]
791
+ }
792
+ let newArguments = [...processed.arguments, ...arguments]
793
+ self.emitCase(newArguments, newMatchCase, newConditions, variables, jump, last, async)
749
794
  | PVariantAs(at, name, variableAt, variable) =>
750
795
  let processed = self.processVariantCase(name, argument)
751
- if(processed.loneVariant) {""} else {
752
- "if(" + argument + "." + processed.variantName + ") {\n"
753
- } +
754
- variable.map(escapeKeyword).filter {_ != argument}.map {
755
- "const " + _ + " = " + argument + ";\n"
756
- }.else {""} +
757
- self.emitCase(arguments, matchCase, jump, last, async) +
758
- if(processed.loneVariant) {""} else {"\n}"}
796
+ let newConditions = if(processed.loneVariant) {conditions} else {
797
+ [...conditions, argument + "." + processed.variantName]
798
+ }
799
+ let newVariables = variable.map(escapeKeyword).filter {_ != argument}.map {
800
+ [...variables, "const " + _ + " = " + argument + ";\n"]
801
+ }.else {[]}
802
+ self.emitCase(arguments, matchCase, newConditions, newVariables, jump, last, async)
759
803
  | PAlias(_, pattern, variable) =>
760
804
  let escaped = escapeKeyword(variable)
761
- if(escaped != argument) {"const " + escaped + " = " + argument + ";\n"} else {""} +
762
- self.emitPattern(argument, pattern, arguments, matchCase, jump, last, async)
805
+ let newVariables = if(escaped != argument) {
806
+ [...variables, "const " + escaped + " = " + argument + ";\n"]
807
+ } else {variables}
808
+ self.emitPattern(argument, pattern, arguments, matchCase, conditions, newVariables, jump, last, async)
763
809
  }
764
810
  }
765
811
 
@@ -771,8 +817,6 @@ extend self: JsEmitter {
771
817
  }
772
818
 
773
819
  processVariantCase(name: String, argument: String): ProcessedVariantCase {
774
- if(name == "List$Empty") {ProcessedVariantCase(name, False, False, [])} else:
775
- if(name == "List$Link") {ProcessedVariantCase(name, False, False, [argument + "[0]", argument + ".slice(1)"])} else:
776
820
  let variantNameUnqualified = name.reverse().takeWhile {_ != '.'}.reverse()
777
821
  let variantName = escapeKeyword(variantNameUnqualified)
778
822
  let moduleName = name.dropLast(variantNameUnqualified.size() + 1)
@@ -66,11 +66,23 @@ data SymbolHook(
66
66
 
67
67
  class Box[T](mutable value: T)
68
68
 
69
+ data DocumentSymbolKind {
70
+ SLet(mutable: Bool)
71
+ SFunction(member: Bool)
72
+ SExtend
73
+ STraitFunction
74
+ STrait
75
+ SInstance
76
+ SVariant
77
+ SType
78
+ SParameter
79
+ }
80
+
69
81
  class ResultHook {
70
82
  ParseSymbolBegin
71
83
  ParseSymbolEnd(
72
84
  name: String
73
- kind: Int
85
+ kind: DocumentSymbolKind
74
86
  selectionStart: Location
75
87
  selectionEnd: Location
76
88
  start: Location
@@ -84,6 +96,7 @@ class ResultHook {
84
96
  ResolveSymbolHook(
85
97
  symbol: SymbolHook
86
98
  annotation: Option[Type]
99
+ topLevel: Bool
87
100
  )
88
101
  ResolveTypeHook(
89
102
  types: Map[String, String]
@@ -98,6 +111,7 @@ class ResultHook {
98
111
  ResolveSignatureHook(
99
112
  signature: Signature
100
113
  isInstanceMethod: Bool
114
+ topLevel: Bool
101
115
  )
102
116
  ResolveVariantFieldHook(
103
117
  symbol: SymbolHook
@@ -181,8 +195,8 @@ showHook(hook: ResultHook): String {
181
195
  | ParseSymbolBegin => "ParseSymbolBegin(...)"
182
196
  | ParseSymbolEnd(name, kind, selectionStart, selectionEnd, start, end) => "ParseSymbolEnd(...)"
183
197
  | ResolveConstraintHook(symbol, constrant) => "ResolveConstraintHook(...)"
184
- | ResolveSignatureHook(signature, _) => "ResolveSignatureHook(...)"
185
- | ResolveSymbolHook(symbol, annotation) => "ResolveSymbolHook(...)"
198
+ | ResolveSignatureHook(signature, _, _) => "ResolveSignatureHook(...)"
199
+ | ResolveSymbolHook(symbol, annotation, _) => "ResolveSymbolHook(...)"
186
200
  | ResolveTypeHook(types, typeGenerics, symbol, explicitType) => "ResolveTypeHook(...)"
187
201
  | ResolveVariantFieldHook(symbol, type, commonField) => "ResolveVariantFieldHook(...)"
188
202
  }
package/compiler/Main.ff CHANGED
@@ -82,8 +82,9 @@ main(system: NodeSystem): Unit {
82
82
  importAndRun(fireflyPath, "build", resolvedDependencies.mainPackagePair, localMainFile, [])
83
83
 
84
84
  | CheckCommand(filePath) =>
85
- Builder.check(system, fireflyPath, system.path(filePath), Map.empty(), LspHook.disabled(), True)
86
-
85
+ let errors = Builder.check(system, fireflyPath, system.path(filePath), None, Map.empty(), LspHook.disabled(), True)
86
+ if(!errors.isEmpty()) {throw(CompileErrors(errors))}
87
+
87
88
  | BootstrapCommand =>
88
89
  let workingDirectory = system.path(".")
89
90
  Builder.build(
@@ -110,11 +111,16 @@ main(system: NodeSystem): Unit {
110
111
  try {
111
112
  let command = parseCommandLine(system.arguments())
112
113
  runCommand(command)
113
- } catch {| CommandLineError(message), error =>
114
+ } catch {| CommandLineError(message), _ =>
114
115
  Log.debug(message)
115
- } catch {| CompileError(at, message), error =>
116
+ } catch {| CompileError(at, message), _ =>
116
117
  Log.debug(message)
117
118
  Log.debug(" at " + at.file.replace("./", "") + ":" + at.line + ":" + at.column)
119
+ } catch {| CompileErrors(errors), _ =>
120
+ errors.map {| CompileError(at, message) =>
121
+ Log.debug(message)
122
+ Log.debug(" at " + at.file.replace("./", "") + ":" + at.line + ":" + at.column)
123
+ }
118
124
  } grab()
119
125
  }
120
126
 
@@ -164,13 +170,13 @@ parseCommandLine(arguments: List[String]): MainCommand {
164
170
  }
165
171
  | ["check", ...checkArguments] =>
166
172
  checkArguments.{
167
- | [fileName] {fileName.removeLast(".ff") | Some(_)} =>
173
+ | [fileName] =>
168
174
  CheckCommand(fileName)
169
175
  | [_, _, ...] => throw(CommandLineError(
170
176
  "You must only specify a single argument to check." + usageString
171
177
  ))
172
- | _ => throw(CommandLineError(
173
- "You must specify a Firefly file (.ff) as the argument to build." + usageString
178
+ | [] => throw(CommandLineError(
179
+ "You must specify a Firefly file (.ff) or directory as the argument to check." + usageString
174
180
  ))
175
181
  }
176
182
  | ["bootstrap", _] =>
@@ -232,7 +232,7 @@ extend self: Parser {
232
232
  if(self.lspHook.trackSymbols) {
233
233
  self.lspHook.emit(ParseSymbolEnd(
234
234
  name = nameToken.raw()
235
- kind = 14
235
+ kind = SLet(mutable = False)
236
236
  selectionStart = nameToken.at()
237
237
  selectionEnd = nameToken.end()
238
238
  start = nameToken.at()
@@ -254,10 +254,9 @@ extend self: Parser {
254
254
  bestTarget
255
255
  )
256
256
  if(self.lspHook.trackSymbols) {
257
- let kind = if(member) {6} else {12}
258
257
  self.lspHook.emit(ParseSymbolEnd(
259
258
  name = signature.name
260
- kind = kind
259
+ kind = SFunction(member)
261
260
  selectionStart = signature.at
262
261
  selectionEnd = signature.at.Location(column = signature.at.column + signature.name.size())
263
262
  start = signature.at
@@ -365,7 +364,7 @@ extend self: Parser {
365
364
  }
366
365
  self.lspHook.emit(ParseSymbolEnd(
367
366
  name = name
368
- kind = 3 // Namespace
367
+ kind = SExtend
369
368
  selectionStart = nameToken.at()
370
369
  selectionEnd = nameToken.end()
371
370
  start = extendToken.at()
@@ -411,7 +410,7 @@ extend self: Parser {
411
410
  if(self.lspHook.trackSymbols) {
412
411
  self.lspHook.emit(ParseSymbolEnd(
413
412
  name = signatureNameToken.raw()
414
- kind = 12 // Function
413
+ kind = STraitFunction
415
414
  selectionStart = signatureNameToken.at()
416
415
  selectionEnd = signatureNameToken.end()
417
416
  start = signatureNameToken.at()
@@ -436,7 +435,7 @@ extend self: Parser {
436
435
  if(self.lspHook.trackSymbols) {
437
436
  self.lspHook.emit(ParseSymbolEnd(
438
437
  name = nameToken.raw()
439
- kind = 11 // Interface
438
+ kind = STrait
440
439
  selectionStart = nameToken.at()
441
440
  selectionEnd = nameToken.end()
442
441
  start = traitToken.at()
@@ -487,7 +486,7 @@ extend self: Parser {
487
486
  let name = token.raw() + ": " + nameToken.raw()
488
487
  self.lspHook.emit(ParseSymbolEnd(
489
488
  name = name
490
- kind = 19 // Object
489
+ kind = SInstance
491
490
  selectionStart = nameToken.at()
492
491
  selectionEnd = nameToken.end()
493
492
  start = instanceToken.at()
@@ -545,7 +544,7 @@ extend self: Parser {
545
544
  if(self.lspHook.trackSymbols) {
546
545
  self.lspHook.emit(ParseSymbolEnd(
547
546
  name = variantNameToken.raw()
548
- kind = 10 // Enum
547
+ kind = SVariant
549
548
  selectionStart = variantNameToken.at()
550
549
  selectionEnd = variantNameToken.end()
551
550
  start = variantNameToken.at()
@@ -571,7 +570,7 @@ extend self: Parser {
571
570
  if(self.lspHook.trackSymbols) {
572
571
  self.lspHook.emit(ParseSymbolEnd(
573
572
  name = nameToken.raw()
574
- kind = 5
573
+ kind = SType
575
574
  selectionStart = nameToken.at()
576
575
  selectionEnd = nameToken.end()
577
576
  start = kindToken.at()
@@ -770,7 +769,7 @@ extend self: Parser {
770
769
  if(lspTrackSymbols) {
771
770
  self.lspHook.emit(ParseSymbolEnd(
772
771
  name = parameterNameToken.raw()
773
- kind = 7 // Property
772
+ kind = SParameter
774
773
  selectionStart = parameterNameToken.at()
775
774
  selectionEnd = parameterNameToken.end()
776
775
  start = lspFirst.at()
@@ -1059,10 +1058,9 @@ extend self: Parser {
1059
1058
  self.skip(LAssign)
1060
1059
  let value = self.parseTerm()
1061
1060
  if(self.lspHook.trackSymbols) {
1062
- let kind = if(mutable) {13} else {14}
1063
1061
  self.lspHook.emit(ParseSymbolEnd(
1064
1062
  name = nameToken.raw()
1065
- kind = kind
1063
+ kind = SLet(mutable)
1066
1064
  selectionStart = nameToken.at()
1067
1065
  selectionEnd = nameToken.end()
1068
1066
  start = mutableToken.at()
@@ -1095,7 +1093,7 @@ extend self: Parser {
1095
1093
  if(self.lspHook.trackSymbols) {
1096
1094
  self.lspHook.emit(ParseSymbolEnd(
1097
1095
  name = signature.name
1098
- kind = 12
1096
+ kind = SFunction(member = False)
1099
1097
  selectionStart = signature.at
1100
1098
  selectionEnd = signature.at.Location(column = signature.at.column + signature.name.size())
1101
1099
  start = functionAt