module Hydra.Ext.Scala.Serde where

import Hydra.Util.Codetree.Ast
import Hydra.Util.Codetree.Script
import qualified Hydra.Lib.Literals as Literals
import qualified Hydra.Util.Codetree.Ast as CT
import qualified Hydra.Ext.Scala.Meta as Scala

import qualified Data.List as L
import qualified Data.Maybe as Y


dotOp :: Op
dotOp :: Op
dotOp = Symbol -> Padding -> Precedence -> Associativity -> Op
Op (String -> Symbol
Symbol String
".") (Ws -> Ws -> Padding
Padding Ws
WsNone Ws
WsNone) (Int -> Precedence
Precedence Int
0) Associativity
AssociativityLeft

functionArrowOp :: Op
functionArrowOp :: Op
functionArrowOp = String -> Int -> Associativity -> Op
op String
"=>" (forall a. Num a => a -> a
negate Int
1) Associativity
AssociativityRight

matchOp :: Op
matchOp :: Op
matchOp = Symbol -> Padding -> Precedence -> Associativity -> Op
Op (String -> Symbol
Symbol String
"match") (Ws -> Ws -> Padding
Padding Ws
WsSpace Ws
WsBreakAndIndent) (Int -> Precedence
Precedence Int
0) Associativity
AssociativityNone

writeCase :: Scala.Case -> CT.Expr
writeCase :: Case -> Expr
writeCase (Scala.Case Pat
pat Maybe Data
_ Data
term) = [Expr] -> Expr
spaceSep [String -> Expr
cst String
"case", Pat -> Expr
writePat Pat
pat, String -> Expr
cst String
"=>", Data -> Expr
writeTerm Data
term]

writeDefn :: Scala.Defn -> CT.Expr
writeDefn :: Defn -> Expr
writeDefn Defn
def = case Defn
def of
  Scala.DefnDef (Scala.Defn_Def [Mod]
_ Data_Name
name [Type_Param]
tparams [[Data_Param]
params] Maybe Type
scod Data
body) -> [Expr] -> Expr
spaceSep [
      String -> Expr
cst String
"def", Expr
nameAndParams, String -> Expr
cst String
"=", Data -> Expr
writeTerm Data
body]
    where
      nameAndParams :: Expr
nameAndParams = [Expr] -> Expr
noSep forall a b. (a -> b) -> a -> b
$ forall a. [Maybe a] -> [a]
Y.catMaybes [
        forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Data_Name -> Expr
writeData_Name Data_Name
name,
        if forall (t :: * -> *) a. Foldable t => t a -> Bool
L.null [Type_Param]
tparams then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ BlockStyle -> [Expr] -> Expr
bracketList BlockStyle
inlineStyle (Type_Param -> Expr
writeType_Param forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Type_Param]
tparams),
        forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Bool -> [Expr] -> Expr
parenList Bool
False (Data_Param -> Expr
writeData_Param forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Data_Param]
params),
        forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Type
t -> [Expr] -> Expr
spaceSep [String -> Expr
cst String
":", Type -> Expr
writeType Type
t]) Maybe Type
scod]
  Scala.DefnVal (Scala.Defn_Val [Mod]
_ [Scala.PatVar (Scala.Pat_Var (Scala.Data_Name (Scala.PredefString String
name)))] Maybe Type
typ Data
term) -> [Expr] -> Expr
spaceSep [
      String -> Expr
cst String
"val", Expr
nameAndType, String -> Expr
cst String
"=", Data -> Expr
writeTerm Data
term]
    where
      nameAndType :: Expr
nameAndType = forall b a. b -> (a -> b) -> Maybe a -> b
Y.maybe (String -> Expr
cst String
name) (\Type
t -> [Expr] -> Expr
spaceSep [String -> Expr
cst forall a b. (a -> b) -> a -> b
$ String
name forall a. [a] -> [a] -> [a]
++ String
":", Type -> Expr
writeType Type
t]) Maybe Type
typ

writeImportExportStat :: Scala.ImportExportStat -> CT.Expr
writeImportExportStat :: ImportExportStat -> Expr
writeImportExportStat ImportExportStat
ie = case ImportExportStat
ie of
  Scala.ImportExportStatImport (Scala.Import [Importer]
importers) -> [Expr] -> Expr
newlineSep (Importer -> Expr
writeImporter forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Importer]
importers)
--  Scala.ImportExportStatExport exp ->

writeImporter :: Scala.Importer -> CT.Expr
writeImporter :: Importer -> Expr
writeImporter (Scala.Importer (Scala.Data_RefName (Scala.Data_Name (Scala.PredefString String
ref))) [Importee]
importees) = [Expr] -> Expr
spaceSep [
    String -> Expr
cst String
"import", [Expr] -> Expr
noSep [String -> Expr
cst String
ref, [Importee] -> Expr
forImportees [Importee]
importees]]
  where
    forImportee :: Importee -> Expr
