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.
Files changed (72) hide show
  1. package/compiler/Builder.ff +23 -13
  2. package/compiler/Dictionaries.ff +10 -10
  3. package/compiler/Inference.ff +167 -148
  4. package/compiler/JsEmitter.ff +122 -78
  5. package/compiler/LspHook.ff +6 -3
  6. package/compiler/Main.ff +24 -10
  7. package/compiler/Patterns.ff +1 -1
  8. package/compiler/Resolver.ff +167 -159
  9. package/compiler/Substitution.ff +2 -2
  10. package/compiler/Syntax.ff +1 -0
  11. package/compiler/Unification.ff +1 -1
  12. package/core/Array.ff +6 -4
  13. package/core/Int.ff +12 -12
  14. package/core/List.ff +6 -4
  15. package/core/Map.ff +8 -0
  16. package/core/Set.ff +7 -0
  17. package/experimental/benchmarks/ListGrab.ff +23 -0
  18. package/experimental/benchmarks/ListGrab.java +55 -0
  19. package/experimental/benchmarks/Pyrotek45.ff +30 -0
  20. package/experimental/benchmarks/Pyrotek45.java +64 -0
  21. package/experimental/tests/TestJson.ff +26 -0
  22. package/lsp/Handler.ff +65 -61
  23. package/lsp/SignatureHelpHandler.ff +5 -4
  24. package/lsp/TestReferences.ff +15 -0
  25. package/lsp/TestReferencesCase.ff +8 -0
  26. package/output/js/ff/compiler/Builder.mjs +50 -44
  27. package/output/js/ff/compiler/Dependencies.mjs +0 -2
  28. package/output/js/ff/compiler/Deriver.mjs +16 -140
  29. package/output/js/ff/compiler/Dictionaries.mjs +24 -238
  30. package/output/js/ff/compiler/Environment.mjs +12 -154
  31. package/output/js/ff/compiler/Inference.mjs +207 -1069
  32. package/output/js/ff/compiler/JsEmitter.mjs +434 -2342
  33. package/output/js/ff/compiler/JsImporter.mjs +0 -12
  34. package/output/js/ff/compiler/LspHook.mjs +20 -446
  35. package/output/js/ff/compiler/Main.mjs +110 -553
  36. package/output/js/ff/compiler/Parser.mjs +36 -356
  37. package/output/js/ff/compiler/Patterns.mjs +24 -204
  38. package/output/js/ff/compiler/Resolver.mjs +428 -554
  39. package/output/js/ff/compiler/Substitution.mjs +6 -164
  40. package/output/js/ff/compiler/Syntax.mjs +449 -3293
  41. package/output/js/ff/compiler/Token.mjs +9 -1095
  42. package/output/js/ff/compiler/Tokenizer.mjs +4 -2
  43. package/output/js/ff/compiler/Unification.mjs +30 -364
  44. package/output/js/ff/compiler/Wildcards.mjs +0 -86
  45. package/output/js/ff/compiler/Workspace.mjs +8 -96
  46. package/output/js/ff/core/Array.mjs +15 -8
  47. package/output/js/ff/core/AssetSystem.mjs +4 -14
  48. package/output/js/ff/core/Bool.mjs +0 -12
  49. package/output/js/ff/core/Core.mjs +0 -30
  50. package/output/js/ff/core/Int.mjs +24 -24
  51. package/output/js/ff/core/IntMap.mjs +0 -8
  52. package/output/js/ff/core/Json.mjs +0 -40
  53. package/output/js/ff/core/List.mjs +23 -32
  54. package/output/js/ff/core/Lock.mjs +0 -10
  55. package/output/js/ff/core/Map.mjs +26 -24
  56. package/output/js/ff/core/Option.mjs +10 -286
  57. package/output/js/ff/core/Ordering.mjs +16 -158
  58. package/output/js/ff/core/Pair.mjs +2 -34
  59. package/output/js/ff/core/Path.mjs +2 -28
  60. package/output/js/ff/core/Random.mjs +4 -4
  61. package/output/js/ff/core/RbMap.mjs +56 -644
  62. package/output/js/ff/core/Set.mjs +16 -0
  63. package/output/js/ff/core/Show.mjs +0 -16
  64. package/output/js/ff/core/Stream.mjs +14 -144
  65. package/output/js/ff/core/StringMap.mjs +0 -8
  66. package/output/js/ff/core/Try.mjs +4 -108
  67. package/output/js/ff/core/Unit.mjs +2 -16
  68. package/package.json +1 -1
  69. package/postgresql/Pg.ff +23 -23
  70. package/vscode/package.json +1 -1
  71. package/bin/firefly.mjs +0 -2
  72. package/guide/Main.ff +0 -22
