proto-lens-protoc 0.2.2.0 → 0.2.2.1
raw patch · 3 files changed
+64/−36 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Changelog.md +4/−0
- proto-lens-protoc.cabal +1/−1
- src/Data/ProtoLens/Compiler/Definitions.hs +59/−35
Changelog.md view
@@ -2,6 +2,10 @@ ## Unreleased changes +## v0.2.2.1+- Fix the case where types/constructors of oneofs overlap with those of+ submessages or subenums, by appending `"'"` to the former when required.+ ## v0.2.2.0 - Bump the dependency on `base` to support `ghc-8.2.1` and `Cabal-2.0`. - Bump the dependency for `haskell-src-exts-0.19`.
proto-lens-protoc.cabal view
@@ -1,5 +1,5 @@ name: proto-lens-protoc-version: 0.2.2.0+version: 0.2.2.1 synopsis: Protocol buffer compiler for the proto-lens library. description: Turn protocol buffer files (.proto) into Haskell files (.hs) which
src/Data/ProtoLens/Compiler/Definitions.hs view
@@ -39,7 +39,7 @@ import Data.String (IsString(..)) import Data.Text (Text, cons, splitOn, toLower, uncons, unpack) import qualified Data.Text as T-import Lens.Family2 ((^.), (^..))+import Lens.Family2 ((^.), (^..), toListOf) import Proto.Google.Protobuf.Descriptor ( DescriptorProto , EnumDescriptorProto@@ -214,52 +214,77 @@ where protoName = protoPrefix <> d ^. name hsPrefix' = hsPrefix ++ hsName (d ^. name) ++ "'"- hsName = unpack . capitalize . camelCase- allFields = collectFieldsByOneofIndex (d ^. field)+ allFields = groupFieldsByOneofIndex (d ^. field) thisDef = Message MessageInfo { messageName = fromString $ hsPrefix ++ hsName (d ^. name) , messageDescriptor = d , messageFields =- map fieldInfo $ Map.findWithDefault [] Nothing allFields- , messageOneofFields =- zipWith oneofInfo [0..]- $ d ^.. oneofDecl . traverse . name+ map (fieldInfo hsPrefix')+ $ Map.findWithDefault [] Nothing allFields+ , messageOneofFields = collectOneofFields hsPrefix' d allFields }- fieldInfo f = FieldInfo f $ mkFieldName $ f ^. name- mkFieldName n = FieldName- { overloadedName = fromString n'- , haskellRecordFieldName = fromString $ "_" ++ hsPrefix' ++ n'- }- where- n' = fieldName n- oneofInfo :: Int32 -> Text -> OneofInfo++fieldInfo :: String -> FieldDescriptorProto -> FieldInfo+fieldInfo hsPrefix f = FieldInfo f $ mkFieldName hsPrefix $ f ^. name++collectOneofFields+ :: String -> DescriptorProto -> Map.Map (Maybe Int32) [FieldDescriptorProto]+ -> [OneofInfo]+collectOneofFields hsPrefix d allFields+ = zipWith oneofInfo [0..] $ d ^.. oneofDecl . traverse . name+ where oneofInfo idx n = OneofInfo- { oneofFieldName = mkFieldName n- , oneofTypeName = fromString $ hsPrefix' ++ hsName n- , oneofCases = map oneofCase- $ Map.findWithDefault [] (Just idx)- allFields- }+ { oneofFieldName = mkFieldName hsPrefix n+ , oneofTypeName = fromString $ hsPrefix ++ hsNameUnique subdefTypes n+ , oneofCases = map oneofCase+ $ Map.findWithDefault [] (Just idx)+ allFields+ } oneofCase f = OneofCase- { caseField = fieldInfo f- , caseConstructorName =- -- Note: oneof case constructors aren't prefixed- -- by the oneof name; field names (even inside- -- of a oneof) are unique within a message.- fromString $ hsPrefix' ++ hsName (f ^. name)- }-+ { caseField = fieldInfo hsPrefix f+ , caseConstructorName =+ -- Note: oneof case constructors aren't prefixed+ -- by the oneof name; field names (even inside+ -- of a oneof) are unique within a message.+ fromString $ hsPrefix ++ hsNameUnique subdefCons (f ^. name)+ }+ -- Make a name that doesn't overlap with those already defined by submessages+ -- or subenums.+ hsNameUnique ns n+ | n' `elem` ns = n' <> "'"+ | otherwise = n'+ where+ n' = hsName n+ -- The Haskell "type" namespace+ subdefTypes = Set.fromList $ map hsName+ $ toListOf (nestedType . traverse . name) d+ ++ toListOf (enumType . traverse . name) d+ -- The Haskell "expression" namespace (i.e., constructors)+ subdefCons = Set.fromList $ map hsName+ $ toListOf (nestedType . traverse . name) d+ ++ toListOf (enumType . traverse . value . traverse . name) d -- | Group fields by the index of the oneof field that they belong to. -- (Or 'Nothing' if they don't belong to a oneof.)-collectFieldsByOneofIndex+groupFieldsByOneofIndex :: [FieldDescriptorProto] -> Map.Map (Maybe Int32) [FieldDescriptorProto]-collectFieldsByOneofIndex =+groupFieldsByOneofIndex = fmap reverse . Map.fromListWith (++) . fmap (\f -> (f ^. maybe'oneofIndex, [f])) +hsName :: Text -> String+hsName = unpack . capitalize . camelCase++mkFieldName :: String -> Text -> FieldName+mkFieldName hsPrefix n = FieldName+ { overloadedName = fromString n'+ , haskellRecordFieldName = fromString $ "_" ++ hsPrefix ++ n'+ }+ where+ n' = fieldName n+ -- | Get the name in Haskell of a proto field, taking care of camel casing and -- clashes with language keywords. fieldName :: Text -> String@@ -351,11 +376,10 @@ -> (Map.Map Int32 Name, EnumValueInfo Name) helper seenNames v | Just n' <- Map.lookup k seenNames = (seenNames, mkValue (Just n'))- | otherwise = (Map.insert k hsName seenNames, mkValue Nothing)+ | otherwise = (Map.insert k n seenNames, mkValue Nothing) where- mkValue = EnumValueInfo hsName v- hsName = mkHsName n- n = v ^. name+ mkValue = EnumValueInfo n v+ n = mkHsName (v ^. name) k = v ^. number -- Haskell types must start with an uppercase letter, so we capitalize message