firefly-compiler 0.5.62 → 0.5.64

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 (60) hide show
  1. package/compiler/Builder.ff +47 -31
  2. package/compiler/Compiler.ff +42 -47
  3. package/compiler/Dependencies.ff +4 -2
  4. package/compiler/Deriver.ff +2 -2
  5. package/compiler/Dictionaries.ff +11 -12
  6. package/compiler/Environment.ff +5 -5
  7. package/compiler/Inference.ff +1 -2
  8. package/compiler/JsEmitter.ff +34 -33
  9. package/compiler/Main.ff +32 -31
  10. package/compiler/ModuleCache.ff +17 -25
  11. package/compiler/Parser.ff +7 -11
  12. package/compiler/Resolver.ff +8 -11
  13. package/compiler/Syntax.ff +53 -17
  14. package/compiler/Unification.ff +2 -5
  15. package/core/BuildSystem.ff +1 -1
  16. package/core/Path.ff +11 -1
  17. package/core/SourceLocation.ff +4 -0
  18. package/experimental/foldertest/.firefly/package.ff +1 -0
  19. package/experimental/foldertest/Root.ff +10 -0
  20. package/experimental/foldertest/a/A.ff +3 -0
  21. package/experimental/foldertest/a/MainA.ff +3 -0
  22. package/experimental/tests/TestCancel.ff +19 -0
  23. package/fireflysite/CommunityOverview.ff +0 -2
  24. package/fireflysite/FrontPage.ff +0 -2
  25. package/fireflysite/Main.ff +1 -1
  26. package/fireflysite/PackagesOverview.ff +0 -2
  27. package/fireflysite/Router.ff +3 -3
  28. package/fireflysite/{ExamplesOverview.ff → demos/ExamplesOverview.ff} +3 -3
  29. package/fireflysite/{RouteFront.ff → routes/RouteFront.ff} +2 -3
  30. package/fireflysite/{RouteNonMarkdown.ff → routes/RouteNonMarkdown.ff} +5 -5
  31. package/fireflysite/{RouteReference.ff → routes/RouteReference.ff} +2 -3
  32. package/lsp/CompletionHandler.ff +2 -2
  33. package/lsp/Handler.ff +14 -13
  34. package/lsp/LanguageServer.ff +5 -4
  35. package/output/js/ff/compiler/Builder.mjs +118 -80
  36. package/output/js/ff/compiler/Compiler.mjs +85 -89
  37. package/output/js/ff/compiler/Dependencies.mjs +6 -8
  38. package/output/js/ff/compiler/Deriver.mjs +6 -6
  39. package/output/js/ff/compiler/Dictionaries.mjs +6 -6
  40. package/output/js/ff/compiler/Environment.mjs +10 -6
  41. package/output/js/ff/compiler/Inference.mjs +4 -4
  42. package/output/js/ff/compiler/JsEmitter.mjs +60 -38
  43. package/output/js/ff/compiler/Main.mjs +66 -56
  44. package/output/js/ff/compiler/ModuleCache.mjs +34 -38
  45. package/output/js/ff/compiler/Parser.mjs +14 -14
  46. package/output/js/ff/compiler/Resolver.mjs +12 -22
  47. package/output/js/ff/compiler/Substitution.mjs +2 -2
  48. package/output/js/ff/compiler/Syntax.mjs +395 -183
  49. package/output/js/ff/compiler/Unification.mjs +18 -32
  50. package/output/js/ff/core/BuildSystem.mjs +2 -6
  51. package/output/js/ff/core/Path.mjs +32 -0
  52. package/output/js/ff/core/SourceLocation.mjs +12 -0
  53. package/package.json +1 -1
  54. package/vscode/client/src/extension.ts +1 -1
  55. package/vscode/package.json +2 -2
  56. package/vscode/syntaxes/firefly.tmLanguage.json +299 -299
  57. package/fireflysite/ReferenceIntroduction.ff +0 -11
  58. /package/fireflysite/{CountingButtonDemo.ff → demos/CountingButtonDemo.ff} +0 -0
  59. /package/fireflysite/{MatchingPasswordsDemo.ff → demos/MatchingPasswordsDemo.ff} +0 -0
  60. /package/fireflysite/{PostgresqlDemo.ff → demos/PostgresqlDemo.ff} +0 -0
