module Language.Virgil
( -- * Virgil Parsers
decode
, eitherDecode
, decodeStrict
, eitherDecodeStrict
-- * Re-Exported Aeson Types
-- ** Core JSON Types
, Aeson.Value(..)
, Aeson.Array
, Aeson.Object
-- ** Type Conversion
, Aeson.FromJSON(..)
, Aeson.ToJSON(..)
, Aeson.Result(..)
, Aeson.fromJSON
-- ** Inspecting Values
, Aeson.withObject
, Aeson.withText
, Aeson.withArray
, Aeson.withScientific
, Aeson.withBool
-- ** Accessors
, (Aeson..:)
, (Aeson..:?)
, (Aeson..:!)
, (Aeson..!=)
) where
import Data.Aeson (FromJSON, Result(..), fromJSON)
import qualified Data.Aeson as Aeson
import qualified Data.ByteString as BSE
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy.Char8 as BS
import Language.Virgil.AST (ChValue)
import Language.Virgil.Eval
import Language.Virgil.Lexer
import Language.Virgil.Parser
parseVirgil :: ByteString -> Either String ChValue
parseVirgil = runAlex' parse "<input>" . BS.unpack
-- | Deserialize and execute a Virgil program. If parsing fails,
-- or if type-checking fails, or if the execution of the Virgil
-- program otherwise fails at runtime, then this function will
-- return 'Nothing'.
--
-- Note that Virgil rules out recursive programs, so executing a
-- Virgil program won't loop forever---but it may still take
-- a fair amount longer than parsing the equivalent JSON!
decode :: FromJSON a => ByteString -> Maybe a
decode bs = case eitherDecode bs of
Error err -> Nothing
Success val -> pure val
-- | Deserialize and execute a Virgil program. If parsing fails,
-- or if type-checking fails, or if the execution of the Virgil
-- program otherwise fails at runtime, then this function will
-- return an approrpriately informative error message.
eitherDecode :: FromJSON a => ByteString -> Result a
eitherDecode bs = case parseVirgil bs of
Left err -> Error err
Right ch -> case evalCh ch of
Left err -> Error err
Right v -> fromJSON v
decodeStrict :: FromJSON a => BSE.ByteString -> Maybe a
decodeStrict = decode . BS.fromStrict
eitherDecodeStrict :: FromJSON a => BSE.ByteString -> Result a
eitherDecodeStrict = eitherDecode . BS.fromStrict