sire_26_compile.sire (12362B)
1 ; Copyright 2023 The Plunder Authors 2 ; Use of this source code is governed by a BSD-style license that can be 3 ; found in the LICENSE file. 4 5 #### sire_26_compile <- sire_25_datatype 6 7 ;;;; This file contains the "backend" of the Sire compiler. The code 8 ;;;; that transforms as Sire AST into a Fan value. Basically this is 9 ;;;; just inlining, lambda lifting, let-optimization, and code generation. 10 11 :| sire_01_fan 12 :| sire_02_bit 13 :| sire_03_nat 14 :| sire_05_row 15 :| sire_04_cmp 16 :| sire_05_row 17 :| sire_06_rex 18 :| sire_07_dat 19 :| sire_10_str 20 :| sire_11_set 21 :| sire_12_tab 22 :| sire_13_exp 23 :| sire_14_hax 24 :| sire_15_pad 25 :| sire_16_bar 26 :| sire_17_sug 27 :| sire_18_pat 28 :| sire_19_bst [] 29 :| sire_20_prp [] 30 :| sire_21_switch 31 :| sire_22_seed 32 :| sire_23_repl [lineRepl cogMap] 33 :| sire_25_datatype 34 35 36 ;;; Types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 37 38 # record Lam 39 | LAM 40 * pin : Bit 41 * mark : Bit 42 * recr : Bit 43 * tag : Nat 44 * args : Nat 45 * body : Sire 46 47 # data Sire -legible 48 - V Nat 49 - K Any 50 - G Bind 51 - A Sire Sire 52 - L Sire Sire 53 - R (Row Sire) Sire 54 - M Sire 55 - F Lam 56 57 # record Bind 58 | BIND 59 * bindKey : Nat ; The binding-key of the binder. 60 * bindValue : Any ; The value of the binder. 61 * bindCode : Sire ; Source for inlining (unoptimized, unlifted). 62 * bindLocation : Any ; What module was this defined in? 63 * bindName : Any ; What name was this defined under? 64 * bindProps : Any ; Free-form table of metadata about the bind. 65 66 ;; At the moment, the value that macros put in {bindProps} is always 67 ;; a tab, but Sire itself doesn't directly interact with this value in 68 ;; any way, so it can technically be anything. 69 70 71 ;;; Utils ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 72 73 74 apple=(foldl A) 75 76 (apple_ exps)=(foldl A fst-exps (drop 1 exps)) 77 78 appList=(listFoldl A) 79 80 81 ;;; Inlining ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 82 83 * # record Arg | ARG d:Nat x:Sire 84 * # record Pot | POT eLam:Lam eMark:Bool eDeep:Nat eNeed:Nat eArgs:(List Arg) 85 * # record Res | RES out:Sire xExpo:(Maybe Pot) 86 87 = (hasRefTo d exp) 88 # case exp 89 - V v | v==d 90 - A f x | (hasRefTo d f || hasRefTo d x) 91 - L v b | (hasRefTo d v || hasRefTo inc-d b) 92 - R v b | listAny (hasRefTo (add d len-v)) (b :: listFromRow v) 93 - M f | hasRefTo d f 94 - F l | hasRefTo inc-(add d getArgs-l) getBody-l 95 - _ | FALSE 96 97 =?= 1 | hasRefTo 0 | V 0 98 =?= 0 | hasRefTo 0 | V 1 99 =?= 0 | hasRefTo 0 | K 1 100 =?= 1 | hasRefTo 0 | M (V 0) 101 =?= 1 | hasRefTo 0 | L (K 7) (V 1) 102 =?= 1 | hasRefTo 0 | L (V 0) (V 0) 103 =?= 1 | hasRefTo 0 | R [(K 7)] (V 1) 104 =?= 1 | hasRefTo 0 | R [(V 1)] (V 0) 105 =?= 1 | hasRefTo 0 | F | LAM 0 0 0 0 2 (V 3) 106 =?= 0 | hasRefTo 0 | F | LAM 0 0 0 0 2 (V 2) 107 =?= 1 | hasRefTo 0 | F | LAM 0 0 0 0 2 | A (V 3) (V 2) 108 109 > Nat > Nat > Nat > Sire > Sire 110 = (moveTo from to alreadyBound topExp) 111 ^ if from==to topExp (_ alreadyBound topExp) 112 ? (go l e) 113 # case e 114 - V v | if (lth v l) e (V | sub (add v to) from) 115 - M x | M (go l x) 116 - A f x | A (go l f) (go l x) 117 - L v b | L (go l v) (go inc-l b) 118 - R v b | (ll @ add l len-v)(R (map (go ll) v) (go ll b)) 119 - F fn | F (setBody (go _ getBody-fn) fn)^(inc | add l getArgs-fn) 120 - _ | e 121 122 =?= (V 3) | moveTo 0 3 0 | V 0 123 =?= (V 2) | moveTo 1 3 0 | V 0 124 =?= (L (K 9) (V 0)) | moveTo 1 3 0 | L (K 9) (V 0) 125 =?= (L (K 9) (V 3)) | moveTo 1 3 0 | L (K 9) (V 1) 126 =?= (L (K 9) (V 4)) | moveTo 0 3 0 | L (K 9) (V 1) 127 =?= (V 0) | moveTo 0 3 1 | V 0 128 =?= (F | LAM 0 0 0 0 1 V-0) | moveTo 0 3 0 | F (LAM 0 0 0 0 1 V-0) 129 =?= (F | LAM 0 0 1 0 1 V-1) | moveTo 0 3 0 | F (LAM 0 0 1 0 1 V-1) 130 =?= (F | LAM 0 0 0 0 1 V-5) | moveTo 0 3 0 | F (LAM 0 0 0 0 1 V-2) 131 =?= (F | LAM 0 0 0 0 1 V-6) | moveTo 0 3 0 | F (LAM 0 0 0 0 1 V-3) 132 133 = (renum d !n args) 134 : a@(ARG ad ax) as < listCase args NIL 135 | (moveTo ad (add d n) 0 ax :: renum d inc-n as) 136 137 =?= ~[K-0 V-1 V-2] | renum 3 0 ~[[3 K-0] [3 V-0] [3 V-0]] 138 =?= ~[K-0 V-2 V-3] | renum 3 0 ~[[3 K-0] [2 V-0] [2 V-0]] 139 =?= ~[K-0 V-2 (L K-0 V-0)] | renum 3 0 ~[[3 K-0] [2 V-0] [2 (L K-0 V-0)]] 140 141 = (expand d e@(POT lam _ deep _ args)) 142 @ body | moveTo deep d (inc getArgs-lam) getBody-lam 143 | listFoldr L body 144 | renum d 0 (ARG d (K 0) :: listRev args) 145 146 = (reApp inline d s args f@(RES !fx !me)) 147 @ otherwise 148 : r@[rd rx] rs < listCase args f 149 | reApp inline d s rs 150 | RES (A fx | moveTo rd d 0 rx) 151 : e@[_ eMark _ eNeed eArgs] < **maybeCase me NONE 152 | ifz eNeed NONE 153 | SOME | setENeed-(dec eNeed) | setEArgs-(r :: eArgs) e 154 : e < **maybeCase me otherwise 155 | ifNot (getENeed e == 0)&&(getEMark e) otherwise 156 | inline d s args (expand d e) 157 158 > Nat > List (Maybe Pot) > List Arg > Sire > Res 159 = (inline d s params syr) 160 @ rap (reApp inline d s params) 161 # case syr 162 - K _ | rap | RES syr NONE 163 - V v | rap | RES syr | listIdx v s 164 - G p | rap | RES syr | getXExpo | inline d NIL NIL | getBindCode pinItem-p 165 - M b 166 @ @(RES r me) | inline d s ~[] b 167 | rap | RES r (fmapMaybe me | setEMark TRUE) 168 - F (lam@(LAM _ lMark lRecr _ lArgs lBody)) 169 | rap 170 | RES @ s | listWeld (listRep NONE inc-lArgs) s 171 @ d | inc (add lArgs d) 172 | F | (setBody _ lam)^(getOut | inline d s ~[] lBody) 173 | if lRecr NONE 174 | SOME (POT lam lMark d lArgs ~[]) 175 - R vs b 176 @ nBinds (len vs) 177 @ d_ | add d nBinds 178 @ s_ | listWeld (listRep NONE nBinds) s 179 @ vr | map (inline d_ s_ NIL) vs 180 @ br | inline d_ s_ params b 181 | RES (R (map getOut vr) getOut-br) NONE 182 - L v b 183 @ @(RES vrs vre) | inline d s NIL v 184 @ @(RES brs _bre) | inline inc-d (vre::s) params b 185 | RES (L vrs brs) NONE 186 - A f x 187 @ @(RES x _) | inline d s ~[] x 188 | inline d s (ARG d x :: params) f 189 190 191 ;;; Compilation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 192 193 ;; {codeShaped} checks if a value is a valid law-shape. Nats are valid 194 ;; code if they are less than the binding depth (variable references). 195 ;; Otherwise, only the following forms are valid: 196 ;; 197 ;; (0 _ _) 198 ;; (1 _ _) 199 ;; (2 x) 200 201 = (codeShaped depth v) 202 @ h | car v 203 @ t | cdr v 204 @ hh | car h 205 || (isNat v && lth v depth) 206 && (isApp v) 207 || (h == 2) 208 && (isApp h) 209 || (hh == 1) 210 || (hh == 0) 211 212 !! (codeShaped 1 0) 213 !! (codeShaped 0 (0 0 0)) 214 !! (codeShaped 0 (2 0)) 215 !! (codeShaped 0 (1 0 0)) 216 !! not (codeShaped | 5 5) 217 !! not (codeShaped | 0 0) 218 !! not (codeShaped | 1 0) 219 !! not (codeShaped | 1 0 0 0) 220 !! not (codeShaped | 2 1 2) 221 !! not (codeShaped | codeShaped) 222 !! not (codeShaped | (x&x)) 223 224 = (getSVal x fallback k) 225 # case x 226 - K x | k x 227 - G b | k (**getBindValue | pinItem b) 228 - M x | getSVal x fallback k 229 - _ | fallback 230 231 232 ;;; New Compiler ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 233 234 # data Exp -legible 235 - VAL Any 236 - VAR Nat 237 - APP Exp Exp 238 239 # record Fun 240 | FUN 241 * pin : Bool 242 * tag : Nat 243 * slf : Nat 244 * arg : List Nat 245 * bin : Tab Nat Exp 246 * bod : Exp 247 248 (**getVal x o k)=(# case x)(VAL v - (**k v))(_ - o) 249 250 =?= %nah | getVal (APP 3 4) %nah v2 251 =?= %nah | getVal (VAR 9) %nah (I x ?? x) 252 =?= 9 | getVal (VAL 9) %nah id 253 254 > Exp > Exp > Exp 255 = (app f x) 256 @ fallback (APP f x) 257 : fv < getVal f fallback 258 : xv < getVal x fallback 259 | if (arity fv == 1) fallback 260 | VAL (fv xv) 261 262 =?= (VAL 0-1) | app VAL-0 VAL-1 263 =?= (APP VAL-4 VAL-4) | app VAL-4 VAL-4 264 =?= (APP VAL-4 VAL-4) | app VAL-4 VAL-4 265 =?= (APP VAL-0 VAR-0) | app VAL-0 VAR-0 266 267 = (ing compile s x st@[env nex]) 268 @ ing (ing compile) 269 # case x 270 - V i | st,(listIdx i s) 271 - M x | ing s x st 272 - G g | st,(VAL (**getBindValue | pinItem g)) 273 - K x | st,(VAL x) 274 - A f x @ [st f] (ing s f st) 275 @ [st x] (ing s x st) 276 | st,(app f x) 277 - L v b @ [[env nex] vr] | ing s v [env nex] 278 # case vr 279 - _ | ing (vr::s) b [env nex] 280 - APP _ _ @ k | nex 281 @ nex | inc nex 282 @ env | tabPut env k vr 283 | ing (VAR k :: s) b [env nex] 284 - R vs b 285 @ nBinds | len vs 286 @ ks | gen nBinds add-nex 287 @ nex | add nex nBinds 288 @ ss | listWeld (listFromRow | map VAR ks) s 289 @ st ^ foldl _ [env nex] (zip vs ks) 290 & (st [vx k]) 291 @ [[env nex] vr] (ing ss vx st) 292 | [(tabPut env k vr) nex] 293 | ing ss b st 294 - F lam @ @(LAM pin _mark _rec tag lArg lBod) lam 295 @ slf | nex 296 @ !nex | inc nex 297 @ arg | listGen lArg (add nex) 298 @ !nex | add nex lArg 299 @ s2 | listWeld (listMap VAR listRev-arg) (VAR slf :: s) 300 @ [bin nex],bod | ing s2 lBod [#[] nex] 301 @ [cns free] | compile nex (FUN pin tag slf arg bin bod) 302 ^ [[env nex] _] 303 | listFoldl APP (VAL cns) (listMap VAR free) 304 305 (ingest compile top)=(ing compile NIL top [#[] 0]) 306 307 ;; TODO: This are using {#=} because Stew does not yet understand 308 ;; {#genenv}. 309 310 #= gAdd 311 #| G 312 #| tabIdx {add} #getenv 313 314 =?= ([#[] 0], VAL 0) ^ ing v2 NIL _ [#[] 0] | K-0 315 =?= ([#[] 0], VAL add) ^ ing v2 NIL _ [#[] 0] | gAdd 316 =?= ([#[] 0], VAL (add 1)) ^ ing v2 NIL _ [#[] 0] | A gAdd K-1 317 =?= ([#[] 0], VAL 7) ^ ing v2 NIL _ [#[] 0] | L K-7 V-0 318 =?= ([#[] 0], APP VAL-7 VAL-7) ^ ing v2 NIL _ [#[] 0] | L K-7 (A V-0 V-0) 319 =?= ([#[] 0], APP VAL-7 VAL-7) ^ ing v2 NIL _ [#[] 0] | L K-7 (A V-0 V-0) 320 321 =?= ++ [[0=(APP VAL-4 VAL-4)] 1] 322 ++ VAR-0 323 ^ ing v2 ~[VAR-0] _ [#[0=(APP VAL-4 VAL-4)] 1] 324 | V-0 325 326 =?= ++ [[0=(APP VAL-4 VAL-4)] 1] 327 ++ APP (VAL 1) (VAR 0) 328 ^ ing v2 ~[VAR-0] _ [[0=(APP VAL-4 VAL-4)] 1] 329 | L K-1 (A V-0 V-1) 330 331 > Fun > (Tab Nat Nat, List Nat) 332 = (stats fun@(FUN _ _ fSlf fArg fBin fBod)) 333 ^ @ final@[seen tab lis] (_ fBod (%[], #[], NIL)) 334 | (tab, listRev lis) 335 ? (go sx st0@[seen0 tab0 lis0]) 336 # case sx 337 - VAL _ | st0 338 - APP f x | go x (go f st0) 339 - VAR k @ [seen tab lis] 340 | if (setHas k seen0 || not (tabHas k fBin)) st0 341 | go (tabIdx k fBin) 342 | (setIns k seen0, tab0, lis0) 343 ++ seen 344 ++ tabIns k inc-(tabIdx k tab) tab 345 ++ if (tabHas k tab) lis k::lis 346 347 =?= [[=1 3=2] ~[1 3]] 348 | stats 349 | FUN 0 0 0 ~[1 2] #[3=(APP VAL-2 VAR-3)] (APP VAR-1 VAR-3) 350 351 > Fun > (Tab Nat Nat, List Nat) > Any 352 = (codeGen fn stat@(refcounts, refSeq)) 353 @ @(FUN fPin fTag fSlf fArg fBin fBod) fn 354 @ (keep k) 355 : _ _ < tabSearchCase k fBin FALSE 356 : _ cv < tabSearchCase k refcounts FALSE 357 | gth cv 1 358 @ binds | listFilter keep refSeq 359 @ nBind | listLen binds 360 @ nArg | listLen fArg 361 @ scopeSz | inc (add nArg nBind) 362 @ scope | (fSlf :: listWeld fArg binds) 363 @ table | tabFromPairsList (listZip scope | listEnumFrom 0) 364 @ (cgen s) 365 # case s 366 - VAL k | if (codeShaped scopeSz k) (2 k) k 367 - APP f x | 0 (cgen f) (cgen x) 368 - VAR v @ fall (tabIdx v table) 369 | if (1 /= tabIdx v refcounts) fall 370 : _ bx < tabSearchCase v fBin fall 371 | cgen bx 372 @ (bind k rest) 373 | 1 (cgen | tabIdx k fBin) rest 374 ^ if fPin (4 _) _ 375 @ bOut (cgen fBod) 376 | 0 fTag nArg 377 | listFoldr bind bOut binds 378 379 > Nat > Fun > (Any, List Nat) 380 = (compile nex f1) 381 @ @(FUN pin1 tag1 slf1 arg1 bin1 bod1) f1 382 @ (isFree k) | not (k==slf1 || tabHas k bin1 || listHas k arg1) 383 @ stat1@(_, !refs1) | stats f1 384 @ free | listFilter isFree refs1 385 @ newSelf | listFoldl APP VAR-nex (listMap VAR free) 386 @ f2 | setSlf | nex 387 | setArg | listWeld free arg1 388 | setBin | tabIns slf1 newSelf bin1 389 | f1 390 @ (f3, stat3) | if listIsEmpty-free (f1, stat1) (f2, stats f2) 391 | (codeGen f3 stat3, free) 392 393 > Sire > Any 394 = (compileSire inlined) 395 ^ (fst _) 0 396 @ ([bin n], bod) (ingest compile inlined) 397 | compile (add 2 n) 398 | FUN 0 0 n ~[inc-n] bin bod 399 400 401 ;;; Compiler API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 402 403 > Sire > Any 404 (evalSire sire)=(| compileSire | getOut | inline 0 NIL NIL sire) 405 406 407 ;;; Tests ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 408 409 three=3 410 411 ;; TODO: These are using {#=} because Stew does not yet understand 412 ;; {#genenv}. 413 414 #= gAdd #| G #| tabIdx {add} #getenv 415 #= gThree #| G #| tabIdx {three} #getenv 416 417 =?= add | evalSire | apple_ [gAdd] 418 =?= 6 | evalSire | apple_ [gAdd K-3 gThree] 419 420 421 ;;; Exports ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 422 423 ^-^ 424 ^-^ LAM 425 ^-^ V K G A L R M F 426 ^-^ BIND getBindKey getBindValue getBindCode getBindLocation getBindName 427 ^-^ hasRefTo 428 ^-^ 429 ^-^ evalSire 430 ^-^ apple apple_ appList 431 ^-^