Skip to content

Commit 4659c74

Browse files
committed
Declare submodules in mod.rs and lib.rs
1 parent aa706dd commit 4659c74

File tree

3 files changed

+176
-38
lines changed

3 files changed

+176
-38
lines changed

src/Nirum/Targets/Rust.hs

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,24 @@ module Nirum.Targets.Rust ( Rust
99
import qualified Data.Map.Strict as M
1010
import qualified Data.SemVer as SV
1111
import qualified Data.Text as T
12+
import qualified Data.Text.Lazy as TL
1213
import Data.Text.Encoding (encodeUtf8)
1314
import Data.Text.Lazy (toStrict)
1415
import Data.Typeable (Typeable)
1516

1617
import GHC.Exts (IsList (toList))
1718

18-
import System.FilePath (joinPath, replaceExtension)
19-
2019
import Text.Blaze.Renderer.Text
2120
import Text.Heterocephalus (compileText)
2221

2322
import qualified Nirum.Constructs.Identifier as I
24-
import Nirum.Constructs.Module
2523
import Nirum.Constructs.ModulePath (ModulePath)
26-
import Nirum.Constructs.Name
2724
import Nirum.Constructs.TypeDeclaration
2825
import Nirum.Package.Metadata
2926
import qualified Nirum.Package.ModuleSet as MS
27+
import Nirum.Targets.Rust.Item
3028
import Nirum.Targets.Rust.Keyword
29+
import Nirum.Targets.Rust.ModuleTree
3130
import Nirum.TypeInstance.BoundModule
3231

3332
data Rust = Rust { packageName :: T.Text
@@ -48,53 +47,41 @@ name = "#{ name' }"
4847
version = "#{ SV.toLazyText version' }"
4948
|]
5049

51-
compileModule :: BoundModule Rust -> Code
52-
compileModule m =
53-
toStrict $
54-
renderMarkup [compileText|%{ forall (moduleName, members') <- enums }
55-
pub enum #{ toRustIdentifier I.toPascalCaseText $ facialName moduleName } {
56-
%{ forall EnumMember memberName _ <- members' }
57-
#{ toRustIdentifier I.toPascalCaseText $ facialName memberName },
58-
%{ endforall }
59-
}
50+
buildPrologue :: RustModule -> TL.Text
51+
buildPrologue mod' =
52+
renderMarkup [compileText|%{ forall child <- children mod' }
53+
pub mod #{ toRustIdentifier I.toCamelCaseText child };
6054
%{ endforall }
6155
|]
56+
57+
buildBody :: Maybe (BoundModule Rust) -> TL.Text
58+
buildBody (Just m) =
59+
TL.concat [renderItem i | i <- moduleTypes]
6260
where
6361
moduleTypes :: [TypeDeclaration]
6462
moduleTypes = toList $ boundTypes m
65-
enums :: [(Name, [EnumMember])]
66-
enums =
67-
[ (moduleName, toList members')
68-
| TypeDeclaration { typename = moduleName
69-
, type' = EnumType { members = members' }
70-
} <- moduleTypes
71-
]
63+
buildBody Nothing = TL.empty
7264

7365
compilePackage' :: Package Rust
7466
-> M.Map FilePath (Either CompileError' Code)
7567
compilePackage' package =
7668
M.fromList $
77-
[ ( toFilename mp
78-
, Right $ compileModule m
69+
[ ( fileName
70+
, Right $
71+
toStrict $
72+
TL.append (buildPrologue mod')
73+
(buildBody (mp >>= resolveWithModulePath))
7974
)
80-
| (mp, _) <- modules'
81-
, Just m <- [resolveBoundModule mp package]
75+
| mod'@RustModule { filePath = fileName
76+
, modPath = mp
77+
} <- modules'
8278
] ++
83-
[ ("Cargo.toml", Right $ genCargoToml package)
84-
, (joinPath ["src", "lib.rs"], Right "")
85-
]
79+
[ ("Cargo.toml", Right $ genCargoToml package) ]
8680
where
87-
convertModulePath :: ModulePath -> [FilePath]
88-
convertModulePath mp =
89-
"src" :
90-
[ T.unpack (toRustIdentifier I.toSnakeCaseText i)
91-
| i <- toList mp
92-
]
93-
toFilename :: ModulePath -> FilePath
94-
toFilename mp =
95-
replaceExtension (joinPath $ convertModulePath mp) "rs"
96-
modules' :: [(ModulePath, Module)]
97-
modules' = MS.toAscList $ modules package
81+
resolveWithModulePath :: ModulePath -> Maybe (BoundModule Rust)
82+
resolveWithModulePath mp = resolveBoundModule mp package
83+
modules' :: [RustModule]
84+
modules' = buildRustModuleList [mp | (mp, _) <- MS.toAscList $ modules package]
9885

9986
instance Target Rust where
10087
type CompileResult Rust = Code

src/Nirum/Targets/Rust/Item.hs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{-# LANGUAGE ExtendedDefaultRules, OverloadedLists, TypeSynonymInstances,
2+
QuasiQuotes #-}
3+
module Nirum.Targets.Rust.Item ( renderItem
4+
) where
5+
6+
import qualified Data.Text.Lazy as TL
7+
8+
import GHC.Exts (IsList (toList))
9+
10+
import Text.Blaze.Renderer.Text
11+
import Text.Heterocephalus (compileText)
12+
13+
import qualified Nirum.Constructs.Identifier as I
14+
import Nirum.Constructs.Name
15+
import Nirum.Constructs.TypeDeclaration
16+
import Nirum.Targets.Rust.Keyword
17+
18+
renderItem :: TypeDeclaration -> TL.Text
19+
renderItem TypeDeclaration { typename = moduleName
20+
, type' = ty
21+
} =
22+
renderType ty
23+
where
24+
renderType :: Type -> TL.Text
25+
renderType EnumType { members = members' } =
26+
renderMarkup [compileText|
27+
pub enum #{ toRustIdentifier I.toPascalCaseText $ facialName moduleName } {
28+
%{ forall EnumMember memberName _ <- toList members' }
29+
#{ toRustIdentifier I.toPascalCaseText $ facialName memberName },
30+
%{ endforall }
31+
}
32+
|]
33+
renderType _ = TL.empty
34+
renderItem _ = TL.empty

src/Nirum/Targets/Rust/ModuleTree.hs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
{-# LANGUAGE OverloadedLists, TypeSynonymInstances #-}
2+
module Nirum.Targets.Rust.ModuleTree ( RustModule ( RustModule
3+
, filePath
4+
, modPath
5+
, children
6+
)
7+
, buildRustModuleList
8+
) where
9+
10+
import Data.List
11+
import qualified Data.Text as T
12+
import Data.Tree
13+
14+
import GHC.Exts (IsList (toList))
15+
16+
import System.FilePath (joinPath)
17+
18+
import Nirum.Constructs.Identifier
19+
import Nirum.Constructs.ModulePath (ModulePath)
20+
import Nirum.Targets.Rust.Keyword
21+
22+
data UnpackedModule = UnpackedModule { unpackedModulePath :: [Identifier]
23+
, originalModulePath :: ModulePath
24+
}
25+
data ModuleNode = ModuleNode { moduleName :: Identifier
26+
, moduleNodePath :: Maybe ModulePath
27+
}
28+
29+
instance Eq UnpackedModule where
30+
a == b = (unpackedModulePath a) == (unpackedModulePath b)
31+
instance Ord UnpackedModule where
32+
a <= b = (unpackedModulePath a) <= (unpackedModulePath b)
33+
34+
type ModuleTree = Tree ModuleNode
35+
36+
data RustModule = RustModule { filePath :: FilePath
37+
, modPath :: Maybe ModulePath
38+
, children :: [Identifier]
39+
}
40+
41+
-- type a = Identifier
42+
-- type b = (Identifier, [UnpackedModule])
43+
-- moduleUnfolder :: b -> (a, [b])
44+
moduleUnfolder :: (ModuleNode, [UnpackedModule])
45+
-> (ModuleNode, [(ModuleNode, [UnpackedModule])])
46+
moduleUnfolder (ident, mps) =
47+
(ident, groupByParent mps)
48+
where
49+
isParentEqual :: UnpackedModule -> UnpackedModule -> Bool
50+
isParentEqual UnpackedModule { unpackedModulePath = (a:_) }
51+
UnpackedModule { unpackedModulePath = (b:_) } =
52+
a == b
53+
isParentEqual _ _ = False
54+
extractCommonParent :: [UnpackedModule] -> (ModuleNode, [UnpackedModule])
55+
extractCommonParent mps' =
56+
( ModuleNode { moduleName = commonParent
57+
, moduleNodePath = maybeModulePath
58+
}
59+
, [ UnpackedModule { unpackedModulePath = x:xs
60+
, originalModulePath = omn
61+
}
62+
| UnpackedModule { unpackedModulePath = x:xs
63+
, originalModulePath = omn
64+
} <- mps'
65+
]
66+
)
67+
where
68+
commonParent :: Identifier
69+
commonParent = head $ unpackedModulePath $ head mps'
70+
maybeModulePath :: Maybe ModulePath
71+
maybeModulePath =
72+
fmap originalModulePath $
73+
find (((==) 1) . length . unpackedModulePath) mps'
74+
groupByParent :: [UnpackedModule] -> [(ModuleNode, [UnpackedModule])]
75+
groupByParent = (map extractCommonParent) . (groupBy isParentEqual) . sort
76+
77+
buildModuleTree :: [ModulePath] -> ModuleTree
78+
buildModuleTree mps =
79+
unfoldTree moduleUnfolder seed
80+
where
81+
srcModule :: ModuleNode
82+
srcModule = ModuleNode { moduleName = "src"
83+
, moduleNodePath = Nothing
84+
}
85+
seed :: (ModuleNode, [UnpackedModule])
86+
seed = ( srcModule
87+
, [ UnpackedModule { unpackedModulePath = toList mp
88+
, originalModulePath = mp
89+
}
90+
| mp <- mps
91+
]
92+
)
93+
94+
toRustModuleList :: [String] -> ModuleTree -> [RustModule]
95+
toRustModuleList baseDir Node { rootLabel = ModuleNode { moduleName = modName
96+
, moduleNodePath = modPath'
97+
}
98+
, subForest = children'
99+
} =
100+
RustModule { filePath = joinPath identPath
101+
, modPath = modPath'
102+
, children = map (moduleName . rootLabel) children'
103+
} :
104+
(concat $ map (toRustModuleList identPath) children')
105+
where
106+
libOrMod :: String
107+
libOrMod = case baseDir of
108+
[] -> "lib.rs"
109+
_ -> "mod.rs"
110+
identPath :: [String]
111+
identPath =
112+
baseDir ++
113+
[T.unpack $ toRustIdentifier toSnakeCaseText modName] ++
114+
[libOrMod]
115+
116+
buildRustModuleList :: [ModulePath] -> [RustModule]
117+
buildRustModuleList = (toRustModuleList []) . buildModuleTree

0 commit comments

Comments
 (0)