allow multiple values in cps conversion

This commit is contained in:
2026-08-27 00:57:09 -06:00
parent 87baed9efc
commit 21b9f0e69d
9 changed files with 84 additions and 29 deletions
+2
View File
@@ -0,0 +1,2 @@
ret > ExitSuccess
out > #t
+12
View File
@@ -0,0 +1,12 @@
(letrec ((iter (λ (n f)
(if (zero? n)
#f
(begin (f n)
(iter (- n 1) f))))))
(call/cc
(λ (k)
(iter 10 (λ (n)
;; i don't feel like implementing (= n 5) right now lmfao
(if (zero? (- n 5))
(k #t)
#f))))))
+30 -17
View File
@@ -12,6 +12,7 @@ import Data.List.NonEmpty (NonEmpty((:|)))
import Control.Monad.Cont qualified as Cont import Control.Monad.Cont qualified as Cont
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import Gyehoek.Prelude import Gyehoek.Prelude
import Debug.Pretty.Simple
-- 뻘짓이어라 -- 뻘짓이어라
@@ -23,23 +24,34 @@ telescope f = Cont.runCont . traverse (Cont.cont . f)
one :: a -> List a
one a = [a]
oneOrUndefined :: List Val -> Val
oneOrUndefined = \case
[x] -> x
_ -> ValImm ImmUndefined
convert1 :: (GenSym :> es) => Scm.Exp -> (Val -> Eff es Exp) -> Eff es Exp
convert1 e k = convert e (k . oneOrUndefined)
-- | Transform an expression with a meta-continuation. -- | Transform an expression with a meta-continuation.
convert convert
:: forall es. (GenSym :> es) :: forall es. (GenSym :> es)
=> Scm.Exp -> (Val -> Eff es Exp) -> Eff es Exp => Scm.Exp -> (List Val -> Eff es Exp) -> Eff es Exp
convert (Scm.ExpVar x) k = k $ ValVar x convert (Scm.ExpVar x) k = k [ValVar x]
convert (Scm.ExpLit l) k = k . ValImm $ case l of convert (Scm.ExpLit l) k = k . one . ValImm $ case l of
LitInt n -> ImmInt n LitInt n -> ImmInt n
LitBool b -> ImmBool b LitBool b -> ImmBool b
_ -> _ _ -> _
-- special case: call/cc is desugared during cps-conversion... -- special case: call/cc is desugared during cps-conversion...
convert (Scm.ExpPrim (PrimCallCC withcc)) k = do convert (Scm.ExpPrim (PrimCallCC withcc)) k = do
convert withcc \withcc' -> do convert1 withcc \withcc' -> do
cc <- gensym' @Name "cc" cc <- gensym' @Name "cc"
r <- gensym' "r" r <- gensym' "r"
m <- k $ ValVar r m <- k . one $ ValVar r
ccish <- gensym' @Name "cc-ish" ccish <- gensym' @Name "cc-ish"
x <- gensym' @Name "x" x <- gensym' @Name "x"
pure [cps| pure [cps|
@@ -51,30 +63,31 @@ convert (Scm.ExpPrim (PrimCallCC withcc)) k = do
-- ...while all other prims are left as-is for later stages to -- ...while all other prims are left as-is for later stages to
-- handle.. -- handle..
convert (Scm.ExpPrim p) k = convert (Scm.ExpPrim p) k =
telescope (convert @es) p \p' -> do telescope (convert1 @es) p \p' -> do
r <- gensym' "r" r <- gensym' "r"
ExpPrim p' . MkKappa [r] <$> k (ValVar r) ExpPrim p' . MkKappa [r] <$> k [ValVar r]
convert (Scm.ExpLambda xs e) k = do convert (Scm.ExpLambda xs e) k = do
f <- gensym' "lambda-body" f <- gensym' "lambda-body"
lam <- convertLambda xs e lam <- convertLambda xs e
ke <- k $ ValVar f ke <- k [ValVar f]
pure [cps| pure [cps|
(letrec ((#{f} #{lam})) (letrec ((#{f} #{lam}))
#{ke}) #{ke})
|] |]
convert (Scm.ExpApply f xs) k = convert (Scm.ExpApply f xs) k =
telescope (convert @es) (f:|xs) \(f':|xs') -> do telescope (convert1 @es) (f:|xs) \(f':|xs') -> do
r <- gensym' "r" r <- gensym' "r"
x <- gensym' "x" x <- gensym' "x"
m <- k (ValVar x) m <- k [ValVar x]
pure $ ExpLetRec [(r, AbsKappa' [x] m)] $ ExpApply f' xs' r pure $ ExpLetRec [(r, AbsKappa' [x] m)] $
ExpApply f' xs' r
convert (Scm.ExpBegin xs) k = _ convert (Scm.ExpBegin xs) k = telescope (convert @es) xs (k . NE.last)
convert (Scm.ExpIf c t f) k = convert (Scm.ExpIf c t f) k =
convert c \c' -> convert1 c \c' ->
ExpIf c' <$> convert t k <*> convert f k ExpIf c' <$> convert t k <*> convert f k
-- let-bindings are desugared into continuation calls whose parameters -- let-bindings are desugared into continuation calls whose parameters
@@ -82,7 +95,7 @@ convert (Scm.ExpIf c t f) k =
-- sides. -- sides.
convert (Scm.ExpLet bs e) k = convert (Scm.ExpLet bs e) k =
let rhss = bs ^.. each . _2 let rhss = bs ^.. each . _2
in telescope (convert @es) rhss \rhss' -> do in telescope (convert1 @es) rhss \rhss' -> do
e' <- convert e k e' <- convert e k
kbody <- gensym' @Name "let-body" kbody <- gensym' @Name "let-body"
let bs' = bs ^.. each . _1 let bs' = bs ^.. each . _1
@@ -105,15 +118,15 @@ convertLambda
=> List Name -> Scm.Exp -> Eff es Lambda => List Name -> Scm.Exp -> Eff es Lambda
convertLambda bs m = do convertLambda bs m = do
ktail <- gensym' "lambda-tail" ktail <- gensym' "lambda-tail"
m' <- convert m $ pure . ExpContinue (ValVar ktail) . (:[]) m' <- convert1 m $ pure . ExpContinue (ValVar ktail) . (:[])
pure [cps|(λ (##{bs} #{ktail}) #{m'})|] pure [cps|(λ (##{bs} #{ktail}) #{m'})|]
convertProgram :: forall es. (GenSym :> es) => Scm.Program -> Eff es Program convertProgram :: forall es. (GenSym :> es) => Scm.Program -> Eff es Program
convertProgram p = do convertProgram p = do
ktail <- gensym' "start-ktail" ktail <- gensym' "start-ktail"
m <- telescope (convert @es) (p ^.. each . _Left) m <- telescope (convert1 @es) (p ^.. each . _Left)
(pure . ExpContinue (ValVar ktail)) (pure . ExpContinue (ValVar ktail))
pure . MkProgram $ MkLambda [] ktail m pure . MkProgram $ MkLambda [] ktail m
convertExp :: forall es. (GenSym :> es) => Scm.Exp -> Eff es Exp convertExp :: forall es. (GenSym :> es) => Scm.Exp -> Eff es Exp
convertExp e = convert e (pure . Halt1) convertExp e = convert e (pure . Halt)
+3 -1
View File
@@ -67,6 +67,7 @@ data Imm
= ImmInt Int = ImmInt Int
| ImmBool Bool | ImmBool Bool
| ImmLabel Name | ImmLabel Name
| ImmUndefined
deriving stock (Show, Generic, Data, Eq) deriving stock (Show, Generic, Data, Eq)
deriving anyclass (NFData) deriving anyclass (NFData)
@@ -168,6 +169,7 @@ instance S.DatumIso Imm where
$ S.With (. S.int) $ S.With (. S.int)
$ S.With (. S.datumIso) $ S.With (. S.datumIso)
$ S.With (. labelName) $ S.With (. labelName)
$ S.With (. S.unreadable (const "#<undefined>"))
$ S.End $ S.End
labelName :: S.DatumGrammar Name labelName :: S.DatumGrammar Name
@@ -261,7 +263,7 @@ instance S.DatumIso Program where
-- quasiquoters -- quasiquoters
class Data a => CPS a where class Data a => CPS a where
toCPS :: Datum -> a toCPS :: HasCallStack => Datum -> a
instance CPS Exp where toCPS = S.fromDatumUnsafe S.datumIso instance CPS Exp where toCPS = S.fromDatumUnsafe S.datumIso
instance CPS Val where toCPS = S.fromDatumUnsafe S.datumIso instance CPS Val where toCPS = S.fromDatumUnsafe S.datumIso
+15 -4
View File
@@ -51,7 +51,7 @@ import qualified Effectful.FileSystem.IO.ByteString as FB
import qualified Data.Set.Ordered as O import qualified Data.Set.Ordered as O
import Gyehoek.Sexp.Grammar qualified as Sexp import Gyehoek.Sexp.Grammar qualified as Sexp
import Gyehoek.Sexp.Grammar qualified as S import Gyehoek.Sexp.Grammar qualified as S
import Gyehoek.Sexp.Grammar (DatumIso, DataIso) import Gyehoek.Sexp.Grammar (DatumIso, G, DataIso, (:-)((:-)))
import Gyehoek.Prelude import Gyehoek.Prelude
@@ -84,6 +84,8 @@ data Prim e
| PrimEnvRef e Int | PrimEnvRef e Int
| PrimEnvCode e | PrimEnvCode e
| PrimCallCC e | PrimCallCC e
| PrimValues (List e)
| PrimCallWithValues e e
deriving stock (Show, Generic, Functor, Foldable, Traversable, Data, Eq) deriving stock (Show, Generic, Functor, Foldable, Traversable, Data, Eq)
deriving anyclass (NFData) deriving anyclass (NFData)
@@ -106,7 +108,7 @@ data Exp
= ExpLet (List (Name, Exp)) Exp = ExpLet (List (Name, Exp)) Exp
| ExpLetRec (List (Name, Exp)) Exp | ExpLetRec (List (Name, Exp)) Exp
| ExpPrim (Prim Exp) | ExpPrim (Prim Exp)
| ExpBegin (List Exp) | ExpBegin (NonEmpty Exp)
| ExpIf Exp Exp Exp | ExpIf Exp Exp Exp
| ExpLit Lit | ExpLit Lit
| ExpLambda (List Name) Exp | ExpLambda (List Name) Exp
@@ -167,6 +169,8 @@ primDatumIso namefn a = S.match
$ S.With (. S.headTagged2 (namefn "env-ref") a S.int) $ S.With (. S.headTagged2 (namefn "env-ref") a S.int)
$ S.With (. ht1 "env-code") $ S.With (. ht1 "env-code")
$ S.With (. ht1 "call/cc") $ S.With (. ht1 "call/cc")
$ S.With (. ht0' "values")
$ S.With (. ht2 "call-with-values")
$ S.End $ S.End
where where
idn = S.el . S.sym . namefn idn = S.el . S.sym . namefn
@@ -174,6 +178,7 @@ primDatumIso namefn a = S.match
ht1 s = S.headTagged1 (namefn s) a ht1 s = S.headTagged1 (namefn s) a
ht2 s = S.headTagged2 (namefn s) a a ht2 s = S.headTagged2 (namefn s) a a
ht1' s = S.headTagged1' (namefn s) a a ht1' s = S.headTagged1' (namefn s) a a
ht0' s = S.headTagged0' (namefn s) a
instance DatumIso a => DatumIso (Prim a) where instance DatumIso a => DatumIso (Prim a) where
-- datumIso = primDatumIso ("prim:"<>) datumIso -- datumIso = primDatumIso ("prim:"<>) datumIso
@@ -203,7 +208,7 @@ instance DatumIso Exp where
$ S.With (. S.letLike "let" S.datumIso S.datumIso S.datumIso) $ S.With (. S.letLike "let" S.datumIso S.datumIso S.datumIso)
$ S.With (. S.letLike "letrec" S.datumIso S.datumIso S.datumIso) $ S.With (. S.letLike "letrec" S.datumIso S.datumIso S.datumIso)
$ S.With (. S.datumIso) $ S.With (. S.datumIso)
$ S.With (. S.beginLike "begin" S.datumIso) $ S.With (. begin)
$ S.With (. S.ifLike "if" S.datumIso S.datumIso S.datumIso) $ S.With (. S.ifLike "if" S.datumIso S.datumIso S.datumIso)
$ S.With (. S.datumIso) $ S.With (. S.datumIso)
$ S.With (. lam) $ S.With (. lam)
@@ -212,12 +217,18 @@ instance DatumIso Exp where
$ S.End $ S.End
where where
lam = S.lambdaLike S.lambdaKeyword S.datumIso (S.el S.datumIso) lam = S.lambdaLike S.lambdaKeyword S.datumIso (S.el S.datumIso)
begin :: forall t. G (S.Datum :- t) (NonEmpty Exp :- t)
begin = S.beginLike "begin" $
S.el (S.datumIso @Exp) >>> S.rest (S.datumIso @Exp)
>>> S.onTail (S.Iso
(\(xs:-x:-t) -> (x:|xs):-t)
(\((x:|xs):-t) -> xs:-x:-t))
instance DatumIso CommandOrDef where instance DatumIso CommandOrDef where
datumIso = S.match datumIso = S.match
$ S.With (\_Command -> _Command . S.datumIso) $ S.With (\_Command -> _Command . S.datumIso)
$ S.With (\_Definition -> _Definition . S.datumIso) $ S.With (\_Definition -> _Definition . S.datumIso)
$ S.With (\_Begin -> _Begin . S.beginLike "begin" S.datumIso) $ S.With (\_Begin -> _Begin . S.beginLike "begin" (S.rest S.datumIso))
$ S.End $ S.End
instance DataIso Program where instance DataIso Program where
+6 -4
View File
@@ -59,19 +59,21 @@ toData g =
>>> runGrammar noAnn >>> runGrammar noAnn
>>> either (throwError . GrammarError) pure >>> either (throwError . GrammarError) pure
fromDatum :: Jalmot :> es => DatumGrammar a -> Datum -> Eff es a fromDatum :: (HasCallStack, Jalmot :> es) => DatumGrammar a -> Datum -> Eff es a
fromDatum g = fromDatum g =
forward (sealed g) forward (sealed g)
>>> runGrammar noAnn >>> runGrammar noAnn
>>> either (throwError . GrammarError) pure >>> either (throwError . GrammarError) pure
fromDatumUnsafe :: DatumGrammar a -> Datum -> a fromDatumUnsafe :: HasCallStack => DatumGrammar a -> Datum -> a
fromDatumUnsafe g = runJalmotUnsafe . fromDatum g fromDatumUnsafe g = runJalmotUnsafe . fromDatum g
fromDataUnsafe :: DataGrammar a -> List Datum -> a fromDataUnsafe :: HasCallStack => DataGrammar a -> List Datum -> a
fromDataUnsafe g = runJalmotUnsafe . fromData g fromDataUnsafe g = runJalmotUnsafe . fromData g
fromData :: Jalmot :> es => DataGrammar a -> List Datum -> Eff es a fromData
:: (HasCallStack, Jalmot :> es)
=> DataGrammar a -> List Datum -> Eff es a
fromData g = fromData g =
forward (sealed g) forward (sealed g)
>>> runGrammar noAnn >>> runGrammar noAnn
+12 -3
View File
@@ -31,6 +31,7 @@ module Gyehoek.Sexp.Grammar.Base
, number , number
, integer , integer
, int , int
, unreadable
-- * TODO: sort lol -- * TODO: sort lol
, prismIso , prismIso
, isoIso, decorate , isoIso, decorate
@@ -381,11 +382,19 @@ kappaKeyword = coproduct [ sym "κ", sym "kappa" ]
beginLike beginLike
:: Text :: Text
-> DatumGrammar a -> G (ListContext :- t) (ListContext :- t')
-> G (Datum :- t) (List a :- t) -> G (Datum :- t) t'
beginLike kw g = beginLike kw g =
listWithIndentation (NSpecial 0) $ listWithIndentation (NSpecial 0) $
el (symBuiltin kw) >>> rest g el (symBuiltin kw) >>> g
-- | define a printed syntax for an object which cannot be read.
unreadable
:: (t -> Text)
-> G (Datum :- t) t
unreadable f = Flip $ PartialIso
(\t -> Unreadable (f t) :- t)
(const $ Left mempty)
isoIso :: Iso' s a -> Grammar p (s :- t) (a :- t) isoIso :: Iso' s a -> Grammar p (s :- t) (a :- t)
isoIso l = iso (view l) (review l) isoIso l = iso (view l) (review l)
+1
View File
@@ -87,6 +87,7 @@ prettySimple depth = \case
& annotate SynConstant & annotate SynConstant
SimpleString s -> annotate SynString $ viaShow s SimpleString s -> annotate SynString $ viaShow s
SimpleSymbol s -> pretty s SimpleSymbol s -> pretty s
SimpleUnreadable s -> pretty s
putDoc :: Doc Syn -> IO () putDoc :: Doc Syn -> IO ()
putDoc = ANSI.renderIO stdout putDoc = ANSI.renderIO stdout
+3
View File
@@ -29,6 +29,7 @@ module Gyehoek.Sexp.Syntax
, indentation , indentation
, adorn , adorn
, indentWith , indentWith
, pattern Unreadable
, pattern Bytevector , pattern Bytevector
, pattern Symbol , pattern Symbol
, pattern String , pattern String
@@ -79,6 +80,7 @@ data Simple
| SimpleString Text | SimpleString Text
| SimpleSymbol Text | SimpleSymbol Text
| SimpleBytevector ByteString | SimpleBytevector ByteString
| SimpleUnreadable Text
deriving stock (Show, Eq, Data, Generic, Lift) deriving stock (Show, Eq, Data, Generic, Lift)
deriving anyclass (NFData) deriving anyclass (NFData)
@@ -230,6 +232,7 @@ pattern Character a = Simple (SimpleCharacter a)
pattern String a = Simple (SimpleString a) pattern String a = Simple (SimpleString a)
pattern Symbol a = Simple (SimpleSymbol a) pattern Symbol a = Simple (SimpleSymbol a)
pattern Bytevector a = Simple (SimpleBytevector a) pattern Bytevector a = Simple (SimpleBytevector a)
pattern Unreadable a = Simple (SimpleUnreadable a)
--- Lift1 instances --- Lift1 instances