packages feed

prosidyc 0.2.0.0 → 0.3.0.0

raw patch · 13 files changed

+1245/−978 lines, 13 filesdep +containersdep +prettyprinterdep +profunctorsdep −mtldep ~hashabledep ~prosidyPVP ok

version bump matches the API change (PVP)

Dependencies added: containers, prettyprinter, profunctors

Dependencies removed: mtl

Dependency ranges changed: hashable, prosidy

API changes (from Hackage documentation)

- Prosidy.Compile: Custom :: a -> Error a
- Prosidy.Compile: EmptyMatch :: Error a
- Prosidy.Compile: ExpectedBreak :: Error a
- Prosidy.Compile: ExpectedParagraph :: Error a
- Prosidy.Compile: ExpectedTag :: TagKind -> Key -> Error a
- Prosidy.Compile: ExpectedText :: Error a
- Prosidy.Compile: Group :: Maybe Location -> ErrorSet a -> Error a
- Prosidy.Compile: ParseError :: Key -> String -> Error a
- Prosidy.Compile: Required :: Key -> Error a
- Prosidy.Compile: UnknownMetadata :: HashSet (MetadataKind, Key) -> Error a
- Prosidy.Compile: class (forall i e. Functor (Pattern t i e), HasLocation t) => CanMatch t
- Prosidy.Compile: class FromSetting a
- Prosidy.Compile: data Error a
- Prosidy.Compile: data ErrorSet e
- Prosidy.Compile: data RuleT input error context output
- Prosidy.Compile: escapeHatch :: (i -> f (Either (Error e) a)) -> RuleT i e f a
- Prosidy.Compile: fromSetting :: FromSetting a => Text -> Either String a
- Prosidy.Compile: getContent :: HasContent i => RuleT (Content i) e f a -> RuleT i e f a
- Prosidy.Compile: matchContent :: (Applicative f, Traversable t, HasContent i, t x ~ Content i, CanMatch x) => Match x e f a -> RuleT i e f (t a)
- Prosidy.Compile: opt :: (FromSetting a, HasMetadata i) => Key -> RuleT i e f (Maybe a)
- Prosidy.Compile: optParse :: HasMetadata i => Key -> (Text -> Either String a) -> RuleT i e f (Maybe a)
- Prosidy.Compile: prop :: HasMetadata i => Key -> RuleT i e f Bool
- Prosidy.Compile: req :: (FromSetting a, HasMetadata i) => Key -> RuleT i e f a
- Prosidy.Compile: reqParse :: HasMetadata i => Key -> (Text -> Either String a) -> RuleT i e f a
- Prosidy.Compile: run :: IsError e => RuleT i e Identity a -> i -> Either (ErrorSet e) a
- Prosidy.Compile: runM :: (Applicative context, IsError e) => RuleT i e context a -> i -> context (Either (ErrorSet e) a)
- Prosidy.Compile: self :: RuleT i e f i
- Prosidy.Compile: strict :: (Applicative f, HasMetadata i) => RuleT i e f a -> RuleT i e f a
- Prosidy.Compile: traversing :: Traversable t => RuleT i e f a -> RuleT (t i) e f (t a)
- Prosidy.Compile: type Error' = Error Void
- Prosidy.Compile: type ErrorSet' = ErrorSet Void
- Prosidy.Compile: type Rule input error = RuleT input error Identity
- Prosidy.Compile.Core: [Fail] :: Error error -> RuleF input error context output
- Prosidy.Compile.Core: [GetContent] :: HasContent input => RuleT (Content input) error context output -> RuleF input error context output
- Prosidy.Compile.Core: [GetProperty] :: HasMetadata input => (Bool -> a) -> Key -> RuleF input error context a
- Prosidy.Compile.Core: [GetRequiredSetting] :: HasMetadata input => Key -> (Text -> Either String output) -> RuleF input error context output
- Prosidy.Compile.Core: [GetSelf] :: (input -> output) -> RuleF input error context output
- Prosidy.Compile.Core: [GetSetting] :: HasMetadata input => (Maybe x -> output) -> Key -> (Text -> Either String x) -> RuleF input error context output
- Prosidy.Compile.Core: [Lift] :: (input -> context (Either (Error error) output)) -> RuleF input error context output
- Prosidy.Compile.Core: [TestMatch] :: CanMatch input => NonEmpty (Pattern input error context output) -> RuleF input error context output
- Prosidy.Compile.Core: [Traverse] :: Traversable t => (input -> t i) -> (t o -> output) -> RuleT i error context o -> RuleF input error context output
- Prosidy.Compile.Core: class (forall i e. Functor (Pattern t i e), HasLocation t) => CanMatch t
- Prosidy.Compile.Core: data RuleF input error context output
- Prosidy.Compile.Core: data RuleT input error context output
- Prosidy.Compile.Core: evalPattern :: (CanMatch t, Applicative g) => Pattern t error context output -> Interpret error context g -> t -> Either (NoMatch t) (g output)
- Prosidy.Compile.Core: evalPatterns :: (CanMatch i, IsError e, ApErrors e g) => NonEmpty (Pattern i e f o) -> Interpret e f g -> i -> g o
- Prosidy.Compile.Core: instance Control.Monad.Trans.Class.MonadTrans (Prosidy.Compile.Core.RuleT input error)
- Prosidy.Compile.Core: instance GHC.Base.Applicative (Prosidy.Compile.Core.RuleT input error context)
- Prosidy.Compile.Core: instance GHC.Base.Functor (Prosidy.Compile.Core.Pattern Prosidy.Types.Block error context)
- Prosidy.Compile.Core: instance GHC.Base.Functor (Prosidy.Compile.Core.Pattern Prosidy.Types.Inline error context)
- Prosidy.Compile.Core: instance GHC.Base.Functor (Prosidy.Compile.Core.RuleT input error context)
- Prosidy.Compile.Core: instance GHC.Base.Functor context => GHC.Base.Functor (Prosidy.Compile.Core.RuleF input error context)
- Prosidy.Compile.Core: instance Prosidy.Compile.Core.CanMatch Prosidy.Types.Block
- Prosidy.Compile.Core: instance Prosidy.Compile.Core.CanMatch Prosidy.Types.Inline
- Prosidy.Compile.Core: interpretWith :: Applicative g => RuleT i e f a -> Interpret e f g -> i -> g a
- Prosidy.Compile.Core: noMatchError :: CanMatch t => NoMatch t -> Error e
- Prosidy.Compile.Core: type BlockRegion = Region (Series Block)
- Prosidy.Compile.Core: type InlineRegion = Region (Series Inline)
- Prosidy.Compile.Core: type Interpret e f g = forall i a. i -> RuleF i e f a -> g a
- Prosidy.Compile.Core: type LiteralRegion = Region Text
- Prosidy.Compile.Core: type Rule input error = RuleT input error Identity
- Prosidy.Compile.Error: BlockKind :: TagKind
- Prosidy.Compile.Error: Custom :: a -> Error a
- Prosidy.Compile.Error: EmptyMatch :: Error a
- Prosidy.Compile.Error: ExpectedBreak :: Error a
- Prosidy.Compile.Error: ExpectedParagraph :: Error a
- Prosidy.Compile.Error: ExpectedTag :: TagKind -> Key -> Error a
- Prosidy.Compile.Error: ExpectedText :: Error a
- Prosidy.Compile.Error: Group :: Maybe Location -> ErrorSet a -> Error a
- Prosidy.Compile.Error: InlineKind :: TagKind
- Prosidy.Compile.Error: LiteralKind :: TagKind
- Prosidy.Compile.Error: ParseError :: Key -> String -> Error a
- Prosidy.Compile.Error: PropertyKind :: MetadataKind
- Prosidy.Compile.Error: Required :: Key -> Error a
- Prosidy.Compile.Error: SettingKind :: MetadataKind
- Prosidy.Compile.Error: UnknownMetadata :: HashSet (MetadataKind, Key) -> Error a
- Prosidy.Compile.Error: allErrors :: ErrorSet e -> NonEmpty (Error e)
- Prosidy.Compile.Error: class Applicative f => ApError e f | f -> e
- Prosidy.Compile.Error: customError :: Hashable e => e -> ErrorSet e
- Prosidy.Compile.Error: data Error a
- Prosidy.Compile.Error: data ErrorSet e
- Prosidy.Compile.Error: data MetadataKind
- Prosidy.Compile.Error: data TagKind
- Prosidy.Compile.Error: groupErrors :: (IsError e, ApErrors e m, HasLocation l) => l -> m a -> m a
- Prosidy.Compile.Error: instance (Data.Typeable.Internal.Typeable a, GHC.Exception.Type.Exception a) => GHC.Exception.Type.Exception (Prosidy.Compile.Error.Error a)
- Prosidy.Compile.Error: instance Data.Hashable.Class.Hashable Prosidy.Compile.Error.MetadataKind
- Prosidy.Compile.Error: instance Data.Hashable.Class.Hashable Prosidy.Compile.Error.TagKind
- Prosidy.Compile.Error: instance Data.Hashable.Class.Hashable a => Data.Hashable.Class.Hashable (Prosidy.Compile.Error.Error a)
- Prosidy.Compile.Error: instance Data.Hashable.Class.Hashable e => Data.Hashable.Class.Hashable (Prosidy.Compile.Error.ErrorSet e)
- Prosidy.Compile.Error: instance GHC.Classes.Eq Prosidy.Compile.Error.MetadataKind
- Prosidy.Compile.Error: instance GHC.Classes.Eq Prosidy.Compile.Error.TagKind
- Prosidy.Compile.Error: instance GHC.Classes.Eq a => GHC.Classes.Eq (Prosidy.Compile.Error.Error a)
- Prosidy.Compile.Error: instance GHC.Classes.Eq e => GHC.Classes.Eq (Prosidy.Compile.Error.ErrorSet e)
- Prosidy.Compile.Error: instance GHC.Exception.Type.Exception e => GHC.Exception.Type.Exception (Prosidy.Compile.Error.ErrorSet e)
- Prosidy.Compile.Error: instance GHC.Generics.Generic (Prosidy.Compile.Error.Error a)
- Prosidy.Compile.Error: instance GHC.Generics.Generic (Prosidy.Compile.Error.ErrorSet e)
- Prosidy.Compile.Error: instance GHC.Generics.Generic Prosidy.Compile.Error.MetadataKind
- Prosidy.Compile.Error: instance GHC.Generics.Generic Prosidy.Compile.Error.TagKind
- Prosidy.Compile.Error: instance GHC.Show.Show Prosidy.Compile.Error.MetadataKind
- Prosidy.Compile.Error: instance GHC.Show.Show Prosidy.Compile.Error.TagKind
- Prosidy.Compile.Error: instance GHC.Show.Show a => GHC.Show.Show (Prosidy.Compile.Error.Error a)
- Prosidy.Compile.Error: instance GHC.Show.Show e => GHC.Show.Show (Prosidy.Compile.Error.ErrorSet e)
- Prosidy.Compile.Error: instance Prosidy.Compile.Error.IsError e => GHC.Base.Semigroup (Prosidy.Compile.Error.ErrorSet e)
- Prosidy.Compile.Error: liftError :: ApError e f => e -> f a
- Prosidy.Compile.Error: liftError1 :: (IsError e, ApErrors e m) => Error e -> m a
- Prosidy.Compile.Error: mapError :: ApError e f => (e -> e) -> f a -> f a
- Prosidy.Compile.Error: singleError :: Hashable e => Error e -> ErrorSet e
- Prosidy.Compile.Error: type ApErrors e = ApError (ErrorSet e)
- Prosidy.Compile.Error: type Error' = Error Void
- Prosidy.Compile.Error: type ErrorSet' = ErrorSet Void
- Prosidy.Compile.Error: type IsError e = (Exception e, Hashable e, Eq e)
- Prosidy.Compile.FromSetting: Sep :: [a] -> Sep (delim :: Symbol) a
- Prosidy.Compile.FromSetting: [unsep] :: Sep (delim :: Symbol) a -> [a]
- Prosidy.Compile.FromSetting: class FromSetting a
- Prosidy.Compile.FromSetting: fromSetting :: FromSetting a => Text -> Either String a
- Prosidy.Compile.FromSetting: instance (Data.Typeable.Internal.Typeable a, GHC.Read.Read a) => Prosidy.Compile.FromSetting.FromSetting a
- Prosidy.Compile.FromSetting: instance (GHC.TypeLits.KnownSymbol delim, Prosidy.Compile.FromSetting.FromSetting a) => Prosidy.Compile.FromSetting.FromSetting (Prosidy.Compile.FromSetting.Sep delim a)
- Prosidy.Compile.FromSetting: instance Data.Foldable.Foldable (Prosidy.Compile.FromSetting.Sep delim)
- Prosidy.Compile.FromSetting: instance Data.Traversable.Traversable (Prosidy.Compile.FromSetting.Sep delim)
- Prosidy.Compile.FromSetting: instance GHC.Base.Applicative (Prosidy.Compile.FromSetting.Sep delim)
- Prosidy.Compile.FromSetting: instance GHC.Base.Functor (Prosidy.Compile.FromSetting.Sep delim)
- Prosidy.Compile.FromSetting: instance GHC.Base.Monad (Prosidy.Compile.FromSetting.Sep delim)
- Prosidy.Compile.FromSetting: instance GHC.Base.Monoid (Prosidy.Compile.FromSetting.Sep delim a)
- Prosidy.Compile.FromSetting: instance GHC.Base.Semigroup (Prosidy.Compile.FromSetting.Sep delim a)
- Prosidy.Compile.FromSetting: instance GHC.Classes.Eq a => GHC.Classes.Eq (Prosidy.Compile.FromSetting.Sep delim a)
- Prosidy.Compile.FromSetting: instance GHC.Show.Show a => GHC.Show.Show (Prosidy.Compile.FromSetting.Sep delim a)
- Prosidy.Compile.FromSetting: instance Prosidy.Compile.FromSetting.FromSetting Data.Text.Internal.Lazy.Text
- Prosidy.Compile.FromSetting: instance Prosidy.Compile.FromSetting.FromSetting Data.Text.Internal.Text
- Prosidy.Compile.FromSetting: instance Prosidy.Compile.FromSetting.FromSetting [GHC.Types.Char]
- Prosidy.Compile.FromSetting: newtype Sep (delim :: Symbol) a
- Prosidy.Compile.Match: blockTag :: Applicative f => Key -> RuleT BlockRegion e f a -> Match Block e f a
- Prosidy.Compile.Match: blockTag' :: Key -> RuleT BlockRegion e f a -> Match Block e f a
- Prosidy.Compile.Match: break :: RuleT () e f a -> Match Inline e f a
- Prosidy.Compile.Match: breakWith :: a -> Match Inline e f a
- Prosidy.Compile.Match: data MatchM i e a f r
- Prosidy.Compile.Match: inlineTag :: Applicative f => Key -> RuleT InlineRegion e f a -> Match Inline e f a
- Prosidy.Compile.Match: inlineTag' :: Key -> RuleT InlineRegion e f a -> Match Inline e f a
- Prosidy.Compile.Match: instance GHC.Base.Applicative (Prosidy.Compile.Match.MatchM i e a f)
- Prosidy.Compile.Match: instance GHC.Base.Functor (Prosidy.Compile.Match.MatchM i e a f)
- Prosidy.Compile.Match: instance GHC.Base.Monad (Prosidy.Compile.Match.MatchM i e a f)
- Prosidy.Compile.Match: literalTag :: Applicative f => Key -> RuleT LiteralRegion e f a -> Match Block e f a
- Prosidy.Compile.Match: literalTag' :: Key -> RuleT LiteralRegion e f a -> Match Block e f a
- Prosidy.Compile.Match: match :: (Applicative f, CanMatch i) => Match i e f a -> RuleT i e f a
- Prosidy.Compile.Match: paragraph :: RuleT (SeriesNE Inline) e f a -> Match Block e f a
- Prosidy.Compile.Match: text :: RuleT Text e f a -> Match Inline e f a
- Prosidy.Compile.Match: type Match i e f a = MatchM i e a f ()
- Prosidy.Compile.Strict: instance GHC.Base.Applicative Prosidy.Compile.Strict.Strict
- Prosidy.Compile.Strict: instance GHC.Base.Functor Prosidy.Compile.Strict.Strict
- Prosidy.Compile.Strict: instance GHC.Base.Monoid Prosidy.Compile.Strict.Schema
- Prosidy.Compile.Strict: instance GHC.Base.Semigroup Prosidy.Compile.Strict.Schema
- Prosidy.Compile.Strict: strict :: (Applicative f, HasMetadata i) => RuleT i e f a -> RuleT i e f a
+ Data.Either.Valid: Invalid :: !e -> Valid e a
+ Data.Either.Valid: Valid :: !a -> Valid e a
+ Data.Either.Valid: data Valid e a
+ Data.Either.Valid: fromEither :: Either e a -> Valid e a
+ Data.Either.Valid: instance (GHC.Base.Semigroup e, GHC.Base.Monoid a) => GHC.Base.Monoid (Data.Either.Valid.Valid e a)
+ Data.Either.Valid: instance (GHC.Base.Semigroup e, GHC.Base.Semigroup a) => GHC.Base.Semigroup (Data.Either.Valid.Valid e a)
+ Data.Either.Valid: instance (GHC.Classes.Eq e, GHC.Classes.Eq a) => GHC.Classes.Eq (Data.Either.Valid.Valid e a)
+ Data.Either.Valid: instance (GHC.Classes.Ord e, GHC.Classes.Ord a) => GHC.Classes.Ord (Data.Either.Valid.Valid e a)
+ Data.Either.Valid: instance (GHC.Show.Show e, GHC.Show.Show a) => GHC.Show.Show (Data.Either.Valid.Valid e a)
+ Data.Either.Valid: instance Data.Bifunctor.Bifunctor Data.Either.Valid.Valid
+ Data.Either.Valid: instance GHC.Base.Functor (Data.Either.Valid.Valid e)
+ Data.Either.Valid: instance GHC.Base.Monoid e => GHC.Base.Alternative (Data.Either.Valid.Valid e)
+ Data.Either.Valid: instance GHC.Base.Semigroup e => GHC.Base.Applicative (Data.Either.Valid.Valid e)
+ Data.Either.Valid: toEither :: Valid e a -> Either e a
+ Data.Either.Valid: valid :: (e -> r) -> (a -> r) -> Valid e a -> r
+ Data.Void.HKT: absurd :: Uninhabited a => a -> b
+ Data.Void.HKT: class Uninhabited a
+ Data.Void.HKT: data family Void :: k
+ Data.Void.HKT: instance Data.Bifunctor.Bifunctor Data.Void.HKT.Void
+ Data.Void.HKT: instance Data.Profunctor.Choice.Choice Data.Void.HKT.Void
+ Data.Void.HKT: instance Data.Profunctor.Strong.Strong Data.Void.HKT.Void
+ Data.Void.HKT: instance Data.Profunctor.Unsafe.Profunctor Data.Void.HKT.Void
+ Data.Void.HKT: instance Data.Void.HKT.Uninhabited Data.Void.HKT.Void
+ Data.Void.HKT: instance GHC.Base.Functor Data.Void.HKT.Void
+ Data.Void.HKT: instance forall k (a :: k). Data.Bifunctor.Bifunctor (Data.Void.HKT.Void a)
+ Data.Void.HKT: instance forall k (a :: k). Data.Profunctor.Choice.Choice (Data.Void.HKT.Void a)
+ Data.Void.HKT: instance forall k (a :: k). Data.Profunctor.Strong.Strong (Data.Void.HKT.Void a)
+ Data.Void.HKT: instance forall k (a :: k). Data.Profunctor.Unsafe.Profunctor (Data.Void.HKT.Void a)
+ Data.Void.HKT: instance forall k (a :: k). Data.Void.HKT.Uninhabited (Data.Void.HKT.Void a)
+ Data.Void.HKT: instance forall k (a :: k). GHC.Base.Functor (Data.Void.HKT.Void a)
+ Data.Void.HKT: instance forall k1 k2 (a :: k1) (b :: k2). Data.Void.HKT.Uninhabited (Data.Void.HKT.Void a b)
+ Data.Void.HKT: instance forall k1 k2 (a :: k1) (b :: k2). GHC.Base.Functor (Data.Void.HKT.Void a b)
+ Data.Void.HKT: instance forall k1 k2 k3 (a :: k1) (b :: k2) (c :: k3). Data.Void.HKT.Uninhabited (Data.Void.HKT.Void a b c)
+ Prosidy.Compile.Core: (<|>) :: Alternative f => f a -> f a -> f a
+ Prosidy.Compile.Core: --
+ Prosidy.Compile.Core: -- This type defaults to an uninhabited type. Only override this type if
+ Prosidy.Compile.Core: -- you intend on overriding <a>liftRule</a>, as well.
+ Prosidy.Compile.Core: -- | A type for expressions that can be lifted by the interpreter.
+ Prosidy.Compile.Core: BlockRuleBlockTag :: Rules BlockTag f a -> BlockRule f a
+ Prosidy.Compile.Core: BlockRuleLiteralTag :: Rules LiteralTag f a -> BlockRule f a
+ Prosidy.Compile.Core: BlockRuleParagraph :: Rules Paragraph f a -> BlockRule f a
+ Prosidy.Compile.Core: DocumentRule :: RegionRule (Series Block) f a -> DocumentRule f a
+ Prosidy.Compile.Core: Escape :: f a -> Rule t f a
+ Prosidy.Compile.Core: FragmentRuleLocation :: (Maybe Location -> a) -> FragmentRule f a
+ Prosidy.Compile.Core: FragmentRuleText :: (Text -> a) -> FragmentRule f a
+ Prosidy.Compile.Core: InlineRuleBreak :: a -> InlineRule f a
+ Prosidy.Compile.Core: InlineRuleFragment :: Rules Fragment f a -> InlineRule f a
+ Prosidy.Compile.Core: InlineRuleInlineTag :: Rules InlineTag f a -> InlineRule f a
+ Prosidy.Compile.Core: MetadataRuleAllowUnknown :: a -> MetadataRule f a
+ Prosidy.Compile.Core: MetadataRuleProperty :: (Bool -> a) -> Key -> MetadataRule f a
+ Prosidy.Compile.Core: MetadataRuleSetting :: (Text -> Either String a) -> Maybe a -> Key -> MetadataRule f a
+ Prosidy.Compile.Core: ParagraphRuleContent :: Rules (SeriesNE Inline) f a -> ParagraphRule f a
+ Prosidy.Compile.Core: ParagraphRuleLocation :: (Maybe Location -> a) -> ParagraphRule f a
+ Prosidy.Compile.Core: RegionRuleContent :: Rules t f a -> RegionRule t f a
+ Prosidy.Compile.Core: RegionRuleLocation :: (Maybe Location -> a) -> RegionRule t f a
+ Prosidy.Compile.Core: RegionRuleMetadata :: MetadataRule f a -> RegionRule t f a
+ Prosidy.Compile.Core: RuleFor :: RuleFor t f a -> Rule t f a
+ Prosidy.Compile.Core: Self :: (t -> a) -> Rule t f a
+ Prosidy.Compile.Core: SeriesNERule :: (b -> c -> a) -> Rules t f b -> Rules (Series t) f c -> SeriesNERule t f a
+ Prosidy.Compile.Core: SeriesRuleEmpty :: a -> SeriesRule t f a
+ Prosidy.Compile.Core: SeriesRuleNext :: SeriesNERule t f a -> SeriesRule t f a
+ Prosidy.Compile.Core: TagRuleKey :: Key -> a -> TagRule t f a
+ Prosidy.Compile.Core: TagRuleRegion :: RegionRule t f a -> TagRule t f a
+ Prosidy.Compile.Core: class Applicative f => Alternative (f :: Type -> Type)
+ Prosidy.Compile.Core: class (forall i. Alternative (t i)) => Context t where {
+ Prosidy.Compile.Core: class HoistRuleFor t
+ Prosidy.Compile.Core: class Context t => Interpret t i
+ Prosidy.Compile.Core: data BlockRule f a
+ Prosidy.Compile.Core: data FragmentRule f a
+ Prosidy.Compile.Core: data InlineRule f a
+ Prosidy.Compile.Core: data MetadataRule f a
+ Prosidy.Compile.Core: data ParagraphRule f a
+ Prosidy.Compile.Core: data RegionRule t f a
+ Prosidy.Compile.Core: data Rule t f a
+ Prosidy.Compile.Core: data Rules t f a
+ Prosidy.Compile.Core: data SeriesNERule t f a
+ Prosidy.Compile.Core: data SeriesRule t f a
+ Prosidy.Compile.Core: data TagRule t f a
+ Prosidy.Compile.Core: empty :: Alternative f => f a
+ Prosidy.Compile.Core: hoist :: HoistRuleFor t => (forall b. f b -> g b) -> Rules t f a -> Rules t g a
+ Prosidy.Compile.Core: infixl 3 <|>
+ Prosidy.Compile.Core: interpret :: forall t i a. Interpret t i => Rules i (Local t) a -> t i a
+ Prosidy.Compile.Core: liftRule :: (Context t, Local t a ~ Void t a) => Local t a -> t i a
+ Prosidy.Compile.Core: local :: Functor f => f a -> Rules t f a
+ Prosidy.Compile.Core: many :: Alternative f => f a -> f [a]
+ Prosidy.Compile.Core: mapRules :: forall a a' t t' f. (Functor f, Functor (RuleFor t' f)) => (forall x. RuleFor t f x -> RuleFor t' f x) -> (t' -> t) -> (a -> a') -> Rules t f a -> Rules t' f a'
+ Prosidy.Compile.Core: newtype DocumentRule f a
+ Prosidy.Compile.Core: runRule :: (Interpret t i, RuleFor i ~ Void i) => RuleFor i (Local t) a -> t i a
+ Prosidy.Compile.Core: runRules :: Alternative g => (forall b. Rule t f b -> g b) -> Rules t f a -> g a
+ Prosidy.Compile.Core: runSelf :: Context t => t i i
+ Prosidy.Compile.Core: self :: Rules t f t
+ Prosidy.Compile.Core: some :: Alternative f => f a -> f [a]
+ Prosidy.Compile.Core: type Local t = Void t;
+ Prosidy.Compile.Core: type family Local t :: * -> *;
+ Prosidy.Compile.Core: }
+ Prosidy.Compile.DSL: (&>) :: Rules t f a -> Rules (Series t) f (Series a) -> Rules (Series t) f (Series a)
+ Prosidy.Compile.DSL: (&>>) :: Rules t f a -> Rules (Series t) f (Series a) -> Rules (SeriesNE t) f (SeriesNE a)
+ Prosidy.Compile.DSL: blockTag :: Functor f => Key -> Rules BlockRegion f a -> Match Block f a
+ Prosidy.Compile.DSL: breakWith :: a -> Match Inline f a
+ Prosidy.Compile.DSL: class FromSetting a
+ Prosidy.Compile.DSL: class HasContent t => RegionLike t
+ Prosidy.Compile.DSL: collect :: Rules t f a -> Rules (Series t) f (Series a)
+ Prosidy.Compile.DSL: content :: RegionLike t => Rules (Content t) f a -> Rules t f a
+ Prosidy.Compile.DSL: end :: Rules (Series t) f (Series a)
+ Prosidy.Compile.DSL: endWith :: a -> Rules (Series t) f a
+ Prosidy.Compile.DSL: folded :: Monoid a => Rules t f a -> Rules (Series t) f a
+ Prosidy.Compile.DSL: folded1 :: Monoid a => Rules t f a -> Rules (SeriesNE t) f a
+ Prosidy.Compile.DSL: hoist :: HoistRuleFor t => (forall b. f b -> g b) -> Rules t f a -> Rules t g a
+ Prosidy.Compile.DSL: infixr 1 &>>
+ Prosidy.Compile.DSL: infixr 3 &>
+ Prosidy.Compile.DSL: inlineTag :: Functor f => Key -> Rules InlineRegion f a -> Match Inline f a
+ Prosidy.Compile.DSL: instance GHC.Base.Applicative (Prosidy.Compile.DSL.MatchM t f a)
+ Prosidy.Compile.DSL: instance GHC.Base.Functor (Prosidy.Compile.DSL.MatchM t f a)
+ Prosidy.Compile.DSL: instance GHC.Base.Monad (Prosidy.Compile.DSL.MatchM t f a)
+ Prosidy.Compile.DSL: instance GHC.Base.Monoid r => GHC.Base.Monoid (Prosidy.Compile.DSL.MatchM t a f r)
+ Prosidy.Compile.DSL: instance GHC.Base.Semigroup r => GHC.Base.Semigroup (Prosidy.Compile.DSL.MatchM t a f r)
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting Data.Text.Internal.Lazy.Text
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting Data.Text.Internal.Text
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting GHC.Base.String
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting GHC.Integer.Type.Integer
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting GHC.Natural.Natural
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting GHC.Types.Double
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting GHC.Types.Float
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting GHC.Types.Int
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.FromSetting GHC.Types.Word
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.RegionLike (Prosidy.Types.Region t)
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.RegionLike (Prosidy.Types.Tag t)
+ Prosidy.Compile.DSL: instance Prosidy.Compile.DSL.RegionLike Prosidy.Types.Document
+ Prosidy.Compile.DSL: lax :: RegionLike t => Rules t f ()
+ Prosidy.Compile.DSL: literalTag :: Functor f => Key -> Rules LiteralRegion f a -> Match Block f a
+ Prosidy.Compile.DSL: local :: Functor f => f a -> Rules t f a
+ Prosidy.Compile.DSL: match :: Match t f a -> Rules t f a
+ Prosidy.Compile.DSL: opt :: forall a t f. (RegionLike t, FromSetting a) => Key -> Rules t f (Maybe a)
+ Prosidy.Compile.DSL: paragraph :: Rules (SeriesNE Inline) f a -> Match Block f a
+ Prosidy.Compile.DSL: parseSetting :: (FromSetting a, Typeable a, Read a) => Text -> Either String a
+ Prosidy.Compile.DSL: prop :: RegionLike t => Key -> Rules t f Bool
+ Prosidy.Compile.DSL: req :: forall a t f. (RegionLike t, FromSetting a) => Key -> Rules t f a
+ Prosidy.Compile.DSL: self :: Rules t f t
+ Prosidy.Compile.DSL: text :: (Text -> a) -> Match Inline f a
+ Prosidy.Compile.DSL: type Match t f a = MatchM t f a ()
+ Prosidy.Compile.Run: Group :: Location -> Set RunError -> RunError
+ Prosidy.Compile.Run: MatchError :: Text -> RunError
+ Prosidy.Compile.Run: ParseError :: Key -> String -> RunError
+ Prosidy.Compile.Run: RequiredSetting :: Key -> RunError
+ Prosidy.Compile.Run: RunErrors :: Set RunError -> RunErrors
+ Prosidy.Compile.Run: TooFewElements :: RunError
+ Prosidy.Compile.Run: TooManyElements :: RunError
+ Prosidy.Compile.Run: UnexpectedProperties :: HashSet Key -> HashSet Key -> RunError
+ Prosidy.Compile.Run: UnexpectedSettings :: HashSet Key -> HashSet Key -> RunError
+ Prosidy.Compile.Run: data RunError
+ Prosidy.Compile.Run: data RunT f t a
+ Prosidy.Compile.Run: instance (GHC.Base.Applicative f, Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) t) => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) (Prosidy.Types.Region t)
+ Prosidy.Compile.Run: instance (GHC.Base.Applicative f, Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) t) => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) (Prosidy.Types.Series.Series t)
+ Prosidy.Compile.Run: instance (GHC.Base.Applicative f, Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) t) => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) (Prosidy.Types.Series.SeriesNE t)
+ Prosidy.Compile.Run: instance (GHC.Base.Applicative f, Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) t) => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) (Prosidy.Types.Tag t)
+ Prosidy.Compile.Run: instance Data.Text.Prettyprint.Doc.Internal.Pretty Prosidy.Compile.Run.Location
+ Prosidy.Compile.Run: instance Data.Text.Prettyprint.Doc.Internal.Pretty Prosidy.Compile.Run.RunError
+ Prosidy.Compile.Run: instance Data.Text.Prettyprint.Doc.Internal.Pretty Prosidy.Compile.Run.RunErrors
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => GHC.Base.Alternative (Prosidy.Compile.Run.RunT f t)
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => GHC.Base.Applicative (Prosidy.Compile.Run.RunT f t)
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => Prosidy.Compile.Core.Interpret.Context (Prosidy.Compile.Run.RunT f)
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) Data.Text.Internal.Text
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) Prosidy.Types.Block
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) Prosidy.Types.Document
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) Prosidy.Types.Fragment
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) Prosidy.Types.Inline
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) Prosidy.Types.Metadata
+ Prosidy.Compile.Run: instance GHC.Base.Applicative f => Prosidy.Compile.Core.Interpret.Interpret (Prosidy.Compile.Run.RunT f) Prosidy.Types.Paragraph
+ Prosidy.Compile.Run: instance GHC.Base.Functor f => Data.Profunctor.Strong.Strong (Prosidy.Compile.Run.RunT f)
+ Prosidy.Compile.Run: instance GHC.Base.Functor f => Data.Profunctor.Unsafe.Profunctor (Prosidy.Compile.Run.RunT f)
+ Prosidy.Compile.Run: instance GHC.Base.Functor f => GHC.Base.Functor (Prosidy.Compile.Run.RunT f t)
+ Prosidy.Compile.Run: instance GHC.Base.Monoid Prosidy.Compile.Run.Observe
+ Prosidy.Compile.Run: instance GHC.Base.Monoid Prosidy.Compile.Run.Observing
+ Prosidy.Compile.Run: instance GHC.Base.Monoid Prosidy.Compile.Run.RunErrors
+ Prosidy.Compile.Run: instance GHC.Base.Semigroup Prosidy.Compile.Run.Observe
+ Prosidy.Compile.Run: instance GHC.Base.Semigroup Prosidy.Compile.Run.Observing
+ Prosidy.Compile.Run: instance GHC.Base.Semigroup Prosidy.Compile.Run.RunErrors
+ Prosidy.Compile.Run: instance GHC.Classes.Eq Prosidy.Compile.Run.Location
+ Prosidy.Compile.Run: instance GHC.Classes.Eq Prosidy.Compile.Run.RunError
+ Prosidy.Compile.Run: instance GHC.Classes.Eq Prosidy.Compile.Run.RunErrors
+ Prosidy.Compile.Run: instance GHC.Classes.Ord Prosidy.Compile.Run.Location
+ Prosidy.Compile.Run: instance GHC.Classes.Ord Prosidy.Compile.Run.RunError
+ Prosidy.Compile.Run: instance GHC.Classes.Ord Prosidy.Compile.Run.RunErrors
+ Prosidy.Compile.Run: instance GHC.Exception.Type.Exception Prosidy.Compile.Run.RunError
+ Prosidy.Compile.Run: instance GHC.Exception.Type.Exception Prosidy.Compile.Run.RunErrors
+ Prosidy.Compile.Run: instance GHC.Show.Show Prosidy.Compile.Run.Location
+ Prosidy.Compile.Run: instance GHC.Show.Show Prosidy.Compile.Run.Observe
+ Prosidy.Compile.Run: instance GHC.Show.Show Prosidy.Compile.Run.Observing
+ Prosidy.Compile.Run: instance GHC.Show.Show Prosidy.Compile.Run.RunError
+ Prosidy.Compile.Run: instance GHC.Show.Show Prosidy.Compile.Run.RunErrors
+ Prosidy.Compile.Run: newtype RunErrors
+ Prosidy.Compile.Run: run :: i -> Run i a -> Either RunErrors a
+ Prosidy.Compile.Run: runT :: i -> RunT f i a -> Either RunErrors (f a)
+ Prosidy.Compile.Run: type Run = RunT Identity
- Prosidy.Compile.Core: rule :: RuleF i e f o -> RuleT i e f o
+ Prosidy.Compile.Core: rule :: RuleFor t f a -> Rules t f a