@@ -13,8 +13,7 @@ import DependencyLock
13
13
  build(
14
14
  system: NodeSystem
15
15
  emitTarget: EmitTarget
16
- mainPackage: PackagePair
17
- mainModules: List[String]
16
+ mainModules: List[ModuleKey]
18
17
  resolvedDependencies: ResolvedDependencies
19
18
  compilerModulePath: Option[Path]
20
19
  tempPath: Path
@@ -40,9 +39,7 @@ build(
40
39
  moduleCache
41
40
  lspHook = LspHook.disabled()
42
41
  )
43
- mainModules.each {mainModule =>
44
- compiler.emit(mainPackage, mainModule, isMainModule = True)
45
- }
42
+ mainModules.each {moduleKey => compiler.emit(moduleKey, isMainModule = True)}
46
43
  if(printMeasurements) {compiler.printMeasurements()}
47
44
  resolvedDependencies.packagePaths.each {packagePair, packagePath =>
48
45
  resolvedDependencies.packages.get(packagePair).each {packageInfo =>
@@ -87,29 +84,33 @@ processNodeModules(system: NodeSystem, jsPathFile: Path, packagePath: Path, info
87
84
  }
88
85
  }
89
86
 
90
- buildViaBuildSystem(system: NodeSystem, fireflyPath: Path, mainFiles: List[String], target: String) {
91
- let mainPaths = mainFiles.map {system.path(_).parent().grab().absolute()}
92
- mainPaths.find {_ != mainPaths.grabFirst()}.each {path =>
93
- panic("Can't build multiple main files in different directories: " + path + " vs. " + mainPaths.grabFirst())
94
- }
87
+ buildViaBuildSystem(system: NodeSystem, fireflyPath: Path, mainFiles: List[Path], target: String) {
95
88
  let resolvedDependencies = Dependencies.process(
96
89
  system.httpClient()
97
90
  DependencyLock.new(system.mainTask())
98
- system.path(mainFiles.grabFirst())
91
+ mainFiles.grabFirst()
99
92
  )
100
93
  let fixedPackagePaths = if(resolvedDependencies.packagePaths.contains(PackagePair("ff", "core"))) {
101
94
  resolvedDependencies.packagePaths
102
95
  } else {
103
96
  resolvedDependencies.packagePaths.add(PackagePair("ff", "core"), fireflyPath.slash("core"))
104
97
  }
98
+ let packageRoot = resolvedDependencies.packagePaths.grab(resolvedDependencies.mainPackagePair)
99
+ let mainModuleKeys = mainFiles.map {mainFile =>
100
+ resolvedDependencies.mainPackagePair.moduleKey(packageRoot, mainFile).else {
101
+ panic(
102
+ "Can't build multiple main files in different packages: " +
103
+ mainFile.absolute() + " isn't part of " + packageRoot.absolute()
104
+ )
105
+ }
106
+ }
105
107
  if(target != "browser") {
106
108
  panic("buildViaBuildSystem is currently limited to browser target only - the restriction can be lifted")
107
109
  }
108
110
  build(
109
111
  system = system
110
112
  emitTarget = EmitBrowser
111
- mainPackage = resolvedDependencies.mainPackagePair
112
- mainModules = mainFiles.map {_.dropLast(".ff".size())}
113
+ mainModules = mainModuleKeys
113
114
  resolvedDependencies = resolvedDependencies.ResolvedDependencies(packagePaths = fixedPackagePaths)
114
115
  compilerModulePath = None
115
116
  tempPath = system.path(".firefly/temporary")
@@ -131,16 +132,16 @@ check(
131
132
  newVersion: Int
132
133
  lspHook: LspHook
133
134
  infer: Bool
134
- checkDependencies: Bool
135
135
  ): List[CompileError] {
136
136
  let packages = path.isDirectory().{
137
- | True => findPackageFiles(path, mustContain, skipFiles)
138
137
  | False {path.endsWith([".firefly", "package.ff"])} => [PackageFiles(path.parent().grab(), Some(path), [])]
139
- | False => [PackageFiles(path.parent().grab(), None, [path])]
138
+ | True => findPackageFilesForDirectory(path, mustContain, skipFiles)
139
+ | False => findPackageFilesForFile(path).toList()
140
140
  }
141
141
  let errors = Array.new()
142
142
 
143
- packages.filter {!_.files.isEmpty()}.each {package =>
143
+ let filteredPackages = packages.filter {!_.root.contains([".firefly", "dependencies"])}
144
+ filteredPackages.filter {!_.files.isEmpty()}.each {package =>
144
145
  let firstFile = package.files.grabFirst()
145
146
  try {
146
147
  Some(Dependencies.process(system.httpClient(), dependencyLock, firstFile))
@@ -168,16 +169,16 @@ check(
168
169
  newCache
169
170
  lspHook
170
171
  )
171
- let files = if(checkDependencies) {package.files} else {
172
- package.files.filter {!_.contains([".firefly", "dependencies"])}
173
- }
174
- files.each {file =>
175
- let localFile = file.base()
172
+ package.files.each {file =>
173
+ let packagePair = resolvedDependencies.mainPackagePair
174
+ let folders = file.parent().grab().relativeListTo(package.root)
175
+ let name = file.base().removeLast(".ff").grab()
176
+ let moduleKey = ModuleKey(packagePair, folders, name)
176
177
  try {
177
178
  if(infer) {
178
- compiler.infer(resolvedDependencies.mainPackagePair, localFile.dropLast(".ff".size()))
179
+ compiler.infer(moduleKey)
179
180
  } else {
180
- compiler.resolve(resolvedDependencies.mainPackagePair, localFile.dropLast(".ff".size()))
181
+ compiler.resolve(moduleKey)
181
182
  }
182
183
  } tryCatch {| CompileError(_, _) @ c, error =>
183
184
  errors.push(c)
@@ -198,12 +199,24 @@ capability PackageFiles(
198
199
  )
199
200
 
200
201
 
201
- findPackageFiles(
202
- path: Path
202
+ findPackageFilesForFile(file: Path): Option[PackageFiles] {
203
+ if(file.extension() == ".ff"):
204
+ mutable packageFile = None
205
+ mutable currentDirectory = file.parent()
206
+ while {!currentDirectory.isEmpty() && packageFile.isEmpty()} {
207
+ packageFile = currentDirectory.map {_.slash(".firefly").slash("package.ff")}.filter {_.exists()}
208
+ currentDirectory = currentDirectory.grab().parent()
209
+ }
210
+ let projectRoot = packageFile.map {_.parent().grab().parent().grab()}.else {file.parent().grab()}
211
+ PackageFiles(projectRoot, packageFile, [file])
212
+ }
213
+
214
+ findPackageFilesForDirectory(
215
+ directory: Path
203
216
  mustContain: Option[String]
204
217
  skipFiles: Set[String]
205
218
  ): List[PackageFiles] {
206
- let files = findFireflyFiles(path, mustContain, skipFiles)
219
+ let files = findFireflyFiles(directory, mustContain, skipFiles)
207
220
  let split = files.partition {_.endsWith([".firefly", "package.ff"])}
208
221
  let packageFiles = split.first
209
222
  mutable singleFiles = split.second
@@ -211,7 +224,8 @@ findPackageFiles(
211
224
  let projectRoot = packageFile.parent().grab().parent().grab()
212
225
  let files = singleFiles.partition {_.isInsideOf(projectRoot)}
213
226
  singleFiles = files.second
214
- PackageFiles(projectRoot, Some(packageFile), files.first)
227
+ let packageFiles = files.first
228
+ PackageFiles(projectRoot, Some(packageFile), packageFiles)
215
229
  }
216
230
  let singleFileProjects = singleFiles.map {file =>
217
231
  let projectRoot = file.parent().grab()
@@ -226,15 +240,17 @@ findFireflyFiles(
226
240
  skipFiles: Set[String]
227
241
  ): List[Path] {
228
242
  let split = path.entries().toList().partition {_.isDirectory()}
229
- let directories = split.first.map {_.path()}.filter {_.base().all {c =>
243
+ let directories = split.first
244
+ let files = split.second
245
+ let relevantDirectories = directories.map {_.path()}.filter {_.base().all {c =>
230
246
  c == '.' || c.isAsciiLower() || c.isAsciiDigit()
231
247
  }}
232
- let fireflyFiles = split.second.map {_.path()}.filter {file =>
248
+ let fireflyFiles = files.map {_.path()}.filter {file =>
233
249
  file.extension() == ".ff" && !skipFiles.contains(file.absolute()) && mustContain.all {s =>
234
250
  file.readText().contains(s)
235
251
  }
236
252
  }
237
- [...fireflyFiles, ...directories.flatMap {findFireflyFiles(_, mustContain, skipFiles)}]
253
+ [...fireflyFiles, ...relevantDirectories.flatMap {findFireflyFiles(_, mustContain, skipFiles)}]
238
254
  }
239
255
 
240
256
  internalCreateExecutable(
@@ -106,21 +106,19 @@ coreImports: List[DImport] =
106
106
  DImport(
107
107
  at = Location("<prelude>", 1, 1)
108
108
  alias = moduleName
109
- package = PackagePair("ff", "core")
110
- directory = []
111
- file = moduleName
109
+ moduleKey = ModuleKey(PackagePair("ff", "core"), [], moduleName)
112
110
  )
113
111
  }
114
112
 
115
113
  extend self: Compiler {
116
114
 
117
- measure[T](phase: String, packagePair: PackagePair, moduleName: String, body: () => T): T {
115
+ measure[T](phase: String, moduleKey: ModuleKey, body: () => T): T {
118
116
  let start = Duration(self.task.elapsed().seconds - self.phaseDurationDelta.seconds)
119
117
  let result = body()
120
118
  let stop = Duration(self.task.elapsed().seconds - self.phaseDurationDelta.seconds)
121
119
  let duration = Duration(stop.seconds - start.seconds)
122
120
  self.phaseDurationDelta = Duration(self.phaseDurationDelta.seconds + duration.seconds)
123
- let text = phase + " " + packagePair.groupName() + "/" + moduleName
121
+ let text = phase + " " + moduleKey.qualifiedName()
124
122
  self.phaseDurations.push(Pair(text, duration))
125
123
  result
126
124
  }
@@ -134,20 +132,19 @@ extend self: Compiler {
134
132
  }
135
133
  }
136
134
 
137
- parse(packagePair: PackagePair, moduleName: String, importedAt: Option[Location]): Module {
138
- self.cache.cacheParsedModule(self.packagePaths, packagePair, moduleName): path =>
139
- let packageName = packagePair.groupName()
140
- self.measure("Parse", packagePair, moduleName):
135
+ parse(moduleKey: ModuleKey, importedAt: Option[Location]): Module {
136
+ self.cache.cacheParsedModule(self.packagePaths, moduleKey): path =>
137
+ self.measure("Parse", moduleKey):
141
138
  let code = self.virtualFiles.get(path.absolute()).else {
142
139
  importedAt.each {at => if(!path.exists()) {
143
- throw(CompileError(at, "Imported module not found: " + packageName + "/" + moduleName))
140
+ throw(CompileError(at, "Imported module not found: " + moduleKey.importName()))
144
141
  }}
145
142
  path.readText()
146
143
  }
147
144
  let completionAt = if(self.lspHook.isEnabled() && self.lspHook.insertIdentifier) {self.lspHook.at}
148
145
  let tokens = Tokenizer.tokenize(path.absolute(), code, completionAt, self.lspHook.isEnabled())
149
- let parser = Parser.new(packagePair, path.base(), tokens, self.emitTarget != EmitBrowser, self.lspHook)
150
- let module = if(self.singleFilePackages.contains(packagePair)) {
146
+ let parser = Parser.new(moduleKey, tokens, self.emitTarget != EmitBrowser, self.lspHook)
147
+ let module = if(self.singleFilePackages.contains(moduleKey.packagePair)) {
151
148
  parser.parseModuleWithPackageInfo().module
152
149
  } else {
153
150
  parser.parseModuleWithoutPackageInfo()
@@ -160,63 +157,61 @@ extend self: Compiler {
160
157
 
161
158
  imports(module: Module): List[Module] {
162
159
  module.imports.map {import =>
163
- let newPackagePair = import.package
164
- let newModuleName = import.directory.map {_ + "/"}.join("") + import.file
160
+ let newPackagePair = import.moduleKey.packagePair
165
161
  if(!self.packagePaths.contains(newPackagePair)) {
166
162
  throw(CompileError(import.at, "Missing dependency declaration for: " + newPackagePair.groupName()))
167
163
  }
168
164
  try {
169
- self.parse(newPackagePair, newModuleName, Some(import.at))
165
+ self.parse(import.moduleKey, Some(import.at))
170
166
  } tryCatch {| CompileError(_, _) @ e, error =>
171
- let newError = CompileError(import.at, "Parse error in imported module: " + import.package.groupName() + "/" + newModuleName)
167
+ let newError = CompileError(import.at, "Parse error in imported module: " + import.moduleKey.importName())
172
168
  throw(CompileErrors([e, newError]))
173
169
  } catch {| CompileErrors(compileErrors), error =>
174
- let newError = CompileError(import.at, "Parse errors in imported module: " + import.package.groupName() + "/" + newModuleName)
170
+ let newError = CompileError(import.at, "Parse errors in imported module: " + import.moduleKey.importName())
175
171
  throw(CompileErrors([...compileErrors, newError]))
176
172
  }
177
173
  }
178
174
  }
179
175
 
180
- resolve(packagePair: PackagePair, moduleName: String): Module {
181
- self.cache.cacheResolvedModule(self.packagePaths, packagePair, moduleName): path =>
182
- self.measure("Resolve", packagePair, moduleName):
176
+ resolve(moduleKey: ModuleKey): Module {
177
+ self.cache.cacheResolvedModule(self.packagePaths, moduleKey): path =>
178
+ self.measure("Resolve", moduleKey):
183
179
 
184
- let module = self.parse(packagePair, moduleName, None)
180
+ let module = self.parse(moduleKey, None)
185
181
  let otherModules = self.imports(module)
186
- let resolver = Resolver.new(packagePair, moduleName, self.lspHook)
182
+ let resolver = Resolver.new(self.lspHook)
187
183
  resolver.resolveModule(module, otherModules)
188
184
  }
189
185
 
190
- derive(packagePair: PackagePair, moduleName: String): Module {
191
- self.cache.cacheDerivedModule(self.packagePaths, packagePair, moduleName): path =>
192
- self.measure("Derive", packagePair, moduleName):
186
+ derive(moduleKey: ModuleKey): Module {
187
+ self.cache.cacheDerivedModule(self.packagePaths, moduleKey): path =>
188
+ self.measure("Derive", moduleKey):
193
189
 
194
- let module = self.resolve(packagePair, moduleName)
190
+ let module = self.resolve(moduleKey)
195
191
  Deriver.new().deriveModule(module)
196
192
  }
197
193
 
198
- infer(packagePair: PackagePair, moduleName: String): Module {
199
- self.cache.cacheInferredModule(self.packagePaths, packagePair, moduleName): path =>
200
- self.measure("Infer", packagePair, moduleName):
194
+ infer(moduleKey: ModuleKey): Module {
195
+ self.cache.cacheInferredModule(self.packagePaths, moduleKey): path =>
196
+ self.measure("Infer", moduleKey):
201
197
 
202
- let module = self.derive(packagePair, moduleName)
198
+ let module = self.derive(moduleKey)
203
199
  let otherModules = self.imports(module).map {i =>
204
- self.derive(i.packagePair, i.file.dropLast(".ff".size()))
200
+ self.derive(i.moduleKey)
205
201
  }
206
202
  let inference = Inference.new([module, ...otherModules], self.lspHook)
207
203
  let inferredModule = inference.inferModule(module, otherModules)
208
204
  Dictionaries.new([module, ...otherModules]).processModule(inferredModule, otherModules)
209
205
  }
210
206
 
211
- emit(packagePair: PackagePair, moduleName: String, isMainModule: Bool): Unit {
212
- self.cache.cacheEmittedModule(self.packagePaths, packagePair, moduleName, isMainModule): path =>
213
- self.measure("Emit", packagePair, moduleName):
207
+ emit(moduleKey: ModuleKey, isMainModule: Bool): Unit {
208
+ self.cache.cacheEmittedModule(self.packagePaths, moduleKey, isMainModule): path =>
209
+ self.measure("Emit", moduleKey):
214
210
 
215
- let module = self.infer(packagePair, moduleName)
211
+ let module = self.infer(moduleKey)
216
212
  let otherModules = self.imports(module).map {i =>
217
- let newModuleName = i.file.dropLast(".ff".size())
218
- self.emit(i.packagePair, newModuleName, isMainModule = False)
219
- self.infer(i.packagePair, newModuleName)
213
+ self.emit(i.moduleKey, isMainModule = False)
214
+ self.infer(i.moduleKey)
220
215
  }
221
216
 
222
217
  let allModules = [module, ...otherModules]
@@ -225,22 +220,22 @@ extend self: Compiler {
225
220
  emitTarget = self.emitTarget
226
221
  isMainModule = isMainModule
227
222
  compilerModuleFileUrl = self.compilerModulePath.map {_.url()}
228
- packagePair = packagePair
229
- moduleName = moduleName
223
+ moduleKey = moduleKey
230
224
  )
231
- let js = emitter.emitModule(packagePair, module)
232
- let jsPath = self.jsOutputPath.slash(packagePair.group).slash(packagePair.name)
233
- let jsFile = jsPath.slash(moduleName + ".mjs")
225
+ let js = emitter.emitModule(module)
226
+ let packagePath = self.jsOutputPath.slash(moduleKey.packagePair.group).slash(moduleKey.packagePair.name)
227
+ let jsPath = moduleKey.folders.foldLeft(packagePath) {p, f => p.slash(f)}
228
+ let jsFile = jsPath.slash(moduleKey.name + ".mjs")
234
229
  jsPath.createDirectory(createParentDirectories = True)
235
230
  jsFile.writeText(js)
236
231
  if(isMainModule) {
237
232
  let runJs = emitter.emitRun(
238
- moduleName
233
+ moduleKey.name
239
234
  module.functions
240
- packagePair
241
- packagePair.group == "ff" && packagePair.name == "compiler"
235
+ moduleKey.packagePair
236
+ moduleKey.packagePair.group == "ff" && moduleKey.packagePair.name == "compiler"
242
237
  )
243
- let jsRunFile = jsPath.slash(moduleName + ".run.mjs")
238
+ let jsRunFile = jsPath.slash(moduleKey.name + ".run.mjs")
244
239
  jsRunFile.writeText(runJs.map {_ + "\n"}.join())
245
240
  }
246
241
  }
@@ -25,7 +25,8 @@ extend self: Dependencies {
25
25
  packagePair: PackagePair
26
26
  path: Path
27
27
  ): Option[PackageInfo] {
28
- let packageDirectory = if(path.extension() == ".ff") {path.parent().grab()} else {path}
28
+ //let packageDirectory = if(path.extension() == ".ff") {path.parent().grab()} else {path}
29
+ let packageDirectory = findScriptPackageLocation(path)
29
30
  let sharedPackageFile = packageDirectory.slash(".firefly").slash("package.ff")
30
31
  let packageFile = if(sharedPackageFile.exists()) {
31
32
  sharedPackageFile
@@ -43,7 +44,8 @@ extend self: Dependencies {
43
44
  code: String
44
45
  ): PackageInfo {
45
46
  let tokens = Tokenizer.tokenize(fileName, code, None, True)
46
- let parser = Parser.new(packagePair, fileName, tokens, False, LspHook.disabled())
47
+ let moduleKey = ModuleKey(packagePair, [], "<package>")
48
+ let parser = Parser.new(moduleKey, tokens, False, LspHook.disabled())
47
49
  let info = parser.parsePackageInfo()
48
50
  self.addCoreDependencyIfMissing(info)
49
51
  }
@@ -14,7 +14,7 @@ extend self: Deriver {
14
14
 
15
15
  deriveModule(module: Module): Module {
16
16
 
17
- let modulePrefix = module.packagePair.groupName() + "/" + module.file.dropLast(3)
17
+ let modulePrefix = module.moduleKey.qualifiedName()
18
18
 
19
19
  module.Module(
20
20
  instances = [
@@ -620,7 +620,7 @@ extend self: Deriver {
620
620
  }.toSet()
621
621
 
622
622
  module.types.filter {t =>
623
- (module.packagePair.groupName() != "ff:core" || coreWhitelist.contains(modulePrefix + "." + t.name)) &&
623
+ (!module.moduleKey.packagePair.isCore() || coreWhitelist.contains(modulePrefix + "." + t.name)) &&
624
624
  !t.generics.first().any {_ == "Q$"} &&
625
625
  (allowGenerics || t.generics.isEmpty()) &&
626
626
  t.data && !t.newtype &&
@@ -23,17 +23,17 @@ extend self: Dictionaries {
23
23
  | _ => None
24
24
  }.toMap()
25
25
 
26
- let lets = module.lets.map { self.processLetDefinition(functionSignatures, _) }
27
- let functions = module.functions.map { self.processFunctionDefinition(functionSignatures, _) }
28
- let extends = module.extends.map { self.processExtendDefinition(functionSignatures, _) }
29
- //let traits = module.traits.map { self.processTraitDefinition(functionSignatures, _) }
30
- let instances = module.instances.map { self.processInstanceDefinition(functionSignatures, _) }
26
+ let lets = module.lets.map {self.processLetDefinition(functionSignatures, _)}
27
+ let functions = module.functions.map {self.processFunctionDefinition(functionSignatures, _)}
28
+ let extends = module.extends.map {self.processExtendDefinition(functionSignatures, _)}
29
+ //let traits = module.traits.map {self.processTraitDefinition(functionSignatures, _)}
30
+ let instances = module.instances.map {self.processInstanceDefinition(functionSignatures, _)}
31
31
  module.Module(
32
32
  //traits = traits,
33
- instances = instances,
34
- extends = extends,
35
- lets = lets,
36
- functions = functions,
33
+ instances = instances
34
+ extends = extends
35
+ lets = lets
36
+ functions = functions
37
37
  )
38
38
  }
39
39
 
@@ -177,7 +177,7 @@ extend self: Dictionaries {
177
177
  let dictionaries = instance.constraints.map {c =>
178
178
  self.makeDictionary(at, instance.generics, firstType.generics, c)
179
179
  }
180
- Dictionary(instance.packagePair, instance.moduleName, constraint.name, firstType.name, dictionaries)
180
+ Dictionary(instance.moduleKey, constraint.name, firstType.name, dictionaries)
181
181
  | TVariable t => fail(t.at, " is still a unification variable")
182
182
  }
183
183
  }
@@ -195,8 +195,7 @@ constraintsToInstances(constraints: List[Constraint]): Map[InstanceKey, Instance
195
195
  InstanceValue(
196
196
  generics = []
197
197
  constraints = []
198
- packagePair = PackagePair("", "")
199
- moduleName = ""
198
+ moduleKey = ModuleKey(PackagePair("", ""), [], "")
200
199
  traitName = c.name
201
200
  typeArguments = c.generics
202
201
  )
@@ -25,19 +25,19 @@ data Instantiated(
25
25
  new(module: Module, otherModules: List[Module], alreadyFlat: Bool): Environment {
26
26
  let processed = processModule(module, True, alreadyFlat)
27
27
  let otherProcessed = otherModules.map {processModule(_, False, False)}
28
+ let modulePath = module.moduleKey.importName() + ".ff" // TODO
28
29
  Environment(
29
30
  modulePrefix = fullName(module, "")
30
31
  symbols = processed.symbols.addAll(otherProcessed.map {_.symbols}.foldLeft(Map.new()) {_.addAll(_)})
31
32
  traits = processed.traits.addAll(otherProcessed.map {_.traits}.foldLeft(Map.new()) {_.addAll(_)})
32
33
  imports = module.imports.map {i => Pair(i.alias, i)}.toMap()
33
- effect = TConstructor(Location(module.file, 0, 0), "ff:core/Nothing.Nothing", [])
34
+ effect = TConstructor(Location(modulePath, 0, 0), "ff:core/Nothing.Nothing", [])
34
35
  selfVariable = None
35
36
  )
36
37
  }
37
38
 
38
39
  fullName(module: Module, name: String): String {
39
- module.packagePair.groupName() + "/" +
40
- module.file.dropLast(3) + "." + name
40
+ module.moduleKey.qualifiedSymbol(name)
41
41
  }
42
42
 
43
43
  fail[T](at: Location, message: String): T {
@@ -154,8 +154,8 @@ processModule(module: Module, isCurrentModule: Bool, alreadyFlat: Bool): Environ
154
154
  module.traits.map {d =>
155
155
  Pair(fullName(module, d.name), d)
156
156
  }
157
-
158
- let effect = TConstructor(Location(module.file, 0, 0), "ff:core/Nothing.Nothing", [])
157
+ let modulePath = module.moduleKey.importName() + ".ff" // TODO
158
+ let effect = TConstructor(Location(modulePath, 0, 0), "ff:core/Nothing.Nothing", [])
159
159
  Environment(
160
160
  modulePrefix = ""
161
161
  symbols = [...functions, ...lets, ...fields, ...extends, ...variants, ...traitMethods].toMap()
@@ -1225,8 +1225,7 @@ constraintsToInstances(constraints: List[Constraint]): Map[InstanceKey, Instance
1225
1225
  InstanceValue(
1226
1226
  generics = []
1227
1227
  constraints = []
1228
- packagePair = PackagePair("", "")
1229
- moduleName = ""
1228
+ moduleKey = ModuleKey(PackagePair("", ""), [], "")
1230
1229
  traitName = c.name
1231
1230
  typeArguments = c.generics
1232
1231
  )
@@ -8,8 +8,7 @@ class JsEmitter(
8
8
  emitTarget: EmitTarget
9
9
  isMainModule: Bool
10
10
  compilerModuleFileUrl: Option[String]
11
- packagePair: PackagePair
12
- moduleName: String
11
+ moduleKey: ModuleKey
13
12
  mutable emittingAsync: Bool
14
13
  mutable tailCallUsed: Bool
15
14
  )
@@ -26,20 +25,17 @@ new(
26
25
  emitTarget: EmitTarget
27
26
  isMainModule: Bool
28
27
  compilerModuleFileUrl: Option[String]
29
- packagePair: PackagePair
30
- moduleName: String
28
+ moduleKey: ModuleKey
31
29
  ): JsEmitter {
32
30
  JsEmitter(
33
31
  otherModules = otherModules.map {m =>
34
- let moduleName = m.packagePair.groupName() + "/" + m.file.dropLast(3)
35
- Pair(moduleName, m)
32
+ Pair(m.moduleKey.qualifiedName(), m)
36
33
  }.toMap()
37
34
  jsImporter = JsImporter.new()
38
35
  emitTarget = emitTarget
39
36
  isMainModule = isMainModule
40
37
  compilerModuleFileUrl = compilerModuleFileUrl
41
- packagePair = packagePair
42
- moduleName = moduleName
38
+ moduleKey = moduleKey
43
39
  emittingAsync = False
44
40
  tailCallUsed = False
45
41
  )
@@ -51,13 +47,11 @@ fail[T](at: Location, message: String): T {
51
47
 
52
48
  extend self: JsEmitter {
53
49
 
54
- emitModule(packagePair: PackagePair, module: Module): String {
55
- let selfImport =
56
- "import * as " + packagePair.groupName("_") + "_" + module.file.dropLast(3) + " " +
57
- "from \"../../" + packagePair.groupName("/") + "/" + module.file.dropLast(3) + ".mjs\""
50
+ emitModule(module: Module): String {
51
+ let selfImport = self.emitImport(self.moduleKey)
58
52
  let imports = [
59
53
  self.compilerModuleFileUrl.map {"import * as $firefly_compiler from '" + _ + "'"}.toList()
60
- module.imports.sortBy {i => Pair(i.package, i.file) }.map {self.emitImportDefinition(_)}
54
+ module.imports.sortBy {_.moduleKey}.map {self.emitImport(_.moduleKey)}
61
55
  ].flatten()
62
56
  let parts = [
63
57
  if(imports.any {_ == selfImport}) {imports} else {[selfImport, ...imports]}
@@ -68,15 +62,24 @@ extend self: JsEmitter {
68
62
  module.extends.map {self.emitExtendsDefinition(_)}
69
63
  module.instances.map {self.emitInstanceDefinition(_)}
70
64
  ]
71
- let ignoreJsImports = if(
72
- self.emitTarget == EmitExecutable &&
73
- packagePair.group == "ff" &&
74
- packagePair.name == "core"
75
- ) {["esbuild"]} else {[]}
65
+ let ignoreJsImports = if(self.emitTarget == EmitExecutable && self.moduleKey.packagePair.isCore()) {
66
+ ["esbuild"]
67
+ } else {
68
+ []
69
+ }
76
70
  let jsImports = self.jsImporter.generateImports(ignoreJsImports.toSet())
77
71
  [jsImports, ...parts].map {_.join("\n\n")}.join("\n\n") + "\n"
78
72
  }
79
73
 
74
+ emitImport(moduleKey: ModuleKey): String {
75
+ let dots = "../".repeat(self.moduleKey.folders.size() + 2)
76
+ let jsImportName = moduleKey.packagePair.groupName("_") + "_" +
77
+ moduleKey.folders.map {_ + "_"}.join() + moduleKey.name
78
+ let jsImportFrom = dots + moduleKey.packagePair.groupName("/") + "/" +
79
+ moduleKey.folders.map {_ + "/"}.join() + moduleKey.name + ".mjs"
80
+ "import * as " + jsImportName + " from \"" + jsImportFrom + "\""
81
+ }
82
+
80
83
  withEmittingAsync[T](body: () => T): T {
81
84
  try {
82
85
  self.emittingAsync = True
@@ -153,11 +156,6 @@ extend self: JsEmitter {
153
156
  ].join("\n")]}.else {[]}
154
157
  }
155
158
 
156
- emitImportDefinition(definition: DImport): String {
157
- "import * as " + definition.package.group + "_" + definition.package.name + "_" + definition.file + " " +
158
- "from \"../../" + definition.package.group + "/" + definition.package.name + "/" + definition.file + ".mjs\""
159
- }
160
-
161
159
  emitLetDefinition(definition: DLet, mutable: Bool, async: Bool): String {
162
160
  let mutability = if(mutable) {"let"} else {"const"}
163
161
  let valueCode = self.emitTerm(definition.value, async)
@@ -434,8 +432,10 @@ extend self: JsEmitter {
434
432
  }
435
433
 
436
434
  emitDictionary(d: Dictionary): String {
437
- let m = if(d.moduleName != "") {
438
- d.packagePair.groupName("_") + "_" + d.moduleName.replace("/", "_") + "."
435
+ let m = if(d.moduleKey.name != "") {
436
+ d.moduleKey.packagePair.groupName("_") + "_" +
437
+ d.moduleKey.folders.map {_ + "_"}.join() +
438
+ d.moduleKey.name + "."
439
439
  } else {""}
440
440
  let c = m + makeDictionaryName(d.traitName, d.typeName)
441
441
  if(d.dictionaries.isEmpty()) {
@@ -601,27 +601,27 @@ extend self: JsEmitter {
601
601
  Some(
602
602
  self.emitTerm(e, async) + ".length"
603
603
  )
604
- | "ff:core/Equal.equals" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
604
+ | "ff:core/Equal.equals" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {
605
605
  primitiveTypes.contains(typeName) || typeName == "ff:core/Ordering.Ordering"
606
606
  } =>
607
607
  Some("(" + self.emitTerm(left, async) + " === " + self.emitTerm(right, async) + ")")
608
- | "ff:core/Equal.notEquals" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
608
+ | "ff:core/Equal.notEquals" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {
609
609
  primitiveTypes.contains(typeName) || typeName == "ff:core/Ordering.Ordering"
610
610
  } =>
611
611
  Some("(" + self.emitTerm(left, async) + " !== " + self.emitTerm(right, async) + ")")
612
- | "ff:core/Ordering.before" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
612
+ | "ff:core/Ordering.before" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {
613
613
  primitiveTypes.contains(typeName)
614
614
  } =>
615
615
  Some("(" + self.emitTerm(left, async) + " < " + self.emitTerm(right, async) + ")")
616
- | "ff:core/Ordering.notBefore" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
616
+ | "ff:core/Ordering.notBefore" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {
617
617
  primitiveTypes.contains(typeName)
618
618
  } =>
619
619
  Some("(" + self.emitTerm(left, async) + " >= " + self.emitTerm(right, async) + ")")
620
- | "ff:core/Ordering.after" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
620
+ | "ff:core/Ordering.after" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {
621
621
  primitiveTypes.contains(typeName)
622
622
  } =>
623
623
  Some("(" + self.emitTerm(left, async) + " > " + self.emitTerm(right, async) + ")")
624
- | "ff:core/Ordering.notAfter" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
624
+ | "ff:core/Ordering.notAfter" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {
625
625
  primitiveTypes.contains(typeName)
626
626
  } =>
627
627
  Some("(" + self.emitTerm(left, async) + " <= " + self.emitTerm(right, async) + ")")
@@ -1310,8 +1310,9 @@ extend self: JsEmitter {
1310
1310
  emitArgument(callAt: Location, argument: Argument, async: Bool): String {
1311
1311
  argument.value.{
1312
1312
  | ECall(_, StaticCall("ff:core/SourceLocation.callSite", _, _), _, _, _, _) =>
1313
- "\"" + self.moduleName + ":" + callAt.line + ":" + callAt.column +
1314
- "," + self.packagePair.group + "," + self.packagePair.name + "\""
1313
+ "\"" + self.moduleKey.folders.map {_ + "/"}.join() + self.moduleKey.name +
1314
+ ":" + callAt.line + ":" + callAt.column +
1315
+ "," + self.moduleKey.packagePair.group + "," + self.moduleKey.packagePair.name + "\""
1315
1316
  | value =>
1316
1317
  self.emitTerm(value, async)
1317
1318
  }