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,1383 @@
1
+ import Token
2
+ import Wildcards
3
+ import Syntax
4
+ import LspHook
5
+
6
+ class Parser(
7
+ packagePair: PackagePair
8
+ file: String
9
+ tokens: Array[Token]
10
+ end: Token
11
+ targetIsNode: Bool
12
+ lspHook: LspHook
13
+ mutable lspEmittedArgumentHook: Bool
14
+ mutable offset: Int
15
+ mutable nextUnificationVariableIndex: Int
16
+ )
17
+
18
+ data Poly(generics: List[String], constraints: List[Constraint])
19
+
20
+ data ParsedTargets(
21
+ js: Option[Lambda]
22
+ jsSync: Option[String]
23
+ jsAsync: Option[String]
24
+ browser: Option[Lambda]
25
+ browserSync: Option[String]
26
+ browserAsync: Option[String]
27
+ node: Option[Lambda]
28
+ nodeSync: Option[String]
29
+ nodeAsync: Option[String]
30
+ )
31
+
32
+ make(
33
+ packagePair: PackagePair
34
+ file: String
35
+ tokens: Array[Token]
36
+ targetIsNode: Bool
37
+ lspHook: LspHook
38
+ ): Parser {
39
+ Parser(
40
+ packagePair = packagePair
41
+ file = file
42
+ tokens = tokens
43
+ end = tokens.grabLast()
44
+ targetIsNode = targetIsNode
45
+ lspHook = lspHook
46
+ lspEmittedArgumentHook = False
47
+ offset = 0
48
+ nextUnificationVariableIndex = 1 // To avoid collision with the unification and resolver
49
+ )
50
+ }
51
+
52
+ extend self: Parser {
53
+
54
+ fail[T](at: Location, message: String): T {
55
+ panic(message + " " + at.show())
56
+ }
57
+
58
+ behind(): Token {
59
+ if(self.offset == 0) {self.current()} else {
60
+ if(self.offset - 1 < self.tokens.size()) {self.tokens.grab(self.offset - 1)} else {self.end}
61
+ }
62
+ }
63
+
64
+ current(): Token {
65
+ if(self.offset < self.tokens.size()) {self.tokens.grab(self.offset)} else {self.end}
66
+ }
67
+
68
+ ahead(): Token {
69
+ if(self.offset + 1 < self.tokens.size()) {self.tokens.grab(self.offset + 1)} else {self.end}
70
+ }
71
+
72
+ aheadAhead(): Token {
73
+ if(self.offset + 2 < self.tokens.size()) {self.tokens.grab(self.offset + 2)} else {self.end}
74
+ }
75
+
76
+ skip(kind: TokenKind): Token {
77
+ let c = self.current()
78
+ if(c.kind != kind) {
79
+ if(self.lspHook.isEnabled() && kind == LUpper && c.kind == LLower) {} else:
80
+ throw(CompileError(c.at(), "Expected " + Show.show(kind) + ", got " + c.raw()))
81
+ }
82
+ self.offset += 1
83
+ c
84
+ }
85
+
86
+ rawSkip(kind: TokenKind, value: String): Token {
87
+ let c = self.current()
88
+ if(c.kind != kind) {
89
+ if(self.lspHook.isEnabled() && (value == ")" || value == "]" || value == "}")) {} else:
90
+ throw(CompileError(c.at(), "Expected " + Show.show(kind) + " " + value + ", got " + c.raw()))
91
+ }
92
+ if(!c.rawIs(value)) {
93
+ if(self.lspHook.isEnabled() && (value == ")" || value == "]" || value == "}")) {self.offset -= 1} else:
94
+ throw(CompileError(c.at(), "Expected " + value + " got " + c.raw()))
95
+ }
96
+ self.offset += 1
97
+ c
98
+ }
99
+
100
+ freshUnificationVariable(at: Location): Type {
101
+ let result = TVariable(at, self.nextUnificationVariableIndex)
102
+ self.nextUnificationVariableIndex += 3
103
+ result
104
+ }
105
+
106
+ currentIsSeparator(kind: TokenKind): Bool {
107
+ self.current().is(kind) || self.current().is(LSeparator)
108
+ }
109
+
110
+ skipSeparator(kind: TokenKind): Token {
111
+ if(self.current().is(LSeparator)) {
112
+ self.skip(LSeparator)
113
+ } else {
114
+ self.skip(kind)
115
+ }
116
+ }
117
+
118
+ parseModuleWithoutPackageInfo(): Module {
119
+ let moduleWithPackageInfo = self.parseModuleWithPackageInfo()
120
+ moduleWithPackageInfo.packageInfo.each {info =>
121
+ throw(CompileError(info.package.at, "Package and dependencies already declared in package.ff"))
122
+ }
123
+ moduleWithPackageInfo.module
124
+ }
125
+
126
+ parseModuleWithPackageInfo(): ModuleWithPackageInfo {
127
+ let packageInfo = if(self.current().is(LKeyword) && self.current().rawIs3("package", "dependency", "include")) {
128
+ self.parsePackageInfo()
129
+ }
130
+ let module = self.parseModule()
131
+ ModuleWithPackageInfo(packageInfo, module)
132
+ }
133
+
134
+ parsePackageInfo(): PackageInfo {
135
+ let location = self.current().at()
136
+ let package = if(self.current().is(LKeyword) && self.current().rawIs("package")) {
137
+ let p = self.parsePackageDefinition()
138
+ if(!self.current().is(LEnd)) {self.skipSeparator(LSemicolon)}
139
+ p
140
+ } else {
141
+ DPackage(
142
+ location
143
+ self.packagePair
144
+ Version(location, 0, 0, 0)
145
+ TargetNames(node = self.targetIsNode, browser = !self.targetIsNode)
146
+ )
147
+ }
148
+ if(self.current().is(LKeyword) && self.current().rawIs("package")) {
149
+ throw(CompileError(self.current().at(), "Duplicate package definition"))
150
+ }
151
+ /* TODO: if(self.package != None && self.current().is(LKeyword) && self.current().rawIs("dependency")) {
152
+ self.fail(self.current().at(), "Dependencies must be defined in the same file as the package declaration")
153
+ }*/
154
+ let dependencies = Stack.make[DDependency]()
155
+ while {self.current().is(LKeyword) && self.current().rawIs("dependency")} {
156
+ dependencies.push(self.parseDependencyDefinition(package.targets))
157
+ if(!self.current().is(LEnd)) {self.skipSeparator(LSemicolon)}
158
+ }
159
+ let includes = Stack.make[DInclude]()
160
+ while {self.current().is(LKeyword) && self.current().rawIs("include")} {
161
+ includes.push(self.parseIncludeDefinition())
162
+ if(!self.current().is(LEnd)) {self.skipSeparator(LSemicolon)}
163
+ }
164
+ // TODO: When this method is called directly for package.ff, check that the whole file has been consumed
165
+ PackageInfo(package, dependencies.toList(), includes.toList())
166
+ }
167
+
168
+ parseModule(): Module {
169
+ let imports = Stack.make[DImport]()
170
+ let types = Stack.make[DType]()
171
+ let traits = Stack.make[DTrait]()
172
+ let instances = Stack.make[DInstance]()
173
+ let extends = Stack.make[DExtend]()
174
+ let lets = Stack.make[DLet]()
175
+ let functions = Stack.make[DFunction]()
176
+ while {!self.current().is(LEnd)} {
177
+ if(self.current().is(LLower) && (self.ahead().is(LAssign) || self.ahead().is(LColon))) {
178
+ lets.push(self.parseLetDefinition())
179
+ } elseIf {self.current().is(LLower)} {
180
+ functions.push(self.parseFunctionDefinition(member = False))
181
+ } elseIf {self.current().is(LKeyword) && self.current().rawIs("extend")} {
182
+ extends.push(self.parseExtendDefinition())
183
+ } elseIf {self.current().is(LKeyword) && self.current().rawIs("trait")} {
184
+ traits.push(self.parseTraitDefinition())
185
+ } elseIf {self.current().is(LKeyword) && self.current().rawIs("instance")} {
186
+ instances.push(self.parseInstanceDefinition())
187
+ } elseIf {self.current().is(LKeyword) && self.current().rawIs4("data", "class", "capability", "newtype")} {
188
+ types.push(self.parseTypeDefinition())
189
+ } elseIf {self.current().is(LKeyword) && self.current().rawIs("import")} {
190
+ imports.push(self.parseImportDefinition(self.packagePair))
191
+ } elseIf {self.current().is(LKeyword) && self.current().rawIs("include")} {
192
+ throw(CompileError(self.current().at()
193
+ "Includes must be at the top of the file or below 'package'"
194
+ ))
195
+ } elseIf {self.current().is(LKeyword) && self.current().rawIs("dependency")} {
196
+ throw(CompileError(self.current().at()
197
+ "Dependencies must be at the top of the file or below 'package'"
198
+ ))
199
+ } elseIf {self.current().is(LKeyword) && self.current().rawIs("package")} {
200
+ throw(CompileError(self.current().at()
201
+ "Package definition must be at the top of the file"
202
+ ))
203
+ } else {
204
+ self.skip(LEnd)
205
+ }
206
+ if(!self.current().is(LEnd)) {self.skipSeparator(LSemicolon)}
207
+ }
208
+
209
+ Module(
210
+ file = self.file
211
+ packagePair = self.packagePair
212
+ imports = imports.toList()
213
+ lets = lets.toList()
214
+ functions = functions.toList()
215
+ extends = extends.toList()
216
+ types = types.toList()
217
+ traits = traits.toList()
218
+ instances = instances.toList()
219
+ )
220
+ }
221
+
222
+ parseLetDefinition(): DLet {
223
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
224
+ let nameToken = self.skip(LLower)
225
+ let variableType = if(self.current().is(LColon)) {
226
+ self.skip(LColon)
227
+ self.parseType()
228
+ } else {self.freshUnificationVariable(nameToken.at())}
229
+ self.skip(LAssign)
230
+ let value = self.parseTerm()
231
+ let retult = DLet(nameToken.at(), nameToken.raw(), variableType, value)
232
+ if(self.lspHook.trackSymbols) {
233
+ self.lspHook.emit(ParseSymbolEnd(
234
+ name = nameToken.raw()
235
+ kind = 14
236
+ selectionStart = nameToken.at()
237
+ selectionEnd = nameToken.end()
238
+ start = nameToken.at()
239
+ end = self.behind().end()
240
+ ))
241
+ }
242
+ retult
243
+ }
244
+
245
+ parseFunctionDefinition(member: Bool): DFunction {
246
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
247
+ let signature = self.parseSignature(member)
248
+ let body = if(self.current().rawIs("{")) {self.parseLambda(signature.parameters.size())}
249
+ let targets = self.parseTargets(signature.parameters.size())
250
+ let bestTarget = findBestTarget(self.targetIsNode, body, targets)
251
+ let result = DFunction(
252
+ signature.at
253
+ signature
254
+ bestTarget
255
+ )
256
+ if(self.lspHook.trackSymbols) {
257
+ let kind = if(member) {6} else {12}
258
+ self.lspHook.emit(ParseSymbolEnd(
259
+ name = signature.name
260
+ kind = kind
261
+ selectionStart = signature.at
262
+ selectionEnd = signature.at.Location(column = signature.at.column + signature.name.size())
263
+ start = signature.at
264
+ end = self.behind().end()
265
+ ))
266
+ }
267
+ result
268
+ }
269
+
270
+ parseTargets(parameterCount: Int): ParsedTargets {
271
+ function processCode(code: String): String {
272
+ let dropCount = if(code.startsWith("\"\"\"")) {3} else {1}
273
+ code.dropFirst(dropCount).dropLast(dropCount)
274
+ .replace("\\\"", "\"")
275
+ .replace("\\r", "\r")
276
+ .replace("\\n", "\n")
277
+ .replace("\\t", "\t")
278
+ .replace("\\\\", "\\")
279
+ }
280
+ mutable targets = ParsedTargets(None, None, None, None, None, None, None, None, None)
281
+ while {self.currentIsSeparator(LSemicolon) && self.ahead().is(LKeyword) && self.ahead().rawIs("target")} {
282
+ self.skip(LSeparator)
283
+ let at = self.skip(LKeyword).at()
284
+ let target = if(self.current().is(LLower)) {self.skip(LLower).raw()} else {self.skip(LKeyword).raw()}
285
+ if(self.current().rawIs("{")) {
286
+ let lambda = self.parseLambda(parameterCount)
287
+ target.{
288
+ | "js" =>
289
+ if(targets.jsSync != None) {throw(CompileError(at, "Duplicate target definition"))}
290
+ targets = targets.ParsedTargets(js = Some(lambda))
291
+ | "browser" =>
292
+ if(targets.browserSync != None) {throw(CompileError(at, "Duplicate target definition"))}
293
+ targets = targets.ParsedTargets(browser = Some(lambda))
294
+ | "node" =>
295
+ if(targets.nodeAsync != None) {throw(CompileError(at, "Duplicate target definition"))}
296
+ targets = targets.ParsedTargets(node = Some(lambda))
297
+ | _ =>
298
+ throw(CompileError(at, "Unknown target"))
299
+ }
300
+ } else {
301
+ let mode = self.skip(LKeyword).raw()
302
+ let code = processCode(self.skip(LString).raw())
303
+ Pair(target, mode).{
304
+ | Pair("js", "sync") =>
305
+ if(targets.jsSync != None) {throw(CompileError(at, "Duplicate target definition"))}
306
+ targets = targets.ParsedTargets(jsSync = Some(code))
307
+ | Pair("js", "async") =>
308
+ if(targets.jsAsync != None) {throw(CompileError(at, "Duplicate target definition"))}
309
+ targets = targets.ParsedTargets(jsAsync = Some(code))
310
+ | Pair("browser", "sync") =>
311
+ if(targets.browserSync != None) {throw(CompileError(at, "Duplicate target definition"))}
312
+ targets = targets.ParsedTargets(browserSync = Some(code))
313
+ | Pair("browser", "async") =>
314
+ if(targets.browserAsync != None) {throw(CompileError(at, "Duplicate target definition"))}
315
+ targets = targets.ParsedTargets(browserAsync = Some(code))
316
+ | Pair("node", "sync") =>
317
+ if(targets.nodeSync != None) {throw(CompileError(at, "Duplicate target definition"))}
318
+ targets = targets.ParsedTargets(nodeSync = Some(code))
319
+ | Pair("node", "async") =>
320
+ if(targets.nodeAsync != None) {throw(CompileError(at, "Duplicate target definition"))}
321
+ targets = targets.ParsedTargets(nodeAsync = Some(code))
322
+ | Pair(_, _) =>
323
+ throw(CompileError(at, "Unknown target or mode"))
324
+ }
325
+ }
326
+ }
327
+ targets
328
+ }
329
+
330
+ parseSignature(member: Bool): Signature {
331
+ let nameToken = self.skip(LLower)
332
+ let poly = if(self.current().rawIs("[")) {self.parseTypeParameters()} else {Poly([], [])}
333
+ let parameters = if(self.lspHook.isEnabled() && !self.current().rawIs("(")) {[]} else {self.parseFunctionParameters()}
334
+ let returnType = if(self.current().is(LColon)) {
335
+ self.skip(LColon)
336
+ self.parseType()
337
+ } else {
338
+ TConstructor(self.current().at(), "ff:core/Unit.Unit", [])
339
+ }
340
+ let temporaryEffect = TConstructor(nameToken.at(), "TemporaryEffect$", [])
341
+ Signature(nameToken.at(), nameToken.raw(), member, poly.generics, poly.constraints, parameters, returnType, temporaryEffect)
342
+ }
343
+
344
+ parseExtendDefinition(): DExtend {
345
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
346
+ let extendToken = self.rawSkip(LKeyword, "extend")
347
+ let nameToken = self.skip(LLower)
348
+ let poly = if(self.current().rawIs("[")) {self.parseTypeParameters()} else {Poly([], [])}
349
+ self.skip(LColon)
350
+ let type = self.parseType()
351
+ self.rawSkip(LBracketLeft, "{")
352
+ let methods = Stack.make[DFunction]()
353
+ while {!self.current().is(LBracketRight)} {
354
+ methods.push(self.parseFunctionDefinition(member = True))
355
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LSemicolon)}
356
+ }
357
+ self.rawSkip(LBracketRight, "}")
358
+ if(self.lspHook.trackSymbols) {
359
+ mutable name = type.show([])
360
+ poly.generics.zip(poly.constraints).each {| Pair(generic, constraint) =>
361
+ name = name.replace("[" + generic + "]", "[" + generic + ": " + constraint.name + "]")
362
+ name = name.replace("[" + generic + ",", "[" + generic + ": " + constraint.name + ",")
363
+ name = name.replace(", " + generic + ",", ", " + generic + ": " + constraint.name + ",")
364
+ name = name.replace(", " + generic + "]", ", " + generic + ": " + constraint.name + "]")
365
+ }
366
+ self.lspHook.emit(ParseSymbolEnd(
367
+ name = name
368
+ kind = 3 // Namespace
369
+ selectionStart = nameToken.at()
370
+ selectionEnd = nameToken.end()
371
+ start = extendToken.at()
372
+ end = self.behind().end()
373
+ ))
374
+ }
375
+ DExtend(
376
+ nameToken.at()
377
+ nameToken.raw()
378
+ poly.generics
379
+ poly.constraints
380
+ type
381
+ methods.toList()
382
+ )
383
+ }
384
+
385
+ parseTraitDefinition(): DTrait {
386
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
387
+ let traitToken = self.rawSkip(LKeyword, "trait")
388
+ let typeParameterToken = self.skip(LUpper)
389
+ self.skip(LColon)
390
+ let nameToken = self.skip(LUpper)
391
+ let poly = if(!self.current().rawIs("[")) {Poly([], [])} else {self.parseTypeParameters()}
392
+ let constraints = Stack.make[Constraint]()
393
+ while {self.current().is(LColon)} {
394
+ self.fail(self.current().at(), "Trait constraints is not yet implemented")
395
+ self.skip(LColon)
396
+ let constraint = self.parseConstraint()
397
+ constraints.push(constraint.Constraint(generics =
398
+ [TConstructor(typeParameterToken.at(), typeParameterToken.raw(), []), ...constraint.generics]
399
+ ))
400
+ }
401
+ let generatorParameters = if(!self.current().rawIs("(")) {[]} else {self.parseFunctionParameters()}
402
+ let methodGenerators = Stack.make[Pair[String, Lambda]]()
403
+ let methodDefaults = Stack.make[Pair[String, Lambda]]()
404
+ let methodSignatures = if(!self.current().rawIs("{")) {[]} else {
405
+ let signatures = Stack.make[Signature]()
406
+ self.rawSkip(LBracketLeft, "{")
407
+ while {!self.current().is(LBracketRight)} {
408
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
409
+ let signatureNameToken = self.current()
410
+ let signature = self.parseSignature(member = True)
411
+ if(self.lspHook.trackSymbols) {
412
+ self.lspHook.emit(ParseSymbolEnd(
413
+ name = signatureNameToken.raw()
414
+ kind = 12 // Function
415
+ selectionStart = signatureNameToken.at()
416
+ selectionEnd = signatureNameToken.end()
417
+ start = signatureNameToken.at()
418
+ end = self.behind().end()
419
+ ))
420
+ }
421
+ signatures.push(signature)
422
+ if(self.current().rawIs("{")) {
423
+ let generator = self.ahead().is(LKeyword) && self.ahead().rawIs("generate")
424
+ let body = self.parseLambda(signature.parameters.size(), ignoreGenerateKeyword = True)
425
+ if(generator) {
426
+ methodGenerators.push(Pair(signature.name, body))
427
+ } else {
428
+ methodDefaults.push(Pair(signature.name, body))
429
+ }
430
+ }
431
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LSemicolon)}
432
+ }
433
+ self.rawSkip(LBracketRight, "}")
434
+ signatures.toList()
435
+ }
436
+ if(self.lspHook.trackSymbols) {
437
+ self.lspHook.emit(ParseSymbolEnd(
438
+ name = nameToken.raw()
439
+ kind = 11 // Interface
440
+ selectionStart = nameToken.at()
441
+ selectionEnd = nameToken.end()
442
+ start = traitToken.at()
443
+ end = self.behind().end()
444
+ ))
445
+ }
446
+ DTrait(
447
+ nameToken.at()
448
+ nameToken.raw()
449
+ [typeParameterToken.raw(), ...poly.generics]
450
+ [...constraints.toList(), ...poly.constraints]
451
+ generatorParameters
452
+ methodSignatures
453
+ methodDefaults.toList()
454
+ methodGenerators.toList()
455
+ )
456
+ }
457
+
458
+ parseInstanceDefinition(): DInstance {
459
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
460
+ let instanceToken = self.rawSkip(LKeyword, "instance")
461
+ let token = self.skip(LUpper)
462
+ let poly = if(!self.current().rawIs("[")) {Poly([], [])} else {self.parseTypeParameters()}
463
+ let typeArguments = Stack.make[Type]()
464
+ typeArguments.push(TConstructor(token.at(), token.raw(), poly.generics.map {TConstructor(token.at(), _, [])}))
465
+ self.skip(LColon)
466
+ let nameToken = self.skip(LUpper)
467
+ if(self.current().rawIs("[")) {
468
+ self.rawSkip(LBracketLeft, "[")
469
+ while {!self.current().is(LBracketRight)} {
470
+ typeArguments.push(self.parseType())
471
+ if(!self.current().is(LBracketRight)) {self.skip(LComma)}
472
+ }
473
+ self.rawSkip(LBracketRight, "]")
474
+ }
475
+ let generatorArguments = self.parseFunctionArguments(nameToken.at(), False).first
476
+ let methods = if(!self.current().rawIs("{")) {[]} else {
477
+ let definitions = Stack.make[DFunction]()
478
+ self.rawSkip(LBracketLeft, "{")
479
+ while {!self.current().is(LBracketRight)} {
480
+ definitions.push(self.parseFunctionDefinition(member = False))
481
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LSemicolon)}
482
+ }
483
+ self.rawSkip(LBracketRight, "}")
484
+ definitions.toList()
485
+ }
486
+ if(self.lspHook.trackSymbols) {
487
+ let name = token.raw() + ": " + nameToken.raw()
488
+ self.lspHook.emit(ParseSymbolEnd(
489
+ name = name
490
+ kind = 19 // Object
491
+ selectionStart = nameToken.at()
492
+ selectionEnd = nameToken.end()
493
+ start = instanceToken.at()
494
+ end = self.behind().end()
495
+ ))
496
+ }
497
+ DInstance(
498
+ at = nameToken.at()
499
+ generics = poly.generics
500
+ constraints = poly.constraints
501
+ traitName = nameToken.raw()
502
+ typeArguments = typeArguments.toList()
503
+ generatorArguments = generatorArguments
504
+ methods = methods
505
+ derived = False
506
+ )
507
+ }
508
+
509
+ parseTypeDefinition(): DType {
510
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
511
+ let newtype = self.current().rawIs("newtype")
512
+ let effectParameter = if(self.current().rawIs("capability")) {["Q$"]} else {[]}
513
+ let allowMutable = self.current().rawIs2("class", "capability")
514
+ let kindToken = if(self.current().rawIs("newtype")) {
515
+ self.rawSkip(LKeyword, "newtype")
516
+ } elseIf {self.current().rawIs("data")} {
517
+ self.rawSkip(LKeyword, "data")
518
+ } elseIf {self.current().rawIs("class")} {
519
+ self.rawSkip(LKeyword, "class")
520
+ } else {
521
+ self.rawSkip(LKeyword, "capability")
522
+ }
523
+ let nameToken = self.skip(LUpper)
524
+ let poly = if(!self.current().rawIs("[")) {Poly([], [])} else {self.parseTypeParameters()}
525
+ if(!self.current().rawIs("(") && !self.current().rawIs("{")) {self.rawSkip(LBracketLeft, "{")}
526
+ let commonFields = if(!self.current().rawIs("(")) {[]} else {self.parseFunctionParameters(allowMutable = True)}
527
+ let variants = if(newtype || !self.current().rawIs("{")) {
528
+ [Variant(nameToken.at(), nameToken.raw(), [])]
529
+ } else {
530
+ self.rawSkip(LBracketLeft, "{")
531
+ let variantsBuilder = Stack.make[Variant]()
532
+ while {!self.current().is(LBracketRight)} {
533
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
534
+ let variantNameToken = self.skip(LUpper)
535
+ let variantFields = if(!self.current().rawIs("(")) {[]} else {self.parseFunctionParameters(allowMutable = True)}
536
+ if(!allowMutable && variantFields.any {_.mutable}) {
537
+ throw(CompileError(variantFields.find {_.mutable}.grab().at
538
+ "Only classes can have mutable fields"
539
+ ))
540
+ }
541
+ variantsBuilder.push(
542
+ Variant(variantNameToken.at(), variantNameToken.raw(), variantFields)
543
+ )
544
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LSemicolon)}
545
+ if(self.lspHook.trackSymbols) {
546
+ self.lspHook.emit(ParseSymbolEnd(
547
+ name = variantNameToken.raw()
548
+ kind = 10 // Enum
549
+ selectionStart = variantNameToken.at()
550
+ selectionEnd = variantNameToken.end()
551
+ start = variantNameToken.at()
552
+ end = self.behind().end()
553
+ ))
554
+ }
555
+ }
556
+ self.rawSkip(LBracketRight, "}")
557
+ variantsBuilder.toList()
558
+ }
559
+ if(newtype && commonFields.size() != 1) {
560
+ Log.show(commonFields)
561
+ throw(CompileError(nameToken.at(), "Newtypes must have exactly one field"))
562
+ }
563
+ if(!allowMutable && commonFields.any {_.mutable}) {
564
+ throw(CompileError(
565
+ commonFields.find {_.mutable}.grab().at
566
+ "Only classes and capabilities can have mutable fields"
567
+ ))
568
+ }
569
+ let generics = [...effectParameter, ...poly.generics]
570
+ let result = DType(nameToken.at(), newtype, !allowMutable, nameToken.raw(), generics, poly.constraints, commonFields, variants)
571
+ if(self.lspHook.trackSymbols) {
572
+ self.lspHook.emit(ParseSymbolEnd(
573
+ name = nameToken.raw()
574
+ kind = 5
575
+ selectionStart = nameToken.at()
576
+ selectionEnd = nameToken.end()
577
+ start = kindToken.at()
578
+ end = self.behind().end()
579
+ ))
580
+ }
581
+ result
582
+ }
583
+
584
+ parseImportDefinition(currentPackagePair: PackagePair): DImport {
585
+ let importToken = self.rawSkip(LKeyword, "import")
586
+ let path = Stack.make[String]()
587
+ while {self.current().is(LLower)} {
588
+ path.push(self.parseDashedName())
589
+ self.skip(LDot)
590
+ }
591
+ let fileToken = self.skip(LUpper)
592
+ let alias = if(self.current().rawIs("as")) {
593
+ self.rawSkip(LKeyword, "as")
594
+ self.skip(LUpper).raw()
595
+ } else {fileToken.raw()}
596
+ let packagePair = if(self.current().rawIs("from")) {
597
+ self.rawSkip(LKeyword, "from")
598
+ let userName = self.parseDashedName()
599
+ self.skip(LColon)
600
+ let packageName = self.parseDashedName()
601
+ PackagePair(userName, packageName)
602
+ } else {
603
+ currentPackagePair
604
+ }
605
+ DImport(fileToken.at(), alias, packagePair, path.toList(), fileToken.raw())
606
+ }
607
+
608
+ parsePackageDefinition(): DPackage {
609
+ let at = self.skip(LKeyword).at()
610
+ let user = self.skip(LLower).raw()
611
+ self.skip(LColon)
612
+ let name = self.skip(LLower).raw()
613
+ self.skip(LColon)
614
+ let version = self.parseVersion()
615
+ let targets = self.parseTargetNames(TargetNames(True, True))
616
+ DPackage(
617
+ at = at
618
+ packagePair = PackagePair(user, name)
619
+ version = version
620
+ targets = targets
621
+ )
622
+ }
623
+
624
+ parseDependencyDefinition(defaultTargetNames: TargetNames): DDependency {
625
+ let at = self.skip(LKeyword).at()
626
+ let user = self.skip(LLower).raw()
627
+ self.skip(LColon)
628
+ let name = self.skip(LLower).raw()
629
+ self.skip(LColon)
630
+ let version = self.parseVersion()
631
+ let safety = (
632
+ if(self.current().rawIs("trusted")) {Trusted} else:
633
+ if(self.current().rawIs("unsafe")) {Unsafe} else:
634
+ Safe
635
+ )
636
+ let targets = self.parseTargetNames(defaultTargetNames)
637
+ DDependency(
638
+ at = at
639
+ packagePair = PackagePair(user, name)
640
+ version = version
641
+ safety = safety
642
+ targets = targets
643
+ )
644
+ }
645
+
646
+ parseIncludeDefinition(): DInclude {
647
+ let at = self.skip(LKeyword).at()
648
+ let path = self.skip(LString).raw()
649
+ DInclude(
650
+ at = at
651
+ path = path.dropFirst().dropLast() // TODO: Fix string escaping
652
+ )
653
+ }
654
+
655
+ parseTargetNames(defaultTargets: TargetNames): TargetNames {
656
+ mutable targets = TargetNames(False, False)
657
+ while {self.current().is2(LKeyword, LLower)} {
658
+ let token = if(self.current().is(LLower)) {self.skip(LLower)} else {self.skip(LKeyword)}
659
+ token.raw().{
660
+ | "node" {targets.node} => throw(CompileError(token.at(), "Duplicate target name"))
661
+ | "node" => targets = targets.TargetNames(node = True)
662
+ | "browser" {targets.browser} => throw(CompileError(token.at(), "Duplicate target name"))
663
+ | "browser" => targets = targets.TargetNames(browser = True)
664
+ | t => throw(CompileError(token.at(), "Unexpected target: " + t))
665
+ }
666
+ }
667
+ if(!targets.node && !targets.browser) {
668
+ defaultTargets
669
+ } else {
670
+ targets
671
+ }
672
+ }
673
+
674
+ parseVersion(): Version {
675
+ if(self.current().is(LFloat)) {
676
+ let majorMinor = self.skip(LFloat)
677
+ let parts = majorMinor.raw().split('.')
678
+ let patch = if(self.current().is(LDot)) {
679
+ self.skip(LDot)
680
+ self.skip(LInt).raw().grabInt()
681
+ } else {0}
682
+ Version(majorMinor.at(), parts.grab(0).grabInt(), parts.grab(1).grabInt(), patch)
683
+ } else {
684
+ let major = self.skip(LInt)
685
+ Version(major.at(), major.raw().grabInt(), 0, 0)
686
+ }
687
+ }
688
+
689
+ parseDashedName(): String {
690
+ let at = self.current().at()
691
+ function readPart(): String {
692
+ if(self.current().is(LInt)) {
693
+ let prefix = self.skip(LInt).raw()
694
+ if(self.current().is(LLower)) {prefix + self.skip(LLower).raw()} else {prefix}
695
+ } else {
696
+ self.skip(LLower).raw()
697
+ }
698
+ }
699
+ mutable part = readPart()
700
+ while {self.current().rawIs("-")} {
701
+ self.skip(LOperator)
702
+ part = part + "-" + readPart()
703
+ }
704
+ if(part.any {_.isAsciiUpper()}) {
705
+ throw(CompileError(at, "Package names and paths must not contain upper case letters: " + part))
706
+ }
707
+ if(part.any {_ == '_'} || part.any {_ == '.'}) {
708
+ throw(CompileError(at, "Package names and paths must not contain underscores or dots: " + part))
709
+ }
710
+ part
711
+ }
712
+
713
+ parseTypeParameters(): Poly {
714
+ self.rawSkip(LBracketLeft, "[")
715
+ let parameters = Stack.make[String]()
716
+ let constraints = Stack.make[Constraint]()
717
+ while {!self.current().is(LBracketRight) && !self.current().is(LSemicolon)} {
718
+ if(self.ahead().is(LBracketLeft)) {
719
+ constraints.push(self.parseConstraint())
720
+ } else {
721
+ let parameterNameToken = self.skip(LUpper)
722
+ parameters.push(parameterNameToken.raw())
723
+ while {self.current().is(LColon)} {
724
+ self.skip(LColon)
725
+ let constraint = self.parseConstraint()
726
+ constraints.push(constraint.Constraint(generics =
727
+ [TConstructor(parameterNameToken.at(), parameterNameToken.raw(), []), ...constraint.generics]
728
+ ))
729
+ }
730
+ }
731
+ if(!self.current().is(LBracketRight)) {self.skip(LComma)}
732
+ }
733
+ self.rawSkip(LBracketRight, "]")
734
+ Poly(parameters.toList(), constraints.toList())
735
+ }
736
+
737
+ parseTypeArguments(parenthesis: Bool = False): List[Type] {
738
+ self.rawSkip(LBracketLeft, if(parenthesis) {"("} else {"["})
739
+ let types = Stack.make[Type]()
740
+ while {!self.current().is(LBracketRight)} {
741
+ types.push(self.parseType())
742
+ if(!self.current().is(LBracketRight)) {self.skip(LComma)}
743
+ }
744
+ self.rawSkip(LBracketRight, if(parenthesis) {")"} else {"]"})
745
+ types.toList()
746
+ }
747
+
748
+ parseFunctionParameters(allowMutable: Bool = False): List[Parameter] {
749
+ let parameters = Stack.make[Parameter]()
750
+ self.rawSkip(LBracketLeft, "(")
751
+ while {!self.current().is(LBracketRight)} {
752
+ let lspTrackSymbols = self.lspHook.trackSymbols && allowMutable
753
+ if(lspTrackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
754
+ let lspFirst = self.current()
755
+ let mutable = allowMutable && self.current().is(LKeyword) && self.current().rawIs("mutable")
756
+ if(mutable) {self.skip(LKeyword)}
757
+ let parameterNameToken = self.skip(LLower)
758
+ if(self.lspHook.isEnabled() && !self.current().is(LColon)) {
759
+ let t = TConstructor(parameterNameToken.at(), "ff:core/Nothing.Nothing", [])
760
+ parameters.push(Parameter(parameterNameToken.at(), mutable, parameterNameToken.raw(), t, None))
761
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LComma)}
762
+ } else:
763
+ self.skip(LColon)
764
+ let parameterType = self.parseType()
765
+ let default = if(!self.current().is(LAssign)) {None} else {
766
+ self.skip(LAssign)
767
+ Some(self.parseTerm())
768
+ }
769
+ parameters.push(Parameter(parameterNameToken.at(), mutable, parameterNameToken.raw(), parameterType, default))
770
+ if(lspTrackSymbols) {
771
+ self.lspHook.emit(ParseSymbolEnd(
772
+ name = parameterNameToken.raw()
773
+ kind = 7 // Property
774
+ selectionStart = parameterNameToken.at()
775
+ selectionEnd = parameterNameToken.end()
776
+ start = lspFirst.at()
777
+ end = self.behind().end()
778
+ ))
779
+ }
780
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LComma)}
781
+ }
782
+ self.rawSkip(LBracketRight, ")")
783
+ parameters.toList()
784
+ }
785
+
786
+ parseFunctionArguments(callAt: Location, trailing: Bool): Pair[List[Argument], Bool] {
787
+ let arguments = Stack.make[Argument]()
788
+ if(self.current().rawIs("(")){
789
+ self.rawSkip(LBracketLeft, "(")
790
+ while {!self.current().is(LBracketRight)} {
791
+ let argumentToken = self.current()
792
+ let nameToken = if(self.current().is(LLower) && self.ahead().is(LAssign)) {
793
+ let token = self.skip(LLower)
794
+ self.skip(LAssign)
795
+ Some(token)
796
+ } else {None}
797
+ let value = self.parseTerm()
798
+ if(self.lspHook.isEnabled() && !self.lspEmittedArgumentHook) {
799
+ if(LspHook.strictlyBetween(callAt, self.current().at(), self.lspHook.at, 1)) {
800
+ self.lspHook.emit(ParseArgumentHook(callAt, arguments.size(), nameToken.map {_.raw()}))
801
+ self.lspEmittedArgumentHook = True
802
+ }
803
+ }
804
+ arguments.push(Argument(argumentToken.at(), nameToken.map {_.raw()}, value))
805
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LComma)}
806
+ }
807
+ if(self.lspHook.isEnabled() && !self.lspEmittedArgumentHook) {
808
+ if(LspHook.strictlyBetween(callAt, self.current().at(), self.lspHook.at, 1)) {
809
+ self.lspHook.emit(ParseArgumentHook(callAt, arguments.size(), None))
810
+ self.lspEmittedArgumentHook = True
811
+ }
812
+ }
813
+ self.rawSkip(LBracketRight, ")")
814
+ }
815
+ mutable lastWasCurly = False
816
+ if(trailing) {
817
+ if(self.lspHook.isEnabled() &&
818
+ (self.current().is3(LLower, LUpper, LString) || self.current().is3(LInt, LChar, LFloat))
819
+ ) {
820
+ lastWasCurly = True
821
+ let term = self.parseTerm()
822
+ let temporaryEffect = TConstructor(term.at, "TemporaryEffect$", [])
823
+ let cases = [MatchCase(term.at, [], [], term)]
824
+ if(self.lspHook.isEnabled() && !self.lspEmittedArgumentHook) {
825
+ if(LspHook.strictlyBetween(callAt, self.current().at(), self.lspHook.at, 1)) {
826
+ self.lspHook.emit(ParseArgumentHook(callAt, arguments.size(), None))
827
+ self.lspEmittedArgumentHook = True
828
+ }
829
+ }
830
+ arguments.push(Argument(term.at, None, ELambda(term.at, Lambda(term.at, temporaryEffect, cases))))
831
+ } else {
832
+ while {self.current().rawIs("{") || self.current().is(LColon)} {
833
+ lastWasCurly = self.current().rawIs("{")
834
+ let lambda = self.parseLambda(allowColon = True)
835
+ if(self.lspHook.isEnabled() && !self.lspEmittedArgumentHook) {
836
+ if(LspHook.strictlyBetween(callAt, self.current().at(), self.lspHook.at, 1)) {
837
+ self.lspHook.emit(ParseArgumentHook(callAt, arguments.size(), None))
838
+ self.lspEmittedArgumentHook = True
839
+ }
840
+ }
841
+ arguments.push(Argument(lambda.at, None, ELambda(lambda.at, lambda)))
842
+ }
843
+ }
844
+ }
845
+ Pair(arguments.toList(), lastWasCurly)
846
+ }
847
+
848
+ parseLambda(
849
+ defaultParameterCount: Int = 0
850
+ ignoreGenerateKeyword: Bool = False
851
+ allowColon: Bool = False
852
+ ): Lambda {
853
+ let colon = allowColon && self.current().is(LColon)
854
+ let token = if(colon) {self.skip(LColon)} else {self.rawSkip(LBracketLeft, "{")}
855
+ if(ignoreGenerateKeyword && self.current().is(LKeyword) && self.current().rawIs("generate")) {self.skip(LKeyword)}
856
+ let result = if(self.current().is(LPipe)) {
857
+ let cases = Stack.make[MatchCase]()
858
+ while {self.current().is(LPipe)} {
859
+ cases.push(self.parseCase())
860
+ }
861
+ cases.toList()
862
+ } elseIf {self.current().is2(LLower, LWildcard) && self.ahead().is2(LComma, LArrowThick)} {
863
+ let parameters = Stack.make[MatchPattern]()
864
+ while {!self.current().is(LArrowThick)} {
865
+ let isVariable = self.current().is(LLower)
866
+ let parameterToken = if(isVariable) {self.skip(LLower)} else {self.skip(LWildcard)}
867
+ parameters.push(PVariable(parameterToken.at(), if(isVariable) {Some(parameterToken.raw())} else {None}))
868
+ if(!self.current().is(LArrowThick)) {self.skip(LComma)}
869
+ }
870
+ self.skip(LArrowThick)
871
+ let term = self.parseStatements()
872
+ [MatchCase(token.at(), parameters.toList(), [], term)]
873
+ } else {
874
+ let term = self.parseStatements()
875
+ let wildcards = Wildcards.make()
876
+ let e = wildcards.fixWildcards(term)
877
+ let arguments = if(wildcards.seenWildcards != 0) {
878
+ List.range(wildcards.seenWildcards).map {i => PVariable(token.at(), Some("_w" + (i + 1)))}
879
+ } else {
880
+ List.range(defaultParameterCount).map {i => PVariable(token.at(), None)}
881
+ }
882
+ [MatchCase(token.at(), arguments, [], e)]
883
+ }
884
+ if(!colon) {self.rawSkip(LBracketRight, "}")}
885
+ let temporaryEffect = TConstructor(token.at(), "TemporaryEffect$", [])
886
+ Lambda(token.at(), temporaryEffect, result)
887
+ }
888
+
889
+ parseCase(): MatchCase {
890
+ let token = self.skip(LPipe)
891
+ let patterns = Stack.make[MatchPattern]()
892
+ while {!self.current().is3(LArrowThick, LPipe, LBracketRight) && !self.current().rawIs("{")} {
893
+ patterns.push(self.parsePattern())
894
+ if(!self.current().is3(LArrowThick, LPipe, LBracketRight) && !self.current().rawIs("{")) {
895
+ self.skip(LComma)
896
+ }
897
+ }
898
+ let guards = Stack.make[MatchGuard]()
899
+ while {self.current().rawIs("{")} {
900
+ guards.push(self.parseCaseGuard())
901
+ }
902
+ if(!self.lspHook.isEnabled() || !self.current().is2(LPipe, LBracketRight)) {
903
+ self.skip(LArrowThick)
904
+ }
905
+ let body = self.parseStatements()
906
+ MatchCase(token.at(), patterns.toList(), guards.toList(), body)
907
+ }
908
+
909
+ parseCaseGuard(): MatchGuard {
910
+ let guardToken = self.skip(LBracketLeft)
911
+ let term = self.parseStatements()
912
+ let p = if(!self.current().is(LPipe)) {
913
+ PVariant(guardToken.at(), "True", [])
914
+ } else {
915
+ self.skip(LPipe)
916
+ self.parsePattern()
917
+ }
918
+ self.skip(LBracketRight)
919
+ MatchGuard(guardToken.at(), term, p)
920
+ }
921
+
922
+ parsePattern(): MatchPattern {
923
+ let pattern = if(self.current().is(LWildcard)) {
924
+ let token = self.skip(LWildcard)
925
+ PVariable(token.at(), None)
926
+ } elseIf {self.current().is(LLower)} {
927
+ let token = self.skip(LLower)
928
+ PVariable(token.at(), Some(token.raw()))
929
+ } elseIf {self.current().rawIs("(")} {
930
+ let at = self.current().at()
931
+ let pair = self.parseRecordPattern().unzip()
932
+ PVariant(at, "Record$" + pair.first.join("$"), pair.second)
933
+ } elseIf {self.current().rawIs("[")} {
934
+ self.parseListPattern()
935
+ } elseIf {self.current().is(LString)} {
936
+ let token = self.skip(LString)
937
+ PString(token.at(), token.raw())
938
+ } elseIf {self.current().is(LInt)} {
939
+ let token = self.skip(LInt)
940
+ PInt(token.at(), token.raw())
941
+ } elseIf {self.current().is(LChar)} {
942
+ let token = self.skip(LChar)
943
+ PChar(token.at(), token.raw())
944
+ } else {
945
+ let token = self.skip(LUpper)
946
+ if(self.current().rawIs("(")) {
947
+ let patterns = Stack.make[MatchPattern]()
948
+ self.rawSkip(LBracketLeft, "(")
949
+ while {!self.current().is(LBracketRight)} {
950
+ let pattern = self.parsePattern()
951
+ if(self.lspHook.isEnabled() && !self.lspEmittedArgumentHook) {
952
+ if(LspHook.strictlyBetween(token.at(), self.current().at(), self.lspHook.at, 1)) {
953
+ self.lspHook.emit(ParseArgumentHook(token.at(), patterns.size(), None))
954
+ self.lspEmittedArgumentHook = True
955
+ }
956
+ }
957
+ patterns.push(pattern)
958
+ if(!self.current().is(LBracketRight)) {self.skip(LComma)}
959
+ }
960
+ if(self.lspHook.isEnabled() && !self.lspEmittedArgumentHook) {
961
+ if(LspHook.strictlyBetween(token.at(), self.current().at(), self.lspHook.at, 1)) {
962
+ self.lspHook.emit(ParseArgumentHook(token.at(), patterns.size(), None))
963
+ self.lspEmittedArgumentHook = True
964
+ }
965
+ }
966
+ self.rawSkip(LBracketRight, ")")
967
+ PVariant(token.at(), token.raw(), patterns.toList())
968
+ } else {
969
+ if(self.current().is(LLower)) {
970
+ let asToken = self.skip(LLower)
971
+ PVariantAs(token.at(), token.raw(), asToken.at(), Some(asToken.raw()))
972
+ } elseIf {self.current().is(LWildcard)} {
973
+ let wildcardToken = self.skip(LWildcard)
974
+ PVariantAs(token.at(), token.raw(), wildcardToken.at(), None)
975
+ } else {
976
+ PVariant(token.at(), token.raw(), [])
977
+ }
978
+ }
979
+ }
980
+ if(self.current().rawIs("@")) {
981
+ let atToken = self.skip(LOperator)
982
+ let asToken = self.skip(LLower)
983
+ PAlias(asToken.at(), pattern, asToken.raw())
984
+ } else {pattern}
985
+ }
986
+
987
+ parseType(): Type {
988
+ let leftTypes = if(self.current().rawIs("(") && self.ahead().is(LLower) && self.aheadAhead().is(LColon)) {
989
+ let at = self.current().at()
990
+ let pair = self.parseRecordType().unzip()
991
+ [TConstructor(at, "Record$" + pair.first.join("$"), pair.second)]
992
+ } elseIf {self.current().rawIs("(")} {
993
+ self.parseTypeArguments(parenthesis = True)
994
+ } else {
995
+ let namespace = if(self.current().is(LNamespace)) {self.skip(LNamespace).raw()} else {""}
996
+ let token = self.skip(LUpper)
997
+ let arguments = if(!self.current().rawIs("[")) {[]} else {self.parseTypeArguments()}
998
+ [TConstructor(token.at(), namespace + token.raw(), arguments)]
999
+ }
1000
+ if(!self.current().is(LArrowThick) && leftTypes.size() == 1) {leftTypes.grabFirst()} else {
1001
+ let arrowToken = self.skip(LArrowThick)
1002
+ let rightType = self.parseType()
1003
+ TConstructor(arrowToken.at(), "Function$" + leftTypes.size(), [...leftTypes, rightType])
1004
+ }
1005
+ }
1006
+
1007
+ parseConstraint(): Constraint {
1008
+ let namespace = if(self.current().is(LNamespace)) {self.skip(LNamespace).raw()} else {""}
1009
+ let token = self.skip(LUpper)
1010
+ let arguments = if(!self.current().rawIs("[")) {[]} else {self.parseTypeArguments()}
1011
+ Constraint(token.at(), namespace + token.raw(), arguments)
1012
+ }
1013
+
1014
+ parseStatements(): Term {
1015
+ if(self.current().is2(LBracketRight, LPipe)) {EVariant(self.current().at(), "Unit", [], None)} else {
1016
+ mutable result = self.parseStatement()
1017
+ while {self.currentIsSeparator(LSemicolon)} {
1018
+ let token = self.skipSeparator(LSemicolon)
1019
+ result = ESequential(token.at(), result, self.parseStatement())
1020
+ }
1021
+ result
1022
+ }
1023
+ }
1024
+
1025
+ parseStatement(): Term {
1026
+ if(self.current().is(LKeyword) && (self.current().rawIs("let") || self.current().rawIs("mutable"))) {self.parseLet()} else:
1027
+ if(self.current().is(LKeyword) && self.current().rawIs("function")) {self.parseFunctions()} else:
1028
+ let term = self.parseTerm()
1029
+ if(!self.current().is(LAssign) && !self.current().is3(LAssignPlus, LAssignMinus, LAssignLink)) {term} else:
1030
+ let token = do {
1031
+ if(self.current().is(LAssignPlus)) {self.skip(LAssignPlus)} else:
1032
+ if(self.current().is(LAssignMinus)) {self.skip(LAssignMinus)} else:
1033
+ if(self.current().is(LAssignLink)) {self.skip(LAssignLink)} else:
1034
+ self.skip(LAssign)
1035
+ }
1036
+ let operator = token.raw().dropLast(1)
1037
+ let value = self.parseTerm()
1038
+ term.{
1039
+ | EVariable(at, name) => EAssign(at, operator, name, value)
1040
+ | EField e => EAssignField(e.at, operator, e.record, e.field, value)
1041
+ | _ => throw(CompileError(token.at(), "Only variables and fields are assignable"))
1042
+ }
1043
+ }
1044
+
1045
+ parseLet(): Term {
1046
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
1047
+ let mutableToken = self.current()
1048
+ let mutable = mutableToken.rawIs("mutable")
1049
+ let keywordToken = if(mutable) {self.rawSkip(LKeyword, "mutable")} else {self.rawSkip(LKeyword, "let")}
1050
+ let nameToken = self.skip(LLower)
1051
+ let valueType = if(!self.current().is(LColon)) {self.freshUnificationVariable(nameToken.at())} else {
1052
+ self.skip(LColon)
1053
+ self.parseType()
1054
+ }
1055
+ if(self.lspHook.isEnabled() && !self.current().is(LAssign)) {
1056
+ let unit = EVariant(keywordToken.at(), "Unit", [], None)
1057
+ ELet(nameToken.at(), mutable, nameToken.raw(), valueType, unit, unit)
1058
+ } else:
1059
+ self.skip(LAssign)
1060
+ let value = self.parseTerm()
1061
+ if(self.lspHook.trackSymbols) {
1062
+ let kind = if(mutable) {13} else {14}
1063
+ self.lspHook.emit(ParseSymbolEnd(
1064
+ name = nameToken.raw()
1065
+ kind = kind
1066
+ selectionStart = nameToken.at()
1067
+ selectionEnd = nameToken.end()
1068
+ start = mutableToken.at()
1069
+ end = self.behind().end()
1070
+ ))
1071
+ }
1072
+ let body = if(self.currentIsSeparator(LSemicolon)) {
1073
+ self.skipSeparator(LSemicolon)
1074
+ self.parseStatements()
1075
+ } else {
1076
+ EVariant(keywordToken.at(), "Unit", [], None)
1077
+ }
1078
+ ELet(nameToken.at(), mutable, nameToken.raw(), valueType, value, body)
1079
+ }
1080
+
1081
+ parseFunctions(): Term {
1082
+ let at = self.current().at()
1083
+ let functions = Stack.make[DFunction]()
1084
+ while {self.current().rawIs("function")} {
1085
+ if(self.lspHook.trackSymbols) {self.lspHook.emit(ParseSymbolBegin)}
1086
+ let functionAt = self.rawSkip(LKeyword, "function").at()
1087
+ let signature = self.parseSignature(member = False)
1088
+ let body = if(self.lspHook.isEnabled() && !self.current().rawIs("{")) {
1089
+ let temporaryEffect = TConstructor(functionAt, "TemporaryEffect$", [])
1090
+ Lambda(functionAt, temporaryEffect, [])
1091
+ } else {
1092
+ self.parseLambda(defaultParameterCount = signature.parameters.size())
1093
+ }
1094
+ functions.push(DFunction(signature.at, signature, FireflyTarget(body)))
1095
+ if(self.lspHook.trackSymbols) {
1096
+ self.lspHook.emit(ParseSymbolEnd(
1097
+ name = signature.name
1098
+ kind = 12
1099
+ selectionStart = signature.at
1100
+ selectionEnd = signature.at.Location(column = signature.at.column + signature.name.size())
1101
+ start = functionAt
1102
+ end = self.behind().end()
1103
+ ))
1104
+ }
1105
+ if(self.lspHook.isEnabled() && !self.currentIsSeparator(LSemicolon)) {} else {self.skipSeparator(LSemicolon)}
1106
+ }
1107
+ let body = self.parseStatements()
1108
+ EFunctions(at, functions.toList(), body)
1109
+ }
1110
+
1111
+ parseTerm(): Term {
1112
+ self.parseBinary(0)
1113
+ }
1114
+
1115
+ parseBinary(level: Int): Term {
1116
+ if(level >= binaryOperators.size()) {self.parseUnary()} else:
1117
+ let operators = binaryOperators.grab(level)
1118
+ mutable result = self.parseBinary(level + 1)
1119
+ if(self.current().is(LOperator)) {
1120
+ while {operators.any(self.current().rawIs)} {
1121
+ let token = self.skip(LOperator)
1122
+ let right = self.parseBinary(level + 1)
1123
+ let arguments = [Argument(result.at, None, result), Argument(right.at, None, right)]
1124
+ let effect = self.freshUnificationVariable(token.at())
1125
+ let target = token.raw().{
1126
+ | "==" => DynamicCall(EVariable(token.at(), "ff:core/Equal.equals"), False)
1127
+ | "!=" => DynamicCall(EVariable(token.at(), "ff:core/Equal.notEquals"), False)
1128
+ | "<" => DynamicCall(EVariable(token.at(), "ff:core/Ordering.before"), False)
1129
+ | "<=" => DynamicCall(EVariable(token.at(), "ff:core/Ordering.notAfter"), False)
1130
+ | ">" => DynamicCall(EVariable(token.at(), "ff:core/Ordering.after"), False)
1131
+ | ">=" => DynamicCall(EVariable(token.at(), "ff:core/Ordering.notBefore"), False)
1132
+ | o => DynamicCall(EVariable(token.at(), o), False)
1133
+ }
1134
+ result = ECall(token.at(), target, effect, [], arguments, [])
1135
+ }
1136
+ }
1137
+ result
1138
+ }
1139
+
1140
+ parseUnary(): Term {
1141
+ if(self.current().is(LOperator)) {
1142
+ let token = self.skip(LOperator)
1143
+ let term = self.parseUnary()
1144
+ let effect = self.freshUnificationVariable(token.at())
1145
+ let target = DynamicCall(EVariable(token.at(), token.raw()), False)
1146
+ ECall(token.at(), target, effect, [], [Argument(term.at, None, term)], [])
1147
+ } else {
1148
+ self.parseFieldsAndCalls()
1149
+ }
1150
+ }
1151
+
1152
+ parseFieldsAndCalls(): Term {
1153
+ let tailCall = if(self.current().is(LKeyword) && self.current().rawIs("tailcall")) {
1154
+ self.skip(LKeyword)
1155
+ True
1156
+ } else {False}
1157
+ mutable result = self.parseAtom()
1158
+ while {self.current().is(LBracketLeft) || self.current().is(LColon) || self.current().is(LDot)} {
1159
+ if(self.current().is(LDot)) {
1160
+ self.skip(LDot)
1161
+ if(self.current().rawIs("{")) {
1162
+ let term = self.parseAtom()
1163
+ let effect = self.freshUnificationVariable(term.at)
1164
+ result = EPipe(term.at, result, effect, term)
1165
+ } elseIf {self.current().is2(LUpper, LNamespace)} {
1166
+ result = self.parseCopy(result)
1167
+ } else {
1168
+ let token = self.skip(LLower)
1169
+ result = EField(token.at(), False, result, token.raw())
1170
+ }
1171
+ } else {
1172
+ let at = self.current().at()
1173
+ let typeArguments = if(!self.current().rawIs("[")) {[]} else {self.parseTypeArguments()}
1174
+ let arguments = self.parseFunctionArguments(result.at, True)
1175
+ let effect = self.freshUnificationVariable(at)
1176
+ let target = DynamicCall(result, tailCall)
1177
+ result = ECall(result.at, target, effect, typeArguments, arguments.first, [])
1178
+ if(arguments.second && self.current().is(LLower)) {
1179
+ let token = self.skip(LLower)
1180
+ result = EField(token.at(), False, result, token.raw())
1181
+ }
1182
+ }
1183
+ }
1184
+ result
1185
+ }
1186
+
1187
+ parseAtom(): Term {
1188
+ if(self.current().is(LString)) {
1189
+ let token = self.skip(LString)
1190
+ EString(token.at(), token.raw())
1191
+ } elseIf {self.current().is(LChar)} {
1192
+ let token = self.skip(LChar)
1193
+ EChar(token.at(), token.raw())
1194
+ } elseIf {self.current().is(LInt)} {
1195
+ let token = self.skip(LInt)
1196
+ EInt(token.at(), token.raw())
1197
+ } elseIf {self.current().is(LFloat)} {
1198
+ let token = self.skip(LFloat)
1199
+ EFloat(token.at(), token.raw())
1200
+ } elseIf {self.current().is(LLower)} {
1201
+ let token = self.skip(LLower)
1202
+ EVariable(token.at(), token.raw())
1203
+ } elseIf {self.current().is(LNamespace)} {
1204
+ let namespaceToken = self.skip(LNamespace)
1205
+ let extraNamespace = if(!self.current().is(LNamespace)) {None} else {Some(self.skip(LNamespace).raw())}
1206
+ let prefix = namespaceToken.raw() + extraNamespace.else {""}
1207
+ if(self.current().is(LLower)) {
1208
+ let token = self.skip(LLower)
1209
+ EVariable(token.at(), prefix + token.raw())
1210
+ } else {
1211
+ self.parseVariant(prefix)
1212
+ }
1213
+ } elseIf {self.current().is(LUpper)} {
1214
+ self.parseVariant("")
1215
+ } elseIf {self.current().rawIs("{")} {
1216
+ let lambda = self.parseLambda()
1217
+ ELambda(lambda.at, lambda)
1218
+ } elseIf {self.current().rawIs("[")} {
1219
+ self.parseList()
1220
+ } elseIf {self.current().rawIs("(") && self.ahead().is(LLower) && self.aheadAhead().is(LAssign)} {
1221
+ ERecord(self.current().at(), self.parseRecord(None))
1222
+ } elseIf {self.current().rawIs("(")} {
1223
+ self.rawSkip(LBracketLeft, "(")
1224
+ let result = self.parseTerm()
1225
+ while {self.lspHook.isEnabled() && self.currentIsSeparator(LComma)} {
1226
+ self.skipSeparator(LComma)
1227
+ if(!self.current().is(LBracketRight)) {self.parseTerm()}
1228
+ }
1229
+ self.rawSkip(LBracketRight, ")")
1230
+ result
1231
+ } elseIf {self.current().is(LWildcard)} {
1232
+ let token = self.skip(LWildcard)
1233
+ EWildcard(token.at(), 0)
1234
+ } else {
1235
+ throw(CompileError(self.current().at(), "Expected atom, got " + self.current().raw()))
1236
+ }
1237
+ }
1238
+
1239
+ parseVariant(prefix: String): Term {
1240
+ let token = self.skip(LUpper)
1241
+ let name = prefix + token.raw()
1242
+ let typeArguments = if(!self.current().rawIs("[")) {[]} else {self.parseTypeArguments()}
1243
+ if(self.current().rawIs("?")) {self.skip(LOperator); EVariantIs(token.at(), name, typeArguments)} else:
1244
+ let arguments = Some(self.parseFunctionArguments(token.at(), True))
1245
+ EVariant(token.at(), name, typeArguments, arguments.map {_.first})
1246
+ }
1247
+
1248
+ parseCopy(record: Term): Term {
1249
+ let namespace = if(!self.current().is(LNamespace)) {""} else {self.skip(LNamespace).raw()}
1250
+ let extraNamespace = if(!self.current().is(LNamespace)) {""} else {self.skip(LNamespace).raw()}
1251
+ let prefix = namespace + extraNamespace
1252
+ let token = self.skip(LUpper)
1253
+ let name = prefix + token.raw()
1254
+ let fields = if(self.lspHook.isEnabled() && !self.current().rawIs("(")) {[]} else {self.parseRecord(Some(token.at()))}
1255
+ ECopy(token.at(), name, record, fields)
1256
+ }
1257
+
1258
+ parseRecord(copyAt: Option[Location]): List[Field] {
1259
+ let fields = Stack.make[Field]()
1260
+ let startBracketAt = self.rawSkip(LBracketLeft, "(").at()
1261
+ let startAt = copyAt.else {startBracketAt}
1262
+ while {!self.current().is(LBracketRight)} {
1263
+ let fieldToken = self.skip(LLower)
1264
+ let field = if(!self.lspHook.isEnabled() || self.current().is(LAssign)) {
1265
+ self.skip(LAssign)
1266
+ Field(fieldToken.at(), fieldToken.raw(), self.parseTerm())
1267
+ } else {
1268
+ Field(fieldToken.at(), fieldToken.raw(), EVariable(fieldToken.at(), fieldToken.raw()))
1269
+ }
1270
+ if(self.lspHook.isEnabled() && !self.lspEmittedArgumentHook) {
1271
+ if(LspHook.strictlyBetween(startAt, self.current().at(), self.lspHook.at, 1)) {
1272
+ self.lspHook.emit(ParseArgumentHook(startAt, fields.size(), Some(field.name).filter {_ != ""}))
1273
+ self.lspEmittedArgumentHook = True
1274
+ }
1275
+ }
1276
+ fields.push(field)
1277
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LComma)}
1278
+ }
1279
+ if(self.lspHook.isEnabled() && !self.lspEmittedArgumentHook) {
1280
+ if(LspHook.strictlyBetween(startAt, self.current().at(), self.lspHook.at, 1)) {
1281
+ self.lspHook.emit(ParseArgumentHook(startAt, fields.size(), None))
1282
+ self.lspEmittedArgumentHook = True
1283
+ }
1284
+ }
1285
+ self.rawSkip(LBracketRight, ")")
1286
+ fields.toList()
1287
+ }
1288
+
1289
+ parseRecordType(): List[Pair[String, Type]] {
1290
+ let fields = Stack.make[Pair[String, Type]]()
1291
+ self.rawSkip(LBracketLeft, "(")
1292
+ while {!self.current().is(LBracketRight)} {
1293
+ let fieldToken = self.skip(LLower)
1294
+ self.skipSeparator(LColon)
1295
+ fields.push(Pair(fieldToken.raw(), self.parseType()))
1296
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LComma)}
1297
+ }
1298
+ self.rawSkip(LBracketRight, ")")
1299
+ fields.toList().sortBy {_.first}
1300
+ }
1301
+
1302
+ parseRecordPattern(): List[Pair[String, MatchPattern]] {
1303
+ let fields = Stack.make[Pair[String, MatchPattern]]()
1304
+ self.rawSkip(LBracketLeft, "(")
1305
+ while {!self.current().is(LBracketRight)} {
1306
+ let fieldToken = self.skip(LLower)
1307
+ self.skip(LAssign)
1308
+ fields.push(Pair(fieldToken.raw(), self.parsePattern()))
1309
+ if(!self.current().is(LBracketRight)) {self.skipSeparator(LComma)}
1310
+ }
1311
+ self.rawSkip(LBracketRight, ")")
1312
+ fields.toList().sortBy {_.first}
1313
+ }
1314
+
1315
+ parseListPattern(): MatchPattern {
1316
+ function convertListPattern(at: Location, items: List[Pair[MatchPattern, Bool]]): MatchPattern {
1317
+ | _, [] => PVariant(at, "ff:core/List.Empty", [])
1318
+ | _, [Pair(p, False), ...ps] =>
1319
+ PVariant(at, "ff:core/List.Link", [p, convertListPattern(at, ps)])
1320
+ | _, [Pair(p, True)] => p
1321
+ | _, [Pair(p, True), ...] =>
1322
+ throw(CompileError(p.at, "Invalid pattern: ... is only allowed for the last element in a list"))
1323
+ }
1324
+ let items = Stack.make[Pair[MatchPattern, Bool]]()
1325
+ let at = self.rawSkip(LBracketLeft, "[").at()
1326
+ while {!self.current().rawIs("]")} {
1327
+ let spread = self.current().is(LDotDotDot)
1328
+ if(spread) {self.skip(LDotDotDot)}
1329
+ let pattern = if(spread && self.current().rawIs("]")) {
1330
+ PVariable(self.current().at(), None)
1331
+ } else {
1332
+ self.parsePattern()
1333
+ }
1334
+ items.push(Pair(pattern, spread))
1335
+ if(!self.current().rawIs("]")) {self.skipSeparator(LComma)}
1336
+ }
1337
+ self.rawSkip(LBracketRight, "]")
1338
+ convertListPattern(at, items.toList())
1339
+ }
1340
+
1341
+ parseList(): Term {
1342
+ let items = Stack.make[Pair[Term, Bool]]()
1343
+ let at = self.rawSkip(LBracketLeft, "[").at()
1344
+ while {!self.current().rawIs("]")} {
1345
+ let spread = self.current().is(LDotDotDot)
1346
+ if(spread) {self.skip(LDotDotDot)}
1347
+ items.push(Pair(self.parseTerm(), spread))
1348
+ if(!self.current().rawIs("]")) {self.skipSeparator(LComma)}
1349
+ }
1350
+ self.rawSkip(LBracketRight, "]")
1351
+ EList(at, self.freshUnificationVariable(at), items.toList())
1352
+ }
1353
+
1354
+ }
1355
+
1356
+ binaryOperators = [
1357
+ ["||"]
1358
+ ["&&"]
1359
+ ["!=", "=="]
1360
+ ["<=", ">=", "<", ">"]
1361
+ ["+", "-"]
1362
+ ["*", "/", "%"]
1363
+ ["^"]
1364
+ ].toArray()
1365
+
1366
+ findBestTarget(targetIsNode: Bool, body: Option[Lambda], targets: ParsedTargets): Target {
1367
+ let foreignTarget = if(targetIsNode) {
1368
+ let sync = targets.nodeSync.orElse {targets.jsSync}
1369
+ let async = targets.nodeAsync.orElse {targets.jsAsync}
1370
+ ForeignTarget(sync, async)
1371
+ } else {
1372
+ let sync = targets.browserSync.orElse {targets.jsSync}
1373
+ let async = targets.browserAsync.orElse {targets.jsAsync}
1374
+ ForeignTarget(sync, async)
1375
+ }
1376
+ foreignTarget.{
1377
+ | ForeignTarget(None, None) {targetIsNode} =>
1378
+ targets.node.orElse {targets.js.orElse {body}}.map {FireflyTarget(_)}.else {foreignTarget}
1379
+ | ForeignTarget(None, None) {!targetIsNode} =>
1380
+ targets.browser.orElse {targets.js.orElse {body}}.map {FireflyTarget(_)}.else {foreignTarget}
1381
+ | _ => foreignTarget
1382
+ }
1383
+ }