forImportee Importee
it = String -> Expr
cst forall a b. (a -> b) -> a -> b
$ case Importee
it of
      Importee
Scala.ImporteeWildcard -> String
"*"
      Scala.ImporteeName (Scala.Importee_Name (Scala.NameValue String
name)) -> String
name
    forImportees :: [Importee] -> Expr
forImportees [Importee]
its = if forall (t :: * -> *) a. Foldable t => t a -> Bool
L.null [Importee]
its
      then String -> Expr
cst String
""
      else if forall (t :: * -> *) a. Foldable t => t a -> Int
L.length [Importee]
its forall a. Eq a => a -> a -> Bool
== Int
1
      then [Expr] -> Expr
noSep [String -> Expr
cst String
".", Importee -> Expr
forImportee forall a b. (a -> b) -> a -> b
$ forall a. [a] -> a
L.head [Importee]
its]
      else [Expr] -> Expr
noSep [String -> Expr
cst String
".", BlockStyle -> [Expr] -> Expr
curlyBracesList BlockStyle
inlineStyle (Importee -> Expr
forImportee forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Importee]
its)]
writeLit :: Scala.Lit -> CT.Expr
writeLit :: Lit -> Expr
writeLit Lit
lit = case Lit
lit of
--  Scala.LitNull
  Scala.LitInt Int
i -> String -> Expr
cst forall a b. (a -> b) -> a -> b
$ Int -> String
Literals.showInt32 Int
i
--  Scala.LitDouble Double
--  Scala.LitFloat Float
--  Scala.LitByte Integer
--  Scala.LitShort Integer
--  Scala.LitChar Integer
--  Scala.LitLong Int64
  Scala.LitBoolean Bool
b -> String -> Expr
cst forall a b. (a -> b) -> a -> b
$ if Bool
b then String
"true" else String
"false"
  Lit
Scala.LitUnit -> String -> Expr
cst String
"()"
  Scala.LitString String
s -> String -> Expr
cst forall a b. (a -> b) -> a -> b
$ String -> String
Literals.showString String
s
--  Scala.LitSymbol sym ->
  Lit
_ -> String -> Expr
cst forall a b. (a -> b) -> a -> b
$ String -> String
Literals.showString forall a b. (a -> b) -> a -> b
$ String
"TODO:literal:" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Lit
lit

writeName :: Scala.Name -> CT.Expr
writeName :: Name -> Expr
writeName Name
name = case Name
name of
  Scala.NameValue String
s -> String -> Expr
cst String
s

writePat :: Scala.Pat -> CT.Expr
writePat :: Pat -> Expr
writePat Pat
pat = case Pat
pat of
  Scala.PatExtract (Scala.Pat_Extract Data
fun [Pat]
args) -> [Expr] -> Expr
noSep [Data -> Expr
writeTerm Data
fun, Bool -> [Expr] -> Expr
parenList Bool
False (Pat -> Expr
writePat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Pat]
args)]
  Scala.PatVar (Scala.Pat_Var Data_Name
tname) -> Data_Name -> Expr
writeData_Name Data_Name
tname

writePkg :: Scala.Pkg -> CT.Expr
writePkg :: Pkg -> Expr
writePkg (Scala.Pkg Data_Name
name Data_Ref
_ [Stat]
stats) = [Expr] -> Expr
doubleNewlineSep forall a b. (a -> b) -> a -> b
$ Expr
packageforall a. a -> [a] -> [a]
:(Stat -> Expr
writeStat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Stat]
stats)
  where
    package :: Expr
package = [Expr] -> Expr
spaceSep [String -> Expr
cst String
"package", Data_Name -> Expr
writeData_Name Data_Name
name]

writeStat :: Scala.Stat -> CT.Expr
writeStat :: Stat -> Expr
writeStat Stat
stat = case Stat
stat of
--  Scala.StatTerm Term ->
--  Scala.StatDecl Decl ->
  Scala.StatDefn Defn
def -> Defn -> Expr
writeDefn Defn
def
  Scala.StatImportExport ImportExportStat
ie -> ImportExportStat -> Expr
writeImportExportStat ImportExportStat
ie

writeTerm :: Scala.Data -> CT.Expr
writeTerm :: Data -> Expr
writeTerm Data
term = case Data
term of
  Scala.DataLit Lit
lit -> Lit -> Expr
writeLit Lit
lit
  Scala.DataRef Data_Ref
ref -> Data_Ref -> Expr
writeData_Ref Data_Ref
ref
  Scala.DataApply (Scala.Data_Apply Data
fun [Data]
args) -> [Expr] -> Expr
noSep [Data -> Expr
writeTerm Data
fun, Bool -> [Expr] -> Expr
parenList Bool
False (Data -> Expr
writeTerm forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Data]
args)]
  Scala.DataAssign Data_Assign