Files

prosidyc.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.4 name:                prosidyc-version:             0.2.0.0+version:             0.3.0.0 synopsis:            A DSL for processing Prosidy documents. license:             MPL-2.0 license-file:        LICENSE@@ -43,20 +43,25 @@     exposed-modules:         Prosidy.Compile       , Prosidy.Compile.Core-      , Prosidy.Compile.Error-      , Prosidy.Compile.FromSetting-      , Prosidy.Compile.Match-      , Prosidy.Compile.Strict+      , Prosidy.Compile.DSL+      , Prosidy.Compile.Run+      , Data.Either.Valid+      , Data.Void.HKT      other-modules:-        Prosidy.Compile.Run+        Prosidy.Compile.Core.Interpret+      , Prosidy.Compile.Core.Rules      build-depends:-        base                 >= 4.11 && < 5-      , prosidy              >= 1.6  && < 1.7-      , free                 >= 5.1  && < 5.2-      , hashable             >= 1.2  && < 1.4-      , microlens            >= 0.4  && < 0.5-      , mtl                  >= 2.2  && < 2.3-      , text                 >= 1.2  && < 1.3-      , unordered-containers >= 0.2  && < 0.3+        base                 >= 4.11     && < 5+      , containers           >= 0.6      && < 0.7+      , free                 >= 5.1      && < 5.2+      , microlens            >= 0.4      && < 0.5+      , prosidy              >= 1.6.0.2  && < 1.7+      , text                 >= 1.2      && < 1.3+      , unordered-containers >= 0.2      && < 0.3+      , profunctors          >= 5.5      && < 5.6+      , hashable             >= 1.3      && < 1.4+      , prettyprinter        >= 1.6      && < 1.7++-------------------------------------------------------------------------------
+ src/Data/Either/Valid.hs view
@@ -0,0 +1,79 @@+{-|+Module      : Data.Either.Valid+Description : 'Either', but accumulates its errors.+Copyright   : ©2020 James Alexander Feldman-Crough+License     : MPL-2.0+Maintainer  : alex@fldcr.com+-}+{-# LANGUAGE LambdaCase #-}+module Data.Either.Valid +  ( Valid(..)+  , fromEither+  , toEither+  , valid+  ) where++import Data.Bifunctor (Bifunctor(..))+import Control.Applicative (Alternative(..))++-- | Like the 'Either' type, but its instances accumulates its errors. As such,+-- there is no 'Monad' instance for 'Valid'.+--+-- The 'Invalid' constructor takes precedence over 'Valid' when used with+-- classes that combine two values.+--+-- Note: There are a /lot/ of packages that implement this data type, but+-- finding a well-maintained one with minimal dependencies proved difficult.+data Valid e a =+    Invalid !e+  | Valid   !a+  deriving (Eq, Show, Ord)++instance (Semigroup e, Semigroup a) => Semigroup (Valid e a) where+    Valid   lhs   <> Valid   rhs = Valid   (lhs <> rhs)+    Invalid lhs   <> Invalid rhs = Invalid (lhs <> rhs)+    lhs@Invalid{} <> _           = lhs+    _             <> rhs         = rhs+    +instance (Semigroup e, Monoid a) => Monoid (Valid e a) where+    mempty = Valid mempty++instance Bifunctor Valid where+    bimap f g = valid (Invalid . f) (Valid . g)+    {-# INLINABLE bimap #-}++instance Functor (Valid e) where+    fmap = second+    {-# INLINE fmap #-}++instance Semigroup e => Applicative (Valid e) where+    pure = Valid++    Valid   fn  <*> Valid   x     = Valid (fn x)+    Invalid lhs <*> Invalid rhs   = Invalid (lhs <> rhs)+    Invalid lhs <*> _             = Invalid lhs+    _           <*> Invalid rhs   = Invalid rhs++instance Monoid e => Alternative (Valid e) where+    empty = Invalid mempty++    lhs@Valid{} <|> _           = lhs+    Invalid lhs <|> Invalid rhs = Invalid (lhs <> rhs)+    Invalid{}   <|> rhs         = rhs++-- | Convert an 'Either' value to 'Valid'.+fromEither :: Either e a -> Valid e a+fromEither = either Invalid Valid+{-# INLINE fromEither #-}++-- | Convert a 'Valid' value to 'Either'.+toEither :: Valid e a -> Either e a+toEither = valid Left Right+{-# INLINE toEither #-}++-- | Consume a 'Valid' by handling errors and valid values.+valid :: (e -> r) -> (a -> r) -> Valid e a -> r+valid l r = \case+    Invalid e -> l e+    Valid   a -> r a+{-# INLINE valid #-}
+ src/Data/Void/HKT.hs view
@@ -0,0 +1,89 @@+{-|+Module      : Data.Void.HKT+Description : A poly-kinded uninhabited type.+Copyright   : ©2020 James Alexander Feldman-Crough+License     : MPL-2.0+Maintainer  : alex@fldcr.com+-}+{-# OPTIONS_GHC -Wno-unused-binds #-}+{-# LANGUAGE EmptyCase #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE PolyKinds #-}+module Data.Void.HKT (Void, Uninhabited(..)) where++import           Data.Profunctor                ( Profunctor(..)+                                                , Strong(..)+                                                , Choice(..)+                                                )+import           Data.Bifunctor                 ( Bifunctor(..) )++-- | A poly-kinded, uninhabited type family.+data family Void :: k++-- | The uninhabited type taking no arguments.+data instance Void++-- | The uninhabited type taking one argument.+newtype instance Void (a :: ka) = Void1 Void++-- | The uninhabited type taking two arguments.+newtype instance Void (a :: ka) (b :: kb) = Void2 Void++-- | The uninhabited type taking three arguments.+newtype instance Void (a :: ka) (b :: kb) (c :: kc) = Void3 Void++-- | Defines uninhabited types.+class Uninhabited a where+    -- | If @a@ is an uninhabited type, we will never receive a value of type+    -- @a@ and thus we can return a value of any type.+    absurd :: a -> b++instance Uninhabited Void where+    absurd = \case {}++instance Uninhabited (Void a) where+    absurd = \case {}++instance Uninhabited (Void a b) where+    absurd = \case {}++instance Uninhabited (Void a b c) where+    absurd = \case {}++instance Functor Void where+    fmap = const absurd++instance Functor (Void a) where+    fmap = const absurd++instance Functor (Void a b) where+    fmap = const absurd++instance Bifunctor Void where+    bimap = const (const absurd)++instance Bifunctor (Void a) where+    bimap = const (const absurd)++instance Profunctor Void where+    dimap = const (const absurd)++instance Profunctor (Void a) where+    dimap = const (const absurd)++instance Strong Void where+    first'  = absurd+    second' = absurd++instance Strong (Void a) where+    first'  = absurd+    second' = absurd++instance Choice Void where+    left'  = absurd+    right' = absurd++instance Choice (Void a) where+    left'  = absurd+    right' = absurd
src/Prosidy/Compile.hs view
@@ -1,110 +1,12 @@ {-| Module      : Prosidy.Compile-Description : Compile Prosidy documents into other shapes+Description : Reexport module. You probable want to import this. Copyright   : ©2020 James Alexander Feldman-Crough License     : MPL-2.0 Maintainer  : alex@fldcr.com -}-{-# LANGUAGE ApplicativeDo #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE DerivingVia #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE UndecidableInstances #-}-module Prosidy.Compile-    ( escapeHatch-    , getContent-    , matchContent-    , optParse-    , prop-    , reqParse-    , traversing-    , self-    , strict-    , RuleT-    , Rule-    , CanMatch-    , Error(..)-    , ErrorSet-    , Error'-    , ErrorSet'-    , FromSetting(..)-    , req-    , opt-    , module Prosidy.Compile.Match-    , module Prosidy.Compile.Run-    )-where--import           Prelude                 hiding ( break )-import           Prosidy.Compile.Core-import           Prosidy.Compile.Error-import           Prosidy.Compile.Match-import           Prosidy.Compile.Run-import           Prosidy.Compile.Strict-import           Prosidy.Compile.FromSetting--import           Data.Text                      ( Text )--import qualified Prosidy                       as P------------------------------------------------------------------------------------ | Access the inner 'Prosidy.Types.Content' of a node.-getContent :: P.HasContent i => RuleT (P.Content i) e f a -> RuleT i e f a-getContent = rule . GetContent---- | Traverse over each item in a node's 'P.Content' via fallible matches.-matchContent-    :: ( Applicative f-       , Traversable t-       , P.HasContent i-       , t x ~ P.Content i-       , CanMatch x-       )-    => Match x e f a-    -> RuleT i e f (t a)-matchContent = getContent . traversing . match---- | Parse an optional setting from a node with attached 'P.Metadata'.-optParse-    :: P.HasMetadata i-    => P.Key-    -> (Text -> Either String a)-    -> RuleT i e f (Maybe a)-optParse key = rule . GetSetting id key---- | Check if a property is set on a node with attached 'P.Metadata'.-prop :: P.HasMetadata i => P.Key -> RuleT i e f Bool-prop = rule . GetProperty id---- | Parse an required setting from a node with attached 'P.Metadata'.-reqParse-    :: P.HasMetadata i => P.Key -> (Text -> Either String a) -> RuleT i e f a-reqParse key = rule . GetRequiredSetting key---- | Lift a 'RuleT' so that it operates on a traversable structure.-traversing :: Traversable t => RuleT i e f a -> RuleT (t i) e f (t a)-traversing = rule . Traverse id id---- | Access the contents of a node.-self :: RuleT i e f i-self = rule $ GetSelf id---- | Do anything you want with a node. This should be used sparingly! The--- actions you perform inside of this function are invisible to inspection.-escapeHatch :: (i -> f (Either (Error e) a)) -> RuleT i e f a-escapeHatch = rule . Lift------------------------------------------------------------------------------------ | Retrieve an optional setting, parsing using its 'FromSetting' instance. -opt :: (FromSetting a, P.HasMetadata i) => P.Key -> RuleT i e f (Maybe a)-opt key = optParse key fromSetting+module Prosidy.Compile (module X) where --- | Retrieve an required setting, parsing using its 'FromSetting' instance. -req :: (FromSetting a, P.HasMetadata i) => P.Key -> RuleT i e f a-req key = reqParse key fromSetting+import           Prosidy.Compile.Core          as X+import           Prosidy.Compile.DSL           as X+import           Prosidy.Compile.Run           as X
src/Prosidy/Compile/Core.hs view
@@ -1,286 +1,12 @@ {-|-Module      : Prosidy.Compile.Core-Description : Primitive type definitions and functions.+Module      : Prosidy.Compile.Core.Rule+Description : Basic contextual compilation rules  Copyright   : ©2020 James Alexander Feldman-Crough License     : MPL-2.0 Maintainer  : alex@fldcr.com -}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE DerivingVia #-}-{-# LANGUAGE QuantifiedConstraints #-}-{-# LANGUAGE GeneralisedNewtypeDeriving #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE LambdaCase #-}-module Prosidy.Compile.Core-    ( RuleF(..)-    , RuleT-    , Rule-    , CanMatch(evalPattern, noMatchError)-    , Pattern(..)-    , Interpret-    , BlockRegion-    , InlineRegion-    , LiteralRegion-    , interpretWith-    , evalPatterns-    , rule-    )-where--import           Lens.Micro-import           Prosidy.Compile.Error--import           Prosidy                        ( Key-                                                , HasLocation-                                                , HasMetadata-                                                , HasContent(Content)-                                                )-import           Data.Text                      ( Text )-import           Data.Bifunctor                 ( Bifunctor(..) )-import           Data.List.NonEmpty             ( NonEmpty(..) )-import           Control.Monad.Trans            ( MonadTrans(..) )-import           Data.Functor.Identity          ( Identity )--import qualified Prosidy-import qualified Control.Applicative.Free.Final-                                               as Ap---- | A single compilation rule. Parameterized by the following types:------ * @input@: The type of the Prosidy node that is currently accessible.------ * @error@: Allows users to specify a custom error type to be used for--- throwing errors. 'Data.Void.Void' can be used to rely solely on--- the errors built into this library.------ * @context@: A 'Monad' for performing contextual computation beyond what--- is provided by this library. If additional contextual computation is not--- desired, use 'Data.Functor.Identity.Identity' as the type.------ * @output@: The resulting output type.-newtype RuleT input error context output = RuleT-    (Ap.Ap (RuleF input error context) output)-  deriving (Functor, Applicative)--instance MonadTrans (RuleT input error) where-    lift = rule . Lift . const . fmap Right---- | 'RuleT' without a contextual environment.-type Rule input error = RuleT input error Identity---- | Lifts a 'RuleF' into a 'RuleT'.-rule :: RuleF i e f o -> RuleT i e f o-rule = RuleT . Ap.liftAp---- | The control functor for compiling Prosidy elements. Each action--- corresponds to an action to perform on the @input@ variable.------ See 'RuleT' and 'Rule' for use of this type.-data RuleF input error context output where-    -- | Throw an error.-    Fail-        ::Error error-        -> RuleF input error context output--    -- | Embed a raw action as a rule. Note: Please avoid using this if-    -- possible: it breaks static introspection!-    Lift-        ::(input -> context (Either (Error error) output))-        -> RuleF input error context output--    -- | Given a non-empty list of potential cases, construct a Rule that-    -- processes any items matching at least one of those cases.-    TestMatch-        ::(CanMatch input)-        => NonEmpty (Pattern input error context output)-        -> RuleF input error context output--    Traverse-        ::Traversable t-        => (input -> t i)-        -> (t o -> output)-        -> RuleT i error context o-        -> RuleF input error context output--    -- | When @input@ is a value wrapping some 'Content', enable access to that-    -- 'Content' by wrapping a 'RuleT'.-    GetContent-        ::HasContent input-        => RuleT (Content input) error context output-        -> RuleF input           error context output--    -- | Fetch a property from items with metadata.-    GetProperty-        ::HasMetadata input-        => (Bool -> a)-        -> Key-        -> RuleF input error context a--    -- | Fetch an /optional/ setting from items with metadata.-    GetSetting-        ::HasMetadata input-        => (Maybe x -> output)-        -> Key-        -> (Text -> Either String x)-        -> RuleF input error context output--    -- | Fetch a /required/ setting from items with metadata.-    GetRequiredSetting-        ::HasMetadata input-        => Key-        -> (Text -> Either String output)-        -> RuleF input error context output--    -- | Get the raw text from a 'Text' node.-    GetSelf-        ::(input -> output)-        -> RuleF input error context output--instance Functor context => Functor (RuleF input error context) where-    fmap fn = \case-        Fail      e            -> Fail e-        Lift      lift         -> Lift $ fmap (fmap fn) . lift-        TestMatch matches      -> TestMatch $ fmap (fmap fn) matches-        Traverse f g rule      -> Traverse f (fn . g) rule-        GetContent rule        -> GetContent $ fmap fn rule-        GetProperty k key      -> GetProperty (fn . k) key-        GetSetting k key parse -> GetSetting (fn . k) key parse-        GetRequiredSetting key parse ->-            GetRequiredSetting key (fmap fn . parse)-        GetSelf k -> GetSelf (fn . k)------------------------------------------------------------------------------------ | A (lawless) typeclass for enabling fallible matching on nodes.------ Implementing new instances of this class in library code is *unneccessary*--- and *unsupported*.-class (forall i e. Functor (Pattern t i e), HasLocation t) => CanMatch t where-    -- | A data type representing allowable fallible patterns for @t@.-    data family Pattern t :: * -> (* -> *) -> * -> *--    -- | Information about why a @Pattern@ failed to match.-    data family NoMatch t :: *--    -- | Attempt to match a pattern against a value.-    evalPattern ::-           Applicative g-        => Pattern t error context output-           -- ^ The @Pattern@ to match against-        -> Interpret error context g-           -- ^ An interpreter for evaluating the match.-        -> t-           -- ^ The value to attempt to match against-        -> Either (NoMatch t) (g output)--    -- | Lift a @NoMatch@ error into the 'Error' type.-    noMatchError :: NoMatch t -> Error e--instance CanMatch Prosidy.Block where-    data Pattern Prosidy.Block error context output =-        BlockTagP  Key (RuleT BlockRegion                       error context output)-      | LitTagP    Key (RuleT LiteralRegion                     error context output)-      | ParagraphP     (RuleT (Prosidy.SeriesNE Prosidy.Inline) error context output)-      deriving Functor-    -    data NoMatch Prosidy.Block =-        NoMatchBlockTag  Key-      | NoMatchLitTag    Key-      | NoMatchParagraph--    evalPattern (BlockTagP key rule) = evalPatternWith-        (Prosidy._BlockTag . Prosidy.tagged key)-        (NoMatchBlockTag key)-        rule-    evalPattern (LitTagP key rule) = evalPatternWith-        (Prosidy._BlockLiteral . Prosidy.tagged key)-        (NoMatchLitTag key)-        rule-    evalPattern (ParagraphP rule) = evalPatternWith-        (Prosidy._BlockParagraph . Prosidy.content)-        NoMatchParagraph-        rule--    noMatchError (NoMatchBlockTag key) = ExpectedTag BlockKind key-    noMatchError (NoMatchLitTag   key) = ExpectedTag LiteralKind key-    noMatchError NoMatchParagraph      = ExpectedParagraph--instance CanMatch Prosidy.Inline where-    data Pattern Prosidy.Inline error context output =-        InlineTagP Key (RuleT InlineRegion error context output)-      | BreakP         (RuleT ()           error context output)-      | TextP          (RuleT Text         error context output)-      deriving Functor-    -    data NoMatch Prosidy.Inline =-        NoMatchInlineTag Key-      | NoMatchBreak-      | NoMatchText--    evalPattern (InlineTagP key rule) = evalPatternWith-        (Prosidy._InlineTag . Prosidy.tagged key)-        (NoMatchInlineTag key)-        rule-    evalPattern (TextP rule) =-        evalPatternWith (Prosidy._Text . Prosidy.fragment) NoMatchText rule-    evalPattern (BreakP rule) =-        evalPatternWith Prosidy._Break NoMatchBreak rule--    noMatchError (NoMatchInlineTag key) = ExpectedTag InlineKind key-    noMatchError NoMatchText            = ExpectedText-    noMatchError NoMatchBreak           = ExpectedBreak---- | Match one or more patterns, in sequence, against a value. The result from--- the first successful pattern will be returned. Subsequent matches will not--- be tried.-evalPatterns-    :: (CanMatch i, IsError e, ApErrors e g)-    => NonEmpty (Pattern i e f o)-    -> Interpret e f g-    -> i-    -> g o-evalPatterns (x :| xs) interpret input = either liftError id folded-  where-    folded = foldr (\pat acc -> doEval pat `orElse` acc) (doEval x) xs-    doEval pat =-        first (singleError . noMatchError) $ evalPattern pat interpret input-    orElse lhs@Right{} _          = lhs-    orElse (Left lhs)  (Left rhs) = Left $ lhs <> rhs-    orElse _           rhs        = rhs--evalPatternWith-    :: Applicative g-    => Traversal' i j-    -> e-    -> RuleT j e' f o-    -> Interpret e' f g-    -> i-    -> Either e (g o)-evalPatternWith sel error rule interpret input =-    second (interpretWith rule interpret)-        .  maybe (Left error) Right-        $  input-        ^? sel------------------------------------------------------------------------------------ | Build an interpreter into a functor @g@.-interpretWith :: Applicative g => RuleT i e f a -> Interpret e f g -> i -> g a-interpretWith (RuleT ap) int i = Ap.runAp (int i) ap------------------------------------------------------------------------------------ | Runs a single 'RuleF' into an applicative @g@. Passing this value to--- 'interpretWith' will fully evaluate a 'RuleT' into the same functor.-type Interpret e f g = forall i a . i -> RuleF i e f a -> g a------------------------------------------------------------------------------------ | A 'Prosidy.Types.BlockTag' with the tag name removed.-type BlockRegion = Prosidy.Region (Prosidy.Series Prosidy.Block)---- | An 'Prosidy.Types.InlineTag' with the tag name removed.-type InlineRegion = Prosidy.Region (Prosidy.Series Prosidy.Inline)+module Prosidy.Compile.Core (module X) where --- | A 'Prosidy.Types.LiteralTag' with the tag name removed.-type LiteralRegion = Prosidy.Region Text+import           Prosidy.Compile.Core.Interpret+                                               as X+import           Prosidy.Compile.Core.Rules    as X
+ src/Prosidy/Compile/Core/Interpret.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-|+Module      : Prosidy.Compile.Core.Interpret+Description : Internal module declaring the 'Context' and 'Interpret' classes. +Copyright   : ©2020 James Alexander Feldman-Crough+License     : MPL-2.0+Maintainer  : alex@fldcr.com+-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE TypeFamilies #-}+module Prosidy.Compile.Core.Interpret+    ( Context(..)+    , Interpret(..)+    , interpret+    )+where++import           Control.Applicative            ( Alternative )+import           Prosidy.Compile.Core.Rules     ( RuleFor+                                                , Rules+                                                , Rule(..)+                                                , runRules+                                                )+import           Data.Void.HKT                  ( Void+                                                , absurd+                                                )++-- | A base class for interpreters of 'Rules'.+class (forall i. Alternative (t i)) => Context t where+    -- | Access the current focus of an interpreter. This function is similar+    -- in purpose to 'Control.Monad.Trans.Reader.ask'.+    runSelf :: t i i++    -- | A type for expressions that can be lifted by the interpreter.+    --+    -- This type defaults to an uninhabited type. Only override this type+    -- if you intend on overriding 'liftRule', as well.+    type Local t :: * -> *++    -- | Lift an expression of type 'Local' into the interpreter. +    --+    -- By default, 'Local' is left as an uninhabted type and escaping via+    -- 'liftRule' can never happen. Override both 'Local' and 'liftRule' to+    -- permit arbitrary computation.+    liftRule :: Local t a -> t i a++    type Local t = Void t+    default liftRule :: Local t a ~ Void t a => Local t a -> t i a+    liftRule = absurd++-- | Instructs a 'Context' how to interpret a single rule.+class Context t => Interpret t i where+    -- | Evaluate a single rule into the context.+    runRule :: RuleFor i (Local t) a -> t i a++    default runRule :: (RuleFor i ~ Void i) => RuleFor i (Local t) a -> t i a+    runRule = absurd++-- | Evaluate 'Rules' into a contextual interpreter.+interpret :: forall t i a. Interpret t i => Rules i (Local t) a -> t i a+interpret = runRules $ \x -> case x of+    RuleFor r -> runRule r+    Escape  f -> liftRule f+    Self    s -> s <$> runSelf
+ src/Prosidy/Compile/Core/Rules.hs view
@@ -0,0 +1,291 @@+{-|+Module      : Prosidy.Compile.Core.Rules+Description : Internal module declaring 'Rules' types and functions.+Copyright   : ©2020 James Alexander Feldman-Crough+License     : MPL-2.0+Maintainer  : alex@fldcr.com+-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE EmptyCase #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE StrictData #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE UndecidableInstances #-}+module Prosidy.Compile.Core.Rules+    ( Rules+    , Rule(..)+    , rule+    , local+    , self+    , runRules+    , mapRules+    , hoist++    , HoistRuleFor++    -- * Context-aware ADT rules.+    , RuleFor+    , BlockRule(..)+    , DocumentRule(..)+    , FragmentRule(..)+    , InlineRule(..)+    , MetadataRule(..)+    , ParagraphRule(..)+    , RegionRule(..)+    , SeriesNERule(..)+    , SeriesRule(..)+    , TagRule(..)++    -- * Reëxports+    , Alternative(..)+    )+where++import           Prosidy.Types+import           Prosidy.Source                 ( Location )+import           Data.Void.HKT                  ( Void )+import           Data.Text                      ( Text )++import           Control.Applicative            ( Alternative(..) )+import qualified Control.Alternative.Free.Final+                                               as Alt++-------------------------------------------------------------------------------+-- | A container for building up compilation rules.+--+-- * The type parameter @t@ specifies the /input type/ of these rules. It will+-- almost always be a Prosidy node type, such as 'Document' or 'Tag'.+--+-- * The type parameter @f@ is a contextual functor for implementing custom+-- extensions on top of 'Rules'.+newtype Rules t f a = Rules+  { _runRules :: Alt.Alt (Rule t f) a+  }+  deriving newtype (Functor, Applicative, Alternative, Semigroup, Monoid)++-- | Lift a single rule into the 'Rules' functor.+rule :: RuleFor t f a -> Rules t f a+rule = Rules . Alt.liftAlt . RuleFor++-- | Lift a contextual item into 'Rules'.+local :: Functor f => f a -> Rules t f a+local = Rules . Alt.liftAlt . Escape++-- | Get the currently focused node as a value.+self :: Rules t f t+self = Rules . Alt.liftAlt $ Self id++-- | Given an interpreter which can convert 'Rule's into the functor @g@,+-- convert 'Rules' into the functor @g@.+runRules+    :: Alternative g => (forall b . Rule t f b -> g b) -> Rules t f a -> g a+runRules interpret = Alt.runAlt interpret . _runRules++-- | Map over the contextual functor @f@ in 'Rules'.+hoist :: HoistRuleFor t => (forall b. f b -> g b) -> Rules t f a -> Rules t g a+hoist fToG = Rules . Alt.hoistAlt (hoistRule fToG) . _runRules++-- | Map over 'Rules'.+mapRules+    :: forall a a' t t' f+     . (Functor f, Functor (RuleFor t' f))+    => (forall x . RuleFor t f x -> RuleFor t' f x)+      -- ^ Maps over rules themselves, keeping the context and output types the+      -- same.+    -> (t' -> t)+      -- ^ Maps over the input to rules.+    -> (a -> a')+      -- ^ Maps over the output of rules.+    -> Rules t f a+    -> Rules t' f a'+mapRules f g h (Rules alt) = Rules $ h <$> Alt.hoistAlt (mapRule f g id) alt++-------------------------------------------------------------------------------+-- | An individual 'Rule' in isolation.+data Rule t f a =+    RuleFor (RuleFor t f a)   -- ^ A rule specific to the input type @t@+  | Escape  (f a) -- ^ An escape hatch, allowing arbitrary computation+  | Self    (t -> a)          -- ^ A rule which converts the input type to an output.++instance (Functor f, Functor (RuleFor t f)) => Functor (Rule t f) where+    fmap fn x = case x of+        RuleFor rule -> RuleFor $ fn <$> rule+        Escape  rule -> Escape $ fn <$> rule+        Self    self -> Self $ fn <$> self++hoistRule :: HoistRuleFor t => (forall b. f b -> g b) -> Rule t f a -> Rule t g a+hoistRule f (RuleFor rf) = RuleFor (hoistRuleFor f rf)+hoistRule f (Escape fa)  = Escape (f fa)+hoistRule _ (Self fn)    = Self fn++mapRule+    :: (Functor f, Functor (RuleFor t' f))+    => (forall x . RuleFor t f x -> RuleFor t' f x)+    -> (t' -> t)+    -> (a -> a')+    -> Rule t f a+    -> Rule t' f a'+mapRule f _ h (RuleFor r   ) = RuleFor . fmap h . f $ r+mapRule _ _ h (Escape  es  ) = Escape $ h <$> es+mapRule _ g h (Self    self) = Self $ h . self . g++-------------------------------------------------------------------------------+-- | Defines a relationship between input types and rules specific to those+-- input types.+type family RuleFor t = (rule :: (* -> *) -> * -> *) | rule -> t where+  RuleFor Block        = BlockRule+  RuleFor Document     = DocumentRule+  RuleFor Fragment     = FragmentRule+  RuleFor Inline       = InlineRule+  RuleFor Metadata     = MetadataRule+  RuleFor Paragraph    = ParagraphRule+  RuleFor (Region   a) = RegionRule   a+  RuleFor (Series   a) = SeriesRule   a+  RuleFor (SeriesNE a) = SeriesNERule a+  RuleFor (Tag      a) = TagRule      a+  RuleFor           a  = Void         a++-- | A class defining how to map over the contextual parameter @f@ in a rule for+-- the type @t@.+class HoistRuleFor t where+    hoistRuleFor :: (forall b. f b -> g b) -> RuleFor t f a -> RuleFor t g a++-------------------------------------------------------------------------------+-- | Rules for matching specific types of 'Block' nodes.+data BlockRule f a =+    BlockRuleBlockTag   (Rules BlockTag   f a)+  | BlockRuleLiteralTag (Rules LiteralTag f a)+  | BlockRuleParagraph  (Rules Paragraph  f a)+  deriving stock Functor++instance HoistRuleFor Block where+    hoistRuleFor f = \case+        BlockRuleBlockTag rules -> BlockRuleBlockTag $ hoist f rules+        BlockRuleLiteralTag rules -> BlockRuleLiteralTag $ hoist f rules+        BlockRuleParagraph rules -> BlockRuleParagraph $ hoist f rules++-------------------------------------------------------------------------------+-- | Rules applying to 'Document's.+newtype DocumentRule f a =+    DocumentRule (RegionRule (Series Block) f a)+  deriving newtype Functor++instance HoistRuleFor Document where+    hoistRuleFor f = \case +        DocumentRule r -> DocumentRule $ hoistRuleFor f r++-------------------------------------------------------------------------------+-- | Rules applying to 'Fragment's (i.e. plain text).+data FragmentRule f a =+    FragmentRuleLocation (Maybe Location -> a)+  | FragmentRuleText     (Text           -> a)+  deriving stock Functor++instance HoistRuleFor Fragment where+    hoistRuleFor _ = \case+        FragmentRuleLocation fn -> FragmentRuleLocation fn+        FragmentRuleText fn -> FragmentRuleText fn++-------------------------------------------------------------------------------+-- | Rules for matching specific types of 'Inline' nodes.+data InlineRule f a =+    InlineRuleBreak     a+  | InlineRuleFragment  (Rules Fragment  f a)+  | InlineRuleInlineTag (Rules InlineTag f a)+  deriving stock Functor++instance HoistRuleFor Inline where+    hoistRuleFor f = \case+        InlineRuleBreak a -> InlineRuleBreak a+        InlineRuleFragment rules -> InlineRuleFragment $ hoist f rules+        InlineRuleInlineTag rules -> InlineRuleInlineTag $ hoist f rules++-------------------------------------------------------------------------------+-- | Rules for operating on properties and settings.+data MetadataRule f a =+    MetadataRuleProperty (Bool -> a) Key+  | MetadataRuleSetting  (Text -> Either String a) (Maybe a) Key+  | MetadataRuleAllowUnknown a+  deriving stock Functor++instance HoistRuleFor Metadata where+    hoistRuleFor _ = \case+        MetadataRuleProperty fn key -> MetadataRuleProperty fn key+        MetadataRuleSetting fn def key -> MetadataRuleSetting fn def key+        MetadataRuleAllowUnknown a -> MetadataRuleAllowUnknown a++-------------------------------------------------------------------------------+-- | Rules for accessing paragraphs.+data ParagraphRule f a =+    ParagraphRuleContent  (Rules (SeriesNE Inline) f a)+  | ParagraphRuleLocation (Maybe Location -> a)+  deriving stock Functor++instance HoistRuleFor Paragraph where+    hoistRuleFor f = \case+        ParagraphRuleContent rules -> ParagraphRuleContent $ hoist f rules+        ParagraphRuleLocation fn -> ParagraphRuleLocation fn++-------------------------------------------------------------------------------+-- | Rules for operating on a 'Region'.+data RegionRule t f a =+    RegionRuleLocation (Maybe Location -> a)+  | RegionRuleMetadata (MetadataRule f a)+  | RegionRuleContent  (Rules t f a)+  deriving stock Functor++instance HoistRuleFor t => HoistRuleFor (Region t) where+    hoistRuleFor f = \case+        RegionRuleLocation fn   -> RegionRuleLocation fn+        RegionRuleMetadata rule -> RegionRuleMetadata $ hoistRuleFor f rule+        RegionRuleContent rules -> RegionRuleContent $ hoist f rules++-------------------------------------------------------------------------------+-- | Operates sequentially against a collection of nodes.+data SeriesRule t f a =+    SeriesRuleNext (SeriesNERule t f a)+  | SeriesRuleEmpty a++instance Functor (SeriesRule t f) where+    fmap fn (SeriesRuleNext  rule) = SeriesRuleNext (fmap fn rule)+    fmap fn (SeriesRuleEmpty x   ) = SeriesRuleEmpty (fn x)++instance HoistRuleFor t => HoistRuleFor (Series t) where+    hoistRuleFor f = \case+        SeriesRuleNext rule -> SeriesRuleNext $ hoistRuleFor f rule+        SeriesRuleEmpty a -> SeriesRuleEmpty a++-------------------------------------------------------------------------------+-- | Operates sequentially against a non-empty collection of nodes.+data SeriesNERule t f a =+    forall b c. SeriesNERule (b -> c -> a) (Rules t f b) (Rules (Series t) f c)++instance Functor (SeriesNERule t f) where+    fmap fn (SeriesNERule k rule next) = SeriesNERule (fmap fn . k) rule next++instance HoistRuleFor t => HoistRuleFor (SeriesNE t) where+    hoistRuleFor f = \case+        SeriesNERule k r1 rs -> SeriesNERule k (hoist f r1) (hoist f rs)++-------------------------------------------------------------------------------+-- | Rules for operating on 'Tag's.+data TagRule t f a =+    TagRuleKey Key a+  | TagRuleRegion (RegionRule t f a)+  deriving stock Functor++instance HoistRuleFor t => HoistRuleFor (Tag t) where+    hoistRuleFor f = \case+        TagRuleKey k a -> TagRuleKey k a+        TagRuleRegion rule -> TagRuleRegion $ hoistRuleFor f rule++-------------------------------------------------------------------------------+instance HoistRuleFor Text where+    hoistRuleFor _ = \case
+ src/Prosidy/Compile/DSL.hs view
@@ -0,0 +1,271 @@+{-|+Module      : Prosidy.Compile.DSL+Description : An EDSL for declaring 'Prosidy.Compile.Core.Rules'.+Copyright   : ©2020 James Alexander Feldman-Crough+License     : MPL-2.0+Maintainer  : alex@fldcr.com+-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE PatternSynonyms #-}+module Prosidy.Compile.DSL+    ( content+      -- * Series rules+    , (&>)+    , (&>>)+    , folded+    , folded1+    , collect+    , end+    , endWith+      -- * Metadata rules+    , prop+    , req+    , opt+    , lax+      -- * Matchers+    , Match+    , match+    , blockTag+    , inlineTag+    , literalTag+    , paragraph+    , text+    , breakWith+      -- * Get wild with actions+    , local+    , self+    , hoist+      -- * Convenience classes+    , FromSetting(..)+    , RegionLike+    )+where++import qualified Prosidy+import           Prosidy.Types.Series           ( pattern Empty+                                                , pattern (:<:)+                                                , pattern (:<<:)+                                                )+import           Prosidy.Compile.Core+import           Data.Monoid                    ( Alt(..) )+import           Text.Read                      ( readMaybe )+import           Type.Reflection                ( Typeable+                                                , typeRep+                                                )+import           Data.Text                      ( Text )+import qualified Data.Text                     as Text+import qualified Data.Text.Lazy                as Text.Lazy+import           Numeric.Natural                ( Natural )++infixr 3 &>+infixr 1 &>>++-------------------------------------------------------------------------------+-- | Access the inner content of the 'RegionLike' value @t@. +content :: RegionLike t => Rules (Prosidy.Content t) f a -> Rules t f a+content = rule . liftRegionRule . RegionRuleContent++-------------------------------------------------------------------------------+-- | Given a 'Prosidy.Series', perform the rule on the left hand side on the+-- first element of the 'Prosidy.Series', and the rule on the right hand side+-- on all items after the first.+--+-- This can be used to define rules which must be evaluated sequentially.+(&>)+    :: Rules t f a+    -> Rules (Prosidy.Series t) f (Prosidy.Series a)+    -> Rules (Prosidy.Series t) f (Prosidy.Series a)+r &> rs = rule . SeriesRuleNext $ SeriesNERule (:<:) r rs++-- | Like '(&>)', but returns a combined rule which operates on a non-empty+-- series ('Prosidy.SeriesNE').+(&>>)+    :: Rules t f a+    -> Rules (Prosidy.Series t) f (Prosidy.Series a)+    -> Rules (Prosidy.SeriesNE t) f (Prosidy.SeriesNE a)+r &>> rs = rule $ SeriesNERule (:<<:) r rs++-- | Match the end of a 'Prosidy.Series'.+end :: Rules (Prosidy.Series t) f (Prosidy.Series a)+end = endWith Empty++-- | Match the end of a 'Prosidy.Series', returning the provided value.+endWith :: a -> Rules (Prosidy.Series t) f a+endWith = rule . SeriesRuleEmpty++-- | Lift a rule to collect many of that rule in series+collect :: Rules t f a -> Rules (Prosidy.Series t) f (Prosidy.Series a)+collect rules = go+  where+    go = (rules &> go) <|> end++-- | Lift a rule to operate on a 'Prosidy.Series' by folding the results of+-- evaluation against each element into a single result.+folded :: Monoid a => Rules t f a -> Rules (Prosidy.Series t) f a+folded r = go+  where+    go = rule (SeriesRuleNext $ SeriesNERule (<>) r go)+        <|> rule (SeriesRuleEmpty mempty)++-- | Like 'folded', but operates on a non-empty series.    +folded1 :: Monoid a => Rules t f a -> Rules (Prosidy.SeriesNE t) f a+folded1 r = rule $ SeriesNERule (<>) r (folded r)++-------------------------------------------------------------------------------+-- | A class for recursive nodes in a document.+class Prosidy.HasContent t => RegionLike t where+    liftRegionRule :: RegionRule (Prosidy.Content t) f a -> RuleFor t f a++instance RegionLike Prosidy.Document where+    liftRegionRule = DocumentRule++instance RegionLike (Prosidy.Tag t) where+    liftRegionRule = TagRuleRegion++instance RegionLike (Prosidy.Region t) where+    liftRegionRule = id++-- | Check if a 'Prosidy.Metadata' property is set on a node.+prop :: RegionLike t => Prosidy.Key -> Rules t f Bool+prop = rule . liftRegionRule . RegionRuleMetadata . MetadataRuleProperty id++-- | Fetch a /required/ 'Prosidy.Metadata' value from a node, parsing it using+-- the provided function.+reqWith+    :: forall a t f. RegionLike t => (Text -> Either String a) -> Prosidy.Key -> Rules t f a+reqWith parse =+    rule+        . liftRegionRule+        . RegionRuleMetadata+        . MetadataRuleSetting parse Nothing++-- | Fetch a /required/ 'Prosidy.Metadata' setting from a node.+req :: forall a t f. (RegionLike t, FromSetting a) => Prosidy.Key -> Rules t f a+req = reqWith parseSetting++-- | Fetch an /optional/ 'Prosidy.Metadata' value from a node, parsing it using+-- the provided function.+optWith+    :: forall a t f. RegionLike t+    => (Text -> Either String a)+    -> Prosidy.Key+    -> Rules t f (Maybe a)+optWith parse =+    rule . liftRegionRule . RegionRuleMetadata . MetadataRuleSetting+        (fmap Just . parse)+        (Just Nothing)++-- | Fetch an /optional/ 'Prosidy.Metadata' setting from a node.+opt :: forall a t f. (RegionLike t, FromSetting a) => Prosidy.Key -> Rules t f (Maybe a)+opt = optWith parseSetting++-- | Allow unknown properties and settings in this region.+lax :: RegionLike t => Rules t f ()+lax = rule . liftRegionRule . RegionRuleMetadata $ MetadataRuleAllowUnknown ()++-------------------------------------------------------------------------------+-- | A class for values which can be parsed from 'Text'.+class FromSetting a where+    parseSetting :: Text -> Either String a++    default parseSetting :: (Typeable a, Read a) => Text -> Either String a+    parseSetting raw = case readMaybe (Text.unpack raw) of+        Just ok -> Right ok+        Nothing -> Left $ "Failed to parse " <> show raw <> " as type " <> show (typeRep @a)++instance FromSetting Double+instance FromSetting Float+instance FromSetting Int+instance FromSetting Integer+instance FromSetting Natural+instance FromSetting Word++instance FromSetting String where+    parseSetting = Right . Text.unpack++instance FromSetting Text where+    parseSetting = Right+    {-# INLINE parseSetting #-}++instance FromSetting Text.Lazy.Text where+    parseSetting = Right . Text.Lazy.fromStrict+    {-# INLINE parseSetting #-}++-------------------------------------------------------------------------------+-- | A type used to declare alternatives in @do@ notation.+type Match t f a = MatchM t f a ()++data MatchM t f a r = MatchM !(Alt (Rules t f) a) !r++instance Semigroup r => Semigroup (MatchM t a f r) where+    MatchM r a <> MatchM s b = MatchM (r <> s) (a <> b)++instance Monoid r => Monoid (MatchM t a f r) where+    mempty = MatchM mempty mempty++instance Functor (MatchM t f a) where+    fmap fn (MatchM r x) = MatchM r (fn x)++instance Applicative (MatchM t f a) where+    pure = MatchM mempty+    MatchM lhs fn <*> MatchM rhs x = MatchM (lhs <> rhs) (fn x)++instance Monad (MatchM t f a) where+    MatchM lhs x >>= f = let MatchM rhs x' = f x in MatchM (lhs <> rhs) x'++-- | Lifts a 'Match' into 'Rules' by trying each defined pattern, from top to+-- bottom, until a match is found.+match :: Match t f a -> Rules t f a+match (MatchM (Alt r) ()) = r++-- | Match a 'Prosidy.BlockTag' with the proided 'Prosidy.Key'.+blockTag+    :: Functor f+    => Prosidy.Key+    -> Rules Prosidy.BlockRegion f a+    -> Match Prosidy.Block f a+blockTag key = matchRule . BlockRuleBlockTag . tagRule key++-- | Match a 'Prosidy.LiteralTag' with the provided 'Prosidy.Key'.+literalTag+    :: Functor f+    => Prosidy.Key+    -> Rules Prosidy.LiteralRegion f a+    -> Match Prosidy.Block f a+literalTag key = matchRule . BlockRuleLiteralTag . tagRule key++-- | Match a 'Prosidy.InlineTag' with the provided 'Prosidy.Key'.+inlineTag+    :: Functor f+    => Prosidy.Key+    -> Rules Prosidy.InlineRegion f a+    -> Match Prosidy.Inline f a+inlineTag key = matchRule . InlineRuleInlineTag . tagRule key++-- | Match a paragraph which is not enclosed in a tag.+paragraph+    :: Rules (Prosidy.SeriesNE Prosidy.Inline) f a -> Match Prosidy.Block f a+paragraph = matchRule . BlockRuleParagraph . rule . ParagraphRuleContent++-- | Match textual content, transforming it with the provided function.+text :: (Text -> a) -> Match Prosidy.Inline f a+text = matchRule . InlineRuleFragment . rule . FragmentRuleText++-- | Replace inline breaks with the provided vlaue.+breakWith :: a -> Match Prosidy.Inline f a+breakWith = matchRule . InlineRuleBreak++matchRule :: RuleFor t f a -> Match t f a+matchRule = flip MatchM () . Alt . rule++tagRule+    :: Functor f+    => Prosidy.Key+    -> Rules (Prosidy.Region t) f a+    -> Rules (Prosidy.Tag t) f a+tagRule key r =+    rule (TagRuleKey key ()) *> mapRules liftRegionRule Prosidy.tagToRegion id r
− src/Prosidy/Compile/Error.hs
@@ -1,220 +0,0 @@-{-|-Module      : Prosidy.Compile.Error-Description : Error definitions and utility functions.-Copyright   : ©2020 James Alexander Feldman-Crough-License     : MPL-2.0-Maintainer  : alex@fldcr.com--}-{-# LANGUAGE DerivingVia #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE GeneralisedNewtypeDeriving #-}-{-# LANGUAGE FlexibleInstances #-}-module Prosidy.Compile.Error-    ( Error(..)-    , TagKind(..)-    , MetadataKind(..)-    , ErrorSet-    , Error'-    , ErrorSet'-    , IsError-    , ApError(..)-    , ApErrors-    , singleError-    , customError-    , liftError1-    , allErrors-    , groupErrors-    )-where--import           Lens.Micro--import           Control.Exception              ( Exception(..) )-import           Prosidy.Types.Key              ( Key )-import           Prosidy.Source                 ( Line(..)-                                                , Column(..)-                                                , Location-                                                )-import           Prosidy.Optics.Source          ( HasLocation(..)-                                                , line-                                                , column-                                                )-import           Data.HashSet                   ( HashSet-                                                , singleton-                                                )-import           GHC.Generics                   ( Generic )-import           Data.Hashable                  ( Hashable )-import           Data.Typeable                  ( Typeable )-import           Data.Void                      ( Void )-import           Data.Foldable                  ( toList )-import           Data.List.NonEmpty             ( NonEmpty(..)-                                                , nonEmpty-                                                )---- | Similar to 'Control.Monad.Except.MonadError', but without the 'Monad'--- constraint, and without a method to handle errors, only a method to map over--- them.-class Applicative f => ApError e f | f -> e where-    liftError :: e -> f a-    mapError  :: (e -> e) -> f a -> f a---- | A synonym for 'ApError' when the underlying applicative is capable of--- accumulating errors in an 'ErrorSet'.-type ApErrors e = ApError (ErrorSet e)---- | A constraint alias for errors throwable in a context admitting a--- 'ApErrors' instance.-type IsError e = (Exception e, Hashable e, Eq e)---- | A non-empty set of errors.-newtype ErrorSet e =-    ErrorSet (HashSet (Error e))-  deriving stock (Show, Generic, Eq)-  deriving anyclass (Hashable)--instance Exception e => Exception (ErrorSet e) where-    displayException (ErrorSet errors) = mconcat-        [ showString "encountered " <> shows (length errors) <> showString-            " error(s):\n"-        , showString "-----\n"-        , foldMap (\x -> showString (displayException x) . showChar '\n') errors-        ]-        ""--instance IsError e => Semigroup (ErrorSet e) where-    ErrorSet lhs <> ErrorSet rhs = ErrorSet $! lhs <> rhs---- | A type alias for 'ErrorSet's which never contain empty errors.-type ErrorSet' = ErrorSet Void---- | Enumerates the errors thrown when-data Error a =-    Custom a-    -- ^ A custom error, allowing extensibility.-  | ParseError Key String-    -- ^ Thrown when parsing a setting fails.-  | Required Key-    -- ^ Thrown when a setting was required to be set, but wasn't provided.-  | ExpectedTag TagKind Key-    -- ^ Thrown when matching against a 'Prosidy.Tag', and another node was-    -- found, or the input tag's 'Key' didn't match the specified key.-  | ExpectedParagraph-    -- ^ Thrown when matching against paragraph and an unexpected node was-    -- encountered.-  | ExpectedText-    -- ^ Thrown when matching against text and an unexpected node was-    -- encountered.-  | ExpectedBreak-    -- ^ Thrown when matching against an explicit break and an unexpected node-    -- was encountered.-  | EmptyMatch-    -- ^ Thrown when a match has no cases to check against.-  | UnknownMetadata (HashSet (MetadataKind, Key))-    -- ^ Thrown when an unknown property or setting is encountered when-    -- checking that properties and settings conform to strictly known-    -- keys.-  | Group (Maybe Location) (ErrorSet a)-    -- ^ Used to group a set of errors thrown at the same point in a tree.-  deriving (Eq, Show, Generic, Hashable)--instance (Typeable a, Exception a) => Exception (Error a) where-    displayException (Custom a        ) = displayException a--    displayException (ParseError k msg) = mconcat-        [ showString "failed to parse the setting "-        , shows k-        , showString ": "-        , showString msg-        ]-        ""--    displayException EmptyMatch   = "Match provided with no possible cases."--    displayException (Required k) = "missing required setting " <> show k--    displayException (ExpectedTag kind k) =-        "expected a " <> kindstr kind <> " tag with key " <> show k-      where-        kindstr BlockKind   = "block"-        kindstr InlineKind  = "inline"-        kindstr LiteralKind = "literal"--    displayException ExpectedParagraph = "expected a paragrapgh"--    displayException ExpectedText      = "expected plain text"--    displayException ExpectedBreak     = "expected a break"--    displayException (UnknownMetadata xs) =-        showString "One or more invalid metadata items were encountered:"-            <> foldMap showItem xs-            $  ""-      where-        showItem (PropertyKind, key) =-            showChar ' ' <> shows key <> showString " (property)"-        showItem (SettingKind, key) =-            showChar ' ' <> shows key <> showString " (setting)"--    displayException (Group (Just loc) x) = mconcat-        [ showString "error(s) encountered at line "-        , shows (loc ^?! line . to (\(Line n) -> succ n))-        , showString " column "-        , shows (loc ^?! column . to (\(Column n) -> succ n))-        , showString ":\n"-        , foldMap-            (\exn -> showString (displayException exn) <> showChar '\n')-            (allErrors x)-        ]-        ""--    displayException (Group Nothing x) = foldMap-        (\exn -> showString (displayException exn) <> showChar '\n')-        (allErrors x)-        ""---- | A type alias for 'Error's that never throw a custom error.-type Error' = Error Void---- | A marker class for marking which type of tag 'ExpectedTag' was expecting.-data TagKind = BlockKind | InlineKind | LiteralKind-  deriving (Show, Eq, Generic, Hashable)---- | A marker class for marking which type of metadata (settings or property)--- a key corresponds to.-data MetadataKind = PropertyKind | SettingKind-  deriving (Show, Eq, Generic, Hashable)---- | Group errors together, attaching a location if one is available.-groupErrors :: (IsError e, ApErrors e m, HasLocation l) => l -> m a -> m a-groupErrors item = mapError $ \es -> case allErrors es of-    Group Nothing  es' :| [] -> singleError $ Group (item ^? location) es'-    Group (Just _) _   :| [] -> es-    _                        -> singleError $ Group (item ^? location) es---- | Lift a single 'Error' into an 'ErrorSet'.-singleError :: Hashable e => Error e -> ErrorSet e-singleError = ErrorSet . singleton-{-# INLINE singleError #-}---- | Lift a custom error into an 'ErrorSet'.-customError :: Hashable e => e -> ErrorSet e-customError = singleError . Custom-{-# INLINE customError #-}---- | Throw a single error.-liftError1 :: (IsError e, ApErrors e m) => Error e -> m a-liftError1 = liftError . singleError-{-# INLINE liftError1 #-}---- | Return the set of errors in an 'ErrorSet' as a non-empty list.-allErrors :: ErrorSet e -> NonEmpty (Error e)-allErrors (ErrorSet hs) =-    maybe (error "unexpected empty ErrorSet") id . nonEmpty $ toList hs
− src/Prosidy/Compile/FromSetting.hs
@@ -1,82 +0,0 @@-{-|-Module      : Prosidy.Compile.FromSetting-Description : Typeclass for parsing values from Prosidy settings.-Copyright   : ©2020 James Alexander Feldman-Crough-License     : MPL-2.0-Maintainer  : alex@fldcr.com--}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE UndecidableInstances #-}-module Prosidy.Compile.FromSetting (FromSetting(..), Sep(..)) where--import           Data.Bifunctor                 ( first )-import           Data.Text                      ( Text )-import           Text.Read                      ( readEither )-import           Type.Reflection                ( Typeable-                                                , typeRep-                                                )-import           GHC.TypeLits                   ( KnownSymbol-                                                , Symbol-                                                , symbolVal'-                                                )-import           GHC.Exts                       ( Proxy#-                                                , proxy#-                                                )--import qualified Data.Text                     as Text-import qualified Data.Text.Lazy                as Text.Lazy---- | A typeclass for parsing Prosidy settings into typed values. A default--- instance exists for all types implementing 'Read'.-class FromSetting a where-    -- | Given a 'Text' value containing the setting, either parse a value-    -- or return an error message explaining why the value is malformed.-    fromSetting :: Text -> Either String a--instance FromSetting [Char] where-    fromSetting = Right . Text.unpack-    {-# INLINE fromSetting #-}--instance FromSetting Text where-    fromSetting = Right-    {-# INLINE fromSetting #-}--instance FromSetting Text.Lazy.Text where-    fromSetting = Right . Text.Lazy.fromStrict-    {-# INLINE fromSetting #-}--instance {-# OVERLAPPABLE #-} (Typeable a, Read a) => FromSetting a where-    fromSetting txt = first err . readEither . Text.unpack $ txt-      where-        err = mconcat-            [ showString "failed to parse the string "-            , shows txt-            , showString " as a value of type "-            , shows (typeRep @a)-            , showString ": "-            ]------------------------------------------------------------------------------------ | A newtype wrapper for reading in a delimited list of values. The @delim@--- parameter is a type-level string specifying the seperator between values.--- It must not be empty, or parsing will fail to terminate.--- --- Sep does not handle escaping or other fancy processing.-newtype Sep (delim :: Symbol) a = Sep { unsep :: [a] }-  deriving (Show, Eq, Semigroup, Monoid, Functor, Applicative, Monad, Foldable)--instance Traversable (Sep delim) where-    traverse f = fmap Sep . traverse f . unsep--instance (KnownSymbol delim, FromSetting a) => FromSetting (Sep delim a) where-    fromSetting =-        fmap Sep-            . traverse fromSetting-            . filter (not . Text.null)-            . Text.splitOn (Text.pack $ symbolVal' (proxy# :: Proxy# delim))
− src/Prosidy/Compile/Match.hs
@@ -1,123 +0,0 @@-{-|-Module      : Prosidy.Compile.Match-Description : Fallible pattern rules.-Copyright   : ©2020 James Alexander Feldman-Crough-License     : MPL-2.0-Maintainer  : alex@fldcr.com--}-{-# LANGUAGE DerivingVia #-}-module Prosidy.Compile.Match-    ( -- * DSL for matching cases-      Match-    , MatchM-    , match-    -- ** Specific matchers-    , break-    , breakWith-    , paragraph-    , text--    -- *** Tag matchers which strictly enforce metadata.-    , blockTag-    , inlineTag-    , literalTag--    -- *** Tag matchers which loosely enforce metadata.-    , blockTag'-    , inlineTag'-    , literalTag'-    )-where--import           Prelude                 hiding ( break )-import           Prosidy.Compile.Core-import           Prosidy.Compile.Error-import           Prosidy.Compile.Strict--import           Control.Monad.State            ( StateT(..)-                                                , State-                                                , modify'-                                                , execState-                                                )-import           Data.Monoid                    ( Endo(..) )-import           Data.Text                      ( Text )-import           Data.List.NonEmpty             ( NonEmpty(..) )--import qualified Prosidy                       as P---- | The type of fallible pattern specifications.-type Match i e f a = MatchM i e a f ()---- | A monadic interface for defining fallible patterns. In practice, @r@ will--- always be instantiated to @()@— 'Match' can be more clear.-newtype MatchM i e a f r = MatchM (State (Endo [Pattern i e f a]) r)-  deriving (Functor, Applicative, Monad)-    via State (Endo [Pattern i e f a])---- | Finalize a 'Match' into a rule. This is often used to offset a match--- block:------ @--- blocktags :: Match Block Void Identity String--- blocktags = match $ do---    ...--- @-match :: (Applicative f, CanMatch i) => Match i e f a -> RuleT i e f a-match (MatchM s) = case appEndo (execState s mempty) [] of-    x : xs -> rule . TestMatch $ x :| xs-    []     -> rule $ Fail EmptyMatch---- | Match against a 'Prosidy.Typs.Break'.-break :: RuleT () e f a -> Match P.Inline e f a-break = put . BreakP---- | Replace all 'Prosidy.Types.Break's with the provided value.-breakWith :: a -> Match P.Inline e f a-breakWith = put . BreakP . pure---- | Match 'Prosidy.Types.Paragraph's in a block context.-paragraph :: RuleT (P.SeriesNE P.Inline) e f a -> Match P.Block e f a-paragraph = put . ParagraphP---- | Match plain 'Text' in an inline context.-text :: RuleT Text e f a -> Match P.Inline e f a-text = put . TextP--put :: Pattern i e f a -> Match i e f a-put x = MatchM $ modify' (<> Endo (x :))------------------------------------------------------------------------------------- | Strict: match a 'Prosidy.Types.BlockTag' with the given 'P.Key'.-blockTag-    :: Applicative f => P.Key -> RuleT BlockRegion e f a -> Match P.Block e f a-blockTag key = put . BlockTagP key . strict---- | Strict: match an 'Prosidy.Types.InlineTag' with the given 'P.Key'.-inlineTag-    :: Applicative f-    => P.Key-    -> RuleT InlineRegion e f a-    -> Match P.Inline e f a-inlineTag key = put . InlineTagP key . strict---- | Strict: match an 'Prosidy.Types.LiteralTag' with the given 'P.Key'.-literalTag-    :: Applicative f-    => P.Key-    -> RuleT LiteralRegion e f a-    -> Match P.Block e f a-literalTag key = put . LitTagP key . strict------------------------------------------------------------------------------------ | Lax: match a 'Prosidy.Types.BlockTag' with the given 'P.Key'.-blockTag' :: P.Key -> RuleT BlockRegion e f a -> Match P.Block e f a-blockTag' key = put . BlockTagP key---- | Lax: match an 'Prosidy.Types.InlineTag' with the given 'P.Key'.-inlineTag' :: P.Key -> RuleT InlineRegion e f a -> Match P.Inline e f a-inlineTag' key = put . InlineTagP key---- | Lax: match an 'Prosidy.Types.LiteralTag' with the given 'P.Key'.-literalTag' :: P.Key -> RuleT LiteralRegion e f a -> Match P.Block e f a-literalTag' key = put . LitTagP key
src/Prosidy/Compile/Run.hs view
@@ -1,85 +1,441 @@ {-| Module      : Prosidy.Compile.Run-Description : Interpretation of compilation rules.-Copyright   : ©2020 James Alexander Feldman-Crough+Description : A basic intepreter for 'Prosidy.Compile.Core.Rules'.+Copyrighr   : ©2020 James Alexander Feldman-Crough License     : MPL-2.0 Maintainer  : alex@fldcr.com -}+{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ApplicativeDo #-}-{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-}-module Prosidy.Compile.Run (run, runM) where+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+module Prosidy.Compile.Run (RunError(..), RunErrors(..), RunT, Run, run, runT) where  import           Lens.Micro-import           Prosidy.Compile.Core-import           Prosidy.Compile.Error -import           Data.Bifunctor                 ( Bifunctor(..) )+import qualified Prosidy                       as P+import qualified Prosidy.Source                as PS+import           Prosidy.Types.Series           ( pattern Empty+                                                , pattern (:<:)+                                                , pattern (:<<:)+                                                )++import Control.Exception (Exception(..))+import           Prosidy.Compile.Core+import           Data.Function                  ( on ) import           Data.Functor.Identity          ( Identity(..) )+import           Data.Bifunctor                 ( Bifunctor(..) )+import           Data.Profunctor                ( Profunctor(..)+                                                , Strong(..)+                                                )+import Data.Either.Valid (Valid(..))+import qualified Data.Either.Valid as Valid+import           Data.Text                      ( Text )+import Control.Monad (unless)+import Data.Set (Set)+import Data.Foldable (toList, foldl')+import qualified Data.HashMap.Strict as HM+import Data.Semigroup (Semigroup(..)) -import qualified Prosidy                       as P+import Data.Text.Prettyprint.Doc (Pretty(..), (<+>))+import qualified Data.Text.Prettyprint.Doc as PP+import qualified Data.Text.Prettyprint.Doc.Render.String as PPS +import qualified Data.HashSet as HashSet+import qualified Data.Set                      as Set+import qualified Data.Text as Text++-- | 'RunT' specialized to 'Identity'.+type Run = RunT Identity++-- | An interpreter over 'Rules'.+newtype RunT f t a = RunT+  { _run :: t -> Observe -> Valid RunErrors (f a, Observe) }+--   deriving (Functor, Applicative) via Compose ((->) t) (Compose (Result RunError) _)++instance Functor f => Functor (RunT f t) where+    fmap = rmap++instance Applicative f => Applicative (RunT f t) where+    pure x = RunT $ \_ o -> pure (pure x, o)++    RunT lhs <*> RunT rhs = RunT $ \t obs ->+      let+        combine ~(f, o1) ~(x, o2) = (f <*> x, o1 <> o2)+      in+        combine <$> lhs t obs <*> rhs t obs++instance Applicative f => Alternative (RunT f t) where+    empty = RunT $ \_ _ -> empty++    RunT lhs <|> RunT rhs = RunT $ \t obs ->+        lhs t obs <|> rhs t obs ++instance Functor f => Profunctor (RunT f) where+    dimap f g = RunT . go . _run+      where+        go r t obs = first (fmap g) <$> r (f t) obs++instance Functor f => Strong (RunT f) where+    first' = RunT . go . _run+      where+        go r (t, c) obs = first (fmap (, c)) <$> r t obs+    second' = RunT . go . _run+      where+        go r (c, t) obs = first (fmap (c ,)) <$> r t obs++-- | Run a 'Run' interpreter to completion.+run :: i -> Run i a -> Either RunErrors a+run = (fmap runIdentity .) . runT++-- | Run a 'RunT' interpreter to completion.+runT :: i -> RunT f i a -> Either RunErrors (f a)+runT i = fmap fst . Valid.toEither . (\r -> _run r i mempty)++runWith :: (t -> Valid RunErrors (f a)) -> RunT f t a+runWith f = RunT $ \t obs -> (, obs) <$> f t++-- | Errors that may be returned from the interpreter.+data RunError =+    Group Location (Set RunError)+    -- ^ Groups a set of errors with a location for more helpful error +    -- messages.+  | MatchError Text+    -- ^ Expected a different type. Thrown on failed matches of sum types.+  | ParseError P.Key String+    -- ^ The provided parser failed to parse a setting.+  | RequiredSetting P.Key+    -- ^ A setting was required, but not found on a node.+  | TooFewElements+    -- ^ Expected more elements when matching sequentially.+  | TooManyElements+    -- ^ Expected fewer elements when matching sequentially.+  | UnexpectedProperties (HashSet.HashSet P.Key) (HashSet.HashSet P.Key)+    -- ^ A property was found on a node, but not mentioned in its specification.+  | UnexpectedSettings (HashSet.HashSet P.Key) (HashSet.HashSet P.Key)+    -- ^ A setting was found on a node, but not mentioned in its specification.+  deriving (Show, Eq, Ord)++instance Exception RunError where+    displayException = prettyString++instance Pretty RunError where+    pretty (Group loc errors) = PP.nest 4 $ PP.vsep+        [ "Encountered" <+> errorNoun <+> "in" <+> pretty loc+        , pretty (RunErrors errors)+        ] +      where+        errorCount = length errors+        errorNoun +          | errorCount == 1 = "an error"+          | otherwise       = pretty errorCount <+> "errors"++    pretty (MatchError desc) =+        "Expected" <+> pretty desc++    pretty (ParseError key msg) =+        "Failed to parse setting" <+> pretty key <> ":" <+> pretty msg++    pretty (RequiredSetting key) =+        "Node is missing the required setting" <+> pretty key++    pretty TooFewElements =+        "Expected one or more additional nodes within the current context."++    pretty TooManyElements =+        "Expected no further elements in the current context."++    pretty (UnexpectedProperties allowed got) = PP.nest 4 $ PP.vsep +        [ "Encountered at least one unexpected property on the current node."+        , "Allowed properties:   " <+> pretty (toList allowed)+        , "Unexpected properties:" <+> pretty (toList got)+        ]++    pretty (UnexpectedSettings allowed got) = PP.nest 4 $ PP.vsep +        [ "Encountered at least one unexpected setting on the current node."+        , "Allowed settings:   " <+> pretty (toList allowed)+        , "Unexpected settings:" <+> pretty (toList got)+        ]++-- | A newtype wrapper over a set of 'RunError's. +--+-- This is defined to allow an instances of 'Exception' and 'Pretty' for error+-- sets.+newtype RunErrors = RunErrors (Set RunError)+  deriving (Show, Eq, Ord)++instance Exception RunErrors where+    displayException = prettyString++instance Semigroup RunErrors where+    lhs@(RunErrors lset) <> rhs@(RunErrors rset) +      | null lset = rhs+      | null rset = lhs+      | otherwise = RunErrors $ combineErrors [lhs, rhs]+    sconcat = RunErrors . combineErrors++instance Monoid RunErrors where+    mempty = RunErrors mempty+    mconcat = RunErrors . combineErrors++instance Pretty RunErrors where+    pretty = \(RunErrors es) -> +        mconcat (zipWith combine delims (toList es)) <> PP.rbracket+      where+        delims = PP.lbracket : repeat PP.comma+        combine delim item =+            delim <> PP.flatAlt " " mempty <> pretty item <> PP.line'++runErrors :: RunErrors -> Set RunError+runErrors = \(RunErrors es) -> es++failure :: RunError -> Valid RunErrors a+failure = Invalid . RunErrors . Set.singleton++groupErrors :: P.HasLocation t => RunT f t a -> RunT f t a+groupErrors (RunT f) = RunT $ \i o ->+    case f i o of+        Invalid errors@(RunErrors errorSet)+          | shouldWrap errors +          , Just loc <- i ^? P.location+          -> Invalid . RunErrors . Set.singleton $ Group (Location loc) errorSet+        other -> other++shouldWrap :: RunErrors -> Bool+shouldWrap (RunErrors es) +  | count >= 2 = True+  | otherwise  = any (\case Group{} -> False; _ -> True) es+  where count = length es++combineErrors :: Foldable f => f RunErrors -> Set RunError+combineErrors =+      HM.foldlWithKey' go mempty +    . groupGroups +    . foldMap runErrors+  where+    go acc key val = Set.union acc $ case key of+        Just loc -> Set.singleton (Group (Location loc) val)+        Nothing  -> val++groupGroups :: Foldable f => f RunError -> HM.HashMap (Maybe P.Location) (Set RunError)+groupGroups = foldl' +    (\acc -> \case+        Group (Location loc) e -> HM.insertWith (<>) (Just loc) e acc+        other -> HM.insertWith (<>) Nothing (Set.singleton other) acc)+    mempty+    +newtype Location = Location P.Location+  deriving (Show, Eq)++instance Pretty Location where+    pretty (Location l) = pretty l++instance Ord Location where+    compare = compare `on` \(Location loc) ->+        (PS.sourceName (PS.locationSource loc), PS.locationOffset loc)+ ---------------------------------------------------------------------------------- | Run a 'Rule' against an input, returning a parse result.-run :: IsError e => RuleT i e Identity a -> i -> Either (ErrorSet e) a-run rule = runIdentity . runM rule+instance Applicative f => Context (RunT f) where+    type Local (RunT f) = f --- | Run a 'RuleT' against an input, returning a contextual parse result.-runM-    :: (Applicative context, IsError e)-    => RuleT i e context a-    -> i-    -> context (Either (ErrorSet e) a)-runM rule = (\(Run x) -> x) . runRun rule+    runSelf  = RunT $ \t obs -> pure (pure t, obs)+    liftRule r = RunT $ \_ obs -> pure (r, obs) +instance Applicative f => Interpret (RunT f) P.Block where+    runRule = groupErrors . \case+        BlockRuleBlockTag nested -> RunT $ \block obs -> case block of+            P.BlockTag tag -> _run (pedantic $ interpret nested) tag mempty+            _              -> (, obs) <$> expected "BlockTag"++        BlockRuleLiteralTag nested -> RunT $ \block obs -> case block of+            P.BlockLiteral tag -> _run (pedantic $ interpret nested) tag mempty+            _                  -> (, obs) <$> expected "BlockLiteral"++        BlockRuleParagraph nested -> RunT $ \block obs -> case block of+            P.BlockParagraph pg -> _run (interpret nested) pg mempty+            _                   -> (, obs) <$> expected "BlockParagraph"++instance Applicative f => Interpret (RunT f) P.Document where+    runRule (DocumentRule regionRule) =+        RunT $ _run (runRule regionRule) . P.documentToRegion++instance Applicative f => Interpret (RunT f) P.Fragment where+    runRule = \case+        FragmentRuleLocation callback -> +            runWith $ pure . pure . callback . P.fragmentLocation++        FragmentRuleText callback -> +            runWith $ pure . pure . callback . P.fragmentText++instance Applicative f => Interpret (RunT f) P.Inline where+    runRule = \case+        InlineRuleBreak item -> runWith $ \inline -> case inline of+            P.Break -> pure $ pure item+            _       -> expected "Break"++        InlineRuleInlineTag nested -> RunT $ \inline obs -> case inline of+            P.InlineTag tag -> _run (pedantic $ interpret nested) tag mempty+            _               -> (, obs) <$> expected "InlineTag"++        InlineRuleFragment nested -> RunT $ \inline obs -> case inline of+            P.InlineText fragment -> _run (interpret nested) fragment mempty+            _                     -> (, obs) <$> expected "InlineText"++instance Applicative f => Interpret (RunT f) P.Metadata where+    runRule = \case+        MetadataRuleProperty callback key ->+            observeProperty key *>+            runWith (pure . pure . callback . (^. P.hasProperty key))++        MetadataRuleSetting parse def key -> +            observeSetting key *>+            runWith (\metadata ->+                case metadata ^. P.atSetting key of+                    Nothing -> maybe (failure $ RequiredSetting key) (pure . pure) def+                    Just raw ->+                        Valid.fromEither+                            . bimap (RunErrors . Set.singleton . ParseError key) pure+                            $ parse raw)++        MetadataRuleAllowUnknown x -> RunT $ \_ _ ->+            pure (pure x, NoObserve)++instance Applicative f => Interpret (RunT f) P.Paragraph where+    runRule = \case+        ParagraphRuleContent nested ->+            RunT $ _run (interpret nested) . P.paragraphContent++        ParagraphRuleLocation callback ->+            runWith $ pure . pure . callback . P.paragraphLocation++instance (Applicative f, Interpret (RunT f) t) => Interpret (RunT f) (P.Region t) where+    runRule = \case+        RegionRuleContent nested -> RunT $ \t obs ->+            second (const obs)+            <$> _run (interpret nested) (P.regionContent t) mempty++        RegionRuleLocation callback ->+            runWith $ Valid.Valid . pure @f . callback . P.regionLocation++        RegionRuleMetadata rule ->+            RunT $ _run (runRule rule) . P.regionMetadata++instance (Applicative f, Interpret (RunT f) t) => Interpret (RunT f) (P.Tag t) where+    runRule = \case+        TagRuleKey key ret ->+            runWith+                $ \tag -> if P.tagName tag == key+                      then pure $ pure ret+                      else failure . MatchError $ "rawKey == " <> Text.pack (show $ P.rawKey key)++        TagRuleRegion nested -> RunT $ _run (runRule nested) . P.tagToRegion++instance (Applicative f, Interpret (RunT f) t) => Interpret (RunT f) (P.Series t) where+    runRule = \case+        SeriesRuleNext rule -> RunT $ \series -> case series of+            x :<: xs -> _run (runRule rule) (x :<<: xs)+            Empty    -> const $ failure TooFewElements++        SeriesRuleEmpty ret -> runWith $ \series -> case series of+            _ :<: _ -> failure TooManyElements+            Empty   -> pure $ pure ret++instance (Applicative f, Interpret (RunT f) t) => Interpret (RunT f) (P.SeriesNE t) where+    runRule (SeriesNERule combine rule rules) = RunT $ \(x :<<: xs) o ->+        (\(f1, o1) (f2, o2) -> (combine <$> f1 <*> f2, o1 <> o2))+            <$> _run (interpret rule) x o+            <*> _run (interpret rules) xs o++instance Applicative f => Interpret (RunT f) Text++expected :: Text -> Valid RunErrors a+expected = failure . MatchError+ --------------------------------------------------------------------------------newtype Run error context output = Run-    (context (Either (ErrorSet error) output))-  deriving Functor+data Observe = +    NoObserve+  | Observe !Observing+  deriving Show -instance (Applicative context, IsError error) => Applicative (Run error context) where-    pure = Run . pure . Right-    {-# INLINE pure #-}+instance Semigroup Observe where+    Observe lhs <> Observe rhs = Observe (lhs <> rhs)+    NoObserve <> _ = NoObserve+    _ <> NoObserve = NoObserve -    Run lhsF <*> Run rhsF = Run $ do-        lhs <- lhsF-        rhs <- rhsF-        pure $ either (\es -> Left $ either (es <>) (const es) rhs)-                      (\fn -> second fn rhs)-                      lhs+instance Monoid Observe where+    mempty = NoObserve -instance (Applicative context, IsError error) => ApError (ErrorSet error) (Run error context) where-    liftError = Run . pure . Left-    {-# INLINE liftError #-}+data Observing = Observing+  { obsProperties :: !(HashSet.HashSet P.Key)+  , obsSettings :: !(HashSet.HashSet P.Key)+  }+  deriving Show -    mapError f (Run r) = Run $ fmap (first f) r+instance Semigroup Observing where+    Observing a b <> Observing z y = Observing (a <> z) (b <> y) -runRun-    :: (Applicative context, IsError e)-    => RuleT i e context a-    -> i-    -> Run e context a-runRun rule = interpretWith rule interpret+instance Monoid Observing where+    mempty = Observing mempty mempty -interpret-    :: (Applicative context, IsError error)-    => Interpret error context (Run error context)-interpret input = \case-    Fail e      -> liftError1 e-    Lift lifted -> Run . fmap (first singleError) $ lifted input-    TestMatch matches ->-        groupErrors input $ evalPatterns matches interpret input-    Traverse f g rule -> do-        fmap g . traverse (runRun rule) $ f input-    GetContent rule   -> runRun rule $ input ^. P.content-    GetProperty k key -> input ^. P.hasProperty key & pure . k-    GetSetting k key parse ->-        input ^. P.atSetting key & traverse parse & either-            (liftError1 . ParseError key)-            (pure . k)-    GetRequiredSetting key parse -> do-        input ^. P.atSetting key & maybe-            (liftError1 $ Required key)-            (either (liftError1 . ParseError key) pure . parse)-    GetSelf k -> pure $ k input+observeProperty :: Applicative f => P.Key -> RunT f t ()+observeProperty k = RunT $ \_ o -> +  let+    o' = case o of+        Observe obs -> Observe $ obs +            { obsProperties = HashSet.insert k $ obsProperties obs }+        NoObserve -> o+  in+    pure (pure (), o')++observeSetting :: Applicative f => P.Key -> RunT f t ()+observeSetting k = RunT $ \_ o -> +  let+    o' = case o of+        Observe obs -> Observe $ obs +            { obsSettings = HashSet.insert k $ obsSettings obs }+        NoObserve -> o+  in+    pure (pure (), o')++pedantic :: P.HasMetadata t => RunT f t a -> RunT f t a+pedantic = RunT . go . _run+  where+    check t = \case+        Observe (Observing props settings) -> do+            let unexpectedProps = t ^.. P.properties . folded . filtered (not . flip HashSet.member props)+                unexpectedSettings = t ^.. P.settings . P._Assoc . to HM.keys . folded . filtered (not . flip HashSet.member settings)+            unless (null unexpectedProps) $+                failure (UnexpectedProperties props (HashSet.fromList unexpectedProps))+            unless (null unexpectedSettings) $+                failure (UnexpectedSettings settings (HashSet.fromList unexpectedSettings))+            pure ()++        NoObserve -> +            pure ()++    go f t obs = +      let+        result = f t $ case obs of+            NoObserve -> Observe mempty+            _         -> obs+      in+        result <* case result of+            Valid.Valid (_, o) -> check t o+            _ -> pure ()++-------------------------------------------------------------------------------+prettyString :: Pretty a => a -> String+prettyString = +    PPS.renderString+        . PP.layoutPretty (PP.defaultLayoutOptions { PP.layoutPageWidth = PP.Unbounded }) +        . pretty
− src/Prosidy/Compile/Strict.hs
@@ -1,95 +0,0 @@-{-|-Module      : Prosidy.Compile.Strict-Description : Ensure that no unknown settings or properties are used.-Copyright   : ©2020 James Alexander Feldman-Crough-License     : MPL-2.0-Maintainer  : alex@fldcr.com--}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE StrictData #-}-{-# LANGUAGE TupleSections #-}-module Prosidy.Compile.Strict (strict) where--import           Lens.Micro              hiding ( strict )--import qualified Prosidy                       as P-import           Prosidy.Compile.Core-import           Prosidy.Compile.Error--import           Control.Monad                  ( unless )-import           Data.HashSet                   ( HashSet )--import qualified Data.HashSet                  as HS-import qualified Data.HashMap.Strict           as HM---- | Ensure that all properties and settings on a node are expected, and throw--- an error when extraneous metadata is attached. This is extremely useful--- for catching typos.------ The matchers 'Prosidy.Compile.Match.blockTag', --- 'Prosidy.Compile.Match.inlineTag', and 'Prosidy.Compile.Match.literalTag'--- already match strictly: wrapping them in this combinator is unneccessary.-strict :: (Applicative f, P.HasMetadata i) => RuleT i e f a -> RuleT i e f a-strict r = r <* checked-  where-    checked = rule . Lift $ \item ->-        let-            Schema { schemaProperties, schemaSettings } = collectSchema r item-            extraProperties =-                HS.difference (item ^. P.properties . P._Set) schemaProperties-            extraSettings = HS.difference-                (item ^. P.settings . P._Assoc . to HM.keysSet)-                schemaSettings-            extras =-                HS.map (PropertyKind, ) extraProperties-                    <> HS.map (SettingKind, ) extraSettings-        in-            pure $ unless (HS.null extras) (Left $ UnknownMetadata extras)--collectSchema :: RuleT i e f a -> i -> Schema-collectSchema rule = getSchema . interpretWith rule interpret--interpret :: Interpret e f Strict-interpret _ = \case-    GetProperty _ name        -> recordProperty name-    GetSetting _ name _       -> recordSetting name-    GetRequiredSetting name _ -> recordSetting name-    _                         -> doNothing--newtype Strict a = Strict (Schema -> Schema)--instance Functor Strict where-    fmap _ = coerce--instance Applicative Strict where-    pure _ = Strict id-    Strict lhs <*> Strict rhs = Strict $ lhs <> rhs--data Schema = Schema-    { schemaProperties :: HashSet P.Key-    , schemaSettings   :: HashSet P.Key-    }--instance Semigroup Schema where-    Schema p1 s1 <> Schema p2 s2 = Schema (p1 <> p2) (s1 <> s2)--instance Monoid Schema where-    mempty = Schema mempty mempty--coerce :: Strict a -> Strict b-coerce = \(Strict x) -> Strict x--getSchema :: Strict a -> Schema-getSchema (Strict x) = x mempty--doNothing :: Strict a-doNothing = Strict id--recordProperty :: P.Key -> Strict a-recordProperty k =-    Strict $ \s -> s { schemaProperties = HS.insert k $ schemaProperties s }--recordSetting :: P.Key -> Strict a-recordSetting k =-    Strict $ \s -> s { schemaSettings = HS.insert k $ schemaSettings s }