firefly-compiler 0.4.24 → 0.4.26
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 +14 -1
- package/compiler/Compiler.ff +13 -40
- package/compiler/Main.ff +15 -1
- package/compiler/ModuleCache.ff +160 -0
- package/core/Map.ff +8 -0
- package/core/Path.ff +4 -0
- package/experimental/bidirectional/Bidi.ff +88 -0
- package/lsp/Handler.ff +109 -37
- package/lsp/LanguageServer.ff +12 -8
- package/lsp/TestReferences.ff +3 -1
- package/lux/.firefly/package.ff +0 -1
- package/output/js/ff/compiler/Builder.mjs +30 -16
- package/output/js/ff/compiler/Compiler.mjs +29 -67
- package/output/js/ff/compiler/Dependencies.mjs +0 -2
- package/output/js/ff/compiler/Deriver.mjs +0 -2
- package/output/js/ff/compiler/Dictionaries.mjs +0 -2
- package/output/js/ff/compiler/Environment.mjs +0 -2
- package/output/js/ff/compiler/Inference.mjs +0 -2
- package/output/js/ff/compiler/JsEmitter.mjs +0 -2
- package/output/js/ff/compiler/JsImporter.mjs +0 -2
- package/output/js/ff/compiler/LspHook.mjs +0 -2
- package/output/js/ff/compiler/Main.mjs +8 -8
- package/output/js/ff/compiler/ModuleCache.mjs +428 -0
- package/output/js/ff/compiler/Parser.mjs +0 -2
- package/output/js/ff/compiler/Patterns.mjs +0 -2
- package/output/js/ff/compiler/Resolver.mjs +0 -2
- package/output/js/ff/compiler/Substitution.mjs +0 -2
- package/output/js/ff/compiler/Syntax.mjs +0 -2
- package/output/js/ff/compiler/Token.mjs +0 -2
- package/output/js/ff/compiler/Tokenizer.mjs +0 -2
- package/output/js/ff/compiler/Unification.mjs +0 -2
- package/output/js/ff/compiler/Wildcards.mjs +0 -2
- package/output/js/ff/compiler/Workspace.mjs +0 -2
- package/output/js/ff/core/Any.mjs +0 -2
- package/output/js/ff/core/Array.mjs +0 -2
- package/output/js/ff/core/AssetSystem.mjs +0 -2
- package/output/js/ff/core/Atomic.mjs +0 -2
- package/output/js/ff/core/Bool.mjs +0 -2
- package/output/js/ff/core/BrowserSystem.mjs +0 -2
- package/output/js/ff/core/Buffer.mjs +0 -2
- package/output/js/ff/core/BuildSystem.mjs +0 -2
- package/output/js/ff/core/Channel.mjs +0 -2
- package/output/js/ff/core/Char.mjs +0 -2
- package/output/js/ff/core/Core.mjs +0 -2
- package/output/js/ff/core/Duration.mjs +0 -2
- package/output/js/ff/core/Equal.mjs +0 -2
- package/output/js/ff/core/Error.mjs +0 -2
- package/output/js/ff/core/FileHandle.mjs +0 -2
- package/output/js/ff/core/Float.mjs +0 -2
- package/output/js/ff/core/HttpClient.mjs +0 -2
- package/output/js/ff/core/Instant.mjs +0 -2
- package/output/js/ff/core/Int.mjs +0 -2
- package/output/js/ff/core/IntMap.mjs +0 -2
- package/output/js/ff/core/JsSystem.mjs +0 -2
- package/output/js/ff/core/JsValue.mjs +0 -2
- package/output/js/ff/core/Json.mjs +0 -2
- package/output/js/ff/core/List.mjs +0 -2
- package/output/js/ff/core/Lock.mjs +0 -2
- package/output/js/ff/core/Log.mjs +0 -2
- package/output/js/ff/core/Map.mjs +16 -2
- package/output/js/ff/core/NodeSystem.mjs +0 -2
- package/output/js/ff/core/Nothing.mjs +0 -2
- package/output/js/ff/core/Option.mjs +0 -2
- package/output/js/ff/core/Ordering.mjs +0 -2
- package/output/js/ff/core/Pair.mjs +0 -2
- package/output/js/ff/core/Path.mjs +12 -2
- package/output/js/ff/core/Random.mjs +0 -2
- package/output/js/ff/core/RbMap.mjs +0 -2
- package/output/js/ff/core/Serializable.mjs +0 -2
- package/output/js/ff/core/Set.mjs +0 -2
- package/output/js/ff/core/Show.mjs +0 -2
- package/output/js/ff/core/SourceLocation.mjs +0 -2
- package/output/js/ff/core/Stream.mjs +0 -2
- package/output/js/ff/core/String.mjs +0 -2
- package/output/js/ff/core/StringMap.mjs +0 -2
- package/output/js/ff/core/Task.mjs +0 -2
- package/output/js/ff/core/Try.mjs +0 -2
- package/output/js/ff/core/Unit.mjs +0 -2
- package/package.json +1 -1
- package/vscode/client/src/extension.ts +4 -3
- package/vscode/language-configuration.json +10 -1
- package/vscode/package.json +1 -1
- package/output/js/ff/core/Box.mjs +0 -114
package/compiler/Builder.ff
CHANGED
|
@@ -6,6 +6,7 @@ import Compiler
|
|
|
6
6
|
import Unification
|
|
7
7
|
import Dependencies
|
|
8
8
|
import JsEmitter
|
|
9
|
+
import ModuleCache
|
|
9
10
|
import LspHook
|
|
10
11
|
|
|
11
12
|
build(
|
|
@@ -18,6 +19,7 @@ build(
|
|
|
18
19
|
tempPath: Path
|
|
19
20
|
jsOutputPath: Path
|
|
20
21
|
printMeasurements: Bool
|
|
22
|
+
moduleCache: ModuleCache
|
|
21
23
|
): Unit {
|
|
22
24
|
|
|
23
25
|
if(tempPath.exists()) {tempPath.delete()}
|
|
@@ -34,6 +36,7 @@ build(
|
|
|
34
36
|
jsPathFile
|
|
35
37
|
resolvedDependencies
|
|
36
38
|
Map.empty()
|
|
39
|
+
moduleCache
|
|
37
40
|
lspHook = LspHook.disabled()
|
|
38
41
|
)
|
|
39
42
|
compiler.emit(mainPackage, mainModule, isMainModule = True)
|
|
@@ -81,6 +84,7 @@ buildViaBuildSystem(system: NodeSystem, fireflyPath: Path, mainFile: String, tar
|
|
|
81
84
|
tempPath = system.path(".firefly/temporary")
|
|
82
85
|
jsOutputPath = system.path(".firefly/output").slash(target)
|
|
83
86
|
printMeasurements = False
|
|
87
|
+
moduleCache = ModuleCache.empty(0)
|
|
84
88
|
)
|
|
85
89
|
}
|
|
86
90
|
|
|
@@ -90,8 +94,11 @@ check(
|
|
|
90
94
|
path: Path
|
|
91
95
|
mustContain: Option[String]
|
|
92
96
|
virtualFiles: Map[String, String]
|
|
97
|
+
cache: ModuleCache
|
|
98
|
+
newVersion: Int
|
|
93
99
|
lspHook: LspHook
|
|
94
100
|
infer: Bool
|
|
101
|
+
checkDependencies: Bool
|
|
95
102
|
): List[CompileError] {
|
|
96
103
|
let packages = path.isDirectory().{
|
|
97
104
|
| True => findPackageFiles(path, mustContain)
|
|
@@ -109,6 +116,7 @@ check(
|
|
|
109
116
|
resolvedDependencies.packagePaths.add(PackagePair("ff", "core"), fireflyPath.slash("core"))
|
|
110
117
|
}
|
|
111
118
|
let fixedResolvedDependencies = resolvedDependencies.ResolvedDependencies(packagePaths = fixedPackagePaths)
|
|
119
|
+
let newCache = cache.without(newVersion, path)
|
|
112
120
|
let compiler = Compiler.make(
|
|
113
121
|
EmitBuild
|
|
114
122
|
system.mainTask()
|
|
@@ -116,9 +124,13 @@ check(
|
|
|
116
124
|
package.root.slash(".firefly").slash("temporary")
|
|
117
125
|
fixedResolvedDependencies
|
|
118
126
|
virtualFiles
|
|
127
|
+
newCache
|
|
119
128
|
lspHook
|
|
120
129
|
)
|
|
121
|
-
package.files
|
|
130
|
+
let files = if(checkDependencies) {package.files} else {
|
|
131
|
+
package.files.filter {!_.contains([".firefly", "dependencies"])}
|
|
132
|
+
}
|
|
133
|
+
files.each {file =>
|
|
122
134
|
let localFile = file.base()
|
|
123
135
|
try {
|
|
124
136
|
if(infer) {
|
|
@@ -131,6 +143,7 @@ check(
|
|
|
131
143
|
errors.push(c)
|
|
132
144
|
} grab()
|
|
133
145
|
}
|
|
146
|
+
cache.mergeVersions(compiler.cache)
|
|
134
147
|
}
|
|
135
148
|
errors.drain()
|
|
136
149
|
|
package/compiler/Compiler.ff
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Syntax
|
|
2
2
|
import Tokenizer
|
|
3
|
+
import ModuleCache
|
|
3
4
|
import Parser
|
|
4
5
|
import Resolver
|
|
5
6
|
import Deriver
|
|
@@ -17,12 +18,8 @@ capability Compiler(
|
|
|
17
18
|
packagePaths: Map[PackagePair, Path]
|
|
18
19
|
singleFilePackages: Set[PackagePair]
|
|
19
20
|
virtualFiles: Map[String, String]
|
|
21
|
+
cache: ModuleCache
|
|
20
22
|
lspHook: LspHook
|
|
21
|
-
mutable parsedModules: Map[String, Module]
|
|
22
|
-
mutable resolvedModules: Map[String, Module]
|
|
23
|
-
mutable derivedModules: Map[String, Module]
|
|
24
|
-
mutable inferredModules: Map[String, Module]
|
|
25
|
-
mutable emittedModules: Set[String]
|
|
26
23
|
mutable phaseDurationDelta: Duration
|
|
27
24
|
phaseDurations: Array[Pair[String, Duration]]
|
|
28
25
|
)
|
|
@@ -34,6 +31,7 @@ make(
|
|
|
34
31
|
jsOutputPath: Path
|
|
35
32
|
resolvedDependencies: ResolvedDependencies
|
|
36
33
|
virtualFiles: Map[String, String]
|
|
34
|
+
cache: ModuleCache
|
|
37
35
|
lspHook: LspHook
|
|
38
36
|
): Compiler {
|
|
39
37
|
Compiler(
|
|
@@ -44,12 +42,8 @@ make(
|
|
|
44
42
|
packagePaths = resolvedDependencies.packagePaths
|
|
45
43
|
singleFilePackages = resolvedDependencies.singleFilePackages
|
|
46
44
|
virtualFiles = virtualFiles
|
|
45
|
+
cache = cache
|
|
47
46
|
lspHook = lspHook
|
|
48
|
-
parsedModules = Map.empty()
|
|
49
|
-
resolvedModules = Map.empty()
|
|
50
|
-
derivedModules = Map.empty()
|
|
51
|
-
inferredModules = Map.empty()
|
|
52
|
-
emittedModules = Set.empty()
|
|
53
47
|
phaseDurationDelta = Duration(0.0)
|
|
54
48
|
phaseDurations = [].toArray()
|
|
55
49
|
)
|
|
@@ -66,7 +60,6 @@ coreImports: List[DImport] =
|
|
|
66
60
|
"AssetSystem"
|
|
67
61
|
"Atomic"
|
|
68
62
|
"Bool"
|
|
69
|
-
"Box"
|
|
70
63
|
"BrowserSystem"
|
|
71
64
|
"Buffer"
|
|
72
65
|
"BuildSystem"
|
|
@@ -139,14 +132,9 @@ extend self: Compiler {
|
|
|
139
132
|
}
|
|
140
133
|
|
|
141
134
|
parse(packagePair: PackagePair, moduleName: String, importedAt: Option[Location]): Module {
|
|
135
|
+
self.cache.cacheParsedModule(self.packagePaths, packagePair, moduleName): path =>
|
|
142
136
|
let packageName = packagePair.groupName()
|
|
143
|
-
self.parsedModules.get(packageName + ":" + moduleName).else:
|
|
144
137
|
self.measure("Parse", packagePair, moduleName):
|
|
145
|
-
let packagePath = self.packagePaths.get(packagePair).else {
|
|
146
|
-
panic("Internal error - package path missing: " + packagePair.groupName())
|
|
147
|
-
}
|
|
148
|
-
let file = moduleName + ".ff"
|
|
149
|
-
let path = packagePath.slash(file)
|
|
150
138
|
let code = self.virtualFiles.get(path.absolute()).else {
|
|
151
139
|
importedAt.each {at => if(!path.exists()) {
|
|
152
140
|
throw(CompileError(at, "Imported module not found: " + packageName + "/" + moduleName))
|
|
@@ -155,7 +143,7 @@ extend self: Compiler {
|
|
|
155
143
|
}
|
|
156
144
|
let completionAt = if(self.lspHook.isEnabled() && self.lspHook.insertIdentifier) {self.lspHook.at}
|
|
157
145
|
let tokens = Tokenizer.tokenize(path.absolute(), code, completionAt, self.lspHook.isEnabled())
|
|
158
|
-
let parser = Parser.make(packagePair,
|
|
146
|
+
let parser = Parser.make(packagePair, path.base(), tokens, self.emitTarget != EmitBrowser, self.lspHook)
|
|
159
147
|
let module = if(self.singleFilePackages.contains(packagePair)) {
|
|
160
148
|
parser.parseModuleWithPackageInfo().module
|
|
161
149
|
} else {
|
|
@@ -164,7 +152,6 @@ extend self: Compiler {
|
|
|
164
152
|
let result = module.Module(
|
|
165
153
|
imports = [...coreImports, ...module.imports]
|
|
166
154
|
)
|
|
167
|
-
self.parsedModules = self.parsedModules.add(packageName + ":" + moduleName, result)
|
|
168
155
|
result
|
|
169
156
|
}
|
|
170
157
|
|
|
@@ -180,34 +167,25 @@ extend self: Compiler {
|
|
|
180
167
|
}
|
|
181
168
|
|
|
182
169
|
resolve(packagePair: PackagePair, moduleName: String): Module {
|
|
183
|
-
|
|
184
|
-
self.resolvedModules.get(packageName + ":" + moduleName).else:
|
|
170
|
+
self.cache.cacheResolvedModule(self.packagePaths, packagePair, moduleName): path =>
|
|
185
171
|
self.measure("Resolve", packagePair, moduleName):
|
|
186
172
|
|
|
187
173
|
let module = self.parse(packagePair, moduleName, None)
|
|
188
174
|
let otherModules = self.imports(module)
|
|
189
175
|
let resolver = Resolver.make(packagePair, moduleName, self.lspHook)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
self.resolvedModules = self.resolvedModules.add(packageName + ":" + moduleName, result)
|
|
193
|
-
result
|
|
176
|
+
resolver.resolveModule(module, otherModules)
|
|
194
177
|
}
|
|
195
178
|
|
|
196
179
|
derive(packagePair: PackagePair, moduleName: String): Module {
|
|
197
|
-
|
|
198
|
-
self.derivedModules.get(packageName + ":" + moduleName).else:
|
|
180
|
+
self.cache.cacheDerivedModule(self.packagePaths, packagePair, moduleName): path =>
|
|
199
181
|
self.measure("Derive", packagePair, moduleName):
|
|
200
182
|
|
|
201
183
|
let module = self.resolve(packagePair, moduleName)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
self.derivedModules = self.derivedModules.add(packageName + ":" + moduleName, result)
|
|
205
|
-
result
|
|
184
|
+
Deriver.make().deriveModule(module)
|
|
206
185
|
}
|
|
207
186
|
|
|
208
187
|
infer(packagePair: PackagePair, moduleName: String): Module {
|
|
209
|
-
|
|
210
|
-
self.inferredModules.get(packageName + ":" + moduleName).else:
|
|
188
|
+
self.cache.cacheInferredModule(self.packagePaths, packagePair, moduleName): path =>
|
|
211
189
|
self.measure("Infer", packagePair, moduleName):
|
|
212
190
|
|
|
213
191
|
let module = self.derive(packagePair, moduleName)
|
|
@@ -216,17 +194,12 @@ extend self: Compiler {
|
|
|
216
194
|
}
|
|
217
195
|
let inference = Inference.make([module, ...otherModules], self.lspHook)
|
|
218
196
|
let inferredModule = inference.inferModule(module, otherModules)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
self.inferredModules = self.inferredModules.add(packageName + ":" + moduleName, result)
|
|
222
|
-
result
|
|
197
|
+
Dictionaries.make([module, ...otherModules]).processModule(inferredModule, otherModules)
|
|
223
198
|
}
|
|
224
199
|
|
|
225
200
|
emit(packagePair: PackagePair, moduleName: String, isMainModule: Bool): Unit {
|
|
226
|
-
|
|
227
|
-
if(self.emittedModules.contains(packageName + ":" + moduleName)) {} else:
|
|
201
|
+
self.cache.cacheEmittedModule(self.packagePaths, packagePair, moduleName): path =>
|
|
228
202
|
self.measure("Emit", packagePair, moduleName):
|
|
229
|
-
self.emittedModules = self.emittedModules.add(packageName + ":" + moduleName)
|
|
230
203
|
|
|
231
204
|
let module = self.infer(packagePair, moduleName)
|
|
232
205
|
let otherModules = self.imports(module).map {i =>
|
package/compiler/Main.ff
CHANGED
|
@@ -8,6 +8,7 @@ import Builder
|
|
|
8
8
|
import Dependencies
|
|
9
9
|
import JsEmitter
|
|
10
10
|
import Inference
|
|
11
|
+
import ModuleCache
|
|
11
12
|
import LspHook
|
|
12
13
|
|
|
13
14
|
data MainCommand {
|
|
@@ -54,6 +55,7 @@ main(system: NodeSystem): Unit {
|
|
|
54
55
|
tempPath = system.path(".firefly").slash("temporary")
|
|
55
56
|
jsOutputPath = system.path(".firefly").path("output").path(targetName)
|
|
56
57
|
printMeasurements = False
|
|
58
|
+
moduleCache = ModuleCache.empty(0)
|
|
57
59
|
)
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -85,7 +87,18 @@ main(system: NodeSystem): Unit {
|
|
|
85
87
|
importAndRun(fireflyPath, "build", resolvedDependencies.mainPackagePair, localMainFile, [])
|
|
86
88
|
|
|
87
89
|
| CheckCommand(filePath) =>
|
|
88
|
-
let errors = Builder.check(
|
|
90
|
+
let errors = Builder.check(
|
|
91
|
+
system = system
|
|
92
|
+
fireflyPath = fireflyPath
|
|
93
|
+
path = system.path(filePath)
|
|
94
|
+
mustContain = None
|
|
95
|
+
virtualFiles = Map.empty()
|
|
96
|
+
cache = ModuleCache.empty(1)
|
|
97
|
+
newVersion = 0
|
|
98
|
+
lspHook = LspHook.disabled()
|
|
99
|
+
infer = True
|
|
100
|
+
checkDependencies = False
|
|
101
|
+
)
|
|
89
102
|
if(!errors.isEmpty()) {throw(CompileErrors(errors.distinct()))}
|
|
90
103
|
|
|
91
104
|
| BootstrapCommand =>
|
|
@@ -108,6 +121,7 @@ main(system: NodeSystem): Unit {
|
|
|
108
121
|
tempPath = workingDirectory.slash("output").slash("temporary")
|
|
109
122
|
jsOutputPath = workingDirectory.slash("output").slash("js")
|
|
110
123
|
printMeasurements = True
|
|
124
|
+
moduleCache = ModuleCache.empty(0)
|
|
111
125
|
)
|
|
112
126
|
}
|
|
113
127
|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import Syntax
|
|
2
|
+
|
|
3
|
+
class ModuleCache(
|
|
4
|
+
version: Int
|
|
5
|
+
mutable parsedModules: Map[String, Pair[Module, Int]]
|
|
6
|
+
mutable resolvedModules: Map[String, Pair[Module, Int]]
|
|
7
|
+
mutable derivedModules: Map[String, Pair[Module, Int]]
|
|
8
|
+
mutable inferredModules: Map[String, Pair[Module, Int]]
|
|
9
|
+
mutable emittedModules: Map[String, Int]
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
empty(version: Int): ModuleCache {
|
|
13
|
+
ModuleCache(
|
|
14
|
+
version = version
|
|
15
|
+
parsedModules = Map.empty()
|
|
16
|
+
resolvedModules = Map.empty()
|
|
17
|
+
derivedModules = Map.empty()
|
|
18
|
+
inferredModules = Map.empty()
|
|
19
|
+
emittedModules = Map.empty()
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
extend self: ModuleCache {
|
|
24
|
+
|
|
25
|
+
remove(paths: List[Path]) {
|
|
26
|
+
if(!paths.isEmpty()):
|
|
27
|
+
let keys = paths.map {_.absolute()}
|
|
28
|
+
self.parsedModules = self.parsedModules.removeList(keys)
|
|
29
|
+
self.resolvedModules = self.resolvedModules.removeList(keys)
|
|
30
|
+
self.derivedModules = self.derivedModules.removeList(keys)
|
|
31
|
+
self.inferredModules = self.inferredModules.removeList(keys)
|
|
32
|
+
self.emittedModules = self.emittedModules.removeList(keys)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
without(newVersion: Int, path: Path): ModuleCache {
|
|
36
|
+
let key = path.absolute()
|
|
37
|
+
if(path.isFile()) {
|
|
38
|
+
self.ModuleCache(
|
|
39
|
+
version = newVersion
|
|
40
|
+
parsedModules = self.parsedModules.remove(key)
|
|
41
|
+
resolvedModules = self.resolvedModules.remove(key)
|
|
42
|
+
derivedModules = self.derivedModules.remove(key)
|
|
43
|
+
inferredModules = self.inferredModules.remove(key)
|
|
44
|
+
emittedModules = self.emittedModules.remove(key)
|
|
45
|
+
)
|
|
46
|
+
} else {
|
|
47
|
+
function invalidated(p: String): Bool {
|
|
48
|
+
p.startsWith(key) && !p.contains(".firefly/dependencies") && !p.contains(".firefly\\dependencies")
|
|
49
|
+
}
|
|
50
|
+
self.ModuleCache(
|
|
51
|
+
version = newVersion
|
|
52
|
+
parsedModules = self.parsedModules.toList().filter {| Pair(p, _) => !invalidated(p)}.toMap()
|
|
53
|
+
resolvedModules = self.resolvedModules.toList().filter {| Pair(p, _) => !invalidated(p)}.toMap()
|
|
54
|
+
derivedModules = self.derivedModules.toList().filter {| Pair(p, _) => !invalidated(p)}.toMap()
|
|
55
|
+
inferredModules = self.inferredModules.toList().filter {| Pair(p, _) => !invalidated(p)}.toMap()
|
|
56
|
+
emittedModules = self.emittedModules.toList().filter {| Pair(p, _) => !invalidated(p)}.toMap()
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
mergeVersions(cache: ModuleCache): Unit {
|
|
62
|
+
self.parsedModules = mergeVersionedMap(self.parsedModules, cache.parsedModules) {_.second}
|
|
63
|
+
self.resolvedModules = mergeVersionedMap(self.resolvedModules, cache.resolvedModules) {_.second}
|
|
64
|
+
self.derivedModules = mergeVersionedMap(self.derivedModules, cache.derivedModules) {_.second}
|
|
65
|
+
self.inferredModules = mergeVersionedMap(self.inferredModules, cache.inferredModules) {_.second}
|
|
66
|
+
self.emittedModules = mergeVersionedMap(self.emittedModules, cache.emittedModules) {_}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
cacheParsedModule(
|
|
70
|
+
packagePaths: Map[PackagePair, Path]
|
|
71
|
+
packagePair: PackagePair
|
|
72
|
+
moduleName: String
|
|
73
|
+
body: Path => Module
|
|
74
|
+
): Module {
|
|
75
|
+
let path = modulePath(packagePaths, packagePair, moduleName)
|
|
76
|
+
self.parsedModules.get(path.absolute()).map {_.first}.else:
|
|
77
|
+
let result = body(path)
|
|
78
|
+
self.parsedModules = self.parsedModules.add(path.absolute(), Pair(result, self.version))
|
|
79
|
+
result
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
cacheResolvedModule(
|
|
83
|
+
packagePaths: Map[PackagePair, Path]
|
|
84
|
+
packagePair: PackagePair
|
|
85
|
+
moduleName: String
|
|
86
|
+
body: Path => Module
|
|
87
|
+
): Module {
|
|
88
|
+
let path = modulePath(packagePaths, packagePair, moduleName)
|
|
89
|
+
self.resolvedModules.get(path.absolute()).map {_.first}.else:
|
|
90
|
+
let result = body(path)
|
|
91
|
+
self.resolvedModules = self.resolvedModules.add(path.absolute(), Pair(result, self.version))
|
|
92
|
+
result
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
cacheDerivedModule(
|
|
96
|
+
packagePaths: Map[PackagePair, Path]
|
|
97
|
+
packagePair: PackagePair
|
|
98
|
+
moduleName: String
|
|
99
|
+
body: Path => Module
|
|
100
|
+
): Module {
|
|
101
|
+
let path = modulePath(packagePaths, packagePair, moduleName)
|
|
102
|
+
self.derivedModules.get(path.absolute()).map {_.first}.else:
|
|
103
|
+
let result = body(path)
|
|
104
|
+
self.derivedModules = self.derivedModules.add(path.absolute(), Pair(result, self.version))
|
|
105
|
+
result
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
cacheInferredModule(
|
|
109
|
+
packagePaths: Map[PackagePair, Path]
|
|
110
|
+
packagePair: PackagePair
|
|
111
|
+
moduleName: String
|
|
112
|
+
body: Path => Module
|
|
113
|
+
): Module {
|
|
114
|
+
let path = modulePath(packagePaths, packagePair, moduleName)
|
|
115
|
+
self.inferredModules.get(path.absolute()).map {_.first}.else:
|
|
116
|
+
let result = body(path)
|
|
117
|
+
self.inferredModules = self.inferredModules.add(path.absolute(), Pair(result, self.version))
|
|
118
|
+
result
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
cacheEmittedModule(
|
|
122
|
+
packagePaths: Map[PackagePair, Path]
|
|
123
|
+
packagePair: PackagePair
|
|
124
|
+
moduleName: String
|
|
125
|
+
body: Path => Unit
|
|
126
|
+
): Unit {
|
|
127
|
+
let path = modulePath(packagePaths, packagePair, moduleName)
|
|
128
|
+
if(!self.emittedModules.contains(path.absolute())):
|
|
129
|
+
self.emittedModules = self.emittedModules.add(path.absolute(), self.version)
|
|
130
|
+
try {
|
|
131
|
+
body(path)
|
|
132
|
+
} catchAny {error =>
|
|
133
|
+
self.emittedModules = self.emittedModules.remove(path.absolute())
|
|
134
|
+
error.rethrow()
|
|
135
|
+
} grab()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
mergeVersionedMap[T](oldMap: Map[String, T], newMap: Map[String, T], getVersion: T => Int): Map[String, T] {
|
|
141
|
+
mutable result = newMap
|
|
142
|
+
oldMap.each {k, v =>
|
|
143
|
+
if(!newMap.get(k).any {getVersion(_) >= getVersion(v)}) {
|
|
144
|
+
result = result.add(k, v)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
result
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
modulePath(
|
|
151
|
+
packagePaths: Map[PackagePair, Path]
|
|
152
|
+
packagePair: PackagePair
|
|
153
|
+
moduleName: String
|
|
154
|
+
): Path {
|
|
155
|
+
let packagePath = packagePaths.get(packagePair).else {
|
|
156
|
+
panic("Internal error - package path missing: " + packagePair.groupName())
|
|
157
|
+
}
|
|
158
|
+
let file = moduleName + ".ff"
|
|
159
|
+
packagePath.slash(file)
|
|
160
|
+
}
|
package/core/Map.ff
CHANGED
|
@@ -41,6 +41,14 @@ extend self[K: Order, V]: Map[K, V] {
|
|
|
41
41
|
}
|
|
42
42
|
Map(result)
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
removeList(keys: List[K]): Map[K, V] {
|
|
46
|
+
mutable result = self.redBlack
|
|
47
|
+
keys.each {k =>
|
|
48
|
+
result = RbMap.delete(k, result)
|
|
49
|
+
}
|
|
50
|
+
Map(result)
|
|
51
|
+
}
|
|
44
52
|
|
|
45
53
|
pairs(): List[Pair[K, V]] { // TODO: Remove this method (use toList)
|
|
46
54
|
self.toList()
|
package/core/Path.ff
CHANGED
|
@@ -119,6 +119,10 @@ extend self: Path {
|
|
|
119
119
|
go(Some(self), parts.reverse())
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
contains(parts: List[String]): Bool {
|
|
123
|
+
self.endsWith(parts) || self.parent().any {_.contains(parts)}
|
|
124
|
+
}
|
|
125
|
+
|
|
122
126
|
base(): String
|
|
123
127
|
target node async """
|
|
124
128
|
import * as path from 'path'
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
data Expression {
|
|
2
|
+
EVariable(name: String)
|
|
3
|
+
EApply(function: Expression, argument: Expression)
|
|
4
|
+
ELambda(variable: String, body: Expression)
|
|
5
|
+
EAnnotate(type: Type, expression: Expression)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
data Type(name: String, typeArguments: List[Type])
|
|
9
|
+
|
|
10
|
+
data Context(variables: Map[String, Type])
|
|
11
|
+
|
|
12
|
+
data TypeError(message: String)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
check(c0: Context, t0: Type, e0: Expression): Unit {
|
|
16
|
+
e0.{
|
|
17
|
+
| ELambda(x1, e1) =>
|
|
18
|
+
t0.{
|
|
19
|
+
| Type("Function", [t2, t3]) =>
|
|
20
|
+
let c2 = c0.Context(variables = c0.variables.add(x1, t2))
|
|
21
|
+
check(c2, t3, e1)
|
|
22
|
+
t3
|
|
23
|
+
| _ =>
|
|
24
|
+
throw(TypeError("Function type not expected here"))
|
|
25
|
+
}
|
|
26
|
+
| _ =>
|
|
27
|
+
let t1 = infer(c0, e0)
|
|
28
|
+
checkSame(t0, t1)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
infer(c0: Context, e0: Expression): Type {
|
|
34
|
+
e0.{
|
|
35
|
+
| EVariable(x1) =>
|
|
36
|
+
c0.variables.get(x1).{
|
|
37
|
+
| None =>
|
|
38
|
+
throw(TypeError("Variable not in scope: " + x1))
|
|
39
|
+
| Some(t1) =>
|
|
40
|
+
t1
|
|
41
|
+
}
|
|
42
|
+
| EApply(e1, e2) =>
|
|
43
|
+
let t1 = infer(c0, e1)
|
|
44
|
+
t1.{
|
|
45
|
+
| Type("Function", [t2, t3]) =>
|
|
46
|
+
check(c0, t2, e2)
|
|
47
|
+
t3
|
|
48
|
+
| _ =>
|
|
49
|
+
throw(TypeError("Can't call non-functions"))
|
|
50
|
+
}
|
|
51
|
+
| ELambda _ =>
|
|
52
|
+
throw(TypeError("Lambda functions must be explicitly typed"))
|
|
53
|
+
| EAnnotate(t1, e1) =>
|
|
54
|
+
checkType(t1)
|
|
55
|
+
check(c0, t1, e1)
|
|
56
|
+
t1
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
checkSame(t1: Type, t2: Type): Unit {
|
|
62
|
+
if(t1.name != t2.name) {throw(TypeError("Type mismatch: " + t1.name + " vs. " + t2.name + ""))}
|
|
63
|
+
if(t1.typeArguments.size() != t2.typeArguments.size()) {
|
|
64
|
+
throw(TypeError(
|
|
65
|
+
"Type mismatch: " + t1.name + " with " +
|
|
66
|
+
t1.typeArguments.size() + " vs. " + t2.typeArguments.size() +
|
|
67
|
+
" type arguments"
|
|
68
|
+
))
|
|
69
|
+
}
|
|
70
|
+
t1.typeArguments.zip(t2.typeArguments).each {| Pair(t3, t4) =>
|
|
71
|
+
checkSame(t3, t4)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
checkType(t0: Type): Unit {
|
|
77
|
+
t0.{
|
|
78
|
+
| Type("Function", [t1, t2]) =>
|
|
79
|
+
checkType(t1)
|
|
80
|
+
checkType(t2)
|
|
81
|
+
| Type("Bool", []) =>
|
|
82
|
+
| Type("Int", []) =>
|
|
83
|
+
| Type("List", [t1]) =>
|
|
84
|
+
checkType(t1)
|
|
85
|
+
| _ =>
|
|
86
|
+
throw(TypeError("Type is not well formed"))
|
|
87
|
+
}
|
|
88
|
+
}
|