-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdependencies.stanza
More file actions
325 lines (284 loc) · 12.9 KB
/
dependencies.stanza
File metadata and controls
325 lines (284 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
;; See license.txt for details about licensing.
defpackage stz/dependencies :
import core
import collections
import reader
import macro-utils
import stz/input
import stz/compiler
import stz/core-macros
import stz/arg-parser
import stz/params
import stz/utils
import stz/algorithms
import stz/renamer
import stz/resolver
import stz/type
import stz/type-to-kform
import stz/kform
import stz/kform-to-tgt
import stz/pl-ir
import stz/il-ir
import stz/tl-ir
import stz/kl-ir
import stz/asm-ir
import stz/tgt-ir
import stz/tgt-utils
import stz/namemap
import stz/backend
import stz/codegen
import stz/asm-emitter
import stz/pkg
import stz/fuse
import stz/compiler
import stz/ast-lang
import stz/reader-lang
import stz/check-lang
import stz/renamer-lang
import stz/resolver-lang
import stz/serializer-lang
import stz/ast-printer-lang
import registry
var *build-dir* = "debug"
var *build-opt* = ""
defn macroexpand (forms:List) -> List :
val es = parse-syntax[core / #exps!](forms)
cons(`$begin, es)
defn filename-packages (filenames:Seqable<String>) -> HashTable<String,List<IPackage>> :
defn packages (e:IExp) :
to-list $ generate<IPackage> :
let loop (e:IExp = e) :
match(e) :
(e:IPackage) :
check(e)
yield(e)
(e:IBegin) :
do(loop, exps(e))
(e) :
false
defn packages (filename:String) :
throw(InvalidExtensionError(filename)) when not suffix?(filename,".stanza")
packages(read-prog(macroexpand(read-file(filename))))
to-hashtable<String, List<IPackage>> $ for filename in filenames seq :
filename => packages(filename)
defn pkg-name (name:Symbol) -> String :
string-join([*build-dir* "/" replace(to-string $ name, "/", "$$") ".pkg"])
defn non-suffix (filename:String) :
val index = last-index-of-char(filename, '.')
filename[0 to (index as Int)]
defn obj-filename (filename:String) :
non-suffix(base-name(filename))
;; TODO: CURRENTLY DOESN'T HELP BECAUSE AREN'T PART OF MODELED DEPENDENCIES
defn update-cpp-link (link:Link) :
switch(os(link)) :
`Darwin : [Link(os(link), to-tuple $ cat(value(link), ["-lc++"]))]
`GNU/Linux : [Link(os(link), to-tuple $ cat(value(link), ["-lstdc++"]))]
`* : cat(update-cpp-link(Link(`Darwin, value(link))), update-cpp-link(Link(`GNU/Linux, value(link))))
defn update-cpp-package (pkg:Package) :
Package(name(pkg), dependencies(pkg), to-list $ cat-all(seq(update-cpp-link, links(pkg))))
defn update-cpp-file (file:File) :
if suffix?(name(file), ".cpp") :
val default-package = Package(to-symbol(name(file)), List(), List(Link(`*, [])))
val pkgs = to-list $ [default-package] when empty?(packages(file)) else packages(file)
File(name(file), kind(file), flags(file), syntax(file), map(update-cpp-package, pkgs))
;; println("# UPDATING CPP %_" % [res])
else :
file
public defn gen-dependencies (i-all-files:Seqable<File>) :
val all-files = to-list $ seq(update-cpp-file, i-all-files)
val files0 = to-tuple $ for file in all-files filter : suffix?(name(file), ".stanza")
val filenames = to-list $ seq(name, filter({ kind(_) != `gen}, files0))
val filename-pkgs = filename-packages(filenames)
val file-table0 = to-hashtable<String, File> $ seq(fn (f) : name(f) => f, files0)
val graph = HashTable<Symbol, List<Symbol>>()
val package-filename = HashTable<Symbol, String>()
val files = to-tuple $ generate<File> :
for kv in filename-pkgs do :
val filename = key(kv)
val file = file-table0[filename]
val pkgs = generate<Package> :
val pkg-table = to-hashtable<Symbol, Package> $ seq(fn (p) : name(p) => p, packages(file))
for pkg in value(kv) do :
val pkg-name = name!(pkg)
package-filename[pkg-name] = filename
graph[pkg-name] = to-list $ for imp in imports(pkg) seq : name!(package(imp as IImport))
yield(get?(pkg-table, pkg-name, Package(pkg-name, List(), List())))
yield(File(name(file), kind(file), flags(file), syntax(file), to-list $ pkgs))
for file in files0 do :
if kind(file) == `gen :
val pkg = Package(to-symbol $ obj-filename(name(file)), List(), List())
package-filename[name(pkg)] = name(file)
graph[name(pkg)] = List()
yield(File(name(file), kind(file), flags(file), syntax(file), List(pkg)))
;; println-all(["FILES " files])
val file-table = to-hashtable<String, File> $ seq(fn (f) : name(f) => f, files)
val groups = strong-components(graph)
;; for group in groups do :
;; println("# %_" % [group])
;; for kv in graph do :
;; println-all(["PKG " key(kv) " IMPORTS " value(kv)])
defn user? (name:Symbol) :
kind(file-table[package-filename[name]]) != `stz
val pkgs = to-hashtable<Symbol, Package> $ generate<KeyValue<Symbol, Package>> :
for file in files do :
for package in packages(file) do :
yield(name(package) => package)
for package in get?(filename-pkgs, name(file), List()) do :
if not contains?(seq(name, packages(file)), name!(package)) :
yield(name!(package) => Package(name!(package), List(), List()))
println("%__STZ_FLAGS = -pkg %_ %_" % [*build-dir* *build-dir* *build-opt*])
println("")
print("%_/all:" % [*build-dir*])
for file in filter({ contains?([`app, `plugin], _) }, files) do :
print(" %_/%_" % [*build-dir* obj-filename(name(file))])
println("\n\tmkdir -p %_" % [*build-dir*])
println("")
println("%_/clean: "% [*build-dir*])
println("\trm -f %_/*" % [*build-dir*])
println("")
defn compiler-of (file:File) -> [String, True|False] :
match(syntax(file)) :
(s:Syntax) : [string-join([*build-dir* "/" value(s) "-stanza"]), true]
(s:False) : ["${STZ}", false]
val group-name = HashTable<Symbol, Symbol>()
for group in groups do :
match(group) :
(elts:List<Symbol>) :
for e in elts do :
group-name[e] = head(elts)
(elt:Symbol) :
group-name[elt] = elt
defn print-rule (team:List<Symbol>) :
val e = head(team)
val file = file-table[package-filename[e]]
if contains?([`std, `mac, `app, `plugin], kind(file)) :
print("%s: %s" % [seq(pkg-name, team) seq({package-filename[_]}, team)])
for guy in team do :
for import in unique(seq({ group-name[_] }, graph[guy])) do :
if e != import :
print(" %_" % [pkg-name(import)]) when user?(import)
for dep in dependencies(pkgs[guy]) do :
print(" %_" % [value(dep)])
val [compiler, compiler?] = compiler-of(file-table[package-filename[e]])
print(" %_" % [compiler]) when compiler?
println("")
val file-set = HashSet<String>()
for pkg-name in team do :
add(file-set, package-filename[pkg-name]) when user?(pkg-name)
val files = to-tuple $ file-set
println("\t%_ %_ ${%__STZ_FLAGS}" % [compiler string-join(files, " ") *build-dir*])
println("")
for group in groups do :
match(group) :
(elts:List<Symbol>) :
print-rule(elts)
(elt:Symbol) :
print-rule(List(elt))
val c-files = to-tuple $ for file in all-files filter : suffix?(name(file), ".c")
for file in c-files do :
println("%_/%_.o: %_" % [*build-dir* obj-filename(name(file)) name(file)])
val flags = "" when flags(file) is False else flags(file)
println("\t${CC} %_ -c ${CFLAGS} -o %_/%_.o %_" % [flags *build-dir* obj-filename(name(file)) name(file)])
println("")
val cpp-files = to-tuple $ for file in all-files filter : suffix?(name(file), ".cpp")
for file in cpp-files do :
println("%_/%_.o: %_" % [*build-dir* obj-filename(name(file)) name(file)])
val flags = "" when flags(file) is False else flags(file)
println("\tc++ %_ -c ${CFLAGS} -o %_/%_.o %_" % [flags *build-dir* obj-filename(name(file)) name(file)])
println("")
val gen-files = to-tuple $ for file in files filter : kind(file) == `gen
for file in gen-files do :
val obj = obj-filename(name(file))
val base = obj[length("eval-") to false]
println("%_/%_.stanza: %_/gen-repl %_/eval.pkg %_" % [*build-dir* obj *build-dir* *build-dir* pkg-name(to-symbol $ base)])
println("\t%_/gen-repl %_ ${STANZADIR} %_" % [*build-dir* *build-dir* base])
println("")
println("%_: %_/%_.stanza" % [pkg-name(to-symbol $ obj) *build-dir* obj])
println("\t${STZ} %_/%_.stanza ${%__STZ_FLAGS}" % [*build-dir* obj *build-dir*])
println("")
;; val mac-files = to-tuple $ for file in files filter : kind(file) == `mac
;; for file in mac-files do :
;; println("%_/%_-stanza: %_" % [*build-dir* obj-filename(name(file)) name(file)])
;; println("\tstanza %_ ${STZ_COMPILER_MAIN} -flags OPTIMIZE -s %_/%_.s -o %_/%_-stanza" % [name(file) *build-dir* obj-filename(name(file)) *build-dir* obj-filename(name(file))])
;; println("")
defn used-packages (pkg-roots:Seqable<Package>) :
val used = HashTable<Symbol, Package>()
defn loop (root:Package) -> False :
if not key?(used, name(root)) :
used[name(root)] = root
do(fn (i): loop(pkgs[i]) when key?(pkgs, i), graph[name(root)])
do(loop, pkg-roots)
values(used)
defn direct-packages (pkgs:Seqable<Package>) :
unique(cat-all(seq({ graph[name(_)] }, pkgs)))
defn os-links (os-name:Symbol, pkgs:Seqable<Package>) :
generate<Link> :
for pkg in pkgs do :
for link in links(pkg) do :
if os(link) == os-name or os(link) == `* :
yield(link)
for file in files do :
if contains?([`app, `plugin `mac], kind(file)) :
val [compiler, compiler?] = compiler-of(file)
val used-pkgs = to-tuple $ used-packages(packages(file))
val direct-pkgs = to-tuple $ direct-packages(packages(file))
val app-filename = string-join([obj-filename(name(file)) ("-stanza" when kind(file) == `mac else "")])
;; println("# USED-PKGS %_" % [used-pkgs])
;; ADD DEFAULT C++ LINKING -- TODO: IMPROVE TO ONLY ADD IF NEEDED
val mac-links = cat(os-links(`Darwin, used-pkgs), [ Link(`Darwin, ["-lc++"]) ])
val linux-links = cat(os-links(`GNU/Linux, used-pkgs), [ Link(`GNU/Linux, ["-lstdc++"]) ])
println("ifeq ($(OS2), Darwin)")
defn unique-join (flags:Seqable<String>) -> String :
string-join(unique $ flags, " ")
val mac-extra-flags = ["-dynamiclib"] when kind(file) == `plugin else []
println(" %__FLAGS = %_" % [app-filename, unique-join(cat(cat-all(seq(value, mac-links)), mac-extra-flags))])
println(" %__APP = %_%_" % [app-filename, app-filename, ".dylib" when kind(file) == `plugin else ""])
println("else")
println(" OS := $(strip $(shell uname -o))")
println(" ifeq ($(OS), GNU/Linux)")
val linux-extra-flags = ["-shared"] when kind(file) == `plugin else []
println(" %__FLAGS = %_" % [app-filename, unique-join(cat(cat-all(seq(value, linux-links)), linux-extra-flags))])
println(" %__APP = %_%_" % [app-filename, app-filename, ".so" when kind(file) == `plugin else ""])
println(" endif")
println("endif")
println("")
val imports = join(unique(seq({ pkg-name(group-name[_]) }, filter(user?, direct-pkgs))), " ")
println("%_/%_: %_ %* %_" % [*build-dir* app-filename, name(file), imports, compiler when compiler? else ""])
;; println("%_/%_: %_ %* %_" % [*build-dir* app-filename, name(file), join(seq({ pkg-name(_) }, filter(user?, direct-pkgs)), " "), compiler when compiler? else ""])
println("\t%_ %_ -o %_/${%__APP} -s %_/%_.s ${%__STZ_FLAGS} -ccflags \"${%__FLAGS}\"" %
[compiler, string-join([name(file) (" ${STZ_COMPILER_MAIN}" when kind(file) == `mac else "")])
*build-dir* app-filename *build-dir* app-filename *build-dir* app-filename])
println("")
defn InvalidExtensionError (filename:String) :
new Exception :
defmethod print (o:OutputStream, this) :
print(o, "File %_ does not have a valid Stanza file extension." % [filename])
defn main () :
val filename = command-line-arguments()[1]
val input = to-tuple $ registry-files(filename)
;; println("# %_" % [input])
;; println(stanza-files)
println("STZ = stanza")
println("STANZADIR = `python stanza-utils/stanza-install-dir.py`")
println("STZ_COMPILER_MAIN = ${STANZADIR}/compiler/stz-driver.stanza")
println("OS2 := $(strip $(shell uname))")
println("")
println("ifeq ($(OS2), Darwin)")
println(" $(info Compiling for Darwin)")
println(" CFLAGS = -DMACOSX=1")
println(" LIBS = $(COMMON_LIBS)")
println("else")
println(" $(info Compiling for non Darwin)")
println(" OS := $(strip $(shell uname -o))")
println(" ifeq ($(OS), GNU/Linux)")
println(" $(info Compiling for GNU/Linux)")
println(" CFLAGS = ")
println(" LIBS = $(COMMON_LIBS) -lm")
println(" endif")
println("endif")
println("")
for [dir, opt] in [["release", "-optimize"] ["debug" ""]] do :
let-var *build-dir* = dir :
let-var *build-opt* = opt :
gen-dependencies(input)
main()