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.
- package/compiler/Builder.ff +23 -13
- package/compiler/JsEmitter.ff +120 -76
- package/compiler/LspHook.ff +17 -3
- package/compiler/Main.ff +13 -7
- package/compiler/Parser.ff +11 -13
- package/compiler/Resolver.ff +15 -15
- package/compiler/Syntax.ff +1 -0
- package/core/Array.ff +6 -4
- package/core/Int.ff +12 -12
- package/core/Json.ff +2 -2
- package/core/List.ff +6 -4
- package/experimental/benchmarks/ListGrab.ff +23 -0
- package/experimental/benchmarks/ListGrab.java +55 -0
- package/experimental/benchmarks/Pyrotek45.ff +30 -0
- package/experimental/benchmarks/Pyrotek45.java +64 -0
- package/experimental/tests/TestJson.ff +26 -0
- package/lsp/CompletionHandler.ff +14 -14
- package/lsp/Handler.ff +56 -60
- package/lsp/SignatureHelpHandler.ff +5 -4
- package/lsp/SymbolHandler.ff +18 -4
- package/lsp/TestReferences.ff +15 -0
- package/lsp/TestReferencesCase.ff +8 -0
- package/output/js/ff/compiler/Builder.mjs +50 -44
- package/output/js/ff/compiler/Dependencies.mjs +0 -2
- package/output/js/ff/compiler/Deriver.mjs +16 -140
- package/output/js/ff/compiler/Dictionaries.mjs +8 -222
- package/output/js/ff/compiler/Environment.mjs +12 -154
- package/output/js/ff/compiler/Inference.mjs +127 -1013
- package/output/js/ff/compiler/JsEmitter.mjs +434 -2344
- package/output/js/ff/compiler/JsImporter.mjs +0 -12
- package/output/js/ff/compiler/LspHook.mjs +548 -151
- package/output/js/ff/compiler/Main.mjs +96 -550
- package/output/js/ff/compiler/Parser.mjs +58 -390
- package/output/js/ff/compiler/Patterns.mjs +20 -200
- package/output/js/ff/compiler/Resolver.mjs +26 -340
- package/output/js/ff/compiler/Substitution.mjs +2 -160
- package/output/js/ff/compiler/Syntax.mjs +449 -3293
- package/output/js/ff/compiler/Token.mjs +9 -1095
- package/output/js/ff/compiler/Tokenizer.mjs +4 -2
- package/output/js/ff/compiler/Unification.mjs +26 -360
- package/output/js/ff/compiler/Wildcards.mjs +0 -86
- package/output/js/ff/compiler/Workspace.mjs +8 -96
- package/output/js/ff/core/Array.mjs +15 -8
- package/output/js/ff/core/AssetSystem.mjs +4 -14
- package/output/js/ff/core/Bool.mjs +0 -12
- package/output/js/ff/core/Core.mjs +0 -30
- package/output/js/ff/core/Int.mjs +24 -24
- package/output/js/ff/core/IntMap.mjs +0 -8
- package/output/js/ff/core/Json.mjs +2 -42
- package/output/js/ff/core/List.mjs +23 -32
- package/output/js/ff/core/Lock.mjs +0 -10
- package/output/js/ff/core/Map.mjs +0 -24
- package/output/js/ff/core/Option.mjs +10 -286
- package/output/js/ff/core/Ordering.mjs +16 -158
- package/output/js/ff/core/Pair.mjs +2 -34
- package/output/js/ff/core/Path.mjs +2 -28
- package/output/js/ff/core/Random.mjs +4 -4
- package/output/js/ff/core/RbMap.mjs +56 -644
- package/output/js/ff/core/Show.mjs +0 -16
- package/output/js/ff/core/Stream.mjs +14 -144
- package/output/js/ff/core/StringMap.mjs +0 -8
- package/output/js/ff/core/Try.mjs +4 -108
- package/output/js/ff/core/Unit.mjs +2 -16
- package/package.json +1 -1
- package/postgresql/Pg.ff +23 -23
- package/vscode/client/src/extension.ts +30 -2
- package/vscode/package.json +17 -1
- package/core/Stack.ff +0 -250
package/compiler/Builder.ff
CHANGED
|
@@ -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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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(
|
package/compiler/JsEmitter.ff
CHANGED
|
@@ -223,9 +223,9 @@ extend self: JsEmitter {
|
|
|
223
223
|
}.join("\n")
|
|
224
224
|
let body = self.emitTailCall {
|
|
225
225
|
let casesString = cases.map {
|
|
226
|
-
|
|
226
|
+
self.emitCase(escapedArguments, _, [], [], True, True, async)
|
|
227
227
|
}.join("\n")
|
|
228
|
-
|
|
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 {
|
|
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(
|
|
499
|
+
| ESequential(_, EVariant(_, "ff:core/Unit.Unit", _, _), after) =>
|
|
494
500
|
self.emitStatements(after, last, async)
|
|
495
|
-
| ESequential(
|
|
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 {
|
|
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 {
|
|
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(
|
|
606
|
-
Argument(_, _, ECall(
|
|
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(
|
|
618
|
-
Argument(_, _, ECall(
|
|
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(
|
|
635
|
-
Argument(_, _, ECall(
|
|
636
|
-
Argument(_, _, ECall(
|
|
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(
|
|
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
|
-
|
|
676
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|
|
710
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
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
|
|
737
|
-
let
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
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) {
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
|
|
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) {
|
|
752
|
-
|
|
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) {
|
|
762
|
-
|
|
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)
|
package/compiler/LspHook.ff
CHANGED
|
@@ -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:
|
|
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),
|
|
114
|
+
} catch {| CommandLineError(message), _ =>
|
|
114
115
|
Log.debug(message)
|
|
115
|
-
} catch {| CompileError(at, message),
|
|
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]
|
|
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
|
-
|
|
|
173
|
-
"You must specify a Firefly file (.ff) as the argument to
|
|
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", _] =>
|
package/compiler/Parser.ff
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|