@@ -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(
@@ -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 { unification.instantiate(instantiationMap, _) }
172
- let firstType = newGenerics.grabFirst().{
173
- | TConstructor t => t
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
  }
@@ -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 recordType =
302
- TConstructor(at, "Record$" + parameters.map {_.name}.join("$"), parameters.map {_.valueType})
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
- let e = term.{| ECall e => e | _ => fail(term.at, "Call expected")}
751
- let call = e.target.{
752
- | DynamicCall call => call
753
- | StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferMethodCall")
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
- let e = term.{| ECall e => e | _ => fail(term.at, "Call expected")}
779
- let call = e.target.{
780
- | DynamicCall call => call
781
- | StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferFunctionCall")
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
- let e = term.{| ECall e => e | _ => fail(term.at, "Call expected")}
796
- let call = e.target.{
797
- | DynamicCall call {!call.tailCall} => call
798
- | DynamicCall _ => throw(CompileError(e.at, "Tailcalls not supported on lambda functions"))
799
- | StaticCall _ => fail(e.at, "Internal error: Static calls not expected in inferLambdaCall")
800
- }
801
- let effect = self.unification.freshUnificationVariable(term.at)
802
- let argumentTypes = e.arguments.map {self.unification.freshUnificationVariable(_.at)}
803
- let functionType = TConstructor(e.at, "Function$" + e.arguments.size(), [
804
- effect
805
- ...argumentTypes
806
- expected
807
- ])
808
- let function = self.inferTerm(environment, functionType, call.function)
809
- let arguments = e.arguments.zip(argumentTypes).map {| Pair(argument, t) =>
810
- argument.name.each {name =>
811
- throw(CompileError(argument.at, "Named argument not allowed here: " + name))
812
- }
813
- argument.Argument(value = self.inferTerm(environment, t, argument.value))
814
- }
815
- e.typeArguments.first().each {typeArgument =>
816
- throw(CompileError(typeArgument.at, "Type arguments not allowed here"))
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
- let e = term.{| ECall e => e | _ => fail(term.at, "Call expected") }
829
- let target = StaticCall(operator, instanceCall = False, tailCall = False)
830
- e.arguments.{
831
- | [a1] {
832
- operator == "!"
833
- } =>
834
- let t = TConstructor(e.at, core("Bool"), [])
835
- let e1 = self.inferTerm(environment, t, a1.value)
836
- self.unification.unify(e.at, expected, t)
837
- e.ECall(target = target, arguments = [a1.Argument(value = e1)])
838
- | [a1] {
839
- operator == "-"
840
- } =>
841
- let t1 = self.unification.freshUnificationVariable(e.at)
842
- let e1 = self.inferTerm(environment, t1, a1.value)
843
- self.unification.substitute(t1).{
844
- | TConstructor(_, name, []) {name == core("Float")} =>
845
- self.unification.unify(e.at, expected, t1)
846
- | TConstructor(_, name, []) {name == core("Int")} =>
847
- self.unification.unify(e.at, expected, t1)
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
- throw(CompileError(e.at, "Operators on unknown types not currently supported"))
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
- chooseType(magic(t1), magic(t2))
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