Cons/Nil optimization for scheme backend

This commit is contained in:
2026-03-18 17:07:48 -07:00
parent 4ce5d470ba
commit 5eb43f6252
10 changed files with 151 additions and 74 deletions

View File

@@ -18,6 +18,7 @@ import Data.SortedMap
import Data.IORef
import Data.SnocList
-- FIXME SnocList
SCEnv : U
SCEnv = List String
@@ -64,6 +65,12 @@ scmName qn = scmIdent $ show qn
cexpToScm : SCEnv CExp String
argsToScm : SCEnv List CExp List Quant List String
argsToScm env Nil Nil = Nil
argsToScm env (e :: es) (Many :: qs) = cexpToScm env e :: argsToScm env es qs
argsToScm env (e :: es) (Zero :: qs) = argsToScm env es qs
argsToScm env _ _ = fatalError "Arg count mismatch"
withVar : SCEnv CExp (String String) String
-- don't rebind a variable
withVar env (CBnd n) f = f $ getEnv n env
@@ -117,16 +124,54 @@ cexpToScm env (CCase sc alts) = do
(arg', env') => let ix = 1 + snoclen' lets
in conAlt env' nm (lets :< "(\{arg'} (vector-ref \{nm} \{show ix}))") args body
nilAlt : SCEnv → List Quant → CExp → String
nilAlt env Nil body = cexpToScm env body
nilAlt env (Zero :: qs) body = nilAlt ("#f" :: env) qs body
nilAlt env (Many :: qs) body = fatalError "Non-empty field on nil constructor"
consAlt' : SCEnv List String List Quant CExp String
consAlt' env nms Nil body = cexpToScm env body
consAlt' env nms (Zero :: qs) body = consAlt' ("#f" :: env) nms qs body
consAlt' env Nil (Many :: qs) body = fatalError "Too many fields on cons constructor"
consAlt' env (nm :: nms) (Many :: qs) body = consAlt' (nm :: env) nms qs body
consAlt : SCEnv String List Quant CExp String
consAlt env nm qs body = consAlt' env ("(car \{nm})" :: "(cdr \{nm})" :: Nil) qs body
-- an alt branch in a `case` statement
-- for the Nil/Cons case, we're not inside a `case`.
doAlt : String CAlt String
doAlt nm (CConAlt tag cname _ args body) = "((\{show tag}) \{conAlt env nm Lin args body})"
doAlt nm (CConAlt tag cname _ args qs body) = "((\{show tag}) \{conAlt env nm Lin args body})"
doAlt nm (CDefAlt body) = "(else \{cexpToScm env body})"
doAlt nm (CLitAlt lit body) = "((\{scmLit lit}) \{cexpToScm env body})"
-- doCase decides the top level path - case/cond/if/...
doCase : String List CAlt String
-- I'm not sure the case tree should be generating this, c.f. deleteT23
-- I'm not sure the case tree should be generating this, c.f. deleteT23 (probably from doNumCon)
doCase nm (CDefAlt body :: Nil) = cexpToScm env body
doCase nm (CConAlt tag cname _ args body :: Nil) = conAlt env nm Lin args body
-- TODO singleton ConsCon for pair, too. (Need to detect)
-- oh, but what if it's default?
doCase nm (cons@(CConAlt tag cname ConsCon args qs body ) :: rest) =
let consBranch = consAlt env nm qs body in
case rest of
Nil => consBranch
(CDefAlt body :: Nil) => "(if (null? \{nm}) \{cexpToScm env body} \{consBranch})"
(CConAlt _ _ NilCon _ qs body :: _) => "(if (null? \{nm}) \{nilAlt env qs body} \{consBranch})"
(CConAlt _ _ info _ _ _ :: _) => fatalError "\{show info} alt after cons"
(CLitAlt _ _ :: _) => fatalError "lit alt after cons"
_ => fatalError "too many alts after cons"
doCase nm (cons@(CConAlt tag cname NilCon args qs body ) :: rest) =
let nilBranch = consAlt env nm qs body in
case rest of
Nil => nilBranch
(CDefAlt body :: Nil) => "(if (null? \{nm}) \{nilBranch} \{cexpToScm env body})"
(CConAlt _ _ ConsCon _ qs body :: _) => "(if (null? \{nm}) \{nilBranch} \{consAlt env nm qs body})"
(CConAlt _ _ info _ _ _ :: _) => fatalError "\{show info} alt after nil"
(CLitAlt _ _ :: _) => fatalError "lit alt after nil"
_ => fatalError "too many alts after cons"
doCase nm (CConAlt tag cname _ args qs body :: Nil) = conAlt env nm Lin args body
doCase nm alts@(CLitAlt _ _ :: _) = "(case \{nm} \{joinBy " " $ map (doAlt nm) alts})"
--
doCase nm alts = "(case (vector-ref \{cexpToScm env sc} 0) \{joinBy " " $ map (doAlt nm) alts})"
cexpToScm env (CRef nm) = scmName nm
@@ -141,12 +186,16 @@ cexpToScm env (CLetRec nm t u) =
cexpToScm env (CLetLoop _ _) = fatalError "CLetLoop in scheme codegen"
cexpToScm env (CLoop _ _) = fatalError "CLoop in scheme codegen"
cexpToScm env CErased = "#f"
cexpToScm env (CConstr tag nm args quants) =
-- FIXME need to deal with quants
cexpToScm env (CConstr tag nm args quants NilCon) = "'()"
cexpToScm env (CConstr tag nm args quants ConsCon) = case argsToScm env args quants of
(a :: b :: Nil) => "(cons \{a} \{b})"
_ => fatalError "Wrong number of args on a ConsCon"
cexpToScm env (CConstr tag nm args quants info) =
-- FIXME need to deal with quants (on both sides!)
let args' = map (cexpToScm env) args in
"(vector \{show tag} \{joinBy " " args'})"
-- TODO
cexpToScm env (CRaw _ _) = "CRaw"
cexpToScm env (CRaw _ _) = fatalError "Stray CRaw"
-- TODO We still have a couple of these in CompileExp, for the magic Nat
cexpToScm env (CPrimOp op a b) = "(\{op} \{cexpToScm env a} \{cexpToScm env b})"
@@ -218,13 +267,13 @@ TODO this could be made faster by keeping a map of the done information
REVIEW could I avoid most of this by using `function` instead of arrow functions?
-/
-- TODO factor out to CompilerCommon
sortedNames : SortedMap QName CExp List QName List QName
sortedNames defs names =
map snd $ filter (not fst) $ foldl (go Nil) Nil $ map (True,) names
where
getBody : CAlt CExp
getBody (CConAlt _ _ _ _ t) = t
getBody (CConAlt _ _ _ _ _ t) = t
getBody (CLitAlt _ t) = t
getBody (CDefAlt t) = t
@@ -251,7 +300,7 @@ sortedNames defs names =
getNames deep acc (CRef qn) = (deep, qn) :: acc
getNames deep acc (CLet _ t u) = getNames deep (getNames deep acc t) u
getNames deep acc (CLetRec _ t u) = getNames deep (getNames deep acc t) u
getNames deep acc (CConstr _ _ ts _) = foldl (getNames deep) acc ts
getNames deep acc (CConstr _ _ ts _ info) = foldl (getNames deep) acc ts
-- if the CRaw is called, then the deps are called
getNames deep acc (CRaw _ deps) = acc -- map (_,_ deep) deps ++ acc
-- wrote these out so I get an error when I add a new constructor