module Language.PureScript.CoreFn.FromJSON
( moduleFromJSON
) where
import Prelude.Compat
import Data.Aeson
import Data.Aeson.Types (Parser, Value, listParser)
import Data.Text (Text)
import qualified Data.Text as T
import Text.ParserCombinators.ReadP (readP_to_S)
import qualified Data.Vector as V
import Data.Version (Version, parseVersion)
import Language.PureScript.AST.SourcePos (SourceSpan(SourceSpan))
import Language.PureScript.AST.Literals
import Language.PureScript.CoreFn.Ann
import Language.PureScript.CoreFn
import Language.PureScript.Names
import Language.PureScript.PSString (PSString)
constructorTypeFromJSON :: Value -> Parser ConstructorType
constructorTypeFromJSON v = do
t <- parseJSON v
case t of
"ProductType" -> return ProductType
"SumType" -> return SumType
_ -> fail ("not recognized ConstructorType: " ++ T.unpack t)
metaFromJSON :: Value -> Parser (Maybe Meta)
metaFromJSON Null = return Nothing
metaFromJSON v = withObject "Meta" metaFromObj v
where
metaFromObj o = do
type_ <- o .: "metaType"
case type_ of
"IsConstructor" -> isConstructorFromJSON o
"IsNewtype" -> return $ Just IsNewtype
"IsTypeClassConstructor"
-> return $ Just IsTypeClassConstructor
"IsForeign" -> return $ Just IsForeign
"IsWhere" -> return $ Just IsWhere
_ -> fail ("not recognized Meta: " ++ T.unpack type_)
isConstructorFromJSON o = do
ct <- o .: "constructorType" >>= constructorTypeFromJSON
is <- o .: "identifiers" >>= listParser identFromJSON
return $ Just (IsConstructor ct is)
annFromJSON :: FilePath -> Value -> Parser Ann
annFromJSON modulePath = withObject "Ann" annFromObj
where
annFromObj o = do
ss <- o .: "sourceSpan" >>= sourceSpanFromJSON modulePath
mm <- o .: "meta" >>= metaFromJSON
return (ss, [], Nothing, mm)
sourceSpanFromJSON :: FilePath -> Value -> Parser SourceSpan
sourceSpanFromJSON modulePath = withObject "SourceSpan" $ \o ->
SourceSpan modulePath <$>
o .: "start" <*>
o .: "end"
literalFromJSON :: (Value -> Parser a) -> Value -> Parser (Literal a)
literalFromJSON t = withObject "Literal" literalFromObj
where
literalFromObj o = do
type_ <- o .: "literalType" :: Parser Text
case type_ of
"IntLiteral" -> NumericLiteral . Left <$> o .: "value"
"NumberLiteral" -> NumericLiteral . Right <$> o .: "value"
"StringLiteral" -> StringLiteral <$> o .: "value"
"CharLiteral" -> CharLiteral <$> o .: "value"
"BooleanLiteral" -> BooleanLiteral <$> o .: "value"
"ArrayLiteral" -> parseArrayLiteral o
"ObjectLiteral" -> parseObjectLiteral o
_ -> fail ("error parsing Literal: " ++ show o)
parseArrayLiteral o = do
val <- o .: "value"
as <- mapM t (V.toList val)
return $ ArrayLiteral as
parseObjectLiteral o = do
val <- o .: "value"
ObjectLiteral <$> recordFromJSON t val
identFromJSON :: Value -> Parser Ident
identFromJSON = withText "Ident" (return . Ident)
properNameFromJSON :: Value -> Parser (ProperName a)
properNameFromJSON = fmap ProperName . parseJSON
qualifiedFromJSON :: (Text -> a) -> Value -> Parser (Qualified a)
qualifiedFromJSON f = withObject "Qualified" qualifiedFromObj
where
qualifiedFromObj o = do
mn <- o .:? "moduleName" >>= traverse moduleNameFromJSON
i <- o .: "identifier" >>= withText "Ident" (return . f)
return $ Qualified mn i
moduleNameFromJSON :: Value -> Parser ModuleName
moduleNameFromJSON v = ModuleName <$> listParser properNameFromJSON v
moduleFromJSON :: Value -> Parser (Version, Module Ann)
moduleFromJSON = withObject "Module" moduleFromObj
where
moduleFromObj o = do
version <- o .: "builtWith" >>= versionFromJSON
moduleName <- o .: "moduleName" >>= moduleNameFromJSON
modulePath <- o .: "modulePath"
moduleSourceSpan <- o .: "sourceSpan" >>= sourceSpanFromJSON modulePath
moduleImports <- o .: "imports" >>= listParser (importFromJSON modulePath)
moduleExports <- o .: "exports" >>= listParser identFromJSON
moduleDecls <- o .: "decls" >>= listParser (bindFromJSON modulePath)
moduleForeign <- o .: "foreign" >>= listParser identFromJSON
moduleComments <- o .: "comments" >>= listParser parseJSON
return (version, Module {..})
versionFromJSON :: String -> Parser Version
versionFromJSON v =
case readP_to_S parseVersion v of
(r, _) : _ -> return r
_ -> fail "failed parsing purs version"
importFromJSON :: FilePath -> Value -> Parser (Ann, ModuleName)
importFromJSON modulePath = withObject "Import"
(\o -> do
ann <- o .: "annotation" >>= annFromJSON modulePath
mn <- o .: "moduleName" >>= moduleNameFromJSON
return (ann, mn))
bindFromJSON :: FilePath -> Value -> Parser (Bind Ann)
bindFromJSON modulePath = withObject "Bind" bindFromObj
where
bindFromObj :: Object -> Parser (Bind Ann)
bindFromObj o = do
type_ <- o .: "bindType" :: Parser Text
case type_ of
"NonRec" -> (uncurry . uncurry) NonRec <$> bindFromObj' o
"Rec" -> Rec <$> (o .: "binds" >>= listParser (withObject "Bind" bindFromObj'))
_ -> fail ("not recognized bind type \"" ++ T.unpack type_ ++ "\"")
bindFromObj' :: Object -> Parser ((Ann, Ident), Expr Ann)
bindFromObj' o = do
a <- o .: "annotation" >>= annFromJSON modulePath
i <- o .: "identifier" >>= identFromJSON
e <- o .: "expression" >>= exprFromJSON modulePath
return ((a, i), e)
recordFromJSON :: (Value -> Parser a) -> Value -> Parser [(PSString, a)]
recordFromJSON p = listParser parsePair
where
parsePair v = do
(l, v') <- parseJSON v :: Parser (PSString, Value)
a <- p v'
return (l, a)
exprFromJSON :: FilePath -> Value -> Parser (Expr Ann)
exprFromJSON modulePath = withObject "Expr" exprFromObj
where
exprFromObj o = do
type_ <- o .: "type"
case type_ of
"Var" -> varFromObj o
"Literal" -> literalExprFromObj o
"Constructor" -> constructorFromObj o
"Accessor" -> accessorFromObj o
"ObjectUpdate" -> objectUpdateFromObj o
"Abs" -> absFromObj o
"App" -> appFromObj o
"Case" -> caseFromObj o
"Let" -> letFromObj o
_ -> fail ("not recognized expression type: \"" ++ T.unpack type_ ++ "\"")
varFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
qi <- o .: "value" >>= qualifiedFromJSON Ident
return $ Var ann qi
literalExprFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
lit <- o .: "value" >>= literalFromJSON (exprFromJSON modulePath)
return $ Literal ann lit
constructorFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
tyn <- o .: "typeName" >>= properNameFromJSON
con <- o .: "constructorName" >>= properNameFromJSON
is <- o .: "fieldNames" >>= listParser identFromJSON
return $ Constructor ann tyn con is
accessorFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
f <- o .: "fieldName"
e <- o .: "expression" >>= exprFromJSON modulePath
return $ Accessor ann f e
objectUpdateFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
e <- o .: "expression" >>= exprFromJSON modulePath
us <- o .: "updates" >>= recordFromJSON (exprFromJSON modulePath)
return $ ObjectUpdate ann e us
absFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
idn <- o .: "argument" >>= identFromJSON
e <- o .: "body" >>= exprFromJSON modulePath
return $ Abs ann idn e
appFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
e <- o .: "abstraction" >>= exprFromJSON modulePath
e' <- o .: "argument" >>= exprFromJSON modulePath
return $ App ann e e'
caseFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
cs <- o .: "caseExpressions" >>= listParser (exprFromJSON modulePath)
cas <- o .: "caseAlternatives" >>= listParser (caseAlternativeFromJSON modulePath)
return $ Case ann cs cas
letFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
bs <- o .: "binds" >>= listParser (bindFromJSON modulePath)
e <- o .: "expression" >>= exprFromJSON modulePath
return $ Let ann bs e
caseAlternativeFromJSON :: FilePath -> Value -> Parser (CaseAlternative Ann)
caseAlternativeFromJSON modulePath = withObject "CaseAlternative" caseAlternativeFromObj
where
caseAlternativeFromObj o = do
bs <- o .: "binders" >>= listParser (binderFromJSON modulePath)
isGuarded <- o .: "isGuarded"
if isGuarded
then do
es <- o .: "expressions" >>= listParser parseResultWithGuard
return $ CaseAlternative bs (Left es)
else do
e <- o .: "expression" >>= exprFromJSON modulePath
return $ CaseAlternative bs (Right e)
parseResultWithGuard :: Value -> Parser (Guard Ann, Expr Ann)
parseResultWithGuard = withObject "parseCaseWithGuards" $
\o -> do
g <- o .: "guard" >>= exprFromJSON modulePath
e <- o .: "expression" >>= exprFromJSON modulePath
return (g, e)
binderFromJSON :: FilePath -> Value -> Parser (Binder Ann)
binderFromJSON modulePath = withObject "Binder" binderFromObj
where
binderFromObj o = do
type_ <- o .: "binderType"
case type_ of
"NullBinder" -> nullBinderFromObj o
"VarBinder" -> varBinderFromObj o
"LiteralBinder" -> literalBinderFromObj o
"ConstructorBinder" -> constructorBinderFromObj o
"NamedBinder" -> namedBinderFromObj o
_ -> fail ("not recognized binder: \"" ++ T.unpack type_ ++ "\"")
nullBinderFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
return $ NullBinder ann
varBinderFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
idn <- o .: "identifier" >>= identFromJSON
return $ VarBinder ann idn
literalBinderFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
lit <- o .: "literal" >>= literalFromJSON (binderFromJSON modulePath)
return $ LiteralBinder ann lit
constructorBinderFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
tyn <- o .: "typeName" >>= qualifiedFromJSON ProperName
con <- o .: "constructorName" >>= qualifiedFromJSON ProperName
bs <- o .: "binders" >>= listParser (binderFromJSON modulePath)
return $ ConstructorBinder ann tyn con bs
namedBinderFromObj o = do
ann <- o .: "annotation" >>= annFromJSON modulePath
n <- o .: "identifier" >>= identFromJSON
b <- o .: "binder" >>= binderFromJSON modulePath
return $ NamedBinder ann n b