Differences From
Artifact [bd52030fd5]:
1 -(defn api-parse [src]
2 - {} #TODO parse json
3 - )
1 +# [ʞ] tool/api-compile.janet
2 +# ~ lexi hale <lexi@hale.su>
3 +# 🄯 AGPLv3
4 +# ? gathers the core modules and assembles
5 +# them into a unified image that can be
6 +# loaded into gdjn.
7 +
8 +(def- extern-table @{})
9 +(def marshal-map @{})
10 +(def unmarshal-map @{})
11 +
12 +(defn- safe-to-export? [x]
13 + # only ref types and explicit exportscan be safely replaced;
14 + # otherwise e.g. any use of the string "release" will be
15 + # replaced by the value of janet/build when loaded
16 + # yes this is lunacy i don't know why they did it like that
17 + (or (function? x)
18 + (cfunction? x)
19 + (table? x)
20 + (array? x)
21 + (buffer? x)
22 + (has-key? extern-table x)))
23 +
24 +(defn- register-env [env]
25 + (merge-into extern-table
26 + (tabseq [[sym data] :pairs env
27 + :when (has-key? data :value)
28 + :when (safe-to-export? (data :value))]
29 + (data :value) sym)))
30 +
31 +
32 +# provide symbol mapping for core values &
33 +# external symbols provided by gdjn
34 +(register-env root-env)
35 +
36 +(def modules '[
37 + core prim json
38 +])
39 +
40 +# here we iterate over the core modules and load each
41 +# in turn. the array *gd-api-map* is assembled at
42 +# compile-time and then used by the init function at
43 +# runtime to enumerate and install the core modules.
44 +# when core modules use a primitive, they declare their
45 +# own *gd-api-map* which maps gensyms to the name of
46 +# the desired primitive.
47 +(def *gd-api-map* @{})
48 +(defn- install [name env]
49 + (put *gd-api-map* name env)
50 + (when (has-key? env '*gd-api-map*)
51 + (def gdmap (get-in env ['*gd-api-map* :value]))
52 + (loop [[val key] :pairs gdmap
53 + :when (safe-to-export? val)]
54 + (def sym (symbol '-val- (bxor (hash name) (hash val))))
55 + (put marshal-map val sym)
56 + (put unmarshal-map sym val))
57 + (merge-into extern-table gdmap)))
58 +
59 +(defn- log [fmt & r]
60 + (:write stderr "(api-compile) "
61 + (string/format fmt ;r)))
62 +(defn- install-mod [name]
63 + (log "loading library %s\n" name)
64 + (def env (require (string "/lib/" name)))
65 + (install (string name) env))
66 +
67 +(each m modules (install-mod m))
4 68
5 -(defn api-gen [api]
6 - @{} #TODO gen bindings
7 - )
69 +# macro implementations can be provided directly in janet
70 +# and incorporated into the API image without having to
71 +# implement anything beyond the primitive API in C
8 72
9 -(defn main [_ api-src api-dest & _]
10 - (def api
11 - (with [fd (file/open api-src :r)]
12 - (api-gen (api-parse (:read fd :all)))))
13 - (def api-bin (make-image api))
14 - (with [fd (file/open api-dest :w)]
15 - (:write fd api-bin))
16 - 0)
73 +# this function is exported as part of api.jimage.
74 +# it will be called from vm.c after initializing
75 +# the primitive bindings
76 +(defn init []
77 + (print "beginning merge")
78 + (merge-into module/cache *gd-api-map*)
79 + (print "api loaded"))
17 80
81 +# this is the build-time entry point, which does
82 +# the work of assembling the modules and marshalling
83 +# them out. it is not exported
84 +(defn main [_ out-path]
85 + (def env @{})
86 + (each sym '[init marshal-map unmarshal-map]
87 + (put env sym ((curenv) sym)))
88 + (let [blob (marshal env extern-table)]
89 + (with [fd (file/open out-path :w)]
90 + (:write fd blob)))
91 + 0)