language-thrift 0.9.0.1 → 0.9.0.2
raw patch · 6 files changed
+147/−22 lines, 6 filesdep +containersdep +semigroupsPVP ok
version bump matches the API change (PVP)
Dependencies added: containers, semigroups
API changes (from Hackage documentation)
Files
- CHANGES.md +10/−0
- language-thrift.cabal +18/−3
- src/Language/Thrift/Internal/Reserved.hs +59/−0
- src/Language/Thrift/Parser.hs +17/−3
- test/Language/Thrift/Arbitrary.hs +36/−16
- test/Language/Thrift/ParserSpec.hs +7/−0
CHANGES.md view
@@ -1,3 +1,8 @@+0.9.0.2 (2016-08-31)+====================++- Disallow reserved keywords from being used as identifier names.+ 0.9.0.1 (2016-05-26) ==================== @@ -8,6 +13,11 @@ - Deprecate the `Language.Thrift.Types` in favor of `Language.Thrift.AST`. - Upgrade to `megaparsec` 5.0.++0.8.0.2 (2016-08-31)+====================++- Disallow reserved keywords from being used as identifier names. 0.8.0.1 (2016-05-24) ====================
language-thrift.cabal view
@@ -1,9 +1,9 @@--- This file has been generated from package.yaml by hpack version 0.13.0.+-- This file has been generated from package.yaml by hpack version 0.14.1. -- -- see: https://github.com/sol/hpack name: language-thrift-version: 0.9.0.1+version: 0.9.0.2 bug-reports: https://github.com/abhinav/language-thrift/issues cabal-version: >= 1.10 build-type: Simple@@ -36,9 +36,11 @@ build-depends: base >= 4.7 && < 5, ansi-wl-pprint >= 0.6 && < 0.7,+ containers >= 0.5 && < 0.6, megaparsec >= 5.0 && < 6.0,- text >= 1.2, scientific >= 0.3 && < 0.4,+ semigroups >= 0.18 && < 0.19,+ text >= 1.2, transformers exposed-modules: Language.Thrift.AST@@ -48,6 +50,7 @@ other-modules: Language.Thrift.Internal.AST Language.Thrift.Internal.Lens+ Language.Thrift.Internal.Reserved Paths_language_thrift default-language: Haskell2010 @@ -55,18 +58,30 @@ type: exitcode-stdio-1.0 main-is: Main.hs hs-source-dirs:+ src, test ghc-options: -Wall build-depends: base >= 4.7 && < 5, ansi-wl-pprint >= 0.6 && < 0.7,+ containers >= 0.5 && < 0.6, megaparsec >= 5.0 && < 6.0,+ scientific >= 0.3 && < 0.4,+ semigroups >= 0.18 && < 0.19, text >= 1.2,+ transformers, hspec >= 2.0, hspec-discover >= 2.1, language-thrift, QuickCheck >= 2.5 other-modules:+ Language.Thrift.AST+ Language.Thrift.Internal.AST+ Language.Thrift.Internal.Lens+ Language.Thrift.Internal.Reserved+ Language.Thrift.Parser+ Language.Thrift.Pretty+ Language.Thrift.Types Language.Thrift.Arbitrary Language.Thrift.ASTSpec Language.Thrift.ParserSpec
+ src/Language/Thrift/Internal/Reserved.hs view
@@ -0,0 +1,59 @@+-- |+-- Module : Language.Thrift.Internal.Reserved+-- Copyright : (c) Abhinav Gupta 2016+-- License : BSD3+--+-- Maintainer : Abhinav Gupta <mail@abhinavg.net>+-- Stability : experimental+--+-- This module provides information about reserved Thrift identifiers.+module Language.Thrift.Internal.Reserved+ ( isReserved+ ) where++import Data.Set (Set)+import qualified Data.Set as Set++isReserved :: String -> Bool+isReserved = (`Set.member` reservedKeywords)++reservedKeywords :: Set String+reservedKeywords = Set.fromList+ [ "include"+ , "namespace"+ , "cpp_namespace"+ , "php_namespace"+ , "py_module"+ , "perl_package"+ , "ruby_namespace"+ , "java_package"+ , "cocoa_package"+ , "csharp_namespace"+ , "typedef"+ , "enum"+ , "struct"+ , "union"+ , "exception"+ , "required"+ , "optional"+ , "senum"+ , "const"+ , "string"+ , "binary"+ , "slist"+ , "bool"+ , "byte"+ , "i8"+ , "i16"+ , "i32"+ , "i64"+ , "double"+ , "map"+ , "set"+ , "list"+ , "service"+ , "extends"+ , "oneway"+ , "void"+ , "throws"+ ]
src/Language/Thrift/Parser.hs view
@@ -69,11 +69,14 @@ import Data.Text (Text) import qualified Control.Monad.Trans.State as State+import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Text as Text import qualified Data.Text.IO as Text import qualified Text.Megaparsec as P import qualified Text.Megaparsec.Lexer as PL +import Language.Thrift.Internal.Reserved (isReserved)+ import qualified Language.Thrift.AST as T -- | Keeps track of the last docstring seen by the system so that we can@@ -258,12 +261,21 @@ colon = symbolic ':' equals = symbolic '=' +-- | errorUnlessReserved ensures that the given identifier is in the+-- reservedKeywords list. If it's not, we have a bug and we should crash.+errorUnlessReserved :: Monad m => String -> m ()+errorUnlessReserved name =+ unless (isReserved name) $+ error ("reserved called with unreserved identifier " ++ show name)+ -- | Parses a reserved identifier and adds it to the collection of known -- reserved keywords. reserved :: (P.Stream s, P.Token s ~ Char) => String -> Parser s ()-reserved name = P.label name $ token $ P.try $ do- void (P.string name)- P.notFollowedBy (P.alphaNumChar <|> oneOf "_.")+reserved name =+ errorUnlessReserved name >>+ P.label name $ token $ P.try $ do+ void (P.string name)+ P.notFollowedBy (P.alphaNumChar <|> oneOf "_.") -- | A string literal. @"hello"@@@ -286,6 +298,8 @@ name <- (:) <$> (P.letterChar <|> P.char '_') <*> many (P.alphaNumChar <|> oneOf "_.")+ when (isReserved name) $+ P.unexpected (P.Label (NonEmpty.fromList name)) return (Text.pack name)
test/Language/Thrift/Arbitrary.hs view
@@ -17,6 +17,8 @@ import qualified Data.Text as Text +import Language.Thrift.Internal.Reserved (isReserved)+ import qualified Language.Thrift.AST as T #ifdef MIN_VERSION_QuickCheck@@ -64,6 +66,15 @@ shrink (Docstring t) = Docstring <$> shrink t +newtype Identifier = Identifier { getIdentifier :: Text }+ deriving (Show, Typeable, Generic)++instance Arbitrary Identifier where+ arbitrary = Identifier <$> arbitrary `suchThat` (not . isReserved . Text.unpack)++ shrink (Identifier t) =+ [Identifier t' | t' <- shrink t, not (isReserved (Text.unpack t'))]+ ------------------------------------------------------------------------------ instance Arbitrary (T.Program ()) where@@ -83,7 +94,11 @@ instance Arbitrary (T.Namespace ()) where shrink = genericShrink- arbitrary = T.Namespace <$> elements scopes <*> arbitrary <*> pure ()+ arbitrary =+ T.Namespace+ <$> elements scopes+ <*> (getIdentifier <$> arbitrary)+ <*> pure () where scopes = ["*", "py", "rb", "java", "hs", "cpp"] @@ -101,7 +116,7 @@ arbitrary = T.Const <$> arbitrary- <*> arbitrary+ <*> (getIdentifier <$> arbitrary) <*> arbitrary <*> (getDocstring <$> arbitrary) <*> pure ()@@ -110,8 +125,11 @@ shrink = genericShrink arbitrary = T.Service- <$> arbitrary- <*> arbitrary+ <$> (getIdentifier <$> arbitrary)+ <*> frequency+ [ (1, return Nothing)+ , (3, Just . getIdentifier <$> arbitrary)+ ] <*> arbitrary <*> halfSize arbitrary <*> (getDocstring <$> arbitrary)@@ -123,7 +141,7 @@ T.Function <$> arbitrary <*> halfSize arbitrary- <*> arbitrary+ <*> (getIdentifier <$> arbitrary) <*> halfSize arbitrary <*> halfSize arbitrary <*> halfSize arbitrary@@ -145,7 +163,7 @@ shrink = genericShrink arbitrary = T.Typedef <$> arbitrary- <*> arbitrary+ <*> (getIdentifier <$> arbitrary) <*> halfSize arbitrary <*> (getDocstring <$> arbitrary) <*> pure ()@@ -153,7 +171,7 @@ instance Arbitrary (T.Enum ()) where shrink = genericShrink arbitrary = T.Enum- <$> arbitrary+ <$> (getIdentifier <$> arbitrary) <*> arbitrary <*> halfSize arbitrary <*> (getDocstring <$> arbitrary)@@ -163,7 +181,7 @@ shrink = genericShrink arbitrary = T.EnumDef- <$> arbitrary+ <$> (getIdentifier <$> arbitrary) <*> arbitrary <*> halfSize arbitrary <*> (getDocstring <$> arbitrary)@@ -172,7 +190,7 @@ instance Arbitrary (T.Struct ()) where shrink = genericShrink arbitrary = T.Struct- <$> arbitrary+ <$> (getIdentifier <$> arbitrary) <*> arbitrary <*> halfSize arbitrary <*> (getDocstring <$> arbitrary)@@ -181,7 +199,7 @@ instance Arbitrary (T.Union ()) where shrink = genericShrink arbitrary = T.Union- <$> arbitrary+ <$> (getIdentifier <$> arbitrary) <*> arbitrary <*> halfSize arbitrary <*> (getDocstring <$> arbitrary)@@ -190,7 +208,7 @@ instance Arbitrary (T.Exception ()) where shrink = genericShrink arbitrary = T.Exception- <$> arbitrary+ <$> (getIdentifier <$> arbitrary) <*> arbitrary <*> halfSize arbitrary <*> (getDocstring <$> arbitrary)@@ -199,7 +217,7 @@ instance Arbitrary (T.Senum ()) where shrink = genericShrink arbitrary = T.Senum- <$> arbitrary+ <$> (getIdentifier <$> arbitrary) <*> arbitrary <*> halfSize arbitrary <*> (getDocstring <$> arbitrary)@@ -212,7 +230,7 @@ <$> (fmap getPositive <$> arbitrary) <*> arbitrary <*> halfSize arbitrary- <*> arbitrary+ <*> (getIdentifier <$> arbitrary) <*> halfSize arbitrary <*> halfSize arbitrary <*> (getDocstring <$> arbitrary)@@ -221,7 +239,8 @@ instance Arbitrary (T.TypeReference ()) where shrink = genericShrink arbitrary = oneof- [ T.DefinedType <$> arbitrary <*> pure ()+ [ T.DefinedType <$> (getIdentifier <$> arbitrary)+ <*> pure () , halfSize $ T.StringType <$> arbitrary <*> pure () , halfSize $ T.BinaryType <$> arbitrary <*> pure () , halfSize $ T.SListType <$> arbitrary <*> pure ()@@ -242,7 +261,7 @@ instance Arbitrary T.TypeAnnotation where shrink = genericShrink- arbitrary = T.TypeAnnotation <$> arbitrary <*> arbitrary+ arbitrary = T.TypeAnnotation <$> (getIdentifier <$> arbitrary) <*> arbitrary newtype BasicConstValue = BasicConstValue {@@ -256,7 +275,8 @@ [ T.ConstFloat <$> choose (0.0, 10000.0) <*> pure () , T.ConstInt <$> arbitrary <*> pure () , T.ConstLiteral <$> arbitrary <*> pure ()- , T.ConstIdentifier <$> arbitrary <*> pure ()+ , T.ConstIdentifier <$> (getIdentifier <$> arbitrary)+ <*> pure () ] -- | newtype wrapper around const values so that we're not generating lists
test/Language/Thrift/ParserSpec.hs view
@@ -80,6 +80,13 @@ , "something_else<foo>" ] + it "cannot parse reserved keywords in names" $+ parseFailureCases P.program+ [ "enum struct {}"+ , "strut Foo { 1: required string service }"+ ]++ parseFailureCases :: Show a => Parser a -> [String] -> Expectation parseFailureCases p = mapM_ (p `shouldNotParse`)