packages feed

jsonnet 0.2.0.0 → 0.3.0.0

raw patch · 24 files changed

+1158/−1056 lines, 24 filesdep +lensdep +tasty-benchdep +th-utilitiesdep ~ansi-wl-pprintdep ~basedep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: lens, tasty-bench, th-utilities

Dependency ranges changed: ansi-wl-pprint, base, bytestring, hashable, optparse-applicative, scientific, text, unordered-containers, vector

API changes (from Hackage documentation)

- Language.Jsonnet: [stdlib] :: Config -> Thunk
- Language.Jsonnet: data Config
- Language.Jsonnet.Common: Arith :: ArithOp -> BinOp
- Language.Jsonnet.Common: Bitwise :: BitwiseOp -> BinOp
- Language.Jsonnet.Common: Comp :: CompOp -> BinOp
- Language.Jsonnet.Common: Hideable :: a -> Visibility -> Hideable a
- Language.Jsonnet.Common: Logical :: LogicalOp -> BinOp
- Language.Jsonnet.Common: [value] :: Hideable a -> a
- Language.Jsonnet.Common: [visiblity] :: Hideable a -> Visibility
- Language.Jsonnet.Common: data ArithOp
- Language.Jsonnet.Common: data Backtrace a
- Language.Jsonnet.Common: data BitwiseOp
- Language.Jsonnet.Common: data CompOp
- Language.Jsonnet.Common: data Hideable a
- Language.Jsonnet.Common: data LogicalOp
- Language.Jsonnet.Common: instance Data.Data.Data Language.Jsonnet.Common.ArithOp
- Language.Jsonnet.Common: instance Data.Data.Data Language.Jsonnet.Common.BitwiseOp
- Language.Jsonnet.Common: instance Data.Data.Data Language.Jsonnet.Common.CompOp
- Language.Jsonnet.Common: instance Data.Data.Data Language.Jsonnet.Common.LogicalOp
- Language.Jsonnet.Common: instance Data.Data.Data a => Data.Data.Data (Language.Jsonnet.Common.Hideable a)
- Language.Jsonnet.Common: instance GHC.Base.Functor Language.Jsonnet.Common.Hideable
- Language.Jsonnet.Common: instance GHC.Classes.Eq Language.Jsonnet.Common.ArithOp
- Language.Jsonnet.Common: instance GHC.Classes.Eq Language.Jsonnet.Common.BitwiseOp
- Language.Jsonnet.Common: instance GHC.Classes.Eq Language.Jsonnet.Common.CompOp
- Language.Jsonnet.Common: instance GHC.Classes.Eq Language.Jsonnet.Common.LogicalOp
- Language.Jsonnet.Common: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Jsonnet.Common.Hideable a)
- Language.Jsonnet.Common: instance GHC.Enum.Bounded Language.Jsonnet.Common.ArithOp
- Language.Jsonnet.Common: instance GHC.Enum.Bounded Language.Jsonnet.Common.BitwiseOp
- Language.Jsonnet.Common: instance GHC.Enum.Bounded Language.Jsonnet.Common.CompOp
- Language.Jsonnet.Common: instance GHC.Enum.Bounded Language.Jsonnet.Common.LogicalOp
- Language.Jsonnet.Common: instance GHC.Enum.Bounded Language.Jsonnet.Common.UnyOp
- Language.Jsonnet.Common: instance GHC.Enum.Enum Language.Jsonnet.Common.ArithOp
- Language.Jsonnet.Common: instance GHC.Enum.Enum Language.Jsonnet.Common.BitwiseOp
- Language.Jsonnet.Common: instance GHC.Enum.Enum Language.Jsonnet.Common.CompOp
- Language.Jsonnet.Common: instance GHC.Enum.Enum Language.Jsonnet.Common.LogicalOp
- Language.Jsonnet.Common: instance GHC.Enum.Enum Language.Jsonnet.Common.UnyOp
- Language.Jsonnet.Common: instance GHC.Generics.Generic (Language.Jsonnet.Common.Hideable a)
- Language.Jsonnet.Common: instance GHC.Generics.Generic Language.Jsonnet.Common.ArithOp
- Language.Jsonnet.Common: instance GHC.Generics.Generic Language.Jsonnet.Common.BitwiseOp
- Language.Jsonnet.Common: instance GHC.Generics.Generic Language.Jsonnet.Common.CompOp
- Language.Jsonnet.Common: instance GHC.Generics.Generic Language.Jsonnet.Common.LogicalOp
- Language.Jsonnet.Common: instance GHC.Read.Read a => GHC.Read.Read (Language.Jsonnet.Common.Hideable a)
- Language.Jsonnet.Common: instance GHC.Show.Show Language.Jsonnet.Common.ArithOp
- Language.Jsonnet.Common: instance GHC.Show.Show Language.Jsonnet.Common.BitwiseOp
- Language.Jsonnet.Common: instance GHC.Show.Show Language.Jsonnet.Common.CompOp
- Language.Jsonnet.Common: instance GHC.Show.Show Language.Jsonnet.Common.LogicalOp
- Language.Jsonnet.Common: instance GHC.Show.Show a => GHC.Show.Show (Language.Jsonnet.Common.Hideable a)
- Language.Jsonnet.Common: instance Language.Jsonnet.Common.HasVisibility (Language.Jsonnet.Common.Hideable a)
- Language.Jsonnet.Common: instance Unbound.Generics.LocallyNameless.Alpha.Alpha Language.Jsonnet.Common.ArithOp
- Language.Jsonnet.Common: instance Unbound.Generics.LocallyNameless.Alpha.Alpha Language.Jsonnet.Common.BitwiseOp
- Language.Jsonnet.Common: instance Unbound.Generics.LocallyNameless.Alpha.Alpha Language.Jsonnet.Common.CompOp
- Language.Jsonnet.Common: instance Unbound.Generics.LocallyNameless.Alpha.Alpha Language.Jsonnet.Common.LogicalOp
- Language.Jsonnet.Common: instance Unbound.Generics.LocallyNameless.Alpha.Alpha a => Unbound.Generics.LocallyNameless.Alpha.Alpha (Language.Jsonnet.Common.Hideable a)
- Language.Jsonnet.Common: pushStackFrame :: StackFrame a -> Backtrace a -> Backtrace a
- Language.Jsonnet.Core: CApp :: Core -> Args Core -> Core
- Language.Jsonnet.Core: CArr :: [Core] -> Core
- Language.Jsonnet.Core: CBinOp :: BinOp -> Core -> Core -> Core
- Language.Jsonnet.Core: CComp :: Comp -> Core -> Core
- Language.Jsonnet.Core: CErr :: Core -> Core
- Language.Jsonnet.Core: CFun :: Fun -> Core
- Language.Jsonnet.Core: CIfElse :: Core -> Core -> Core -> Core
- Language.Jsonnet.Core: CLet :: Let -> Core
- Language.Jsonnet.Core: CLit :: Literal -> Core
- Language.Jsonnet.Core: CLoc :: SrcSpan -> Core -> Core
- Language.Jsonnet.Core: CLookup :: Core -> Core -> Core
- Language.Jsonnet.Core: CObj :: [KeyValue Core] -> Core
- Language.Jsonnet.Core: CUnyOp :: UnyOp -> Core -> Core
- Language.Jsonnet.Core: CVar :: Name Core -> Core
- Language.Jsonnet.Core: Fun :: Bind (Rec [Param Core]) Core -> Fun
- Language.Jsonnet.Core: KeyValue :: a -> Hideable a -> KeyValue a
- Language.Jsonnet.Core: Let :: Bind (Rec [(Name Core, Embed Core)]) Core -> Let
- Language.Jsonnet.Core: data KeyValue a
- Language.Jsonnet.Core: instance GHC.Generics.Generic (Language.Jsonnet.Core.KeyValue a)
- Language.Jsonnet.Core: instance GHC.Generics.Generic Language.Jsonnet.Core.Fun
- Language.Jsonnet.Core: instance GHC.Generics.Generic Language.Jsonnet.Core.Let
- Language.Jsonnet.Core: instance GHC.Show.Show Language.Jsonnet.Core.Fun
- Language.Jsonnet.Core: instance GHC.Show.Show Language.Jsonnet.Core.Let
- Language.Jsonnet.Core: instance GHC.Show.Show a => GHC.Show.Show (Language.Jsonnet.Core.KeyValue a)
- Language.Jsonnet.Core: instance Unbound.Generics.LocallyNameless.Alpha.Alpha Language.Jsonnet.Core.Fun
- Language.Jsonnet.Core: instance Unbound.Generics.LocallyNameless.Alpha.Alpha Language.Jsonnet.Core.Let
- Language.Jsonnet.Core: instance Unbound.Generics.LocallyNameless.Alpha.Alpha a => Unbound.Generics.LocallyNameless.Alpha.Alpha (Language.Jsonnet.Core.KeyValue a)
- Language.Jsonnet.Core: newtype Fun
- Language.Jsonnet.Core: newtype Let
- Language.Jsonnet.Eval: eval :: Core -> Eval Value
- Language.Jsonnet.Eval: evalClos :: Ctx -> Fun -> [Arg Thunk] -> Eval Value
- Language.Jsonnet.Eval.Monad: Env :: Ctx -> [Maybe SrcSpan] -> [Maybe (Name Core)] -> Env
- Language.Jsonnet.Eval.Monad: Eval :: ExceptT Error (RWST Env () EvalState (FreshMT IO)) a -> Eval a
- Language.Jsonnet.Eval.Monad: [ctx] :: Env -> Ctx
- Language.Jsonnet.Eval.Monad: [currentPos] :: EvalState -> Maybe SrcSpan
- Language.Jsonnet.Eval.Monad: [scopes] :: Env -> [Maybe (Name Core)]
- Language.Jsonnet.Eval.Monad: [spans] :: Env -> [Maybe SrcSpan]
- Language.Jsonnet.Eval.Monad: data Env
- Language.Jsonnet.Eval.Monad: emptyEnv :: Env
- Language.Jsonnet.Eval.Monad: emptyState :: EvalState
- Language.Jsonnet.Eval.Monad: extendCtx :: Ctx -> Eval a -> Eval a
- Language.Jsonnet.Eval.Monad: instance (GHC.Base.Monoid w, Unbound.Generics.LocallyNameless.Fresh.Fresh m) => Unbound.Generics.LocallyNameless.Fresh.Fresh (Control.Monad.Trans.RWS.Strict.RWST r w s m)
- Language.Jsonnet.Eval.Monad: instance Control.Monad.Catch.MonadCatch Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.Catch.MonadMask Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.Catch.MonadThrow Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.Error.Class.MonadError Language.Jsonnet.Error.Error Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.Fail.MonadFail Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.Fix.MonadFix Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.IO.Class.MonadIO Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.Reader.Class.MonadReader Language.Jsonnet.Eval.Monad.Env Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.State.Class.MonadState Language.Jsonnet.Eval.Monad.EvalState Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance Control.Monad.Writer.Class.MonadWriter () Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance GHC.Base.Applicative Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance GHC.Base.Functor Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance GHC.Base.Monad Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: instance GHC.Generics.Generic (Language.Jsonnet.Eval.Monad.Eval a)
- Language.Jsonnet.Eval.Monad: instance Unbound.Generics.LocallyNameless.Fresh.Fresh Language.Jsonnet.Eval.Monad.Eval
- Language.Jsonnet.Eval.Monad: newtype Eval a
- Language.Jsonnet.Eval.Monad: pushScope :: Name Core -> Eval a -> Eval a
- Language.Jsonnet.Eval.Monad: pushSpan :: Maybe SrcSpan -> Eval a -> Eval a
- Language.Jsonnet.Eval.Monad: runEval :: Env -> Eval a -> ExceptT Error IO a
- Language.Jsonnet.Eval.Monad: withCtx :: Ctx -> Eval a -> Eval a
- Language.Jsonnet.Manifest: forceArray :: Vector Thunk -> Eval (Vector Value)
- Language.Jsonnet.Manifest: forceObject :: Object -> Eval (HashMap Text Value)
- Language.Jsonnet.Manifest: manifest :: Value -> Eval Value
- Language.Jsonnet.Manifest: visibleKeys :: Object -> HashMap Text Thunk
- Language.Jsonnet.Parser: annotateLoc :: Parser (f a) -> Parser (AnnF f SrcSpan a)
- Language.Jsonnet.Parser: applyP :: Parser (Expr' -> Expr')
- Language.Jsonnet.Parser: arrayP :: Parser Expr'
- Language.Jsonnet.Parser: assertP :: Parser Expr'
- Language.Jsonnet.Parser: binary :: Text -> (Expr' -> Expr' -> Expr') -> Operator Parser Expr'
- Language.Jsonnet.Parser: binding :: Parser (String, Expr')
- Language.Jsonnet.Parser: booleanP :: Parser Expr'
- Language.Jsonnet.Parser: braces :: Parser a -> Parser a
- Language.Jsonnet.Parser: brackets :: Parser a -> Parser a
- Language.Jsonnet.Parser: colon :: Parser Text
- Language.Jsonnet.Parser: comma :: Parser Text
- Language.Jsonnet.Parser: errorP :: Parser Expr'
- Language.Jsonnet.Parser: escapeAscii :: Parser Char
- Language.Jsonnet.Parser: escapeUnicode :: Parser Char
- Language.Jsonnet.Parser: exprP :: Parser Expr'
- Language.Jsonnet.Parser: forspecP :: Parser (CompSpec Expr')
- Language.Jsonnet.Parser: function :: Parser [Param Expr'] -> Parser Expr' -> Parser Expr'
- Language.Jsonnet.Parser: functionP :: Parser Expr'
- Language.Jsonnet.Parser: identP :: Parser Expr'
- Language.Jsonnet.Parser: identifier :: Parser String
- Language.Jsonnet.Parser: ifElseP :: Parser Expr'
- Language.Jsonnet.Parser: importP :: Parser Expr'
- Language.Jsonnet.Parser: indexP :: Parser (Expr' -> Expr')
- Language.Jsonnet.Parser: keywordP :: Text -> Parser Text
- Language.Jsonnet.Parser: lexeme :: Parser a -> Parser a
- Language.Jsonnet.Parser: localBndsP :: Parser (NonEmpty (String, Expr'))
- Language.Jsonnet.Parser: localFunc :: Parser (String, Expr')
- Language.Jsonnet.Parser: localP :: Parser Expr'
- Language.Jsonnet.Parser: lookupP :: Parser (Expr' -> Expr')
- Language.Jsonnet.Parser: nullP :: Parser Expr'
- Language.Jsonnet.Parser: numberP :: Parser Expr'
- Language.Jsonnet.Parser: objectP :: Parser Expr'
- Language.Jsonnet.Parser: opTable :: [[Operator Parser Expr']]
- Language.Jsonnet.Parser: paramsP :: Parser [Param Expr']
- Language.Jsonnet.Parser: parens :: Parser a -> Parser a
- Language.Jsonnet.Parser: postfixObjectMerge :: Parser (Expr' -> Expr')
- Language.Jsonnet.Parser: postfixOperators :: Parser (Expr' -> Expr')
- Language.Jsonnet.Parser: prefix :: Text -> (Expr' -> Expr') -> Operator Parser Expr'
- Language.Jsonnet.Parser: primP :: Parser Expr'
- Language.Jsonnet.Parser: reservedKeywords :: [String]
- Language.Jsonnet.Parser: sc :: Parser ()
- Language.Jsonnet.Parser: sliceP :: Parser (Expr' -> Expr')
- Language.Jsonnet.Parser: stringLiteral :: Parser String
- Language.Jsonnet.Parser: stringP :: Parser Expr'
- Language.Jsonnet.Parser: symbol :: Text -> Parser Text
- Language.Jsonnet.Parser: textBlock :: Parser String
- Language.Jsonnet.Parser: type Parser = Parsec Void Text
- Language.Jsonnet.Parser: unquoted :: Parser Expr'
- Language.Jsonnet.Parser: verbatimString :: Parser String
- Language.Jsonnet.Syntax: Field :: a -> a -> Visibility -> Bool -> Field a
- Language.Jsonnet.Syntax: data Field a
- Language.Jsonnet.Syntax: instance Data.Data.Data a => Data.Data.Data (Language.Jsonnet.Syntax.Field a)
- Language.Jsonnet.Syntax: instance Data.Foldable.Foldable Language.Jsonnet.Syntax.Field
- Language.Jsonnet.Syntax: instance Data.Functor.Classes.Show1 Language.Jsonnet.Syntax.Field
- Language.Jsonnet.Syntax: instance Data.Traversable.Traversable Language.Jsonnet.Syntax.Field
- Language.Jsonnet.Syntax: instance GHC.Base.Functor Language.Jsonnet.Syntax.Field
- Language.Jsonnet.Syntax: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Jsonnet.Syntax.Field a)
- Language.Jsonnet.Syntax: instance GHC.Generics.Generic (Language.Jsonnet.Syntax.Field a)
- Language.Jsonnet.Syntax: instance GHC.Read.Read a => GHC.Read.Read (Language.Jsonnet.Syntax.Field a)
- Language.Jsonnet.Syntax: instance GHC.Show.Show a => GHC.Show.Show (Language.Jsonnet.Syntax.Field a)
- Language.Jsonnet.Syntax: instance Unbound.Generics.LocallyNameless.Alpha.Alpha a => Unbound.Generics.LocallyNameless.Alpha.Alpha (Language.Jsonnet.Syntax.Field a)
- Language.Jsonnet.TH: instance Data.Data.Data a => Language.Haskell.TH.Syntax.Lift (Language.Jsonnet.Common.Hideable a)
- Language.Jsonnet.TH: instance Data.Data.Data a => Language.Haskell.TH.Syntax.Lift (Language.Jsonnet.Syntax.Field a)
- Language.Jsonnet.TH: instance Language.Haskell.TH.Syntax.Lift Data.Scientific.Scientific
- Language.Jsonnet.TH: instance Language.Haskell.TH.Syntax.Lift Language.Jsonnet.Common.ArithOp
- Language.Jsonnet.TH: instance Language.Haskell.TH.Syntax.Lift Language.Jsonnet.Common.BitwiseOp
- Language.Jsonnet.TH: instance Language.Haskell.TH.Syntax.Lift Language.Jsonnet.Common.CompOp
- Language.Jsonnet.TH: instance Language.Haskell.TH.Syntax.Lift Language.Jsonnet.Common.LogicalOp
- Language.Jsonnet.Value: TC :: !Ctx -> !Core -> Thunk
- Language.Jsonnet.Value: TV :: !Eval Value -> Thunk
- Language.Jsonnet.Value: data Thunk
- Language.Jsonnet.Value: force :: Thunk -> Eval Value
- Language.Jsonnet.Value: inj' :: (HasValue a, HasValue b) => (a -> b) -> Value -> Eval Value
- Language.Jsonnet.Value: inj'' :: (HasValue a, HasValue b, HasValue c) => (a -> b -> c) -> Value -> Value -> Eval Value
- Language.Jsonnet.Value: instance (Language.Jsonnet.Value.HasValue a, Language.Jsonnet.Value.HasValue b) => Language.Jsonnet.Value.HasValue (a -> Language.Jsonnet.Eval.Monad.Eval b)
- Language.Jsonnet.Value: instance (Language.Jsonnet.Value.HasValue a, Language.Jsonnet.Value.HasValue b) => Language.Jsonnet.Value.HasValue (a -> b)
- Language.Jsonnet.Value: instance (Language.Jsonnet.Value.HasValue a, Language.Jsonnet.Value.HasValue b, Language.Jsonnet.Value.HasValue c) => Language.Jsonnet.Value.HasValue (a -> b -> Language.Jsonnet.Eval.Monad.Eval c)
- Language.Jsonnet.Value: instance (Language.Jsonnet.Value.HasValue a, Language.Jsonnet.Value.HasValue b, Language.Jsonnet.Value.HasValue c) => Language.Jsonnet.Value.HasValue (a -> b -> c)
- Language.Jsonnet.Value: instance GHC.Generics.Generic Language.Jsonnet.Value.Thunk
- Language.Jsonnet.Value: instance GHC.Generics.Generic Language.Jsonnet.Value.Value
- Language.Jsonnet.Value: instance GHC.Real.Integral a => Language.Jsonnet.Value.HasValue a
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue (Data.Vector.Vector Language.Jsonnet.Value.Thunk)
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue Data.ByteString.Internal.ByteString
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue Data.Scientific.Scientific
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue Data.Text.Internal.Text
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue GHC.Types.Bool
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue GHC.Types.Double
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue Language.Jsonnet.Value.Object
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue [GHC.Types.Char]
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue a => Language.Jsonnet.Value.HasValue (Data.Vector.Vector a)
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue a => Language.Jsonnet.Value.HasValue (GHC.Maybe.Maybe a)
- Language.Jsonnet.Value: instance Language.Jsonnet.Value.HasValue a => Language.Jsonnet.Value.HasValue [a]
- Language.Jsonnet.Value: mkThunk' :: Value -> Thunk
- Language.Jsonnet.Value: proj' :: HasValue a => Thunk -> Eval a
- Language.Jsonnet.Value: throwTypeMismatch :: Text -> Value -> Eval a
- Language.Jsonnet.Value: type Array = Vector Thunk
- Language.Jsonnet.Value: valueType :: Value -> Text
+ Language.Jsonnet: VIndir :: !Ref -> Value
+ Language.Jsonnet: VPrim :: !Prim -> Value
+ Language.Jsonnet: VThunk :: !Core -> !Env -> Value
+ Language.Jsonnet: desugar :: Expr -> JsonnetM Core
+ Language.Jsonnet: newtype Config
+ Language.Jsonnet.Common: BinOp :: BinOp -> Prim
+ Language.Jsonnet.Common: Cond :: Prim
+ Language.Jsonnet.Common: Err :: UnyOp
+ Language.Jsonnet.Common: Lookup :: BinOp
+ Language.Jsonnet.Common: UnyOp :: UnyOp -> Prim
+ Language.Jsonnet.Common: data Prim
+ Language.Jsonnet.Common: instance Data.Data.Data Language.Jsonnet.Common.Prim
+ Language.Jsonnet.Common: instance GHC.Classes.Eq Language.Jsonnet.Common.Prim
+ Language.Jsonnet.Common: instance GHC.Generics.Generic Language.Jsonnet.Common.Prim
+ Language.Jsonnet.Common: instance GHC.Show.Show Language.Jsonnet.Common.Prim
+ Language.Jsonnet.Common: instance Unbound.Generics.LocallyNameless.Alpha.Alpha Language.Jsonnet.Common.Prim
+ Language.Jsonnet.Common: newtype Backtrace a
+ Language.Jsonnet.Core: CField :: Core -> Core -> Visibility -> CField
+ Language.Jsonnet.Core: [CApp] :: Core -> Args Core -> Core
+ Language.Jsonnet.Core: [CArr] :: [Core] -> Core
+ Language.Jsonnet.Core: [CComp] :: Comp -> Core -> Core
+ Language.Jsonnet.Core: [CLam] :: Lam -> Core
+ Language.Jsonnet.Core: [CLet] :: Let -> Core
+ Language.Jsonnet.Core: [CLit] :: Literal -> Core
+ Language.Jsonnet.Core: [CLoc] :: SrcSpan -> Core -> Core
+ Language.Jsonnet.Core: [CObj] :: [CField] -> Core
+ Language.Jsonnet.Core: [CPrim] :: Prim -> Core
+ Language.Jsonnet.Core: [CVar] :: Name Core -> Core
+ Language.Jsonnet.Core: [fieldKey] :: CField -> Core
+ Language.Jsonnet.Core: [fieldVal] :: CField -> Core
+ Language.Jsonnet.Core: [fieldVis] :: CField -> Visibility
+ Language.Jsonnet.Core: data CField
+ Language.Jsonnet.Core: instance GHC.Generics.Generic Language.Jsonnet.Core.CField
+ Language.Jsonnet.Core: instance GHC.Show.Show Language.Jsonnet.Core.CField
+ Language.Jsonnet.Core: instance Unbound.Generics.LocallyNameless.Alpha.Alpha Language.Jsonnet.Core.CField
+ Language.Jsonnet.Core: mkField :: Core -> Core -> Visibility -> CField
+ Language.Jsonnet.Core: type Lam = Bind (Rec [Param Core]) Core
+ Language.Jsonnet.Core: type Let = Bind (Rec [(Name Core, Embed Core)]) Core
+ Language.Jsonnet.Error: instance GHC.Exception.Type.Exception Language.Jsonnet.Error.EvalError
+ Language.Jsonnet.Eval: allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
+ Language.Jsonnet.Eval: appDefaults :: [(Name Core, Core)] -> Core -> Eval Value
+ Language.Jsonnet.Eval: append :: Value -> Value -> Eval Text
+ Language.Jsonnet.Eval: equals :: Value -> Value -> Eval Bool
+ Language.Jsonnet.Eval: flattenArrays :: Vector (Vector Value) -> Vector Value
+ Language.Jsonnet.Eval: instance (Language.Jsonnet.Value.HasValue a, Language.Jsonnet.Value.HasValue b) => Language.Jsonnet.Value.HasValue (a -> Language.Jsonnet.Value.Eval b)
+ Language.Jsonnet.Eval: instance (Language.Jsonnet.Value.HasValue a, Language.Jsonnet.Value.HasValue b) => Language.Jsonnet.Value.HasValue (a -> b)
+ Language.Jsonnet.Eval: instance (Language.Jsonnet.Value.HasValue a, Language.Jsonnet.Value.HasValue b, Language.Jsonnet.Value.HasValue c) => Language.Jsonnet.Value.HasValue (a -> b -> Language.Jsonnet.Value.Eval c)
+ Language.Jsonnet.Eval: instance (Language.Jsonnet.Value.HasValue a, Language.Jsonnet.Value.HasValue b, Language.Jsonnet.Value.HasValue c) => Language.Jsonnet.Value.HasValue (a -> b -> c)
+ Language.Jsonnet.Eval: instance GHC.Real.Integral a => Language.Jsonnet.Value.HasValue a
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue Data.ByteString.Internal.ByteString
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue Data.Scientific.Scientific
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue Data.Text.Internal.Text
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue GHC.Types.Bool
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue GHC.Types.Double
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue Language.Jsonnet.Value.Object
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue [GHC.Types.Char]
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue a => Language.Jsonnet.Value.HasValue (Data.Vector.Vector a)
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue a => Language.Jsonnet.Value.HasValue (GHC.Maybe.Maybe a)
+ Language.Jsonnet.Eval: instance Language.Jsonnet.Value.HasValue a => Language.Jsonnet.Value.HasValue [a]
+ Language.Jsonnet.Eval: liftF :: (HasValue a, HasValue b) => (a -> b) -> Value -> Eval Value
+ Language.Jsonnet.Eval: liftF2 :: (HasValue a, HasValue b, HasValue c) => (a -> b -> c) -> Value -> Value -> Eval Value
+ Language.Jsonnet.Eval: liftMaybe :: EvalError -> Maybe a -> Eval a
+ Language.Jsonnet.Eval: lookupVar :: Name Core -> Eval Value
+ Language.Jsonnet.Eval: manifest :: Value -> Eval Value
+ Language.Jsonnet.Eval: mkValue :: Core -> Eval Value
+ Language.Jsonnet.Eval: objectFieldsEx :: Object -> Bool -> [Text]
+ Language.Jsonnet.Eval: objectHasEx :: Object -> Text -> Bool -> Bool
+ Language.Jsonnet.Eval: primitiveEquals :: Value -> Value -> Eval Bool
+ Language.Jsonnet.Eval: proj' :: HasValue a => Value -> Eval a
+ Language.Jsonnet.Eval: rnf :: Core -> Eval Value
+ Language.Jsonnet.Eval: showTy :: Value -> Eval Text
+ Language.Jsonnet.Eval: splitArgs :: [Arg b1] -> [(Name a1, b2)] -> EvalM a2 ([(Name a1, b2)], [(Name a1, b1)], [(Name a1, b1)])
+ Language.Jsonnet.Eval: throwTypeMismatch :: Text -> Value -> Eval a
+ Language.Jsonnet.Eval: toString :: Value -> Eval Text
+ Language.Jsonnet.Eval: visibleKeys :: Object -> HashMap Text Value
+ Language.Jsonnet.Eval: whnf :: Core -> Eval Value
+ Language.Jsonnet.Eval: whnfApp :: Core -> Args Core -> Eval Value
+ Language.Jsonnet.Eval: whnfArgs :: Args Core -> Eval [Arg Value]
+ Language.Jsonnet.Eval: whnfBinOp :: BinOp -> Value -> Value -> Eval Value
+ Language.Jsonnet.Eval: whnfClos :: Env -> Lam -> [Arg Value] -> Eval Value
+ Language.Jsonnet.Eval: whnfComp :: Comp -> Core -> Eval Value
+ Language.Jsonnet.Eval: whnfCond :: Value -> Value -> Value -> Eval Value
+ Language.Jsonnet.Eval: whnfField :: Env -> CField -> Eval (Maybe (Text, VField))
+ Language.Jsonnet.Eval: whnfIndir :: Ref -> Eval Value
+ Language.Jsonnet.Eval: whnfLetrec :: Let -> Eval Value
+ Language.Jsonnet.Eval: whnfLiteral :: Literal -> Value
+ Language.Jsonnet.Eval: whnfLogical :: HasValue a => (a -> Bool) -> Value -> Value -> Eval Value
+ Language.Jsonnet.Eval: whnfLookup :: Value -> Value -> Eval Value
+ Language.Jsonnet.Eval: whnfObj :: [CField] -> Eval Value
+ Language.Jsonnet.Eval: whnfPrim :: Prim -> [Arg Value] -> Eval Value
+ Language.Jsonnet.Eval: whnfUnyOp :: UnyOp -> Value -> Eval Value
+ Language.Jsonnet.Eval: whnfV :: Value -> Eval Value
+ Language.Jsonnet.Eval: withStackFrame :: Core -> Eval a -> Eval a
+ Language.Jsonnet.Eval.Monad: CallStack :: [Maybe SrcSpan] -> [Name Core] -> CallStack
+ Language.Jsonnet.Eval.Monad: EvalM :: ExceptT Error (ReaderT (EvalState a) (FreshMT IO)) b -> EvalM a b
+ Language.Jsonnet.Eval.Monad: [_callStack] :: EvalState a -> CallStack
+ Language.Jsonnet.Eval.Monad: [_ctx] :: EvalState a -> Ctx a
+ Language.Jsonnet.Eval.Monad: [_currentPos] :: EvalState a -> Maybe SrcSpan
+ Language.Jsonnet.Eval.Monad: [_scopes] :: CallStack -> [Name Core]
+ Language.Jsonnet.Eval.Monad: [_spans] :: CallStack -> [Maybe SrcSpan]
+ Language.Jsonnet.Eval.Monad: callStack :: forall a_aZwG. Lens' (EvalState a_aZwG) CallStack
+ Language.Jsonnet.Eval.Monad: ctx :: forall a_aZwG a_aZDT. Lens (EvalState a_aZwG) (EvalState a_aZDT) (Ctx a_aZwG) (Ctx a_aZDT)
+ Language.Jsonnet.Eval.Monad: currentPos :: forall a_aZwG. Lens' (EvalState a_aZwG) (Maybe SrcSpan)
+ Language.Jsonnet.Eval.Monad: data CallStack
+ Language.Jsonnet.Eval.Monad: emptyStack :: CallStack
+ Language.Jsonnet.Eval.Monad: extendEnv :: Ctx a -> EvalM a b -> EvalM a b
+ Language.Jsonnet.Eval.Monad: instance Control.Monad.Catch.MonadCatch (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance Control.Monad.Catch.MonadMask (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance Control.Monad.Catch.MonadThrow (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance Control.Monad.Error.Class.MonadError Language.Jsonnet.Error.Error (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance Control.Monad.Fail.MonadFail (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance Control.Monad.Fix.MonadFix (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance Control.Monad.IO.Class.MonadIO (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance Control.Monad.Reader.Class.MonadReader (Language.Jsonnet.Eval.Monad.EvalState a) (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance GHC.Base.Applicative (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance GHC.Base.Functor (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance GHC.Base.Monad (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: instance Unbound.Generics.LocallyNameless.Fresh.Fresh (Language.Jsonnet.Eval.Monad.EvalM a)
+ Language.Jsonnet.Eval.Monad: newtype EvalM a b
+ Language.Jsonnet.Eval.Monad: pushStackFrame :: (Name Core, Maybe SrcSpan) -> EvalM a b -> EvalM a b
+ Language.Jsonnet.Eval.Monad: runEvalM :: Ctx a -> EvalM a b -> IO (Either Error b)
+ Language.Jsonnet.Eval.Monad: scopes :: Lens' CallStack [Name Core]
+ Language.Jsonnet.Eval.Monad: spans :: Lens' CallStack [Maybe SrcSpan]
+ Language.Jsonnet.Syntax: EField :: a -> a -> Visibility -> Bool -> EField a
+ Language.Jsonnet.Syntax: data EField a
+ Language.Jsonnet.Syntax: instance Data.Data.Data a => Data.Data.Data (Language.Jsonnet.Syntax.EField a)
+ Language.Jsonnet.Syntax: instance Data.Foldable.Foldable Language.Jsonnet.Syntax.EField
+ Language.Jsonnet.Syntax: instance Data.Functor.Classes.Show1 Language.Jsonnet.Syntax.EField
+ Language.Jsonnet.Syntax: instance Data.Traversable.Traversable Language.Jsonnet.Syntax.EField
+ Language.Jsonnet.Syntax: instance GHC.Base.Functor Language.Jsonnet.Syntax.EField
+ Language.Jsonnet.Syntax: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Jsonnet.Syntax.EField a)
+ Language.Jsonnet.Syntax: instance GHC.Generics.Generic (Language.Jsonnet.Syntax.EField a)
+ Language.Jsonnet.Syntax: instance GHC.Read.Read a => GHC.Read.Read (Language.Jsonnet.Syntax.EField a)
+ Language.Jsonnet.Syntax: instance GHC.Show.Show a => GHC.Show.Show (Language.Jsonnet.Syntax.EField a)
+ Language.Jsonnet.Syntax: instance Unbound.Generics.LocallyNameless.Alpha.Alpha a => Unbound.Generics.LocallyNameless.Alpha.Alpha (Language.Jsonnet.Syntax.EField a)
+ Language.Jsonnet.TH: instance Data.Data.Data a => Language.Haskell.TH.Syntax.Lift (Language.Jsonnet.Syntax.EField a)
+ Language.Jsonnet.TH: instance Language.Haskell.TH.Syntax.Lift Language.Jsonnet.Common.Prim
+ Language.Jsonnet.Value: Cell :: Value -> Bool -> Cell
+ Language.Jsonnet.Value: VField :: Value -> Value -> Value -> Visibility -> VField
+ Language.Jsonnet.Value: VIndir :: !Ref -> Value
+ Language.Jsonnet.Value: VPrim :: !Prim -> Value
+ Language.Jsonnet.Value: VThunk :: !Core -> !Env -> Value
+ Language.Jsonnet.Value: [cellIsWHNF] :: Cell -> Bool
+ Language.Jsonnet.Value: [cellVal] :: Cell -> Value
+ Language.Jsonnet.Value: [fieldKey] :: VField -> Value
+ Language.Jsonnet.Value: [fieldValWHNF] :: VField -> Value
+ Language.Jsonnet.Value: [fieldVal] :: VField -> Value
+ Language.Jsonnet.Value: [fieldVis] :: VField -> Visibility
+ Language.Jsonnet.Value: allocate :: MonadIO m => Value -> m (IORef Cell)
+ Language.Jsonnet.Value: data Cell
+ Language.Jsonnet.Value: data VField
+ Language.Jsonnet.Value: instance GHC.Generics.Generic Language.Jsonnet.Value.Cell
+ Language.Jsonnet.Value: instance GHC.Generics.Generic Language.Jsonnet.Value.VField
+ Language.Jsonnet.Value: instance Language.Jsonnet.Common.HasVisibility Language.Jsonnet.Value.VField
+ Language.Jsonnet.Value: mkCell :: Value -> Cell
+ Language.Jsonnet.Value: mkIndirV :: MonadIO m => Value -> m Value
+ Language.Jsonnet.Value: type Env = Ctx Value
+ Language.Jsonnet.Value: type Eval = EvalM Value
+ Language.Jsonnet.Value: type Fun = Value -> Eval Value
+ Language.Jsonnet.Value: type Ref = IORef Cell
- Language.Jsonnet: Config :: FilePath -> Thunk -> Config
+ Language.Jsonnet: Config :: FilePath -> Config
- Language.Jsonnet: VArr :: !Array -> Value
+ Language.Jsonnet: VArr :: !Vector Value -> Value
- Language.Jsonnet: VClos :: !Fun -> !Env -> Value
+ Language.Jsonnet: VClos :: !Lam -> !Env -> Value
- Language.Jsonnet: VFun :: !Thunk -> Eval Value -> Value
+ Language.Jsonnet: VFun :: !Fun -> Value
- Language.Jsonnet: VObj :: !HashMap Text (Hideable Thunk) -> Value
+ Language.Jsonnet: VObj :: !Object -> Value
- Language.Jsonnet.Common: Add :: ArithOp
+ Language.Jsonnet.Common: Add :: BinOp
- Language.Jsonnet.Common: And :: BitwiseOp
+ Language.Jsonnet.Common: And :: BinOp
- Language.Jsonnet.Common: Div :: ArithOp
+ Language.Jsonnet.Common: Div :: BinOp
- Language.Jsonnet.Common: Eq :: CompOp
+ Language.Jsonnet.Common: Eq :: BinOp
- Language.Jsonnet.Common: Ge :: CompOp
+ Language.Jsonnet.Common: Ge :: BinOp
- Language.Jsonnet.Common: Gt :: CompOp
+ Language.Jsonnet.Common: Gt :: BinOp
- Language.Jsonnet.Common: LAnd :: LogicalOp
+ Language.Jsonnet.Common: LAnd :: BinOp
- Language.Jsonnet.Common: LOr :: LogicalOp
+ Language.Jsonnet.Common: LOr :: BinOp
- Language.Jsonnet.Common: Le :: CompOp
+ Language.Jsonnet.Common: Le :: BinOp
- Language.Jsonnet.Common: Lt :: CompOp
+ Language.Jsonnet.Common: Lt :: BinOp
- Language.Jsonnet.Common: Mod :: ArithOp
+ Language.Jsonnet.Common: Mod :: BinOp
- Language.Jsonnet.Common: Mul :: ArithOp
+ Language.Jsonnet.Common: Mul :: BinOp
- Language.Jsonnet.Common: Ne :: CompOp
+ Language.Jsonnet.Common: Ne :: BinOp
- Language.Jsonnet.Common: Or :: BitwiseOp
+ Language.Jsonnet.Common: Or :: BinOp
- Language.Jsonnet.Common: ShiftL :: BitwiseOp
+ Language.Jsonnet.Common: ShiftL :: BinOp
- Language.Jsonnet.Common: ShiftR :: BitwiseOp
+ Language.Jsonnet.Common: ShiftR :: BinOp
- Language.Jsonnet.Common: StackFrame :: Maybe (Name a) -> SrcSpan -> StackFrame a
+ Language.Jsonnet.Common: StackFrame :: Name a -> SrcSpan -> StackFrame a
- Language.Jsonnet.Common: Sub :: ArithOp
+ Language.Jsonnet.Common: Sub :: BinOp
- Language.Jsonnet.Common: Xor :: BitwiseOp
+ Language.Jsonnet.Common: Xor :: BinOp
- Language.Jsonnet.Common: [name] :: StackFrame a -> Maybe (Name a)
+ Language.Jsonnet.Common: [name] :: StackFrame a -> Name a
- Language.Jsonnet.Core: ObjC :: Bind (Name Core) (KeyValue Core, Maybe Core) -> Comp
+ Language.Jsonnet.Core: ObjC :: Bind (Name Core) (CField, Maybe Core) -> Comp
- Language.Jsonnet.Core: type Param a = (Name a, Embed (Maybe a))
+ Language.Jsonnet.Core: type Param a = (Name a, Embed a)
- Language.Jsonnet.Eval: mergeWith :: Object -> Object -> Object
+ Language.Jsonnet.Eval: mergeWith :: Object -> Object -> Eval Value
- Language.Jsonnet.Eval.Monad: EvalState :: Maybe SrcSpan -> EvalState
+ Language.Jsonnet.Eval.Monad: EvalState :: Ctx a -> CallStack -> Maybe SrcSpan -> EvalState a
- Language.Jsonnet.Eval.Monad: [unEval] :: Eval a -> ExceptT Error (RWST Env () EvalState (FreshMT IO)) a
+ Language.Jsonnet.Eval.Monad: [unEval] :: EvalM a b -> ExceptT Error (ReaderT (EvalState a) (FreshMT IO)) b
- Language.Jsonnet.Eval.Monad: data EvalState
+ Language.Jsonnet.Eval.Monad: data EvalState a
- Language.Jsonnet.Eval.Monad: getBacktrace :: Eval (Backtrace Core)
+ Language.Jsonnet.Eval.Monad: getBacktrace :: EvalM a (Backtrace Core)
- Language.Jsonnet.Eval.Monad: throwE :: EvalError -> Eval a
+ Language.Jsonnet.Eval.Monad: throwE :: EvalError -> EvalM a b
- Language.Jsonnet.Eval.Monad: type Ctx = Map (Name Core) Thunk
+ Language.Jsonnet.Eval.Monad: type Ctx a = Map (Name Core) a
- Language.Jsonnet.Eval.Monad: withEnv :: Env -> Eval a -> Eval a
+ Language.Jsonnet.Eval.Monad: withEnv :: Ctx a -> EvalM a b -> EvalM a b
- Language.Jsonnet.Syntax: EObj :: [(Ident, a)] -> [Field a] -> ExprF a
+ Language.Jsonnet.Syntax: EObj :: [(Ident, a)] -> [EField a] -> ExprF a
- Language.Jsonnet.Syntax: EObjComp :: Field a -> [(Ident, a)] -> NonEmpty (CompSpec a) -> ExprF a
+ Language.Jsonnet.Syntax: EObjComp :: EField a -> [(Ident, a)] -> NonEmpty (CompSpec a) -> ExprF a
- Language.Jsonnet.Syntax: [field] :: ExprF a -> Field a
+ Language.Jsonnet.Syntax: [field] :: ExprF a -> EField a
- Language.Jsonnet.Syntax: [fields] :: ExprF a -> [Field a]
+ Language.Jsonnet.Syntax: [fields] :: ExprF a -> [EField a]
- Language.Jsonnet.Syntax: [key] :: Field a -> a
+ Language.Jsonnet.Syntax: [key] :: EField a -> a
- Language.Jsonnet.Syntax: [override] :: Field a -> Bool
+ Language.Jsonnet.Syntax: [override] :: EField a -> Bool
- Language.Jsonnet.Syntax: [value] :: Field a -> a
+ Language.Jsonnet.Syntax: [value] :: EField a -> a
- Language.Jsonnet.Syntax: [visibility] :: Field a -> Visibility
+ Language.Jsonnet.Syntax: [visibility] :: EField a -> Visibility
- Language.Jsonnet.Syntax: mkObjCompF :: Field a -> [(Ident, a)] -> NonEmpty (CompSpec a) -> ExprF' a
+ Language.Jsonnet.Syntax: mkObjCompF :: EField a -> [(Ident, a)] -> NonEmpty (CompSpec a) -> ExprF' a
- Language.Jsonnet.Syntax: mkObjectF :: [Field a] -> [(Ident, a)] -> ExprF' a
+ Language.Jsonnet.Syntax: mkObjectF :: [EField a] -> [(Ident, a)] -> ExprF' a
- Language.Jsonnet.Value: VArr :: !Array -> Value
+ Language.Jsonnet.Value: VArr :: !Vector Value -> Value
- Language.Jsonnet.Value: VClos :: !Fun -> !Env -> Value
+ Language.Jsonnet.Value: VClos :: !Lam -> !Env -> Value
- Language.Jsonnet.Value: VFun :: !Thunk -> Eval Value -> Value
+ Language.Jsonnet.Value: VFun :: !Fun -> Value
- Language.Jsonnet.Value: VObj :: !HashMap Text (Hideable Thunk) -> Value
+ Language.Jsonnet.Value: VObj :: !Object -> Value
- Language.Jsonnet.Value: mkThunk :: MonadIO m => Eval Value -> m Thunk
+ Language.Jsonnet.Value: mkThunk :: Core -> Eval Value
- Language.Jsonnet.Value: type Object = HashMap Text (Hideable Thunk)
+ Language.Jsonnet.Value: type Object = HashMap Text VField

Files

README.md view
@@ -8,6 +8,28 @@ For an introduction to the language itself, see the [tutorial][tutorial] or language [reference][reference]. We are using the same test suite used in the offical [C++][cpp-jsonnet] and [Go][go-jsonnet] implementation (which is fairly comprehensive). +## Progress++Here is the implementation status of the main language features:++- [X] array and object comprehension+- [X] array slices+- [X] Python-style string formatting+- [X] text blocks+- [X] verbatim strings+- [X] object-level locals+- [ ] object-level asserts+- [X] keyword parameters+- [X] default arguments+- [ ] top-level arguments+- [ ] external variables+- [X] hidden fields ([@CristhianMotoche](https://github.com/CristhianMotoche)) +- [X] tailstrict annotation+- [X] outermost object reference `$`+- [X] mixin inheritence (operator `+` with `self` and `super`)+- [X] field composition (operator `+:`)+- [ ] multiple file output+ ## Build  Using the [stack][stack] build tool:@@ -96,32 +118,7 @@  See the Standard library [documentation][stdlib] for more details. -## Progress -Here is the implementation status of the main language features:--- [X] array and object comprehension-- [X] array slices-- [X] Python-style string formatting-- [X] text blocks-- [X] verbatim strings-- [X] object-level locals-- [ ] object-level asserts-- [X] keyword parameters-- [X] default arguments-- [ ] top-level arguments-- [ ] external variables-- [X] hidden fields ([@CristhianMotoche](https://github.com/CristhianMotoche)) -- [X] tailstrict annotation--OO features are implemented but need some more work:--- [X] `self` keyword-- [X] `super` keyword-- [X] outermost object reference `$`-- [X] object composition (merging objects)-- [X] field composition (`+:` field syntax)- [//]: # "Implementation overview"  ## Benchmarks@@ -135,7 +132,7 @@  ## Acknowledgments -I took inspiration from [Expresso][Expresso], [hnix][hnix], [fixplate][fixplate], +I took inspiration from [Expresso][Expresso], [hnix][hnix], [fixplate][fixplate], [Disco][disco],  and numerous other libraries. Thanks to their authors.  ## License@@ -151,6 +148,7 @@ [Expresso]: https://github.com/willtim/Expresso [hnix]: https://github.com/haskell-nix/hnix [fixplate]: https://hackage.haskell.org/package/fixplate+[disco]: https://github.com/disco-lang/disco [contributing]: https://github.com/moleike/haskell-jsonnet/blob/master/CONTRIBUTING.md [license]: https://github.com/moleike/haskell-jsonnet/blob/master/LICENSE [cpp-jsonnet]: https://github.com/google/jsonnet
app/Main.hs view
@@ -22,11 +22,7 @@ import Language.Jsonnet.Desugar import Language.Jsonnet.Error import Language.Jsonnet.Eval-import Language.Jsonnet.Eval (mergeWith)-import Language.Jsonnet.Eval.Monad-import qualified Language.Jsonnet.Std.Lib as Lib-import Language.Jsonnet.Std.TH (mkStdlib)-import Language.Jsonnet.Value+-- import Language.Jsonnet.Value import Options.Applicative import Paths_jsonnet (version) import Text.PrettyPrint.ANSI.Leijen (Pretty, pretty)@@ -36,7 +32,10 @@   runProgram =<< execParser options   return () -runProgram :: Options -> IO ()+runProgram ::+  -- |+  Options ->+  IO () runProgram opts@Options {..} = do   src <- readSource input   conf <- mkConfig opts@@ -68,22 +67,12 @@   FileInput path -> TIO.readFile path   ExecInput str -> pure (T.pack str) --- the jsonnet stdlib is written in both jsonnet and Haskell, here we merge--- the native (a small subset) with the interpreted (the splice mkStdlib)--std :: Eval Value-std = eval core >>= flip mergeObjects Lib.std-  where-    core = desugar (annMap (const ()) $mkStdlib)-    mergeObjects (VObj x) (VObj y) = pure $ VObj (x `mergeWith` y)- mkConfig :: Options -> IO Config mkConfig Options {..} = do   let fname = case input of         Stdin -> ""         FileInput path -> path         ExecInput _ -> ""-  stdlib <- mkThunk std   pure Config {..}  fileOutput :: Parser Output
+ benchmarks/Bench.hs view
@@ -0,0 +1,113 @@+{-# LANGUAGE QuasiQuotes #-}++import qualified Data.ByteString.Lazy as LBS+import Data.Text.Lazy+import Data.Text.Lazy.Encoding (encodeUtf8)+import Language.Jsonnet+import Language.Jsonnet.Core (Core)+import Language.Jsonnet.Syntax.Annotated (Expr)+import Language.Jsonnet.TH.QQ+import Test.Tasty.Bench+import Text.PrettyPrint.ANSI.Leijen (Pretty, pretty)++render :: Pretty a => a -> LBS.ByteString+render = encodeUtf8 . pack . show . pretty++conf = Config ""++eval :: Expr -> IO LBS.ByteString+eval expr = do+  outp <- runJsonnetM conf (desugar expr >>= evaluate)+  pure (either render render outp)++main :: IO ()+main =+  defaultMain+    [ bgroup+        "simple"+        [ bench "bench01" $ nfAppIO eval bench01,+          bench "bench02" $ nfAppIO eval bench02,+          bench "bench03" $ nfAppIO eval bench03+        ],+      bgroup+        "caching"+        [ bench "bench08" $ nfAppIO eval bench08+        ],+      bgroup+        "stdlib"+        [ bench "bench04" $ nfAppIO eval bench04+        , bench "bench06" $ nfAppIO eval bench06+        ]+    ]++bench01 =+  [jsonnet|+    local sum(x) =+      if x == 0 then+      0+      else+      x + sum(x - 1);+    sum(300)+  |]++bench02 =+  [jsonnet|+    local Fib = {+      n: 1,+      local outer = self,+      r: if self.n <= 1+           then 1+           else (Fib { n: outer.n - 1 }).r + (Fib { n: outer.n - 2 }).r,+    };++    (Fib { n: 25 }).r+  |]++bench03 =+  [jsonnet|+    local fibonacci(n) =+      if n <= 1 then+        1+      else+        fibonacci(n - 1) + fibonacci(n - 2);+    fibonacci(25)+  |]++bench04 =+  [jsonnet|+    std.foldl(function(e, res) e + res, std.makeArray(20000, function(i) 'aaaaa'), '')+  |]++bench06 =+  [jsonnet|+    // A benchmark for builtin sort++    local reverse = std.reverse;+    local sort = std.sort;++    true+    && std.assertEqual(std.range(1, 500), sort(std.range(1, 500)))+    && std.assertEqual(std.range(1, 1000), sort(std.range(1, 1000)))+    && std.assertEqual(reverse(std.range(1, 1000)), sort(std.range(1, 1000), keyF=function(x) -x))+    && std.assertEqual(std.range(1, 1000), sort(reverse(std.range(1, 1000))))+    && std.assertEqual(std.makeArray(2000, function(i) std.floor((i + 2) / 2)), sort(std.range(1, 1000) + reverse(std.range(1, 1000))))+  |]++bench08 =+  [jsonnet|+    local fib(n) =+      local fibnext = {+        a: super.a + super.b,+        b: super.a,+      };++      local go(n) =+        if n == 0 then+          { a: 1, b: 1 }+        else+          go(n - 1) + fibnext;++      go(n).b;++    fib(25)+  |]
jsonnet.cabal view
@@ -1,6 +1,6 @@ cabal-version:  2.2 name:           jsonnet-version:        0.2.0.0+version:        0.3.0.0 synopsis:       Jsonnet implementaton in pure Haskell description:    Please see the README on GitHub at <https://github.com/moleike/jsonnet-haskell#readme> homepage:       https://github.com/moleike/haskell-jsonnet#readme@@ -43,7 +43,6 @@     , Language.Jsonnet.Core     , Language.Jsonnet.Check     , Language.Jsonnet.Desugar-    , Language.Jsonnet.Manifest   autogen-modules:       Paths_jsonnet   other-modules:@@ -52,29 +51,31 @@   hs-source-dirs:       src   build-depends:-    aeson                 >= 1.5.6 && < 1.6,-    base                  >= 4.15.0 && < 4.16,-    bytestring            >= 0.10.12 && < 0.11,-    containers            >= 0.6.4 && < 0.7,-    scientific            >= 0.3.6 && < 0.4,-    hashable              >= 1.3.1 && < 1.4,-    text                  >= 1.2.4 && < 1.3,-    template-haskell      >= 2.17.0 && < 2.18,-    data-fix              >= 0.3.1 && < 0.4,-    transformers-compat   >= 0.6.6 && < 0.7,-    unordered-containers  >= 0.2.13 && < 0.3,-    mtl                   >= 2.2.2 && < 2.3,-    vector                >= 0.12.2 && < 0.13,-    ansi-wl-pprint        >= 0.6.9 && < 0.7,-    deriving-compat       >= 0.5.10 && < 0.6,-    directory             >= 1.3.6 && < 1.4,-    filepath              >= 1.4.2 && < 1.5,-    exceptions            >= 0.10.4 && < 0.11,-    megaparsec            >= 9.0.1 && < 9.1,-    parser-combinators    >= 1.3.0 && < 1.4,-    semigroupoids         >= 5.3.5 && < 5.4,-    unbound-generics      >= 0.4.1 && < 0.5,-    optparse-applicative  >= 0.16.1 && < 0.17+      aeson                         >= 1.5.6 && < 1.6,+      base                          >= 4.15.0 && < 4.16,+      bytestring                    >= 0.10.12 && < 0.11,+      containers                    >= 0.6.4 && < 0.7,+      scientific                    >= 0.3.7 && < 0.4,+      hashable                      >= 1.3.2 && < 1.4,+      text                          >= 1.2.4 && < 1.3,+      template-haskell              >= 2.17.0 && < 2.18,+      data-fix                      >= 0.3.1 && < 0.4,+      transformers-compat           >= 0.6.6 && < 0.7,+      unordered-containers          >= 0.2.14 && < 0.3,+      mtl                           >= 2.2.2 && < 2.3,+      vector                        >= 0.12.3 && < 0.13,+      ansi-wl-pprint                >= 0.6.9 && < 0.7,+      deriving-compat               >= 0.5.10 && < 0.6,+      directory                     >= 1.3.6 && < 1.4,+      filepath                      >= 1.4.2 && < 1.5,+      exceptions                    >= 0.10.4 && < 0.11,+      lens                          >= 5.0.1 && < 5.1,+      semigroupoids                 >= 5.3.5 && < 5.4,+      megaparsec                    >= 9.0.1 && < 9.1,+      parser-combinators            >= 1.3.0 && < 1.4,+      unbound-generics              >= 0.4.1 && < 0.5,+      th-utilities                  == 0.2.4.2+   default-language: Haskell2010   default-extensions:       MultiParamTypeClasses@@ -85,20 +86,22 @@  executable hs-jsonnet   main-is: Main.hs+  autogen-modules:+      Paths_jsonnet   other-modules:       Paths_jsonnet   hs-source-dirs:       app-  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  ghc-options: -O2 -threaded -rtsopts -with-rtsopts=-N   build-depends:-      jsonnet-    , base-    , optparse-applicative-    , text-    , ansi-wl-pprint-    , mtl-    , bytestring-    , aeson+      jsonnet,+      aeson,+      base,+      bytestring,+      text,+      mtl,+      ansi-wl-pprint,+      optparse-applicative >= 0.16.1 && < 0.17   default-language: Haskell2010  test-suite jsonnet-test@@ -108,7 +111,7 @@       Paths_jsonnet   hs-source-dirs:       test/golden-  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  ghc-options: -O2 -threaded -rtsopts -with-rtsopts=-N   build-depends:       base     , ansi-wl-pprint@@ -121,3 +124,21 @@     , tasty-golden     , tasty-hunit   default-language: Haskell2010++benchmark jsonnet-bench+  main-is: Bench.hs+  type: exitcode-stdio-1.0+  hs-source-dirs:+      benchmarks+  build-depends:+      base+    , tasty-bench+    , jsonnet+    , bytestring+    , text+    , ansi-wl-pprint+  default-language: Haskell2010+  if impl(ghc >= 8.10)+    ghc-options: "-with-rtsopts=-A32m --nonmoving-gc"+  else+    ghc-options: "-with-rtsopts=-A32m"
src/Language/Jsonnet.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}  module Language.Jsonnet   ( JsonnetM,@@ -13,6 +14,7 @@     runJsonnetM,     parse,     evaluate,+    desugar,   ) where @@ -22,19 +24,23 @@ import qualified Data.Aeson as JSON import Data.Functor.Identity import Data.Functor.Sum+import qualified Data.Map.Lazy as M import Data.Map.Strict (singleton) import Data.Text (Text) import qualified Data.Text.IO as T (readFile) import Debug.Trace import Language.Jsonnet.Annotate import qualified Language.Jsonnet.Check as Check+import Language.Jsonnet.Common import Language.Jsonnet.Core import qualified Language.Jsonnet.Desugar as Desugar import Language.Jsonnet.Error import Language.Jsonnet.Eval-import Language.Jsonnet.Manifest (manifest)+import Language.Jsonnet.Eval.Monad import qualified Language.Jsonnet.Parser as Parser import Language.Jsonnet.Pretty ()+import qualified Language.Jsonnet.Std.Lib as Lib+import Language.Jsonnet.Std.TH (mkStdlib) import Language.Jsonnet.Syntax.Annotated import Language.Jsonnet.Value @@ -55,9 +61,8 @@       MonadFail     ) -data Config = Config-  { fname :: FilePath,-    stdlib :: Thunk+newtype Config = Config+  { fname :: FilePath   }  runJsonnetM :: Config -> JsonnetM a -> IO (Either Error a)@@ -85,12 +90,19 @@   pure expr  desugar :: Expr -> JsonnetM Core-desugar expr = pure (Desugar.desugar expr)+desugar = pure . Desugar.desugar --- evaluate a Core expression with the implicit stdlib+-- | evaluate a Core expression with the implicit stdlib evaluate :: Core -> JsonnetM JSON.Value evaluate expr = do-  ctx <- singleton "std" <$> asks stdlib-  JsonnetM $-    lift $-      runEval (emptyEnv {ctx = ctx}) ((eval >=> manifest) expr)+  env <- singleton "std" <$> std+  JsonnetM $ lift $ ExceptT $ runEvalM env (rnf expr)++-- | the jsonnet stdlib is written in both jsonnet and Haskell, here we merge+--   the native (a small subset) with the interpreted (the splice mkStdlib)+std :: JsonnetM Value+std = JsonnetM $ lift $ ExceptT $ runEvalM M.empty stdlib+  where+    stdlib = whnf core >>= flip mergeObjects Lib.std+    core = Desugar.desugar (annMap (const ()) $mkStdlib)+    mergeObjects x y = whnfPrim (BinOp Add) [Pos x, Pos y]
src/Language/Jsonnet/Common.hs view
@@ -1,10 +1,14 @@+{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}  module Language.Jsonnet.Common where @@ -34,42 +38,46 @@   subst _ _ = id   substs _ = id +data Prim+  = UnyOp UnyOp+  | BinOp BinOp+  | Cond+  deriving (Show, Eq, Generic, Typeable, Data)++instance Alpha Prim+ data BinOp-  = Arith ArithOp-  | Comp CompOp-  | Bitwise BitwiseOp-  | Logical LogicalOp+  = Add+  | Sub+  | Mul+  | Div+  | Mod+  | Lt+  | Le+  | Gt+  | Ge+  | Eq+  | Ne+  | And+  | Or+  | Xor+  | ShiftL+  | ShiftR+  | LAnd+  | LOr   | In+  | Lookup   deriving (Show, Eq, Generic, Typeable, Data) +instance Alpha BinOp+ data UnyOp   = Compl   | LNot   | Plus   | Minus-  deriving (Show, Eq, Enum, Bounded, Generic, Typeable, Data)--data ArithOp = Add | Sub | Mul | Div | Mod-  deriving (Show, Eq, Enum, Bounded, Generic, Typeable, Data)--data CompOp = Lt | Le | Gt | Ge | Eq | Ne-  deriving (Show, Eq, Enum, Bounded, Generic, Typeable, Data)--data BitwiseOp = And | Or | Xor | ShiftL | ShiftR-  deriving (Show, Eq, Enum, Bounded, Generic, Typeable, Data)--data LogicalOp = LAnd | LOr-  deriving (Show, Eq, Enum, Bounded, Generic, Typeable, Data)--instance Alpha ArithOp--instance Alpha BinOp--instance Alpha CompOp--instance Alpha BitwiseOp--instance Alpha LogicalOp+  | Err+  deriving (Show, Eq, Generic, Typeable, Data)  instance Alpha UnyOp @@ -159,18 +167,12 @@ instance Alpha a => Alpha (CompSpec a)  data StackFrame a = StackFrame-  { name :: Maybe (Name a),+  { name :: Name a,     span :: SrcSpan   }   deriving (Eq, Show) -pushStackFrame ::-  StackFrame a ->-  Backtrace a ->-  Backtrace a-pushStackFrame x (Backtrace xs) = Backtrace (x : xs)--data Backtrace a = Backtrace [StackFrame a]+newtype Backtrace a = Backtrace [StackFrame a]   deriving (Eq, Show)  data Visibility = Visible | Hidden | Forced@@ -189,26 +191,3 @@   visible :: a -> Bool   forced :: a -> Bool   hidden :: a -> Bool--data Hideable a = Hideable {value :: a, visiblity :: Visibility}-  deriving-    ( Eq,-      Read,-      Show,-      Generic,-      Functor,-      Typeable,-      Data-    )--instance Alpha a => Alpha (Hideable a)--instance HasVisibility (Hideable a) where-  visible (Hideable _ Visible) = True-  visible _ = False--  forced (Hideable _ Forced) = True-  forced _ = False--  hidden (Hideable _ Hidden) = True-  hidden _ = False
src/Language/Jsonnet/Core.hs view
@@ -1,9 +1,11 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTSyntax #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE StandaloneDeriving #-}  module Language.Jsonnet.Core where@@ -16,46 +18,47 @@ import Language.Jsonnet.Parser.SrcSpan import Unbound.Generics.LocallyNameless -type Param a = (Name a, Embed (Maybe a))--data KeyValue a = KeyValue a (Hideable a)-  deriving (Show, Typeable, Generic)--instance Alpha a => Alpha (KeyValue a)+type Param a = (Name a, Embed a) -newtype Fun = Fun (Bind (Rec [Param Core]) Core)-  deriving (Show, Typeable, Generic)+data CField = CField+  { -- |+    fieldKey :: Core,+    -- |+    fieldVal :: Core,+    -- |+    fieldVis :: Visibility+  }+  deriving (Show, Generic) -instance Alpha Fun+mkField :: Core -> Core -> Visibility -> CField+mkField = CField -newtype Let-  = Let (Bind (Rec [(Name Core, Embed Core)]) Core)-  deriving (Show, Typeable, Generic)+--pattern CField k v h <- CField_ k _ v h -instance Alpha Let+instance Alpha CField  data Comp   = ArrC (Bind (Name Core) (Core, Maybe Core))-  | ObjC (Bind (Name Core) (KeyValue Core, Maybe Core))+  | ObjC (Bind (Name Core) (CField, Maybe Core))   deriving (Show, Typeable, Generic)  instance Alpha Comp -data Core-  = CLoc SrcSpan Core-  | CLit Literal-  | CVar (Name Core)-  | CFun Fun-  | CApp Core (Args Core)-  | CLet Let-  | CObj [KeyValue Core]-  | CArr [Core]-  | CBinOp BinOp Core Core-  | CUnyOp UnyOp Core-  | CIfElse Core Core Core-  | CErr Core-  | CLookup Core Core-  | CComp Comp Core+type Lam = Bind (Rec [Param Core]) Core++type Let = Bind (Rec [(Name Core, Embed Core)]) Core++data Core where+  CLoc :: SrcSpan -> Core -> Core+  CLit :: Literal -> Core+  CVar :: Name Core -> Core+  CLam :: Lam -> Core+  CPrim :: Prim -> Core+  CApp :: Core -> Args Core -> Core+  CLet :: Let -> Core+  CObj :: [CField] -> Core+  CArr :: [Core] -> Core+  CComp :: Comp -> Core -> Core   deriving (Show, Typeable, Generic)  instance Alpha Core
src/Language/Jsonnet/Desugar.hs view
@@ -10,16 +10,22 @@  module Language.Jsonnet.Desugar (desugar) where +import qualified Data.Bifunctor import Data.Fix as F-import Data.List.NonEmpty (NonEmpty (..), fromList, toList)+import Data.List.NonEmpty (NonEmpty (..), toList) import qualified Data.List.NonEmpty as NE import Data.Maybe (fromMaybe) import Data.Text (Text)+import qualified Data.Text as T (pack)+import Debug.Trace import Language.Jsonnet.Annotate import Language.Jsonnet.Common import Language.Jsonnet.Core+import Language.Jsonnet.Error import Language.Jsonnet.Parser.SrcSpan+import Language.Jsonnet.Pretty () import Language.Jsonnet.Syntax+import Text.PrettyPrint.ANSI.Leijen hiding (encloseSep, (<$>)) import Unbound.Generics.LocallyNameless  class Desugarer a where@@ -33,44 +39,41 @@ instance Desugarer (Ann ExprF SrcSpan) where   desugar = foldFix go . zipWithOutermost     where-      go (AnnF f (a, b)) = alg b $ CLoc a <$> f+      go (AnnF f (a, b)) = CLoc a (alg b f) --- annotate nodes with a boolean denoting outermost objects+-- | annotate nodes with a boolean denoting outermost objects zipWithOutermost :: Ann ExprF a -> Ann ExprF (a, Bool) zipWithOutermost = annZip . inherit go False   where-    go (Fix (AnnF (EObj {}) _)) False = (True, True)-    go (Fix (AnnF (EObj {}) _)) True = (False, True)+    go (Fix (AnnF EObj {} _)) False = (True, True)+    go (Fix (AnnF EObj {} _)) True = (False, True)     go _ x = (False, x) +alg :: Bool -> ExprF Core -> Core alg outermost = \case   ELit l -> CLit l   EIdent i -> CVar (s2n i)-  EFun ps e -> mkFun ps e+  EFun ps e -> desugarFun ps e   EApply e es -> CApp e es-  ELocal bnds e -> mkLet bnds e-  -- operator % is overloaded for both modulo and string formatting-  EBinOp (Arith Mod) e1 e2 ->+  ELocal bnds e -> desugarLet bnds e+  EBinOp Mod e1 e2 ->+    -- operator % is overloaded for both modulo and string formatting     stdFunc "mod" (Args [Pos e1, Pos e2] Lazy)-  EBinOp (Comp Eq) e1 e2 ->-    stdFunc "equals" (Args [Pos e1, Pos e2] Lazy)-  EBinOp (Comp Ne) e1 e2 ->-    CUnyOp LNot (stdFunc "equals" (Args [Pos e1, Pos e2] Lazy))-  EBinOp op e1 e2 -> CBinOp op e1 e2-  EUnyOp op e -> CUnyOp op e-  EIfElse c t e -> CIfElse c t e-  EIf c t -> CIfElse c t (CLit Null)+  EBinOp op e1 e2 -> desugarBinOp op e1 e2+  EUnyOp op e -> desugarUnyOp op e+  EIfElse c t e -> desugarIfElse c t e+  EIf c t -> desugarIfElse c t (CLit Null)   EArr e -> CArr e-  EObj {..} -> mkObj outermost locals fields-  ELookup e1 e2 -> CLookup e1 e2-  EIndex e1 e2 -> CLookup e1 e2-  EErr e -> CErr e-  EAssert e -> mkAssert e-  ESlice {..} -> mkSlice expr start end step-  EArrComp {expr, comp} -> mkArrComp expr comp-  EObjComp {field, comp, locals} -> mkObjComp field comp locals+  EObj {..} -> desugarObj outermost locals fields+  ELookup e1 e2 -> desugarLookup e1 e2+  EIndex e1 e2 -> desugarLookup e1 e2+  EErr e -> desugarErr e+  EAssert e -> desugarAssert e+  ESlice {..} -> desugarSlice expr start end step+  EArrComp {expr, comp} -> desugarArrComp expr comp+  EObjComp {field, comp, locals} -> desugarObjComp field comp locals -mkSlice expr start end step =+desugarSlice expr start end step =   stdFunc     "slice"     ( Args@@ -84,54 +87,75 @@   where     maybeNull = fromMaybe (CLit Null) -mkObj outermost locals fields =-  --mkLet (("self", CObj fields) :| bnds) self-  case bnds of-    [] -> fs-    xs -> mkLet (NE.fromList xs) fs+desugarIfElse :: Core -> Core -> Core -> Core+desugarIfElse c t e = CApp (CPrim Cond) (Args [Pos c, Pos t, Pos e] Lazy)++desugarLookup :: Core -> Core -> Core+desugarLookup e1 e2 = CApp (CPrim (BinOp Lookup)) (Args [Pos e1, Pos e2] Lazy)++desugarErr :: Core -> Core+desugarErr e = CApp (CPrim (UnyOp Err)) (Args [Pos e] Lazy)++desugarBinOp :: BinOp -> Core -> Core -> Core+desugarBinOp op e1 e2 = CApp (CPrim (BinOp op)) (Args [Pos e1, Pos e2] Lazy)++desugarUnyOp :: UnyOp -> Core -> Core+desugarUnyOp op e = CApp (CPrim (UnyOp op)) (Args [Pos e] Lazy)++desugarObj outermost locals fields = obj   where+    obj = CObj (desugarField <$> fields')+     bnds =       if outermost-        then (("$", fs) : locals)+        then ("$", CVar "self") : locals         else locals-    fs = CObj (mkKeyValue <$> fields) -mkAssert :: Assert Core -> Core-mkAssert (Assert c m e) =-  CIfElse+    f v@(CLit _) = v+    f v@(CLoc _ (CLit _)) = v+    f v = case bnds of+      [] -> v+      xs -> desugarLet (NE.fromList xs) v++    fields' =+      (\(EField key val v o) -> EField key (f val) v o) <$> fields++desugarAssert :: Assert Core -> Core+desugarAssert (Assert c m e) =+  desugarIfElse     c     e-    ( CErr $+    ( desugarErr $         fromMaybe           (CLit $ String "Assertion failed")           m     ) -mkArrComp :: Core -> NonEmpty (CompSpec Core) -> Core-mkArrComp expr comp = foldr f (CArr [expr]) comp+desugarArrComp :: Core -> NonEmpty (CompSpec Core) -> Core+desugarArrComp expr = foldr f (CArr [expr])   where     f CompSpec {..} e =       CComp (ArrC (bind (s2n var) (e, ifspec))) forspec -mkKeyValue :: Field Core -> KeyValue Core-mkKeyValue Field {..} = KeyValue key (Hideable value' visibility)+desugarField :: EField Core -> CField+desugarField EField {..} = mkField key value' visibility   where     value' =       if override         then-          CIfElse-            (CBinOp In key super)-            (CBinOp (Arith Add) (CLookup super key) value)+          desugarIfElse+            (desugarBinOp In key super)+            (desugarBinOp Add (desugarLookup super key) value)             value         else value     super = CVar $ s2n "super" -mkObjComp (Field {..}) comp locals =+desugarObjComp EField {..} comp locals =   CComp (ObjC (bind (s2n "arr") (kv', Nothing))) arrComp   where     kv' =-      mkKeyValue-        ( Field+      desugarField+        ( EField             { key = key',               value = value',               visibility,@@ -139,47 +163,53 @@             }         )     bnds = NE.zip (fmap var comp) xs-    key' = mkLet bnds key+    key' = desugarLet bnds key     value' = case locals of-      [] -> mkLet bnds value+      [] -> desugarLet bnds value       -- we need to nest the let bindings due to the impl.-      xs -> mkLet bnds $ mkLet (NE.fromList xs) value-    xs = CLookup (CVar $ s2n "arr") . CLit . Number . fromIntegral <$> [0 ..]-    arrComp = mkArrComp arr comp+      xs -> desugarLet bnds $ desugarLet (NE.fromList xs) value+    xs = desugarLookup (CVar $ s2n "arr") . CLit . Number . fromIntegral <$> [0 ..]+    arrComp = desugarArrComp arr comp     arr = CArr $ NE.toList $ CVar . s2n . var <$> comp  stdFunc :: Text -> Args Core -> Core stdFunc f =   CApp-    ( CLookup+    ( desugarLookup         (CVar "std")         (CLit $ String f)     ) -mkFun ps e =-  CFun $-    Fun $-      bind-        ( rec $-            fmap-              ( \(n, a) ->-                  (s2n n, Embed a)-              )-              ps-        )-        e+desugarFun ps e =+  CLam $+    bind+      ( rec $+          fmap+            ( \(n, a) ->+                (s2n n, Embed (fromMaybe (errNotBound n) a))+            )+            ps+      )+      e+  where+    errNotBound n =+      desugarErr $+        CLit $+          String+            ( T.pack $+                show $+                  pretty $ ParamNotBound (pretty n)+            ) -mkLet bnds e =+desugarLet bnds e =   CLet $-    Let $-      bind-        ( rec $-            toList-              ( fmap-                  ( \(n, a) ->-                      (s2n n, Embed a)-                  )-                  bnds-              )-        )-        e+    bind+      ( rec $+          toList+            ( fmap+                ( Data.Bifunctor.bimap s2n Embed+                )+                bnds+            )+      )+      e
src/Language/Jsonnet/Error.hs view
@@ -5,8 +5,10 @@  module Language.Jsonnet.Error where +import Control.Exception import Data.Scientific (Scientific) import Data.Text (Text)+import Data.Typeable (Typeable) import Data.Void (Void) import Language.Jsonnet.Common import Language.Jsonnet.Core@@ -39,7 +41,9 @@   | StdError Doc   | RuntimeError Doc   | ManifestError Doc-  deriving (Show)+  deriving (Show, Typeable)++instance Exception EvalError  data ParserError   = ParseError (ParseErrorBundle Text Void)
src/Language/Jsonnet/Eval.hs view
@@ -1,139 +1,100 @@-{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecursiveDo #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-} -module Language.Jsonnet.Eval-  ( eval,-    evalClos,-    mergeWith,-    module Language.Jsonnet.Eval.Monad,-  )-where+module Language.Jsonnet.Eval where  import Control.Applicative+import Control.Lens (locally, view) import Control.Monad.Except-import Control.Monad.Reader-import Control.Monad.State.Lazy-import Data.Aeson.Text+import qualified Data.Aeson as JSON+import Data.Aeson.Text (encodeToLazyText) import Data.Bifunctor (second) import Data.Bits+import Data.ByteString (ByteString) import Data.Foldable+import Data.HashMap.Lazy (HashMap) import qualified Data.HashMap.Lazy as H-import Data.Int-import Data.List+import Data.IORef+import Data.Int (Int64)+import qualified Data.List as L (sort) import qualified Data.Map.Lazy as M-import Data.Maybe (catMaybes, isNothing)-import Data.Scientific (isInteger, toBoundedInteger)+import Data.Maybe+import Data.Scientific import Data.Text (Text) import qualified Data.Text as T+import Data.Text.Encoding (decodeUtf8, encodeUtf8) import Data.Text.Lazy (toStrict)+import Data.Traversable (for) import Data.Vector (Vector, (!?)) import qualified Data.Vector as V import Debug.Trace-import Language.Jsonnet.Common hiding (span)+import Language.Jsonnet.Common import Language.Jsonnet.Core import Language.Jsonnet.Error import Language.Jsonnet.Eval.Monad-import Language.Jsonnet.Manifest-import Language.Jsonnet.Parser.SrcSpan import Language.Jsonnet.Pretty ()-import qualified Language.Jsonnet.Std.Lib as Std import Language.Jsonnet.Value-import Text.PrettyPrint.ANSI.Leijen (pretty)+import Text.PrettyPrint.ANSI.Leijen hiding (equals, (<$>)) import Unbound.Generics.LocallyNameless-import Unbound.Generics.LocallyNameless.Bind+import Prelude hiding (length)+import qualified Prelude as P (length) --- an evaluator for the core calculus, based on a--- big-step, call-by-need operational semantics, matching--- jsonnet specificaton+rnf :: Core -> Eval JSON.Value+rnf = whnf >=> manifest -eval :: Core -> Eval Value-eval = \case-  CLoc sp e -> do-    --traceShowM (spanBegin sp)-    updateSpan (Just sp) >> eval e-  CLit l -> evalLiteral l-  CVar n -> do-    env <- asks ctx-    --sp <- gets currentPos-    --traceShowM (spanBegin <$> sp)-    v <- liftMaybe (VarNotFound (pretty n)) (M.lookup n env)-    force v-  CFun f -> VClos f <$> ask-  CApp e es -> evalApp e =<< evalArgs es-  cc@(CLet (Let bnd)) -> mdo-    (r, e1) <- unbind bnd-    bnds <--      mapM-        ( \(v, Embed e) -> do-            th <- mkThunk $ extendCtx' bnds $ eval e-            pure (v, th)-        )-        (unrec r)+whnfV :: Value -> Eval Value+whnfV (VIndir loc) = whnfIndir loc >>= whnfV+whnfV (VThunk c e) = withEnv e (whnf c)+whnfV v = pure v -    --traceShowM "applying the body of the local binding"-    --traceShowM e1-    extendCtx' bnds (eval e1)-  CObj e -> evalObj e-  CArr e -> VArr . V.fromList <$> traverse thunk e-  CBinOp (Logical op) e1 e2 -> do-    e1' <- thunk e1-    e2' <- thunk e2-    evalLogical op e1' e2'-  CBinOp op e1 e2 -> do-    e1' <- eval e1-    e2' <- eval e2-    evalBinOp op e1' e2'-  CUnyOp op e -> do-    e' <- eval e-    evalUnyOp op e'-  CLookup e1 e2 -> do-    v1 <- eval e1-    v2 <- eval e2-    evalLookup v1 v2-  CIfElse c e1 e2 -> do-    eval c >>= \case-      VBool b ->-        if b-          then eval e1-          else eval e2-      v -> throwTypeMismatch "bool" v-  CErr e ->-    ( eval-        >=> toString-        >=> throwE . RuntimeError . pretty-    )-      e-  CComp (ArrC bnd) cs -> do-    evalArrComp cs bnd-  CComp (ObjC bnd) cs -> do-    evalObjComp cs bnd+whnf :: Core -> Eval Value+whnf (CVar n) = lookupVar n+whnf (CLoc sp c) = locally currentPos (const $ Just sp) (whnf c)+whnf (CLit l) = pure (whnfLiteral l)+whnf (CObj bnd) = whnfObj bnd+whnf (CArr cs) = VArr . V.fromList <$> mapM mkValue cs+whnf (CLet bnd) = whnfLetrec bnd+whnf (CPrim p) = pure (VPrim p)+whnf (CApp e es) = whnfApp e es+whnf (CLam f) = VClos f <$> view ctx+whnf (CComp comp e) = whnfComp comp e -thunk :: Core -> Eval Thunk-thunk e =-  ask >>= \rho ->-    mkThunk $ withCtx (ctx rho) (eval e)+mkValue :: Core -> Eval Value+mkValue c@(CLit _) = whnf c+mkValue c@(CLam _) = whnf c+mkValue c@(CPrim _) = whnf c+mkValue c = mkThunk c >>= mkIndirV -extendCtx' :: [(Name Core, Thunk)] -> Eval a -> Eval a-extendCtx' = extendCtx . M.fromList+lookupVar :: Name Core -> Eval Value+lookupVar n = do+  rho <- view ctx+  v <- liftMaybe (VarNotFound (pretty n)) (M.lookup n rho)+  whnfV v -evalArgs :: Args Core -> Eval [Arg Thunk]-evalArgs = \case-  as@(Args _ Lazy) -> args <$> traverse thunk as-  as@(Args _ Strict) -> args <$> traverse f as-    where-      f = eval >=> pure . mkThunk'+whnfLiteral :: Literal -> Value+whnfLiteral = \case+  Null -> VNull+  Bool b -> VBool b+  String s -> VStr s+  Number n -> VNum n -evalApp :: Core -> [Arg Thunk] -> Eval Value-evalApp e vs = withStackFrame e $ do-  eval e >>= \case-    VClos f Env {..} -> evalClos ctx f vs+whnfArgs :: Args Core -> Eval [Arg Value]+whnfArgs = \case+  as@(Args _ Strict) -> args <$> mapM whnf as+  as@(Args _ Lazy) -> args <$> mapM mkValue as++whnfApp :: Core -> Args Core -> Eval Value+whnfApp e es = withStackFrame e $ do+  vs <- whnfArgs es+  whnf e >>= whnfV >>= \case+    VClos f env -> whnfClos env f vs+    VPrim op -> whnfPrim op vs     v@(VFun _) -> foldlM f v vs       where         f (VFun g) (Pos v) = g v@@ -142,266 +103,482 @@  withStackFrame :: Core -> Eval a -> Eval a withStackFrame (CLoc sp (CVar n)) e =-  pushScope n (pushSpan (Just sp) e)+  pushStackFrame (n, Just sp) e withStackFrame (CLoc sp _) e =-  pushScope (s2n "anonymous") (pushSpan (Just sp) e)-withStackFrame (CVar n) e =-  pushScope n (pushSpan Nothing e)-withStackFrame _ e =-  pushScope (s2n "anonymous") (pushSpan Nothing e)+  pushStackFrame (s2n "anonymous", Just sp) e+withStackFrame (CVar _) e = e+--pushStackFrame (n, Nothing) e+withStackFrame _ e = e -evalClos :: Ctx -> Fun -> [Arg Thunk] -> Eval Value-evalClos rho (Fun f) vs = do+--pushStackFrame (s2n "anonymous", Nothing) e++whnfClos :: Env -> Lam -> [Arg Value] -> Eval Value+whnfClos rho f args = do   (bnds, e) <- unbind f-  let xs = second unembed <$> unrec bnds-  withCtx rho (evalFun xs e vs)+  (rs, ps, ns) <- splitArgs args (second unembed <$> unrec bnds)+  withEnv rho $+    extendEnv (M.fromList ps) $+      extendEnv (M.fromList ns) $+        appDefaults rs e -appDefaults :: [(Name Core, Maybe Core)] -> Core -> Eval Value-appDefaults rs e = do-  case findIndex isNothing ds of-    Just x -> throwE $ ParamNotBound (pretty $ ns !! x)-    Nothing -> mdo-      bnds <--        mapM-          ( \(v, e) -> do-              th <- mkThunk $ extendCtx' bnds $ eval e-              pure (v, th)-          )-          (zip ns $ catMaybes ds)-      extendCtx' bnds (eval e)-  where-    (ns, ds) = unzip rs+-- all parameter names are bound in default values+appDefaults :: [(Name Core, Core)] -> Core -> Eval Value+appDefaults rs e = mdo+  bnds <-+    M.fromList+      <$> mapM+        ( \(n, e) -> do+            th <- extendEnv bnds (mkValue e)+            pure (n, th)+        )+        rs+  extendEnv bnds (whnf e) -evalFun bnds e args = do-  if length ps > length bnds-    then throwE $ TooManyArgs (length bnds)-    else extendCtx' (zip names ps') $ evalNamedArgs ns bnds'+-- returns a triple with unapplied binders, positional and named+splitArgs args bnds = do+  named <- getNamed+  pos <- getPos+  unapp <- getUnapp named+  pure (unapp, pos, named)   where-    isPos = \case-      Pos _ -> True-      _ -> False-    (ps, ns) = span isPos args-    ps' = fmap (\(Pos a) -> a) ps-    (names, _) = unzip bnds-    bnds' = drop (length ps) bnds-    evalNamedArgs ns bnds = do-      ns' <- forM ns $ \case-        Named n v -> pure (n, v)-      (names, vs) <- unzip <$> buildParams ns' bnds-      let rs = filter ((`notElem` names) . fst) bnds-      extendCtx' (zip names vs) (appDefaults rs e)+    (bnds1, bnds2) = splitAt (length ps) bnds+    (ps, ns) = split args+    pNames = map fst bnds++    getPos =+      if length ps > length bnds+        then throwE $ TooManyArgs (length bnds)+        else pure $ zip (map fst bnds1) ps++    -- checks the provided named arguments exist+    getNamed = traverse f ns       where-        buildParams as bnds = traverse f as-          where-            ns = fst $ unzip bnds-            f (a, b) = case g a of-              Nothing -> throwE $ BadParam (pretty a)-              Just n -> pure (n, b)-            g a = find ((a ==) . name2String) ns+        f (a, b) = case g a of+          Nothing -> throwE $ BadParam (pretty a)+          Just n -> pure (n, b)+        g a = find ((a ==) . name2String) pNames --- | right-biased union of two objects, i.e. '{x : 1} + {x : 2} == {x : 2}'-mergeWith :: Object -> Object -> Object-mergeWith xs ys =-  let f a b-        | hidden a && visible b = a-        | otherwise = b-      g name xs = fmap $-        \case-          TC rho e -> TC (M.insert name (mkThunk' $ VObj xs) rho) e-          v@(TV {}) -> v-      h name xs = fmap $-        \case-          TC rho e -> TC (insert' name (mkThunk' $ VObj xs) rho) e-          v@(TV {}) -> v-      xs' = H.map (g "self" zs') xs-      ys' = H.map (g "self" zs' . h "super" xs') ys-      zs' = H.unionWith f xs' ys'-      insert' = M.insertWith (const)-   in zs'+    getUnapp named =+      pure $ filter ((`notElem` ns) . fst) bnds2+      where+        ns = map fst named -evalObj :: [KeyValue Core] -> Eval Value-evalObj xs = mdo-  env <- asks ctx-  fs <--    catMaybes+    split [] = ([], [])+    split (Pos p : xs) =+      let (ys, zs) = split xs in (p : ys, zs)+    split (Named n v : xs) =+      let (ys, zs) = split xs in (ys, (n, v) : zs)++whnfPrim :: Prim -> [Arg Value] -> Eval Value+whnfPrim (UnyOp op) [Pos e] = whnfV e >>= whnfUnyOp op+whnfPrim (BinOp LAnd) [Pos e1, Pos e2] = whnfLogical id e1 e2+whnfPrim (BinOp LOr) [Pos e1, Pos e2] = whnfLogical not e1 e2+whnfPrim (BinOp op) [Pos e1, Pos e2] =+  liftA2 (,) (whnfV e1) (whnfV e2) >>= uncurry (whnfBinOp op)+whnfPrim Cond [Pos c, Pos t, Pos e] = whnfCond c t e++whnfBinOp :: BinOp -> Value -> Value -> Eval Value+whnfBinOp Lookup e1 e2 = whnfLookup e1 e2+whnfBinOp Add x@(VStr _) y = inj <$> append x y+whnfBinOp Add x y@(VStr _) = inj <$> append x y+whnfBinOp Add x@(VArr _) y@(VArr _) = liftF2 ((V.++) @Value) x y+whnfBinOp Add (VObj x) (VObj y) = x `mergeWith` y+whnfBinOp Add n1 n2 = liftF2 ((+) @Double) n1 n2+whnfBinOp Sub n1 n2 = liftF2 ((-) @Double) n1 n2+whnfBinOp Mul n1 n2 = liftF2 ((*) @Double) n1 n2+whnfBinOp Div (VNum _) (VNum 0) = throwE DivByZero+whnfBinOp Div n1 n2 = liftF2 ((/) @Double) n1 n2+whnfBinOp Mod (VNum _) (VNum 0) = throwE DivByZero+whnfBinOp Mod n1 n2 = liftF2 (mod @Int64) n1 n2+whnfBinOp Eq e1 e2 = inj <$> equals e1 e2+whnfBinOp Ne e1 e2 = inj . not <$> equals e1 e2+whnfBinOp Lt e1 e2 = liftF2 ((<) @Double) e1 e2+whnfBinOp Gt e1 e2 = liftF2 ((>) @Double) e1 e2+whnfBinOp Le e1 e2 = liftF2 ((<=) @Double) e1 e2+whnfBinOp Ge e1 e2 = liftF2 ((>=) @Double) e1 e2+whnfBinOp And e1 e2 = liftF2 ((.&.) @Int64) e1 e2+whnfBinOp Or e1 e2 = liftF2 ((.|.) @Int64) e1 e2+whnfBinOp Xor e1 e2 = liftF2 (xor @Int64) e1 e2+whnfBinOp ShiftL e1 e2 = liftF2 (shiftL @Int64) e1 e2+whnfBinOp ShiftR e1 e2 = liftF2 (shiftR @Int64) e1 e2+whnfBinOp In s o = liftF2 (\o s -> objectHasEx o s True) o s++whnfLogical :: HasValue a => (a -> Bool) -> Value -> Value -> Eval Value+whnfLogical f e1 e2 = do+  x <- whnfV e1 >>= proj'+  if f x+    then inj <$> (whnfV e2 >>= proj' @Bool)+    else pure (inj x)++append :: Value -> Value -> Eval Text+append v1 v2 = T.append <$> toString v1 <*> toString v2++whnfUnyOp :: UnyOp -> Value -> Eval Value+whnfUnyOp Compl x = inj <$> fmap (complement @Int64) (proj' x)+whnfUnyOp LNot x = inj <$> fmap not (proj' x)+whnfUnyOp Minus x = inj <$> fmap (negate @Double) (proj' x)+whnfUnyOp Plus x = inj <$> fmap (id @Double) (proj' x)+whnfUnyOp Err x = (toString >=> throwE . RuntimeError . pretty) x++toString :: Value -> Eval Text+toString (VStr s) = pure s+toString v = toStrict . encodeToLazyText <$> manifest v++whnfCond :: Value -> Value -> Value -> Eval Value+whnfCond c e1 e2 = do+  c' <- proj' c+  if c'+    then whnfV e1+    else whnfV e2++whnfLookup :: Value -> Value -> Eval Value+whnfLookup (VObj o) (VStr s) =+  whnfV . fieldValWHNF =<< liftMaybe (NoSuchKey (pretty s)) (H.lookup s o)+whnfLookup (VArr a) (VNum i)+  | isInteger i =+    whnfV =<< liftMaybe (IndexOutOfBounds i) ((a !?) =<< toBoundedInteger i)+whnfLookup (VArr _) _ =+  throwE (InvalidIndex "array index was not integer")+whnfLookup (VStr s) (VNum i)+  | isInteger i =+    liftMaybe (IndexOutOfBounds i) (f =<< bounded)+  where+    f = pure . VStr . T.singleton . T.index s+    bounded =+      toBoundedInteger i >>= \i' ->+        if T.length s - 1 < i' && i' < 0+          then Nothing+          else Just i'+whnfLookup (VStr _) _ =+  throwE (InvalidIndex "string index was not integer")+whnfLookup v _ = throwTypeMismatch "array/object/string" v++whnfIndir :: Ref -> Eval Value+whnfIndir ref = do+  c <- liftIO $ readIORef ref+  case c of+    Cell v True ->+      return v -- Already evaluated, just return it+    Cell v False -> do+      v' <- whnfV v -- Needs to be reduced+      liftIO $ writeIORef ref (Cell v' True)+      return v'++whnfLetrec :: Let -> Eval Value+whnfLetrec bnd = mdo+  (r, e1) <- unbind bnd+  bnds <-+    M.fromList       <$> mapM-        ( \(KeyValue key value) -> do-            k <- evalKey key-            v <- pure $ TC (M.insert "self" (self fs) env) <$> value-            case k of-              Just k -> pure $ Just (k, v)-              _ -> pure Nothing+        ( \(n, Embed e) -> do+            v <- extendEnv bnds (mkValue e)+            pure (n, v)         )+        (unrec r)+  extendEnv bnds (mkValue e1)++whnfObj :: [CField] -> Eval Value+whnfObj xs = mdo+  obj <-+    mkIndirV . VObj . H.fromList . catMaybes+      =<< mapM+        ( \field ->+            let self = M.singleton (s2n "self") obj+             in whnfField self field+        )         xs-  pure $ VObj $ H.fromList $ fs-  where-    self = mkThunk' . VObj . H.fromList+  pure obj -evalKey :: Core -> Eval (Maybe Text)-evalKey key =-  eval key >>= \case-    VStr k -> pure $ Just k-    VNull -> pure Nothing-    v -> throwInvalidKey v+whnfField ::+  -- | self object+  Env ->+  -- |+  CField ->+  -- |+  Eval (Maybe (Text, VField))+whnfField self (CField k v h) = do+  let fieldVis = h+  fieldKey <- whnf k -- keys are strictly evaluated+  fieldValWHNF <- extendEnv self (mkValue v)+  fieldVal <- extendEnv self (mkThunk v)+  fmap (,VField {..}) <$> proj' fieldKey -evalKeyValue :: KeyValue Core -> Eval (Maybe (Text, Hideable Thunk))-evalKeyValue (KeyValue key value) = do-  a <- evalKey key-  b <- asks ctx >>= \rho -> pure (TC rho <$> value)-  pure $ (,b) <$> a+flattenArrays :: Vector (Vector Value) -> Vector Value+flattenArrays = join -evalArrComp ::+whnfComp ::+  Comp ->   Core ->-  Bind (Name Core) (Core, Maybe Core) ->   Eval Value-evalArrComp cs bnd = do+whnfComp (ArrC bnd) cs = do   xs <- comp-  inj' flattenArrays $ VArr $ V.mapMaybe id xs+  liftF flattenArrays $ VArr $ V.mapMaybe id xs   where     comp =-      eval cs >>= \case+      whnf cs >>= \case         VArr xs -> forM xs $ \x -> do           (n, (e, cond)) <- unbind bnd-          extendCtx' [(n, x)] $ do+          extendEnv (M.fromList [(n, x)]) $ do             b <- f cond             if b-              then Just <$> thunk e+              then Just <$> mkValue e               else pure Nothing-        v -> throwTypeMismatch "array" v+        v -> throwTypeMismatch "" v       where         f Nothing = pure True-        f (Just c) = do-          vb <- eval c-          proj vb--evalObjComp ::-  Core ->-  Bind (Name Core) (KeyValue Core, Maybe Core) ->-  Eval Value-evalObjComp cs bnd = do+        f (Just c) = proj' =<< whnf c+whnfComp (ObjC bnd) cs = do   xs <- comp   pure $ VObj $ H.fromList $ catMaybes $ V.toList xs   where     comp =-      eval cs >>= \case+      whnf cs >>= \case         VArr xs -> forM xs $ \x -> do-          (n, (e, cond)) <- unbind bnd-          extendCtx' [(n, x)] $ do+          (n, (CField k v h, cond)) <- unbind bnd+          extendEnv (M.fromList [(n, x)]) $ do             b <- f cond             if b-              then evalKeyValue e+              then do+                fieldKey <- whnf k+                fieldValWHNF <- mkValue v+                fieldVal <- mkThunk v+                let fieldVis = h+                fmap (,VField {..}) <$> proj' fieldKey               else pure Nothing         v -> throwTypeMismatch "array" v     f Nothing = pure True-    f (Just c) = do-      vb <- eval c-      proj vb+    f (Just c) = proj' =<< whnf c -evalUnyOp :: UnyOp -> Value -> Eval Value-evalUnyOp Compl x = inj <$> fmap (complement @Int64) (proj x)-evalUnyOp LNot x = inj <$> fmap not (proj x)-evalUnyOp Minus x = inj <$> fmap (negate @Double) (proj x)-evalUnyOp Plus x = inj <$> fmap (id @Double) (proj x)+-- | Right-biased union of two objects, i.e. '{x : 1} + {x : 2} == {x : 2}'+--   with OO-like `self` and `super` support via value recursion (knot-tying)+mergeWith :: Object -> Object -> Eval Value+mergeWith xs ys = mdo+  zs' <- mkIndirV $ VObj (H.unionWith f xs' ys')+  xs' <- for xs (update self zs')+  ys' <- do+    xs'' <- mkIndirV (VObj xs')+    ys'' <- for ys (update self zs')+    for ys'' (update super xs'')+  pure zs'+  where+    self = s2n "self"+    super = s2n "super"+    f a b+      | hidden a && visible b = a+      | otherwise = b+    update name xs f@VField {..} = case fieldVal of+      VThunk c env -> do+        let env' = M.insert name xs env+        let fieldVal = VThunk c env'+        fieldValWHNF <- mkIndirV fieldVal+        pure VField {..}+      _ -> pure f -evalBinOp :: BinOp -> Value -> Value -> Eval Value-evalBinOp In s o = evalBin (\o s -> Std.objectHasEx o s True) o s-evalBinOp (Arith Add) x@(VStr _) y = inj <$> append x y-evalBinOp (Arith Add) x y@(VStr _) = inj <$> append x y-evalBinOp (Arith Add) x@(VArr _) y@(VArr _) = evalBin ((V.++) @Thunk) x y-evalBinOp (Arith Add) (VObj x) (VObj y) = pure $ VObj (x `mergeWith` y)-evalBinOp (Arith op) x y = evalArith op x y-evalBinOp (Comp op) x y = evalComp op x y-evalBinOp (Bitwise op) x y = evalBitwise op x y+visibleKeys :: Object -> HashMap Text Value+visibleKeys = H.mapMaybe f+  where+    f v@VField {..}+      | not (hidden v) = Just fieldValWHNF+      | otherwise = Nothing -evalArith :: ArithOp -> Value -> Value -> Eval Value-evalArith Add n1 n2 = evalBin ((+) @Double) n1 n2-evalArith Sub n1 n2 = evalBin ((-) @Double) n1 n2-evalArith Mul n1 n2 = evalBin ((*) @Double) n1 n2-evalArith Div (VNum _) (VNum 0) = throwE DivByZero-evalArith Div n1 n2 = evalBin ((/) @Double) n1 n2-evalArith Mod (VNum _) (VNum 0) = throwE DivByZero-evalArith Mod n1 n2 = evalBin (mod @Int64) n1 n2+liftMaybe :: EvalError -> Maybe a -> Eval a+liftMaybe e =+  \case+    Nothing -> throwE e+    Just a -> pure a -evalComp :: CompOp -> Value -> Value -> Eval Value-evalComp Lt n1 n2 = evalBin ((<) @Double) n1 n2-evalComp Gt n1 n2 = evalBin ((>) @Double) n1 n2-evalComp Le n1 n2 = evalBin ((<=) @Double) n1 n2-evalComp Ge n1 n2 = evalBin ((>=) @Double) n1 n2+manifest :: Value -> Eval JSON.Value+manifest = \case+  VNull -> pure JSON.Null+  VBool b -> pure (JSON.Bool b)+  VStr s -> pure (JSON.String s)+  VNum n -> pure (JSON.Number n)+  VObj vs -> JSON.Object <$> mapM manifest (visibleKeys vs)+  VArr vs -> JSON.Array <$> mapM manifest vs+  VClos {} -> throwE (ManifestError "function")+  VFun _ -> throwE (ManifestError "function")+  v@VThunk {} -> whnfV v >>= manifest+  v@VIndir {} -> whnfV v >>= manifest+  _ -> throwE (ManifestError "impossible") -evalLogical :: LogicalOp -> Thunk -> Thunk -> Eval Value-evalLogical LAnd e1 e2 = do-  force e1 >>= \case-    VBool True -> force e2 >>= \x -> inj <$> fmap (id @Bool) (proj x)-    VBool False -> pure (VBool False)-    v -> throwTypeMismatch "boolean" v-evalLogical LOr e1 e2 = do-  force e1 >>= \case-    VBool False -> force e2 >>= \x -> inj <$> fmap (id @Bool) (proj x)-    VBool True -> pure (VBool True)-    v -> throwTypeMismatch "boolean" v+objectFieldsEx :: Object -> Bool -> [Text]+objectFieldsEx o True = L.sort (H.keys o) -- all fields+objectFieldsEx o False = L.sort $ H.keys $ H.filter (not . hidden) o -- only visible (incl. forced) -evalBitwise :: BitwiseOp -> Value -> Value -> Eval Value-evalBitwise And = evalBin ((.&.) @Int64)-evalBitwise Or = evalBin ((.|.) @Int64)-evalBitwise Xor = evalBin (xor @Int64)-evalBitwise ShiftL = evalBin (shiftL @Int64)-evalBitwise ShiftR = evalBin (shiftR @Int64)+objectHasEx :: Object -> Text -> Bool -> Bool+objectHasEx o f all = f `elem` objectFieldsEx o all -evalLookup :: Value -> Value -> Eval Value-evalLookup (VArr a) (VNum i)-  | isInteger i =-    liftMaybe (IndexOutOfBounds i) ((a !?) =<< toBoundedInteger i) >>= force-evalLookup (VArr _) _ =-  throwE (InvalidIndex $ "array index was not integer")-evalLookup (VObj o) (VStr s) =-  liftMaybe (NoSuchKey (pretty s)) (H.lookup s o)-    >>= \(Hideable v _) -> force v-evalLookup (VStr s) (VNum i) | isInteger i = do-  liftMaybe (IndexOutOfBounds i) (f =<< bounded)+primitiveEquals :: Value -> Value -> Eval Bool+primitiveEquals VNull VNull = pure True+primitiveEquals (VBool a) (VBool b) = pure (a == b)+primitiveEquals (VStr a) (VStr b) = pure (a == b)+primitiveEquals (VNum a) (VNum b) = pure (a == b)+primitiveEquals a b =+  throwE+    ( StdError $+        text $+          T.unpack $+            "primitiveEquals operates on primitive types "+            --  <> showTy a+            --  <> showTy b+    )++equals :: Value -> Value -> Eval Bool+equals e1 e2 = liftA2 (,) (whnfV e1) (whnfV e2) >>= uncurry go   where-    f = pure . VStr . T.singleton . T.index s-    bounded =-      toBoundedInteger i >>= \i' ->-        if T.length s - 1 < i' && i' < 0-          then Nothing-          else Just i'-evalLookup (VStr _) _ =-  throwE (InvalidIndex $ "string index was not integer")-evalLookup v _ = throwTypeMismatch "array/object/string" v+    go as@(VArr a) bs@(VArr b)+      | P.length a == P.length b = do+        as' <- proj' as+        bs' <- proj' bs+        allM (uncurry equals) (zip as' bs')+      | P.length a /= P.length b = pure False+    go (VObj a) (VObj b) = do+      let fields = objectFieldsEx a False+      if fields /= objectFieldsEx b False+        then pure False+        else allM objectFieldEquals fields+      where+        objectFieldEquals field =+          let a' = fieldValWHNF (a H.! field)+              b' = fieldValWHNF (b H.! field)+           in equals a' b'+    go a b = do+      ta <- showTy a+      tb <- showTy b+      if ta == tb+        then primitiveEquals a b+        else pure False -evalLiteral :: Literal -> Eval Value-evalLiteral = \case-  Null -> pure VNull-  Bool b -> pure $ VBool b-  String s -> pure $ VStr s-  Number n -> pure $ VNum n+allM :: Monad m => (a -> m Bool) -> [a] -> m Bool+allM p = foldrM (\a b -> (&& b) <$> p a) True -evalBin ::+-- better names?+liftF ::+  (HasValue a, HasValue b) =>+  (a -> b) ->+  (Value -> Eval Value)+liftF f v = inj . f <$> proj' v+{-# INLINE liftF #-}++liftF2 ::   (HasValue a, HasValue b, HasValue c) =>   (a -> b -> c) ->   Value ->   Value ->   Eval Value-evalBin = inj''+liftF2 f v1 v2 = inj <$> liftA2 f (proj' v1) (proj' v2)+{-# INLINE liftF2 #-} -append :: Value -> Value -> Eval Text-append v1 v2 = T.append <$> toString v1 <*> toString v2+proj' :: HasValue a => Value -> Eval a+proj' = whnfV >=> proj+{-# INLINE proj' #-} -throwInvalidKey :: Value -> Eval a-throwInvalidKey = throwE . InvalidKey . pretty . valueType+throwTypeMismatch :: Text -> Value -> Eval a+throwTypeMismatch e = throwE . TypeMismatch e <=< showTy -updateSpan :: Maybe SrcSpan -> Eval ()-updateSpan sp = modify $ \st -> st {currentPos = sp}+showTy :: Value -> Eval Text+showTy = \case+  VNull -> pure "null"+  VNum _ -> pure "number"+  VBool _ -> pure "boolean"+  VStr _ -> pure "string"+  VObj _ -> pure "object"+  VArr _ -> pure "array"+  VClos {} -> pure "function"+  VFun _ -> pure "function"+  VPrim _ -> pure "function"+  VThunk {} -> pure "thunk"+  VIndir {} -> pure "pointer" -toString :: Value -> Eval Text-toString (VStr s) = pure s-toString v = toStrict . encodeToLazyText <$> manifest v+--v@VThunk {} -> whnfV v >>= showTy+--v@VIndir {} -> whnfV v >>= showTy -flattenArrays :: Vector (Vector Thunk) -> Vector Thunk-flattenArrays = join+instance HasValue Bool where+  proj (VBool n) = pure n+  proj v = throwTypeMismatch "bool" v+  inj = VBool+  {-# INLINE inj #-} -liftMaybe :: EvalError -> Maybe a -> Eval a-liftMaybe e =-  \case-    Nothing -> throwE e-    Just a -> pure a+instance HasValue Text where+  proj (VStr s) = pure s+  proj v = throwTypeMismatch "string" v+  inj = VStr+  {-# INLINE inj #-}++instance {-# OVERLAPPING #-} HasValue [Char] where+  proj (VStr s) = pure $ T.unpack s+  proj v = throwTypeMismatch "string" v+  inj = VStr . T.pack+  {-# INLINE inj #-}++instance HasValue ByteString where+  proj (VStr s) = pure (encodeUtf8 s)+  proj v = throwTypeMismatch "string" v+  inj = VStr . decodeUtf8+  {-# INLINE inj #-}++instance HasValue Scientific where+  proj (VNum n) = pure n+  proj v = throwTypeMismatch "number" v+  inj = VNum+  {-# INLINE inj #-}++instance HasValue Double where+  proj (VNum n) = pure (toRealFloat n)+  proj v = throwTypeMismatch "number" v+  inj = VNum . fromFloatDigits+  {-# INLINE inj #-}++instance {-# OVERLAPS #-} Integral a => HasValue a where+  proj (VNum n) = pure (round n)+  proj v = throwTypeMismatch "number" v+  inj = VNum . fromIntegral+  {-# INLINE inj #-}++instance HasValue a => HasValue (Maybe a) where+  proj VNull = pure Nothing+  proj a = Just <$> proj' a+  inj Nothing = VNull+  inj (Just a) = inj a+  {-# INLINE inj #-}++instance {-# OVERLAPS #-} HasValue Object where+  proj (VObj o) = pure o+  proj v = throwTypeMismatch "object" v+  inj = VObj+  {-# INLINE inj #-}++instance HasValue a => HasValue (Vector a) where+  proj (VArr as) = mapM proj' as+  proj v = throwTypeMismatch "array" v+  inj as = VArr (inj <$> as)+  {-# INLINE inj #-}++instance {-# OVERLAPPABLE #-} HasValue a => HasValue [a] where+  proj = fmap V.toList . proj'+  inj = inj . V.fromList+  {-# INLINE inj #-}++instance {-# OVERLAPS #-} (HasValue a, HasValue b) => HasValue (a -> b) where+  inj f = VFun $ fmap (inj . f) . proj'+  {-# INLINE inj #-}+  proj = throwTypeMismatch "impossible"++instance {-# OVERLAPS #-} (HasValue a, HasValue b, HasValue c) => HasValue (a -> b -> c) where+  inj f = inj $ \x -> inj (f x)+  {-# INLINE inj #-}+  proj = throwTypeMismatch "impossible"++instance {-# OVERLAPS #-} (HasValue a, HasValue b) => HasValue (a -> Eval b) where+  inj f = VFun $ proj' >=> fmap inj . f+  {-# INLINE inj #-}+  proj (VFun f) = pure $ \x -> f (inj x) >>= proj'+  proj (VClos f e) = pure $ \x -> proj =<< whnfClos e f [Pos (inj x)]+  proj v = throwTypeMismatch "function" v++instance {-# OVERLAPS #-} (HasValue a, HasValue b, HasValue c) => HasValue (a -> b -> Eval c) where+  inj f = inj $ \x -> inj (f x)+  {-# INLINE inj #-}+  proj (VFun f) = pure $ \x y -> f (inj x) >>= \(VFun g) -> g (inj y) >>= proj'+  proj (VClos f env) = pure $ \x y -> proj' =<< whnfClos env f [Pos (inj x), Pos (inj y)]+  proj v = throwTypeMismatch "function" v
− src/Language/Jsonnet/Eval.hs-boot
@@ -1,9 +0,0 @@-module Language.Jsonnet.Eval where--import Language.Jsonnet.Common-import Language.Jsonnet.Core-import Language.Jsonnet.Eval.Monad-import {-# SOURCE #-} Language.Jsonnet.Value (Thunk, Value)--eval :: Core -> Eval Value-evalClos :: Ctx -> Fun -> [Arg Thunk] -> Eval Value
src/Language/Jsonnet/Eval/Monad.hs view
@@ -1,121 +1,104 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-} +-- | module Language.Jsonnet.Eval.Monad where -import Control.Arrow+import Control.Lens (locally, makeLenses, view) import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow) import Control.Monad.Except-import Control.Monad.RWS.Strict-import Control.Monad.Reader+  ( ExceptT (..),+    MonadError (throwError),+    MonadFix,+    MonadIO,+    runExceptT,+  )+import Control.Monad.Reader (MonadReader, ReaderT (..)) import Data.Map.Lazy (Map)-import qualified Data.Map.Lazy as M-import Data.Maybe (listToMaybe)-import Debug.Trace-import GHC.Generics-import Language.Jsonnet.Common-import Language.Jsonnet.Core-import Language.Jsonnet.Error-import Language.Jsonnet.Parser.SrcSpan-import {-# SOURCE #-} Language.Jsonnet.Value (Thunk)+import qualified Data.Map.Lazy as M (union)+import Language.Jsonnet.Common (Backtrace (..), StackFrame (..))+import Language.Jsonnet.Core (Core)+import Language.Jsonnet.Error (Error (EvalError), EvalError)+import Language.Jsonnet.Parser.SrcSpan (SrcSpan) import Unbound.Generics.LocallyNameless+  ( Fresh,+    FreshMT,+    Name,+    runFreshMT,+    s2n,+  ) -instance (Monoid w, Fresh m) => Fresh (RWST r w s m) where-  fresh = lift . fresh+type Ctx a = Map (Name Core) a -newtype Eval a = Eval-  { unEval :: ExceptT Error (RWST Env () EvalState (FreshMT IO)) a+-- | Simulate a call-stack to report stack traces+data CallStack = CallStack+  { -- | source location of call-sites+    _spans :: [Maybe SrcSpan],+    -- | names of called functions+    _scopes :: [Name Core]   }++makeLenses ''CallStack++emptyStack :: CallStack+emptyStack = CallStack [] [s2n "top-level"]++data EvalState a = EvalState+  { -- | binding local variables to their values+    _ctx :: Ctx a,+    -- | call-stack simulation+    _callStack :: CallStack,+    -- | source span of expression being evaluated+    _currentPos :: Maybe SrcSpan+  }++makeLenses ''EvalState++newtype EvalM a b = EvalM+  { unEval :: ExceptT Error (ReaderT (EvalState a) (FreshMT IO)) b+  }   deriving     ( Functor,       Applicative,       Monad,       MonadIO,-      MonadFix,-      MonadWriter (),-      MonadReader Env,+      MonadReader (EvalState a),       MonadError Error,-      MonadState EvalState,       MonadThrow,       MonadCatch,       MonadMask,       MonadFail,-      Fresh,-      Generic-    )--type Ctx = Map (Name Core) Thunk--extendCtx :: Ctx -> Eval a -> Eval a-extendCtx ctx' =-  local-    ( \env@Env {ctx} ->-        env {ctx = M.union ctx' ctx}-    )--pushScope :: Name Core -> Eval a -> Eval a-pushScope name =-  local-    ( \env@Env {scopes} ->-        env {scopes = Just name : scopes}+      MonadFix,+      Fresh     ) -pushSpan :: Maybe SrcSpan -> Eval a -> Eval a-pushSpan span c = do-  local-    ( \env@Env {spans} ->-        env {spans = span : spans}-    )-    c--withCtx :: Ctx -> Eval a -> Eval a-withCtx ctx = local (\env -> env {ctx = ctx})--data Env = Env-  { ctx :: Ctx,-    spans :: [Maybe SrcSpan],-    scopes :: [Maybe (Name Core)]-  }+runEvalM :: Ctx a -> EvalM a b -> IO (Either Error b)+runEvalM ctx e = runFreshMT (runReaderT (runExceptT (unEval e)) st)+  where+    st = EvalState ctx emptyStack Nothing -withEnv :: Env -> Eval a -> Eval a-withEnv rho = local (const rho)+throwE :: EvalError -> EvalM a b+throwE e = throwError . EvalError e =<< getBacktrace -emptyEnv :: Env-emptyEnv = Env M.empty [] [Nothing]+extendEnv :: Ctx a -> EvalM a b -> EvalM a b+extendEnv = locally ctx . M.union -data EvalState = EvalState-  { currentPos :: Maybe SrcSpan-  }+withEnv :: Ctx a -> EvalM a b -> EvalM a b+withEnv = locally ctx . const -emptyState :: EvalState-emptyState = EvalState Nothing+pushStackFrame :: (Name Core, Maybe SrcSpan) -> EvalM a b -> EvalM a b+pushStackFrame (name, span) =+  locally (callStack . scopes) (name :)+    . locally (callStack . spans) (span :) ---  traceShowM $ "length of spans: "---  traceShowM $ length sp---  traceShowM $ "length of scopes: "---  traceShowM $ length sc-getBacktrace :: Eval (Backtrace Core)+getBacktrace :: EvalM a (Backtrace Core) getBacktrace = do-  sp <- (:) <$> gets currentPos <*> asks spans-  sc <- asks scopes+  sp <- (:) <$> view currentPos <*> view (callStack . spans)+  sc <- view (callStack . scopes)   pure $     Backtrace $       case sequence sp of         Just sp -> zipWith StackFrame sc sp         Nothing -> []--throwE :: EvalError -> Eval a-throwE e = throwError . EvalError e =<< getBacktrace--runEval :: Env -> Eval a -> ExceptT Error IO a-runEval env = mapExceptT f . unEval-  where-    f comp = do-      (a, _, _) <- runFreshMT $ runRWST comp env emptyState-      pure a
− src/Language/Jsonnet/Eval/Monad.hs-boot
@@ -1,5 +0,0 @@-module Language.Jsonnet.Eval.Monad where--data Eval a--data EvalState
− src/Language/Jsonnet/Manifest.hs
@@ -1,43 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}---- |-module Language.Jsonnet.Manifest where--import Control.Monad.Except-import Data.Aeson (FromJSON (..))-import qualified Data.Aeson as JSON-import Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as H-import Data.Text (Text)-import Data.Vector (Vector)-import Debug.Trace-import Language.Jsonnet.Common-import Language.Jsonnet.Error-import Language.Jsonnet.Eval.Monad-import Language.Jsonnet.Value--manifest :: Value -> Eval JSON.Value-manifest =-  \case-    VNull -> pure JSON.Null-    VBool b -> pure $ JSON.Bool b-    VNum n -> pure $ JSON.Number n-    VStr s -> pure $ JSON.String s-    VArr a -> JSON.Array <$> forceArray a-    VObj o -> JSON.Object <$> forceObject o-    VClos {} -> throwE (ManifestError "function")-    VFun _ -> throwE (ManifestError "function")--forceArray :: Vector Thunk -> Eval (Vector JSON.Value)-forceArray = traverse (force >=> manifest)--forceObject :: Object -> Eval (HashMap Text JSON.Value)-forceObject = traverse (force >=> manifest) . visibleKeys--visibleKeys :: Object -> HashMap Text Thunk-visibleKeys o =-  H.fromList [(k, v) | (k, vv@(Hideable v _)) <- xs, not (hidden vv)]-  where-    xs = H.toList o
src/Language/Jsonnet/Parser.hs view
@@ -3,7 +3,12 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TupleSections #-} -module Language.Jsonnet.Parser where+-- | Parser for Jsonnet source code.+module Language.Jsonnet.Parser+  ( parse,+    resolveImports,+  )+where  import Control.Applicative hiding (many, some) import Control.Arrow (left)@@ -40,8 +45,11 @@  parse ::   MonadError Error m =>+  -- | File name (only for source location annotations)   FilePath ->+  -- | Input for parser   Text ->+  -- | AST with unresolved imports   m Expr' parse fp inp =   liftEither $@@ -50,8 +58,11 @@  resolveImports ::   (MonadError Error m, MonadIO m) =>+  -- | File path (modules are resolved relative to this path)   FilePath ->+  -- | AST with unresolved imports   Expr' ->+  -- | AST with imports resolved   m Expr resolveImports fp = foldFixM go   where@@ -101,8 +112,7 @@ annotateLoc p = do   begin <- getSourcePos   res <- p-  end <- getSourcePos-  pure $ AnnF res $ SrcSpan begin end+  AnnF res . SrcSpan begin <$> getSourcePos  identifier :: Parser String identifier = do@@ -161,7 +171,7 @@     quoted c =       c         *> manyTill-          ((c *> c) <|> anySingle)+          (c *> c <|> anySingle)           (try $ c <* notFollowedBy c)  textBlock :: Parser String@@ -228,8 +238,7 @@       cond <- keywordP "assert" *> exprP       msg <- optional (colon *> exprP)       _ <- symbol ";"-      expr <- exprP-      pure $ mkAssertF cond msg expr+      mkAssertF cond msg <$> exprP  ifElseP :: Parser Expr' ifElseP = Fix <$> annotateLoc ifElseExpr@@ -290,8 +299,7 @@     localExpr = do       bnds <- localBndsP       _ <- symbol ";"-      expr <- exprP-      pure $ mkLocalF bnds expr+      mkLocalF bnds <$> exprP  arrayP :: Parser Expr' arrayP = Fix <$> annotateLoc (brackets (try arrayComp <|> array))@@ -314,9 +322,9 @@       key <- keyP       (override, visibility) <-         (,)-          <$> option False ((symbol "+") $> True) <*> sepP+          <$> option False (symbol "+" $> True) <*> sepP       value <- exprP-      pure $ Field {..}+      pure $ EField {..}     keyP = brackets exprP <|> unquoted <|> stringP     methodP = do       let override = False@@ -324,11 +332,11 @@       ps <- paramsP       visibility <- sepP       value <- function (pure ps) exprP-      pure $ Field {..}+      pure $ EField {..}     sepP =       try (symbol ":::" $> Forced)         <|> try (symbol "::" $> Hidden)-        <|> (symbol ":" $> Visible)+        <|> symbol ":" $> Visible     localP = do       _ <- keywordP "local"       try binding <|> localFunc@@ -351,7 +359,7 @@ binary name f = InfixL (f <$ operator name)   where     operator sym = try $ symbol sym <* notFollowedBy opChar-    opChar = oneOf (":~+&|^=<>*/%" :: [Char]) <?> "operator"+    opChar = oneOf (":~+&|^=<>*/%" :: String) <?> "operator"  prefix ::   Text ->@@ -381,38 +389,38 @@       prefix "!" (mkUnyOp LNot),       prefix "~" (mkUnyOp Compl)     ],-    [ binary "*" (mkBinOp (Arith Mul)),-      binary "/" (mkBinOp (Arith Div)),-      binary "%" (mkBinOp (Arith Mod))+    [ binary "*" (mkBinOp Mul),+      binary "/" (mkBinOp Div),+      binary "%" (mkBinOp Mod)     ],-    [ binary "+" (mkBinOp (Arith Add)),-      binary "-" (mkBinOp (Arith Sub)),+    [ binary "+" (mkBinOp Add),+      binary "-" (mkBinOp Sub),       Postfix postfixObjectMerge     ],-    [ binary ">>" (mkBinOp (Bitwise ShiftR)),-      binary "<<" (mkBinOp (Bitwise ShiftL))+    [ binary ">>" (mkBinOp ShiftR),+      binary "<<" (mkBinOp ShiftL)     ],     [ binary "in" (mkBinOp In),-      binary ">" (mkBinOp (Comp Gt)),-      binary "<=" (mkBinOp (Comp Le)),-      binary ">=" (mkBinOp (Comp Ge)),-      binary "<" (mkBinOp (Comp Lt))+      binary ">" (mkBinOp Gt),+      binary "<=" (mkBinOp Le),+      binary ">=" (mkBinOp Ge),+      binary "<" (mkBinOp Lt)     ],-    [ binary "==" (mkBinOp (Comp Eq)),-      binary "!=" (mkBinOp (Comp Ne))+    [ binary "==" (mkBinOp Eq),+      binary "!=" (mkBinOp Ne)     ],-    [binary "&" (mkBinOp (Bitwise And))],-    [binary "^" (mkBinOp (Bitwise Xor))],-    [binary "|" (mkBinOp (Bitwise Or))],-    [binary "&&" (mkBinOp (Logical LAnd))],-    [binary "||" (mkBinOp (Logical LOr))]+    [binary "&" (mkBinOp And)],+    [binary "^" (mkBinOp Xor)],+    [binary "|" (mkBinOp Or)],+    [binary "&&" (mkBinOp LAnd)],+    [binary "||" (mkBinOp LOr)]   ]  -- | shorthand syntax for object composition: -- when the right-hand side is an object literal the '+' -- operator can be elided. postfixObjectMerge :: Parser (Expr' -> Expr')-postfixObjectMerge = flip (mkBinOp (Arith Add)) <$> objectP+postfixObjectMerge = flip (mkBinOp Add) <$> objectP  -- | application, indexing and lookup: e(...) e[...] e.f -- all have the same precedence (the highest)
src/Language/Jsonnet/Pretty.hs view
@@ -155,9 +155,10 @@  instance Pretty (StackFrame a) where   pretty StackFrame {..} =-    pretty span <+> pretty name'+    pretty span <+> pretty (f $ name2String name)     where-      name' = (<+>) (text "function") . angles . pretty <$> name+      f "top-level" = mempty+      f x = text "function" <+> (angles $ pretty x)  instance Pretty (Backtrace a) where   pretty (Backtrace xs) = vcat $ pretty <$> xs
src/Language/Jsonnet/Std/Lib.hs view
@@ -1,4 +1,6 @@+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE LiberalTypeSynonyms #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}@@ -10,6 +12,7 @@   ) where +import Control.Lens (view) import Control.Monad.Except import Control.Monad.State import Data.Aeson (FromJSON (..))@@ -18,14 +21,17 @@ import Data.Foldable (foldrM) import Data.HashMap.Lazy (HashMap) import qualified Data.HashMap.Lazy as H-import Data.List (sort)+import qualified Data.List as L (intercalate, sort) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Encoding as T+import Data.Vector (Vector)+import qualified Data.Vector as V import Data.Word import Language.Jsonnet.Common-import Language.Jsonnet.Core (Fun (Fun), KeyValue (..))+import Language.Jsonnet.Core import Language.Jsonnet.Error+import Language.Jsonnet.Eval import Language.Jsonnet.Eval.Monad import Language.Jsonnet.Parser.SrcSpan import Language.Jsonnet.Value@@ -36,94 +42,58 @@ import Prelude hiding (length) import qualified Prelude as P (length) --- | The native subset of Jsonnet standard library+-- | Jsonnet standard library built-in methods std :: Value std = VObj $ H.fromList $ map f xs   where-    f = \(k, v) -> (k, TV <$> Hideable v Hidden)+    f = \(k, v) -> (k, VField (VStr k) v v Hidden)     xs =-      ("thisFile", inj <$> thisFile) :-      map-        (\(k, v) -> (k, pure v))-        [ ("type", inj valueType),-          ("primitiveEquals", inj primitiveEquals),-          ("equals", inj equals),-          ("length", inj length),-          ("pow", inj ((^^) @Double @Int)),-          ("exp", inj (exp @Double)),-          ("log", inj (log @Double)),-          ("exponent", inj (exponent @Double)),-          ("mantissa", inj (significand @Double)),-          ("floor", inj (floor @Double @Integer)),-          ("ceil", inj (ceiling @Double @Integer)),-          ("sqrt", inj (sqrt @Double)),-          ("sin", inj (sin @Double)),-          ("cos", inj (cos @Double)),-          ("tan", inj (tan @Double)),-          ("asin", inj (asin @Double)),-          ("acos", inj (acos @Double)),-          ("atan", inj (atan @Double)),-          ("modulo", inj (mod @Integer)),-          ("codepoint", inj (fromEnum . T.head)),-          ("char", inj (T.singleton . toEnum)),-          ("encodeUTF8", inj (B.unpack . T.encodeUtf8 :: Text -> [Word8])),-          ("decodeUTF8", inj (T.decodeUtf8 . B.pack :: [Word8] -> Text)),-          ("makeArray", inj makeArray),-          ("filter", inj (filterM @Eval @Value)),-          ("objectHasEx", inj objectHasEx),-          ("objectFieldsEx", inj objectFieldsEx),-          ("parseJson", inj (JSON.decodeStrict @Value))-        ]--primitiveEquals :: Value -> Value -> Eval Bool-primitiveEquals VNull VNull = pure True-primitiveEquals (VBool a) (VBool b) = pure (a == b)-primitiveEquals (VStr a) (VStr b) = pure (a == b)-primitiveEquals (VNum a) (VNum b) = pure (a == b)-primitiveEquals a b =-  throwE-    ( StdError $-        text $-          T.unpack $-            "primitiveEquals operates on primitive types "-              <> valueType a-              <> valueType b-    )+      [ ("type", inj showTy),+        ("primitiveEquals", inj primitiveEquals),+        ("equals", inj equals),+        ("length", inj length),+        ("pow", inj ((^^) @Double @Int)),+        ("exp", inj (exp @Double)),+        ("log", inj (log @Double)),+        ("exponent", inj (exponent @Double)),+        ("mantissa", inj (significand @Double)),+        ("floor", inj (floor @Double @Integer)),+        ("ceil", inj (ceiling @Double @Integer)),+        ("sqrt", inj (sqrt @Double)),+        ("sin", inj (sin @Double)),+        ("cos", inj (cos @Double)),+        ("tan", inj (tan @Double)),+        ("asin", inj (asin @Double)),+        ("acos", inj (acos @Double)),+        ("atan", inj (atan @Double)),+        ("modulo", inj (mod @Integer)),+        ("codepoint", inj (fromEnum . T.head)),+        ("char", inj (T.singleton . toEnum)),+        ("encodeUTF8", inj (B.unpack . T.encodeUtf8 :: Text -> [Word8])),+        ("decodeUTF8", inj (T.decodeUtf8 . B.pack :: [Word8] -> Text)),+        ("makeArray", inj (makeArray @Eval)),+        ("filter", inj (filterM @Eval @Value)),+        ("join", inj intercalate),+        ("objectHasEx", inj objectHasEx),+        ("objectFieldsEx", inj objectFieldsEx),+        ("parseJson", inj (JSON.decodeStrict @Value))+      ] -equals :: Value -> Value -> Eval Bool-equals as@(VArr a) bs@(VArr b)-  | P.length a == P.length b = do-    as' <- proj as-    bs' <- proj bs-    allM (uncurry equals) (zip as' bs')-  | P.length a /= P.length b = pure False-equals (VObj a) (VObj b) = do-  let fields = objectFieldsEx a False-  if fields /= objectFieldsEx b False-    then pure False-    else allM objectFieldEquals fields+intercalate :: Value -> [Value] -> Eval Value+intercalate sep arr = go sep (filter null arr)   where-    objectFieldEquals field = do-      a' <- force (value $ a H.! field)-      b' <- force (value $ b H.! field)-      equals a' b'-equals a b-  | valueType a == valueType b = primitiveEquals a b-equals _ _ = pure False--objectFieldsEx :: Object -> Bool -> [Text]-objectFieldsEx o True = sort (H.keys o) -- all fields-objectFieldsEx o False = sort $ H.keys $ H.filter (not . hidden) o -- only visible (incl. forced)--objectHasEx :: Object -> Text -> Bool -> Bool-objectHasEx o f all = f `elem` objectFieldsEx o all+    null VNull = False+    null _ = True+    go sep@(VArr _) = app (L.intercalate @Value) sep+    go sep@(VStr _) = app T.intercalate sep+    app f sep arr = inj <$> (f <$> proj sep <*> traverse proj arr)  length :: Value -> Eval Int length = \case   VStr s -> pure $ T.length s   VArr a -> pure $ P.length a   VObj o -> pure $ P.length (H.keys o)-  VClos (Fun f) _ -> do+  VClos f _ -> do     (ps, _) <- unbind f     pure $ P.length (unrec ps)   v ->@@ -132,20 +102,11 @@           text $             T.unpack $               "length operates on strings, objects, functions and arrays, got "-                <> valueType v+              --   <> showTy v       ) -makeArray :: Int -> (Int -> Eval Value) -> Eval [Value]-makeArray n f = traverse f [0 .. n - 1]---- hacky way of returning the current file-thisFile :: Eval (Maybe FilePath)-thisFile = f <$> gets currentPos-  where-    f = fmap (takeFileName . sourceName . spanBegin)--allM :: Monad m => (a -> m Bool) -> [a] -> m Bool-allM p = foldrM (\a b -> (&& b) <$> p a) True+makeArray :: Monad m => Int -> (Int -> m Value) -> m (Vector Value)+makeArray n f = traverse f (V.fromList [0 .. n - 1])  instance FromJSON Value where   parseJSON = \case@@ -153,13 +114,13 @@     JSON.Bool b -> pure $ VBool b     JSON.Number n -> pure $ VNum n     JSON.String s -> pure $ VStr s-    JSON.Array a -> VArr <$> traverse (fmap mkThunk' . parseJSON) a+    JSON.Array a -> VArr <$> traverse parseJSON a     JSON.Object o -> VObj . f <$> traverse parseJSON o     where       f :: HashMap Text Value -> Object       f o =         H.fromList-          [ (mkField k (mkThunk' v))+          [ mkField k v             | (k, v) <- H.toList o           ]-      mkField k v = (k, Hideable v Visible)+      mkField k v = (k, VField (VStr k) v v Visible)
src/Language/Jsonnet/Std/TH.hs view
@@ -8,13 +8,15 @@ import Language.Haskell.TH.Quote () import Language.Haskell.TH.Syntax (addDependentFile) import Language.Jsonnet.TH (parse)+import TH.RelativePaths (pathRelativeToCabalPackage)  stdlibPath :: String stdlibPath = "stdlib/std.jsonnet"  mkStdlib :: Q Exp mkStdlib = do+  fp <- pathRelativeToCabalPackage stdlibPath+  addDependentFile fp   src <- runIO (TIO.readFile stdlibPath)   ast <- parse stdlibPath src-  addDependentFile stdlibPath   pure ast
src/Language/Jsonnet/Syntax.hs view
@@ -23,7 +23,7 @@  type Param a = (Ident, Maybe a) -data Field a = Field+data EField a = EField   { key :: a,     value :: a,     visibility :: Visibility,@@ -41,9 +41,9 @@       Traversable     ) -instance Alpha a => Alpha (Field a)+instance Alpha a => Alpha (EField a) -deriveShow1 ''Field+deriveShow1 ''EField  data ExprF a   = ELit Literal@@ -51,12 +51,16 @@   | EFun [Param a] a   | EApply a (Args a)   | ELocal-      { bnds :: NonEmpty (Ident, a),+      { -- | non-empty list of recursive bindings+        bnds :: NonEmpty (Ident, a),+        -- | body expression         expr :: a       }   | EObj-      { locals :: [(Ident, a)],-        fields :: [Field a]+      { -- |+        locals :: [(Ident, a)],+        -- |+        fields :: [EField a]         --asserts :: [Assert a]       }   | EArr [a]@@ -67,20 +71,29 @@   | EIf a a   | EIfElse a a a   | ESlice-      { expr :: a,+      { -- |+        expr :: a,+        -- |         start :: Maybe a,+        -- |         end :: Maybe a,+        -- |         step :: Maybe a       }   | EBinOp BinOp a a   | EUnyOp UnyOp a   | EArrComp-      { expr :: a,+      { -- |+        expr :: a,+        -- |         comp :: NonEmpty (CompSpec a)       }   | EObjComp-      { field :: Field a,+      { -- |+        field :: EField a,+        -- |         locals :: [(Ident, a)],+        -- |         comp :: NonEmpty (CompSpec a)       }   deriving@@ -142,10 +155,24 @@ mkIndexF :: a -> a -> ExprF' a mkIndexF e = InL . EIndex e -mkSliceF :: a -> Maybe a -> Maybe a -> Maybe a -> ExprF' a+mkSliceF ::+  -- |+  a ->+  -- |+  Maybe a ->+  -- |+  Maybe a ->+  -- |+  Maybe a ->+  ExprF' a mkSliceF e f g = InL . ESlice e f g -mkObjectF :: [Field a] -> [(Ident, a)] -> ExprF' a+mkObjectF ::+  -- |+  [EField a] ->+  -- |+  [(Ident, a)] ->+  ExprF' a mkObjectF fs ls = InL $ EObj ls fs  mkArrayF :: [a] -> ExprF' a@@ -160,5 +187,12 @@ mkArrCompF :: a -> NonEmpty (CompSpec a) -> ExprF' a mkArrCompF e = InL . EArrComp e -mkObjCompF :: Field a -> [(Ident, a)] -> NonEmpty (CompSpec a) -> ExprF' a+mkObjCompF ::+  -- |+  EField a ->+  -- |+  [(Ident, a)] ->+  -- |+  NonEmpty (CompSpec a) ->+  ExprF' a mkObjCompF f ls = InL . EObjComp f ls
src/Language/Jsonnet/Syntax/Annotated.hs view
@@ -10,10 +10,10 @@ import Language.Jsonnet.Parser.SrcSpan import Language.Jsonnet.Syntax --- annotated syntax tree with resolved imports+-- | annotated syntax tree with resolved imports type Expr = Ann ExprF SrcSpan --- annotated syntax tree with unresolved imports+-- | annotated syntax tree with unresolved imports type Expr' = Ann ExprF' SrcSpan  mkApply :: Expr' -> Args Expr' -> Expr'
src/Language/Jsonnet/TH.hs view
@@ -29,9 +29,6 @@ instance Data a => Lift (Arg a) where   lift = liftData -instance Data a => Lift (Hideable a) where-  lift = liftData- instance Lift SrcSpan where   lift = liftData @@ -47,28 +44,16 @@ instance Lift Literal where   lift = liftData -instance Lift Scientific where-  lift s = [|fromRational $(return $ LitE $ RationalL (toRational s))|]--instance Lift BinOp where-  lift = liftData--instance Lift ArithOp where-  lift = liftData--instance Lift CompOp where-  lift = liftData--instance Lift BitwiseOp where+instance Lift Prim where   lift = liftData -instance Lift LogicalOp where+instance Lift BinOp where   lift = liftData  instance Lift UnyOp where   lift = liftData -instance Data a => Lift (Field a) where+instance Data a => Lift (EField a) where   lift = liftData  instance Data a => Lift (Assert a) where@@ -99,7 +84,7 @@  -- ouch: https://gitlab.haskell.org/ghc/ghc/-/issues/12596 liftDataWithText :: Data a => a -> Q Exp-liftDataWithText = dataToExpQ (\a -> liftText <$> cast a)+liftDataWithText = dataToExpQ (fmap liftText . cast)  parse :: FilePath -> Text -> Q Exp parse path str = do
src/Language/Jsonnet/Value.hs view
@@ -1,216 +1,90 @@-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RecordWildCards #-}  -- | module Language.Jsonnet.Value where -import Control.Applicative-import Control.Arrow+import Control.Lens (view) import Control.Monad.Except-import Control.Monad.IO.Class import Control.Monad.Reader-import Control.Monad.State.Lazy-import Data.Bits-import Data.ByteString (ByteString)-import Data.Data import Data.HashMap.Lazy (HashMap)-import qualified Data.HashMap.Lazy as H-import Data.Hashable (Hashable) import Data.IORef-import Data.Int import Data.Map.Lazy (Map)-import qualified Data.Map.Lazy as M-import Data.Scientific (Scientific, fromFloatDigits, toRealFloat)+import Data.Scientific import Data.Text (Text)-import qualified Data.Text as T-import Data.Text.Encoding (decodeUtf8, encodeUtf8)-import Data.Typeable-import Data.Vector (Vector, (!?))-import qualified Data.Vector as V-import Debug.Trace-import GHC.Generics (Generic)+import Data.Vector (Vector)+import GHC.Generics import Language.Jsonnet.Common import Language.Jsonnet.Core-import Language.Jsonnet.Error-import {-# SOURCE #-} Language.Jsonnet.Eval (eval, evalClos) import Language.Jsonnet.Eval.Monad-import Language.Jsonnet.Parser.SrcSpan import Language.Jsonnet.Pretty ()-import Text.PrettyPrint.ANSI.Leijen (Doc, pretty) import Unbound.Generics.LocallyNameless --- jsonnet value+type Eval = EvalM Value++type Env = Ctx Value+ data Value   = VNull   | VBool !Bool-  | VNum !Scientific   | VStr !Text-  | VArr !Array-  | VObj !(HashMap Text (Hideable Thunk))-  | VClos !Fun !Env-  | VFun !(Thunk -> Eval Value)-  deriving (Generic)+  | VNum !Scientific+  | VObj !Object -- !Object+  | VArr !(Vector Value)+  | VThunk !Core !Env+  | VIndir !Ref+  | VPrim !Prim+  | VClos !Lam !Env+  | VFun !Fun -type Array = Vector Thunk+data VField = VField+  { -- |+    fieldKey :: Value,+    -- |+    fieldValWHNF :: Value,+    -- |+    fieldVal :: Value,+    -- |+    fieldVis :: Visibility+  }+  deriving (Generic) -type Object = HashMap Text (Hideable Thunk)+type Fun = Value -> Eval Value -valueType :: Value -> Text-valueType =-  \case-    VNull -> "null"-    VBool _ -> "boolean"-    VNum _ -> "number"-    VStr _ -> "string"-    VArr _ -> "array"-    VObj _ -> "object"-    VClos _ _ -> "function"-    VFun _ -> "function"+type Object = HashMap Text VField -data Thunk = TC !Ctx !Core | TV !(Eval Value)+data Cell = Cell {cellVal :: Value, cellIsWHNF :: Bool}   deriving (Generic) -force :: Thunk -> Eval Value-force = \case-  TC rho expr -> withCtx rho (eval expr)-  TV comp -> comp--mkThunk' :: Value -> Thunk-mkThunk' = TV . pure--mkThunk :: MonadIO m => Eval Value -> m Thunk-mkThunk ev = do-  ref <- liftIO $ newIORef Nothing-  pure $-    TV $-      liftIO (readIORef ref) >>= \case-        Nothing -> do-          v <- ev-          liftIO $ writeIORef ref $ Just v-          pure v-        Just v -> pure v+type Ref = IORef Cell -proj' :: HasValue a => Thunk -> Eval a-proj' = force >=> proj+instance HasVisibility VField where+  visible VField {..} = fieldVis == Visible+  forced VField {..} = fieldVis == Forced+  hidden VField {..} = fieldVis == Hidden  class HasValue a where-  proj :: Value -> Eval a   inj :: a -> Value+  proj :: Value -> Eval a -instance {-# OVERLAPS #-} HasValue Value where-  proj = pure+instance HasValue Value where   inj = id--instance HasValue Bool where-  proj (VBool n) = pure n-  proj v = throwTypeMismatch "bool" v-  inj = VBool--instance HasValue Text where-  proj (VStr s) = pure s-  proj v = throwTypeMismatch "string" v-  inj = VStr--instance {-# OVERLAPPING #-} HasValue [Char] where-  proj (VStr s) = pure $ T.unpack s-  proj v = throwTypeMismatch "string" v-  inj = VStr . T.pack--instance HasValue ByteString where-  proj (VStr s) = pure (encodeUtf8 s)-  proj v = throwTypeMismatch "string" v-  inj = VStr . decodeUtf8--instance HasValue Scientific where-  proj (VNum n) = pure n-  proj v = throwTypeMismatch "number" v-  inj = VNum--instance HasValue Double where-  proj (VNum n) = pure (toRealFloat n)-  proj v = throwTypeMismatch "number" v-  inj = VNum . fromFloatDigits--instance {-# OVERLAPS #-} Integral a => HasValue a where-  proj (VNum n) = pure (round n)-  proj v = throwTypeMismatch "number" v-  inj = VNum . fromIntegral--instance HasValue a => HasValue (Maybe a) where-  proj VNull = pure Nothing-  proj a = Just <$> proj a-  inj Nothing = VNull-  inj (Just a) = inj a--instance HasValue a => HasValue (Vector a) where-  proj (VArr as) = traverse proj' as-  proj v = throwTypeMismatch "array" v-  inj as = VArr $ mkThunk' . inj <$> as--instance {-# OVERLAPS #-} HasValue (Vector Thunk) where-  proj (VArr as) = pure as-  proj v = throwTypeMismatch "array" v-  inj = VArr--instance {-# OVERLAPPABLE #-} HasValue a => HasValue [a] where-  proj = fmap V.toList . proj-  inj = inj . V.fromList--instance {-# OVERLAPS #-} HasValue Object where-  proj (VObj o) = pure o-  proj v = throwTypeMismatch "object" v-  inj = VObj--instance {-# OVERLAPS #-} (HasValue a, HasValue b) => HasValue (a -> b) where-  proj v = throwTypeMismatch "impossible" v-  inj f = VFun $ \x -> force x >>= fmap (inj . f) . proj--instance {-# OVERLAPS #-} (HasValue a, HasValue b, HasValue c) => HasValue (a -> b -> c) where-  proj v = throwTypeMismatch "impossible" v-  inj f = inj $ \x -> inj (f x)--instance {-# OVERLAPS #-} (HasValue a, HasValue b) => HasValue (a -> Eval b) where-  proj (VFun f) = pure $ \x -> do-    r <- f (mkThunk' $ inj x)-    proj r-  proj (VClos f env) = pure $ \x -> do-    r <- evalClos (ctx env) f $ [Pos $ mkThunk' $ inj x]-    proj r-  proj v = throwTypeMismatch "function" v-  inj f = VFun $ \v -> proj' v >>= fmap inj . f+  proj = pure -instance {-# OVERLAPS #-} (HasValue a, HasValue b, HasValue c) => HasValue (a -> b -> Eval c) where-  proj (VFun f) = pure $ \x y -> do-    VFun g <- f (mkThunk' $ inj x)-    r <- g (mkThunk' $ inj y)-    proj r-  proj (VClos f env) = pure $ \x y -> do-    r <- evalClos (ctx env) f $ Pos . mkThunk' <$> [inj x, inj y]-    proj r-  proj v = throwTypeMismatch "function" v-  inj f = inj $ \x -> inj (f x)+mkCell :: Value -> Cell+mkCell v = Cell v False -throwTypeMismatch :: Text -> Value -> Eval a-throwTypeMismatch expected =-  throwE-    . TypeMismatch expected-    . valueType+mkIndirV :: MonadIO m => Value -> m Value+mkIndirV v = VIndir <$> allocate v -inj' ::-  (HasValue a, HasValue b) =>-  (a -> b) ->-  (Value -> Eval Value)-inj' f v = inj . f <$> proj v+mkThunk :: Core -> Eval Value+mkThunk c = VThunk c <$> view ctx -inj'' ::-  (HasValue a, HasValue b, HasValue c) =>-  (a -> b -> c) ->-  Value ->-  Value ->-  Eval Value-inj'' f v1 v2 = inj <$> liftA2 f (proj v1) (proj v2)+allocate :: MonadIO m => Value -> m (IORef Cell)+allocate = liftIO . newIORef . mkCell
− src/Language/Jsonnet/Value.hs-boot
@@ -1,5 +0,0 @@-module Language.Jsonnet.Value where--data Value--data Thunk
test/golden/Test.hs view
@@ -18,7 +18,6 @@ import Language.Jsonnet.Desugar import Language.Jsonnet.Error import Language.Jsonnet.Eval-import Language.Jsonnet.Eval (mergeWith) import Language.Jsonnet.Eval.Monad import Language.Jsonnet.Pretty () import qualified Language.Jsonnet.Std.Lib as Lib@@ -45,22 +44,13 @@ goldenTests :: IO TestTree goldenTests = do   jsonnetFiles <- findByExtension [".jsonnet"] "./test/golden"-  stdlib <- mkThunk std   return $     testGroup       "Jsonnet golden tests"       [ goldenVsString           (takeBaseName jsonnetFile) -- test name           goldenFile -- golden file path-          (run $ Config jsonnetFile stdlib)+          (run $ Config jsonnetFile)         | jsonnetFile <- jsonnetFiles,           let goldenFile = replaceExtension jsonnetFile ".golden"       ]---- the jsonnet stdlib is written in both jsonnet and Haskell, here we merge--- the native (small, Haskell) with the interpreted (the splice mkStdlib)-std :: Eval Value-std = eval core >>= flip mergeObjects Lib.std-  where-    core = desugar (annMap (const ()) $mkStdlib)-    mergeObjects (VObj x) (VObj y) = pure $ VObj (x `mergeWith` y)