fix: closure-conversion of recursive functions
build / build (push) Successful in 1m28s

This commit is contained in:
2026-08-30 02:12:16 -06:00
parent 03797d573b
commit 276c2c1249
3 changed files with 17 additions and 15 deletions
+3 -3
View File
@@ -16,12 +16,12 @@ close = transformM \case
-- it would probably be most sane to generate a symbol for `env`, -- it would probably be most sane to generate a symbol for `env`,
-- but we're reusing the lambda binding so we don't have to -- but we're reusing the lambda binding so we don't have to
-- explicitly substitute recursive calls. -- explicitly substitute recursive calls.
let frees = nub $ freeWithBound' [f] lam let frees = nub $ free' lam
let m' = ifoldr let m' = ifoldr
(\n x q -> (\n x q ->
let n' = if x == f then 0 else n+1 let p = if x == f then PrimEnv @Val else PrimEnvRef n
in [cps| in [cps|
(prim (env-ref #{n'}) (prim #{p}
(κ (#{x}) #{q})) (κ (#{x}) #{q}))
|]) |])
m frees m frees
+2
View File
@@ -81,6 +81,7 @@ data Prim e
| PrimZeroP e | PrimZeroP e
| PrimNewline | PrimNewline
| PrimMakeClosure { code :: e, env :: List e } | PrimMakeClosure { code :: e, env :: List e }
| PrimEnv
| PrimEnvRef Int | PrimEnvRef Int
| PrimEnvCode e | PrimEnvCode e
| PrimCallCC e | PrimCallCC e
@@ -167,6 +168,7 @@ primDatumIso namefn a = S.match
$ S.With (. ht1 "zero?") $ S.With (. ht1 "zero?")
$ S.With (. ht0 "newline") $ S.With (. ht0 "newline")
$ S.With (. ht1' "make-closure") $ S.With (. ht1' "make-closure")
$ S.With (. ht0 "env")
$ S.With (. S.headTagged1 (namefn "env-ref") S.int) $ S.With (. S.headTagged1 (namefn "env-ref") S.int)
$ S.With (. ht1 "env-code") $ S.With (. ht1 "env-code")
$ S.With (. ht1 "call/cc") $ S.With (. ht1 "call/cc")
+12 -12
View File
@@ -132,7 +132,7 @@ stepT :: Jalmot :> es => Env -> VM -> Tail -> Eff es VM
stepT g vm tc@(Call nargs) = do stepT g vm tc@(Call nargs) = do
(args,f,ret,frm) <- parseCall nargs (vm ^. activeFrame) (args,f,ret,frm) <- parseCall nargs (vm ^. activeFrame)
& expectOf [i|#{show tc}|] _Just & expectOf [i|bad call: #{show tc}|] _Just
rt <- getRoutine g f rt <- getRoutine g f
let newFrame = MkFrame $ args ++ [f,ret] let newFrame = MkFrame $ args ++ [f,ret]
pure $ vm pure $ vm
@@ -145,7 +145,7 @@ stepT g vm tc@(Call nargs) = do
stepT g vm tc@(Return nret) = do stepT g vm tc@(Return nret) = do
(xs,_) <- splitAtExact nret (vm ^. activeFrame . #locals) (xs,_) <- splitAtExact nret (vm ^. activeFrame . #locals)
& expectOf [i|"#{show tc}"|] _Just & expectOf [i|bad return: #{show tc}|] _Just
expectOf [i|no return addr|] (activeFrame . returnAddress) vm >>= \case expectOf [i|no return addr|] (activeFrame . returnAddress) vm >>= \case
ObjLabel "halt" -> pure $ vm & #result ?~ xs ObjLabel "halt" -> pure $ vm & #result ?~ xs
ra -> do ra -> do
@@ -159,7 +159,7 @@ stepT g vm tc@(Return nret) = do
stepT g vm tc@(TailCall nargs) = do stepT g vm tc@(TailCall nargs) = do
(args,f,ra) <- parseTailCall nargs (vm ^. activeFrame) (args,f,ra) <- parseTailCall nargs (vm ^. activeFrame)
& expectOf [i|#{show tc}|] _Just & expectOf [i|bad call: #{show tc}|] _Just
case f of case f of
ObjLabel "halt" -> pure $ vm & #result ?~ args ObjLabel "halt" -> pure $ vm & #result ?~ args
_ -> do _ -> do
@@ -196,12 +196,14 @@ stepP g vm p = traverse (evalVal g vm) p >>= \case
case env of case env of
ObjHob (HobClosure l _) -> ret1 . ObjImm . ImmLabel $ l ObjHob (HobClosure l _) -> ret1 . ObjImm . ImmLabel $ l
_ -> vmerror [i|expected closure, got #{env}|] _ -> vmerror [i|expected closure, got #{env}|]
PrimEnvRef n -> PrimEnv -> do
case vm ^? activeFrame . activeProcedure of x <- vm & expectOf "expected closure" (activeFrame . activeProcedure)
Just (ObjHob (HobClosure {label,env})) -> ret1 case n of ret1 x
0 -> ObjLabel label PrimEnvRef n -> do
n -> env ^?! ix (n-1) (label,env) <- vm & expectOf "expected closure"
x -> vmerror [i|expected closure, got #{x}|] (activeFrame . activeProcedure . #_ObjHob . #_HobClosure)
x <- env & expectOf "expected upval" (ix n)
ret1 x
PrimCons x y -> ret1 $ ObjHob $ HobPair x y PrimCons x y -> ret1 $ ObjHob $ HobPair x y
PrimCar x -> case x of PrimCar x -> case x of
ObjHob (HobPair car _) -> ret1 car ObjHob (HobPair car _) -> ret1 car
@@ -250,9 +252,7 @@ getRoutine g f = do
expectOf expectOf
:: (HasCallStack, Jalmot :> es) :: (HasCallStack, Jalmot :> es)
=> Text -> Getting (First a) s a -> s -> Eff es a => Text -> Getting (First a) s a -> s -> Eff es a
expectOf msg l s = case s ^? l of expectOf msg l = maybe (vmerror msg) pure . preview l
Just x -> pure x
Nothing -> vmerror [i|bad stack, expecting #{msg}|]
evalToLabel :: Jalmot :> es => Env -> VM -> Val -> Eff es Label evalToLabel :: Jalmot :> es => Env -> VM -> Val -> Eff es Label
evalToLabel e vm v = evalToLabel e vm v =