plunder

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 ^-^