Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added aliased import #258

Merged
merged 16 commits into from
Apr 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ To be released.
- Fixed a compiler bug that an error message on name duplicates had referred
to a wrong line/column number. [[#255]]

- Added aliased import. It's handy to avoid a name shadowing.
[[#217], [#258]]

~~~~~~~~ nirum
import iso (country as iso-country);
import types (country);
~~~~~~~~


### Docs target

- A new required configuration `targets.docs.title` was added.
Expand Down Expand Up @@ -175,12 +184,14 @@ To be released.
March 2018.

[#13]: https://github.com/spoqa/nirum/issues/13
[#217]: https://github.com/spoqa/nirum/issues/217
[#220]: https://github.com/spoqa/nirum/issues/220
[#227]: https://github.com/spoqa/nirum/pull/227
[#253]: https://github.com/spoqa/nirum/pull/253
[#254]: https://github.com/spoqa/nirum/pull/254
[#255]: https://github.com/spoqa/nirum/pull/255
[#257]: https://github.com/spoqa/nirum/pull/257
[#258]: https://github.com/spoqa/nirum/pull/258
[#259]: https://github.com/spoqa/nirum/pull/259
[entry points]: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
[python2-numbers-integral]: https://docs.python.org/2/library/numbers.html#numbers.Integral
Expand Down
6 changes: 6 additions & 0 deletions examples/address.nrm
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import countries (country);
import geo (geo as geo-point);

record address (
float32 lat,
Expand All @@ -8,3 +9,8 @@ record address (
country country,
text postal-code,
);


record pin (
geo-point geo,
);
2 changes: 1 addition & 1 deletion examples/countries.nrm
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ enum country
| ax # Åland Islands
| al # Albania
| dz # Algeria
| as # American Samoa
| `as` # American Samoa
| ad # Andorra
| ao # Angola
| ai # Anguilla
Expand Down
4 changes: 4 additions & 0 deletions examples/geo.nrm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
record geo (
float32 latitude,
float32 longitude,
);
1 change: 1 addition & 0 deletions src/Nirum/Constructs/Identifier.hs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ reservedKeywords = [ "enum"
, "unboxed"
, "union"
, "default"
, "as"
]

identifierRule :: P.Parsec Void T.Text Identifier
Expand Down
14 changes: 11 additions & 3 deletions src/Nirum/Constructs/Module.hs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,18 @@ instance Construct Module where
where
typeList :: [TypeDeclaration]
typeList = DS.toList types'
importIdentifiersToCode :: (Identifier, Identifier) -> T.Text
importIdentifiersToCode (i, s) = if i == s
then toCode i
else T.concat [ toCode s
, " as "
, toCode i
]
importCodes :: [T.Text]
importCodes =
[ T.concat [ "import ", toCode p, " ("
, T.intercalate ", " $ map toCode $ S.toAscList i
, T.intercalate ", " $
map importIdentifiersToCode $ S.toAscList i
, ");"
]
| (p, i) <- M.toAscList (imports m)
Expand All @@ -76,9 +84,9 @@ instance Construct Module where
instance Documented Module where
docs (Module _ docs') = docs'

imports :: Module -> M.Map ModulePath (S.Set Identifier)
imports :: Module -> M.Map ModulePath (S.Set (Identifier, Identifier))
imports (Module decls _) =
M.fromListWith S.union [(p, [i]) | Import p i _ <- DS.toList decls]
M.fromListWith S.union [(p, [(i, s)]) | Import p i s _ <- DS.toList decls]

coreModulePath :: ModulePath
coreModulePath = ["core"]
Expand Down
19 changes: 12 additions & 7 deletions src/Nirum/Constructs/TypeDeclaration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ module Nirum.Constructs.TypeDeclaration ( EnumMember (EnumMember)
, service
, serviceAnnotations
, serviceName
, sourceName
, type'
, typeAnnotations
, typename
Expand Down Expand Up @@ -191,6 +192,7 @@ data TypeDeclaration
}
| Import { modulePath :: ModulePath
, importName :: Identifier
, sourceName :: Identifier
, importAnnotations :: AnnotationSet
}
deriving (Eq, Ord, Show)
Expand Down Expand Up @@ -285,13 +287,16 @@ instance Construct TypeDeclaration where
methodsText = T.intercalate "\n" $ map toCode methods'
docs' :: Maybe Docs
docs' = A.lookupDocs annotations'
toCode (Import path ident aSet) = T.concat [ "import "
, toCode path
, " ("
, toCode aSet
, toCode ident
, ");\n"
]
toCode (Import path iName sName aSet) = T.concat
[ "import "
, toCode path
, " ("
, toCode aSet
, if iName == sName
then toCode iName
else T.concat [ toCode sName, " as ", toCode iName ]
, ");\n"
]

instance Documented TypeDeclaration

Expand Down
8 changes: 4 additions & 4 deletions src/Nirum/Package/ModuleSet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ detectMissingImports moduleSet =
Nothing -> [MissingModulePathError path path']
Just (Module decls _) ->
[ e
| i <- S.toList idents
, e <- case DS.lookup i decls of
| (_, s) <- S.toList idents
, e <- case DS.lookup s decls of
Just TypeDeclaration {} -> []
Just ServiceDeclaration {} -> []
Just Import {} -> [MissingImportError path path' i]
Nothing -> [MissingImportError path path' i]
Just Import {} -> [MissingImportError path path' s]
Nothing -> [MissingImportError path path' s]
]
]

Expand Down
44 changes: 33 additions & 11 deletions src/Nirum/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module Nirum.Parser ( Parser
, handleNameDuplication
, handleNameDuplicationError
, identifier
, importName
, imports
, listModifier
, mapModifier
Expand All @@ -32,7 +33,7 @@ module Nirum.Parser ( Parser
, unionTypeDeclaration
) where

import Control.Monad (void, when)
import Control.Monad (unless, void, when)
import Data.Void
import qualified System.IO as SIO

Expand Down Expand Up @@ -627,28 +628,49 @@ modulePath = do
f Nothing i = Just $ ModuleName i
f (Just p) i = Just $ ModulePath p i

importName :: Parser (Identifier, A.AnnotationSet)
importName = do
importName :: [Identifier]
-> Parser (Identifier, Identifier, A.AnnotationSet)
importName forwardNames = do
aSet <- annotationSet <?> "import annotations"
spaces
iName <- identifier <?> "name to import"
return (iName, aSet)
hasAlias <- optional $ try $ do
spaces
string' "as"
aName <- case hasAlias of
Just _ -> do
spaces
uniqueIdentifier forwardNames "alias name to import"
Nothing ->
return iName
return (aName, iName, aSet)

imports :: Parser [TypeDeclaration]
imports = do
imports :: [Identifier] -> Parser [TypeDeclaration]
imports forwardNames = do
string' "import" <?> "import keyword"
spaces
path <- modulePath <?> "module path"
spaces
char '('
spaces
idents <- (importName >>= \ i -> spaces >> return i)
`sepEndBy1` (char ',' >> spaces)
<?> "names to import"
idents <- many' [] $ \ importNames' -> do
notFollowedBy $ choice [char ')', char ',' >> spaces >> char ')']
let forwardNames' = [i | (i, _, _) <- importNames'] ++ forwardNames
unless (L.null importNames') $ do
string' ","
spaces
n <- importName forwardNames'
spaces
return n
when (L.null idents) $ fail "parentheses cannot be empty"
void $ optional $ string' ","
spaces
char ')'
spaces
char ';'
return [Import path ident aSet | (ident, aSet) <- idents]
return [ Import path imp source aSet
| (imp, source, aSet) <- idents
]


module' :: Parser Module
Expand All @@ -660,7 +682,7 @@ module' = do
return d
spaces
importLists <- many $ do
importList <- imports
importList <- imports []
spaces
return importList
let imports' = [i | l <- importLists, i <- l]
Expand Down
12 changes: 6 additions & 6 deletions src/Nirum/Targets/Python/Serializers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,22 @@ compileSerializer mod' (TypeIdentifier typeId) pythonVar =
case lookupType typeId mod' of
Missing -> "None" -- must never happen
Local (Alias t) -> compileSerializer mod' t pythonVar
Imported modulePath' (Alias t) ->
Imported modulePath' _ (Alias t) ->
case resolveBoundModule modulePath' (boundPackage mod') of
Nothing -> "None" -- must never happen
Just foundMod -> compileSerializer foundMod t pythonVar
Local PrimitiveType { primitiveTypeIdentifier = p } ->
compilePrimitiveTypeSerializer p pythonVar
Imported _ PrimitiveType { primitiveTypeIdentifier = p } ->
Imported _ _ PrimitiveType { primitiveTypeIdentifier = p } ->
compilePrimitiveTypeSerializer p pythonVar
Local EnumType {} -> serializerCall
Imported _ EnumType {} -> serializerCall
Imported _ _ EnumType {} -> serializerCall
Local RecordType {} -> serializerCall
Imported _ RecordType {} -> serializerCall
Imported _ _ RecordType {} -> serializerCall
Local UnboxedType {} -> serializerCall
Imported _ UnboxedType {} -> serializerCall
Imported _ _ UnboxedType {} -> serializerCall
Local UnionType {} -> serializerCall
Imported _ UnionType {} -> serializerCall
Imported _ _ UnionType {} -> serializerCall
where
serializerCall :: Code
serializerCall = [qq|$pythonVar.__nirum_serialize__()|]
Expand Down
9 changes: 6 additions & 3 deletions src/Nirum/Targets/Python/TypeExpression.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ compileTypeExpression :: BoundModule Python
compileTypeExpression mod' (Just (TypeIdentifier i)) =
case lookupType i mod' of
Missing -> fail $ "undefined identifier: " ++ toString i
Imported _ (PrimitiveType p _) -> compilePrimitiveType p
Imported m _ -> do
insertThirdPartyImports [(toImportPath target' m, [toClassName i])]
Imported _ _ (PrimitiveType p _) -> compilePrimitiveType p
Imported m in' _ -> do
insertThirdPartyImportsA [ ( toImportPath target' m
, [(toClassName i, toClassName in')]
)
]
return $ toClassName i
Local _ -> return $ toClassName i
where
Expand Down
4 changes: 2 additions & 2 deletions src/Nirum/Targets/Python/Validators.hs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ compileValidator mod' (TypeIdentifier typeId) pythonVar =
case lookupType typeId mod' of
Missing -> return $ Validator "False" [] -- must never happen
Local (Alias typeExpr') -> compileValidator mod' typeExpr' pythonVar
Imported modulePath' (Alias typeExpr') ->
Imported modulePath' _ (Alias typeExpr') ->
case resolveBoundModule modulePath' (boundPackage mod') of
Nothing -> return $ Validator "False" [] -- must never happen
Just foundMod -> compileValidator foundMod typeExpr' pythonVar
Local PrimitiveType { primitiveTypeIdentifier = pId } ->
compilePrimitiveTypeValidator pId pythonVar
Imported _ PrimitiveType { primitiveTypeIdentifier = pId } ->
Imported _ _ PrimitiveType { primitiveTypeIdentifier = pId } ->
compilePrimitiveTypeValidator pId pythonVar
_ ->
compileInstanceValidator mod' typeId pythonVar
Expand Down
19 changes: 11 additions & 8 deletions src/Nirum/TypeInstance/BoundModule.hs
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,28 @@ boundTypes = findInBoundModule types DS.empty

data TypeLookup = Missing
| Local Type
| Imported ModulePath Type
| Imported ModulePath Identifier Type
deriving (Eq, Ord, Show)

lookupType :: Target t => Identifier -> BoundModule t -> TypeLookup
lookupType identifier boundModule =
case DS.lookup identifier (boundTypes boundModule) of
Nothing -> toType coreModulePath
(DS.lookup identifier $ types coreModule)
Nothing ->
toType
coreModulePath
identifier
(DS.lookup identifier $ types coreModule)
Just TypeDeclaration { type' = t } -> Local t
Just (Import path' _ _) ->
Just (Import path' _ s _) ->
case resolveModule path' (boundPackage boundModule) of
Nothing -> Missing
Just (Module decls _) ->
toType path' (DS.lookup identifier decls)
toType path' s (DS.lookup s decls)
Just ServiceDeclaration {} -> Missing
where
toType :: ModulePath -> Maybe TypeDeclaration -> TypeLookup
toType mp (Just TypeDeclaration { type' = t }) = Imported mp t
toType _ _ = Missing
toType :: ModulePath -> Identifier -> Maybe TypeDeclaration -> TypeLookup
toType mp i (Just TypeDeclaration { type' = t }) = Imported mp i t
toType _ _ _ = Missing

instance Target t => Documented (BoundModule t) where
docs = findInBoundModule Nirum.Constructs.Module.docs Nothing
4 changes: 2 additions & 2 deletions test/Nirum/CodeBuilderSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ spec = do
let run' = fst . runBuilder package ["fruits"] ()
let core = ModuleName "core"
run' (lookupType "text") `shouldBe`
Imported core (TD.PrimitiveType TD.Text TD.String)
Imported core "text" (TD.PrimitiveType TD.Text TD.String)
run' (lookupType "int32") `shouldBe`
Imported core (TD.PrimitiveType TD.Int32 TD.Number)
Imported core "int32" (TD.PrimitiveType TD.Int32 TD.Number)


data DummyTarget = DummyTarget deriving (Eq, Ord, Show)
Expand Down
27 changes: 19 additions & 8 deletions test/Nirum/Constructs/ModuleSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,27 @@ spec =
pathT = TypeDeclaration "path" (Alias "text") (singleton docsAnno)
offsetT =
TypeDeclaration "offset" (UnboxedType "float64") empty
decls = [ Import ["foo", "bar"] "baz" empty
, Import ["foo", "bar"] "qux" empty
, Import ["zzz"] "qqq" empty
, Import ["zzz"] "ppp" empty
, Import ["xyz"] "asdf" empty
decls = [ Import ["foo", "bar"] "baz" "baz" empty
, Import ["foo", "bar"] "qux" "qux" empty
, Import ["zzz"] "qqq" "qqq" empty
, Import ["zzz"] "ppp" "ppp" empty
, Import ["xyz"] "asdf" "asdf" empty
, pathT
, offsetT
] :: DeclarationSet TypeDeclaration
decls2 = [ Import ["foo", "bar"] "qux" "baz" empty
] :: DeclarationSet TypeDeclaration
mod1 = Module decls Nothing
mod2 = Module decls $ Just "module level docs...\nblahblah"
mod3 = Module decls2 Nothing
specify "imports" $ do
imports mod1 `shouldBe` [ (["foo", "bar"], ["baz", "qux"])
, (["xyz"], ["asdf"])
, (["zzz"], ["qqq", "ppp"])
imports mod1 `shouldBe` [ ( ["foo", "bar"]
, [("baz", "baz"), ("qux", "qux")]
)
, (["xyz"], [("asdf", "asdf")])
, ( ["zzz"]
, [("qqq", "qqq"), ("ppp", "ppp")]
)
]
imports mod2 `shouldBe` imports mod1
specify "toCode" $ do
Expand All @@ -57,4 +64,8 @@ type path = text;
# path string

unboxed offset (float64);
|]
toCode mod3 `shouldBe` [q|import foo.bar (baz as qux);


|]
Loading