5 Commits
Author SHA1 Message Date
msyds 3cdae9eab4 disable broken tests
build / build (push) Successful in 1m33s
2026-09-06 21:51:39 -06:00
msyds c6036ffbb4 parse/print libraries 2026-09-06 21:39:52 -06:00
msyds 6ebe92e7cd tests 2026-09-06 00:00:30 -06:00
msyds 0f9ba3c51e eval call/cc }:) 2026-09-05 23:58:37 -06:00
msyds 10bd6b733a eval cons 2026-09-05 23:00:44 -06:00
10 changed files with 188 additions and 22 deletions
+9
View File
@@ -0,0 +1,9 @@
#+title: on libraries
R⁷RS leaves it unspecified how exactly libraries correspond to files:
#+begin_quote
Programs and libraries are typically stored in files, although in some implementations they can be entered interactively into a running Scheme system. Other paradigms are possible. Implementations which store libraries in files should document the mapping from the name of a library to its location in the file system.
#+end_quote
thus the implementation of ~define-library~ is open to much interpretation. we could possibly define libraries as first-class objects, or deal with them statically. the former case is appealing to me, as it could massively simplify interactive use.
+2
View File
@@ -0,0 +1,2 @@
ret > ExitSuccess
out > (456 . 123)
+2
View File
@@ -0,0 +1,2 @@
ret > ExitSuccess
out > (0 . (1 . (4 . (9 . (16 . ())))))
+7
View File
@@ -0,0 +1,7 @@
(letrec ((my-map (λ (f l)
(if (pair? l)
(cons (f (car l))
(my-map f (cdr l)))
(list)))))
(my-map (λ (x) (* x x))
(list 0 1 2 3 4)))
+60 -16
View File
@@ -12,7 +12,7 @@ module Gyehoek.CPS.Eval
import Gyehoek.CPS.Syntax hiding (Hob(..), Obj(..), cont) import Gyehoek.CPS.Syntax hiding (Hob(..), Obj(..), cont)
import Gyehoek.Sexp qualified as S import Gyehoek.Sexp qualified as S
import Control.Lens hiding (assign) import Control.Lens hiding (assign)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe, isJust)
import Text.Show.Functions () import Text.Show.Functions ()
import qualified Data.HashMap.Strict as H import qualified Data.HashMap.Strict as H
import Gyehoek.Prelude hiding (assign) import Gyehoek.Prelude hiding (assign)
@@ -29,7 +29,7 @@ import Data.IntMap.Strict qualified as IM
import Data.Monoid import Data.Monoid
import Control.Monad.State import Control.Monad.State
import Data.Traversable (for) import Data.Traversable (for)
import Data.Foldable (traverse_) import Data.Foldable (traverse_, foldrM)
newtype Loc = MkLoc { getLoc :: Int } newtype Loc = MkLoc { getLoc :: Int }
@@ -116,6 +116,13 @@ data Mutability
wrong :: Text -> M Answer a wrong :: Text -> M Answer a
wrong s = ContT \_ -> pure . AnswerError . EvalError $ s wrong s = ContT \_ -> pure . AnswerError . EvalError $ s
orWrong
:: Getting (First a) s a
-> Text -> s -> M Answer a
orWrong p msg s = case getFirst . getConst $ p (Const . First . Just) s of
Nothing -> wrong msg
Just x -> pure x
bind :: Name -> Loc -> Env bind :: Name -> Loc -> Env
bind k = MkEnv . H.singleton k bind k = MkEnv . H.singleton k
@@ -139,9 +146,9 @@ data E
| EUndefined | EUndefined
| EUnspecified | EUnspecified
| ENull | ENull
| EPair Loc Loc Mutability | EPair Mutability Loc Loc
| EVec (List Loc) Mutability | EVec Mutability (List Loc)
| EString (List Loc) Mutability | EString Mutability (List Loc)
| EProcedure Procedure | EProcedure Procedure
deriving stock (Show, Generic) deriving stock (Show, Generic)
@@ -158,25 +165,32 @@ eGrammar st = S.partialOsi (const . Left $ mempty) go
EBool b -> S.Boolean b EBool b -> S.Boolean b
EUndefined -> S.Unreadable "#<undefined>" EUndefined -> S.Unreadable "#<undefined>"
EUnspecified -> S.Unreadable "#<unspecified>" EUnspecified -> S.Unreadable "#<unspecified>"
EProcedure _ -> S.Unreadable "#<procedure>"
ENull -> S.List [] ENull -> S.List []
EPair car cdr _mut -> S.DotList [gofetch car] (gofetch cdr) EPair _mut car cdr -> S.DotList [gofetch car] (gofetch cdr)
EVec xs _mut -> S.Vector . fmap gofetch $ xs EVec _mut xs -> S.Vector . fmap gofetch $ xs
EString xs _mut -> S.String _ EString _mut xs -> S.String _
data DynPoints = MkDynPoints data DynPoints = MkDynPoints
deriving (Generic, Data) deriving (Generic, Data)
truthy :: E -> Bool
truthy (EBool False) = False
truthy _ = True
evalVal :: Env -> Val -> M Answer E evalVal :: Env -> Val -> M Answer E
evalVal g (ValVar x) = var g x >>= fetch evalVal g (ValVar x) = var g x >>= fetch
evalVal g (ValImm imm) = pure case imm of evalVal g (ValImm imm) = case imm of
ImmLabel l -> error [i|#{l}|] ImmLabel (MkLabel l) -> var g l >>= fetch
ImmInt n -> EInt n ImmInt n -> pure $ EInt n
ImmBool b -> EBool b ImmBool b -> pure $ EBool b
ImmUndefined -> EUndefined ImmUndefined -> pure EUndefined
evalKexp :: Env -> Kexp -> M Answer E evalKexp :: Env -> Kexp -> M Answer E
evalKexp g (KexpVar x) = var g x >>= fetch evalKexp g (KexpVar x) = var g x >>= fetch
@@ -212,25 +226,55 @@ eval g dps (ExpLetRec bs e) = do
traverse_ (uncurry assign) $ zip ls (bs' ^.. each . _2) traverse_ (uncurry assign) $ zip ls (bs' ^.. each . _2)
eval g' dps e eval g' dps e
eval g dps (ExpPrim (PrimCallCC withcc) k) = do
withcc' <- evalVal g withcc >>= orWrong #_EProcedure
[i|call/cc: 함수가 아닌 것을 받았다|]
k' <- evalKexp g k
kproc <- orWrong #_EProcedure [i|call/cc: 몰라...|] k'
let cc = EProcedure \xs dps -> case unsnoc xs of
Just (xs',_) -> kproc xs' dps
Nothing -> wrong [i|call/cc: 잘못하는데!|]
withcc' [cc,k'] dps
eval g dps (ExpPrim p k) = do eval g dps (ExpPrim p k) = do
p' <- evalPrim g =<< traverse (evalVal g) p p' <- evalPrim g dps =<< traverse (evalVal g) p
evalKexp g k >>= \case evalKexp g k >>= \case
EProcedure fp -> fp p' dps EProcedure fp -> fp p' dps
_ -> wrong [i|prim(#{p})의 계속을 나쁘다|] _ -> wrong [i|prim(#{p})의 계속을 나쁘다|]
eval g dps (ExpIf c t f) = do
c' <- evalVal g c
let b = if truthy c' then t else f
var g b >>= fetch >>= \case
EProcedure fp -> fp [] dps
_ -> wrong [i|if의 계속을 나쁘다|]
eval g dps e = error [i|unimplemented #{e}|] eval g dps e = error [i|unimplemented #{e}|]
evalPrim :: Env -> Prim E -> M Answer (List E) evalPrim :: Env -> DynPoints -> Prim E -> M Answer (List E)
evalPrim g = \case evalPrim g dps = \case
PrimAdd x y -> arith2 (+) x y PrimAdd x y -> arith2 (+) x y
PrimMul x y -> arith2 (*) x y PrimMul x y -> arith2 (*) x y
PrimSub x y -> arith2 (-) x y PrimSub x y -> arith2 (-) x y
PrimDiv x y -> arith2 div x y PrimDiv x y -> arith2 div x y
PrimZeroP x -> pure1 . EBool . isJust $ x ^? #EInt . only 0
PrimCons x y -> pcons x y >>= pure1
PrimCar p -> cr p _2
PrimCdr p -> cr p _3
PrimPairP p -> pure1 . EBool . maybe False (const True) $
p ^? #_EPair
PrimValues xs -> pure xs PrimValues xs -> pure xs
PrimList xs -> foldrM pcons ENull xs >>= pure1
p -> wrong [i|prim(#{p})은 벌써 나지 않다|] p -> wrong [i|prim(#{p})은 벌써 나지 않다|]
where where
pure1 x = pure [x]
pcons x y = do
(x',y') <- traverseOf both new' (x,y)
pure $ EPair Mut x' y'
arith2 f (EInt x) (EInt y) = pure [EInt $ f x y] arith2 f (EInt x) (EInt y) = pure [EInt $ f x y]
arith2 f x y = wrong [i|나쁜 인자: #{x}, #{y}|] arith2 f x y = wrong [i|나쁜 인자: #{x}, #{y}|]
cr p l = orWrong (#_EPair . l) [i|car/cdr는 pair을 받지 않다|] p
>>= fmap (:[]) . fetch
+89 -3
View File
@@ -10,6 +10,7 @@
{-# LANGUAGE OrPatterns #-} {-# LANGUAGE OrPatterns #-}
{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE ViewPatterns #-}
module Gyehoek.Scheme.Syntax module Gyehoek.Scheme.Syntax
( Name(..) ( Name(..)
, Prim(..) , Prim(..)
@@ -53,6 +54,8 @@ 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, G, DataIso, (:-)((:-))) import Gyehoek.Sexp.Grammar (DatumIso, G, DataIso, (:-)((:-)))
import Gyehoek.Prelude import Gyehoek.Prelude
import Control.Lens.Extras (is)
import qualified Data.Scientific as Sci
newtype Name = MkName { inner :: Text } newtype Name = MkName { inner :: Text }
@@ -90,6 +93,8 @@ data Prim e
| PrimInvokeCC e (List e) | PrimInvokeCC e (List e)
| PrimValues (List e) | PrimValues (List e)
| PrimCallWithValues e e | PrimCallWithValues e e
| PrimPairP e
| PrimList (List 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)
@@ -128,8 +133,37 @@ data CommandOrDef
deriving stock (Show, Generic, Data) deriving stock (Show, Generic, Data)
deriving anyclass (NFData) deriving anyclass (NFData)
newtype Program = MkProgram newtype LibName = MkLibName { inner :: NonEmpty Name }
{ commandsAndDefs :: List CommandOrDef deriving stock (Show, Generic, Data)
deriving anyclass (NFData)
data ImportSet
= ImportLib LibName
| ImportOnly ImportSet (NonEmpty Name)
| ImportExcept ImportSet (NonEmpty Name)
| ImportPrefix ImportSet Name
| ImportRename ImportSet (NonEmpty (Name, Name))
deriving stock (Show, Generic, Data)
deriving anyclass (NFData)
newtype ImportDecl = MkImportDecl (NonEmpty ImportSet)
deriving stock (Show, Generic, Data)
deriving anyclass (NFData)
data LibDecl
deriving stock (Show, Generic, Data)
deriving anyclass (NFData)
data Lib = MkLib
{ name :: LibName
, decls :: List LibDecl
}
deriving stock (Show, Generic, Data)
deriving anyclass (NFData)
data Program = MkProgram
{ imports :: List ImportDecl
, commandsAndDefs :: List CommandOrDef
} }
deriving stock (Show, Generic, Data) deriving stock (Show, Generic, Data)
deriving anyclass (NFData) deriving anyclass (NFData)
@@ -181,6 +215,8 @@ primDatumIso namefn a = S.match
$ S.With (. ht1' "invoke/cc") $ S.With (. ht1' "invoke/cc")
$ S.With (. ht0' "values") $ S.With (. ht0' "values")
$ S.With (. ht2 "call-with-values") $ S.With (. ht2 "call-with-values")
$ S.With (. ht1 "pair?")
$ S.With (. ht0' "list")
$ S.End $ S.End
where where
idn = S.el . S.sym . namefn idn = S.el . S.sym . namefn
@@ -240,8 +276,58 @@ instance DatumIso CommandOrDef where
$ S.With (\_Begin -> _Begin . S.beginLike "begin" (S.rest S.datumIso)) $ S.With (\_Begin -> _Begin . S.beginLike "begin" (S.rest S.datumIso))
$ S.End $ S.End
instance DatumIso LibName where
datumIso = S.with \g ->
S.list (S.restData $ S.nonEmptyData comp)
>>> g
where
comp = S.partialOsi
(\case
S.Symbol s -> Right $ MkName s
S.Number (Sci.floatingOrInteger @Double @Int -> Right n)
| n > 0 -> Right $ MkName [i|#{n}|]
_ -> Left $ S.expected "library name part"
)
\(MkName s) -> S.Symbol s
instance DatumIso ImportSet where
datumIso = S.match
$ S.With (S.datumIso @LibName >>>)
$ S.With (imp "only" >>>)
$ S.With (imp "except" >>>)
$ S.With (imp' "prefix" >>>)
$ S.With (imp "rename" >>>)
$ S.End
where
imp s = S.list $ S.el (S.symBuiltin s)
>>> S.el S.datumIso >>> S.restData S.dataIso
imp' s = S.list $
S.el (S.symBuiltin s)
>>> S.el S.datumIso
>>> S.el S.datumIso
instance DatumIso ImportDecl where
datumIso = S.with \decl ->
S.list (S.el (S.symBuiltin "import") >>> S.restData S.dataIso)
>>> decl
instance DataIso Program where instance DataIso Program where
dataIso = S.dataIso @(List CommandOrDef) >>> S.iso coerce coerce dataIso = S.with \g ->
splitG
>>> S.onHead (S.sealed S.dataIso)
>>> S.onTail (S.onHead . S.sealed $ S.dataIso)
>>> g
where
isImport = \case
S.List (S.Symbol "import" : _) -> True
_ -> False
splitG :: G (List S.Datum :- t) (List S.Datum :- List S.Datum :- t)
splitG = S.Iso
(\(xs:-t) ->
let (ys,zs) = span isImport xs
in zs :- ys :- t
)
\(zs:-ys:-t) -> (ys ++ zs) :- t
-- utilities -- utilities
+4
View File
@@ -49,6 +49,7 @@ import qualified Data.Vector as V
import Data.String (IsString (fromString)) import Data.String (IsString (fromString))
import qualified Data.Text as T import qualified Data.Text as T
import System.Environment (lookupEnv) import System.Environment (lookupEnv)
import Data.Foldable (toList)
toDatum :: Jalmot :> es => DatumGrammar a -> a -> Eff es Datum toDatum :: Jalmot :> es => DatumGrammar a -> a -> Eff es Datum
@@ -187,5 +188,8 @@ instance DatumIso a => DataIso (V.Vector a) where
dataIso = iso fromList V.toList dataIso = iso fromList V.toList
>>> (onHead . traversed . sealed $ datumIso @a) >>> (onHead . traversed . sealed $ datumIso @a)
instance DatumIso a => DataIso (NonEmpty a) where
dataIso = nonEmptyData datumIso
instance (DatumIso a, DatumIso b) => DatumIso (a, b) where instance (DatumIso a, DatumIso b) => DatumIso (a, b) where
datumIso = with \tup2 -> list (el datumIso >>> el datumIso) >>> tup2 datumIso = with \tup2 -> list (el datumIso >>> el datumIso) >>> tup2
+13 -1
View File
@@ -17,6 +17,7 @@ module Gyehoek.Sexp.Grammar.Base
, el , el
, rest , rest
, restData , restData
, nonEmptyData
, headTagged0' , headTagged0'
, headTagged0 , headTagged0
, headTagged1' , headTagged1'
@@ -32,6 +33,8 @@ module Gyehoek.Sexp.Grammar.Base
, integer , integer
, int , int
, unreadable , unreadable
-- ** symbols
, symBuiltin
-- * TODO: sort lol -- * TODO: sort lol
, prismIso , prismIso
, isoIso, decorate , isoIso, decorate
@@ -49,7 +52,7 @@ import Data.InvertibleGrammar.Base
import Data.InvertibleGrammar.Base as Re import Data.InvertibleGrammar.Base as Re
( Grammar(..)) ( Grammar(..))
import Data.InvertibleGrammar.Combinators import Data.InvertibleGrammar.Combinators
import Gyehoek.Prelude hiding (iso, cons, coerced, Iso, Simple, simple) import Gyehoek.Prelude hiding (traversed, iso, cons, coerced, Iso, Simple, simple)
import Gyehoek.Sexp.Syntax hiding (position) import Gyehoek.Sexp.Syntax hiding (position)
import Gyehoek.Sexp.Print (printDatum') import Gyehoek.Sexp.Print (printDatum')
import Data.Scientific (Scientific) import Data.Scientific (Scientific)
@@ -57,6 +60,7 @@ import qualified Data.Scientific as Sci
import qualified Data.Text as T import qualified Data.Text as T
import Control.Monad.RWS (modify) import Control.Monad.RWS (modify)
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import Data.Foldable (toList)
-- $setup -- $setup
@@ -238,6 +242,14 @@ restData g =
>>> g >>> g
>>> push (MkListContext []) (const True) mempty >>> push (MkListContext []) (const True) mempty
nonEmptyData :: DatumGrammar a -> DataGrammar (NonEmpty a)
nonEmptyData g = partialOsi
(\case
[] -> Left $ expected "non-empty sequence"
x:xs -> Right $ x:|xs)
toList
>>> (onHead . traversed . sealed $ g)
snoced snoced
:: Snoc s s a a :: Snoc s s a a
=> Grammar p (s :- a :- t) (s :- t) => Grammar p (s :- a :- t) (s :- t)
+1 -1
View File
@@ -58,7 +58,7 @@ test_eval = do
<&> fmap ("golden/exec" </>) <&> fmap ("golden/exec" </>)
pure $ testGroup "cps interpreter" pure $ testGroup "cps interpreter"
[ testGroup "higher-order" $ cpsCase Driver.eval_cps2_e2e <$> cs [ testGroup "higher-order" $ cpsCase Driver.eval_cps2_e2e <$> cs
, testGroup "first-order" $ cpsCase Driver.eval_cps_e2e <$> cs -- , testGroup "first-order" $ cpsCase Driver.eval_cps_e2e <$> cs
] ]
maybeBroken name broken = applyWhen (name `elem` broken) expectFail maybeBroken name broken = applyWhen (name `elem` broken) expectFail