firefly-compiler 0.5.63 → 0.5.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/Builder.ff +47 -31
- package/compiler/Compiler.ff +42 -47
- package/compiler/Dependencies.ff +9 -3
- package/compiler/Deriver.ff +2 -2
- package/compiler/Dictionaries.ff +11 -12
- package/compiler/Environment.ff +5 -5
- package/compiler/Inference.ff +1 -2
- package/compiler/JsEmitter.ff +34 -33
- package/compiler/Main.ff +32 -31
- package/compiler/ModuleCache.ff +17 -25
- package/compiler/Parser.ff +7 -11
- package/compiler/Resolver.ff +8 -11
- package/compiler/Syntax.ff +53 -17
- package/compiler/Unification.ff +2 -5
- package/core/BuildSystem.ff +1 -1
- package/core/Path.ff +11 -1
- package/core/SourceLocation.ff +4 -0
- package/experimental/foldertest/.firefly/package.ff +1 -0
- package/experimental/foldertest/Root.ff +10 -0
- package/experimental/foldertest/a/A.ff +3 -0
- package/experimental/foldertest/a/MainA.ff +3 -0
- package/experimental/tests/TestCancel.ff +19 -0
- package/fireflysite/CommunityOverview.ff +0 -2
- package/fireflysite/FrontPage.ff +0 -2
- package/fireflysite/Main.ff +1 -1
- package/fireflysite/PackagesOverview.ff +0 -2
- package/fireflysite/Router.ff +3 -3
- package/fireflysite/{ExamplesOverview.ff → demos/ExamplesOverview.ff} +3 -3
- package/fireflysite/{RouteFront.ff → routes/RouteFront.ff} +2 -3
- package/fireflysite/{RouteNonMarkdown.ff → routes/RouteNonMarkdown.ff} +5 -5
- package/fireflysite/{RouteReference.ff → routes/RouteReference.ff} +2 -3
- package/lsp/CompletionHandler.ff +2 -2
- package/lsp/Handler.ff +14 -13
- package/lsp/LanguageServer.ff +5 -4
- package/output/js/ff/compiler/Builder.mjs +118 -80
- package/output/js/ff/compiler/Compiler.mjs +85 -89
- package/output/js/ff/compiler/Dependencies.mjs +16 -10
- package/output/js/ff/compiler/Deriver.mjs +6 -6
- package/output/js/ff/compiler/Dictionaries.mjs +6 -6
- package/output/js/ff/compiler/Environment.mjs +10 -6
- package/output/js/ff/compiler/Inference.mjs +4 -4
- package/output/js/ff/compiler/JsEmitter.mjs +60 -38
- package/output/js/ff/compiler/Main.mjs +66 -56
- package/output/js/ff/compiler/ModuleCache.mjs +34 -38
- package/output/js/ff/compiler/Parser.mjs +14 -14
- package/output/js/ff/compiler/Resolver.mjs +12 -22
- package/output/js/ff/compiler/Substitution.mjs +2 -2
- package/output/js/ff/compiler/Syntax.mjs +395 -183
- package/output/js/ff/compiler/Unification.mjs +18 -32
- package/output/js/ff/core/BuildSystem.mjs +2 -6
- package/output/js/ff/core/Path.mjs +32 -0
- package/output/js/ff/core/SourceLocation.mjs +12 -0
- package/package.json +1 -1
- package/vscode/package.json +1 -1
- package/vscode/syntaxes/firefly.tmLanguage.json +299 -299
- package/fireflysite/ReferenceIntroduction.ff +0 -11
- /package/fireflysite/{CountingButtonDemo.ff → demos/CountingButtonDemo.ff} +0 -0
- /package/fireflysite/{MatchingPasswordsDemo.ff → demos/MatchingPasswordsDemo.ff} +0 -0
- /package/fireflysite/{PostgresqlDemo.ff → demos/PostgresqlDemo.ff} +0 -0
package/compiler/Builder.ff
CHANGED
|
@@ -13,8 +13,7 @@ import DependencyLock
|
|
|
13
13
|
build(
|
|
14
14
|
system: NodeSystem
|
|
15
15
|
emitTarget: EmitTarget
|
|
16
|
-
|
|
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 {
|
|
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[
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
|
138
|
+
| True => findPackageFilesForDirectory(path, mustContain, skipFiles)
|
|
139
|
+
| False => findPackageFilesForFile(path).toList()
|
|
140
140
|
}
|
|
141
141
|
let errors = Array.new()
|
|
142
142
|
|
|
143
|
-
packages.filter {!_.
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
let
|
|
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(
|
|
179
|
+
compiler.infer(moduleKey)
|
|
179
180
|
} else {
|
|
180
|
-
compiler.resolve(
|
|
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
|
-
|
|
202
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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, ...
|
|
253
|
+
[...fireflyFiles, ...relevantDirectories.flatMap {findFireflyFiles(_, mustContain, skipFiles)}]
|
|
238
254
|
}
|
|
239
255
|
|
|
240
256
|
internalCreateExecutable(
|
package/compiler/Compiler.ff
CHANGED
|
@@ -106,21 +106,19 @@ coreImports: List[DImport] =
|
|
|
106
106
|
DImport(
|
|
107
107
|
at = Location("<prelude>", 1, 1)
|
|
108
108
|
alias = moduleName
|
|
109
|
-
|
|
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,
|
|
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 + " " +
|
|
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(
|
|
138
|
-
self.cache.cacheParsedModule(self.packagePaths,
|
|
139
|
-
|
|
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: " +
|
|
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(
|
|
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.
|
|
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(
|
|
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.
|
|
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.
|
|
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(
|
|
181
|
-
self.cache.cacheResolvedModule(self.packagePaths,
|
|
182
|
-
self.measure("Resolve",
|
|
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(
|
|
180
|
+
let module = self.parse(moduleKey, None)
|
|
185
181
|
let otherModules = self.imports(module)
|
|
186
|
-
let resolver = Resolver.new(
|
|
182
|
+
let resolver = Resolver.new(self.lspHook)
|
|
187
183
|
resolver.resolveModule(module, otherModules)
|
|
188
184
|
}
|
|
189
185
|
|
|
190
|
-
derive(
|
|
191
|
-
self.cache.cacheDerivedModule(self.packagePaths,
|
|
192
|
-
self.measure("Derive",
|
|
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(
|
|
190
|
+
let module = self.resolve(moduleKey)
|
|
195
191
|
Deriver.new().deriveModule(module)
|
|
196
192
|
}
|
|
197
193
|
|
|
198
|
-
infer(
|
|
199
|
-
self.cache.cacheInferredModule(self.packagePaths,
|
|
200
|
-
self.measure("Infer",
|
|
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(
|
|
198
|
+
let module = self.derive(moduleKey)
|
|
203
199
|
let otherModules = self.imports(module).map {i =>
|
|
204
|
-
self.derive(i.
|
|
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(
|
|
212
|
-
self.cache.cacheEmittedModule(self.packagePaths,
|
|
213
|
-
self.measure("Emit",
|
|
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(
|
|
211
|
+
let module = self.infer(moduleKey)
|
|
216
212
|
let otherModules = self.imports(module).map {i =>
|
|
217
|
-
|
|
218
|
-
self.
|
|
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
|
-
|
|
229
|
-
moduleName = moduleName
|
|
223
|
+
moduleKey = moduleKey
|
|
230
224
|
)
|
|
231
|
-
let js = emitter.emitModule(
|
|
232
|
-
let
|
|
233
|
-
let
|
|
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
|
-
|
|
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(
|
|
238
|
+
let jsRunFile = jsPath.slash(moduleKey.name + ".run.mjs")
|
|
244
239
|
jsRunFile.writeText(runJs.map {_ + "\n"}.join())
|
|
245
240
|
}
|
|
246
241
|
}
|
package/compiler/Dependencies.ff
CHANGED
|
@@ -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
|
|
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
|
}
|
|
@@ -144,7 +146,11 @@ process(fetch: HttpClient, dependencyLock: DependencyLock, path: Path): Resolved
|
|
|
144
146
|
let workspace = Workspace.loadWorkspace(path)
|
|
145
147
|
let self = Dependencies(workspace, [].toMap(), [].toMap(), [].toSet())
|
|
146
148
|
let packageInfo = self.loadPackageInfo(PackagePair("script", "script"), path).else {
|
|
147
|
-
|
|
149
|
+
if(!path.exists()) {
|
|
150
|
+
throw(CompileError(Location(path.absolute(), 1, 1), "File not found"))
|
|
151
|
+
} else {
|
|
152
|
+
throw(CompileError(Location(path.absolute(), 1, 1), "Could not load package info"))
|
|
153
|
+
}
|
|
148
154
|
}
|
|
149
155
|
let newDependencies = self.processPackageInfo(packageInfo)
|
|
150
156
|
self.processDependencies(path, fetch, dependencyLock, newDependencies)
|
package/compiler/Deriver.ff
CHANGED
|
@@ -14,7 +14,7 @@ extend self: Deriver {
|
|
|
14
14
|
|
|
15
15
|
deriveModule(module: Module): Module {
|
|
16
16
|
|
|
17
|
-
let modulePrefix = module.
|
|
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.
|
|
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 &&
|
package/compiler/Dictionaries.ff
CHANGED
|
@@ -23,17 +23,17 @@ extend self: Dictionaries {
|
|
|
23
23
|
| _ => None
|
|
24
24
|
}.toMap()
|
|
25
25
|
|
|
26
|
-
let lets = module.lets.map {
|
|
27
|
-
let functions = module.functions.map {
|
|
28
|
-
let extends = module.extends.map {
|
|
29
|
-
//let traits = module.traits.map {
|
|
30
|
-
let instances = module.instances.map {
|
|
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.
|
|
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
|
-
|
|
199
|
-
moduleName = ""
|
|
198
|
+
moduleKey = ModuleKey(PackagePair("", ""), [], "")
|
|
200
199
|
traitName = c.name
|
|
201
200
|
typeArguments = c.generics
|
|
202
201
|
)
|
package/compiler/Environment.ff
CHANGED
|
@@ -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(
|
|
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.
|
|
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(
|
|
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()
|
package/compiler/Inference.ff
CHANGED
|
@@ -1225,8 +1225,7 @@ constraintsToInstances(constraints: List[Constraint]): Map[InstanceKey, Instance
|
|
|
1225
1225
|
InstanceValue(
|
|
1226
1226
|
generics = []
|
|
1227
1227
|
constraints = []
|
|
1228
|
-
|
|
1229
|
-
moduleName = ""
|
|
1228
|
+
moduleKey = ModuleKey(PackagePair("", ""), [], "")
|
|
1230
1229
|
traitName = c.name
|
|
1231
1230
|
typeArguments = c.generics
|
|
1232
1231
|
)
|
package/compiler/JsEmitter.ff
CHANGED
|
@@ -8,8 +8,7 @@ class JsEmitter(
|
|
|
8
8
|
emitTarget: EmitTarget
|
|
9
9
|
isMainModule: Bool
|
|
10
10
|
compilerModuleFileUrl: Option[String]
|
|
11
|
-
|
|
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
|
-
|
|
30
|
-
moduleName: String
|
|
28
|
+
moduleKey: ModuleKey
|
|
31
29
|
): JsEmitter {
|
|
32
30
|
JsEmitter(
|
|
33
31
|
otherModules = otherModules.map {m =>
|
|
34
|
-
|
|
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
|
-
|
|
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(
|
|
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 {
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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.
|
|
438
|
-
d.packagePair.groupName("_") + "_" +
|
|
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(_, _,
|
|
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(_, _,
|
|
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(_, _,
|
|
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(_, _,
|
|
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(_, _,
|
|
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(_, _,
|
|
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.
|
|
1314
|
-
"
|
|
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
|
}
|