eval agian

This commit is contained in:
2026-09-05 20:22:07 -06:00
parent 31c610db34
commit ac39175767
2 changed files with 110 additions and 120 deletions
+108 -120
View File
@@ -9,24 +9,27 @@ module Gyehoek.CPS.Eval
, eGrammar , eGrammar
) where ) where
import Gyehoek.CPS.Syntax hiding (Hob(..), Obj(..)) import Gyehoek.CPS.Syntax hiding (Hob(..), Obj(..), cont)
import Gyehoek.Sexp qualified as S import Gyehoek.Sexp qualified as S
import Control.Lens import Control.Lens hiding (assign)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
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 import Gyehoek.Prelude hiding (assign)
import Debug.Pretty.Simple import Debug.Pretty.Simple
import Gyehoek.Jalmot import Gyehoek.Jalmot
import Control.Monad.Cont qualified as Cont import Control.Monad.Cont
import Gyehoek.Sexp qualified as S import Gyehoek.Sexp qualified as S
import GHC.Generics (Generically(..)) import GHC.Generics (Generically(..))
import Gyehoek.Sexp ((:-)(..)) import Gyehoek.Sexp ((:-)(..))
import Data.List (nub, mapAccumR) import Data.List (nub, mapAccumR, compareLength)
import Data.HashSet.Lens (setOf) import Data.HashSet.Lens (setOf)
import Data.IntMap.Strict (IntMap) import Data.IntMap.Strict (IntMap)
import Data.IntMap.Strict qualified as IM import Data.IntMap.Strict qualified as IM
import Data.Monoid import Data.Monoid
import Control.Monad.State
import Data.Traversable (for)
import Data.Foldable (traverse_)
newtype Loc = MkLoc { getLoc :: Int } newtype Loc = MkLoc { getLoc :: Int }
@@ -37,11 +40,17 @@ data Store = MkStore
{ nextLoc :: Loc { nextLoc :: Loc
, heap :: IntMap E , heap :: IntMap E
} }
deriving stock (Show, Generic, Data) deriving stock (Show, Generic)
type instance Index Store = Loc
type instance IxValue Store = E
instance Ixed Store where ix (MkLoc j) = #heap . ix j
instance At Store where at (MkLoc j) = #heap . at j
emptyStore :: Store emptyStore :: Store
emptyStore = MkStore emptyStore = MkStore
{ nextLoc = 0 { nextLoc = MkLoc 0
, heap = mempty , heap = mempty
} }
@@ -67,57 +76,45 @@ update (MkLoc loc) v = #heap %~ IM.alter f loc
updates :: Foldable f => f (Loc, E) -> Store -> Store updates :: Foldable f => f (Loc, E) -> Store -> Store
updates = alaf Endo foldMap (uncurry update) updates = alaf Endo foldMap (uncurry update)
fetch :: Loc -> Store -> E fetch :: Loc -> M r E
fetch (MkLoc loc) st = st ^?! #heap . ix loc fetch (MkLoc loc) = gets (^?! #heap . ix loc)
new :: Store -> (Store, Loc) new :: M r Loc
new st = (st & #nextLoc %~ succ, st.nextLoc) new = state \st -> (st.nextLoc, st & #nextLoc %~ succ)
new' :: E -> Store -> (Store, Loc) new' :: E -> M r Loc
new' e st = (update l e st', l) new' e = state \st ->
where ( st.nextLoc
(st',l) = new st , st & #nextLoc %~ succ & at st.nextLoc ?~ e
)
news' :: Traversable t => t E -> Store -> (Store, Loc) defines :: Traversable t => t (Name, E) -> M Answer Env
news' es st = mapAccumR _ st es defines = alaf Ap foldMap \(name,e) -> do
where l <- new' e
(st',l) = new st pure $ bind name l
var :: HasCallStack => Env -> Name -> Loc var :: HasCallStack => Env -> Name -> M Answer Loc
var g x = g ^?! ix x var g x = case g ^. at x of
Just l -> pure l
Nothing -> wrong [i|unbound variable #{x}|]
type CmdCont = Store -> Answer type CmdCont = Store -> Answer
type ExpCont = List E -> CmdCont type ExpCont = List E -> CmdCont
type M r = ContT r (State Store)
data Answer data Answer
= AnswerValues Store (List E) = AnswerValues (List E)
| AnswerError Text | AnswerError AJalmot
deriving (Show, Generic, Data) deriving (Show, Generic)
data Mutability data Mutability
= Mut = Mut
| NoMut | NoMut
deriving (Show, Generic, Data, Eq) deriving (Show, Generic, Data, Eq)
wrong :: Text -> CmdCont wrong :: Text -> M Answer a
wrong = const . AnswerError wrong s = ContT \_ -> pure . AnswerError . EvalError $ s
single :: (E -> CmdCont) -> ExpCont
single k = \case
[x] -> k x
_ -> wrong "wrong number of return values"
send :: E -> ExpCont -> CmdCont
send e k = k [e]
-- | Continue with the value located at a given 'Loc'.
hold :: Loc -> ExpCont -> CmdCont
hold loc k st = send (fetch loc st) k st
tievals :: Traversable t => t E -> (t Loc -> CmdCont) -> CmdCont
tievals es f st0 = f ls stn
where
(stn,ls) = mapAccumR (flip new') st0 es
bind :: Name -> Loc -> Env bind :: Name -> Loc -> Env
bind k = MkEnv . H.singleton k bind k = MkEnv . H.singleton k
@@ -125,13 +122,19 @@ bind k = MkEnv . H.singleton k
extends :: Foldable f => f (Name, Loc) -> Env -> Env extends :: Foldable f => f (Name, Loc) -> Env -> Env
extends xs g = g <> foldMap (uncurry bind) xs extends xs g = g <> foldMap (uncurry bind) xs
assign :: Loc -> E -> M Answer ()
assign l e = do
use (at l) >>= \case
Just _ -> at l ?= e
Nothing -> wrong [i|#{e} #{l} |]
-- | The denotation of an expressed value. -- | The denotation of an expressed value.
data E data E
= ESymbol Text = ESymbol Text
| ECharacter Char | ECharacter Char
| EInteger Int | EInt Int
| EBool Bool | EBool Bool
| EUndefined | EUndefined
| EUnspecified | EUnspecified
@@ -139,19 +142,19 @@ data E
| EPair Loc Loc Mutability | EPair Loc Loc Mutability
| EVec (List Loc) Mutability | EVec (List Loc) Mutability
| EString (List Loc) Mutability | EString (List Loc) Mutability
| EProcedure Loc Procedure | EProcedure Procedure
deriving stock (Show, Generic, Data) deriving stock (Show, Generic)
type Procedure = List E -> DynPoints -> ExpCont -> CmdCont type Procedure = List E -> DynPoints -> M Answer (List E)
eGrammar :: Store -> S.DatumGrammar E eGrammar :: Store -> S.DatumGrammar E
eGrammar st = S.partialOsi (const . Left $ mempty) go eGrammar st = S.partialOsi (const . Left $ mempty) go
where where
gofetch x = go $ fetch x st gofetch x = go $ st ^?! ix x
go = \case go = \case
ESymbol s -> S.Symbol s ESymbol s -> S.Symbol s
ECharacter c -> S.Character c ECharacter c -> S.Character c
EInteger n -> S.Number (fromIntegral n) EInt n -> S.Number (fromIntegral n)
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>"
@@ -165,88 +168,73 @@ data DynPoints = MkDynPoints
-- 뻘짓이어라 evalVal :: Env -> Val -> M Answer E
telescope
:: Traversable t
=> (a -> (b -> r) -> r)
-> t a -> (t b -> r) -> r
telescope f = Cont.runCont . traverse (Cont.cont . f)
evalVal g (ValVar x) = var g x >>= fetch
procedure :: Env -> Procedure -> (E -> CmdCont) -> CmdCont evalVal g (ValImm imm) = pure case imm of
procedure = _ ImmInt n -> EInt n
ImmBool b -> EBool b
ImmUndefined -> EUndefined
evalVal :: Env -> Val -> ExpCont -> CmdCont evalKexp :: Env -> Kexp -> M Answer E
evalVal g (ValVar x) k = hold (var g x) $ single \case evalKexp g (KexpVar x) = var g x >>= fetch
EUndefined -> wrong "undefined variable" evalKexp g (KexpKappa kap) = evalAbs g (AbsKappa kap)
e -> send e k
evalVal1 :: Env -> Val -> (E -> CmdCont) -> CmdCont evalAbs :: Env -> Abs -> M Answer E
evalVal1 g v k = evalVal g v (single k) evalAbs g (MkAbs formals ktail e) = pure . EProcedure $ \xs dps ->
evalKexp :: Env -> Kexp -> ExpCont -> CmdCont
evalKexp g (KexpVar x) k = evalVal g (ValVar x) k
evalKexp g (KexpKappa kap) k = evalAbs g (AbsKappa kap) k
evalAbs :: Env -> Abs -> ExpCont -> CmdCont
evalAbs g (MkAbs formals mtail e) k st = send ab k st'
where
(st',l) = new' EUnspecified st
ab = EProcedure l \args dps k' ->
tievals args \argLocs ->
let argEnv = zip (formals ++ foldMap (:[]) mtail) argLocs
g' = g <> foldMap (uncurry bind) argEnv
in eval g' dps e k'
eval :: Env -> DynPoints -> Exp -> ExpCont -> CmdCont
eval g dps (ExpLetRec bs e) k = \st0 ->
let let
rhss = bs ^.. each . _2 formals' = formals ++ foldMap (:[]) ktail
(st',ls) = mapAccumR (\st _ -> new st) st0 bs lformals = length formals'
g' = g & extends (zip (bs ^.. each . _1) ls) lxs = length xs
f :: List E -> CmdCont in if lformals /= lxs
f = \rhss' -> eval g' dps e k . updates (zip ls rhss') then wrong [i| #{lformals} #{lxs} .|]
in telescope (\ab -> evalAbs g' ab . single) rhss f st' else do
ls <- xs & traverse new'
let g' = g & extends (zip formals' ls)
eval g' dps e
eval g dps (ExpJump f xs ktail) k = eval :: Env -> DynPoints -> Exp -> M Answer (List E)
telescope (evalVal1 g) (f:|xs) \(f':|xs') ->
telescope (\ke -> evalKexp g ke . single) (ktail ^.. each) \ktail' ->
case f' of
EProcedure _loc fp -> fp xs' dps k
_ -> wrong "bad procedure"
eval g dps (ExpContinue f xs) k = eval g dps (ExpJump f xs ktail) = do
telescope (evalVal1 g) (f:|xs) \(f':|xs') -> f' <- evalVal g f
case f' of xs' <- traverse (evalVal g) xs
EProcedure _loc fp -> fp xs' dps k ktail' <- traverse (evalKexp g) (ktail ^.. _Just)
_ -> wrong "bad procedure" case f' of
EProcedure p -> p (xs' ++ ktail') dps
_ -> wrong "bad procedure"
eval g dps (ExpApply f xs ktail) k = eval g dps (ExpLetRec bs e) = do
telescope (evalVal1 g) (f:|xs) \(f':|xs') -> ls <- for bs . const $ new' EUndefined
evalKexp g ktail . single $ \ktail' -> let g' = g & extends (zip (bs ^.. each . _1) ls)
case f' of bs' <- forOf (each . _2) bs (evalAbs g')
EProcedure _loc fp -> fp (xs' ++ [ktail']) dps k traverse_ (uncurry assign) $ zip ls (bs' ^.. each . _2)
_ -> wrong "bad procedure" eval g' dps e
eval g dps e = error [i|unimplemented #{e}|]
prim_halt :: Procedure
prim_halt xs _dps _k st = AnswerValues st xs
setup :: (Env -> CmdCont) -> CmdCont
setup k = tievals (defs ^.. each) _
where
defs :: HashMap Name E
defs =
[ ("halt", EProcedure _ prim_halt)
]
evalExp :: Jalmot :> es => Exp -> Eff es _ evalExp :: Jalmot :> es => Exp -> Eff es _
evalExp e = _ evalExp e = _
evalProgram :: Jalmot :> es => Program -> Eff es (List E) evalProgram :: Jalmot :> es => Program -> Eff es (List S.Datum)
evalProgram (MkProgram lam) = _ evalProgram (MkProgram lam) = case run (pure . AnswerValues) of
(AnswerError jm, _) -> throwError jm
(AnswerValues vs, st) -> traverse (S.toDatum $ eGrammar st) vs
where
run f = (`runState` emptyStore) . (`runContT` f) $ do
g <- setup
eval g MkDynPoints (ExpLetRec
[("_start",AbsLambda lam)]
(ExpApply (ValVar "_start") [] (KexpVar "halt")))
setup :: M Answer Env
setup = defines @List
[ ("halt", EProcedure prim_halt)
]
prim_halt :: Procedure
prim_halt xs _dps = ContT \_ -> pure $ AnswerValues xs
+2
View File
@@ -31,6 +31,7 @@ data AJalmot
= ReaderError (ParseErrorBundle Text Void) = ReaderError (ParseErrorBundle Text Void)
| GrammarError (Grammar.ErrorMessage Ann) | GrammarError (Grammar.ErrorMessage Ann)
| VMError Text | VMError Text
| EvalError Text
deriving (Show, Generic, Data) deriving (Show, Generic, Data)
data AJalmotCS = MkAJalmotCS !CallStack !AJalmot data AJalmotCS = MkAJalmotCS !CallStack !AJalmot
@@ -66,6 +67,7 @@ instance Exception AJalmot where
& layoutPretty defaultLayoutOptions & layoutPretty defaultLayoutOptions
& renderString & renderString
VMError err -> [i|#{err}|] VMError err -> [i|#{err}|]
EvalError err -> [i|#{err}|]
instance Exception AJalmotCS where instance Exception AJalmotCS where
backtraceDesired = const False backtraceDesired = const False