summaryrefslogtreecommitdiff
path: root/ddl/Generate.hs
blob: 855406f8d0d7d4f4494387bbe1d647a20639d225 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
{-# LANGUAGE OverloadedStrings, FlexibleInstances, LambdaCase #-}
import qualified Data.Text.Lazy as LText
import           Text.EDE
import           Text.EDE.Filters

import           Data.HashMap.Strict          (HashMap)
import qualified Data.HashMap.Strict          as HashMap
import           Data.Text                    (Text)
import qualified Data.Map as Map
import qualified Data.Set as Set

import System.Directory
import System.FilePath

import Data.Time.Clock
import Control.Monad.Writer

import Definitions
import Language

instance Unquote [Field]
instance Unquote [Char]
instance Quote [Char]
instance Quote [Instance]
instance Unquote DataDef
instance Unquote Type
instance Unquote [(Target,Instance)]

main :: IO ()
main = do
  dataSwift <- eitherParseFile "templates/data.swift.ede"
  dataJava <- eitherParseFile "templates/data.java.ede"
  jsonJava <- eitherParseFile "templates/json.java.ede"
  dataHpp <- eitherParseFile "templates/data.hpp.ede"
  dataHpp2 <- eitherParseFile "templates/data.hpp2.ede"
  dataCpp <- eitherParseFile "templates/data.cpp.ede"
  dataCs <- eitherParseFile "templates/data.cs.ede"
  dataHs <- eitherParseFile "templates/data.hs.ede"
  dataPs <- eitherParseFile "templates/data.purs.ede"
  let generate mod@(ModuleDef name imports def) = do
        dt <- getCurrentTime
        let env = fromPairs
              [ "dataAndType" .= def
              , "definitions" .= [a | a@DataDef{} <- def ]
              , "moduleName"  .= name
              , "dateTime"    .= dt
              , "imports"     .= imports
              , "usedTypes"   .= collectTypes aliasMap mod
              , "usedCSTypes"   .= (Set.fromList $ Map.elems $ Map.fromList [ (csType name aliasMap t,t) | t <- Set.toList $ collectTypes aliasMap mod])
              ]
            aliasMap = Map.fromList [(n,t) | TypeAlias n t <- def]
            mylib :: HashMap Text Term
            mylib = HashMap.fromList
                [ "hasFieldNames"   @: hasFieldNames
                , "parens"          @: parens
                , "constType"       @: constType
                , "hsType"          @: hsType aliasMap
                , "psType"          @: psType aliasMap
                , "cppType"         @: cppType aliasMap
                , "csType"          @: csType name aliasMap
                , "typeEnum"        @: typeEnum aliasMap
                , "javaType"        @: javaType aliasMap
                , "swiftType"       @: swiftType aliasMap
                , "hasEnumConstructor" @: hasEnumConstructor
                , "psInstances"     @: filterInstances PureScript
                , "hsInstances"     @: filterInstances Haskell
                ]

            toPath a = flip map a $ \case
              '.' -> '/'
              c -> c

            writeFileIfDiffer fname txt = doesFileExist fname >>= \case
              False -> do
                        createDirectoryIfMissing True $ takeDirectory fname
                        writeFile fname txt
              True  -> do
                        oldTxt <- readFile fname
                        case (lines oldTxt, lines txt) of
                          (_ : oldTime : old, _ : newTime : new) | old == new -> return () -- NOTE: timestamp is always in the second line
                          _ -> removeFile fname >> writeFile fname txt

        -- Haskell
        either error (\x -> writeFileIfDiffer ("out/haskell/" ++ toPath name ++ ".hs") $ LText.unpack x) $ dataHs >>= (\t -> eitherRenderWith mylib t env)
        -- Purescript
        either error (\x -> writeFileIfDiffer ("out/purescript/" ++ toPath name ++ ".purs") $ LText.unpack x) $ dataPs >>= (\t -> eitherRenderWith mylib t env)
        -- C++
        either error (\x -> writeFileIfDiffer ("out/cpp/" ++ name ++ "2.hpp") $ LText.unpack x) $ dataHpp2 >>= (\t -> eitherRenderWith mylib t env)
        either error (\x -> writeFileIfDiffer ("out/cpp/" ++ name ++ ".hpp") $ LText.unpack x) $ dataHpp >>= (\t -> eitherRenderWith mylib t env)
        either error (\x -> writeFileIfDiffer ("out/cpp/" ++ name ++ ".cpp") $ LText.unpack x) $ dataCpp >>= (\t -> eitherRenderWith mylib t env)
        -- Java
        forM_ [a | a@DataDef{} <- def {-TODO-}] $ \d -> do
          let env = fromPairs
                [ "def"         .= d
                , "moduleName"  .= name
                , "dateTime"    .= dt
                , "imports"     .= imports
                ]
              fname = "out/java/" ++ toPath name ++ "/" ++ dataName d ++ ".java"
          either error (\x -> writeFileIfDiffer fname $ LText.unpack x) $ dataJava >>= (\t -> eitherRenderWith mylib t env)
        either error (\x -> writeFileIfDiffer ("out/java/" ++ toPath name ++ "/JSON.java") $ LText.unpack x) $ jsonJava >>= (\t -> eitherRenderWith mylib t env)
        -- C#
        either error (\x -> writeFileIfDiffer ("out/csharp/" ++ name ++ ".cs") $ LText.unpack x) $ dataCs >>= (\t -> eitherRenderWith mylib t env)
        -- Swift
        either error (\x -> writeFileIfDiffer ("out/swift/" ++ name ++ ".swift") $ LText.unpack x) $ dataSwift >>= (\t -> eitherRenderWith mylib t env)
  mapM_ generate $ execWriter modules