firefly-compiler 0.4.4

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 (221) hide show
  1. package/.firefly-workspace +1 -0
  2. package/.vscode/settings.json +5 -0
  3. package/LICENSE.txt +21 -0
  4. package/README.md +96 -0
  5. package/bin/firefly.mjs +2 -0
  6. package/compiler/.firefly/package.ff +1 -0
  7. package/compiler/Builder.ff +218 -0
  8. package/compiler/Compiler.ff +241 -0
  9. package/compiler/Dependencies.ff +179 -0
  10. package/compiler/Deriver.ff +647 -0
  11. package/compiler/Dictionaries.ff +205 -0
  12. package/compiler/Environment.ff +166 -0
  13. package/compiler/Inference.ff +1117 -0
  14. package/compiler/JsEmitter.ff +861 -0
  15. package/compiler/JsImporter.ff +56 -0
  16. package/compiler/LspHook.ff +188 -0
  17. package/compiler/Main.ff +237 -0
  18. package/compiler/Parser.ff +1383 -0
  19. package/compiler/Patterns.ff +111 -0
  20. package/compiler/Resolver.ff +620 -0
  21. package/compiler/Substitution.ff +178 -0
  22. package/compiler/Syntax.ff +299 -0
  23. package/compiler/Token.ff +180 -0
  24. package/compiler/Tokenizer.ff +278 -0
  25. package/compiler/Unification.ff +220 -0
  26. package/compiler/Wildcards.ff +50 -0
  27. package/compiler/Workspace.ff +88 -0
  28. package/core/.firefly/package.ff +2 -0
  29. package/core/Any.ff +30 -0
  30. package/core/Array.ff +249 -0
  31. package/core/AssetSystem.ff +61 -0
  32. package/core/Atomic.ff +64 -0
  33. package/core/Bool.ff +13 -0
  34. package/core/BrowserSystem.ff +14 -0
  35. package/core/Buffer.ff +211 -0
  36. package/core/BuildSystem.ff +144 -0
  37. package/core/Channel.ff +131 -0
  38. package/core/Char.ff +18 -0
  39. package/core/Core.ff +58 -0
  40. package/core/Duration.ff +15 -0
  41. package/core/Equal.ff +52 -0
  42. package/core/Error.ff +20 -0
  43. package/core/FileHandle.ff +41 -0
  44. package/core/Float.ff +41 -0
  45. package/core/HttpClient.ff +84 -0
  46. package/core/Instant.ff +9 -0
  47. package/core/Int.ff +61 -0
  48. package/core/IntMap.ff +85 -0
  49. package/core/JsSystem.ff +66 -0
  50. package/core/JsValue.ff +240 -0
  51. package/core/List.ff +440 -0
  52. package/core/Lock.ff +144 -0
  53. package/core/Log.ff +24 -0
  54. package/core/Map.ff +126 -0
  55. package/core/NodeSystem.ff +88 -0
  56. package/core/Nothing.ff +1 -0
  57. package/core/Option.ff +133 -0
  58. package/core/Ordering.ff +157 -0
  59. package/core/Pair.ff +55 -0
  60. package/core/Path.ff +393 -0
  61. package/core/RbMap.ff +216 -0
  62. package/core/Serializable.ff +173 -0
  63. package/core/Set.ff +38 -0
  64. package/core/Show.ff +43 -0
  65. package/core/Stack.ff +263 -0
  66. package/core/Stream.ff +406 -0
  67. package/core/String.ff +175 -0
  68. package/core/StringMap.ff +85 -0
  69. package/core/Task.ff +138 -0
  70. package/core/Try.ff +81 -0
  71. package/core/Unit.ff +3 -0
  72. package/experimental/random/AltGeneric.ff +44 -0
  73. package/experimental/random/Async.ff +68 -0
  74. package/experimental/random/Buffer2.ff +77 -0
  75. package/experimental/random/Cat.ff +12 -0
  76. package/experimental/random/Dictionary.ff +52 -0
  77. package/experimental/random/Example.ff +46 -0
  78. package/experimental/random/Generic.ff +102 -0
  79. package/experimental/random/HappyEyeballs.ff +40 -0
  80. package/experimental/random/HashMap.ff +72 -0
  81. package/experimental/random/IfElseUnit.ff +9 -0
  82. package/experimental/random/InputOutput.ff +23 -0
  83. package/experimental/random/ListVsArray.ff +45 -0
  84. package/experimental/random/Main.ff +44 -0
  85. package/experimental/random/MapTest.ff +67 -0
  86. package/experimental/random/OldTaskSystem.ff +210 -0
  87. package/experimental/random/PatternTest.ff +39 -0
  88. package/experimental/random/Patterns.ff +226 -0
  89. package/experimental/random/ReadBytesTest.ff +10 -0
  90. package/experimental/random/RunLength.ff +65 -0
  91. package/experimental/random/Scrape.ff +51 -0
  92. package/experimental/random/Serialization.ff +217 -0
  93. package/experimental/random/SerializationTest.ff +46 -0
  94. package/experimental/random/Serializer.ff +36 -0
  95. package/experimental/random/StdInOutErr.ff +4 -0
  96. package/experimental/random/Symbols.ff +74 -0
  97. package/experimental/random/Tag.ff +49 -0
  98. package/experimental/random/Tensor.ff +52 -0
  99. package/experimental/random/Try.ff +56 -0
  100. package/experimental/random/Tsv.ff +9 -0
  101. package/experimental/random/TypesAreModules.ff +87 -0
  102. package/experimental/random/blueprints/Blueprint.ff +52 -0
  103. package/experimental/random/blueprints/Main.ff +11 -0
  104. package/experimental/random/blueprints/Pretty.ff +58 -0
  105. package/experimental/random/blueprints/User.ff +64 -0
  106. package/experimental/random/blueprintsystem/BlueprintSystem.ff +48 -0
  107. package/experimental/random/blueprintsystem/Deserialize.ff +53 -0
  108. package/experimental/random/blueprintsystem/ReadJs.ff +13 -0
  109. package/experimental/random/blueprintsystem/User.ff +2 -0
  110. package/experimental/random/kahrs/Kahrs.ff +112 -0
  111. package/experimental/random/kahrs/TestKahrs.ff +22 -0
  112. package/experimental/random/kahrs/TestMap.ff +18 -0
  113. package/experimental/random/streaming/Gzip.ff +3 -0
  114. package/experimental/random/streaming/Main.ff +34 -0
  115. package/experimental/random/streaming/S3Bucket.ff +11 -0
  116. package/experimental/random/streaming/Tar.ff +5 -0
  117. package/experimental/rhymeapp/Main.ff +81 -0
  118. package/experimental/rhymeapp/index.html +14 -0
  119. package/firefly.sh +5 -0
  120. package/fireflysite/Main.ff +13 -0
  121. package/httpserver/.firefly/package.ff +1 -0
  122. package/httpserver/HttpServer.ff +184 -0
  123. package/lsp/.firefly/package.ff +1 -0
  124. package/lsp/CompletionHandler.ff +814 -0
  125. package/lsp/Handler.ff +551 -0
  126. package/lsp/HoverHandler.ff +82 -0
  127. package/lsp/LanguageServer.ff +229 -0
  128. package/lsp/SignatureHelpHandler.ff +55 -0
  129. package/lsp/SymbolHandler.ff +167 -0
  130. package/output/js/ff/compiler/Builder.mjs +483 -0
  131. package/output/js/ff/compiler/Compiler.mjs +410 -0
  132. package/output/js/ff/compiler/Dependencies.mjs +388 -0
  133. package/output/js/ff/compiler/Deriver.mjs +1166 -0
  134. package/output/js/ff/compiler/Dictionaries.mjs +1305 -0
  135. package/output/js/ff/compiler/Environment.mjs +1005 -0
  136. package/output/js/ff/compiler/Inference.mjs +4264 -0
  137. package/output/js/ff/compiler/JsEmitter.mjs +5353 -0
  138. package/output/js/ff/compiler/JsImporter.mjs +262 -0
  139. package/output/js/ff/compiler/LspHook.mjs +789 -0
  140. package/output/js/ff/compiler/Main.mjs +1695 -0
  141. package/output/js/ff/compiler/Parser.mjs +4004 -0
  142. package/output/js/ff/compiler/Patterns.mjs +923 -0
  143. package/output/js/ff/compiler/Resolver.mjs +2303 -0
  144. package/output/js/ff/compiler/Substitution.mjs +1146 -0
  145. package/output/js/ff/compiler/Syntax.mjs +12430 -0
  146. package/output/js/ff/compiler/Token.mjs +3092 -0
  147. package/output/js/ff/compiler/Tokenizer.mjs +589 -0
  148. package/output/js/ff/compiler/Unification.mjs +1748 -0
  149. package/output/js/ff/compiler/Wildcards.mjs +604 -0
  150. package/output/js/ff/compiler/Workspace.mjs +683 -0
  151. package/output/js/ff/core/Any.mjs +139 -0
  152. package/output/js/ff/core/Array.mjs +594 -0
  153. package/output/js/ff/core/AssetSystem.mjs +270 -0
  154. package/output/js/ff/core/Atomic.mjs +186 -0
  155. package/output/js/ff/core/Bool.mjs +141 -0
  156. package/output/js/ff/core/BrowserSystem.mjs +122 -0
  157. package/output/js/ff/core/Buffer.mjs +467 -0
  158. package/output/js/ff/core/BuildSystem.mjs +320 -0
  159. package/output/js/ff/core/Channel.mjs +268 -0
  160. package/output/js/ff/core/Char.mjs +145 -0
  161. package/output/js/ff/core/Core.mjs +300 -0
  162. package/output/js/ff/core/Duration.mjs +112 -0
  163. package/output/js/ff/core/Equal.mjs +175 -0
  164. package/output/js/ff/core/Error.mjs +138 -0
  165. package/output/js/ff/core/FileHandle.mjs +164 -0
  166. package/output/js/ff/core/Float.mjs +214 -0
  167. package/output/js/ff/core/HttpClient.mjs +210 -0
  168. package/output/js/ff/core/Instant.mjs +105 -0
  169. package/output/js/ff/core/Int.mjs +254 -0
  170. package/output/js/ff/core/IntMap.mjs +282 -0
  171. package/output/js/ff/core/JsSystem.mjs +234 -0
  172. package/output/js/ff/core/JsValue.mjs +678 -0
  173. package/output/js/ff/core/List.mjs +2335 -0
  174. package/output/js/ff/core/Lock.mjs +322 -0
  175. package/output/js/ff/core/Log.mjs +159 -0
  176. package/output/js/ff/core/Map.mjs +358 -0
  177. package/output/js/ff/core/NodeSystem.mjs +288 -0
  178. package/output/js/ff/core/Nothing.mjs +100 -0
  179. package/output/js/ff/core/Option.mjs +1002 -0
  180. package/output/js/ff/core/Ordering.mjs +734 -0
  181. package/output/js/ff/core/Pair.mjs +318 -0
  182. package/output/js/ff/core/Path.mjs +768 -0
  183. package/output/js/ff/core/RbMap.mjs +1936 -0
  184. package/output/js/ff/core/Serializable.mjs +434 -0
  185. package/output/js/ff/core/Set.mjs +250 -0
  186. package/output/js/ff/core/Show.mjs +201 -0
  187. package/output/js/ff/core/Stack.mjs +595 -0
  188. package/output/js/ff/core/Stream.mjs +1300 -0
  189. package/output/js/ff/core/String.mjs +433 -0
  190. package/output/js/ff/core/StringMap.mjs +282 -0
  191. package/output/js/ff/core/Task.mjs +345 -0
  192. package/output/js/ff/core/Try.mjs +503 -0
  193. package/output/js/ff/core/Unit.mjs +103 -0
  194. package/package.json +29 -0
  195. package/postgresql/.firefly/include/package-lock.json +250 -0
  196. package/postgresql/.firefly/include/package.json +5 -0
  197. package/postgresql/.firefly/include/prepare.sh +2 -0
  198. package/postgresql/.firefly/package.ff +3 -0
  199. package/postgresql/Pg.ff +530 -0
  200. package/unsafejs/.firefly/package.ff +1 -0
  201. package/unsafejs/UnsafeJs.ff +19 -0
  202. package/vscode/.vscode/launch.json +18 -0
  203. package/vscode/.vscode/tasks.json +33 -0
  204. package/vscode/LICENSE.txt +21 -0
  205. package/vscode/Prepublish.ff +15 -0
  206. package/vscode/README.md +17 -0
  207. package/vscode/client/package-lock.json +544 -0
  208. package/vscode/client/package.json +22 -0
  209. package/vscode/client/src/extension.ts +64 -0
  210. package/vscode/client/tsconfig.json +12 -0
  211. package/vscode/icons/firefly-icon.png +0 -0
  212. package/vscode/icons/firefly-icon.svg +10 -0
  213. package/vscode/icons/firefly-logo-notext.png +0 -0
  214. package/vscode/icons/firefly-logo.png +0 -0
  215. package/vscode/language-configuration.json +39 -0
  216. package/vscode/package-lock.json +3623 -0
  217. package/vscode/package.json +144 -0
  218. package/vscode/snippets-none.json +1 -0
  219. package/vscode/snippets.json +241 -0
  220. package/vscode/syntaxes/firefly.tmLanguage.json +294 -0
  221. package/vscode/tsconfig.json +20 -0
