-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
{-# LANGUAGE DeriveDataTypeable, ExtendedDefaultRules, OverloadedLists, | ||
QuasiQuotes, TypeFamilies, TypeSynonymInstances, | ||
MultiParamTypeClasses #-} | ||
module Nirum.Targets.Rust ( Rust | ||
, Code | ||
, CompileError | ||
) where | ||
|
||
import qualified Data.Map.Strict as M | ||
import qualified Data.SemVer as SV | ||
import qualified Data.Text as T | ||
import Data.Text.Encoding (encodeUtf8) | ||
import Data.Text.Lazy (toStrict) | ||
import Data.Typeable (Typeable) | ||
|
||
import GHC.Exts (IsList (toList)) | ||
|
||
import System.FilePath (joinPath, replaceExtension) | ||
|
||
import Text.Blaze.Renderer.Text | ||
import Text.Heterocephalus (compileText) | ||
|
||
import qualified Nirum.Constructs.Identifier as I | ||
import Nirum.Constructs.Module | ||
import Nirum.Constructs.ModulePath (ModulePath) | ||
import Nirum.Constructs.Name | ||
import Nirum.Constructs.TypeDeclaration | ||
import Nirum.Package.Metadata | ||
import qualified Nirum.Package.ModuleSet as MS | ||
import Nirum.Targets.Rust.Keyword | ||
import Nirum.TypeInstance.BoundModule | ||
|
||
data Rust = Rust { packageName :: T.Text | ||
} | ||
deriving (Eq, Ord, Show, Typeable) | ||
|
||
type Code = T.Text | ||
type CompileError' = () | ||
|
||
genCargoToml :: Package Rust -> Code | ||
genCargoToml Package { metadata = Metadata { version = version' | ||
, target = Rust { packageName = name' } | ||
} | ||
} = | ||
toStrict $ | ||
renderMarkup [compileText|[package] | ||
name = "#{ name' }" | ||
version = "#{ SV.toLazyText version' }" | ||
|] | ||
|
||
compileModule :: BoundModule Rust -> Code | ||
compileModule m = | ||
toStrict $ | ||
renderMarkup [compileText|%{ forall (moduleName, members') <- enums } | ||
pub enum #{ toRustIdentifier I.toPascalCaseText $ facialName moduleName } { | ||
%{ forall EnumMember memberName _ <- members' } | ||
#{ toRustIdentifier I.toPascalCaseText $ facialName memberName }, | ||
%{ endforall } | ||
} | ||
%{ endforall } | ||
|] | ||
where | ||
moduleTypes :: [TypeDeclaration] | ||
moduleTypes = toList $ boundTypes m | ||
enums :: [(Name, [EnumMember])] | ||
enums = | ||
[ (moduleName, toList members') | ||
| TypeDeclaration { typename = moduleName | ||
, type' = EnumType { members = members' } | ||
} <- moduleTypes | ||
] | ||
|
||
compilePackage' :: Package Rust | ||
-> M.Map FilePath (Either CompileError' Code) | ||
compilePackage' package = | ||
M.fromList $ | ||
[ ( toFilename mp | ||
, Right $ compileModule m | ||
) | ||
| (mp, _) <- modules' | ||
, Just m <- [resolveBoundModule mp package] | ||
] ++ | ||
[ ("Cargo.toml", Right $ genCargoToml package) | ||
, (joinPath ["src", "lib.rs"], Right "") | ||
] | ||
where | ||
convertModulePath :: ModulePath -> [FilePath] | ||
convertModulePath mp = | ||
"src" : | ||
[ T.unpack (toRustIdentifier I.toSnakeCaseText i) | ||
| i <- toList mp | ||
] | ||
toFilename :: ModulePath -> FilePath | ||
toFilename mp = | ||
replaceExtension (joinPath $ convertModulePath mp) "rs" | ||
modules' :: [(ModulePath, Module)] | ||
modules' = MS.toAscList $ modules package | ||
|
||
instance Target Rust where | ||
type CompileResult Rust = Code | ||
type CompileError Rust = CompileError' | ||
|
||
targetName _ = "rust" | ||
parseTarget table = do | ||
name' <- stringField "name" table | ||
return Rust { packageName = name' | ||
} | ||
compilePackage = compilePackage' | ||
showCompileError _ _ = "" | ||
toByteString _ = encodeUtf8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
{-# LANGUAGE ExtendedDefaultRules, OverloadedLists, TypeSynonymInstances #-} | ||
module Nirum.Targets.Rust.Keyword ( isPossibleKeyword | ||
, toRustIdentifier | ||
) where | ||
|
||
import qualified Data.Set as S | ||
import qualified Data.Text as T | ||
|
||
import qualified Nirum.Constructs.Identifier as I | ||
|
||
-- | The set of Rust keywords. | ||
-- See also: https://doc.rust-lang.org/reference/keywords.html | ||
strictKeywords :: S.Set T.Text | ||
strictKeywords = | ||
[ "as", "box", "break", "const", "continue" | ||
, "crate", "else", "enum", "extern", "false" | ||
, "fn", "for", "if", "impl", "in", "let" | ||
, "loop", "match", "mod", "move", "mut", "pub" | ||
, "ref", "return", "self", "Self", "static" | ||
, "struct", "super", "trait", "true", "type" | ||
, "unsafe", "use", "where", "while" | ||
] | ||
weakKeywords :: S.Set T.Text | ||
weakKeywords = | ||
[ "catch", "default", "union", "'static" ] | ||
reservedKeywords :: S.Set T.Text | ||
reservedKeywords = | ||
[ "abstract", "alignof", "become", "do" | ||
, "final", "macro", "offsetof", "override" | ||
, "priv", "proc", "pure", "sizeof", "typeof" | ||
, "unsized", "virtual", "yield" | ||
] | ||
|
||
isPossibleKeyword :: T.Text -> Bool | ||
isPossibleKeyword name' = | ||
(findMember strictKeywords) || | ||
(findMember weakKeywords) || | ||
(findMember reservedKeywords) | ||
where | ||
findMember :: S.Set T.Text -> Bool | ||
findMember = S.member name' | ||
|
||
toRustIdentifier :: (I.Identifier -> T.Text) -> I.Identifier -> T.Text | ||
toRustIdentifier convertIdent identifier = | ||
if isPossibleKeyword attrName then attrName `T.snoc` '_' else attrName | ||
where | ||
attrName :: T.Text | ||
attrName = convertIdent identifier |