typst-0.1.0.0: src/Typst/Bind.hs
{-# LANGUAGE RankNTypes #-}
module Typst.Bind (destructuringBind) where
import Control.Monad.State
import qualified Data.Map.Ordered as OM
import Data.Maybe (fromMaybe)
import qualified Data.Vector as V
import Typst.Syntax
import Typst.Types
destructuringBind ::
Monad m =>
(forall m'. Monad m' => Identifier -> Val -> MP m' ()) ->
[BindPart] ->
Val ->
MP m ()
destructuringBind setIdentifier parts val = do
let isSink Sink {} = True
isSink _ = False
let (fronts, rest) = break isSink parts
let (sinks, backs) = span isSink rest
mbsink <- case sinks of
[Sink s] -> pure s
[] -> pure Nothing
_ -> fail "Bind cannot contain multiple sinks"
case val of
VDict m ->
evalStateT (destructureDict setIdentifier fronts backs mbsink) m
VArray v ->
evalStateT (destructureArray setIdentifier fronts backs mbsink) v
_ -> fail "Only Array or Dictionary values can be destructured"
destructureDict ::
Monad m =>
(forall m'. Monad m' => Identifier -> Val -> MP m' ()) ->
[BindPart] ->
[BindPart] ->
Maybe Identifier ->
StateT (OM.OMap Identifier Val) (MP m) ()
destructureDict setIdentifier fronts backs mbsink = do
mapM_ handleDictBind (fronts ++ backs)
case mbsink of
Just i -> get >>= lift . setIdentifier i . VDict
Nothing -> pure ()
where
handleDictBind :: Monad m => BindPart -> StateT (OM.OMap Identifier Val) (MP m) ()
handleDictBind (Sink {}) = fail "Bind cannot contain multiple sinks"
handleDictBind (Simple Nothing) = pure ()
handleDictBind (Simple (Just i)) = do
m <- get
case OM.lookup i m of
Nothing ->
fail $ "Destructuring key not found in dictionary: " <> show i
Just v -> do
put $ OM.delete i m
lift $ setIdentifier i v
handleDictBind (WithKey key mbident) = do
m <- get
case OM.lookup key m of
Nothing ->
fail $ "Destructuring key not found in dictionary: " <> show key
Just v -> do
put $ OM.delete key m
lift $ setIdentifier (fromMaybe key mbident) v
destructureArray ::
Monad m =>
(forall m'. Monad m' => Identifier -> Val -> MP m' ()) ->
[BindPart] ->
[BindPart] ->
Maybe Identifier ->
StateT (V.Vector Val) (MP m) ()
destructureArray setIdentifier fronts backs mbsink = do
mapM_ handleFrontBind fronts
mapM_ handleBackBind (reverse backs)
case mbsink of
Just i -> get >>= lift . setIdentifier i . VArray
Nothing -> pure ()
where
handleFrontBind :: Monad m => BindPart -> StateT (V.Vector Val) (MP m) ()
handleFrontBind (Sink {}) = fail "Bind cannot contain multiple sinks"
handleFrontBind (WithKey {}) = fail "Cannot destructure array with key"
handleFrontBind (Simple mbi) = do
v <- get
case V.uncons v of
Nothing -> fail "Array does not contain enough elements to destructure"
Just (x, v') -> do
put v'
case mbi of
Nothing -> pure ()
Just i -> lift $ setIdentifier i x
handleBackBind :: Monad m => BindPart -> StateT (V.Vector Val) (MP m) ()
handleBackBind (Sink {}) = fail "Bind cannot contain multiple sinks"
handleBackBind (WithKey {}) = fail "Cannot destructure array with key"
handleBackBind (Simple mbi) = do
v <- get
case V.unsnoc v of
Nothing -> fail "Array does not contain enough elements to destructure"
Just (v', x) -> do
put v'
case mbi of
Nothing -> pure ()
Just i -> lift $ setIdentifier i x