@@ -0,0 +1,647 @@
1
+ import Syntax
2
+
3
+ data Deriver()
4
+
5
+ make(): Deriver {
6
+ Deriver()
7
+ }
8
+
9
+ fail[T](at: Location, message: String): T {
10
+ panic(message + " " + at.show())
11
+ }
12
+
13
+ extend self: Deriver {
14
+
15
+ deriveModule(module: Module): Module {
16
+
17
+ let modulePrefix = module.packagePair.groupName() + "/" + module.file.dropLast(3)
18
+
19
+ module.Module(
20
+ instances = [
21
+ ...module.instances
22
+ ...self.makeHasAnyTagInstances(modulePrefix, module)
23
+ ...self.makeShowInstances(modulePrefix, module)
24
+ ...self.makeEqualInstances(modulePrefix, module)
25
+ ...self.makeOrderingInstances(modulePrefix, module)
26
+ ...self.makeSerializableInstances(modulePrefix, module)
27
+ ]
28
+ )
29
+ }
30
+
31
+ // HasAnyTag
32
+ makeHasAnyTagInstances(modulePrefix: String, module: Module): List[DInstance] {
33
+ let coreWhitelist = [
34
+ "ff:core/Serializable.DeserializationChecksumException"
35
+ "ff:core/Core.GrabException"
36
+ ].toSet() // Maybe whitelist all?
37
+ let missingInstance =
38
+ self.findTypesThatNeedInstances("ff:core/Any.HasAnyTag", modulePrefix, coreWhitelist, True, module)
39
+ missingInstance.map {self.makeHasAnyTagInstance(modulePrefix, _)}
40
+ }
41
+
42
+ makeHasAnyTagInstance(modulePrefix: String, declaration: DType): DInstance {
43
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
44
+ let constraints = declaration.generics.map {t =>
45
+ Constraint(at, "ff:core/Any.HasAnyTag", [TConstructor(at, t, [])])
46
+ }
47
+ let typeArguments = declaration.generics.map {t =>
48
+ TConstructor(at, t, [])
49
+ }
50
+ let selfTypeName = modulePrefix + "." + declaration.name
51
+ let selfType = TConstructor(at, selfTypeName, typeArguments)
52
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
53
+ let signature = Signature(
54
+ at = at
55
+ name = "anyTag"
56
+ member = False
57
+ generics = []
58
+ constraints = []
59
+ parameters = []
60
+ returnType = TConstructor(at, "ff:core/Any.AnyTag", [selfType])
61
+ effect = noEffect
62
+ )
63
+ let typeArgumentStrings = typeArguments.map {
64
+ self.makeMethodCall(at, self.makeSimpleCall(at, "ff:core/Any.anyTag", [], [_]), "show", [])
65
+ }
66
+ let strings =
67
+ [EString(at, "\"[\""), ...typeArgumentStrings.insertBetween([EString(at, "\",\"")]), EString(at, "\"]\"")]
68
+ let body = FireflyTarget(
69
+ Lambda(at, noEffect, [MatchCase(
70
+ at = at,
71
+ patterns = []
72
+ guards = []
73
+ body = self.makeSimpleCall(at, "ff:core/Any.internalAnyTag", [
74
+ strings.foldLeft(EString(at, "\"" + selfTypeName + "\"")) {a, b =>
75
+ self.makeSimpleCall(at, "+", [a, b])
76
+ }
77
+ ])
78
+ )])
79
+ )
80
+ let method = DFunction(at, signature, body)
81
+ DInstance(
82
+ at = at
83
+ generics = declaration.generics
84
+ constraints = constraints
85
+ traitName = "ff:core/Any.HasAnyTag"
86
+ typeArguments = [selfType]
87
+ generatorArguments = []
88
+ methods = [method]
89
+ derived = True
90
+ )
91
+ }
92
+
93
+ // Show
94
+ makeShowInstances(modulePrefix: String, module: Module): List[DInstance] {
95
+ let coreWhitelist = [
96
+ "ff:core/Option.Option"
97
+ ].toSet()
98
+ let missingInstance =
99
+ self.findTypesThatNeedInstances("ff:core/Show.Show", modulePrefix, coreWhitelist, True, module)
100
+ missingInstance.map {self.makeShowInstance(modulePrefix, _)}
101
+ }
102
+
103
+ makeShowInstance(modulePrefix: String, declaration: DType): DInstance {
104
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
105
+ let constraints = declaration.generics.map {t =>
106
+ Constraint(at, "ff:core/Show.Show", [TConstructor(at, t, [])])
107
+ }
108
+ let typeArguments = declaration.generics.map {t =>
109
+ TConstructor(at, t, [])
110
+ }
111
+ let selfType = TConstructor(at, modulePrefix + "." + declaration.name, typeArguments)
112
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
113
+ let signature = Signature(
114
+ at = at
115
+ name = "show"
116
+ member = False
117
+ generics = []
118
+ constraints = []
119
+ parameters = [Parameter(at, False, "value", selfType, None)]
120
+ returnType = TConstructor(at, "ff:core/String.String", [])
121
+ effect = noEffect
122
+ )
123
+ let body = FireflyTarget(
124
+ Lambda(at, noEffect, self.makeShowCases(modulePrefix, declaration, selfType))
125
+ )
126
+ let showMethod = DFunction(at, signature, body)
127
+ DInstance(
128
+ at = at
129
+ generics = declaration.generics
130
+ constraints = constraints
131
+ traitName = "ff:core/Show.Show"
132
+ typeArguments = [selfType]
133
+ generatorArguments = []
134
+ methods = [showMethod]
135
+ derived = True
136
+ )
137
+ }
138
+
139
+ makeShowCases(modulePrefix: String, declaration: DType, selfType: Type): List[MatchCase] {
140
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
141
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
142
+ let wildcardPattern = PVariable(at, None)
143
+ declaration.variants.{
144
+ | variants =>
145
+ variants.map {variant =>
146
+ let variantName = modulePrefix + "." + variant.name
147
+ let fields = [...declaration.commonFields, ...variant.fields]
148
+ let strings = if(fields.size() == 0) {[]} else {[
149
+ EString(at, "\"(\"")
150
+ ...fields.map {field =>
151
+ self.makeSimpleCall(at, "ff:core/Show.show", [
152
+ EField(at, False, EVariable(at, "z"), field.name)
153
+ ])
154
+ }.insertBetween([EString(at, "\", \"")])
155
+ EString(at, "\")\"")
156
+ ]}
157
+ MatchCase(
158
+ at = at
159
+ patterns = [PVariantAs(at, variantName, at, Some("z"))]
160
+ guards = []
161
+ body = strings.foldLeft(EString(at, "\"" + variant.name + "\"")) {a, b =>
162
+ self.makeSimpleCall(at, "+", [a, b])
163
+ }
164
+ )
165
+ }
166
+ }
167
+ }
168
+
169
+ // Ordering
170
+ makeOrderingInstances(modulePrefix: String, module: Module): List[DInstance] {
171
+ let coreWhitelist = [
172
+ "ff:core/Option.Option"
173
+ ].toSet()
174
+ let missingInstance =
175
+ self.findTypesThatNeedInstances("ff:core/Ordering.Order", modulePrefix, coreWhitelist, True, module)
176
+ missingInstance.map {self.makeOrderingInstance(modulePrefix, _)}
177
+ }
178
+
179
+ makeOrderingInstance(modulePrefix: String, declaration: DType): DInstance {
180
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
181
+ let constraints = declaration.generics.map {t =>
182
+ Constraint(at, "ff:core/Ordering.Order", [TConstructor(at, t, [])])
183
+ }
184
+ let typeArguments = declaration.generics.map {t =>
185
+ TConstructor(at, t, [])
186
+ }
187
+ let selfType = TConstructor(at, modulePrefix + "." + declaration.name, typeArguments)
188
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
189
+ let signature = Signature(
190
+ at = at
191
+ name = "compare"
192
+ member = False
193
+ generics = []
194
+ constraints = []
195
+ parameters = [
196
+ Parameter(at, False, "x", selfType, None)
197
+ Parameter(at, False, "y", selfType, None)
198
+ ]
199
+ returnType = TConstructor(at, "ff:core/Ordering.Ordering", [])
200
+ effect = noEffect
201
+ )
202
+ let body = FireflyTarget(
203
+ Lambda(at, noEffect, self.makeOrderingCases(modulePrefix, declaration, selfType))
204
+ )
205
+ let compareMethod = DFunction(at, signature, body)
206
+ DInstance(
207
+ at = at
208
+ generics = declaration.generics
209
+ constraints = constraints
210
+ traitName = "ff:core/Ordering.Order"
211
+ typeArguments = [selfType]
212
+ generatorArguments = []
213
+ methods = [compareMethod]
214
+ derived = True
215
+ )
216
+ }
217
+
218
+ makeOrderingCases(modulePrefix: String, declaration: DType, selfType: Type): List[MatchCase] {
219
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
220
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
221
+ let wildcardPattern = PVariable(at, None)
222
+ let sameCase = MatchCase(
223
+ at = at,
224
+ patterns = [wildcardPattern, wildcardPattern]
225
+ guards = [MatchGuard(
226
+ at,
227
+ self.makeSimpleCall(at, "===", [EVariable(at, "x"), EVariable(at, "y")]),
228
+ PVariant(at, "ff:core/Bool.True", [])
229
+ )]
230
+ body = EVariant(at, "ff:core/Ordering.OrderingSame", [], None)
231
+ )
232
+ declaration.variants.{
233
+ | [variant] =>
234
+ let fields = [...declaration.commonFields, ...variant.fields]
235
+ [sameCase, MatchCase(
236
+ at = at
237
+ patterns = [wildcardPattern, wildcardPattern]
238
+ guards = []
239
+ body = self.makeOrderingFields(modulePrefix, declaration, fields)
240
+ )]
241
+ | variants =>
242
+ let variantsWithFields = variants.filter {variant =>
243
+ !declaration.commonFields.isEmpty() || !variant.fields.isEmpty()
244
+ } // We can skip no-arg constructors assuming there are never more than one instance of them
245
+ let sameVariantCases = variantsWithFields.map { variant =>
246
+ let variantName = modulePrefix + "." + variant.name
247
+ let fields = [...declaration.commonFields, ...variant.fields]
248
+ MatchCase(
249
+ at = at,
250
+ patterns = [PVariantAs(at, variantName, at, Some("x")), PVariantAs(at, variantName, at, Some("y"))]
251
+ guards = []
252
+ body = self.makeOrderingFields(modulePrefix, declaration, fields)
253
+ )
254
+ }
255
+ let intType = TConstructor(at, "ff:core/Int.Int", [])
256
+ let numberSignature =
257
+ Signature(at, "number", False, [], [], [Parameter(at, False, "z", selfType, None)], intType, noEffect)
258
+ let numberCases = declaration.variants.pairs().map {| Pair(index, variant) =>
259
+ let variantName = modulePrefix + "." + variant.name
260
+ MatchCase(
261
+ at = at
262
+ patterns = [PVariantAs(at, variantName, at, None)]
263
+ guards = []
264
+ body = EInt(at, "" + index)
265
+ )
266
+ }
267
+ let differentVariant = MatchCase(
268
+ at = at,
269
+ patterns = [wildcardPattern, wildcardPattern]
270
+ guards = []
271
+ body =
272
+ EFunctions(at,
273
+ [DFunction(at, numberSignature, FireflyTarget(Lambda(at, noEffect, numberCases)))],
274
+ self.makeSimpleCall(at, "ff:core/Ordering.compare", [
275
+ self.makeSimpleCall(at, "number", [EVariable(at, "x")])
276
+ self.makeSimpleCall(at, "number", [EVariable(at, "y")])
277
+ ])
278
+ )
279
+ )
280
+ [sameCase, ...sameVariantCases, differentVariant]
281
+ }
282
+ }
283
+
284
+ makeOrderingFields(modulePrefix: String, declaration: DType, fields: List[Parameter]): Term {
285
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
286
+ let orderingType = TConstructor(at, "ff:core/Ordering.Ordering", [])
287
+ let orderingSame = EVariant(at, "ff:core/Ordering.OrderingSame", [], None)
288
+ function go(fields: List[Parameter]): Term {
289
+ | [] =>
290
+ orderingSame
291
+ | [head, ...tail] =>
292
+ let variableName = head.name + "Ordering"
293
+ let compareTerm = self.makeSimpleCall(at, "ff:core/Ordering.compare", [
294
+ EField(at, False, EVariable(at, "x"), head.name)
295
+ EField(at, False, EVariable(at, "y"), head.name)
296
+ ])
297
+ let notEqualTerm = self.makeSimpleCall(at, "!==", [
298
+ EVariable(at, variableName)
299
+ orderingSame
300
+ ])
301
+ let ifTerm = self.makeIf(at, notEqualTerm, EVariable(at, variableName), go(tail))
302
+ ELet(at, False, variableName, orderingType, compareTerm, ifTerm)
303
+ }
304
+ go(fields)
305
+ }
306
+
307
+ // Equal
308
+ makeEqualInstances(modulePrefix: String, module: Module): List[DInstance] {
309
+ let coreWhitelist = [
310
+ "ff:core/Option.Option"
311
+ "ff:core/List.List"
312
+ "ff:core/Pair.Pair"
313
+ ].toSet()
314
+ let missingInstance =
315
+ self.findTypesThatNeedInstances("ff:core/Equal.Equal", modulePrefix, coreWhitelist, True, module)
316
+ missingInstance.map {self.makeEqualInstance(modulePrefix, _)}
317
+ }
318
+
319
+ makeEqualInstance(modulePrefix: String, declaration: DType): DInstance {
320
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
321
+ let constraints = declaration.generics.map {t =>
322
+ Constraint(at, "ff:core/Equal.Equal", [TConstructor(at, t, [])])
323
+ }
324
+ let typeArguments = declaration.generics.map {t =>
325
+ TConstructor(at, t, [])
326
+ }
327
+ let selfType = TConstructor(at, modulePrefix + "." + declaration.name, typeArguments)
328
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
329
+ let signature = Signature(
330
+ at = at
331
+ name = "equals"
332
+ member = False
333
+ generics = []
334
+ constraints = []
335
+ parameters = [
336
+ Parameter(at, False, "x", selfType, None)
337
+ Parameter(at, False, "y", selfType, None)
338
+ ]
339
+ returnType = TConstructor(at, "ff:core/Bool.Bool", [])
340
+ effect = noEffect
341
+ )
342
+ let body = FireflyTarget(
343
+ Lambda(at, noEffect, self.makeEqualsCases(modulePrefix, declaration, selfType))
344
+ )
345
+ let equalsMethod = DFunction(at, signature, body)
346
+ DInstance(
347
+ at = at
348
+ generics = declaration.generics
349
+ constraints = constraints
350
+ traitName = "ff:core/Equal.Equal"
351
+ typeArguments = [selfType]
352
+ generatorArguments = []
353
+ methods = [equalsMethod]
354
+ derived = True
355
+ )
356
+ }
357
+
358
+ makeEqualsCases(modulePrefix: String, declaration: DType, selfType: Type): List[MatchCase] {
359
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
360
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
361
+ let wildcardPattern = PVariable(at, None)
362
+ let sameCase = MatchCase(
363
+ at = at
364
+ patterns = [wildcardPattern, wildcardPattern]
365
+ guards = [MatchGuard(
366
+ at
367
+ self.makeSimpleCall(at, "===", [EVariable(at, "x"), EVariable(at, "y")])
368
+ PVariant(at, "ff:core/Bool.True", [])
369
+ )]
370
+ body = EVariant(at, "ff:core/Bool.True", [], None)
371
+ )
372
+ declaration.variants.{
373
+ | [variant] =>
374
+ let fields = [...declaration.commonFields, ...variant.fields]
375
+ [sameCase, MatchCase(
376
+ at = at
377
+ patterns = [wildcardPattern, wildcardPattern]
378
+ guards = []
379
+ body = self.makeEqualFields(modulePrefix, declaration, fields)
380
+ )]
381
+ | variants =>
382
+ let variantsWithFields = variants.filter {variant =>
383
+ !declaration.commonFields.isEmpty() || !variant.fields.isEmpty()
384
+ } // We can skip no-arg constructors assuming there are never more than one instance of them
385
+ let sameVariantCases = variantsWithFields.map { variant =>
386
+ let variantName = modulePrefix + "." + variant.name
387
+ let fields = [...declaration.commonFields, ...variant.fields]
388
+ MatchCase(
389
+ at = at
390
+ patterns = [PVariantAs(at, variantName, at, Some("x")), PVariantAs(at, variantName, at, Some("y"))]
391
+ guards = []
392
+ body = self.makeEqualFields(modulePrefix, declaration, fields)
393
+ )
394
+ }
395
+ let differentVariant = MatchCase(
396
+ at = at
397
+ patterns = [wildcardPattern, wildcardPattern]
398
+ guards = []
399
+ body = EVariant(at, "ff:core/Bool.False", [], None)
400
+ )
401
+ [sameCase, ...sameVariantCases, differentVariant]
402
+ }
403
+ }
404
+
405
+ makeEqualFields(modulePrefix: String, declaration: DType, fields: List[Parameter]): Term {
406
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
407
+ function go(fields: List[Parameter]): Term {
408
+ | [] =>
409
+ EVariant(at, "ff:core/Bool.True", [], None)
410
+ | [head] =>
411
+ self.makeSimpleCall(at, "ff:core/Equal.equals", [
412
+ EField(at, False, EVariable(at, "x"), head.name)
413
+ EField(at, False, EVariable(at, "y"), head.name)
414
+ ])
415
+ | [head, ...tail] =>
416
+ let equalsTerm = self.makeSimpleCall(at, "ff:core/Equal.equals", [
417
+ EField(at, False, EVariable(at, "x"), head.name)
418
+ EField(at, False, EVariable(at, "y"), head.name)
419
+ ])
420
+ self.makeSimpleCall(at, "&&", [
421
+ equalsTerm
422
+ go(tail)
423
+ ])
424
+ }
425
+ go(fields)
426
+ }
427
+
428
+ // Serializable
429
+ makeSerializableInstances(modulePrefix: String, module: Module): List[DInstance] {
430
+ let coreWhitelist = [
431
+ "ff:core/Option.Option"
432
+ "ff:core/Pair.Pair"
433
+ ].toSet()
434
+ let missingInstance =
435
+ self.findTypesThatNeedInstances("ff:core/Serializable.Serializable", modulePrefix, coreWhitelist, True, module)
436
+ missingInstance.map {self.makeSerializableInstance(modulePrefix, _)}
437
+ }
438
+
439
+ makeSerializableInstance(modulePrefix: String, declaration: DType): DInstance {
440
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
441
+ let constraints = declaration.generics.map { t =>
442
+ Constraint(at, "ff:core/Serializable.Serializable", [TConstructor(at, t, [])])
443
+ }
444
+ let typeArguments = declaration.generics.map { t =>
445
+ TConstructor(at, t, [])
446
+ }
447
+ let selfType = TConstructor(at, modulePrefix + "." + declaration.name, typeArguments)
448
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
449
+ let serializationType = TConstructor(at, "ff:core/Serializable.Serialization", [])
450
+ let serializeSignature = Signature(
451
+ at = at
452
+ name = "serializeUsing"
453
+ member = False
454
+ generics = []
455
+ constraints = []
456
+ parameters = [
457
+ Parameter(at, False, "serialization", serializationType, None)
458
+ Parameter(at, False, "value", selfType, None)
459
+ ]
460
+ returnType = TConstructor(at, "ff:core/Unit.Unit", [])
461
+ effect = noEffect
462
+ )
463
+ let deserializeSignature = Signature(
464
+ at = at
465
+ name = "deserializeUsing"
466
+ member = False
467
+ generics = []
468
+ constraints = []
469
+ parameters = [
470
+ Parameter(at, False, "serialization", serializationType, None)
471
+ ]
472
+ returnType = selfType
473
+ effect = noEffect
474
+ )
475
+ let wildcardPattern = PVariable(at, None)
476
+ let serializeBody = FireflyTarget(
477
+ Lambda(at, noEffect, self.makeSerializeBody(modulePrefix, declaration, selfType))
478
+ )
479
+ let deserializeBody = FireflyTarget(
480
+ Lambda(at, noEffect, [MatchCase(
481
+ at = at
482
+ patterns = [wildcardPattern]
483
+ guards = []
484
+ body = self.makeDeserializeBody(modulePrefix, declaration, selfType)
485
+ )])
486
+ )
487
+ DInstance(
488
+ at = at
489
+ generics = declaration.generics
490
+ constraints = constraints
491
+ traitName = "ff:core/Serializable.Serializable"
492
+ typeArguments = [selfType]
493
+ generatorArguments = []
494
+ methods = [
495
+ DFunction(at, serializeSignature, serializeBody)
496
+ DFunction(at, deserializeSignature, deserializeBody)
497
+ ]
498
+ derived = True
499
+ )
500
+ }
501
+
502
+ makeSerializeBody(modulePrefix: String, declaration: DType, selfType: Type): List[MatchCase] {
503
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
504
+ let wildcardPattern = PVariable(at, None)
505
+ declaration.variants.pairs().map {| Pair(index, variant) =>
506
+ let variantName = modulePrefix + "." + variant.name
507
+ let fields = [...declaration.commonFields, ...variant.fields]
508
+ let updateChecksum = self.makeUpdateChecksum(at, variantName, declaration, variant)
509
+ let setVariantIndex = self.makeMethodCall(
510
+ at = at
511
+ target = EField(at, False, EVariable(at, "serialization"), "buffer")
512
+ methodName = "setUint8"
513
+ arguments = [EField(at, False, EVariable(at, "serialization"), "offset"), EInt(at, "" + index)]
514
+ )
515
+ let fieldSerializations = fields.map {field =>
516
+ self.makeSimpleCall(at, "ff:core/Serializable.serializeUsing", [
517
+ EVariable(at, "serialization")
518
+ EField(at, False, EVariable(at, "v"), field.name)
519
+ ])
520
+ }
521
+ MatchCase(
522
+ at = at,
523
+ patterns = [wildcardPattern, PVariantAs(at, variantName, at, Some("v"))]
524
+ guards = []
525
+ body = [
526
+ setVariantIndex
527
+ EAssignField(at, "+", EVariable(at, "serialization"), "offset", EInt(at, "1"))
528
+ ...fieldSerializations
529
+ ].foldLeft(updateChecksum) {ESequential(at, _, _)}
530
+ )
531
+ }
532
+ }
533
+
534
+ makeDeserializeBody(modulePrefix: String, declaration: DType, selfType: Type): Term {
535
+ let at = declaration.at.Location(file = declaration.at.file + "/<derived>")
536
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
537
+ let wildcardPattern = PVariable(at, None)
538
+ let grabVariantIndex = self.makeMethodCall(
539
+ at = at
540
+ target = EField(at, False, EVariable(at, "serialization"), "buffer")
541
+ methodName = "grabUint8"
542
+ arguments = [EField(at, False, EVariable(at, "serialization"), "offset")]
543
+ )
544
+ let intType = TConstructor(at, "ff:core/Int.Int", [])
545
+ let incrementOffset = EAssignField(at, "+", EVariable(at, "serialization"), "offset", EInt(at, "1"))
546
+ let cases = declaration.variants.pairs().map {| Pair(index, variant) =>
547
+ let variantName = modulePrefix + "." + variant.name
548
+ let fields = [...declaration.commonFields, ...variant.fields]
549
+ let fieldValues = fields.map {field =>
550
+ Argument(
551
+ at
552
+ None
553
+ self.makeSimpleCall(at, "ff:core/Serializable.deserializeUsing", [EVariable(at, "serialization")])
554
+ )
555
+ }
556
+ let updateChecksum = self.makeUpdateChecksum(at, variantName, declaration, variant)
557
+ let makeVariant = EVariant(at, variantName, [], Some(fieldValues))
558
+ MatchCase(
559
+ at = at,
560
+ patterns = [PInt(at, "" + index)]
561
+ guards = []
562
+ body = ESequential(at, updateChecksum, makeVariant)
563
+ )
564
+ }
565
+ let otherwiseCase = MatchCase(
566
+ at = at,
567
+ patterns = [wildcardPattern]
568
+ guards = []
569
+ body = self.makeSimpleCall(at, "ff:core/Core.throw", [
570
+ EVariant(at, "ff:core/Serializable.DeserializationChecksumException", [], None)
571
+ ])
572
+ )
573
+ let matchLambda = ELambda(at, Lambda(at, noEffect, [...cases, otherwiseCase]))
574
+ let match = EPipe(at, EVariable(at, "variantIndex"), noEffect, matchLambda)
575
+ ELet(at, False, "variantIndex", intType, grabVariantIndex, ESequential(at, incrementOffset, match))
576
+ }
577
+
578
+ makeUpdateChecksum(at: Location, variantName: String, declaration: DType, variant: Variant): Term {
579
+ let fields = [...declaration.commonFields, ...variant.fields]
580
+ let variantChecksum = variantName.size() // TODO: Hash variantName + fields with type terms + type parameters (+ type arguments?)
581
+ EAssignField(at, "", EVariable(at, "serialization"), "checksum"
582
+ self.makeMethodCall(
583
+ at = at
584
+ target = self.makeSimpleCall(at, "+", [
585
+ self.makeSimpleCall(at, "*", [
586
+ EInt(at, "31")
587
+ EField(at, False, EVariable(at, "serialization"), "checksum")
588
+ ])
589
+ EInt(at, "" + variantChecksum)
590
+ ])
591
+ methodName = "bitOr"
592
+ arguments = [EInt(at, "0")]
593
+ )
594
+ )
595
+ }
596
+
597
+ // Common
598
+
599
+ findTypesThatNeedInstances(
600
+ traitName: String
601
+ modulePrefix: String
602
+ coreWhitelist: Set[String]
603
+ allowGenerics: Bool
604
+ module: Module
605
+ ): List[DType] {
606
+ let typesWithInstance = module.instances.collect {
607
+ | instance {instance.typeArguments.first() | Some(TConstructor(_, name, _))} =>
608
+ if(instance.traitName == traitName) {name}
609
+ | _ => None
610
+ }.toSet()
611
+
612
+ module.types.filter {t =>
613
+ (module.packagePair.groupName() != "ff:core" || coreWhitelist.contains(modulePrefix + "." + t.name)) &&
614
+ !t.generics.first().any {_ == "Q$"} &&
615
+ (allowGenerics || t.generics.isEmpty()) &&
616
+ t.data && !t.newtype &&
617
+ !typesWithInstance.contains(modulePrefix + "." + t.name)
618
+ }
619
+ }
620
+
621
+ makeSimpleCall(at: Location, name: String, arguments: List[Term], typeArguments: List[Type] = []): Term {
622
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
623
+ let callTarget = DynamicCall(EVariable(at, name), tailCall = False)
624
+ ECall(at, callTarget, noEffect, typeArguments, arguments.map { e =>
625
+ Argument(at, None, e)
626
+ }, [])
627
+ }
628
+
629
+ makeMethodCall(at: Location, target: Term, methodName: String, arguments: List[Term]): Term {
630
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
631
+ let method = EField(at, False, target, methodName)
632
+ ECall(at, DynamicCall(method, False), noEffect, [], arguments.map {Argument(at, None, _)}, [])
633
+ }
634
+
635
+ makeIf(at: Location, condition: Term, then: Term, else: Term): Term {
636
+ let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
637
+ let target = DynamicCall(EVariable(at, "ff:core/Core.if"), tailCall = False)
638
+ let option = ECall(at, target, noEffect, [], [
639
+ Argument(at, None, condition)
640
+ Argument(at, None, ELambda(at, Lambda(at, noEffect, [MatchCase(at, [], [], then)])))
641
+ ], [])
642
+ ECall(at, DynamicCall(EField(at, False, option, "else"), tailCall = False), noEffect, [], [
643
+ Argument(at, None, ELambda(at, Lambda(at, noEffect, [MatchCase(at, [], [], else)])))
644
+ ], [])
645
+ }
646
+
647
+ }