+30
-27
@@ -25,23 +25,22 @@ common ghcstuffs
|
|||||||
default-extensions:
|
default-extensions:
|
||||||
BlockArguments
|
BlockArguments
|
||||||
DeriveGeneric
|
DeriveGeneric
|
||||||
OverloadedRecordDot
|
DerivingVia
|
||||||
DuplicateRecordFields
|
DuplicateRecordFields
|
||||||
NoFieldSelectors
|
NoFieldSelectors
|
||||||
|
OrPatterns
|
||||||
|
OverloadedLabels
|
||||||
|
OverloadedRecordDot
|
||||||
OverloadedStrings
|
OverloadedStrings
|
||||||
PartialTypeSignatures
|
PartialTypeSignatures
|
||||||
PatternSynonyms
|
PatternSynonyms
|
||||||
QuasiQuotes
|
QuasiQuotes
|
||||||
DerivingVia
|
|
||||||
OverloadedLabels
|
|
||||||
OrPatterns
|
|
||||||
|
|
||||||
executable gyehoek
|
executable gyehoek
|
||||||
import: ghcstuffs, ghcstuffs-dev
|
import: ghcstuffs, ghcstuffs-dev
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, base ^>=4.21.2.0
|
, base ^>=4.21.2.0
|
||||||
, gyehoek
|
, gyehoek
|
||||||
|
|
||||||
hs-source-dirs: app
|
hs-source-dirs: app
|
||||||
@@ -49,19 +48,19 @@ executable gyehoek
|
|||||||
|
|
||||||
library
|
library
|
||||||
import: ghcstuffs, ghcstuffs-dev
|
import: ghcstuffs, ghcstuffs-dev
|
||||||
ghc-options: -fplugin=Effectful.Plugin
|
ghc-options: -fplugin=Effectful.Plugin
|
||||||
|
|
||||||
-- cabal-fmt: expand src
|
-- cabal-fmt: expand src
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Gyehoek.CPS.Convert
|
Gyehoek.CPS.Convert
|
||||||
Gyehoek.CPS.Lower
|
Gyehoek.CPS.Lower
|
||||||
Gyehoek.CPS.Syntax
|
Gyehoek.CPS.Syntax
|
||||||
|
Gyehoek.Driver
|
||||||
Gyehoek.GenSym
|
Gyehoek.GenSym
|
||||||
Gyehoek.Options
|
Gyehoek.Options
|
||||||
Gyehoek.Scheme.Syntax
|
Gyehoek.Scheme.Syntax
|
||||||
Gyehoek.Sexp
|
Gyehoek.Sexp
|
||||||
Gyehoek.Wasm
|
Gyehoek.Wasm
|
||||||
Gyehoek.Driver
|
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, base ^>=4.21.2.0
|
, base ^>=4.21.2.0
|
||||||
@@ -79,36 +78,40 @@ library
|
|||||||
, megaparsec
|
, megaparsec
|
||||||
, mtl
|
, mtl
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
|
, pretty-simple
|
||||||
, prettyprinter
|
, prettyprinter
|
||||||
, process
|
, process
|
||||||
, recursion-schemes
|
, recursion-schemes
|
||||||
, sexp-grammar
|
, sexp-grammar
|
||||||
|
, string-interpolate
|
||||||
, template-haskell
|
, template-haskell
|
||||||
, text
|
, text
|
||||||
, text-short
|
, text-short
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
, vector
|
, vector
|
||||||
, string-interpolate
|
|
||||||
, pretty-simple
|
|
||||||
|
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: GHC2024
|
default-language: GHC2024
|
||||||
|
|
||||||
test-suite test
|
test-suite test
|
||||||
import: ghcstuffs, ghcstuffs-dev
|
import: ghcstuffs, ghcstuffs-dev
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
other-modules:
|
other-modules:
|
||||||
Gyehoek.Test.Golden
|
Gyehoek.Test.CPS.Syntax
|
||||||
Gyehoek.Test.Sexp
|
Gyehoek.Test.Golden
|
||||||
build-depends: base
|
Gyehoek.Test.Sexp
|
||||||
, gyehoek
|
|
||||||
, filepath
|
build-depends:
|
||||||
, tasty
|
, base
|
||||||
, tasty-silver
|
, directory
|
||||||
, tasty-hunit
|
, filepath
|
||||||
, directory
|
, gyehoek
|
||||||
, process-extras
|
, process-extras
|
||||||
, sexp-grammar
|
, sexp-grammar
|
||||||
default-language: GHC2024
|
, tasty
|
||||||
|
, tasty-hunit
|
||||||
|
, tasty-silver
|
||||||
|
|
||||||
|
default-language: GHC2024
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{-# LANGUAGE OverloadedLists #-}
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
|
{- HLINT ignore "Use camelCase" -}
|
||||||
module Gyehoek.CPS.Convert
|
module Gyehoek.CPS.Convert
|
||||||
( convert
|
( convertProgram
|
||||||
, convertProgram
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Gyehoek.CPS.Syntax
|
import Gyehoek.CPS.Syntax
|
||||||
@@ -12,6 +12,7 @@ import Effectful
|
|||||||
import Control.Monad.Cont qualified as Cont
|
import Control.Monad.Cont qualified as Cont
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import qualified Data.List.NonEmpty as NE
|
import qualified Data.List.NonEmpty as NE
|
||||||
|
import qualified Gyehoek.Sexp
|
||||||
|
|
||||||
|
|
||||||
-- 뻘짓이어라
|
-- 뻘짓이어라
|
||||||
@@ -21,6 +22,14 @@ telescope
|
|||||||
-> t a -> (t b -> r) -> r
|
-> t a -> (t b -> r) -> r
|
||||||
telescope f = Cont.runCont . traverse (Cont.cont . f)
|
telescope f = Cont.runCont . traverse (Cont.cont . f)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pattern Atomic e <-
|
||||||
|
e@( Scm.ExpLambda _ _
|
||||||
|
; Scm.ExpVar _
|
||||||
|
; Scm.ExpLit _ )
|
||||||
|
|
||||||
|
-- | 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 -> (Val -> Eff es Exp) -> Eff es Exp
|
||||||
@@ -31,21 +40,25 @@ convert (Scm.ExpLit l) k = k $ ValLit l
|
|||||||
convert (Scm.ExpPrim p) k =
|
convert (Scm.ExpPrim p) k =
|
||||||
telescope (convert @es) p \p' -> do
|
telescope (convert @es) p \p' -> do
|
||||||
r <- gensym' "r"
|
r <- gensym' "r"
|
||||||
ExpPrim p' [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' "λ-body"
|
f <- gensym' "λ-body"
|
||||||
ktail <- gensym' "λ-tail"
|
ktail <- gensym' "λ-tail"
|
||||||
m <- convert e $ \e' ->
|
m <- convert e $ \e' -> pure $ ExpContinue ktail [e']
|
||||||
pure $ ExpContinue ktail [e']
|
ke <- k $ ValVar f
|
||||||
ExpLet [(f, MkLambda xs ktail m)] <$> k (ValVar f)
|
pure [cps|
|
||||||
|
(letrec ((#{f} (λ (##{xs} #{ktail}) #{m})))
|
||||||
|
#{ke})
|
||||||
|
|]
|
||||||
|
|
||||||
convert (Scm.ExpApply f xs) k =
|
convert (Scm.ExpApply f xs) k =
|
||||||
telescope (convert @es) (f:|xs) \(f':|xs') -> do
|
telescope (convert @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 $ ExpFix [(r, MkKappa [x] m)] $ ExpApply f' (xs' ++ [ValVar r])
|
-- pure $ ExpFix [(r, MkKappa [x] m)] $ ExpApply f' (xs' ++ [ValVar r])
|
||||||
|
_
|
||||||
|
|
||||||
convert (Scm.ExpBegin xs) k = _
|
convert (Scm.ExpBegin xs) k = _
|
||||||
|
|
||||||
|
|||||||
+46
-33
@@ -23,6 +23,8 @@ import Gyehoek.Wasm qualified as Wasm
|
|||||||
import Gyehoek.Wasm hiding (Expr)
|
import Gyehoek.Wasm hiding (Expr)
|
||||||
import Language.Sexp.Located qualified as SL
|
import Language.Sexp.Located qualified as SL
|
||||||
import Control.Monad.Fix
|
import Control.Monad.Fix
|
||||||
|
import qualified Gyehoek.Sexp
|
||||||
|
import Data.Text qualified as T
|
||||||
|
|
||||||
|
|
||||||
data Env = MkEnv
|
data Env = MkEnv
|
||||||
@@ -70,10 +72,10 @@ popArg n = [expr|
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
lowerVal :: Env -> Val -> Wasm.Expr
|
lowerVal :: GenMod :> es => Env -> Val -> Eff es Wasm.Expr
|
||||||
|
|
||||||
lowerVal g (ValLit l) =
|
lowerVal g (ValLit l) =
|
||||||
case l of
|
pure $ case l of
|
||||||
LitInt n -> [expr|
|
LitInt n -> [expr|
|
||||||
(i32.const #{n})
|
(i32.const #{n})
|
||||||
##{makeSmallFixnum}
|
##{makeSmallFixnum}
|
||||||
@@ -85,27 +87,36 @@ lowerVal g (ValLit l) =
|
|||||||
where b' :: Int = if b then 0b11 else 0b01
|
where b' :: Int = if b then 0b11 else 0b01
|
||||||
_ -> _
|
_ -> _
|
||||||
|
|
||||||
lowerVal g (ValVar x) = [expr|(local.get #{l})|]
|
lowerVal g (ValVar x) = pure $ [expr|(local.get #{l})|]
|
||||||
where
|
where
|
||||||
l = succ $ V.elemIndex x g.vars ^?! _Just
|
l = succ $ V.elemIndex x g.vars ^?! _Just
|
||||||
|
|
||||||
|
-- lowerVal g (ValLambda lam) = do
|
||||||
|
-- idx <- lowerLambda g lam
|
||||||
|
-- pure [expr|
|
||||||
|
-- (i32.const 0)
|
||||||
|
-- (ref.func #{idx})
|
||||||
|
-- (struct.new $closure)
|
||||||
|
-- |]
|
||||||
|
|
||||||
lower' :: (GenMod :> es) => Env -> Exp -> Eff es Wasm.Expr
|
lower' :: (GenMod :> es) => Env -> Exp -> Eff es Wasm.Expr
|
||||||
|
|
||||||
lower' g (Halt [v]) = pure [expr|
|
lower' g (Halt [v]) = do
|
||||||
##{arg}
|
arg <- pushArg 0 <$> lowerVal g v
|
||||||
(return_call $halt (i32.const 1))
|
pure [expr|
|
||||||
|]
|
##{arg}
|
||||||
where arg = pushArg 0 (lowerVal g v)
|
(return_call $halt (i32.const 1))
|
||||||
|
|]
|
||||||
|
|
||||||
lower' g (ExpPrim p [r] e) =
|
lower' g (ExpPrim p k) =
|
||||||
case p of
|
case p of
|
||||||
PrimAdd x y -> lowerBinOp "i32.add" g x y r e
|
PrimAdd x y -> lowerBinOp "i32.add" g x y k
|
||||||
PrimMul x y -> lowerBinOp "i32.mul" g x y r e
|
PrimMul x y -> lowerBinOp "i32.mul" g x y k
|
||||||
|
|
||||||
lower' g (ExpIf c t f) = do
|
lower' g (ExpIf c t f) = do
|
||||||
|
c' <- lowerVal g c
|
||||||
t' <- lower' g t
|
t' <- lower' g t
|
||||||
f' <- lower' g f
|
f' <- lower' g f
|
||||||
let c' = lowerVal g c
|
|
||||||
pure [expr|
|
pure [expr|
|
||||||
##{c'}
|
##{c'}
|
||||||
(call $gh-truthy?)
|
(call $gh-truthy?)
|
||||||
@@ -113,7 +124,7 @@ lower' g (ExpIf c t f) = do
|
|||||||
(else ##{f'}))
|
(else ##{f'}))
|
||||||
|]
|
|]
|
||||||
|
|
||||||
lower' g (ExpLet [(r,lam)] e) = do
|
lower' g (ExpLetRec [(r,AbsLambda lam)] e) = do
|
||||||
idx <- lowerLambda g lam
|
idx <- lowerLambda g lam
|
||||||
let g' = g & #vars <>~ [r]
|
let g' = g & #vars <>~ [r]
|
||||||
let n = succ $ length g.vars
|
let n = succ $ length g.vars
|
||||||
@@ -126,25 +137,27 @@ lower' g (ExpLet [(r,lam)] e) = do
|
|||||||
##{e'}
|
##{e'}
|
||||||
|]
|
|]
|
||||||
|
|
||||||
lower' g (ExpContinue k [x]) = pure . mconcat $
|
lower' g (ExpContinue k [x]) = do
|
||||||
[ pushArg 0 (lowerVal g x)
|
arg <- pushArg 0 <$> lowerVal g x
|
||||||
, [expr|
|
pure [expr|
|
||||||
(i32.const 1)
|
##{arg}
|
||||||
(global.get $cont-stack)
|
(i32.const 1)
|
||||||
(global.get $cont-stack-top)
|
(global.get $cont-stack)
|
||||||
(array.get $cont-stack-type)
|
(global.get $cont-stack-top)
|
||||||
ref.as_non_null
|
(array.get $cont-stack-type)
|
||||||
(global.get $cont-stack-top)
|
ref.as_non_null
|
||||||
(i32.const #{l})
|
(global.get $cont-stack-top)
|
||||||
i32.sub
|
(i32.const #{l})
|
||||||
(global.set $cont-stack-top)
|
i32.sub
|
||||||
(return_call_ref $cont-type)
|
(global.set $cont-stack-top)
|
||||||
|]
|
(return_call_ref $cont-type)
|
||||||
]
|
|]
|
||||||
where
|
where
|
||||||
l = succ $ V.elemIndex k g.kvars ^?! _Just
|
l = succ $ V.elemIndex k g.kvars ^?! _Just
|
||||||
|
|
||||||
lower' g e = error . show $ e
|
lower' g e = error $ case Gyehoek.Sexp.encode e of
|
||||||
|
Left _ -> show e
|
||||||
|
Right x -> T.unpack x
|
||||||
|
|
||||||
lowerLambda :: GenMod :> es => Env -> Lambda -> Eff es Idx
|
lowerLambda :: GenMod :> es => Env -> Lambda -> Eff es Idx
|
||||||
lowerLambda g (MkLambda xs ktail m) = do
|
lowerLambda g (MkLambda xs ktail m) = do
|
||||||
@@ -167,13 +180,13 @@ lowerLambda g (MkLambda xs ktail m) = do
|
|||||||
|
|
||||||
lowerBinOp
|
lowerBinOp
|
||||||
:: (GenMod :> es)
|
:: (GenMod :> es)
|
||||||
=> Text -> Env -> Val -> Val -> Name -> Exp -> Eff es Wasm.Expr
|
=> Text -> Env -> Val -> Val -> Kappa -> Eff es Wasm.Expr
|
||||||
lowerBinOp op g x y r e = do
|
lowerBinOp op g x y (MkKappa [r] e) = do
|
||||||
let op' = SL.Symbol op
|
let op' = SL.Symbol op
|
||||||
let g' = g & #vars <>~ [r]
|
let g' = g & #vars <>~ [r]
|
||||||
let n = succ $ length (g ^. #vars)
|
let n = succ $ length (g ^. #vars)
|
||||||
let x' = lowerVal g x
|
x' <- lowerVal g x
|
||||||
let y' = lowerVal g y
|
y' <- lowerVal g y
|
||||||
e' <- lower' g' e
|
e' <- lower' g' e
|
||||||
pure [expr|
|
pure [expr|
|
||||||
##{x'}
|
##{x'}
|
||||||
|
|||||||
+90
-30
@@ -1,6 +1,7 @@
|
|||||||
{-# LANGUAGE OverloadedLabels #-}
|
{-# LANGUAGE OverloadedLabels #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{-# LANGUAGE PatternSynonyms #-}
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
module Gyehoek.CPS.Syntax
|
module Gyehoek.CPS.Syntax
|
||||||
( Val(..)
|
( Val(..)
|
||||||
, Kappa(..)
|
, Kappa(..)
|
||||||
@@ -15,8 +16,12 @@ module Gyehoek.CPS.Syntax
|
|||||||
, pattern Halt1
|
, pattern Halt1
|
||||||
, _MkKappa
|
, _MkKappa
|
||||||
, _ExpPrim
|
, _ExpPrim
|
||||||
, _ExpFix
|
, _ExpLetRec
|
||||||
, _ExpApply
|
, _ExpApply
|
||||||
|
, cps
|
||||||
|
, pattern AbsLambda'
|
||||||
|
, pattern AbsKappa'
|
||||||
|
, Abs(..)
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -27,46 +32,62 @@ import Data.List (List)
|
|||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
import Language.SexpGrammar.Generic
|
import Language.SexpGrammar.Generic
|
||||||
import Control.Category
|
import Control.Category
|
||||||
import Control.Lens
|
import Control.Lens hiding (op)
|
||||||
import Prelude hiding ((.), id)
|
import Prelude hiding ((.), id)
|
||||||
import Data.List.NonEmpty (NonEmpty)
|
import Data.List.NonEmpty (NonEmpty)
|
||||||
|
import Language.Haskell.TH.Quote (QuasiQuoter)
|
||||||
|
import Data.Data (Data)
|
||||||
|
import Language.Sexp.Located (Sexp)
|
||||||
|
import qualified Data.InvertibleGrammar.Base as IG
|
||||||
|
import qualified Gyehoek.Scheme.Syntax as Gyehoek
|
||||||
|
import Data.InvertibleGrammar.Base (type (:-)((:-)))
|
||||||
|
|
||||||
-- Data types
|
-- Data types
|
||||||
|
|
||||||
data Val
|
data Val
|
||||||
= ValLabel Name
|
= ValVar Name
|
||||||
| ValVar Name
|
|
||||||
| ValLit Lit
|
| ValLit Lit
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
data Kappa = MkKappa (List Name) Exp
|
data Kappa = MkKappa (List Name) Exp
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
data Lambda = MkLambda (List Name) Name Exp
|
data Lambda = MkLambda (List Name) Name Exp
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
|
data Abs
|
||||||
|
= AbsKappa Kappa
|
||||||
|
| AbsLambda Lambda
|
||||||
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
|
pattern AbsKappa' xs e = AbsKappa (MkKappa xs e)
|
||||||
|
pattern AbsLambda' xs e ktail = AbsLambda (MkLambda xs e ktail)
|
||||||
|
|
||||||
data Exp
|
data Exp
|
||||||
= ExpPrim (Prim Val) (List Name) Exp
|
= ExpPrim (Prim Val) Kappa
|
||||||
| ExpFix (NonEmpty (Name, Kappa)) Exp
|
| ExpLetRec (NonEmpty (Name, Abs)) Exp
|
||||||
| ExpLet (NonEmpty (Name, Lambda)) Exp
|
|
||||||
| ExpContinue Name (List Val)
|
| ExpContinue Name (List Val)
|
||||||
| ExpIf Val Exp Exp
|
| ExpIf Val Exp Exp
|
||||||
| ExpApply Val (List Val)
|
| ExpApply
|
||||||
deriving (Show, Generic)
|
{ op :: Val
|
||||||
|
, args :: List Val
|
||||||
|
, cont :: Name
|
||||||
|
}
|
||||||
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
pattern Halt :: List Val -> Exp
|
pattern Halt :: List Val -> Exp
|
||||||
pattern Halt xs = ExpApply (ValVar "halt") xs
|
pattern Halt xs = ExpContinue "halt" xs
|
||||||
|
|
||||||
pattern Halt1 :: Val -> Exp
|
pattern Halt1 :: Val -> Exp
|
||||||
pattern Halt1 x = ExpApply (ValVar "halt") [x]
|
pattern Halt1 x = ExpContinue "halt" [x]
|
||||||
|
|
||||||
data Def = DefConstant Name Exp
|
data Def = DefConstant Name Exp
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
data Program = MkProgram
|
data Program = MkProgram
|
||||||
{ body :: Exp
|
{ body :: Exp
|
||||||
}
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
makePrisms ''Kappa
|
makePrisms ''Kappa
|
||||||
makePrisms ''Exp
|
makePrisms ''Exp
|
||||||
@@ -76,13 +97,10 @@ makePrisms ''Exp
|
|||||||
|
|
||||||
instance S.SexpIso Val where
|
instance S.SexpIso Val where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
$ With (. label)
|
-- $ With (. label)
|
||||||
$ With (. var)
|
$ With (\var -> var . S.sexpIso)
|
||||||
$ With (. S.sexpIso)
|
$ With (\lit -> lit . S.sexpIso)
|
||||||
$ End
|
$ End
|
||||||
where
|
|
||||||
label = S.keyword >>> S.iso MkName getName
|
|
||||||
var = S.sexpIso
|
|
||||||
|
|
||||||
instance S.SexpIso Lambda where
|
instance S.SexpIso Lambda where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
@@ -91,9 +109,18 @@ instance S.SexpIso Lambda where
|
|||||||
where
|
where
|
||||||
lambda = S.list $
|
lambda = S.list $
|
||||||
S.el Gyehoek.Sexp.lambdaKeyword
|
S.el Gyehoek.Sexp.lambdaKeyword
|
||||||
>>> S.el (S.list (S.rest S.sexpIso))
|
>>> S.el binders
|
||||||
>>> S.el S.sexpIso
|
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.sexpIso
|
||||||
|
binders :: forall t.
|
||||||
|
IG.Grammar S.Position (Sexp :- t) (Name :- List Name :- t)
|
||||||
|
binders = S.list $
|
||||||
|
S.rest (S.sexpIso @Name)
|
||||||
|
>>> S.onTail (S.flipped $ IG.PartialIso
|
||||||
|
(\(ktail:-args:-t) -> (args ++ [ktail]) :- t)
|
||||||
|
(\(args:-t) -> case args ^? _Snoc of
|
||||||
|
Just (args',ktail) -> Right $ ktail :- args' :- t
|
||||||
|
Nothing -> Left $ S.expected "cont param")
|
||||||
|
)
|
||||||
|
|
||||||
instance S.SexpIso Kappa where
|
instance S.SexpIso Kappa where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
@@ -105,11 +132,16 @@ instance S.SexpIso Kappa where
|
|||||||
>>> S.el (S.list $ S.rest S.sexpIso)
|
>>> S.el (S.list $ S.rest S.sexpIso)
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.sexpIso
|
||||||
|
|
||||||
|
instance S.SexpIso Abs where
|
||||||
|
sexpIso = match
|
||||||
|
$ With (\lambda -> lambda . S.sexpIso)
|
||||||
|
$ With (\kappa -> kappa . S.sexpIso)
|
||||||
|
$ End
|
||||||
|
|
||||||
instance S.SexpIso Exp where
|
instance S.SexpIso Exp where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
$ With (. prim)
|
$ With (. prim)
|
||||||
$ With (. fix)
|
$ With (. letrec)
|
||||||
$ With (. let_)
|
|
||||||
$ With (. continue)
|
$ With (. continue)
|
||||||
$ With (. if_)
|
$ With (. if_)
|
||||||
$ With (. app)
|
$ With (. app)
|
||||||
@@ -119,16 +151,44 @@ instance S.SexpIso Exp where
|
|||||||
S.el (S.sym "continue")
|
S.el (S.sym "continue")
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.sexpIso
|
||||||
>>> S.rest S.sexpIso
|
>>> S.rest S.sexpIso
|
||||||
fix = Gyehoek.Sexp.let_ "fix" S.sexpIso S.sexpIso S.sexpIso
|
letrec = Gyehoek.Sexp.let_ "letrec" S.sexpIso S.sexpIso S.sexpIso
|
||||||
let_ = Gyehoek.Sexp.let_ "let" S.sexpIso S.sexpIso S.sexpIso
|
|
||||||
if_ = S.list $ S.el (S.sym "if")
|
if_ = S.list $ S.el (S.sym "if")
|
||||||
>>> S.el S.sexpIso >>> S.el S.sexpIso >>> S.el S.sexpIso
|
>>> S.el S.sexpIso >>> S.el S.sexpIso >>> S.el S.sexpIso
|
||||||
app = S.list $ S.el S.sexpIso >>> S.rest S.sexpIso
|
app :: forall t.
|
||||||
|
IG.Grammar S.Position (Sexp :- t) (Name :- ([Val] :- (Val :- t)))
|
||||||
|
app = S.list $ S.el (S.sexpIso @Val)
|
||||||
|
-- >>> S.flipped Gyehoek.Sexp.nonEmptyGrammar
|
||||||
|
>>> S.rest (S.sexpIso @Val)
|
||||||
|
-- >>> _
|
||||||
|
>>> S.onTail (S.flipped $ IG.PartialIso
|
||||||
|
(\(karg :- args :- op :- t) ->
|
||||||
|
(args ++ [ValVar karg]) :- op :- t)
|
||||||
|
(\(xs :- op :- t) -> case xs ^? _Snoc of
|
||||||
|
Just (args,preview #ValVar -> Just karg) ->
|
||||||
|
Right $ karg:- args :- op :- t
|
||||||
|
_ -> Left $ S.expected "continuation arg"
|
||||||
|
))
|
||||||
|
where
|
||||||
|
_ = S.flipped $ Gyehoek.Sexp.nonEmptyGrammar @S.Position @Val
|
||||||
prim = S.list $
|
prim = S.list $
|
||||||
S.el (S.sym "prim")
|
S.el (S.sym "prim")
|
||||||
>>> S.el (primSexpIso id (S.sexpIso @Val))
|
>>> S.el (primSexpIso id (S.sexpIso @Val))
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.sexpIso
|
||||||
>>> S.el S.sexpIso
|
|
||||||
|
|
||||||
instance S.SexpIso Program where
|
instance S.SexpIso Program where
|
||||||
sexpIso = with \prog -> S.sexpIso @Exp >>> prog
|
sexpIso = with \prog -> S.sexpIso @Exp >>> prog
|
||||||
|
|
||||||
|
|
||||||
|
-- quasiquoters
|
||||||
|
|
||||||
|
class Data a => CPS a where
|
||||||
|
toCPS :: Sexp -> a
|
||||||
|
|
||||||
|
instance CPS Exp where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Val where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Kappa where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Lambda where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Abs where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
|
||||||
|
cps :: QuasiQuoter
|
||||||
|
cps = Gyehoek.Sexp.makeSx' [| toCPS |]
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ module Gyehoek.Scheme.Syntax
|
|||||||
, free
|
, free
|
||||||
, subst
|
, subst
|
||||||
, getName
|
, getName
|
||||||
|
, scm
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ import Data.Functor.Foldable hiding (fold)
|
|||||||
import Data.HashSet (HashSet)
|
import Data.HashSet (HashSet)
|
||||||
import qualified Data.HashSet as HS
|
import qualified Data.HashSet as HS
|
||||||
import Data.Foldable (fold)
|
import Data.Foldable (fold)
|
||||||
|
import Language.Haskell.TH.Quote (QuasiQuoter)
|
||||||
|
|
||||||
|
|
||||||
newtype Name = MkName { inner :: Text }
|
newtype Name = MkName { inner :: Text }
|
||||||
@@ -70,7 +72,7 @@ data Prim e
|
|||||||
| PrimWrite e
|
| PrimWrite e
|
||||||
| PrimZeroP e
|
| PrimZeroP e
|
||||||
| PrimNewline
|
| PrimNewline
|
||||||
deriving (Show, Generic, Functor, Foldable, Traversable, Data)
|
deriving (Show, Generic, Functor, Foldable, Traversable, Data, Eq)
|
||||||
|
|
||||||
instance Each (Prim e) (Prim e') e e'
|
instance Each (Prim e) (Prim e') e e'
|
||||||
|
|
||||||
@@ -80,7 +82,7 @@ data Lit
|
|||||||
| LitBool Bool
|
| LitBool Bool
|
||||||
| LitString Text
|
| LitString Text
|
||||||
| LitQuote Sexp
|
| LitQuote Sexp
|
||||||
deriving (Show, Generic, Data)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
pattern Void :: Lit
|
pattern Void :: Lit
|
||||||
pattern Void = LitNil
|
pattern Void = LitNil
|
||||||
@@ -105,7 +107,7 @@ data Sexp
|
|||||||
= SexpCons Sexp Sexp
|
= SexpCons Sexp Sexp
|
||||||
| SexpSymbol Text
|
| SexpSymbol Text
|
||||||
| SexpLit Lit
|
| SexpLit Lit
|
||||||
deriving (Show, Generic, Data)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
data CommandOrDef
|
data CommandOrDef
|
||||||
= Command Exp
|
= Command Exp
|
||||||
@@ -228,6 +230,9 @@ instance SexpIso CommandOrDef where
|
|||||||
|
|
||||||
-- utilities
|
-- utilities
|
||||||
|
|
||||||
|
scm :: QuasiQuoter
|
||||||
|
scm = Gyehoek.Sexp.makeSx [|| Gyehoek.Sexp.fromSexp @Exp ||]
|
||||||
|
|
||||||
free :: Exp -> HashSet Name
|
free :: Exp -> HashSet Name
|
||||||
free = cata \case
|
free = cata \case
|
||||||
ExpVarF x -> HS.singleton x
|
ExpVarF x -> HS.singleton x
|
||||||
|
|||||||
+16
-3
@@ -35,11 +35,13 @@ module Gyehoek.Sexp
|
|||||||
, sxs
|
, sxs
|
||||||
, makeSx
|
, makeSx
|
||||||
, makeSxs
|
, makeSxs
|
||||||
|
, makeSx'
|
||||||
, toSexp
|
, toSexp
|
||||||
, fromSexp
|
, fromSexp
|
||||||
, stripLocation
|
, stripLocation
|
||||||
, format
|
, format
|
||||||
, equivalent
|
, equivalent
|
||||||
|
, encodeOrShow
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@ import Debug.Pretty.Simple
|
|||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
import qualified Data.Vector.Strict
|
import qualified Data.Vector.Strict
|
||||||
import Data.Function (on)
|
import Data.Function (on)
|
||||||
|
import Data.String (IsString (fromString))
|
||||||
|
|
||||||
|
|
||||||
sexp :: SexpIso a => Iso' a Text
|
sexp :: SexpIso a => Iso' a Text
|
||||||
@@ -385,6 +388,11 @@ deriving instance Lift SL.Atom
|
|||||||
deriving instance Lift SL.Position
|
deriving instance Lift SL.Position
|
||||||
deriving instance Lift SL.Prefix
|
deriving instance Lift SL.Prefix
|
||||||
|
|
||||||
|
encodeOrShow :: (SexpIso a, Show a, IsString s) => a -> s
|
||||||
|
encodeOrShow a = fromString case encode a of
|
||||||
|
Left _ -> show a
|
||||||
|
Right e -> T.unpack e
|
||||||
|
|
||||||
extQ :: (Typeable a, Typeable b) => (a -> r) -> (b -> r) -> a -> r
|
extQ :: (Typeable a, Typeable b) => (a -> r) -> (b -> r) -> a -> r
|
||||||
extQ f g a = maybe (f a) g (cast a)
|
extQ f g a = maybe (f a) g (cast a)
|
||||||
|
|
||||||
@@ -404,13 +412,15 @@ makeSxs f = QuasiQuoter
|
|||||||
, quoteDec = undefined
|
, quoteDec = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
makeSx :: Data r => Code Q (Sexp -> r) -> QuasiQuoter
|
-- | An untyped variant of 'makeSx', useful when the user function is
|
||||||
makeSx f = QuasiQuoter
|
-- polymorphic in its return value.
|
||||||
|
makeSx' :: ExpQ -> QuasiQuoter
|
||||||
|
makeSx' f = QuasiQuoter
|
||||||
{ quoteExp = \str -> do
|
{ quoteExp = \str -> do
|
||||||
pos <- getPos
|
pos <- getPos
|
||||||
case readSexpWithPos pos (T.pack str) of
|
case readSexpWithPos pos (T.pack str) of
|
||||||
Left e -> fail e
|
Left e -> fail e
|
||||||
Right x -> [| $(unTypeCode f) $e |]
|
Right x -> [| $f $e |]
|
||||||
where
|
where
|
||||||
e = dataToExpQ
|
e = dataToExpQ
|
||||||
(const Nothing `extQ` metaSexp `extQ` metaSexps)
|
(const Nothing `extQ` metaSexp `extQ` metaSexps)
|
||||||
@@ -420,5 +430,8 @@ makeSx f = QuasiQuoter
|
|||||||
, quoteDec = undefined
|
, quoteDec = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
makeSx :: Data r => Code Q (Sexp -> r) -> QuasiQuoter
|
||||||
|
makeSx = makeSx' . unTypeCode
|
||||||
|
|
||||||
sxs = makeSxs [||id||]
|
sxs = makeSxs [||id||]
|
||||||
sx = makeSx [||id||]
|
sx = makeSx [||id||]
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
module Gyehoek.Test.CPS.Syntax (root) where
|
||||||
|
|
||||||
|
import Test.Tasty (TestTree, testGroup)
|
||||||
|
import Test.Tasty.HUnit
|
||||||
|
import Language.Sexp.Located qualified as SL
|
||||||
|
import Language.SexpGrammar ()
|
||||||
|
import Gyehoek.CPS.Syntax (cps)
|
||||||
|
import Gyehoek.CPS.Syntax qualified as Sut
|
||||||
|
import Data.Function (on)
|
||||||
|
import Gyehoek.Test.Sexp (equivto)
|
||||||
|
|
||||||
|
|
||||||
|
root :: IO TestTree
|
||||||
|
root = pure . testGroup "cps syntax" $
|
||||||
|
[ qqTree
|
||||||
|
]
|
||||||
|
|
||||||
|
qqTree :: TestTree
|
||||||
|
qqTree = testGroup "parser"
|
||||||
|
[ testCase "lambda" do
|
||||||
|
assertEqual "" (Sut.MkLambda ["x","y"] "ktail"
|
||||||
|
(Sut.ExpContinue "ktail" [Sut.ValVar "x"]))
|
||||||
|
[cps|(λ (x y ktail) (continue ktail x))|]
|
||||||
|
assertEqual "" (Sut.MkLambda [] "ktail"
|
||||||
|
(Sut.ExpContinue "ktail" [Sut.ValVar "x"]))
|
||||||
|
[cps|(λ (ktail) (continue ktail x))|]
|
||||||
|
, testCase "kappa" do
|
||||||
|
assertEqual "" (Sut.MkKappa ["x","y"]
|
||||||
|
(Sut.ExpContinue "k123" [Sut.ValVar "x", Sut.ValVar "y"]))
|
||||||
|
[cps|(κ (x y) (continue k123 x y))|]
|
||||||
|
, testCase "application" do
|
||||||
|
assertEqual "" (Sut.ExpApply (Sut.ValVar "f")
|
||||||
|
[Sut.ValVar "x",Sut.ValVar "y"]
|
||||||
|
"k")
|
||||||
|
[cps|(f x y k)|]
|
||||||
|
assertEqual "" (Sut.ExpApply (Sut.ValVar "f")
|
||||||
|
[] "k")
|
||||||
|
[cps|(f k)|]
|
||||||
|
]
|
||||||
@@ -14,7 +14,7 @@ import qualified System.Process.Text as PT
|
|||||||
|
|
||||||
disabled :: List String
|
disabled :: List String
|
||||||
disabled =
|
disabled =
|
||||||
[ "square"
|
[
|
||||||
]
|
]
|
||||||
|
|
||||||
root :: IO TestTree
|
root :: IO TestTree
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
module Gyehoek.Test.Sexp (root) where
|
module Gyehoek.Test.Sexp
|
||||||
|
( root
|
||||||
|
, EquivSexp(..)
|
||||||
|
, assertEquiv
|
||||||
|
, equivto
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
import Test.Tasty (TestTree, testGroup)
|
import Test.Tasty (TestTree, testGroup)
|
||||||
import Test.Tasty.HUnit
|
import Test.Tasty.HUnit
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Test.Tasty (TestTree, testGroup)
|
|||||||
import Test.Tasty.Silver.Interactive (defaultMain)
|
import Test.Tasty.Silver.Interactive (defaultMain)
|
||||||
import qualified Gyehoek.Test.Golden
|
import qualified Gyehoek.Test.Golden
|
||||||
import qualified Gyehoek.Test.Sexp
|
import qualified Gyehoek.Test.Sexp
|
||||||
|
import qualified Gyehoek.Test.CPS.Syntax
|
||||||
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
@@ -13,5 +14,6 @@ root :: IO TestTree
|
|||||||
root = testGroup "test" <$> sequenceA
|
root = testGroup "test" <$> sequenceA
|
||||||
[ Gyehoek.Test.Golden.root
|
[ Gyehoek.Test.Golden.root
|
||||||
, Gyehoek.Test.Sexp.root
|
, Gyehoek.Test.Sexp.root
|
||||||
|
, Gyehoek.Test.CPS.Syntax.root
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user