firefly-compiler 0.4.20 → 0.4.22
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/Dictionaries.ff +10 -10
- package/compiler/Inference.ff +167 -148
- package/compiler/JsEmitter.ff +122 -78
- package/compiler/LspHook.ff +6 -3
- package/compiler/Main.ff +24 -10
- package/compiler/Patterns.ff +1 -1
- package/compiler/Resolver.ff +167 -159
- package/compiler/Substitution.ff +2 -2
- package/compiler/Syntax.ff +1 -0
- package/compiler/Unification.ff +1 -1
- package/core/Array.ff +6 -4
- package/core/Int.ff +12 -12
- package/core/List.ff +6 -4
- package/core/Map.ff +8 -0
- package/core/Set.ff +7 -0
- 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/Handler.ff +65 -61
- package/lsp/SignatureHelpHandler.ff +5 -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 +24 -238
- package/output/js/ff/compiler/Environment.mjs +12 -154
- package/output/js/ff/compiler/Inference.mjs +207 -1069
- package/output/js/ff/compiler/JsEmitter.mjs +434 -2342
- package/output/js/ff/compiler/JsImporter.mjs +0 -12
- package/output/js/ff/compiler/LspHook.mjs +20 -446
- package/output/js/ff/compiler/Main.mjs +110 -553
- package/output/js/ff/compiler/Parser.mjs +36 -356
- package/output/js/ff/compiler/Patterns.mjs +24 -204
- package/output/js/ff/compiler/Resolver.mjs +428 -554
- package/output/js/ff/compiler/Substitution.mjs +6 -164
- 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 +30 -364
- 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 +0 -40
- 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 +26 -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/Set.mjs +16 -0
- 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/package.json +1 -1
- package/bin/firefly.mjs +0 -2
- package/guide/Main.ff +0 -22
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/Dictionaries.ff
CHANGED
|
@@ -168,18 +168,18 @@ extend self: Dictionaries {
|
|
|
168
168
|
): Dictionary {
|
|
169
169
|
let instantiationMap = typeParameters.zip(typeArguments).toMap()
|
|
170
170
|
let unification = Unification.make([], False)
|
|
171
|
-
let newGenerics = constraint.generics.map {
|
|
172
|
-
|
|
173
|
-
| TConstructor
|
|
171
|
+
let newGenerics = constraint.generics.map {unification.instantiate(instantiationMap, _)}
|
|
172
|
+
newGenerics.grabFirst().{
|
|
173
|
+
| TConstructor firstType =>
|
|
174
|
+
let instance = self.instances.get(InstanceKey(constraint.name, firstType.name)).else {
|
|
175
|
+
throw(CompileError(at, "Missing instance " + firstType.name + ": " + constraint.name))
|
|
176
|
+
}
|
|
177
|
+
let dictionaries = instance.constraints.map {c =>
|
|
178
|
+
self.makeDictionary(at, instance.generics, firstType.generics, c)
|
|
179
|
+
}
|
|
180
|
+
Dictionary(instance.packagePair, instance.moduleName, constraint.name, firstType.name, dictionaries)
|
|
174
181
|
| TVariable t => fail(t.at, " is still a unification variable")
|
|
175
182
|
}
|
|
176
|
-
let instance = self.instances.get(InstanceKey(constraint.name, firstType.name)).else {
|
|
177
|
-
throw(CompileError(at, "Missing instance " + firstType.name + ": " + constraint.name))
|
|
178
|
-
}
|
|
179
|
-
let dictionaries = instance.constraints.map { c =>
|
|
180
|
-
self.makeDictionary(at, instance.generics, firstType.generics, c)
|
|
181
|
-
}
|
|
182
|
-
Dictionary(instance.packagePair, instance.moduleName, constraint.name, firstType.name, dictionaries)
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
}
|
package/compiler/Inference.ff
CHANGED
|
@@ -298,8 +298,11 @@ extend self: Inference {
|
|
|
298
298
|
}
|
|
299
299
|
self.unification.unify(at, expected, instantiated.scheme.signature.returnType)
|
|
300
300
|
let parameters = instantiated.scheme.signature.parameters.sortBy {_.name}
|
|
301
|
-
let
|
|
302
|
-
TConstructor
|
|
301
|
+
let paramtersWithFieldAt = parameters.map {p => p.valueType.{
|
|
302
|
+
| TConstructor t => t.TConstructor(at = p.at)
|
|
303
|
+
| TVariable t => t.TVariable(at = p.at)
|
|
304
|
+
}}
|
|
305
|
+
let recordType = TConstructor(at, "Record$" + parameters.map {_.name}.join("$"), paramtersWithFieldAt)
|
|
303
306
|
variableOption.toList().map {Pair(_, Pair(variableAt, recordType))}.toMap()
|
|
304
307
|
| PVariant(at, "List$Empty", []) =>
|
|
305
308
|
let itemType = self.unification.freshUnificationVariable(at)
|
|
@@ -371,14 +374,18 @@ extend self: Inference {
|
|
|
371
374
|
let record = self.inferTerm(environment, recordType, e.record)
|
|
372
375
|
self.unification.substitute(recordType).{
|
|
373
376
|
| TConstructor(_, name, typeArguments)@t {name.startsWith("Record$")} =>
|
|
374
|
-
if(self.lspHook.isAt(e.at)) {
|
|
375
|
-
let symbolHook = SymbolHook(e.field, e.at, e.at)
|
|
376
|
-
let noEffect = self.unification.freshUnificationVariable(e.at)
|
|
377
|
-
self.lspHook.emit(
|
|
378
|
-
InferRecordFieldHook(self.unification, environment, expected, t, e.field)
|
|
379
|
-
)
|
|
380
|
-
}
|
|
381
377
|
let fieldNames = name.split('$').dropFirst(1)
|
|
378
|
+
if(self.lspHook.isEnabled()) {
|
|
379
|
+
fieldNames.zip(typeArguments).each {| Pair(fieldName, fieldType) =>
|
|
380
|
+
if(e.field == fieldName):
|
|
381
|
+
let definedAt = self.unification.substitute(fieldType).at
|
|
382
|
+
if(self.lspHook.isAt(e.at) || self.lspHook.isDefinedAt(definedAt)) {
|
|
383
|
+
self.lspHook.emit(
|
|
384
|
+
InferRecordFieldHook(e.at, self.unification, environment, expected, t, e.field)
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
382
389
|
fieldNames.pairs().find {_.second == e.field}.map {_.first}.map {index =>
|
|
383
390
|
let t1 = typeArguments.grab(index)
|
|
384
391
|
self.unification.unify(e.at, expected, t1)
|
|
@@ -568,7 +575,7 @@ extend self: Inference {
|
|
|
568
575
|
| ECall e =>
|
|
569
576
|
if((self.lspHook.isEnabled()) && e.target.{| StaticCall _ => True | _ => False}) {term} else:
|
|
570
577
|
let call = e.target.{
|
|
571
|
-
| DynamicCall call => call
|
|
578
|
+
| DynamicCall call => (function = call.function, tailCall = call.tailCall)
|
|
572
579
|
| StaticCall _ => fail(e.at, "Internal error: Static calls not expected in the Inference phase")
|
|
573
580
|
}
|
|
574
581
|
call.function.{
|
|
@@ -747,23 +754,26 @@ extend self: Inference {
|
|
|
747
754
|
recordType: Type
|
|
748
755
|
name: String
|
|
749
756
|
): Term {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
757
|
+
term.{
|
|
758
|
+
| ECall e =>
|
|
759
|
+
let tailCall = e.target.{
|
|
760
|
+
| DynamicCall call => call.tailCall
|
|
761
|
+
| StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferMethodCall")
|
|
762
|
+
}
|
|
763
|
+
let selfParameter = signature.parameters.grabFirst()
|
|
764
|
+
let selfArgument = Argument(record.at, Some(selfParameter.name), record) // Be careful not to infer again
|
|
765
|
+
self.unification.unify(term.at, expected, signature.returnType)
|
|
766
|
+
self.unification.unify(term.at, selfParameter.valueType, recordType)
|
|
767
|
+
let arguments = self.inferArguments(term.at, name, environment, signature.parameters.dropFirst(), e.arguments)
|
|
768
|
+
self.unification.affect(term.at, signature.effect, environment.effect)
|
|
769
|
+
e.ECall(
|
|
770
|
+
target = StaticCall(name, instanceCall = False, tailCall = tailCall)
|
|
771
|
+
typeArguments = instantiation.map {_.second}
|
|
772
|
+
arguments = [selfArgument, ...arguments]
|
|
773
|
+
effect = signature.effect
|
|
774
|
+
)
|
|
775
|
+
| _ => fail(term.at, "Call expected")
|
|
754
776
|
}
|
|
755
|
-
let selfParameter = signature.parameters.grabFirst()
|
|
756
|
-
let selfArgument = Argument(record.at, Some(selfParameter.name), record) // Be careful not to infer again
|
|
757
|
-
self.unification.unify(term.at, expected, signature.returnType)
|
|
758
|
-
self.unification.unify(term.at, selfParameter.valueType, recordType)
|
|
759
|
-
let arguments = self.inferArguments(term.at, name, environment, signature.parameters.dropFirst(), e.arguments)
|
|
760
|
-
self.unification.affect(term.at, signature.effect, environment.effect)
|
|
761
|
-
e.ECall(
|
|
762
|
-
target = StaticCall(name, instanceCall = False, tailCall = call.tailCall)
|
|
763
|
-
typeArguments = instantiation.map {_.second}
|
|
764
|
-
arguments = [selfArgument, ...arguments]
|
|
765
|
-
effect = signature.effect
|
|
766
|
-
)
|
|
767
777
|
}
|
|
768
778
|
|
|
769
779
|
inferFunctionCall(
|
|
@@ -775,139 +785,148 @@ extend self: Inference {
|
|
|
775
785
|
term: Term
|
|
776
786
|
name: String
|
|
777
787
|
): Term {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
788
|
+
term.{
|
|
789
|
+
| ECall e =>
|
|
790
|
+
let tailCall = e.target.{
|
|
791
|
+
| DynamicCall call => call.tailCall
|
|
792
|
+
| StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferFunctionCall")
|
|
793
|
+
}
|
|
794
|
+
self.unification.unify(e.at, expected, signature.returnType)
|
|
795
|
+
let arguments = self.inferArguments(e.at, name, environment, signature.parameters, e.arguments)
|
|
796
|
+
self.unification.affect(term.at, signature.effect, environment.effect)
|
|
797
|
+
e.ECall(
|
|
798
|
+
target = StaticCall(name, instanceCall = instanceCall, tailCall = tailCall)
|
|
799
|
+
typeArguments = instantiation.map {_.second}
|
|
800
|
+
arguments = arguments
|
|
801
|
+
effect = signature.effect
|
|
802
|
+
)
|
|
803
|
+
| _ => fail(term.at, "Call expected")
|
|
782
804
|
}
|
|
783
|
-
self.unification.unify(e.at, expected, signature.returnType)
|
|
784
|
-
let arguments = self.inferArguments(e.at, name, environment, signature.parameters, e.arguments)
|
|
785
|
-
self.unification.affect(term.at, signature.effect, environment.effect)
|
|
786
|
-
e.ECall(
|
|
787
|
-
target = StaticCall(name, instanceCall = instanceCall, tailCall = call.tailCall)
|
|
788
|
-
typeArguments = instantiation.map {_.second}
|
|
789
|
-
arguments = arguments
|
|
790
|
-
effect = signature.effect
|
|
791
|
-
)
|
|
792
805
|
}
|
|
793
806
|
|
|
794
807
|
inferLambdaCall(environment: Environment, expected: Type, term: Term): Term {
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
808
|
+
term.{
|
|
809
|
+
| ECall e =>
|
|
810
|
+
let call = e.target.{
|
|
811
|
+
| DynamicCall call {!call.tailCall} => (function = call.function, tailCall = call.tailCall)
|
|
812
|
+
| DynamicCall _ => throw(CompileError(e.at, "Tailcalls not supported on lambda functions"))
|
|
813
|
+
| StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferLambdaCall")
|
|
814
|
+
}
|
|
815
|
+
let effect = self.unification.freshUnificationVariable(term.at)
|
|
816
|
+
let argumentTypes = e.arguments.map {self.unification.freshUnificationVariable(_.at)}
|
|
817
|
+
let functionType = TConstructor(e.at, "Function$" + e.arguments.size(), [
|
|
818
|
+
effect
|
|
819
|
+
...argumentTypes
|
|
820
|
+
expected
|
|
821
|
+
])
|
|
822
|
+
let function = self.inferTerm(environment, functionType, call.function)
|
|
823
|
+
let arguments = e.arguments.zip(argumentTypes).map {| Pair(argument, t) =>
|
|
824
|
+
argument.name.each {name =>
|
|
825
|
+
throw(CompileError(argument.at, "Named argument not allowed here: " + name))
|
|
826
|
+
}
|
|
827
|
+
argument.Argument(value = self.inferTerm(environment, t, argument.value))
|
|
828
|
+
}
|
|
829
|
+
e.typeArguments.first().each {typeArgument =>
|
|
830
|
+
throw(CompileError(typeArgument.at, "Type arguments not allowed here"))
|
|
831
|
+
}
|
|
832
|
+
self.unification.affect(term.at, effect, environment.effect)
|
|
833
|
+
e.ECall(
|
|
834
|
+
target = call.DynamicCall(function = function)
|
|
835
|
+
typeArguments = []
|
|
836
|
+
arguments = arguments
|
|
837
|
+
effect = effect
|
|
838
|
+
)
|
|
839
|
+
| _ => fail(term.at, "Call expected")
|
|
817
840
|
}
|
|
818
|
-
self.unification.affect(term.at, effect, environment.effect)
|
|
819
|
-
e.ECall(
|
|
820
|
-
target = call.DynamicCall(function = function)
|
|
821
|
-
typeArguments = []
|
|
822
|
-
arguments = arguments
|
|
823
|
-
effect = effect
|
|
824
|
-
)
|
|
825
841
|
}
|
|
826
842
|
|
|
827
843
|
inferOperator(environment: Environment, expected: Type, operator: String, term: Term): Term {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
844
|
+
term.{
|
|
845
|
+
| ECall e =>
|
|
846
|
+
let target = StaticCall(operator, instanceCall = False, tailCall = False)
|
|
847
|
+
e.arguments.{
|
|
848
|
+
| [a1] {
|
|
849
|
+
operator == "!"
|
|
850
|
+
} =>
|
|
851
|
+
let t = TConstructor(e.at, core("Bool"), [])
|
|
852
|
+
let e1 = self.inferTerm(environment, t, a1.value)
|
|
853
|
+
self.unification.unify(e.at, expected, t)
|
|
854
|
+
e.ECall(target = target, arguments = [a1.Argument(value = e1)])
|
|
855
|
+
| [a1] {
|
|
856
|
+
operator == "-"
|
|
857
|
+
} =>
|
|
858
|
+
let t1 = self.unification.freshUnificationVariable(e.at)
|
|
859
|
+
let e1 = self.inferTerm(environment, t1, a1.value)
|
|
860
|
+
self.unification.substitute(t1).{
|
|
861
|
+
| TConstructor(_, name, []) {name == core("Float")} =>
|
|
862
|
+
self.unification.unify(e.at, expected, t1)
|
|
863
|
+
| TConstructor(_, name, []) {name == core("Int")} =>
|
|
864
|
+
self.unification.unify(e.at, expected, t1)
|
|
865
|
+
| _ {self.lspHook.isEnabled()} =>
|
|
866
|
+
| _ =>
|
|
867
|
+
throw(CompileError(e.at, "Operators on unknown types not currently supported"))
|
|
868
|
+
}
|
|
869
|
+
e.ECall(target = target, arguments = [a1.Argument(value = e1)])
|
|
870
|
+
| [a1, a2] {
|
|
871
|
+
operator == "||" || operator == "&&"
|
|
872
|
+
} =>
|
|
873
|
+
let t = TConstructor(e.at, core("Bool"), [])
|
|
874
|
+
let e1 = self.inferTerm(environment, t, a1.value)
|
|
875
|
+
let e2 = self.inferTerm(environment, t, a2.value)
|
|
876
|
+
self.unification.unify(e.at, expected, t)
|
|
877
|
+
e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
|
|
878
|
+
| [a1, a2] {
|
|
879
|
+
operator == "===" || operator == "!==" // For internal use
|
|
880
|
+
} =>
|
|
881
|
+
let t1 = self.unification.freshUnificationVariable(e.at)
|
|
882
|
+
let e1 = self.inferTerm(environment, t1, a1.value)
|
|
883
|
+
let e2 = self.inferTerm(environment, t1, a2.value)
|
|
884
|
+
self.unification.unify(e.at, expected, TConstructor(e.at, core("Bool"), []))
|
|
885
|
+
e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
|
|
886
|
+
| [a1, a2] {
|
|
887
|
+
operator == "+" || operator == "-" ||
|
|
888
|
+
operator == "*" || operator == "/" || operator == "%" ||
|
|
889
|
+
operator == "^"
|
|
890
|
+
} =>
|
|
891
|
+
let t1 = self.unification.freshUnificationVariable(e.at)
|
|
892
|
+
let t2 = self.unification.freshUnificationVariable(e.at)
|
|
893
|
+
let e1 = self.inferTerm(environment, t1, a1.value)
|
|
894
|
+
let e2 = self.inferTerm(environment, t2, a2.value)
|
|
895
|
+
let magic: Type => Option[String] = {t =>
|
|
896
|
+
self.unification.substitute(t).{
|
|
897
|
+
| TConstructor(_, name, []) {name == core("Float")} => Some("Float")
|
|
898
|
+
| TConstructor(_, name, []) {name == core("Int")} => Some("Int")
|
|
899
|
+
| TConstructor(_, name, []) {operator == "+" && name == core("String")} => Some("String")
|
|
900
|
+
| _ => None
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
let chooseType: (Option[String], Option[String]) => Unit = {
|
|
904
|
+
| Some("String"), Some(_) => self.unification.unify(e.at, expected, t1)
|
|
905
|
+
| Some(_), Some("String") => self.unification.unify(e.at, expected, t2)
|
|
906
|
+
| Some("Float"), Some(_) => self.unification.unify(e.at, expected, t1)
|
|
907
|
+
| Some(_), Some("Float") => self.unification.unify(e.at, expected, t2)
|
|
908
|
+
| Some("Int"), Some(_) => self.unification.unify(e.at, expected, t1)
|
|
909
|
+
| Some(_), Some("Int") => self.unification.unify(e.at, expected, t2)
|
|
910
|
+
| Some(_), None =>
|
|
911
|
+
self.unification.unify(e.at, t1, t2)
|
|
912
|
+
self.unification.unify(e.at, expected, t1)
|
|
913
|
+
| None, Some(_) =>
|
|
914
|
+
self.unification.unify(e.at, t2, t1)
|
|
915
|
+
self.unification.unify(e.at, expected, t2)
|
|
916
|
+
| _, _ {self.lspHook.isEnabled()} =>
|
|
917
|
+
| Some(_), Some(_) =>
|
|
918
|
+
throw(CompileError(e.at, "Operators on these types not currently supported"))
|
|
919
|
+
| None, None =>
|
|
920
|
+
throw(CompileError(e.at, "Operators on unknown types not currently supported"))
|
|
921
|
+
}
|
|
922
|
+
chooseType(magic(t1), magic(t2))
|
|
923
|
+
e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
|
|
848
924
|
| _ {self.lspHook.isEnabled()} =>
|
|
925
|
+
term
|
|
849
926
|
| _ =>
|
|
850
|
-
|
|
851
|
-
}
|
|
852
|
-
e.ECall(target = target, arguments = [a1.Argument(value = e1)])
|
|
853
|
-
| [a1, a2] {
|
|
854
|
-
operator == "||" || operator == "&&"
|
|
855
|
-
} =>
|
|
856
|
-
let t = TConstructor(e.at, core("Bool"), [])
|
|
857
|
-
let e1 = self.inferTerm(environment, t, a1.value)
|
|
858
|
-
let e2 = self.inferTerm(environment, t, a2.value)
|
|
859
|
-
self.unification.unify(e.at, expected, t)
|
|
860
|
-
e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
|
|
861
|
-
| [a1, a2] {
|
|
862
|
-
operator == "===" || operator == "!==" // For internal use
|
|
863
|
-
} =>
|
|
864
|
-
let t1 = self.unification.freshUnificationVariable(e.at)
|
|
865
|
-
let e1 = self.inferTerm(environment, t1, a1.value)
|
|
866
|
-
let e2 = self.inferTerm(environment, t1, a2.value)
|
|
867
|
-
self.unification.unify(e.at, expected, TConstructor(e.at, core("Bool"), []))
|
|
868
|
-
e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
|
|
869
|
-
| [a1, a2] {
|
|
870
|
-
operator == "+" || operator == "-" ||
|
|
871
|
-
operator == "*" || operator == "/" || operator == "%" ||
|
|
872
|
-
operator == "^"
|
|
873
|
-
} =>
|
|
874
|
-
let t1 = self.unification.freshUnificationVariable(e.at)
|
|
875
|
-
let t2 = self.unification.freshUnificationVariable(e.at)
|
|
876
|
-
let e1 = self.inferTerm(environment, t1, a1.value)
|
|
877
|
-
let e2 = self.inferTerm(environment, t2, a2.value)
|
|
878
|
-
let magic: Type => Option[String] = {t =>
|
|
879
|
-
self.unification.substitute(t).{
|
|
880
|
-
| TConstructor(_, name, []) {name == core("Float")} => Some("Float")
|
|
881
|
-
| TConstructor(_, name, []) {name == core("Int")} => Some("Int")
|
|
882
|
-
| TConstructor(_, name, []) {operator == "+" && name == core("String")} => Some("String")
|
|
883
|
-
| _ => None
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
let chooseType: (Option[String], Option[String]) => Unit = {
|
|
887
|
-
| Some("String"), Some(_) => self.unification.unify(e.at, expected, t1)
|
|
888
|
-
| Some(_), Some("String") => self.unification.unify(e.at, expected, t2)
|
|
889
|
-
| Some("Float"), Some(_) => self.unification.unify(e.at, expected, t1)
|
|
890
|
-
| Some(_), Some("Float") => self.unification.unify(e.at, expected, t2)
|
|
891
|
-
| Some("Int"), Some(_) => self.unification.unify(e.at, expected, t1)
|
|
892
|
-
| Some(_), Some("Int") => self.unification.unify(e.at, expected, t2)
|
|
893
|
-
| Some(_), None =>
|
|
894
|
-
self.unification.unify(e.at, t1, t2)
|
|
895
|
-
self.unification.unify(e.at, expected, t1)
|
|
896
|
-
| None, Some(_) =>
|
|
897
|
-
self.unification.unify(e.at, t2, t1)
|
|
898
|
-
self.unification.unify(e.at, expected, t2)
|
|
899
|
-
| _, _ {self.lspHook.isEnabled()} =>
|
|
900
|
-
| Some(_), Some(_) =>
|
|
901
|
-
throw(CompileError(e.at, "Operators on these types not currently supported"))
|
|
902
|
-
| None, None =>
|
|
903
|
-
throw(CompileError(e.at, "Operators on unknown types not currently supported"))
|
|
927
|
+
fail(e.at, "Unknown operator: " + operator)
|
|
904
928
|
}
|
|
905
|
-
|
|
906
|
-
e.ECall(target = target, arguments = [a1.Argument(value = e1), a2.Argument(value = e2)])
|
|
907
|
-
| _ {self.lspHook.isEnabled()} =>
|
|
908
|
-
term
|
|
909
|
-
| _ =>
|
|
910
|
-
fail(e.at, "Unknown operator: " + operator)
|
|
929
|
+
| _ => fail(term.at, "Call expected")
|
|
911
930
|
}
|
|
912
931
|
}
|
|
913
932
|
|