ede 0.3.2.0 → 0.3.3.0
raw patch · 9 files changed
+155/−99 lines, 9 filesdep ~aesondep ~attoparsecdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: aeson, attoparsec, base, bytestring
API changes (from Hackage documentation)
- Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Quote Data.Aeson.Types.Internal.Array
- Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Quote Data.Aeson.Types.Internal.Object
- Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Unquote Data.Aeson.Types.Internal.Array
- Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Unquote Data.Aeson.Types.Internal.Object
+ Text.EDE.Internal.Compat: fromHashMapText :: HashMap Text v -> KeyMap v
+ Text.EDE.Internal.Compat: toHashMapText :: KeyMap v -> HashMap Text v
+ Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Quote (Data.Aeson.KeyMap.KeyMap Data.Aeson.Types.Internal.Value)
+ Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Quote (Data.HashMap.Internal.HashMap Data.Text.Internal.Text Data.Aeson.Types.Internal.Value)
+ Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Quote (Data.Vector.Vector Data.Aeson.Types.Internal.Value)
+ Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Unquote (Data.Aeson.KeyMap.KeyMap Data.Aeson.Types.Internal.Value)
+ Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Unquote (Data.HashMap.Internal.HashMap Data.Text.Internal.Text Data.Aeson.Types.Internal.Value)
+ Text.EDE.Internal.Quoting: instance Text.EDE.Internal.Quoting.Unquote (Data.Vector.Vector Data.Aeson.Types.Internal.Value)
- Text.EDE: (.=) :: (KeyValue kv, ToJSON v) => Text -> v -> kv
+ Text.EDE: (.=) :: (KeyValue kv, ToJSON v) => Key -> v -> kv
- Text.EDE: delimBlock :: HasSyntax c_adjL => Lens' c_adjL Delim
+ Text.EDE: delimBlock :: HasSyntax c_adP9 => Lens' c_adP9 Delim
- Text.EDE: delimComment :: HasSyntax c_adjL => Lens' c_adjL Delim
+ Text.EDE: delimComment :: HasSyntax c_adP9 => Lens' c_adP9 Delim
- Text.EDE: delimInline :: HasSyntax c_adjL => Lens' c_adjL Delim
+ Text.EDE: delimInline :: HasSyntax c_adP9 => Lens' c_adP9 Delim
- Text.EDE: delimPragma :: HasSyntax c_adjL => Lens' c_adjL Delim
+ Text.EDE: delimPragma :: HasSyntax c_adP9 => Lens' c_adP9 Delim
- Text.EDE: eitherRender :: Template -> Object -> Either String Text
+ Text.EDE: eitherRender :: Template -> HashMap Text Value -> Either String Text
- Text.EDE: eitherRenderWith :: HashMap Id Term -> Template -> Object -> Either String Text
+ Text.EDE: eitherRenderWith :: HashMap Id Term -> Template -> HashMap Text Value -> Either String Text
- Text.EDE: fromPairs :: [Pair] -> Object
+ Text.EDE: fromPairs :: [Pair] -> HashMap Text Value
- Text.EDE: fromValue :: Value -> Maybe Object
+ Text.EDE: fromValue :: Value -> Maybe (HashMap Text Value)
- Text.EDE: render :: Template -> Object -> Result Text
+ Text.EDE: render :: Template -> HashMap Text Value -> Result Text
- Text.EDE: renderWith :: HashMap Id Term -> Template -> Object -> Result Text
+ Text.EDE: renderWith :: HashMap Id Term -> Template -> HashMap Text Value -> Result Text
- Text.EDE.Filters: qcol1 :: (Quote a, Quote b, Quote c) => Id -> (Text -> a) -> (Object -> b) -> (Array -> c) -> (Id, Term)
+ Text.EDE.Filters: qcol1 :: (Quote a, Quote b, Quote c) => Id -> (Text -> a) -> (HashMap Text Value -> b) -> (Vector Value -> c) -> (Id, Term)
- Text.EDE.Internal.Eval: bind :: (Object -> Object) -> Context a -> Context a
+ Text.EDE.Internal.Eval: bind :: (HashMap Text Value -> HashMap Text Value) -> Context a -> Context a
- Text.EDE.Internal.Filters: headV :: Array -> Value
+ Text.EDE.Internal.Filters: headV :: Vector Value -> Value
- Text.EDE.Internal.Filters: initV :: Array -> Value
+ Text.EDE.Internal.Filters: initV :: Vector Value -> Value
- Text.EDE.Internal.Filters: lastV :: Array -> Value
+ Text.EDE.Internal.Filters: lastV :: Vector Value -> Value
- Text.EDE.Internal.Filters: qcol1 :: (Quote a, Quote b, Quote c) => Id -> (Text -> a) -> (Object -> b) -> (Array -> c) -> (Id, Term)
+ Text.EDE.Internal.Filters: qcol1 :: (Quote a, Quote b, Quote c) => Id -> (Text -> a) -> (HashMap Text Value -> b) -> (Vector Value -> c) -> (Id, Term)
- Text.EDE.Internal.Filters: qlist1 :: (Quote a, Quote b) => Id -> (Text -> a) -> (Array -> b) -> (Id, Term)
+ Text.EDE.Internal.Filters: qlist1 :: (Quote a, Quote b) => Id -> (Text -> a) -> (Vector Value -> b) -> (Id, Term)
- Text.EDE.Internal.Filters: tailV :: Array -> Value
+ Text.EDE.Internal.Filters: tailV :: Vector Value -> Value
- Text.EDE.Internal.Filters: vec :: (Array -> Value) -> Array -> Value
+ Text.EDE.Internal.Filters: vec :: (Vector Value -> Value) -> Vector Value -> Value
- Text.EDE.Internal.Parser: array :: Parser m => m Array
+ Text.EDE.Internal.Parser: array :: Parser m => m (Vector Value)
- Text.EDE.Internal.Parser: object :: Parser m => m Object
+ Text.EDE.Internal.Parser: object :: Parser m => m (HashMap Text Value)
- Text.EDE.Internal.Types: _Failure :: forall a_abo1. Prism' (Result a_abo1) AnsiDoc
+ Text.EDE.Internal.Types: _Failure :: forall a_abTC. Prism' (Result a_abTC) AnsiDoc
- Text.EDE.Internal.Types: _Success :: forall a_abo1 a_ad3E. Prism (Result a_ad3E) (Result a_abo1) a_ad3E a_abo1
+ Text.EDE.Internal.Types: _Success :: forall a_adyU a_abTC. Prism (Result a_adyU) (Result a_abTC) a_adyU a_abTC
- Text.EDE.Internal.Types: class HasSyntax c_adjL
+ Text.EDE.Internal.Types: class HasSyntax c_adP9
- Text.EDE.Internal.Types: delimBlock :: HasSyntax c_adjL => Lens' c_adjL Delim
+ Text.EDE.Internal.Types: delimBlock :: HasSyntax c_adP9 => Lens' c_adP9 Delim
- Text.EDE.Internal.Types: delimComment :: HasSyntax c_adjL => Lens' c_adjL Delim
+ Text.EDE.Internal.Types: delimComment :: HasSyntax c_adP9 => Lens' c_adP9 Delim
- Text.EDE.Internal.Types: delimInline :: HasSyntax c_adjL => Lens' c_adjL Delim
+ Text.EDE.Internal.Types: delimInline :: HasSyntax c_adP9 => Lens' c_adP9 Delim
- Text.EDE.Internal.Types: delimPragma :: HasSyntax c_adjL => Lens' c_adjL Delim
+ Text.EDE.Internal.Types: delimPragma :: HasSyntax c_adP9 => Lens' c_adP9 Delim
- Text.EDE.Internal.Types: fromPairs :: [Pair] -> Object
+ Text.EDE.Internal.Types: fromPairs :: [Pair] -> HashMap Text Value
- Text.EDE.Internal.Types: fromValue :: Value -> Maybe Object
+ Text.EDE.Internal.Types: fromValue :: Value -> Maybe (HashMap Text Value)
- Text.EDE.Internal.Types: syntax :: HasSyntax c_adjL => Lens' c_adjL Syntax
+ Text.EDE.Internal.Types: syntax :: HasSyntax c_adP9 => Lens' c_adP9 Syntax
Files
- app/Main.hs +10/−7
- ede.cabal +11/−9
- lib/Text/EDE.hs +22/−22
- lib/Text/EDE/Internal/Compat.hs +35/−0
- lib/Text/EDE/Internal/Eval.hs +9/−7
- lib/Text/EDE/Internal/Filters.hs +14/−11
- lib/Text/EDE/Internal/Parser.hs +18/−20
- lib/Text/EDE/Internal/Quoting.hs +25/−13
- lib/Text/EDE/Internal/Types.hs +11/−10
app/Main.hs view
@@ -8,20 +8,23 @@ import qualified Data.Attoparsec.ByteString as Parsec import qualified Data.ByteString as ByteString import qualified Data.ByteString.Lazy as ByteString.Lazy+import Data.HashMap.Strict (HashMap)+import Data.Text (Text) import qualified Data.Text as Text import qualified Data.Text.Encoding as Text.Encoding import qualified Data.Text.Lazy.IO as Text.Lazy.IO import qualified Options.Applicative as Options import qualified Options.Applicative.Help.Pretty as Pretty-import qualified System.Exit as Exit-import qualified Text.EDE as EDE import qualified Prettyprinter as PP import qualified Prettyprinter.Render.Terminal as PP+import qualified System.Exit as Exit+import qualified Text.EDE as EDE+import qualified Text.EDE.Internal.Compat as Compat data Options = Options { templateFile :: FilePath, jsonFile :: Maybe FilePath,- jsonObject :: Maybe Aeson.Object+ jsonObject :: Maybe (HashMap Text Aeson.Value) } optionsParser :: Options.Parser Options@@ -117,7 +120,7 @@ EDE.Failure err -> PP.putDoc (err <> PP.hardline) >> Exit.exitFailure EDE.Success output -> Text.Lazy.IO.putStr output -stdinParser :: Parsec.Parser Aeson.Object+stdinParser :: Parsec.Parser (HashMap Text Aeson.Value) stdinParser = Aeson.json >>= requireObject readValue :: Options.ReadM Aeson.Value@@ -129,10 +132,10 @@ . Text.Encoding.encodeUtf8 . Text.pack -readObject :: Options.ReadM Aeson.Object+readObject :: Options.ReadM (HashMap Text Aeson.Value) readObject = readValue >>= requireObject -requireObject :: Fail.MonadFail m => Aeson.Value -> m Aeson.Object+requireObject :: Fail.MonadFail m => Aeson.Value -> m (HashMap Text Aeson.Value) requireObject = \case- Aeson.Object obj -> pure obj+ Aeson.Object obj -> pure (Compat.toHashMapText obj) _ -> fail "JSON value must be an object"
ede.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: ede-version: 0.3.2.0+version: 0.3.3.0 synopsis: Templating language with similar syntax and features to Liquid or Jinja2. @@ -49,9 +49,9 @@ default-language: Haskell2010 ghc-options: -Wall -funbox-strict-fields -fwarn-incomplete-uni-patterns- -fwarn-incomplete-record-updates+ -fwarn-incomplete-record-updates -fwarn-unused-packages - build-depends: base >=4.12 && <5+ build-depends: base >=4.13 && <5 autogen-modules: Paths_ede other-modules: Paths_ede @@ -62,6 +62,7 @@ Text.EDE Text.EDE.Filters Text.EDE.Internal.AST+ Text.EDE.Internal.Compat Text.EDE.Internal.Eval Text.EDE.Internal.Filters Text.EDE.Internal.Parser@@ -70,8 +71,8 @@ Text.EDE.Internal.Types build-depends:- , aeson >=0.7- , bytestring >=0.9+ , aeson >=1.4+ , bytestring >=0.10.4 , comonad >=4.2 , directory >=1.2 , filepath >=1.2@@ -79,7 +80,7 @@ , lens >=4.0 , mtl >=2.1.3.1 , parsers >=0.12.1.1- , prettyprinter >=1.6+ , prettyprinter >=1.7 , prettyprinter-ansi-terminal >=1.1 , scientific >=0.3.1 , text >=1.2@@ -94,14 +95,15 @@ main-is: Main.hs ghc-options: -threaded -rtsopts -with-rtsopts=-A128m build-depends:- , aeson >=0.8- , attoparsec+ , aeson >=1.4+ , attoparsec >=0.13 , bytestring >=0.10.4 , ede , optparse-applicative >=0.11- , prettyprinter >=1.6+ , prettyprinter >= 1.7 , prettyprinter-ansi-terminal >=1.1 , text >=1.2+ , unordered-containers >=0.2.3 test-suite tests import: base
lib/Text/EDE.hs view
@@ -114,7 +114,7 @@ import qualified Control.Monad as Monad import Data.Aeson ((.=))-import Data.Aeson.Types (Object)+import Data.Aeson.Types (Value) import Data.ByteString (ByteString) import qualified Data.ByteString as ByteString import qualified Data.Foldable as Foldable@@ -125,9 +125,9 @@ import qualified Data.Text as Text import qualified Data.Text.Lazy as Text.Lazy import qualified Data.Text.Lazy.Builder as Text.Builder-import Data.Text.Prettyprint.Doc (Pretty (..)) import Data.Version (Version) import qualified Paths_ede as Paths+import Prettyprinter (Pretty (..)) import qualified System.Directory as Directory import qualified System.FilePath as FilePath import qualified Text.EDE.Internal.Eval as Eval@@ -270,23 +270,23 @@ then failure ("file " <> pretty path <> " doesn't exist.") else ByteString.readFile path >>= success --- | Render an 'Object' using the supplied 'Template'.+-- | Render an 'HashMap Text Value' using the supplied 'Template'. render :: -- | Parsed 'Template' to render. Template -> -- | Bindings to make available in the environment.- Object ->+ HashMap Text Value -> Result Text.Lazy.Text render = renderWith mempty --- | Render an 'Object' using the supplied 'Template'.+-- | Render an 'HashMap Text Value' using the supplied 'Template'. renderWith :: -- | Filters to make available in the environment. HashMap Id Term -> -- | Parsed 'Template' to render. Template -> -- | Bindings to make available in the environment.- Object ->+ HashMap Text Value -> Result Text.Lazy.Text renderWith fs (Template _ u ts) = fmap Text.Builder.toLazyText . Eval.render ts fs u@@ -312,7 +312,7 @@ -- | /See:/ 'render' eitherRender :: Template ->- Object ->+ HashMap Text Value -> Either String Text.Lazy.Text eitherRender t = eitherResult . render t @@ -320,7 +320,7 @@ eitherRenderWith :: HashMap Id Term -> Template ->- Object ->+ HashMap Text Value -> Either String Text.Lazy.Text eitherRenderWith fs t = eitherResult . renderWith fs t @@ -333,15 +333,15 @@ -- -- >>> tmpl <- parse "{% if var %}\nHello, {{ var }}!\n{% else %}\nnegative!\n{% endif %}\n" :: Result Template ----- Then an 'Object' is defined containing the environment which will be+-- Then an 'HashMap Text Value' is defined containing the environment which will be -- available to the 'Template' during rendering: ----- >>> let env = fromPairs [ "var" .= "World" ] :: Object+-- >>> let env = fromPairs [ "var" .= "World" ] :: HashMap Text Value -- -- Note: the 'fromPairs' function above is a wrapper over Aeson's 'object'--- which removes the outer 'Object' 'Value' constructor, exposing the underlying 'HashMap'.+-- which removes the outer 'Data.Aeson.Object' 'Value' constructor, exposing the underlying 'HashMap'. ----- Then, the 'Template' is rendered using the 'Object' environment:+-- Then, the 'Template' is rendered using the 'HashMap Text Value' environment: -- -- >>> render tmpl env :: Result Text -- > Success "Hello, World!"@@ -379,7 +379,7 @@ -- which can be cached for future use. -- -- * Rendering takes a 'HashMap' of custom 'Fun's (functions available in the--- template context), an 'Object' as the binding environment, and a parsed+-- template context), an 'HashMap Text Value' as the binding environment, and a parsed -- 'Template' to subsitute the values into. -- The result is a Lazy 'Text.Lazy.Text' value containing the rendered output. @@ -487,12 +487,12 @@ -- -- Variables are substituted directly for their renderable representation. -- An error is raised if the varaible being substituted is not a literal type--- (ie. an 'Array' or 'Object') or doesn't exist in the supplied environment.+-- (ie. an 'Array' or 'HashMap Text Value') or doesn't exist in the supplied environment. -- -- > {{ var }} ----- Nested variable access is also supported for variables which resolve to an 'Object'.--- Dot delimiters are used to chain access through multiple nested 'Object's.+-- Nested variable access is also supported for variables which resolve to an 'HashMap Text Value'.+-- Dot delimiters are used to chain access through multiple nested 'HashMap Text Value's. -- The right-most accessor must resolve to a renderable type as with the previous -- non-nested variable access. --@@ -564,7 +564,7 @@ -- $loops ----- Iterating over an 'Array' or 'Object' can be acheived using the 'for ... in' section syntax.+-- Iterating over an 'Array' or 'HashMap Text Value' can be acheived using the 'for ... in' section syntax. -- Attempting to iterate over any other type will raise an error. -- -- Example:@@ -578,13 +578,13 @@ -- The iteration branch is rendering per item with the else branch being (which is optional) -- being rendered if the @{{ list }}@ variable is empty. ----- When iterating over an 'Object', a stable sort using key equivalence is applied, 'Array's+-- When iterating over an 'HashMap Text Value', a stable sort using key equivalence is applied, 'Array's -- are unmodified. -- -- The resulting binding within the iteration expression (in this case, @{{ var }}@) is--- an 'Object' containing the following keys:+-- an 'HashMap Text Value' containing the following keys: ----- * @key :: Text@: They key if the loop target is an 'Object'+-- * @key :: Text@: They key if the loop target is an 'HashMap Text Value' -- -- * @value :: a@: The value of the loop target --@@ -620,8 +620,8 @@ -- Will render each item with its (1-based) loop index as a prefix, separated -- by a blank newline, without a trailing at the end of the document. ----- Valid loop targets are 'Object's, 'Array's, and 'String's, with only 'Object's--- having an available @{{ <var>.key }}@ in scope.+-- Valid loop targets are 'HashMap Text Value's, 'Array's, and 'String's, with+-- only 'HashMap Text Value's having an available @{{ <var>.key }}@ in scope. -- $includes --
+ lib/Text/EDE/Internal/Compat.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE CPP #-}++-- |+-- Module : Text.EDE.Internal.Eval+-- Copyright : (c) 2022 Brendan Hay <brendan.g.hay@gmail.com>+-- License : This Source Code Form is subject to the terms of+-- the Mozilla Public License, v. 2.0.+-- A copy of the MPL can be found in the LICENSE file or+-- you can obtain it at http://mozilla.org/MPL/2.0/.+-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>+-- Stability : experimental+-- Portability : non-portable (GHC extensions)+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+module Text.EDE.Internal.Compat+ ( toHashMapText,+ fromHashMapText,+ )+where++#if MIN_VERSION_aeson(2,0,0)+import Data.Aeson.KeyMap (toHashMapText, fromHashMapText)+#else+import Data.HashMap.Strict (HashMap)+import Data.Aeson.Types (Value)+import Data.Text (Text)++toHashMapText :: HashMap Text Value -> HashMap Text Value+toHashMapText = id++fromHashMapText :: HashMap Text Value -> HashMap Text Value+fromHashMapText = id+#endif
lib/Text/EDE/Internal/Eval.hs view
@@ -26,20 +26,22 @@ import Control.Monad.Trans (lift) import Data.Aeson ((.=)) import qualified Data.Aeson as Aeson-import Data.Aeson.Types (Object, Value (..))+import Data.Aeson.Types (Value (..)) import qualified Data.Foldable as Foldable import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NonEmpty import Data.Scientific (isFloating)+import Data.Text (Text) import qualified Data.Text as Text import Data.Text.Lazy.Builder (Builder) import qualified Data.Text.Lazy.Builder as Text.Builder import Data.Text.Lazy.Builder.Scientific (FPFormat (Fixed), formatScientificBuilder) import Data.Text.Manipulate (toOrdinal)-import Data.Text.Prettyprint.Doc ((<+>))-import qualified Data.Text.Prettyprint.Doc as PP+import Prettyprinter ((<+>))+import qualified Prettyprinter as PP+import Text.EDE.Internal.Compat import Text.EDE.Internal.Filters (stdlib) import Text.EDE.Internal.Quoting import Text.EDE.Internal.Types@@ -171,13 +173,13 @@ <+> PP.brackets (pp (Text.intercalate "," $ HashMap.keys ts)) {-# INLINEABLE eval #-} -bind :: (Object -> Object) -> Context a -> Context a+bind :: (HashMap Text Value -> HashMap Text Value) -> Context a -> Context a bind f = Reader.withReaderT (\x -> x {_values = f (_values x)}) {-# INLINEABLE bind #-} variable :: Delta -> Var -> Context Value variable d (Var is) =- Reader.asks _values >>= go (NonEmpty.toList is) [] . Object+ Reader.asks _values >>= go (NonEmpty.toList is) [] . Object . fromHashMapText where go [] _ v = pure v go (k : ks) r v = do@@ -189,8 +191,8 @@ where cur = Var (k :| r) - nest :: Value -> Context Object- nest (Object o) = pure o+ nest :: Value -> Context (HashMap Text Value)+ nest (Object o) = pure (toHashMapText o) nest x = throwError d $ "variable"
lib/Text/EDE/Internal/Filters.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE ExtendedDefaultRules #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-}@@ -22,7 +23,7 @@ module Text.EDE.Internal.Filters where import qualified Data.Aeson as Aeson-import Data.Aeson.Types (Array, Object, Value (..))+import Data.Aeson.Types (Value (..)) import qualified Data.Char as Char import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap@@ -33,9 +34,11 @@ import qualified Data.Text.Lazy as Text.Lazy import qualified Data.Text.Lazy.Encoding as Text.Lazy.Encoding import qualified Data.Text.Manipulate as Text.Manipulate-import Data.Text.Prettyprint.Doc ((<+>)) import qualified Data.Text.Unsafe as Text.Unsafe+import Data.Vector (Vector) import qualified Data.Vector as Vector+import Prettyprinter ((<+>))+import Text.EDE.Internal.Compat import Text.EDE.Internal.Quoting import Text.EDE.Internal.Types @@ -110,8 +113,8 @@ qlist1 "init" initT initV, "at" @: (\x i -> x Vector.! i :: Value), -- object- "keys" @: (HashMap.keys :: Object -> [Text]),- "elems" @: (HashMap.elems :: Object -> [Value]),+ "keys" @: (HashMap.keys :: HashMap Text Value -> [Text]),+ "elems" @: (HashMap.elems :: HashMap Text Value -> [Value]), -- , "map" @: undefined -- , "filter" @: undefined -- , "zip" @: undefined@@ -119,7 +122,7 @@ -- polymorphic "show" @: (Text.Lazy.Encoding.decodeUtf8 . Aeson.encode :: Value -> Text.Lazy.Text),- "singleton" @: (pure :: Value -> Vector.Vector Value)+ "singleton" @: (pure :: Value -> Vector Value) -- FIXME: existence checks currently hardcoded into the evaluator: -- "default" -- "defined"@@ -146,7 +149,7 @@ (Quote a, Quote b) => Id -> (Text -> a) ->- (Array -> b) ->+ (Vector Value -> b) -> (Id, Term) qlist1 k f g = (k,) . TLam $ \case TVal (String t) -> pure . quote k 0 $ f t@@ -161,12 +164,12 @@ (Quote a, Quote b, Quote c) => Id -> (Text -> a) ->- (Object -> b) ->- (Array -> c) ->+ (HashMap Text Value -> b) ->+ (Vector Value -> c) -> (Id, Term) qcol1 k f g h = (k,) . TLam $ \case TVal (String t) -> pure . quote k 0 $ f t- TVal (Object o) -> pure . quote k 0 $ g o+ TVal (Object o) -> pure . quote k 0 $ g (toHashMapText o) TVal (Array v) -> pure . quote k 0 $ h v x -> Failure $@@ -178,7 +181,7 @@ tailT = text Text.Unsafe.unsafeTail initT = text Text.init -headV, lastV, tailV, initV :: Array -> Value+headV, lastV, tailV, initV :: Vector Value -> Value headV = vec Vector.unsafeHead lastV = vec Vector.unsafeLast tailV = vec (Array . Vector.unsafeTail)@@ -187,7 +190,7 @@ text :: (Text -> Text) -> Text -> Value text f = String . safe mempty Text.null f -vec :: (Array -> Value) -> Array -> Value+vec :: (Vector Value -> Value) -> Vector Value -> Value vec = safe (Array Vector.empty) Vector.null safe :: b -> (a -> Bool) -> (a -> b) -> a -> b
lib/Text/EDE/Internal/Parser.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}@@ -31,11 +30,11 @@ import Control.Comonad.Cofree (Cofree ((:<))) import Control.Lens ((%=)) import qualified Control.Lens as Lens-import Control.Monad (MonadPlus, void, unless)+import Control.Monad (MonadPlus, unless, void) import Control.Monad.State.Strict (MonadState, StateT) import qualified Control.Monad.State.Strict as State import Control.Monad.Trans (lift)-import Data.Aeson.Types (Array, Object, Value (..))+import Data.Aeson.Types (Value (..)) import qualified Data.Bifunctor as Bifunctor import Data.ByteString (ByteString) import qualified Data.Char as Char@@ -48,8 +47,10 @@ import Data.Text (Text) import qualified Data.Text as Text import qualified Data.Text.Encoding as Text.Encoding+import Data.Vector (Vector) import qualified Data.Vector as Vector import Text.EDE.Internal.AST+import Text.EDE.Internal.Compat import Text.EDE.Internal.Syntax import Text.EDE.Internal.Types import qualified Text.Parser.Expression as Expression@@ -73,9 +74,7 @@ type Parser m = ( Monad m,-#if MIN_VERSION_base(4,13,0) MonadFail m,-#endif MonadState Env m, Trifecta.TokenParsing m, Trifecta.DeltaParsing m,@@ -89,9 +88,7 @@ Applicative, Alternative, Monad,-#if MIN_VERSION_base(4,13,0) MonadFail,-#endif MonadPlus, Trifecta.Parsing, Trifecta.CharParsing,@@ -137,10 +134,11 @@ pragma :: Parser m => m () pragma = void . Trifecta.many $ do- !xs <- pragmal- *> Trifecta.symbol "EDE_SYNTAX"- *> Trifecta.sepBy field spaces- <* trimr pragmar+ !xs <-+ pragmal+ *> Trifecta.symbol "EDE_SYNTAX"+ *> Trifecta.sepBy field spaces+ <* trimr pragmar mapM_ (uncurry Lens.assign) xs where@@ -194,7 +192,7 @@ block :: Parser m => String -> m a -> m a block k p = Trifecta.try (multiLine (keyword k) p)- <|> singleLine (keyword k) p+ <|> singleLine (keyword k) p multiLine :: Parser m => m b -> m a -> m a multiLine s =@@ -342,7 +340,7 @@ collection = ann (EVar <$> variable <|> ELit <$> col) where col =- Object <$> object+ (Object . fromHashMapText) <$> object <|> Array <$> array <|> String <$> Trifecta.stringLiteral @@ -351,7 +349,7 @@ Bool <$> bool <|> Number <$> number <|> String <$> Trifecta.stringLiteral- <|> Object <$> object+ <|> (Object . fromHashMapText) <$> object <|> Array <$> array number :: Parser m => m Scientific@@ -364,7 +362,7 @@ Trifecta.symbol "true" *> pure True <|> Trifecta.symbol "false" *> pure False -object :: Parser m => m Object+object :: Parser m => m (HashMap Text Value) object = HashMap.fromList <$> Trifecta.braces (Trifecta.commaSep pair) where pair =@@ -372,7 +370,7 @@ <$> (Trifecta.stringLiteral <* Trifecta.spaces) <*> (Trifecta.char ':' *> Trifecta.spaces *> literal) -array :: Parser m => m Array+array :: Parser m => m (Vector Value) array = Vector.fromList <$> Trifecta.brackets (Trifecta.commaSep literal) operator :: Parser m => Text -> m Delta@@ -413,10 +411,10 @@ triml :: Parser m => m a -> m a triml p = do- c <- Trifecta.Delta.column <$> Trifecta.position- if c == 0- then Trifecta.spaces *> p- else fail "left whitespace removal failed"+ c <- Trifecta.Delta.column <$> Trifecta.position+ if c == 0+ then Trifecta.spaces *> p+ else fail "left whitespace removal failed" trimr :: Parser m => m a -> m a trimr p = p <* Trifecta.newline -- <* Trifecta.newline
lib/Text/EDE/Internal/Quoting.hs view
@@ -1,5 +1,5 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE ExtendedDefaultRules #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}@@ -26,9 +26,10 @@ import Control.Monad ((>=>)) import Data.Aeson (FromJSON, ToJSON) import qualified Data.Aeson as Aeson-import Data.Aeson.Types (Array, Object, Value (..))+import Data.Aeson.Types (Value (..)) import qualified Data.Bifunctor as Bifunctor import qualified Data.ByteString.Char8 as ByteString.Char8+import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap import Data.List (sortBy) import Data.Ord (comparing)@@ -41,15 +42,18 @@ import Data.Text.Lazy.Builder (Builder) import qualified Data.Text.Lazy.Builder as Text.Builder import Data.Text.Manipulate (toOrdinal)-import Data.Text.Prettyprint.Doc (Pretty (..), (<+>))-import qualified Data.Text.Prettyprint.Doc as PP+import Data.Vector (Vector) import qualified Data.Vector as Vector+import Prettyprinter (Pretty (..), (<+>))+import qualified Prettyprinter as PP import Text.EDE.Internal.Types import Text.Trifecta.Delta (Delta) import qualified Text.Trifecta.Delta as Trifecta.Delta import qualified Text.Trifecta.Rendering as Trifecta.Rendering -default (AnsiDoc, Double, Integer)+#if MIN_VERSION_aeson(2,0,0)+import Data.Aeson.KeyMap (KeyMap)+#endif -- | A HOAS representation of (possibly partially applied) values -- in the environment.@@ -96,6 +100,14 @@ instance Unquote Value +#if MIN_VERSION_aeson(2,0,0)+instance Unquote (KeyMap Value)+#endif++instance Unquote (HashMap Text Value)++instance Unquote (Vector Value)+ instance Unquote Text instance Unquote [Text]@@ -108,10 +120,6 @@ instance Unquote Scientific -instance Unquote Object--instance Unquote Array- instance Unquote Int where unquote k n = unquote k n@@ -164,6 +172,14 @@ instance Quote Value +#if MIN_VERSION_aeson(2,0,0)+instance Quote (KeyMap Value)+#endif++instance Quote (HashMap Text Value)++instance Quote (Vector Value)+ instance Quote [Value] instance Quote Text@@ -181,10 +197,6 @@ instance Quote Double instance Quote Scientific--instance Quote Object--instance Quote Array instance Quote Builder where quote k n = quote k n . Text.Builder.toLazyText
lib/Text/EDE/Internal/Types.hs view
@@ -30,7 +30,7 @@ import Control.Comonad.Cofree (Cofree) import qualified Control.Lens as Lens import qualified Data.Aeson as Aeson-import Data.Aeson.Types (Object, Pair, Value (..))+import Data.Aeson.Types (Pair, Value (..)) import qualified Data.Functor.Classes as Functor.Classes import Data.HashMap.Strict (HashMap) import qualified Data.List as List@@ -38,9 +38,10 @@ import qualified Data.List.NonEmpty as NonEmpty import Data.Text (Text) import qualified Data.Text as Text-import Data.Text.Prettyprint.Doc (Doc, Pretty (..))-import qualified Data.Text.Prettyprint.Doc as PP-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as PP+import Prettyprinter (Doc, Pretty (..))+import qualified Prettyprinter as PP+import qualified Prettyprinter.Render.Terminal as PP+import Text.EDE.Internal.Compat import Text.Trifecta.Delta (Delta, HasDelta) import qualified Text.Trifecta.Delta as Trifecta.Delta @@ -86,7 +87,7 @@ $(Lens.makePrisms ''Result) instance Monad Result where- return = Success+ return = pure {-# INLINE return #-} Success x >>= k = k x@@ -94,7 +95,7 @@ {-# INLINE (>>=) #-} instance Applicative Result where- pure = return+ pure = Success {-# INLINE pure #-} Success f <*> Success x = Success (f x)@@ -228,15 +229,15 @@ -- | Unwrap a 'Value' to an 'Object' safely. -- -- See Aeson\'s documentation for more details.-fromValue :: Value -> Maybe Object-fromValue (Object o) = Just o+fromValue :: Value -> Maybe (HashMap Text Value)+fromValue (Object o) = Just (toHashMapText o) fromValue _ = Nothing -- | Create an 'Object' from a list of name/value 'Pair's. -- -- See Aeson\'s documentation for more details.-fromPairs :: [Pair] -> Object+fromPairs :: [Pair] -> HashMap Text Value fromPairs xs = case Aeson.object xs of- Object o -> o+ Object o -> toHashMapText o _other -> mempty