A categorical programming language
修订版 | 3c16c3b79096f4a6c757e06af58bb81d68910725 (tree) |
---|---|
时间 | 2023-01-10 09:15:42 |
作者 | Corbin <cds@corb...> |
Commiter | Corbin |
Use a macro to simplify some append°.
This is a 40% efficient abstraction (5 lines added, 2 lines removed); it
is not worthwhile on its own. It might be more useful in a few minutes,
though.
@@ -4,6 +4,16 @@ | ||
4 | 4 | |
5 | 5 | (import (cammyo)) |
6 | 6 | |
7 | +; Flatten an arbitrary number of lists into one list by repeated appending. | |
8 | +; This is not as cheap as flatten°, but it correctly preserves nested | |
9 | +; structure. It's mostly meant as syntax sugar. Note that the arguments are | |
10 | +; backwards from appendo: (concat° out x1 x2 x3 …) | |
11 | +(define-syntax concat° | |
12 | + (syntax-rules () | |
13 | + ((_ xs) (nullo xs)) | |
14 | + ((_ xs x) (== xs x)) | |
15 | + ((_ xs x1 x2 . rest) (fresh (l) (appendo x1 x2 l) (concat° xs l . rest))))) | |
16 | + | |
7 | 17 | ; Give a WASM type to a single atomic value. |
8 | 18 | ; Cammy Ty <-> WAT Ty |
9 | 19 | (define (atomic-type° cty wty) |
@@ -108,6 +118,11 @@ | ||
108 | 118 | ((== expr 'succ) (== insts '((i32.const 1) (i32.add)))) |
109 | 119 | )) |
110 | 120 | |
121 | +; Create a fresh symbol ala (gensym s) and bind it to a logic variable. | |
122 | +; Meant for creating fresh locals for WASM. | |
123 | +; string -> WAT Symbol | |
124 | +(define (sym° s v) (conda ((== v (gensym s))) ((symbolo v)))) | |
125 | + | |
111 | 126 | ; Relate expressions to operations and input+output port contexts. |
112 | 127 | ; Cammy <-> WAT Insts × Port × Port |
113 | 128 | (define (ops-ports° expr insts input output) |
@@ -120,25 +135,20 @@ | ||
120 | 135 | (context-prim° expr input output) |
121 | 136 | (port-ctx° ip _ls1 ictx) (port-ctx° op _ls2 octx) |
122 | 137 | (get-locals° get ip) (save-locals° save op) |
123 | - (appendo get temp insts) (appendo body save temp))) | |
138 | + (concat° insts get body save))) | |
124 | 139 | ; Composition of stackful portful operations. |
125 | 140 | ((fresh (f g finsts ginsts ctx) |
126 | 141 | (== expr `(comp ,f ,g)) (appendo finsts ginsts insts) |
127 | 142 | (ops-ports° f finsts input ctx) (ops-ports° g ginsts ctx output))) |
128 | 143 | )) |
129 | 144 | |
130 | -; Create a fresh symbol ala (gensym s) and bind it to a logic variable. | |
131 | -; Meant for creating fresh locals for WASM. | |
132 | -; string -> WAT Symbol | |
133 | -(define (sym° s v) (conda ((== v (gensym s))) ((symbolo v)))) | |
134 | - | |
135 | 145 | ; Compile code which operates on the WASM stack and also accesses some fresh |
136 | 146 | ; locals. (WASM toolchains require declaring all locals before usage.) |
137 | 147 | ; Cammy <-> WAT Insts × WAT Locals |
138 | 148 | (define (local-ops° expr ops locals) |
139 | 149 | (conde |
140 | 150 | ((stack-ops° expr ops) (nullo locals)) |
141 | - ((fresh (x f done loop i v t xty xops fops xlocals flocals xflocals block loop1 loop2) | |
151 | + ((fresh (x f done loop i v t xty xops fops xlocals flocals block loopbody) | |
142 | 152 | (== expr `(pr ,x ,f)) (cammy° expr 'N t) (atomic-type° t xty) |
143 | 153 | (local-ops° x xops xlocals) (local-ops° f fops flocals) |
144 | 154 | (sym° "$done" done) (sym° "$loop" loop) (sym° "$i" i) (sym° "$v" v) |
@@ -146,18 +156,17 @@ | ||
146 | 156 | (appendo xops |
147 | 157 | `((local.set ,v) (block ,done ,loop1) (local.get ,v)) |
148 | 158 | block) |
149 | - (appendo | |
150 | - `(loop ,loop | |
151 | - (local.get ,i) (i32.eqz) (br_if ,done) | |
152 | - (local.get ,v)) | |
153 | - loop2 loop1) | |
154 | - (appendo fops | |
155 | - `((local.set ,v) | |
156 | - (local.get ,i) (i32.const 1) (i32.sub) (local.set ,i) | |
157 | - (br ,loop)) | |
158 | - loop2) | |
159 | - (appendo xlocals flocals xflocals) | |
160 | - (appendo `((local ,v ,xty) (local ,i i32)) xflocals locals))) | |
159 | + (concat° loopbody | |
160 | + `(loop ,loop | |
161 | + (local.get ,i) (i32.eqz) (br_if ,done) | |
162 | + (local.get ,v)) | |
163 | + fops | |
164 | + `((local.set ,v) | |
165 | + (local.get ,i) (i32.const 1) (i32.sub) (local.set ,i) | |
166 | + (br ,loop))) | |
167 | + (concat° locals | |
168 | + `((local ,v ,xty) (local ,i i32)) xlocals flocals) | |
169 | + )) | |
161 | 170 | )) |
162 | 171 | |
163 | 172 | ; Types for a row of variables on the stack. |
@@ -185,15 +194,14 @@ | ||
185 | 194 | ; Relationally compile to WASM. |
186 | 195 | ; Cammy <-> string × WAT Func |
187 | 196 | (define (wasm-func° expr name func) |
188 | - (fresh (source target ops params locals results decls ps rs plen prelude body) | |
197 | + (fresh (source target ops params locals results ps rs plen prelude) | |
189 | 198 | (cammy° expr source target) |
190 | 199 | (local-ops° expr ops locals) |
191 | 200 | (row° source params) (row° target results) |
192 | 201 | (conso 'param params ps) (conso 'result results rs) |
193 | - (appendo `(func ,name ,ps ,rs) locals decls) | |
194 | 202 | ; We have to load each param to the stack at the beginning of the function. |
195 | - (lengtho params plen) (prelude° plen prelude) (appendo prelude ops body) | |
196 | - (appendo decls body func) | |
203 | + (lengtho params plen) (prelude° plen prelude) | |
204 | + (concat° func `(func ,name ,ps ,rs) locals prelude ops) | |
197 | 205 | )) |
198 | 206 | |
199 | 207 | ; The relational boundary for compiling a single function. |