assign -> String -> Expr
cst String
">ASSIGN"
  Scala.DataTuple (Scala.Data_Tuple [Data]
args) -> Bool -> [Expr] -> Expr
parenList Bool
False (Data -> Expr
writeTerm forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Data]
args)
  Scala.DataMatch (Scala.Data_Match Data
expr [Case]
cases) -> Op -> Expr -> Expr -> Expr
ifx Op
matchOp (Data -> Expr
writeTerm Data
expr) forall a b. (a -> b) -> a -> b
$ [Expr] -> Expr
newlineSep (Case -> Expr
writeCase forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Case]
cases)
  Scala.DataFunctionData Data_FunctionData
ft -> Data_FunctionData -> Expr
writeData_FunctionData Data_FunctionData
ft

writeData_FunctionData :: Scala.Data_FunctionData -> CT.Expr
writeData_FunctionData :: Data_FunctionData -> Expr
writeData_FunctionData Data_FunctionData
ft = case Data_FunctionData
ft of
  Scala.Data_FunctionDataFunction (Scala.Data_Function [Data_Param]
params Data
body) ->
    [Expr] -> Expr
spaceSep [Bool -> [Expr] -> Expr
parenList Bool
False (Data_Param -> Expr
writeData_Param forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Data_Param]
params), String -> Expr
cst String
"=>", Data -> Expr
writeTerm Data
body]

writeData_Name :: Scala.Data_Name -> CT.Expr
writeData_Name :: Data_Name -> Expr
writeData_Name (Scala.Data_Name (Scala.PredefString String
name)) = String -> Expr
cst String
name

writeData_Param :: Scala.Data_Param -> CT.Expr
writeData_Param :: Data_Param -> Expr
writeData_Param (Scala.Data_Param [Mod]
_ Name
name Maybe Type
stype Maybe Data
_) = [Expr] -> Expr
noSep forall a b. (a -> b) -> a -> b
$ forall a. [Maybe a] -> [a]
Y.catMaybes [
  forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Name -> Expr
writeName Name
name,
  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Type
t -> [Expr] -> Expr
spaceSep [String -> Expr
cst String
":", Type -> Expr
writeType Type
t]) Maybe Type
stype]

writeData_Ref :: Scala.Data_Ref -> CT.Expr
writeData_Ref :: Data_Ref -> Expr
writeData_Ref Data_Ref
ref = case Data_Ref
ref of
  Scala.Data_RefName Data_Name
name -> Data_Name -> Expr
writeData_Name Data_Name
name
  Scala.Data_RefSelect Data_Select
sel -> Data_Select -> Expr
writeData_Select Data_Select
sel

writeData_Select :: Scala.Data_Select -> CT.Expr
writeData_Select :: Data_Select -> Expr
writeData_Select (Scala.Data_Select Data
arg Data_Name
name) = Op -> Expr -> Expr -> Expr
ifx Op
dotOp (Data -> Expr
writeTerm Data
arg) (Data -> Expr
writeTerm Data
proj)
  where
    proj :: Data
proj = Data_Ref -> Data
Scala.DataRef forall a b. (a -> b) -> a -> b
$ Data_Name -> Data_Ref
Scala.Data_RefName Data_Name
name

writeType :: Scala.Type -> CT.Expr
writeType :: Type -> Expr
writeType Type
typ = case Type
typ of
  Scala.TypeRef (Scala.Type_RefName Type_Name
name) -> Type_Name -> Expr
writeType_Name Type_Name
name
  Scala.TypeApply (Scala.Type_Apply Type
fun [Type]
args) -> [Expr] -> Expr
noSep [Type -> Expr
writeType Type
fun, BlockStyle -> [Expr] -> Expr
bracketList BlockStyle
inlineStyle (Type -> Expr
writeType forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Type]
args)]
  Scala.TypeFunctionType (Scala.Type_FunctionTypeFunction (Scala.Type_Function [Type
dom] Type
cod)) -> Op -> Expr -> Expr -> Expr
ifx Op
functionArrowOp (Type -> Expr
writeType Type
dom) (Type -> Expr
writeType Type
cod)
  Scala.TypeLambda (Scala.Type_Lambda [Type_Param]
params Type
body) -> [Expr] -> Expr
noSep [Type -> Expr
writeType Type
body, BlockStyle -> [Expr] -> Expr
bracketList BlockStyle
inlineStyle (Type_Param -> Expr
writeType_Param forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Type_Param]
params)]
  Scala.TypeVar (Scala.Type_Var Type_Name
name) -> Type_Name -> Expr
writeType_Name Type_Name
name
  Type
_ -> String -> Expr
cst forall a b. (a -> b) -> a -> b
$ String
"UNKNOWN TYPE: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Type
typ

writeType_Name :: Scala.Type_Name -> CT.Expr
writeType_Name :: Type_Name -> Expr
writeType_Name (Scala.Type_Name String
name) = String -> Expr
cst String
name

writeType_Param :: Scala.Type_Param -> CT.Expr
writeType_Param :: Type_Param -> Expr
writeType_Param (Scala.Type_Param [] Name
n [] [] [] []) = Name -> Expr
writeName Name
n