Compare commits
5
Commits
superfuck
...
3cdae9eab4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cdae9eab4 | ||
|
|
c6036ffbb4 | ||
|
|
6ebe92e7cd | ||
|
|
0f9ba3c51e | ||
|
|
10bd6b733a |
@@ -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.
|
||||
@@ -1,2 +1,2 @@
|
||||
ret > ExitSuccess
|
||||
out > 12
|
||||
out > 12
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ret > ExitSuccess
|
||||
out > (456 . 123)
|
||||
@@ -0,0 +1,2 @@
|
||||
ret > ExitSuccess
|
||||
out > (0 . (1 . (4 . (9 . (16 . ())))))
|
||||
@@ -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
@@ -12,7 +12,7 @@ module Gyehoek.CPS.Eval
|
||||
import Gyehoek.CPS.Syntax hiding (Hob(..), Obj(..), cont)
|
||||
import Gyehoek.Sexp qualified as S
|
||||
import Control.Lens hiding (assign)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Data.Maybe (fromMaybe, isJust)
|
||||
import Text.Show.Functions ()
|
||||
import qualified Data.HashMap.Strict as H
|
||||
import Gyehoek.Prelude hiding (assign)
|
||||
@@ -29,7 +29,7 @@ import Data.IntMap.Strict qualified as IM
|
||||
import Data.Monoid
|
||||
import Control.Monad.State
|
||||
import Data.Traversable (for)
|
||||
import Data.Foldable (traverse_)
|
||||
import Data.Foldable (traverse_, foldrM)
|
||||
|
||||
|
||||
newtype Loc = MkLoc { getLoc :: Int }
|
||||
@@ -116,6 +116,13 @@ data Mutability
|
||||
wrong :: Text -> M Answer a
|
||||
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 k = MkEnv . H.singleton k
|
||||
|
||||
@@ -139,9 +146,9 @@ data E
|
||||
| EUndefined
|
||||
| EUnspecified
|
||||
| ENull
|
||||
| EPair Loc Loc Mutability
|
||||
| EVec (List Loc) Mutability
|
||||
| EString (List Loc) Mutability
|
||||
| EPair Mutability Loc Loc
|
||||
| EVec Mutability (List Loc)
|
||||
| EString Mutability (List Loc)
|
||||
| EProcedure Procedure
|
||||
deriving stock (Show, Generic)
|
||||
|
||||
@@ -158,25 +165,32 @@ eGrammar st = S.partialOsi (const . Left $ mempty) go
|
||||
EBool b -> S.Boolean b
|
||||
EUndefined -> S.Unreadable "#<undefined>"
|
||||
EUnspecified -> S.Unreadable "#<unspecified>"
|
||||
EProcedure _ -> S.Unreadable "#<procedure>"
|
||||
ENull -> S.List []
|
||||
EPair car cdr _mut -> S.DotList [gofetch car] (gofetch cdr)
|
||||
EVec xs _mut -> S.Vector . fmap gofetch $ xs
|
||||
EString xs _mut -> S.String _
|
||||
EPair _mut car cdr -> S.DotList [gofetch car] (gofetch cdr)
|
||||
EVec _mut xs -> S.Vector . fmap gofetch $ xs
|
||||
EString _mut xs -> S.String _
|
||||
|
||||
data DynPoints = MkDynPoints
|
||||
deriving (Generic, Data)
|
||||
|
||||
|
||||
|
||||
truthy :: E -> Bool
|
||||
truthy (EBool False) = False
|
||||
truthy _ = True
|
||||
|
||||
|
||||
|
||||
evalVal :: Env -> Val -> M Answer E
|
||||
|
||||
evalVal g (ValVar x) = var g x >>= fetch
|
||||
|
||||
evalVal g (ValImm imm) = pure case imm of
|
||||
ImmLabel l -> error [i|#{l}|]
|
||||
ImmInt n -> EInt n
|
||||
ImmBool b -> EBool b
|
||||
ImmUndefined -> EUndefined
|
||||
evalVal g (ValImm imm) = case imm of
|
||||
ImmLabel (MkLabel l) -> var g l >>= fetch
|
||||
ImmInt n -> pure $ EInt n
|
||||
ImmBool b -> pure $ EBool b
|
||||
ImmUndefined -> pure EUndefined
|
||||
|
||||
evalKexp :: Env -> Kexp -> M Answer E
|
||||
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)
|
||||
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
|
||||
p' <- evalPrim g =<< traverse (evalVal g) p
|
||||
p' <- evalPrim g dps =<< traverse (evalVal g) p
|
||||
evalKexp g k >>= \case
|
||||
EProcedure fp -> fp p' dps
|
||||
_ -> 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}|]
|
||||
|
||||
evalPrim :: Env -> Prim E -> M Answer (List E)
|
||||
evalPrim g = \case
|
||||
evalPrim :: Env -> DynPoints -> Prim E -> M Answer (List E)
|
||||
evalPrim g dps = \case
|
||||
PrimAdd x y -> arith2 (+) x y
|
||||
PrimMul x y -> arith2 (*) x y
|
||||
PrimSub x y -> arith2 (-) 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
|
||||
PrimList xs -> foldrM pcons ENull xs >>= pure1
|
||||
p -> wrong [i|prim(#{p})은 벌써 나지 않다|]
|
||||
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 x y = wrong [i|나쁜 인자: #{x}, #{y}|]
|
||||
cr p l = orWrong (#_EPair . l) [i|car/cdr는 pair을 받지 않다|] p
|
||||
>>= fmap (:[]) . fetch
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
{-# LANGUAGE OrPatterns #-}
|
||||
{-# LANGUAGE PatternSynonyms #-}
|
||||
{-# LANGUAGE DeriveAnyClass #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
module Gyehoek.Scheme.Syntax
|
||||
( Name(..)
|
||||
, Prim(..)
|
||||
@@ -53,6 +54,8 @@ import Gyehoek.Sexp.Grammar qualified as Sexp
|
||||
import Gyehoek.Sexp.Grammar qualified as S
|
||||
import Gyehoek.Sexp.Grammar (DatumIso, G, DataIso, (:-)((:-)))
|
||||
import Gyehoek.Prelude
|
||||
import Control.Lens.Extras (is)
|
||||
import qualified Data.Scientific as Sci
|
||||
|
||||
|
||||
newtype Name = MkName { inner :: Text }
|
||||
@@ -90,6 +93,8 @@ data Prim e
|
||||
| PrimInvokeCC e (List e)
|
||||
| PrimValues (List e)
|
||||
| PrimCallWithValues e e
|
||||
| PrimPairP e
|
||||
| PrimList (List e)
|
||||
deriving stock (Show, Generic, Functor, Foldable, Traversable, Data, Eq)
|
||||
deriving anyclass (NFData)
|
||||
|
||||
@@ -128,8 +133,37 @@ data CommandOrDef
|
||||
deriving stock (Show, Generic, Data)
|
||||
deriving anyclass (NFData)
|
||||
|
||||
newtype Program = MkProgram
|
||||
{ commandsAndDefs :: List CommandOrDef
|
||||
newtype LibName = MkLibName { inner :: NonEmpty Name }
|
||||
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 anyclass (NFData)
|
||||
@@ -181,6 +215,8 @@ primDatumIso namefn a = S.match
|
||||
$ S.With (. ht1' "invoke/cc")
|
||||
$ S.With (. ht0' "values")
|
||||
$ S.With (. ht2 "call-with-values")
|
||||
$ S.With (. ht1 "pair?")
|
||||
$ S.With (. ht0' "list")
|
||||
$ S.End
|
||||
where
|
||||
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.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
|
||||
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
|
||||
|
||||
@@ -49,6 +49,7 @@ import qualified Data.Vector as V
|
||||
import Data.String (IsString (fromString))
|
||||
import qualified Data.Text as T
|
||||
import System.Environment (lookupEnv)
|
||||
import Data.Foldable (toList)
|
||||
|
||||
|
||||
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
|
||||
>>> (onHead . traversed . sealed $ datumIso @a)
|
||||
|
||||
instance DatumIso a => DataIso (NonEmpty a) where
|
||||
dataIso = nonEmptyData datumIso
|
||||
|
||||
instance (DatumIso a, DatumIso b) => DatumIso (a, b) where
|
||||
datumIso = with \tup2 -> list (el datumIso >>> el datumIso) >>> tup2
|
||||
|
||||
@@ -17,6 +17,7 @@ module Gyehoek.Sexp.Grammar.Base
|
||||
, el
|
||||
, rest
|
||||
, restData
|
||||
, nonEmptyData
|
||||
, headTagged0'
|
||||
, headTagged0
|
||||
, headTagged1'
|
||||
@@ -32,6 +33,8 @@ module Gyehoek.Sexp.Grammar.Base
|
||||
, integer
|
||||
, int
|
||||
, unreadable
|
||||
-- ** symbols
|
||||
, symBuiltin
|
||||
-- * TODO: sort lol
|
||||
, prismIso
|
||||
, isoIso, decorate
|
||||
@@ -49,7 +52,7 @@ import Data.InvertibleGrammar.Base
|
||||
import Data.InvertibleGrammar.Base as Re
|
||||
( Grammar(..))
|
||||
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.Print (printDatum')
|
||||
import Data.Scientific (Scientific)
|
||||
@@ -57,6 +60,7 @@ import qualified Data.Scientific as Sci
|
||||
import qualified Data.Text as T
|
||||
import Control.Monad.RWS (modify)
|
||||
import qualified Data.List.NonEmpty as NE
|
||||
import Data.Foldable (toList)
|
||||
|
||||
|
||||
-- $setup
|
||||
@@ -238,6 +242,14 @@ restData g =
|
||||
>>> g
|
||||
>>> 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
|
||||
:: Snoc s s a a
|
||||
=> Grammar p (s :- a :- t) (s :- t)
|
||||
|
||||
@@ -58,7 +58,7 @@ test_eval = do
|
||||
<&> fmap ("golden/exec" </>)
|
||||
pure $ testGroup "cps interpreter"
|
||||
[ 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
|
||||
|
||||
Reference in New Issue
Block a user