firefly-compiler 0.5.63 → 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.
- package/compiler/Builder.ff +47 -31
- package/compiler/Compiler.ff +42 -47
- package/compiler/Dependencies.ff +4 -2
- 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 +6 -8
- 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/Main.ff
CHANGED
|
@@ -28,11 +28,11 @@ main(system: NodeSystem): Unit {
|
|
|
28
28
|
let fireflyPath = detectFireflyPath(system)
|
|
29
29
|
|
|
30
30
|
function buildScript(
|
|
31
|
-
|
|
31
|
+
mainPath: Path
|
|
32
32
|
mainPackagePair: PackagePair
|
|
33
33
|
emitTarget: EmitTarget
|
|
34
34
|
resolvedDependencies: ResolvedDependencies
|
|
35
|
-
) {
|
|
35
|
+
): ModuleKey {
|
|
36
36
|
let fixedPackagePaths = if(resolvedDependencies.packagePaths.contains(PackagePair("ff", "core"))) {
|
|
37
37
|
resolvedDependencies.packagePaths
|
|
38
38
|
} else {
|
|
@@ -47,11 +47,13 @@ main(system: NodeSystem): Unit {
|
|
|
47
47
|
| EmitBrowser => "browser"
|
|
48
48
|
| EmitExecutable => "executable"
|
|
49
49
|
}
|
|
50
|
+
let folders = mainPath.parent().grab().relativeListTo(fixedPackagePaths.grab(mainPackagePair))
|
|
51
|
+
let name = mainPath.base().removeLast(".ff").grab()
|
|
52
|
+
let moduleKey = ModuleKey(mainPackagePair, folders, name)
|
|
50
53
|
Builder.build(
|
|
51
54
|
system = system
|
|
52
55
|
emitTarget = emitTarget
|
|
53
|
-
|
|
54
|
-
mainModules = [mainFile]
|
|
56
|
+
mainModules = [moduleKey]
|
|
55
57
|
resolvedDependencies = resolvedDependencies.ResolvedDependencies(packagePaths = fixedPackagePaths)
|
|
56
58
|
compilerModulePath = compilerModulePath
|
|
57
59
|
tempPath = system.path(".firefly").slash("temporary")
|
|
@@ -59,6 +61,7 @@ main(system: NodeSystem): Unit {
|
|
|
59
61
|
printMeasurements = False
|
|
60
62
|
moduleCache = ModuleCache.new(0)
|
|
61
63
|
)
|
|
64
|
+
moduleKey
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
function runCommand(command: MainCommand) {
|
|
@@ -66,13 +69,13 @@ main(system: NodeSystem): Unit {
|
|
|
66
69
|
let resolvedDependencies = Dependencies.process(
|
|
67
70
|
system.httpClient()
|
|
68
71
|
DependencyLock.new(system.mainTask())
|
|
69
|
-
system.path(mainFile
|
|
72
|
+
system.path(mainFile)
|
|
70
73
|
)
|
|
71
74
|
prepareFireflyDirectory(system.path("."))
|
|
72
|
-
let
|
|
73
|
-
buildScript(
|
|
74
|
-
if(!importAndRun(system, fireflyPath, "node",
|
|
75
|
-
let at = Location(system.path(mainFile
|
|
75
|
+
let mainPath = system.path(mainFile)
|
|
76
|
+
let moduleKey = buildScript(mainPath, resolvedDependencies.mainPackagePair, EmitNode, resolvedDependencies)
|
|
77
|
+
if(!importAndRun(system, fireflyPath, "node", moduleKey, arguments)) {
|
|
78
|
+
let at = Location(system.path(mainFile).absolute(), 1, 1)
|
|
76
79
|
throw(CompileError(at, "This module does not contain a 'nodeMain' function"))
|
|
77
80
|
}
|
|
78
81
|
|
|
@@ -80,12 +83,12 @@ main(system: NodeSystem): Unit {
|
|
|
80
83
|
let resolvedDependencies = Dependencies.process(
|
|
81
84
|
system.httpClient()
|
|
82
85
|
DependencyLock.new(system.mainTask())
|
|
83
|
-
system.path(mainFile
|
|
86
|
+
system.path(mainFile)
|
|
84
87
|
)
|
|
85
88
|
prepareFireflyDirectory(system.path("."))
|
|
86
|
-
let
|
|
87
|
-
buildScript(
|
|
88
|
-
bundleForBrowser(system, resolvedDependencies.mainPackagePair,
|
|
89
|
+
let mainPath = system.path(mainFile)
|
|
90
|
+
buildScript(mainPath, resolvedDependencies.mainPackagePair, EmitBrowser, resolvedDependencies)
|
|
91
|
+
bundleForBrowser(system, resolvedDependencies.mainPackagePair, mainPath.base())
|
|
89
92
|
|
|
90
93
|
| BuildCommand(mainFile) =>
|
|
91
94
|
let resolvedDependencies = Dependencies.process(
|
|
@@ -94,11 +97,11 @@ main(system: NodeSystem): Unit {
|
|
|
94
97
|
system.path(mainFile + ".ff")
|
|
95
98
|
)
|
|
96
99
|
prepareFireflyDirectory(system.path("."))
|
|
97
|
-
let
|
|
98
|
-
buildScript(
|
|
99
|
-
buildScript(
|
|
100
|
-
bundleForPkg(system, resolvedDependencies.mainPackagePair,
|
|
101
|
-
importAndRun(system, fireflyPath, "build",
|
|
100
|
+
let mainPath = system.path(mainFile)
|
|
101
|
+
let moduleKey = buildScript(mainPath, resolvedDependencies.mainPackagePair, EmitBuild, resolvedDependencies)
|
|
102
|
+
buildScript(mainPath, resolvedDependencies.mainPackagePair, EmitExecutable, resolvedDependencies)
|
|
103
|
+
bundleForPkg(system, resolvedDependencies.mainPackagePair, mainPath.base())
|
|
104
|
+
importAndRun(system, fireflyPath, "build", moduleKey, [])
|
|
102
105
|
|
|
103
106
|
| CheckCommand(filePath) =>
|
|
104
107
|
let errors = Builder.check(
|
|
@@ -113,7 +116,6 @@ main(system: NodeSystem): Unit {
|
|
|
113
116
|
newVersion = 0
|
|
114
117
|
lspHook = LspHook.disabled()
|
|
115
118
|
infer = True
|
|
116
|
-
checkDependencies = False
|
|
117
119
|
)
|
|
118
120
|
if(!errors.isEmpty()) {throw(CompileErrors(errors.distinct()))}
|
|
119
121
|
|
|
@@ -123,8 +125,7 @@ main(system: NodeSystem): Unit {
|
|
|
123
125
|
Builder.build(
|
|
124
126
|
system = system
|
|
125
127
|
emitTarget = EmitNode
|
|
126
|
-
|
|
127
|
-
mainModules = ["Main"]
|
|
128
|
+
mainModules = [ModuleKey(PackagePair("ff", "compiler"), [], "Main")]
|
|
128
129
|
resolvedDependencies = ResolvedDependencies(
|
|
129
130
|
mainPackagePair = PackagePair("ff", "compiler")
|
|
130
131
|
packages = [Pair(
|
|
@@ -150,8 +151,9 @@ main(system: NodeSystem): Unit {
|
|
|
150
151
|
let path = system.path(filePath)
|
|
151
152
|
let code = path.readText()
|
|
152
153
|
let packagePair = PackagePair("script", "script")
|
|
154
|
+
let moduleKey = ModuleKey(packagePair, [], path.base().removeLast(".ff").grab())
|
|
153
155
|
let tokens = Tokenizer.tokenize(path.absolute(), code, None, False)
|
|
154
|
-
let parser = Parser.new(
|
|
156
|
+
let parser = Parser.new(moduleKey, tokens, True, LspHook.disabled())
|
|
155
157
|
let module = parser.parseModuleWithPackageInfo().module
|
|
156
158
|
makeSymbolColumns(module)
|
|
157
159
|
}
|
|
@@ -191,11 +193,11 @@ These are the commands:
|
|
|
191
193
|
|
|
192
194
|
parseCommandLine(arguments: List[String]): MainCommand {
|
|
193
195
|
| [mainFile, ...mainArguments] {mainFile.removeLast(".ff") | Some(mainName)} =>
|
|
194
|
-
RunCommand(
|
|
196
|
+
RunCommand(mainFile, mainArguments)
|
|
195
197
|
| ["run", ...runArguments] =>
|
|
196
198
|
runArguments.{
|
|
197
199
|
| [mainFile, ...mainArguments] {mainFile.removeLast(".ff") | Some(mainName)} =>
|
|
198
|
-
RunCommand(
|
|
200
|
+
RunCommand(mainFile, mainArguments)
|
|
199
201
|
| _ => throw(CommandLineError(
|
|
200
202
|
"You must specify a Firefly file (.ff) as first argument to run." + usageString
|
|
201
203
|
))
|
|
@@ -203,7 +205,7 @@ parseCommandLine(arguments: List[String]): MainCommand {
|
|
|
203
205
|
| ["browser", ...browserArguments] =>
|
|
204
206
|
browserArguments.{
|
|
205
207
|
| [mainFile] {mainFile.removeLast(".ff") | Some(mainName)} =>
|
|
206
|
-
BrowserCommand(
|
|
208
|
+
BrowserCommand(mainFile)
|
|
207
209
|
| [_, _, ...] => throw(CommandLineError(
|
|
208
210
|
"You must only specify a single argument to browser." + usageString
|
|
209
211
|
))
|
|
@@ -214,7 +216,7 @@ parseCommandLine(arguments: List[String]): MainCommand {
|
|
|
214
216
|
| ["build", ...buildArguments] =>
|
|
215
217
|
buildArguments.{
|
|
216
218
|
| [mainFile] {mainFile.removeLast(".ff") | Some(mainName)} =>
|
|
217
|
-
BuildCommand(
|
|
219
|
+
BuildCommand(mainFile)
|
|
218
220
|
| [_, _, ...] => throw(CommandLineError(
|
|
219
221
|
"You must only specify a single argument to build." + usageString
|
|
220
222
|
))
|
|
@@ -266,15 +268,14 @@ importAndRun(
|
|
|
266
268
|
system: NodeSystem
|
|
267
269
|
fireflyPath: Path
|
|
268
270
|
target: String
|
|
269
|
-
|
|
270
|
-
mainFile: String
|
|
271
|
+
moduleKey: ModuleKey
|
|
271
272
|
arguments: List[String]
|
|
272
273
|
): Bool {
|
|
273
274
|
let process = Js.await(Js.dynamicImport("process"))
|
|
274
275
|
let cwd = process->cwd()
|
|
275
276
|
let workingDirectory = if(cwd->indexOf(":") === 1) {"file:///" + cwd?} else {cwd?}
|
|
276
|
-
let packagePath = packagePair.
|
|
277
|
-
let runFile = workingDirectory + "/.firefly/output/" + target + "/" + packagePath + "/" +
|
|
277
|
+
let packagePath = moduleKey.packagePair.groupName("/")
|
|
278
|
+
let runFile = workingDirectory + "/.firefly/output/" + target + "/" + packagePath + "/" + moduleKey.importName() + ".run.mjs"
|
|
278
279
|
let runFilePath = if(runFile.contains("://")) {system.pathFromUrl(runFile)} else {system.path(runFile)}
|
|
279
280
|
if(runFilePath.exists()) {
|
|
280
281
|
let main = Js.await(Js.dynamicImport(runFile))
|
|
@@ -336,7 +337,7 @@ makeSymbolColumns(module: Module): List[List[String]] {
|
|
|
336
337
|
let all = [...toplevel, ...types, ...traits]
|
|
337
338
|
all.map {r =>
|
|
338
339
|
let generics = if(r.generics.isEmpty()) {""} else {"[" + r.generics.join(", ") + "]"}
|
|
339
|
-
let header = (module.
|
|
340
|
+
let header = (module.moduleKey.importName() + " " + r.name + generics).trim()
|
|
340
341
|
[header, ...r.symbols.sort()]
|
|
341
342
|
}
|
|
342
343
|
}
|
package/compiler/ModuleCache.ff
CHANGED
|
@@ -34,19 +34,18 @@ extend self: ModuleCache {
|
|
|
34
34
|
invalidate(key: String) {
|
|
35
35
|
//Log.trace("Invalidate: " + uri)
|
|
36
36
|
self.parsedModules.get(key).each: | Pair(module, _) =>
|
|
37
|
-
let moduleName = module.file.dropLast(3)
|
|
38
37
|
self.remove([key])
|
|
39
38
|
self.parsedModules.each {| k, Pair(m, _) =>
|
|
40
|
-
if(m.imports.any {i => i.
|
|
39
|
+
if(m.imports.any {i => i.moduleKey == module.moduleKey}) {
|
|
41
40
|
//Log.trace("Invalidating due to import of invalidated module: " + m.packagePair.groupName() + "/" + m.file)
|
|
42
41
|
self.remove([k])
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
filesNotImporting(
|
|
46
|
+
filesNotImporting(moduleKey: ModuleKey): List[String] {
|
|
48
47
|
self.parsedModules.toList().collect {| Pair(k, Pair(m, _)) =>
|
|
49
|
-
if(!m.imports.any {i => i.
|
|
48
|
+
if(!m.imports.any {i => i.moduleKey == moduleKey}): k
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
51
|
|
|
@@ -86,11 +85,10 @@ extend self: ModuleCache {
|
|
|
86
85
|
|
|
87
86
|
cacheParsedModule(
|
|
88
87
|
packagePaths: Map[PackagePair, Path]
|
|
89
|
-
|
|
90
|
-
moduleName: String
|
|
88
|
+
moduleKey: ModuleKey
|
|
91
89
|
body: Path => Module
|
|
92
90
|
): Module {
|
|
93
|
-
let path = modulePath(packagePaths,
|
|
91
|
+
let path = modulePath(packagePaths, moduleKey)
|
|
94
92
|
self.parsedModules.get(path.absolute()).map {_.first}.else:
|
|
95
93
|
let result = body(path)
|
|
96
94
|
self.parsedModules = self.parsedModules.add(path.absolute(), Pair(result, self.version))
|
|
@@ -99,11 +97,10 @@ extend self: ModuleCache {
|
|
|
99
97
|
|
|
100
98
|
cacheResolvedModule(
|
|
101
99
|
packagePaths: Map[PackagePair, Path]
|
|
102
|
-
|
|
103
|
-
moduleName: String
|
|
100
|
+
moduleKey: ModuleKey
|
|
104
101
|
body: Path => Module
|
|
105
102
|
): Module {
|
|
106
|
-
let path = modulePath(packagePaths,
|
|
103
|
+
let path = modulePath(packagePaths, moduleKey)
|
|
107
104
|
self.resolvedModules.get(path.absolute()).map {_.first}.else:
|
|
108
105
|
let result = body(path)
|
|
109
106
|
self.resolvedModules = self.resolvedModules.add(path.absolute(), Pair(result, self.version))
|
|
@@ -112,11 +109,10 @@ extend self: ModuleCache {
|
|
|
112
109
|
|
|
113
110
|
cacheDerivedModule(
|
|
114
111
|
packagePaths: Map[PackagePair, Path]
|
|
115
|
-
|
|
116
|
-
moduleName: String
|
|
112
|
+
moduleKey: ModuleKey
|
|
117
113
|
body: Path => Module
|
|
118
114
|
): Module {
|
|
119
|
-
let path = modulePath(packagePaths,
|
|
115
|
+
let path = modulePath(packagePaths, moduleKey)
|
|
120
116
|
self.derivedModules.get(path.absolute()).map {_.first}.else:
|
|
121
117
|
let result = body(path)
|
|
122
118
|
self.derivedModules = self.derivedModules.add(path.absolute(), Pair(result, self.version))
|
|
@@ -125,11 +121,10 @@ extend self: ModuleCache {
|
|
|
125
121
|
|
|
126
122
|
cacheInferredModule(
|
|
127
123
|
packagePaths: Map[PackagePair, Path]
|
|
128
|
-
|
|
129
|
-
moduleName: String
|
|
124
|
+
moduleKey: ModuleKey
|
|
130
125
|
body: Path => Module
|
|
131
126
|
): Module {
|
|
132
|
-
let path = modulePath(packagePaths,
|
|
127
|
+
let path = modulePath(packagePaths, moduleKey)
|
|
133
128
|
self.inferredModules.get(path.absolute()).map {_.first}.else:
|
|
134
129
|
let result = body(path)
|
|
135
130
|
self.inferredModules = self.inferredModules.add(path.absolute(), Pair(result, self.version))
|
|
@@ -138,12 +133,11 @@ extend self: ModuleCache {
|
|
|
138
133
|
|
|
139
134
|
cacheEmittedModule(
|
|
140
135
|
packagePaths: Map[PackagePair, Path]
|
|
141
|
-
|
|
142
|
-
moduleName: String
|
|
136
|
+
moduleKey: ModuleKey
|
|
143
137
|
isMainModule: Bool
|
|
144
138
|
body: Path => Unit
|
|
145
139
|
): Unit {
|
|
146
|
-
let path = modulePath(packagePaths,
|
|
140
|
+
let path = modulePath(packagePaths, moduleKey)
|
|
147
141
|
if(isMainModule || !self.emittedModules.contains(path.absolute())):
|
|
148
142
|
self.emittedModules = self.emittedModules.add(path.absolute(), self.version)
|
|
149
143
|
try {
|
|
@@ -168,12 +162,10 @@ mergeVersionedMap[T](oldMap: Map[String, T], newMap: Map[String, T], getVersion:
|
|
|
168
162
|
|
|
169
163
|
modulePath(
|
|
170
164
|
packagePaths: Map[PackagePair, Path]
|
|
171
|
-
|
|
172
|
-
moduleName: String
|
|
165
|
+
moduleKey: ModuleKey
|
|
173
166
|
): Path {
|
|
174
|
-
let packagePath = packagePaths.get(packagePair).else {
|
|
175
|
-
panic("Internal error - package path missing: " + packagePair.groupName())
|
|
167
|
+
let packagePath = packagePaths.get(moduleKey.packagePair).else {
|
|
168
|
+
panic("Internal error - package path missing: " + moduleKey.packagePair.groupName())
|
|
176
169
|
}
|
|
177
|
-
|
|
178
|
-
packagePath.slash(file)
|
|
170
|
+
moduleKey.path(packagePath)
|
|
179
171
|
}
|
package/compiler/Parser.ff
CHANGED
|
@@ -4,8 +4,7 @@ import Syntax
|
|
|
4
4
|
import LspHook
|
|
5
5
|
|
|
6
6
|
class Parser(
|
|
7
|
-
|
|
8
|
-
file: String
|
|
7
|
+
moduleKey: ModuleKey
|
|
9
8
|
tokens: List[Token]
|
|
10
9
|
end: Token
|
|
11
10
|
targetIsNode: Bool
|
|
@@ -18,15 +17,13 @@ class Parser(
|
|
|
18
17
|
data Poly(generics: List[String], constraints: List[Constraint])
|
|
19
18
|
|
|
20
19
|
new(
|
|
21
|
-
|
|
22
|
-
file: String
|
|
20
|
+
moduleKey: ModuleKey
|
|
23
21
|
tokens: List[Token]
|
|
24
22
|
targetIsNode: Bool
|
|
25
23
|
lspHook: LspHook
|
|
26
24
|
): Parser {
|
|
27
25
|
Parser(
|
|
28
|
-
|
|
29
|
-
file = file
|
|
26
|
+
moduleKey = moduleKey
|
|
30
27
|
tokens = tokens
|
|
31
28
|
end = tokens.grabLast()
|
|
32
29
|
targetIsNode = targetIsNode
|
|
@@ -128,7 +125,7 @@ extend self: Parser {
|
|
|
128
125
|
} else {
|
|
129
126
|
DPackage(
|
|
130
127
|
location
|
|
131
|
-
self.packagePair
|
|
128
|
+
self.moduleKey.packagePair
|
|
132
129
|
Version(location, 0, 0, 0)
|
|
133
130
|
TargetNames(node = self.targetIsNode, browser = !self.targetIsNode)
|
|
134
131
|
)
|
|
@@ -175,7 +172,7 @@ extend self: Parser {
|
|
|
175
172
|
} elseIf {self.current().is(LKeyword) && self.current().rawIs4("data", "class", "capability", "newtype")} {
|
|
176
173
|
types.push(self.parseTypeDefinition())
|
|
177
174
|
} elseIf {self.current().is(LKeyword) && self.current().rawIs("import")} {
|
|
178
|
-
imports.push(self.parseImportDefinition(self.packagePair))
|
|
175
|
+
imports.push(self.parseImportDefinition(self.moduleKey.packagePair))
|
|
179
176
|
} elseIf {self.current().is(LKeyword) && self.current().rawIs("include")} {
|
|
180
177
|
throw(CompileError(self.current().at()
|
|
181
178
|
"Includes must be at the top of the file or below 'package'"
|
|
@@ -195,8 +192,7 @@ extend self: Parser {
|
|
|
195
192
|
}
|
|
196
193
|
|
|
197
194
|
Module(
|
|
198
|
-
|
|
199
|
-
packagePair = self.packagePair
|
|
195
|
+
moduleKey = self.moduleKey
|
|
200
196
|
imports = imports.toList()
|
|
201
197
|
lets = lets.toList()
|
|
202
198
|
functions = functions.toList()
|
|
@@ -527,7 +523,7 @@ extend self: Parser {
|
|
|
527
523
|
} else {
|
|
528
524
|
currentPackagePair
|
|
529
525
|
}
|
|
530
|
-
DImport(fileToken.at(), alias, packagePair, path.toList(), fileToken.raw())
|
|
526
|
+
DImport(fileToken.at(), alias, ModuleKey(packagePair, path.toList(), fileToken.raw()))
|
|
531
527
|
}
|
|
532
528
|
|
|
533
529
|
parsePackageDefinition(): DPackage {
|
package/compiler/Resolver.ff
CHANGED
|
@@ -26,7 +26,7 @@ data CaseVariable(
|
|
|
26
26
|
asBound: Option[String]
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
new(
|
|
29
|
+
new(lspHook: LspHook): Resolver {
|
|
30
30
|
Resolver(
|
|
31
31
|
variables = [].toMap()
|
|
32
32
|
variableLocations = [].toMap()
|
|
@@ -54,8 +54,6 @@ extend self: Resolver {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
resolveModule(module: Module, otherModules: List[Module]): Module {
|
|
57
|
-
let moduleNamespace =
|
|
58
|
-
module.file.replace("\\", "/").reverse().takeWhile {_ != '/'}.reverse().takeWhile {_ != '.'}
|
|
59
57
|
let self2 = self.processImports(module.imports, otherModules)
|
|
60
58
|
let self3 = self2.processDefinitions(module, None)
|
|
61
59
|
|
|
@@ -103,11 +101,11 @@ extend self: Resolver {
|
|
|
103
101
|
processImports(imports: List[DImport], modules: List[Module]): Resolver {
|
|
104
102
|
mutable resolver = self
|
|
105
103
|
imports.each {import =>
|
|
106
|
-
modules.find {_.
|
|
104
|
+
modules.find {_.moduleKey == import.moduleKey}.{
|
|
107
105
|
| Some(module) =>
|
|
108
106
|
resolver = resolver.processDefinitions(module, Some(import.alias))
|
|
109
107
|
| None =>
|
|
110
|
-
throw(CompileError(import.at, "No such module: " + import.
|
|
108
|
+
throw(CompileError(import.at, "No such module: " + import.moduleKey.importName()))
|
|
111
109
|
}
|
|
112
110
|
}
|
|
113
111
|
resolver
|
|
@@ -115,9 +113,7 @@ extend self: Resolver {
|
|
|
115
113
|
|
|
116
114
|
processDefinitions(module: Module, importAlias: Option[String]): Resolver {
|
|
117
115
|
function entry(name: String, unqualified: Bool): List[Pair[String, String]] {
|
|
118
|
-
let full =
|
|
119
|
-
module.packagePair.groupName() + "/" +
|
|
120
|
-
module.file.dropLast(3) + "." + name
|
|
116
|
+
let full = module.moduleKey.qualifiedSymbol(name)
|
|
121
117
|
importAlias.{
|
|
122
118
|
| None => [Pair(name, full), Pair(full, full)]
|
|
123
119
|
| Some(alias) {unqualified} => [Pair(alias + "." + name, full), Pair(name, full), Pair(full, full)]
|
|
@@ -125,9 +121,10 @@ extend self: Resolver {
|
|
|
125
121
|
}
|
|
126
122
|
}
|
|
127
123
|
let isCore = // TODO: Extend imports to list unqualified symbols instead of this
|
|
128
|
-
module.packagePair.group == "ff" &&
|
|
129
|
-
module.packagePair.name == "core" &&
|
|
130
|
-
module.
|
|
124
|
+
module.moduleKey.packagePair.group == "ff" &&
|
|
125
|
+
module.moduleKey.packagePair.name == "core" &&
|
|
126
|
+
module.moduleKey.folders == [] &&
|
|
127
|
+
module.moduleKey.name == "Core"
|
|
131
128
|
let lets = module.lets.flatMap {entry(_.name, isCore)}.toMap()
|
|
132
129
|
let letLocations = module.lets.flatMap {d => entry(d.name, True).map {_.mapSecond {_ => d.at}}}.toMap()
|
|
133
130
|
let functions = module.functions.flatMap {entry(_.signature.name, isCore)}.toMap()
|
package/compiler/Syntax.ff
CHANGED
|
@@ -22,18 +22,7 @@ data PackageInfo(
|
|
|
22
22
|
includes: List[DInclude]
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
file: String
|
|
27
|
-
packagePair: PackagePair
|
|
28
|
-
imports: List[DImport]
|
|
29
|
-
types: List[DType]
|
|
30
|
-
traits: List[DTrait]
|
|
31
|
-
instances: List[DInstance]
|
|
32
|
-
extends: List[DExtend]
|
|
33
|
-
lets: List[DLet]
|
|
34
|
-
functions: List[DFunction]
|
|
35
|
-
)
|
|
36
|
-
|
|
25
|
+
// TODO rename to PackageKey
|
|
37
26
|
data PackagePair(
|
|
38
27
|
group: String
|
|
39
28
|
name: String
|
|
@@ -43,8 +32,58 @@ extend self: PackagePair {
|
|
|
43
32
|
groupName(delimiter: String = ":"): String {
|
|
44
33
|
self.group + delimiter + self.name
|
|
45
34
|
}
|
|
35
|
+
isCore(): Bool {
|
|
36
|
+
self.group == "ff" &&
|
|
37
|
+
self.name == "core"
|
|
38
|
+
}
|
|
39
|
+
moduleKey(packageRoot: Path, modulePath: Path): Option[ModuleKey] {
|
|
40
|
+
let parts = modulePath.relativeListTo(packageRoot)
|
|
41
|
+
let folders = parts.dropLast()
|
|
42
|
+
parts.last().flatMap {_.removeLast(".ff")}.filter {_ =>
|
|
43
|
+
folders.all {_.first().any {_.isAsciiLower()}} &&
|
|
44
|
+
folders.all {_.all {c => c.isAsciiLower() || c.isAsciiDigit()}}
|
|
45
|
+
}.map: name =>
|
|
46
|
+
ModuleKey(self, folders, name)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
data ModuleKey(
|
|
51
|
+
packagePair: PackagePair
|
|
52
|
+
folders: List[String]
|
|
53
|
+
name: String
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
extend self: ModuleKey {
|
|
57
|
+
// "folder/Module" as in: import folder/Module from group:package
|
|
58
|
+
importName(): String {
|
|
59
|
+
self.folders.map {_ + "/"}.join() + self.name
|
|
60
|
+
}
|
|
61
|
+
// "C:\myProject\folder\Module.ff"
|
|
62
|
+
path(packageRoot: Path): Path {
|
|
63
|
+
let parent = self.folders.foldLeft(packageRoot) {p, f => p.slash(f)}
|
|
64
|
+
parent.slash(self.name + ".ff")
|
|
65
|
+
}
|
|
66
|
+
// "group:package/folder/Module"
|
|
67
|
+
qualifiedName(): String {
|
|
68
|
+
self.packagePair.groupName() + "/" + self.importName()
|
|
69
|
+
}
|
|
70
|
+
// "ff:core/List.List_map"
|
|
71
|
+
qualifiedSymbol(symbol: String): String {
|
|
72
|
+
self.qualifiedName() + "." + symbol
|
|
73
|
+
}
|
|
46
74
|
}
|
|
47
75
|
|
|
76
|
+
data Module(
|
|
77
|
+
moduleKey: ModuleKey
|
|
78
|
+
imports: List[DImport]
|
|
79
|
+
types: List[DType]
|
|
80
|
+
traits: List[DTrait]
|
|
81
|
+
instances: List[DInstance]
|
|
82
|
+
extends: List[DExtend]
|
|
83
|
+
lets: List[DLet]
|
|
84
|
+
functions: List[DFunction]
|
|
85
|
+
)
|
|
86
|
+
|
|
48
87
|
data DPackage(
|
|
49
88
|
at: Location
|
|
50
89
|
packagePair: PackagePair
|
|
@@ -69,9 +108,7 @@ data TargetNames(
|
|
|
69
108
|
data DImport(
|
|
70
109
|
at: Location
|
|
71
110
|
alias: String
|
|
72
|
-
|
|
73
|
-
directory: List[String]
|
|
74
|
-
file: String
|
|
111
|
+
moduleKey: ModuleKey
|
|
75
112
|
)
|
|
76
113
|
data DFunction(
|
|
77
114
|
at: Location
|
|
@@ -181,8 +218,7 @@ data MatchGuard(
|
|
|
181
218
|
)
|
|
182
219
|
|
|
183
220
|
data Dictionary(
|
|
184
|
-
|
|
185
|
-
moduleName: String
|
|
221
|
+
moduleKey: ModuleKey
|
|
186
222
|
traitName: String
|
|
187
223
|
typeName: String
|
|
188
224
|
dictionaries: List[Dictionary]
|
package/compiler/Unification.ff
CHANGED
|
@@ -17,8 +17,7 @@ data InstanceKey(traitName: String, typeName: String)
|
|
|
17
17
|
data InstanceValue(
|
|
18
18
|
generics: List[String]
|
|
19
19
|
constraints: List[Constraint]
|
|
20
|
-
|
|
21
|
-
moduleName: String
|
|
20
|
+
moduleKey: ModuleKey
|
|
22
21
|
traitName: String
|
|
23
22
|
typeArguments: List[Type]
|
|
24
23
|
)
|
|
@@ -34,7 +33,6 @@ new(modules: List[Module], attemptFixes: Bool): Unification {
|
|
|
34
33
|
Map.new()
|
|
35
34
|
3 // To avoid collision with the parser and resolver
|
|
36
35
|
modules.flatMap {module =>
|
|
37
|
-
let moduleName = module.file.dropLast(".ff".size())
|
|
38
36
|
module.instances.map {definition =>
|
|
39
37
|
let typeName = definition.typeArguments.grabFirst().{
|
|
40
38
|
| TConstructor(_, name, _) => name
|
|
@@ -45,8 +43,7 @@ new(modules: List[Module], attemptFixes: Bool): Unification {
|
|
|
45
43
|
InstanceValue(
|
|
46
44
|
generics = definition.generics
|
|
47
45
|
constraints = definition.constraints
|
|
48
|
-
|
|
49
|
-
moduleName = moduleName
|
|
46
|
+
moduleKey = module.moduleKey
|
|
50
47
|
traitName = definition.traitName
|
|
51
48
|
typeArguments = definition.typeArguments
|
|
52
49
|
)
|
package/core/BuildSystem.ff
CHANGED
|
@@ -148,7 +148,7 @@ internalCompile(buildSystem: BuildSystem, mainFiles: List[Path], target: String)
|
|
|
148
148
|
Js.await(Js.rawIdentifier("$firefly_compiler")->"buildViaBuildSystem_$"(
|
|
149
149
|
buildSystem!
|
|
150
150
|
internalPath(buildSystem, buildSystem!->"fireflyPath_"?)!
|
|
151
|
-
mainFiles
|
|
151
|
+
mainFiles!
|
|
152
152
|
target
|
|
153
153
|
Js.currentTask()!
|
|
154
154
|
))
|
package/core/Path.ff
CHANGED
|
@@ -101,10 +101,20 @@ extend self: Path {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
relativeTo(path: Path): String {
|
|
104
|
-
let nodePath = Js.import("path")
|
|
104
|
+
let nodePath = Js.import("path")
|
|
105
105
|
nodePath->relative(path.absolutePath, self.absolutePath)?
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
relativeListTo(path: Path): List[String] {
|
|
109
|
+
let nodePath = Js.import("path")
|
|
110
|
+
let relative = self.relativeTo(path)
|
|
111
|
+
if(nodePath->sep === "\\") {
|
|
112
|
+
relative.split('/').flatMap {_.split('\\')}.filter {_ != ""}
|
|
113
|
+
} else {
|
|
114
|
+
relative.split('/').filter {_ != ""}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
108
118
|
endsWith(parts: List[String]): Bool {
|
|
109
119
|
function go(pathOption: Option[Path], reversed: List[String]): Bool {
|
|
110
120
|
| _, [] => True
|
package/core/SourceLocation.ff
CHANGED
|
@@ -26,6 +26,10 @@ extend self: SourceLocation {
|
|
|
26
26
|
self.location.takeWhile {_ != ':'}.reverse().takeWhile {_ != '/'}.reverse()
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
directoryAndModule(): String {
|
|
30
|
+
self.location.takeWhile {_ != ':'}.reverse().reverse()
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
line(): Int {
|
|
30
34
|
self.location.dropWhile {_ != ':'}.dropFirst().takeWhile {_ != ':'}.grabInt()
|
|
31
35
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
package foldergroup:test:0.0.0
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
nodeMain(system: NodeSystem) {
|
|
2
|
+
|
|
3
|
+
let task1 = system.mainTask().spawn {task =>
|
|
4
|
+
Log.debug("Starting task 1")
|
|
5
|
+
try {
|
|
6
|
+
while {True} {
|
|
7
|
+
task.sleep(Duration(0.1))
|
|
8
|
+
}
|
|
9
|
+
} catchAny {error =>
|
|
10
|
+
Log.debug(error.name())
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
Log.debug("Aborting task 1")
|
|
15
|
+
task1.abort()
|
|
16
|
+
Log.debug("Aborted task 1")
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
package/fireflysite/FrontPage.ff
CHANGED
package/fireflysite/Main.ff
CHANGED