inline-c 0.5.3.4 → 0.5.4.0
raw patch · 13 files changed
+780/−364 lines, 13 filesdep +hashablePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: hashable
API changes (from Hackage documentation)
- Language.C.Inline.Context: isTypeName :: TypesTable -> Identifier -> Bool
- Language.C.Types: Identifier :: String -> Identifier
- Language.C.Types: instance Eq ParameterDeclaration
- Language.C.Types: instance Eq Type
- Language.C.Types: instance Pretty ParameterDeclaration
- Language.C.Types: instance Pretty Type
- Language.C.Types: instance Show ParameterDeclaration
- Language.C.Types: instance Show Type
- Language.C.Types: newtype Identifier
- Language.C.Types: type IsTypeName = Identifier -> Bool
- Language.C.Types: unIdentifier :: Identifier -> String
- Language.C.Types.Parse: Identifier :: String -> Identifier
- Language.C.Types.Parse: identifier :: CParser m => m Identifier
- Language.C.Types.Parse: instance Arbitrary ParameterDeclarationWithTypeNames
- Language.C.Types.Parse: instance Eq AbstractDeclarator
- Language.C.Types.Parse: instance Eq ArrayOrProto
- Language.C.Types.Parse: instance Eq ArrayType
- Language.C.Types.Parse: instance Eq Declarator
- Language.C.Types.Parse: instance Eq DirectAbstractDeclarator
- Language.C.Types.Parse: instance Eq DirectDeclarator
- Language.C.Types.Parse: instance Eq Identifier
- Language.C.Types.Parse: instance Eq ParameterDeclaration
- Language.C.Types.Parse: instance Eq ParameterDeclarationWithTypeNames
- Language.C.Types.Parse: instance IsString Identifier
- Language.C.Types.Parse: instance Ord Identifier
- Language.C.Types.Parse: instance Pretty AbstractDeclarator
- Language.C.Types.Parse: instance Pretty ArrayOrProto
- Language.C.Types.Parse: instance Pretty ArrayType
- Language.C.Types.Parse: instance Pretty Declarator
- Language.C.Types.Parse: instance Pretty DirectAbstractDeclarator
- Language.C.Types.Parse: instance Pretty DirectDeclarator
- Language.C.Types.Parse: instance Pretty Identifier
- Language.C.Types.Parse: instance Pretty ParameterDeclaration
- Language.C.Types.Parse: instance Show AbstractDeclarator
- Language.C.Types.Parse: instance Show ArrayOrProto
- Language.C.Types.Parse: instance Show ArrayType
- Language.C.Types.Parse: instance Show Declarator
- Language.C.Types.Parse: instance Show DirectAbstractDeclarator
- Language.C.Types.Parse: instance Show DirectDeclarator
- Language.C.Types.Parse: instance Show Identifier
- Language.C.Types.Parse: instance Show ParameterDeclaration
- Language.C.Types.Parse: instance Show ParameterDeclarationWithTypeNames
- Language.C.Types.Parse: instance Typeable Identifier
- Language.C.Types.Parse: newtype Identifier
- Language.C.Types.Parse: type IsTypeName = Identifier -> Bool
- Language.C.Types.Parse: unIdentifier :: Identifier -> String
+ Language.C.Inline.Context: typeNamesFromTypesTable :: TypesTable -> TypeNames
+ Language.C.Inline.HaskellIdentifier: data HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: haskellCParserContext :: TypeNames -> CParserContext HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: haskellIdentifierFromString :: String -> Either String HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: instance Arbitrary HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: instance Eq HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: instance Hashable HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: instance IsString HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: instance Ord HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: instance Pretty HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: instance Show HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: instance Typeable HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: mangleHaskellIdentifier :: HaskellIdentifier -> CIdentifier
+ Language.C.Inline.HaskellIdentifier: parseHaskellIdentifier :: CParser i m => m HaskellIdentifier
+ Language.C.Inline.HaskellIdentifier: unHaskellIdentifier :: HaskellIdentifier -> String
+ Language.C.Types: cCParserContext :: TypeNames -> CParserContext CIdentifier
+ Language.C.Types: cIdentifierFromString :: String -> Either String CIdentifier
+ Language.C.Types: data CIdentifier
+ Language.C.Types: data CParserContext i
+ Language.C.Types: instance Eq i => Eq (ParameterDeclaration i)
+ Language.C.Types: instance Eq i => Eq (Type i)
+ Language.C.Types: instance Foldable ParameterDeclaration
+ Language.C.Types: instance Foldable Type
+ Language.C.Types: instance Functor ParameterDeclaration
+ Language.C.Types: instance Functor Type
+ Language.C.Types: instance Pretty i => Pretty (ParameterDeclaration i)
+ Language.C.Types: instance Pretty i => Pretty (Type i)
+ Language.C.Types: instance Show i => Show (ParameterDeclaration i)
+ Language.C.Types: instance Show i => Show (Type i)
+ Language.C.Types: instance Traversable ParameterDeclaration
+ Language.C.Types: instance Traversable Type
+ Language.C.Types: type TypeNames = HashSet CIdentifier
+ Language.C.Types: unCIdentifier :: CIdentifier -> String
+ Language.C.Types.Parse: CParserContext :: String -> TypeNames -> (forall m. CParser i m => m i) -> (i -> String) -> CParserContext i
+ Language.C.Types.Parse: IsAbstractDeclarator :: (AbstractDeclarator i) -> DeclaratorOrAbstractDeclarator i
+ Language.C.Types.Parse: IsDeclarator :: (Declarator i) -> DeclaratorOrAbstractDeclarator i
+ Language.C.Types.Parse: arbitraryParameterDeclarationWithTypeNames :: (Arbitrary i, Hashable i) => (i -> String) -> Gen (ParameterDeclarationWithTypeNames i)
+ Language.C.Types.Parse: cCParserContext :: TypeNames -> CParserContext CIdentifier
+ Language.C.Types.Parse: cIdentLetter :: [Char]
+ Language.C.Types.Parse: cIdentStart :: [Char]
+ Language.C.Types.Parse: cIdentifierFromString :: String -> Either String CIdentifier
+ Language.C.Types.Parse: cReservedWords :: HashSet String
+ Language.C.Types.Parse: cpcIdentName :: CParserContext i -> String
+ Language.C.Types.Parse: cpcIdentToString :: CParserContext i -> i -> String
+ Language.C.Types.Parse: cpcParseIdent :: CParserContext i -> forall m. CParser i m => m i
+ Language.C.Types.Parse: cpcTypeNames :: CParserContext i -> TypeNames
+ Language.C.Types.Parse: data CIdentifier
+ Language.C.Types.Parse: data CParserContext i
+ Language.C.Types.Parse: data DeclaratorOrAbstractDeclarator i
+ Language.C.Types.Parse: instance Arbitrary CIdentifier
+ Language.C.Types.Parse: instance Eq CIdentifier
+ Language.C.Types.Parse: instance Eq i => Eq (AbstractDeclarator i)
+ Language.C.Types.Parse: instance Eq i => Eq (ArrayOrProto i)
+ Language.C.Types.Parse: instance Eq i => Eq (ArrayType i)
+ Language.C.Types.Parse: instance Eq i => Eq (Declarator i)
+ Language.C.Types.Parse: instance Eq i => Eq (DeclaratorOrAbstractDeclarator i)
+ Language.C.Types.Parse: instance Eq i => Eq (DirectAbstractDeclarator i)
+ Language.C.Types.Parse: instance Eq i => Eq (DirectDeclarator i)
+ Language.C.Types.Parse: instance Eq i => Eq (ParameterDeclaration i)
+ Language.C.Types.Parse: instance Eq i => Eq (ParameterDeclarationWithTypeNames i)
+ Language.C.Types.Parse: instance Foldable AbstractDeclarator
+ Language.C.Types.Parse: instance Foldable ArrayOrProto
+ Language.C.Types.Parse: instance Foldable ArrayType
+ Language.C.Types.Parse: instance Foldable Declarator
+ Language.C.Types.Parse: instance Foldable DeclaratorOrAbstractDeclarator
+ Language.C.Types.Parse: instance Foldable DirectAbstractDeclarator
+ Language.C.Types.Parse: instance Foldable DirectDeclarator
+ Language.C.Types.Parse: instance Foldable ParameterDeclaration
+ Language.C.Types.Parse: instance Functor AbstractDeclarator
+ Language.C.Types.Parse: instance Functor ArrayOrProto
+ Language.C.Types.Parse: instance Functor ArrayType
+ Language.C.Types.Parse: instance Functor Declarator
+ Language.C.Types.Parse: instance Functor DeclaratorOrAbstractDeclarator
+ Language.C.Types.Parse: instance Functor DirectAbstractDeclarator
+ Language.C.Types.Parse: instance Functor DirectDeclarator
+ Language.C.Types.Parse: instance Functor ParameterDeclaration
+ Language.C.Types.Parse: instance Hashable CIdentifier
+ Language.C.Types.Parse: instance IsString CIdentifier
+ Language.C.Types.Parse: instance Ord CIdentifier
+ Language.C.Types.Parse: instance Pretty CIdentifier
+ Language.C.Types.Parse: instance Pretty i => Pretty (AbstractDeclarator i)
+ Language.C.Types.Parse: instance Pretty i => Pretty (ArrayOrProto i)
+ Language.C.Types.Parse: instance Pretty i => Pretty (ArrayType i)
+ Language.C.Types.Parse: instance Pretty i => Pretty (Declarator i)
+ Language.C.Types.Parse: instance Pretty i => Pretty (DirectAbstractDeclarator i)
+ Language.C.Types.Parse: instance Pretty i => Pretty (DirectDeclarator i)
+ Language.C.Types.Parse: instance Pretty i => Pretty (ParameterDeclaration i)
+ Language.C.Types.Parse: instance Show CIdentifier
+ Language.C.Types.Parse: instance Show i => Show (AbstractDeclarator i)
+ Language.C.Types.Parse: instance Show i => Show (ArrayOrProto i)
+ Language.C.Types.Parse: instance Show i => Show (ArrayType i)
+ Language.C.Types.Parse: instance Show i => Show (Declarator i)
+ Language.C.Types.Parse: instance Show i => Show (DeclaratorOrAbstractDeclarator i)
+ Language.C.Types.Parse: instance Show i => Show (DirectAbstractDeclarator i)
+ Language.C.Types.Parse: instance Show i => Show (DirectDeclarator i)
+ Language.C.Types.Parse: instance Show i => Show (ParameterDeclaration i)
+ Language.C.Types.Parse: instance Show i => Show (ParameterDeclarationWithTypeNames i)
+ Language.C.Types.Parse: instance Traversable AbstractDeclarator
+ Language.C.Types.Parse: instance Traversable ArrayOrProto
+ Language.C.Types.Parse: instance Traversable ArrayType
+ Language.C.Types.Parse: instance Traversable Declarator
+ Language.C.Types.Parse: instance Traversable DeclaratorOrAbstractDeclarator
+ Language.C.Types.Parse: instance Traversable DirectAbstractDeclarator
+ Language.C.Types.Parse: instance Traversable DirectDeclarator
+ Language.C.Types.Parse: instance Traversable ParameterDeclaration
+ Language.C.Types.Parse: instance Typeable CIdentifier
+ Language.C.Types.Parse: instance Typeable DeclaratorOrAbstractDeclarator
+ Language.C.Types.Parse: type TypeNames = HashSet CIdentifier
+ Language.C.Types.Parse: unCIdentifier :: CIdentifier -> String
- Language.C.Inline.Context: AntiQuoter :: (forall m. CParser m => m (String, Type, a)) -> (Purity -> TypesTable -> Type -> a -> Q (Type, Exp)) -> AntiQuoter a
+ Language.C.Inline.Context: AntiQuoter :: (forall m. CParser HaskellIdentifier m => m (CIdentifier, Type CIdentifier, a)) -> (Purity -> TypesTable -> Type CIdentifier -> a -> Q (Type, Exp)) -> AntiQuoter a
- Language.C.Inline.Context: aqMarshaller :: AntiQuoter a -> Purity -> TypesTable -> Type -> a -> Q (Type, Exp)
+ Language.C.Inline.Context: aqMarshaller :: AntiQuoter a -> Purity -> TypesTable -> Type CIdentifier -> a -> Q (Type, Exp)
- Language.C.Inline.Context: aqParser :: AntiQuoter a -> forall m. CParser m => m (String, Type, a)
+ Language.C.Inline.Context: aqParser :: AntiQuoter a -> forall m. CParser HaskellIdentifier m => m (CIdentifier, Type CIdentifier, a)
- Language.C.Inline.Context: convertType :: Purity -> TypesTable -> Type -> Q (Maybe Type)
+ Language.C.Inline.Context: convertType :: Purity -> TypesTable -> Type CIdentifier -> Q (Maybe Type)
- Language.C.Inline.Internal: ParseTypedC :: Type -> [(Identifier, Type, ParameterType)] -> String -> ParseTypedC
+ Language.C.Inline.Internal: ParseTypedC :: Type CIdentifier -> [(CIdentifier, Type CIdentifier, ParameterType)] -> String -> ParseTypedC
- Language.C.Inline.Internal: Plain :: String -> ParameterType
+ Language.C.Inline.Internal: Plain :: HaskellIdentifier -> ParameterType
- Language.C.Inline.Internal: genericQuote :: Purity -> (TypeQ -> Type -> [(Identifier, Type)] -> String -> ExpQ) -> QuasiQuoter
+ Language.C.Inline.Internal: genericQuote :: Purity -> (TypeQ -> Type CIdentifier -> [(CIdentifier, Type CIdentifier)] -> String -> ExpQ) -> QuasiQuoter
- Language.C.Inline.Internal: inlineExp :: Safety -> TypeQ -> Type -> [(Identifier, Type)] -> String -> ExpQ
+ Language.C.Inline.Internal: inlineExp :: Safety -> TypeQ -> Type CIdentifier -> [(CIdentifier, Type CIdentifier)] -> String -> ExpQ
- Language.C.Inline.Internal: inlineItems :: Safety -> TypeQ -> Type -> [(Identifier, Type)] -> String -> ExpQ
+ Language.C.Inline.Internal: inlineItems :: Safety -> TypeQ -> Type CIdentifier -> [(CIdentifier, Type CIdentifier)] -> String -> ExpQ
- Language.C.Inline.Internal: parseTypedC :: CParser m => AntiQuoters -> m ParseTypedC
+ Language.C.Inline.Internal: parseTypedC :: CParser HaskellIdentifier m => AntiQuoters -> m ParseTypedC
- Language.C.Inline.Internal: ptcParameters :: ParseTypedC -> [(Identifier, Type, ParameterType)]
+ Language.C.Inline.Internal: ptcParameters :: ParseTypedC -> [(CIdentifier, Type CIdentifier, ParameterType)]
- Language.C.Inline.Internal: ptcReturnType :: ParseTypedC -> Type
+ Language.C.Inline.Internal: ptcReturnType :: ParseTypedC -> Type CIdentifier
- Language.C.Inline.Internal: runParserInQ :: String -> IsTypeName -> (forall m. CParser m => m a) -> Q a
+ Language.C.Inline.Internal: runParserInQ :: String -> TypeNames -> (forall m. CParser HaskellIdentifier m => m a) -> Q a
- Language.C.Types: Array :: ArrayType -> Type -> Type
+ Language.C.Types: Array :: (ArrayType i) -> (Type i) -> Type i
- Language.C.Types: Enum :: Identifier -> TypeSpecifier
+ Language.C.Types: Enum :: CIdentifier -> TypeSpecifier
- Language.C.Types: ParameterDeclaration :: Maybe Identifier -> Type -> ParameterDeclaration
+ Language.C.Types: ParameterDeclaration :: Maybe i -> (Type i) -> ParameterDeclaration i
- Language.C.Types: Proto :: Type -> [ParameterDeclaration] -> Type
+ Language.C.Types: Proto :: (Type i) -> [ParameterDeclaration i] -> Type i
- Language.C.Types: Ptr :: [TypeQualifier] -> Type -> Type
+ Language.C.Types: Ptr :: [TypeQualifier] -> (Type i) -> Type i
- Language.C.Types: SizedByIdentifier :: Identifier -> ArrayType
+ Language.C.Types: SizedByIdentifier :: i -> ArrayType i
- Language.C.Types: SizedByInteger :: Integer -> ArrayType
+ Language.C.Types: SizedByInteger :: Integer -> ArrayType i
- Language.C.Types: Struct :: Identifier -> TypeSpecifier
+ Language.C.Types: Struct :: CIdentifier -> TypeSpecifier
- Language.C.Types: TypeName :: Identifier -> TypeSpecifier
+ Language.C.Types: TypeName :: CIdentifier -> TypeSpecifier
- Language.C.Types: TypeSpecifier :: Specifiers -> TypeSpecifier -> Type
+ Language.C.Types: TypeSpecifier :: Specifiers -> TypeSpecifier -> Type i
- Language.C.Types: Unsized :: ArrayType
+ Language.C.Types: Unsized :: ArrayType i
- Language.C.Types: VariablySized :: ArrayType
+ Language.C.Types: VariablySized :: ArrayType i
- Language.C.Types: data ArrayType
+ Language.C.Types: data ArrayType i
- Language.C.Types: data ParameterDeclaration
+ Language.C.Types: data ParameterDeclaration i
- Language.C.Types: data Type
+ Language.C.Types: data Type i
- Language.C.Types: describeParameterDeclaration :: ParameterDeclaration -> Doc
+ Language.C.Types: describeParameterDeclaration :: Pretty i => ParameterDeclaration i -> Doc
- Language.C.Types: describeType :: Type -> Doc
+ Language.C.Types: describeType :: Pretty i => Type i -> Doc
- Language.C.Types: parameterDeclarationId :: ParameterDeclaration -> Maybe Identifier
+ Language.C.Types: parameterDeclarationId :: ParameterDeclaration i -> Maybe i
- Language.C.Types: parameterDeclarationType :: ParameterDeclaration -> Type
+ Language.C.Types: parameterDeclarationType :: ParameterDeclaration i -> (Type i)
- Language.C.Types: parseIdentifier :: CParser m => m Identifier
+ Language.C.Types: parseIdentifier :: CParser i m => m i
- Language.C.Types: parseParameterDeclaration :: CParser m => m ParameterDeclaration
+ Language.C.Types: parseParameterDeclaration :: (CParser i m, Pretty i) => m (ParameterDeclaration i)
- Language.C.Types: parseParameterList :: CParser m => m [ParameterDeclaration]
+ Language.C.Types: parseParameterList :: (CParser i m, Pretty i) => m [ParameterDeclaration i]
- Language.C.Types: parseType :: CParser m => m Type
+ Language.C.Types: parseType :: (CParser i m, Pretty i) => m (Type i)
- Language.C.Types: quickCParser :: IsTypeName -> String -> (ReaderT IsTypeName (Parsec String ()) a) -> a
+ Language.C.Types: quickCParser :: CParserContext i -> String -> (ReaderT (CParserContext i) (Parsec String ()) a) -> a
- Language.C.Types: quickCParser_ :: String -> (ReaderT IsTypeName (Parsec String ()) a) -> a
+ Language.C.Types: quickCParser_ :: String -> (ReaderT (CParserContext CIdentifier) (Parsec String ()) a) -> a
- Language.C.Types: runCParser :: Stream s Identity Char => IsTypeName -> String -> s -> (ReaderT IsTypeName (Parsec s ()) a) -> Either ParseError a
+ Language.C.Types: runCParser :: Stream s Identity Char => CParserContext i -> String -> s -> (ReaderT (CParserContext i) (Parsec s ()) a) -> Either ParseError a
- Language.C.Types: tangleParameterDeclaration :: ParameterDeclaration -> ParameterDeclaration
+ Language.C.Types: tangleParameterDeclaration :: ParameterDeclaration i -> ParameterDeclaration i
- Language.C.Types: type CParser m = (Monad m, Functor m, Applicative m, MonadPlus m, Parsing m, CharParsing m, TokenParsing m, LookAheadParsing m, MonadReader IsTypeName m)
+ Language.C.Types: type CParser i m = (Monad m, Functor m, Applicative m, MonadPlus m, Parsing m, CharParsing m, TokenParsing m, LookAheadParsing m, MonadReader (CParserContext i) m, Hashable i)
- Language.C.Types: untangleParameterDeclaration :: ParameterDeclaration -> Either UntangleErr ParameterDeclaration
+ Language.C.Types: untangleParameterDeclaration :: ParameterDeclaration i -> Either UntangleErr (ParameterDeclaration i)
- Language.C.Types.Parse: AbstractDeclarator :: [Pointer] -> Maybe DirectAbstractDeclarator -> AbstractDeclarator
+ Language.C.Types.Parse: AbstractDeclarator :: [Pointer] -> Maybe (DirectAbstractDeclarator i) -> AbstractDeclarator i
- Language.C.Types.Parse: AbstractDeclaratorParens :: AbstractDeclarator -> DirectAbstractDeclarator
+ Language.C.Types.Parse: AbstractDeclaratorParens :: (AbstractDeclarator i) -> DirectAbstractDeclarator i
- Language.C.Types.Parse: Array :: ArrayType -> ArrayOrProto
+ Language.C.Types.Parse: Array :: (ArrayType i) -> ArrayOrProto i
- Language.C.Types.Parse: ArrayOrProto :: DirectDeclarator -> ArrayOrProto -> DirectDeclarator
+ Language.C.Types.Parse: ArrayOrProto :: (DirectDeclarator i) -> (ArrayOrProto i) -> DirectDeclarator i
- Language.C.Types.Parse: ArrayOrProtoHere :: ArrayOrProto -> DirectAbstractDeclarator
+ Language.C.Types.Parse: ArrayOrProtoHere :: (ArrayOrProto i) -> DirectAbstractDeclarator i
- Language.C.Types.Parse: ArrayOrProtoThere :: DirectAbstractDeclarator -> ArrayOrProto -> DirectAbstractDeclarator
+ Language.C.Types.Parse: ArrayOrProtoThere :: (DirectAbstractDeclarator i) -> (ArrayOrProto i) -> DirectAbstractDeclarator i
- Language.C.Types.Parse: Declarator :: [Pointer] -> DirectDeclarator -> Declarator
+ Language.C.Types.Parse: Declarator :: [Pointer] -> (DirectDeclarator i) -> Declarator i
- Language.C.Types.Parse: DeclaratorParens :: Declarator -> DirectDeclarator
+ Language.C.Types.Parse: DeclaratorParens :: (Declarator i) -> DirectDeclarator i
- Language.C.Types.Parse: DeclaratorRoot :: Identifier -> DirectDeclarator
+ Language.C.Types.Parse: DeclaratorRoot :: i -> DirectDeclarator i
- Language.C.Types.Parse: Enum :: Identifier -> TypeSpecifier
+ Language.C.Types.Parse: Enum :: CIdentifier -> TypeSpecifier
- Language.C.Types.Parse: ParameterDeclaration :: [DeclarationSpecifier] -> Either Declarator AbstractDeclarator -> ParameterDeclaration
+ Language.C.Types.Parse: ParameterDeclaration :: [DeclarationSpecifier] -> DeclaratorOrAbstractDeclarator i -> ParameterDeclaration i
- Language.C.Types.Parse: ParameterDeclarationWithTypeNames :: Set Identifier -> ParameterDeclaration -> ParameterDeclarationWithTypeNames
+ Language.C.Types.Parse: ParameterDeclarationWithTypeNames :: HashSet CIdentifier -> (ParameterDeclaration i) -> ParameterDeclarationWithTypeNames i
- Language.C.Types.Parse: Proto :: [ParameterDeclaration] -> ArrayOrProto
+ Language.C.Types.Parse: Proto :: [ParameterDeclaration i] -> ArrayOrProto i
- Language.C.Types.Parse: SizedByIdentifier :: Identifier -> ArrayType
+ Language.C.Types.Parse: SizedByIdentifier :: i -> ArrayType i
- Language.C.Types.Parse: SizedByInteger :: Integer -> ArrayType
+ Language.C.Types.Parse: SizedByInteger :: Integer -> ArrayType i
- Language.C.Types.Parse: Struct :: Identifier -> TypeSpecifier
+ Language.C.Types.Parse: Struct :: CIdentifier -> TypeSpecifier
- Language.C.Types.Parse: TypeName :: Identifier -> TypeSpecifier
+ Language.C.Types.Parse: TypeName :: CIdentifier -> TypeSpecifier
- Language.C.Types.Parse: Unsized :: ArrayType
+ Language.C.Types.Parse: Unsized :: ArrayType i
- Language.C.Types.Parse: VariablySized :: ArrayType
+ Language.C.Types.Parse: VariablySized :: ArrayType i
- Language.C.Types.Parse: abstractDeclaratorDirect :: AbstractDeclarator -> Maybe DirectAbstractDeclarator
+ Language.C.Types.Parse: abstractDeclaratorDirect :: AbstractDeclarator i -> Maybe (DirectAbstractDeclarator i)
- Language.C.Types.Parse: abstractDeclaratorPointers :: AbstractDeclarator -> [Pointer]
+ Language.C.Types.Parse: abstractDeclaratorPointers :: AbstractDeclarator i -> [Pointer]
- Language.C.Types.Parse: abstract_declarator :: CParser m => m AbstractDeclarator
+ Language.C.Types.Parse: abstract_declarator :: CParser i m => m (AbstractDeclarator i)
- Language.C.Types.Parse: array_or_proto :: CParser m => m ArrayOrProto
+ Language.C.Types.Parse: array_or_proto :: CParser i m => m (ArrayOrProto i)
- Language.C.Types.Parse: array_type :: CParser m => m ArrayType
+ Language.C.Types.Parse: array_type :: CParser i m => m (ArrayType i)
- Language.C.Types.Parse: data AbstractDeclarator
+ Language.C.Types.Parse: data AbstractDeclarator i
- Language.C.Types.Parse: data ArrayOrProto
+ Language.C.Types.Parse: data ArrayOrProto i
- Language.C.Types.Parse: data ArrayType
+ Language.C.Types.Parse: data ArrayType i
- Language.C.Types.Parse: data Declarator
+ Language.C.Types.Parse: data Declarator i
- Language.C.Types.Parse: data DirectAbstractDeclarator
+ Language.C.Types.Parse: data DirectAbstractDeclarator i
- Language.C.Types.Parse: data DirectDeclarator
+ Language.C.Types.Parse: data DirectDeclarator i
- Language.C.Types.Parse: data ParameterDeclaration
+ Language.C.Types.Parse: data ParameterDeclaration i
- Language.C.Types.Parse: data ParameterDeclarationWithTypeNames
+ Language.C.Types.Parse: data ParameterDeclarationWithTypeNames i
- Language.C.Types.Parse: declaration_specifiers :: CParser m => m [DeclarationSpecifier]
+ Language.C.Types.Parse: declaration_specifiers :: CParser i m => m [DeclarationSpecifier]
- Language.C.Types.Parse: declarator :: CParser m => m Declarator
+ Language.C.Types.Parse: declarator :: CParser i m => m (Declarator i)
- Language.C.Types.Parse: declaratorDirect :: Declarator -> DirectDeclarator
+ Language.C.Types.Parse: declaratorDirect :: Declarator i -> (DirectDeclarator i)
- Language.C.Types.Parse: declaratorPointers :: Declarator -> [Pointer]
+ Language.C.Types.Parse: declaratorPointers :: Declarator i -> [Pointer]
- Language.C.Types.Parse: direct_abstract_declarator :: CParser m => m DirectAbstractDeclarator
+ Language.C.Types.Parse: direct_abstract_declarator :: CParser i m => m (DirectAbstractDeclarator i)
- Language.C.Types.Parse: direct_declarator :: CParser m => m DirectDeclarator
+ Language.C.Types.Parse: direct_declarator :: CParser i m => m (DirectDeclarator i)
- Language.C.Types.Parse: function_specifier :: CParser m => m FunctionSpecifier
+ Language.C.Types.Parse: function_specifier :: CParser i m => m FunctionSpecifier
- Language.C.Types.Parse: identifier_no_lex :: CParser m => m Identifier
+ Language.C.Types.Parse: identifier_no_lex :: CParser i m => m i
- Language.C.Types.Parse: parameterDeclarationDeclarator :: ParameterDeclaration -> Either Declarator AbstractDeclarator
+ Language.C.Types.Parse: parameterDeclarationDeclarator :: ParameterDeclaration i -> DeclaratorOrAbstractDeclarator i
- Language.C.Types.Parse: parameterDeclarationSpecifiers :: ParameterDeclaration -> [DeclarationSpecifier]
+ Language.C.Types.Parse: parameterDeclarationSpecifiers :: ParameterDeclaration i -> [DeclarationSpecifier]
- Language.C.Types.Parse: parameter_declaration :: CParser m => m ParameterDeclaration
+ Language.C.Types.Parse: parameter_declaration :: CParser i m => m (ParameterDeclaration i)
- Language.C.Types.Parse: parameter_list :: CParser m => m [ParameterDeclaration]
+ Language.C.Types.Parse: parameter_list :: CParser i m => m [ParameterDeclaration i]
- Language.C.Types.Parse: pdwtnParameterDeclaration :: ParameterDeclarationWithTypeNames -> ParameterDeclaration
+ Language.C.Types.Parse: pdwtnParameterDeclaration :: ParameterDeclarationWithTypeNames i -> (ParameterDeclaration i)
- Language.C.Types.Parse: pdwtnTypeNames :: ParameterDeclarationWithTypeNames -> Set Identifier
+ Language.C.Types.Parse: pdwtnTypeNames :: ParameterDeclarationWithTypeNames i -> HashSet CIdentifier
- Language.C.Types.Parse: pointer :: CParser m => m Pointer
+ Language.C.Types.Parse: pointer :: CParser i m => m Pointer
- Language.C.Types.Parse: quickCParser :: IsTypeName -> String -> (ReaderT IsTypeName (Parsec String ()) a) -> a
+ Language.C.Types.Parse: quickCParser :: CParserContext i -> String -> (ReaderT (CParserContext i) (Parsec String ()) a) -> a
- Language.C.Types.Parse: quickCParser_ :: String -> (ReaderT IsTypeName (Parsec String ()) a) -> a
+ Language.C.Types.Parse: quickCParser_ :: String -> (ReaderT (CParserContext CIdentifier) (Parsec String ()) a) -> a
- Language.C.Types.Parse: runCParser :: Stream s Identity Char => IsTypeName -> String -> s -> (ReaderT IsTypeName (Parsec s ()) a) -> Either ParseError a
+ Language.C.Types.Parse: runCParser :: Stream s Identity Char => CParserContext i -> String -> s -> (ReaderT (CParserContext i) (Parsec s ()) a) -> Either ParseError a
- Language.C.Types.Parse: storage_class_specifier :: CParser m => m StorageClassSpecifier
+ Language.C.Types.Parse: storage_class_specifier :: CParser i m => m StorageClassSpecifier
- Language.C.Types.Parse: type CParser m = (Monad m, Functor m, Applicative m, MonadPlus m, Parsing m, CharParsing m, TokenParsing m, LookAheadParsing m, MonadReader IsTypeName m)
+ Language.C.Types.Parse: type CParser i m = (Monad m, Functor m, Applicative m, MonadPlus m, Parsing m, CharParsing m, TokenParsing m, LookAheadParsing m, MonadReader (CParserContext i) m, Hashable i)
- Language.C.Types.Parse: type_qualifier :: CParser m => m TypeQualifier
+ Language.C.Types.Parse: type_qualifier :: CParser i m => m TypeQualifier
- Language.C.Types.Parse: type_specifier :: CParser m => m TypeSpecifier
+ Language.C.Types.Parse: type_specifier :: CParser i m => m TypeSpecifier
Files
- README.md +3/−0
- changelog.md +1/−0
- inline-c.cabal +5/−1
- src/Language/C/Inline/Context.hs +59/−40
- src/Language/C/Inline/HaskellIdentifier.hs +166/−0
- src/Language/C/Inline/Internal.hs +74/−38
- src/Language/C/Types.hs +58/−43
- src/Language/C/Types/Parse.hs +316/−202
- test/Language/C/Inline/ContextSpec.hs +1/−1
- test/Language/C/Inline/ParseSpec.hs +36/−12
- test/Language/C/Types/ParseSpec.hs +21/−9
- test/tests.c +32/−17
- test/tests.hs +8/−1
README.md view
@@ -136,6 +136,9 @@ Here, the Haskell variable `n` is captured right where we need it using `$(int n)`. Standard anti-quotation (we'll talk about additional ones later) consists of a `$` followed by a C declaration in parenthesis.+Note that any valid Haskell identifiers can be used when anti-quoting,+including ones including constructors, qualified names, names containing+unicode, etc. For each anti-quotation, a variable with a matching type is expected in the Haskell environment. In this case `inline-c` expects a variable
changelog.md view
@@ -1,3 +1,4 @@+- 0.5.4.0: Allow Haskell identifiers in anti-quotes. See issue #23. - 0.5.3.4: Fix `bsCtx` docs. - 0.5.3.3: * Fix errors when using parallel builds. See issue #22.
inline-c.cabal view
@@ -1,5 +1,5 @@ name: inline-c-version: 0.5.3.4+version: 0.5.4.0 synopsis: Write Haskell source files including C code inline. No FFI required. description: See <https://github.com/fpco/inline-c/blob/master/README.md>. license: MIT@@ -24,6 +24,7 @@ library exposed-modules: Language.C.Inline , Language.C.Inline.Context+ , Language.C.Inline.HaskellIdentifier , Language.C.Inline.Internal , Language.C.Inline.Unsafe , Language.C.Types@@ -39,6 +40,7 @@ , cryptohash , directory , filepath+ , hashable , mtl , parsec >= 3 , parsers@@ -61,6 +63,7 @@ build-depends: base >=4 && <5 , ansi-wl-pprint , containers+ , hashable , hspec >= 2 , inline-c , parsers@@ -69,6 +72,7 @@ , regex-posix , template-haskell , transformers+ , unordered-containers , vector default-language: Haskell2010 ghc-options: -Wall
src/Language/C/Inline/Context.hs view
@@ -24,7 +24,7 @@ , Purity(..) , convertType , CArray- , isTypeName+ , typeNamesFromTypesTable -- * 'AntiQuoter' , AntiQuoter(..)@@ -47,9 +47,10 @@ import Control.Monad.Trans.Maybe (MaybeT, runMaybeT) import qualified Data.ByteString as BS import qualified Data.ByteString.Unsafe as BS-import qualified Data.Map as Map import Data.Int (Int8, Int16, Int32, Int64)+import qualified Data.Map as Map import Data.Monoid ((<>))+import Data.Traversable (traverse) import Data.Typeable (Typeable) import qualified Data.Vector.Storable as V import qualified Data.Vector.Storable.Mutable as VM@@ -59,6 +60,7 @@ import Foreign.Storable (Storable) import qualified Language.Haskell.TH as TH import qualified Text.Parser.Token as Parser+import qualified Data.HashSet as HashSet #if __GLASGOW_HASKELL__ < 710 import Data.Monoid (Monoid(..))@@ -66,6 +68,7 @@ import Language.C.Inline.FunPtr import qualified Language.C.Types as C+import Language.C.Inline.HaskellIdentifier -- | A mapping from 'C.TypeSpecifier's to Haskell types. Needed both to -- parse C types, and to convert them to Haskell types.@@ -89,12 +92,15 @@ -- Where @XXX@ is the name of the antiquoter and @YYY@ is something -- parseable by the respective 'aqParser'. data AntiQuoter a = AntiQuoter- { aqParser :: forall m. C.CParser m => m (String, C.Type, a)+ { aqParser :: forall m. C.CParser HaskellIdentifier m => m (C.CIdentifier, C.Type C.CIdentifier, a) -- ^ Parses the body of the antiquotation, returning a hint for the name to -- assign to the variable that will replace the anti-quotation, the type of -- said variable, and some arbitrary data which will then be fed to -- 'aqMarshaller'.- , aqMarshaller :: Purity -> TypesTable -> C.Type -> a -> TH.Q (TH.Type, TH.Exp)+ --+ -- The 'C.Type' has 'Void' as an identifier type to make sure that+ -- no names appear in it.+ , aqMarshaller :: Purity -> TypesTable -> C.Type C.CIdentifier -> a -> TH.Q (TH.Type, TH.Exp) -- ^ Takes the requested purity, the current 'TypesTable', and the -- type and the body returned by 'aqParser'. --@@ -229,13 +235,13 @@ convertType :: Purity -> TypesTable- -> C.Type+ -> C.Type C.CIdentifier -> TH.Q (Maybe TH.Type) convertType purity cTypes = runMaybeT . go where goDecl = go . C.parameterDeclarationType - go :: C.Type -> MaybeT TH.Q TH.Type+ go :: C.Type C.CIdentifier -> MaybeT TH.Q TH.Type go cTy = case cTy of C.TypeSpecifier _specs cSpec -> case Map.lookup cSpec cTypes of@@ -262,21 +268,22 @@ buildArr (hsPar : hsPars) hsRetType = [t| $(return hsPar) -> $(buildArr hsPars hsRetType) |] -isTypeName :: TypesTable -> C.Identifier -> Bool-isTypeName cTypes id' = Map.member (C.TypeName id') cTypes+typeNamesFromTypesTable :: TypesTable -> C.TypeNames+typeNamesFromTypesTable cTypes = HashSet.fromList+ [ id' | C.TypeName id' <- Map.keys cTypes ] ------------------------------------------------------------------------ -- Useful contexts -getHsVariable :: String -> String -> TH.ExpQ+getHsVariable :: String -> HaskellIdentifier -> TH.ExpQ getHsVariable err s = do- mbHsName <- TH.lookupValueName s+ mbHsName <- TH.lookupValueName $ unHaskellIdentifier s case mbHsName of- Nothing -> fail $ "Cannot capture Haskell variable " ++ s +++ Nothing -> fail $ "Cannot capture Haskell variable " ++ unHaskellIdentifier s ++ ", because it's not in scope. (" ++ err ++ ")" Just hsName -> TH.varE hsName -convertType_ :: String -> Purity -> TypesTable -> C.Type -> TH.Q TH.Type+convertType_ :: String -> Purity -> TypesTable -> C.Type C.CIdentifier -> TH.Q TH.Type convertType_ err purity cTypes cTy = do mbHsType <- convertType purity cTypes cTy case mbHsType of@@ -300,15 +307,9 @@ { ctxAntiQuoters = Map.fromList [("fun", SomeAntiQuoter funPtrAntiQuoter)] } -funPtrAntiQuoter :: AntiQuoter String+funPtrAntiQuoter :: AntiQuoter HaskellIdentifier funPtrAntiQuoter = AntiQuoter- { aqParser = do- cTy <- Parser.parens C.parseParameterDeclaration- case C.parameterDeclarationId cTy of- Nothing -> fail "Every captured function must be named (funCtx)"- Just id' -> do- let s = C.unIdentifier id'- return (s, C.parameterDeclarationType cTy, s)+ { aqParser = cDeclAqParser , aqMarshaller = \purity cTypes cTy cId -> do hsTy <- convertType_ "funCtx" purity cTypes cTy hsExp <- getHsVariable "funCtx" cId@@ -366,15 +367,9 @@ vecCtxLength = VM.length vecCtxUnsafeWith = VM.unsafeWith -vecPtrAntiQuoter :: AntiQuoter String+vecPtrAntiQuoter :: AntiQuoter HaskellIdentifier vecPtrAntiQuoter = AntiQuoter- { aqParser = do- cTy <- Parser.parens C.parseParameterDeclaration- case C.parameterDeclarationId cTy of- Nothing -> fail "Every captured vector must be named (vecCtx)"- Just id' -> do- let s = C.unIdentifier id'- return (s, C.parameterDeclarationType cTy, s)+ { aqParser = cDeclAqParser , aqMarshaller = \purity cTypes cTy cId -> do hsTy <- convertType_ "vecCtx" purity cTypes cTy hsExp <- getHsVariable "vecCtx" cId@@ -382,12 +377,12 @@ return (hsTy, hsExp') } -vecLenAntiQuoter :: AntiQuoter String+vecLenAntiQuoter :: AntiQuoter HaskellIdentifier vecLenAntiQuoter = AntiQuoter { aqParser = do- cId <- C.parseIdentifier- let s = C.unIdentifier cId- return (s, C.TypeSpecifier mempty (C.Long C.Signed), s)+ hId <- C.parseIdentifier+ let cId = mangleHaskellIdentifier hId+ return (cId, C.TypeSpecifier mempty (C.Long C.Signed), hId) , aqMarshaller = \_purity _cTypes cTy cId -> do case cTy of C.TypeSpecifier _ (C.Long C.Signed) -> do@@ -413,12 +408,12 @@ ] } -bsPtrAntiQuoter :: AntiQuoter String+bsPtrAntiQuoter :: AntiQuoter HaskellIdentifier bsPtrAntiQuoter = AntiQuoter { aqParser = do- cId <- C.parseIdentifier- let s = C.unIdentifier cId- return (s, C.Ptr [] (C.TypeSpecifier mempty (C.Char Nothing)), s)+ hId <- C.parseIdentifier+ let cId = mangleHaskellIdentifier hId+ return (cId, C.Ptr [] (C.TypeSpecifier mempty (C.Char Nothing)), hId) , aqMarshaller = \_purity _cTypes cTy cId -> do case cTy of C.Ptr _ (C.TypeSpecifier _ (C.Char Nothing)) -> do@@ -430,12 +425,12 @@ fail "impossible: got type different from `unsigned char' (bsCtx)" } -bsLenAntiQuoter :: AntiQuoter String+bsLenAntiQuoter :: AntiQuoter HaskellIdentifier bsLenAntiQuoter = AntiQuoter { aqParser = do- cId <- C.parseIdentifier- let s = C.unIdentifier cId- return (s, C.TypeSpecifier mempty (C.Long C.Signed), s)+ hId <- C.parseIdentifier+ let cId = mangleHaskellIdentifier hId+ return (cId, C.TypeSpecifier mempty (C.Long C.Signed), hId) , aqMarshaller = \_purity _cTypes cTy cId -> do case cTy of C.TypeSpecifier _ (C.Long C.Signed) -> do@@ -447,3 +442,27 @@ _ -> do fail "impossible: got type different from `long' (bsCtx)" }++-- Utils+------------------------------------------------------------------------++cDeclAqParser+ :: C.CParser HaskellIdentifier m+ => m (C.CIdentifier, C.Type C.CIdentifier, HaskellIdentifier)+cDeclAqParser = do+ cTy <- Parser.parens C.parseParameterDeclaration+ case C.parameterDeclarationId cTy of+ Nothing -> fail "Every captured function must be named (funCtx)"+ Just hId -> do+ let cId = mangleHaskellIdentifier hId+ cTy' <- deHaskellifyCType $ C.parameterDeclarationType cTy+ return (cId, cTy', hId)++deHaskellifyCType+ :: C.CParser HaskellIdentifier m+ => C.Type HaskellIdentifier -> m (C.Type C.CIdentifier)+deHaskellifyCType = traverse $ \hId -> do+ case C.cIdentifierFromString (unHaskellIdentifier hId) of+ Left err -> fail $ "Illegal Haskell identifier " ++ unHaskellIdentifier hId +++ " in C type:\n" ++ err+ Right x -> return x
+ src/Language/C/Inline/HaskellIdentifier.hs view
@@ -0,0 +1,166 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Language.C.Inline.HaskellIdentifier+ ( HaskellIdentifier+ , unHaskellIdentifier+ , haskellIdentifierFromString+ , haskellCParserContext+ , parseHaskellIdentifier+ , mangleHaskellIdentifier+ ) where++import Control.Applicative ((<*), (<$>))+import Control.Applicative ((<|>), (<*>))+import Control.Monad (when, msum, void)+import Data.Char (ord)+import qualified Data.HashSet as HashSet+import Data.Hashable (Hashable)+import Data.List (intercalate, partition, intersperse)+import Data.Monoid ((<>))+import Data.String (IsString(..))+import Data.Typeable (Typeable)+import Numeric (showHex)+import qualified Test.QuickCheck as QC+import Text.Parser.Char (upper, lower, digit, char)+import Text.Parser.Combinators (many, eof, try, unexpected, (<?>))+import Text.Parser.Token (IdentifierStyle(..), highlight, TokenParsing)+import qualified Text.Parser.Token.Highlight as Highlight+import qualified Text.PrettyPrint.ANSI.Leijen as PP++import qualified Language.C.Types.Parse as C++-- | A possibly qualified Haskell identifier.+newtype HaskellIdentifier = HaskellIdentifier {unHaskellIdentifier :: String}+ deriving (Typeable, Eq, Ord, Show, Hashable)++instance IsString HaskellIdentifier where+ fromString s =+ case haskellIdentifierFromString s of+ Left err -> error $ "HaskellIdentifier fromString: invalid string " ++ s ++ ":\n" ++ err+ Right x -> x++instance PP.Pretty HaskellIdentifier where+ pretty = PP.text . unHaskellIdentifier++haskellIdentifierFromString :: String -> Either String HaskellIdentifier+haskellIdentifierFromString s =+ case C.runCParser cpc "haskellIdentifierFromString" s (parseHaskellIdentifier <* eof) of+ Left err -> Left $ show err+ Right x -> Right x+ where+ cpc = haskellCParserContext HashSet.empty++haskellCParserContext :: C.TypeNames -> C.CParserContext HaskellIdentifier+haskellCParserContext typeNames = C.CParserContext+ { C.cpcTypeNames = typeNames+ , C.cpcParseIdent = parseHaskellIdentifier+ , C.cpcIdentName = "Haskell identifier"+ , C.cpcIdentToString = unHaskellIdentifier+ }++-- | See+-- <https://www.haskell.org/onlinereport/haskell2010/haskellch2.html#x7-160002.2>.+haskellIdentStyle :: C.CParser i m => IdentifierStyle m+haskellIdentStyle = IdentifierStyle+ { _styleName = "Haskell identifier"+ , _styleStart = small+ , _styleLetter = small <|> large <|> digit <|> char '\''+ , _styleReserved = haskellReservedWords+ , _styleHighlight = Highlight.Identifier+ , _styleReservedHighlight = Highlight.ReservedIdentifier+ }+ where+ small = lower <|> char '_'+ large = upper++-- We disallow both Haskell reserved words and C reserved words.+haskellReservedWords :: HashSet.HashSet String+haskellReservedWords = C.cReservedWords <> HashSet.fromList+ [ "case", "class", "data", "default", "deriving", "do", "else"+ , "foreign", "if", "import", "in", "infix", "infixl"+ , "infixr", "instance", "let", "module", "newtype", "of"+ , "then", "type", "where"+ ]++-- | See+-- <https://www.haskell.org/onlinereport/haskell2010/haskellch2.html#x7-160002.2>.+parseHaskellIdentifier :: forall i m. C.CParser i m => m HaskellIdentifier+parseHaskellIdentifier = do+ segments <- go+ return $ HaskellIdentifier $ intercalate "." segments+ where+ small = lower <|> char '_'+ large = upper++ conid :: m String+ conid = try $ highlight Highlight.Identifier $+ ((:) <$> large <*> many (small <|> large <|> digit <|> char '\'')) <?> "Haskell constructor"++ varid :: m String+ varid = identNoLex haskellIdentStyle++ go = msum+ [ do con <- conid+ msum+ [ do void $ char '.'+ (con :) <$> go+ , return [con]+ ]+ , do var <- varid+ return [var]+ ]++-- | Mangles an 'HaskellIdentifier' to produce a valid 'C.CIdentifier'+-- which still sort of resembles the 'HaskellIdentifier'.+mangleHaskellIdentifier :: HaskellIdentifier -> C.CIdentifier+mangleHaskellIdentifier (HaskellIdentifier hs) =+ -- The leading underscore if we have no valid chars is because then+ -- we'd have an identifier starting with numbers.+ let cs = (if null valid then "_" else "") +++ valid +++ (if null mangled || null valid then "" else "_") +++ mangled+ in case C.cIdentifierFromString cs of+ Left err -> error $ "mangleHaskellIdentifier: produced bad C identifier\n" ++ err+ Right x -> x+ where+ (valid, invalid) = partition (`elem` C.cIdentLetter) hs++ mangled = concat $ intersperse "_" $ map (`showHex` "") $ map ord invalid++-- Utils+------------------------------------------------------------------------++identNoLex :: (TokenParsing m, Monad m, IsString s) => IdentifierStyle m -> m s+identNoLex s = fmap fromString $ try $ do+ name <- highlight (_styleHighlight s)+ ((:) <$> _styleStart s <*> many (_styleLetter s) <?> _styleName s)+ when (HashSet.member name (_styleReserved s)) $ unexpected $ "reserved " ++ _styleName s ++ " " ++ show name+ return name++-- Arbitrary instance+------------------------------------------------------------------------++instance QC.Arbitrary HaskellIdentifier where+ arbitrary = do+ modIds <- QC.listOf arbitraryModId+ id_ <- QC.oneof [arbitraryConId, arbitraryVarId]+ if null modIds && HashSet.member id_ haskellReservedWords+ then QC.arbitrary+ else return $ HaskellIdentifier $ intercalate "." $ modIds ++ [id_]+ where+ arbitraryModId = arbitraryConId++ arbitraryConId =+ ((:) <$> QC.elements large <*> QC.listOf (QC.elements (small ++ large ++ digit' ++ ['\''])))++ arbitraryVarId =+ ((:) <$> QC.elements small <*> QC.listOf (QC.elements (small ++ large ++ digit' ++ ['\''])))++ -- We currently do not generate unicode identifiers.+ large = ['A'..'Z']+ small = ['a'..'z'] ++ ['_']+ digit' = ['0'..'9']
src/Language/C/Inline/Internal.hs view
@@ -58,6 +58,7 @@ import Data.Foldable (forM_) import qualified Data.Map as Map import Data.Maybe (fromMaybe)+import Data.Traversable (for) import Data.Typeable (Typeable, cast) import qualified Language.Haskell.TH as TH import qualified Language.Haskell.TH.Quote as TH@@ -75,9 +76,10 @@ import Text.PrettyPrint.ANSI.Leijen ((<+>)) import qualified Text.PrettyPrint.ANSI.Leijen as PP -import qualified Language.C.Types as C import Language.C.Inline.Context import Language.C.Inline.FunPtr+import Language.C.Inline.HaskellIdentifier+import qualified Language.C.Types as C data ModuleState = ModuleState { msContext :: Context@@ -276,9 +278,9 @@ -- ^ Safety of the foreign call -> TH.TypeQ -- ^ Type of the foreign call- -> C.Type+ -> C.Type C.CIdentifier -- ^ Return type of the C expr- -> [(C.Identifier, C.Type)]+ -> [(C.CIdentifier, C.Type C.CIdentifier)] -- ^ Parameters of the C expr -> String -- ^ The C expression@@ -308,9 +310,9 @@ -- ^ Safety of the foreign call -> TH.TypeQ -- ^ Type of the foreign call- -> C.Type+ -> C.Type C.CIdentifier -- ^ Return type of the C expr- -> [(C.Identifier, C.Type)]+ -> [(C.CIdentifier, C.Type C.CIdentifier)] -- ^ Parameters of the C expr -> String -- ^ The C items@@ -319,7 +321,11 @@ let mkParam (id', paramTy) = C.ParameterDeclaration (Just id') paramTy let proto = C.Proto cRetType (map mkParam cParams) funName <- uniqueCName $ show proto ++ cItems- let decl = C.ParameterDeclaration (Just (C.Identifier funName)) proto+ cFunName <- case C.cIdentifierFromString funName of+ Left err -> fail $ "inlineItems: impossible, generated bad C identifier " +++ "funName:\n" ++ err+ Right x -> return x+ let decl = C.ParameterDeclaration (Just cFunName) proto let defs = prettyOneLine decl ++ " {\n" ++ cItems ++ "\n}\n"@@ -334,13 +340,13 @@ -- Parsing runParserInQ- :: String -> C.IsTypeName -> (forall m. C.CParser m => m a) -> TH.Q a-runParserInQ s isTypeName' p = do+ :: String -> C.TypeNames -> (forall m. C.CParser HaskellIdentifier m => m a) -> TH.Q a+runParserInQ s typeNames' p = do loc <- TH.location let (line, col) = TH.loc_start loc let parsecLoc = Parsec.newPos (TH.loc_filename loc) line col let p' = lift (Parsec.setPosition parsecLoc) *> p <* lift Parser.eof- case C.runCParser isTypeName' (TH.loc_filename loc) s p' of+ case C.runCParser (haskellCParserContext typeNames') (TH.loc_filename loc) s p' of Left err -> do -- TODO consider prefixing with "error while parsing C" or similar fail $ show err@@ -364,49 +370,43 @@ fromSomeEq (SomeEq x) = cast x data ParameterType- = Plain String -- The name of the captured variable+ = Plain HaskellIdentifier -- The name of the captured variable | AntiQuote AntiQuoterId SomeEq deriving (Show, Eq) data ParseTypedC = ParseTypedC- { ptcReturnType :: C.Type- , ptcParameters :: [(C.Identifier, C.Type, ParameterType)]+ { ptcReturnType :: C.Type C.CIdentifier+ , ptcParameters :: [(C.CIdentifier, C.Type C.CIdentifier, ParameterType)] , ptcBody :: String } +-- To parse C declarations, we're faced with a bit of a problem: we want+-- to parse the anti-quotations so that Haskell identifiers are+-- accepted, but we want them to appear only as the root of+-- declarations. For this reason, we parse allowing Haskell identifiers+-- everywhere, and then we "purge" Haskell identifiers everywhere but at+-- the root. parseTypedC- :: forall m. C.CParser m+ :: forall m. C.CParser HaskellIdentifier m => AntiQuoters -> m ParseTypedC -- ^ Returns the return type, the captured variables, and the body. parseTypedC antiQs = do -- Parse return type (consume spaces first) Parser.spaces- cRetType <- C.parseType+ cRetType <- purgeHaskellIdentifiers =<< C.parseType -- Parse the body void $ Parser.char '{' (cParams, cBody) <- evalStateT parseBody 0 return $ ParseTypedC cRetType cParams cBody where- parseBody :: StateT Int m ([(C.Identifier, C.Type, ParameterType)], String)+ parseBody+ :: StateT Int m ([(C.CIdentifier, C.Type C.CIdentifier, ParameterType)], String) parseBody = do -- Note that this code does not use "lexing" combinators (apart -- when appropriate) because we want to make sure to preserve -- whitespace after we substitute things. s <- Parser.manyTill Parser.anyChar $ Parser.lookAhead (Parser.char '}' <|> Parser.char '$')- let parseEscapedDollar = do- void $ Parser.char '$'- return ([], "$")- let parseTypedCapture = do- void $ Parser.symbolic '('- decl <- C.parseParameterDeclaration- s' <- case C.parameterDeclarationId decl of- Nothing -> fail $ pretty80 $- "Un-named captured variable in decl" <+> PP.pretty decl- Just id' -> return $ C.unIdentifier id'- id' <- freshId s'- void $ Parser.char ')'- return ([(id', C.parameterDeclarationType decl, Plain s')], C.unIdentifier id') (decls, s') <- msum [ do Parser.try $ do -- Try because we might fail to parse the 'eof' -- 'symbolic' because we want to consume whitespace@@ -424,20 +424,56 @@ return (decls, s ++ s') where - parseAntiQuote :: StateT Int m ([(C.Identifier, C.Type, ParameterType)], String)+ parseAntiQuote+ :: StateT Int m ([(C.CIdentifier, C.Type C.CIdentifier, ParameterType)], String) parseAntiQuote = msum [ do void $ Parser.try (Parser.string $ antiQId ++ ":") Parser.<?> "anti quoter id" (s, cTy, x) <- aqParser antiQ id' <- freshId s- return ([(id', cTy, AntiQuote antiQId (toSomeEq x))], C.unIdentifier id')+ return ([(id', cTy, AntiQuote antiQId (toSomeEq x))], C.unCIdentifier id') | (antiQId, SomeAntiQuoter antiQ) <- Map.toList antiQs ] + parseEscapedDollar :: StateT Int m ([a], String)+ parseEscapedDollar = do+ void $ Parser.char '$'+ return ([], "$")++ parseTypedCapture+ :: StateT Int m ([(C.CIdentifier, C.Type C.CIdentifier, ParameterType)], String)+ parseTypedCapture = do+ void $ Parser.symbolic '('+ decl <- C.parseParameterDeclaration+ declType <- purgeHaskellIdentifiers $ C.parameterDeclarationType decl+ -- Purge the declaration type of all the Haskell identifiers.+ hId <- case C.parameterDeclarationId decl of+ Nothing -> fail $ pretty80 $+ "Un-named captured variable in decl" <+> PP.pretty decl+ Just hId -> return hId+ id' <- freshId $ mangleHaskellIdentifier hId+ void $ Parser.char ')'+ return ([(id', declType, Plain hId)], C.unCIdentifier id')+ freshId s = do c <- get put $ c + 1- return $ C.Identifier $ s ++ "_inline_c_" ++ show c+ case C.cIdentifierFromString (C.unCIdentifier s ++ "_inline_c_" ++ show c) of+ Left _err -> error "freshId: The impossible happened"+ Right x -> return x + -- The @m@ is polymorphic because we use this both for the plain+ -- parser and the StateT parser we use above. We only need 'fail'.+ purgeHaskellIdentifiers+ :: forall n. (Applicative n, Monad n)+ => C.Type HaskellIdentifier -> n (C.Type C.CIdentifier)+ purgeHaskellIdentifiers cTy = for cTy $ \hsIdent -> do+ let hsIdentS = unHaskellIdentifier hsIdent+ case C.cIdentifierFromString hsIdentS of+ Left err -> fail $ "Haskell identifier " ++ hsIdentS ++ " in illegal position" +++ "in C type\n" ++ pretty80 cTy ++ "\n" +++ "A C identifier was expected, but:\n" ++ err+ Right cIdent -> return cIdent+ quoteCode :: (String -> TH.ExpQ) -- ^ The parser@@ -451,23 +487,23 @@ genericQuote :: Purity- -> (TH.TypeQ -> C.Type -> [(C.Identifier, C.Type)] -> String -> TH.ExpQ)- -- ^ Function taking that something and building an expression, see- -- 'inlineExp' for other args.+ -> (TH.TypeQ -> C.Type C.CIdentifier -> [(C.CIdentifier, C.Type C.CIdentifier)] -> String -> TH.ExpQ)+ -- ^ Function building an Haskell expression, see 'inlineExp' for+ -- guidance on the other args. -> TH.QuasiQuoter genericQuote purity build = quoteCode $ \s -> do ctx <- getContext ParseTypedC cType cParams cExp <-- runParserInQ s (isTypeName (ctxTypesTable ctx)) $ parseTypedC $ ctxAntiQuoters ctx+ runParserInQ s (typeNamesFromTypesTable (ctxTypesTable ctx)) $ parseTypedC $ ctxAntiQuoters ctx hsType <- cToHs ctx cType hsParams <- forM cParams $ \(_cId, cTy, parTy) -> do case parTy of Plain s' -> do hsTy <- cToHs ctx cTy- mbHsName <- TH.lookupValueName s'+ mbHsName <- TH.lookupValueName $ unHaskellIdentifier s' hsExp <- case mbHsName of Nothing -> do- fail $ "Cannot capture Haskell variable " ++ s' +++ fail $ "Cannot capture Haskell variable " ++ unHaskellIdentifier s' ++ ", because it's not in scope. (genericQuote)" Just hsName -> do hsExp <- TH.varE hsName@@ -492,7 +528,7 @@ Pure -> [| unsafePerformIO $(return ioCall) |] IO -> return ioCall where- cToHs :: Context -> C.Type -> TH.TypeQ+ cToHs :: Context -> C.Type C.CIdentifier -> TH.TypeQ cToHs ctx cTy = do mbHsTy <- convertType purity (ctxTypesTable ctx) cTy case mbHsTy of
src/Language/C/Types.hs view
@@ -1,12 +1,15 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} -- | Views of C datatypes. While "Language.C.Types.Parse" defines datatypes for@@ -21,7 +24,9 @@ module Language.C.Types ( -- * Types- P.Identifier(..)+ P.CIdentifier+ , P.unCIdentifier+ , P.cIdentifierFromString , P.StorageClassSpecifier(..) , P.TypeQualifier(..) , P.FunctionSpecifier(..)@@ -33,8 +38,10 @@ , ParameterDeclaration(..) -- * Parsing- , P.IsTypeName+ , P.TypeNames , P.CParser+ , P.CParserContext+ , P.cCParserContext , P.runCParser , P.quickCParser , P.quickCParser_@@ -56,9 +63,11 @@ import Control.Arrow (second) import Control.Monad (when, unless, forM_) import Control.Monad.State (execState, modify)+import Data.Foldable (Foldable) import Data.List (partition) import Data.Maybe (fromMaybe) import Data.Monoid ((<>))+import Data.Traversable (Traversable) import Data.Typeable (Typeable) import Text.PrettyPrint.ANSI.Leijen ((</>), (<+>)) import qualified Text.PrettyPrint.ANSI.Leijen as PP@@ -83,9 +92,9 @@ | Float | Double | LDouble- | TypeName P.Identifier- | Struct P.Identifier- | Enum P.Identifier+ | TypeName P.CIdentifier+ | Struct P.CIdentifier+ | Enum P.CIdentifier deriving (Typeable, Show, Eq, Ord) data Specifiers = Specifiers@@ -100,22 +109,22 @@ mappend (Specifiers x1 y1 z1) (Specifiers x2 y2 z2) = Specifiers (x1 ++ x2) (y1 ++ y2) (z1 ++ z2) -data Type+data Type i = TypeSpecifier Specifiers TypeSpecifier- | Ptr [P.TypeQualifier] Type- | Array P.ArrayType Type- | Proto Type [ParameterDeclaration]- deriving (Typeable, Show, Eq)+ | Ptr [P.TypeQualifier] (Type i)+ | Array (P.ArrayType i) (Type i)+ | Proto (Type i) [ParameterDeclaration i]+ deriving (Typeable, Show, Eq, Functor, Foldable, Traversable) data Sign = Signed | Unsigned deriving (Typeable, Show, Eq, Ord) -data ParameterDeclaration = ParameterDeclaration- { parameterDeclarationId :: Maybe P.Identifier- , parameterDeclarationType :: Type- } deriving (Typeable, Show, Eq)+data ParameterDeclaration i = ParameterDeclaration+ { parameterDeclarationId :: Maybe i+ , parameterDeclarationType :: (Type i)+ } deriving (Typeable, Show, Eq, Functor, Foldable, Traversable) ------------------------------------------------------------------------ -- Conversion@@ -130,15 +139,16 @@ failConversion = Left untangleParameterDeclaration- :: P.ParameterDeclaration -> Either UntangleErr ParameterDeclaration+ :: P.ParameterDeclaration i -> Either UntangleErr (ParameterDeclaration i) untangleParameterDeclaration P.ParameterDeclaration{..} = do (specs, tySpec) <- untangleDeclarationSpecifiers parameterDeclarationSpecifiers let baseTy = TypeSpecifier specs tySpec (mbS, ty) <- case parameterDeclarationDeclarator of- Left decltor -> do+ P.IsDeclarator decltor -> do (s, ty) <- untangleDeclarator baseTy decltor return (Just s, ty)- Right decltor -> (Nothing, ) <$> untangleAbstractDeclarator baseTy decltor+ P.IsAbstractDeclarator decltor ->+ (Nothing, ) <$> untangleAbstractDeclarator baseTy decltor return $ ParameterDeclaration mbS ty untangleDeclarationSpecifiers@@ -220,14 +230,14 @@ return (Specifiers pStorage pTyQuals pFunSpecs, tySpec) untangleDeclarator- :: Type -> P.Declarator -> Either UntangleErr (P.Identifier, Type)+ :: forall i. Type i -> P.Declarator i -> Either UntangleErr (i, Type i) untangleDeclarator ty0 (P.Declarator ptrs0 directDecltor) = go ty0 ptrs0 where- go :: Type -> [P.Pointer] -> Either UntangleErr (P.Identifier, Type)+ go :: Type i -> [P.Pointer] -> Either UntangleErr (i, Type i) go ty [] = goDirect ty directDecltor go ty (P.Pointer quals : ptrs) = go (Ptr quals ty) ptrs - goDirect :: Type -> P.DirectDeclarator -> Either UntangleErr (P.Identifier, Type)+ goDirect :: Type i -> P.DirectDeclarator i -> Either UntangleErr (i, Type i) goDirect ty direct0 = case direct0 of P.DeclaratorRoot s -> return (s, ty) P.ArrayOrProto direct (P.Array arrayType) ->@@ -239,17 +249,17 @@ untangleDeclarator ty decltor untangleAbstractDeclarator- :: Type -> P.AbstractDeclarator -> Either UntangleErr Type+ :: forall i. Type i -> P.AbstractDeclarator i -> Either UntangleErr (Type i) untangleAbstractDeclarator ty0 (P.AbstractDeclarator ptrs0 mbDirectDecltor) = go ty0 ptrs0 where- go :: Type -> [P.Pointer] -> Either UntangleErr Type+ go :: Type i -> [P.Pointer] -> Either UntangleErr (Type i) go ty [] = case mbDirectDecltor of Nothing -> return ty Just directDecltor -> goDirect ty directDecltor go ty (P.Pointer quals : ptrs) = go (Ptr quals ty) ptrs - goDirect :: Type -> P.DirectAbstractDeclarator -> Either UntangleErr Type+ goDirect :: Type i -> P.DirectAbstractDeclarator i -> Either UntangleErr (Type i) goDirect ty direct0 = case direct0 of P.ArrayOrProtoThere direct (P.Array arrayType) -> goDirect (Array arrayType ty) direct@@ -267,15 +277,16 @@ ------------------------------------------------------------------------ -- Tangling -tangleParameterDeclaration :: ParameterDeclaration -> P.ParameterDeclaration+tangleParameterDeclaration+ :: forall i. ParameterDeclaration i -> P.ParameterDeclaration i tangleParameterDeclaration (ParameterDeclaration mbId ty00) = uncurry P.ParameterDeclaration $ case mbId of- Nothing -> second Right $ goAbstractDirect ty00 Nothing- Just id' -> second Left $ goConcreteDirect ty00 $ P.DeclaratorRoot id'+ Nothing -> second P.IsAbstractDeclarator $ goAbstractDirect ty00 Nothing+ Just id' -> second P.IsDeclarator $ goConcreteDirect ty00 $ P.DeclaratorRoot id' where goAbstractDirect- :: Type -> Maybe P.DirectAbstractDeclarator- -> ([P.DeclarationSpecifier], P.AbstractDeclarator)+ :: Type i -> Maybe (P.DirectAbstractDeclarator i)+ -> ([P.DeclarationSpecifier], P.AbstractDeclarator i) goAbstractDirect ty0 mbDirect = case ty0 of TypeSpecifier specifiers tySpec -> let declSpecs = tangleTypeSpecifier specifiers tySpec@@ -298,8 +309,8 @@ goAbstractDirect ty $ Just $ P.ArrayOrProtoThere decltor proto goAbstract- :: Type -> [P.Pointer] -> Maybe P.DirectAbstractDeclarator- -> ([P.DeclarationSpecifier], P.AbstractDeclarator)+ :: Type i -> [P.Pointer] -> Maybe (P.DirectAbstractDeclarator i)+ -> ([P.DeclarationSpecifier], P.AbstractDeclarator i) goAbstract ty0 ptrs mbDirect = case ty0 of TypeSpecifier specifiers tySpec -> let declSpecs = tangleTypeSpecifier specifiers tySpec@@ -314,8 +325,8 @@ P.AbstractDeclarator ptrs mbDirect goConcreteDirect- :: Type -> P.DirectDeclarator- -> ([P.DeclarationSpecifier], P.Declarator)+ :: Type i -> P.DirectDeclarator i+ -> ([P.DeclarationSpecifier], P.Declarator i) goConcreteDirect ty0 direct = case ty0 of TypeSpecifier specifiers tySpec -> let declSpecs = tangleTypeSpecifier specifiers tySpec@@ -329,8 +340,8 @@ P.Proto $ map tangleParameterDeclaration params goConcrete- :: Type -> [P.Pointer] -> P.DirectDeclarator- -> ([P.DeclarationSpecifier], P.Declarator)+ :: Type i -> [P.Pointer] -> P.DirectDeclarator i+ -> ([P.DeclarationSpecifier], P.Declarator i) goConcrete ty0 ptrs direct = case ty0 of TypeSpecifier specifiers tySpec -> let declSpecs = tangleTypeSpecifier specifiers tySpec@@ -371,14 +382,14 @@ ------------------------------------------------------------------------ -- To english -describeParameterDeclaration :: ParameterDeclaration -> PP.Doc+describeParameterDeclaration :: PP.Pretty i => ParameterDeclaration i -> PP.Doc describeParameterDeclaration (ParameterDeclaration mbId ty) = let idDoc = case mbId of Nothing -> "" Just id' -> PP.pretty id' <+> "is a " in idDoc <> describeType ty -describeType :: Type -> PP.Doc+describeType :: PP.Pretty i => Type i -> PP.Doc describeType ty0 = case ty0 of TypeSpecifier specs tySpec -> engSpecs specs <> PP.pretty tySpec Ptr quals ty -> engQuals quals <> "ptr to" <+> describeType ty@@ -412,25 +423,29 @@ -- Convenient parsing untangleParameterDeclaration'- :: P.CParser m => P.ParameterDeclaration -> m ParameterDeclaration+ :: (P.CParser i m, PP.Pretty i)+ => P.ParameterDeclaration i -> m (ParameterDeclaration i) untangleParameterDeclaration' pDecl = case untangleParameterDeclaration pDecl of Left err -> fail $ pretty80 $ "Error while parsing declaration:" </> PP.pretty err </> PP.pretty pDecl Right x -> return x -parseParameterDeclaration :: P.CParser m => m ParameterDeclaration+parseParameterDeclaration+ :: (P.CParser i m, PP.Pretty i) => m (ParameterDeclaration i) parseParameterDeclaration = untangleParameterDeclaration' =<< P.parameter_declaration -parseParameterList :: P.CParser m => m [ParameterDeclaration]+parseParameterList+ :: (P.CParser i m, PP.Pretty i)+ => m [ParameterDeclaration i] parseParameterList = mapM untangleParameterDeclaration' =<< P.parameter_list -parseIdentifier :: P.CParser m => m P.Identifier+parseIdentifier :: P.CParser i m => m i parseIdentifier = P.identifier_no_lex -parseType :: P.CParser m => m Type+parseType :: (P.CParser i m, PP.Pretty i) => m (Type i) parseType = parameterDeclarationType <$> parseParameterDeclaration ------------------------------------------------------------------------@@ -466,10 +481,10 @@ NoDataTypes specs -> "No data types in " </> PP.prettyList specs -instance PP.Pretty ParameterDeclaration where+instance PP.Pretty i => PP.Pretty (ParameterDeclaration i) where pretty = PP.pretty . tangleParameterDeclaration -instance PP.Pretty Type where+instance PP.Pretty i => PP.Pretty (Type i) where pretty ty = PP.pretty $ tangleParameterDeclaration $ ParameterDeclaration Nothing ty
src/Language/C/Types/Parse.hs view
@@ -1,7 +1,11 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}@@ -24,16 +28,23 @@ -- @'parameter_declaration'@. module Language.C.Types.Parse- ( -- * Parser type- CParser- , IsTypeName+ ( -- * Parser configuration+ TypeNames+ , CParserContext(..)+ -- ** Default configuration+ , CIdentifier+ , unCIdentifier+ , cIdentifierFromString+ , cCParserContext++ -- * Parser type+ , CParser , runCParser , quickCParser , quickCParser_ -- * Types and parsing- , Identifier(..)- , identifier+ -- , identifier , identifier_no_lex , DeclarationSpecifier(..) , declaration_specifiers@@ -56,6 +67,7 @@ , Pointer(..) , pointer , ParameterDeclaration(..)+ , DeclaratorOrAbstractDeclarator(..) , parameter_declaration , parameter_list , AbstractDeclarator(..)@@ -67,18 +79,24 @@ -- $yacc -- * Testing utilities+ , cIdentStart+ , cIdentLetter+ , cReservedWords , ParameterDeclarationWithTypeNames(..)+ , arbitraryParameterDeclarationWithTypeNames ) where import Control.Applicative import Control.Monad (msum, void, MonadPlus, unless, when)-import Control.Monad.Reader (MonadReader, ask, runReaderT, ReaderT)+import Control.Monad.Reader (MonadReader, runReaderT, ReaderT, asks, ask)+import Data.Foldable (Foldable) import Data.Functor.Identity (Identity) import qualified Data.HashSet as HashSet+import Data.Hashable (Hashable) import Data.Maybe (mapMaybe) import Data.Monoid ((<>))-import qualified Data.Set as Set import Data.String (IsString(..))+import Data.Traversable (Traversable) import Data.Typeable (Typeable) import qualified Test.QuickCheck as QC import qualified Text.Parsec as Parsec@@ -91,73 +109,115 @@ import qualified Text.PrettyPrint.ANSI.Leijen as PP --------------------------------------------------------------------------- Parser+-- Config --- | Function used to determine whether an 'C.Id' is a type name.-type IsTypeName = Identifier -> Bool+-- | A collection of named types (typedefs)+type TypeNames = HashSet.HashSet CIdentifier +data CParserContext i = CParserContext+ { cpcIdentName :: String+ , cpcTypeNames :: TypeNames+ -- ^ Function used to determine whether an identifier is a type name.+ , cpcParseIdent :: forall m. CParser i m => m i+ -- ^ Parses an identifier, *without consuming whitespace afterwards*.+ , cpcIdentToString :: i -> String+ }++-- | A type for C identifiers.+newtype CIdentifier = CIdentifier {unCIdentifier :: String}+ deriving (Typeable, Eq, Ord, Show, Hashable)++cIdentifierFromString :: String -> Either String CIdentifier+cIdentifierFromString s =+ -- Note: it's important not to use 'cidentifier_raw' here, otherwise+ -- we go in a loop:+ --+ -- @+ -- cIdentifierFromString => fromString => cIdentifierFromString => ...+ -- @+ case Parsec.parse (identNoLex cIdentStyle <* eof) "cIdentifierFromString" s of+ Left err -> Left $ show err+ Right x -> Right $ CIdentifier x++instance IsString CIdentifier where+ fromString s =+ case cIdentifierFromString s of+ Left err -> error $ "CIdentifier fromString: invalid string " ++ show s ++ "\n" ++ err+ Right x -> x++cCParserContext :: TypeNames -> CParserContext CIdentifier+cCParserContext typeNames = CParserContext+ { cpcTypeNames = typeNames+ , cpcParseIdent = cidentifier_no_lex+ , cpcIdentToString = unCIdentifier+ , cpcIdentName = "C identifier"+ }++------------------------------------------------------------------------+-- Parser+ -- | All the parsing is done using the type classes provided by the -- @parsers@ package. You can use the parsing routines with any of the parsers -- that implement the classes, such as @parsec@ or @trifecta@. ----- The 'MonadReader' with 'IsTypeName' is required for parsing C, see--- <http://en.wikipedia.org/wiki/The_lexer_hack>.-type CParser m = (Monad m, Functor m, Applicative m, MonadPlus m, Parsing m, CharParsing m, TokenParsing m, LookAheadParsing m, MonadReader IsTypeName m)+-- We parametrize the parsing by the type of the variable identifiers,+-- @i@. We do so because we use this parser to implement anti-quoters+-- referring to Haskell variables, and thus we need to parse Haskell+-- identifiers in certain positions.+type CParser i m =+ ( Monad m+ , Functor m+ , Applicative m+ , MonadPlus m+ , Parsing m+ , CharParsing m+ , TokenParsing m+ , LookAheadParsing m+ , MonadReader (CParserContext i) m+ , Hashable i+ ) -- | Runs a @'CParser'@ using @parsec@. runCParser :: Parsec.Stream s Identity Char- => IsTypeName- -- ^ Function determining if an identifier is a type name.+ => CParserContext i -> String -- ^ Source name. -> s -- ^ String to parse.- -> (ReaderT IsTypeName (Parsec.Parsec s ()) a)- -- ^ Parser. Anything with type @forall m. CParser m => m a@ is a+ -> (ReaderT (CParserContext i) (Parsec.Parsec s ()) a)+ -- ^ Parser. Anything with type @forall m. CParser i m => m a@ is a -- valid argument. -> Either Parsec.ParseError a-runCParser isTypeName fn s p = Parsec.parse (runReaderT p isTypeName) fn s+runCParser typeNames fn s p = Parsec.parse (runReaderT p typeNames) fn s -- | Useful for quick testing. Uses @\"quickCParser\"@ as source name, and throws -- an 'error' if parsing fails. quickCParser- :: IsTypeName- -- ^ Function determining if an identifier is a type name.+ :: CParserContext i -> String -- ^ String to parse.- -> (ReaderT IsTypeName (Parsec.Parsec String ()) a)- -- ^ Parser. Anything with type @forall m. CParser m => m a@ is a+ -> (ReaderT (CParserContext i) (Parsec.Parsec String ()) a)+ -- ^ Parser. Anything with type @forall m. CParser i m => m a@ is a -- valid argument. -> a-quickCParser isTypeName s p = case runCParser isTypeName "quickCParser" s p of+quickCParser typeNames s p = case runCParser typeNames "quickCParser" s p of Left err -> error $ "quickCParser: " ++ show err Right x -> x --- | Like 'quickCParser', but uses @'const' 'False'@ as 'IsTypeName'.+-- | Like 'quickCParser', but uses @'cCParserContext' ('const' 'False')@ as+-- 'CParserContext'. quickCParser_ :: String -- ^ String to parse.- -> (ReaderT IsTypeName (Parsec.Parsec String ()) a)- -- ^ Parser. Anything with type @forall m. CParser m => m a@ is a+ -> (ReaderT (CParserContext CIdentifier) (Parsec.Parsec String ()) a)+ -- ^ Parser. Anything with type @forall m. CParser i m => m a@ is a -- valid argument. -> a-quickCParser_ = quickCParser (const False)--newtype Identifier = Identifier {unIdentifier :: String}- deriving (Typeable, Eq, Ord, Show)--instance IsString Identifier where- fromString s =- case runCParser (const False) "fromString" s (identifier_no_lex <* eof) of- Left _err -> error $ "Identifier fromString: invalid string " ++ show s- Right x -> x--identLetter :: CParser m => m Char-identLetter = oneOf $ ['a'..'z'] ++ ['A'..'Z'] ++ ['_']+quickCParser_ = quickCParser (cCParserContext HashSet.empty) -reservedWords :: HashSet.HashSet String-reservedWords = HashSet.fromList+cReservedWords :: HashSet.HashSet String+cReservedWords = HashSet.fromList [ "auto", "else", "long", "switch" , "break", "enum", "register", "typedef" , "case", "extern", "return", "union"@@ -168,12 +228,18 @@ , "do", "int", "struct", "double" ] -identStyle :: CParser m => IdentifierStyle m-identStyle = IdentifierStyle+cIdentStart :: [Char]+cIdentStart = ['a'..'z'] ++ ['A'..'Z'] ++ ['_']++cIdentLetter :: [Char]+cIdentLetter = ['a'..'z'] ++ ['A'..'Z'] ++ ['_'] ++ ['0'..'9']++cIdentStyle :: (TokenParsing m, Monad m) => IdentifierStyle m+cIdentStyle = IdentifierStyle { _styleName = "C identifier"- , _styleStart = identLetter- , _styleLetter = identLetter <|> digit- , _styleReserved = reservedWords+ , _styleStart = oneOf cIdentStart+ , _styleLetter = oneOf cIdentLetter+ , _styleReserved = cReservedWords , _styleHighlight = Highlight.Identifier , _styleReservedHighlight = Highlight.ReservedIdentifier }@@ -185,7 +251,7 @@ | FunctionSpecifier FunctionSpecifier deriving (Typeable, Eq, Show) -declaration_specifiers :: forall m. CParser m => m [DeclarationSpecifier]+declaration_specifiers :: CParser i m => m [DeclarationSpecifier] declaration_specifiers = many1 $ msum [ StorageClassSpecifier <$> storage_class_specifier , TypeSpecifier <$> type_specifier@@ -201,13 +267,13 @@ | REGISTER deriving (Typeable, Eq, Show) -storage_class_specifier :: CParser m => m StorageClassSpecifier+storage_class_specifier :: CParser i m => m StorageClassSpecifier storage_class_specifier = msum- [ TYPEDEF <$ reserve identStyle "typedef"- , EXTERN <$ reserve identStyle "extern"- , STATIC <$ reserve identStyle "static"- , AUTO <$ reserve identStyle "auto"- , REGISTER <$ reserve identStyle "register"+ [ TYPEDEF <$ reserve cIdentStyle "typedef"+ , EXTERN <$ reserve cIdentStyle "extern"+ , STATIC <$ reserve cIdentStyle "static"+ , AUTO <$ reserve cIdentStyle "auto"+ , REGISTER <$ reserve cIdentStyle "register" ] data TypeSpecifier@@ -220,101 +286,127 @@ | DOUBLE | SIGNED | UNSIGNED- | Struct Identifier- | Enum Identifier- | TypeName Identifier+ | Struct CIdentifier+ | Enum CIdentifier+ | TypeName CIdentifier deriving (Typeable, Eq, Show) -type_specifier :: CParser m => m TypeSpecifier+type_specifier :: CParser i m => m TypeSpecifier type_specifier = msum- [ VOID <$ reserve identStyle "void"- , CHAR <$ reserve identStyle "char"- , SHORT <$ reserve identStyle "short"- , INT <$ reserve identStyle "int"- , LONG <$ reserve identStyle "long"- , FLOAT <$ reserve identStyle "float"- , DOUBLE <$ reserve identStyle "double"- , SIGNED <$ reserve identStyle "signed"- , UNSIGNED <$ reserve identStyle "unsigned"- , Struct <$> (reserve identStyle "struct" >> identifier)- , Enum <$> (reserve identStyle "enum" >> identifier)+ [ VOID <$ reserve cIdentStyle "void"+ , CHAR <$ reserve cIdentStyle "char"+ , SHORT <$ reserve cIdentStyle "short"+ , INT <$ reserve cIdentStyle "int"+ , LONG <$ reserve cIdentStyle "long"+ , FLOAT <$ reserve cIdentStyle "float"+ , DOUBLE <$ reserve cIdentStyle "double"+ , SIGNED <$ reserve cIdentStyle "signed"+ , UNSIGNED <$ reserve cIdentStyle "unsigned"+ , Struct <$> (reserve cIdentStyle "struct" >> cidentifier)+ , Enum <$> (reserve cIdentStyle "enum" >> cidentifier) , TypeName <$> type_name ] -identifier :: CParser m => m Identifier-identifier =- try (do s <- ident identStyle- isTypeName <- ask- when (isTypeName s) $- fail "expecting identifier, got type name"- return s)- <?> "identifier"+identifier :: CParser i m => m i+identifier = token identifier_no_lex -type_name :: CParser m => m Identifier-type_name =- try (do s <- ident identStyle- isTypeName <- ask- unless (isTypeName s) $- fail "expecting type name, got identifier"- return s)- <?> "type name"+isTypeName :: TypeNames -> String -> Bool+isTypeName typeNames id_ =+ case cIdentifierFromString id_ of+ -- If it's not a valid C identifier, then it's definitely not a C type name.+ Left _err -> False+ Right s -> HashSet.member s typeNames +identifier_no_lex :: CParser i m => m i+identifier_no_lex = try $ do+ ctx <- ask+ id_ <- cpcParseIdent ctx <?> cpcIdentName ctx+ when (isTypeName (cpcTypeNames ctx) (cpcIdentToString ctx id_)) $+ unexpected $ "type name " ++ cpcIdentToString ctx id_+ return id_++-- | Same as 'cidentifier_no_lex', but does not check that the+-- identifier is not a type name.+cidentifier_raw :: (TokenParsing m, Monad m) => m CIdentifier+cidentifier_raw = identNoLex cIdentStyle++-- | This parser parses a 'CIdentifier' and nothing else -- it does not consume+-- trailing spaces and the like.+cidentifier_no_lex :: CParser i m => m CIdentifier+cidentifier_no_lex = try $ do+ s <- cidentifier_raw+ typeNames <- asks cpcTypeNames+ when (HashSet.member s typeNames) $+ unexpected $ "type name " ++ unCIdentifier s+ return s++cidentifier :: CParser i m => m CIdentifier+cidentifier = token cidentifier_no_lex++type_name :: CParser i m => m CIdentifier+type_name = try $ do+ s <- ident cIdentStyle <?> "type name"+ typeNames <- asks cpcTypeNames+ unless (HashSet.member s typeNames) $+ unexpected $ "identifier " ++ unCIdentifier s+ return s+ data TypeQualifier = CONST | RESTRICT | VOLATILE deriving (Typeable, Eq, Show) -type_qualifier :: CParser m => m TypeQualifier+type_qualifier :: CParser i m => m TypeQualifier type_qualifier = msum- [ CONST <$ reserve identStyle "const"- , RESTRICT <$ reserve identStyle "restrict"- , VOLATILE <$ reserve identStyle "volatile"+ [ CONST <$ reserve cIdentStyle "const"+ , RESTRICT <$ reserve cIdentStyle "restrict"+ , VOLATILE <$ reserve cIdentStyle "volatile" ] data FunctionSpecifier = INLINE deriving (Typeable, Eq, Show) -function_specifier :: CParser m => m FunctionSpecifier+function_specifier :: CParser i m => m FunctionSpecifier function_specifier = msum- [ INLINE <$ reserve identStyle "inline"+ [ INLINE <$ reserve cIdentStyle "inline" ] -data Declarator = Declarator+data Declarator i = Declarator { declaratorPointers :: [Pointer]- , declaratorDirect :: DirectDeclarator- } deriving (Typeable, Eq, Show)+ , declaratorDirect :: (DirectDeclarator i)+ } deriving (Typeable, Eq, Show, Functor, Foldable, Traversable) -declarator :: CParser m => m Declarator+declarator :: CParser i m => m (Declarator i) declarator = (Declarator <$> many pointer <*> direct_declarator) <?> "declarator" -data DirectDeclarator- = DeclaratorRoot Identifier- | ArrayOrProto DirectDeclarator ArrayOrProto- | DeclaratorParens Declarator- deriving (Typeable, Eq, Show)+data DirectDeclarator i+ = DeclaratorRoot i+ | ArrayOrProto (DirectDeclarator i) (ArrayOrProto i)+ | DeclaratorParens (Declarator i)+ deriving (Typeable, Eq, Show, Functor, Foldable, Traversable) -data ArrayOrProto- = Array ArrayType- | Proto [ParameterDeclaration] -- We don't include old prototypes.- deriving (Typeable, Eq, Show)+data ArrayOrProto i+ = Array (ArrayType i)+ | Proto [ParameterDeclaration i] -- We don't include old prototypes.+ deriving (Eq, Show, Typeable, Functor, Foldable, Traversable) -array_or_proto :: CParser m => m ArrayOrProto+array_or_proto :: CParser i m => m (ArrayOrProto i) array_or_proto = msum [ Array <$> brackets array_type , Proto <$> parens parameter_list ] -- TODO handle more stuff in array brackets-data ArrayType+data ArrayType i = VariablySized | Unsized | SizedByInteger Integer- | SizedByIdentifier Identifier- deriving (Typeable, Eq, Show)+ | SizedByIdentifier i+ deriving (Typeable, Eq, Show, Functor, Foldable, Traversable) -array_type :: CParser m => m ArrayType+array_type :: CParser i m => m (ArrayType i) array_type = msum [ VariablySized <$ symbolic '*' , SizedByInteger <$> natural@@ -322,50 +414,55 @@ , return Unsized ] -direct_declarator :: CParser m => m DirectDeclarator-direct_declarator =- (do ddecltor <- msum- [ DeclaratorRoot <$> identifier- , DeclaratorParens <$> parens declarator- ]- aops <- many array_or_proto- return $ foldl ArrayOrProto ddecltor aops)+direct_declarator :: CParser i m => m (DirectDeclarator i)+direct_declarator = do+ ddecltor <- msum+ [ DeclaratorRoot <$> identifier+ , DeclaratorParens <$> parens declarator+ ]+ aops <- many array_or_proto+ return $ foldl ArrayOrProto ddecltor aops data Pointer = Pointer [TypeQualifier] deriving (Typeable, Eq, Show) -pointer :: CParser m => m Pointer+pointer :: CParser i m => m Pointer pointer = do void $ symbolic '*' Pointer <$> many type_qualifier -parameter_list :: CParser m => m [ParameterDeclaration]+parameter_list :: CParser i m => m [ParameterDeclaration i] parameter_list = sepBy parameter_declaration $ symbolic ',' -data ParameterDeclaration = ParameterDeclaration+data ParameterDeclaration i = ParameterDeclaration { parameterDeclarationSpecifiers :: [DeclarationSpecifier]- , parameterDeclarationDeclarator :: Either Declarator AbstractDeclarator- } deriving (Typeable, Eq, Show)+ , parameterDeclarationDeclarator :: DeclaratorOrAbstractDeclarator i+ } deriving (Eq, Show, Typeable, Functor, Foldable, Traversable) -parameter_declaration :: CParser m => m ParameterDeclaration+data DeclaratorOrAbstractDeclarator i+ = IsDeclarator (Declarator i)+ | IsAbstractDeclarator (AbstractDeclarator i)+ deriving (Eq, Show, Typeable, Functor, Foldable, Traversable)++parameter_declaration :: CParser i m => m (ParameterDeclaration i) parameter_declaration = ParameterDeclaration <$> declaration_specifiers <*> mbabstract where mbabstract =- Left <$> try declarator <|>- Right <$> try abstract_declarator <|>- return (Right (AbstractDeclarator [] Nothing))+ IsDeclarator <$> try declarator <|>+ IsAbstractDeclarator <$> try abstract_declarator <|>+ return (IsAbstractDeclarator (AbstractDeclarator [] Nothing)) -data AbstractDeclarator = AbstractDeclarator+data AbstractDeclarator i = AbstractDeclarator { abstractDeclaratorPointers :: [Pointer]- , abstractDeclaratorDirect :: Maybe DirectAbstractDeclarator- } deriving (Typeable, Eq, Show)+ , abstractDeclaratorDirect :: Maybe (DirectAbstractDeclarator i)+ } deriving (Typeable, Eq, Show, Functor, Foldable, Traversable) -abstract_declarator :: CParser m => m AbstractDeclarator+abstract_declarator :: CParser i m => m (AbstractDeclarator i) abstract_declarator = do ptrs <- many pointer -- If there are no pointers, there must be an abstract declarator.@@ -374,37 +471,26 @@ else (Just <$> try direct_abstract_declarator) <|> return Nothing AbstractDeclarator ptrs <$> p -data DirectAbstractDeclarator- = ArrayOrProtoHere ArrayOrProto- | ArrayOrProtoThere DirectAbstractDeclarator ArrayOrProto- | AbstractDeclaratorParens AbstractDeclarator- deriving (Typeable, Eq, Show)--direct_abstract_declarator :: CParser m => m DirectAbstractDeclarator-direct_abstract_declarator =- (do ddecltor <- msum- [ try (ArrayOrProtoHere <$> array_or_proto)- , AbstractDeclaratorParens <$> parens abstract_declarator- ] <?> "array, prototype, or parenthesised abstract declarator"- aops <- many array_or_proto- return $ foldl ArrayOrProtoThere ddecltor aops)+data DirectAbstractDeclarator i+ = ArrayOrProtoHere (ArrayOrProto i)+ | ArrayOrProtoThere (DirectAbstractDeclarator i) (ArrayOrProto i)+ | AbstractDeclaratorParens (AbstractDeclarator i)+ deriving (Typeable, Eq, Show, Functor, Foldable, Traversable) --- | This parser parses an 'Id' and nothing else -- it does not consume--- trailing spaces and the like.-identifier_no_lex :: CParser m => m Identifier-identifier_no_lex =- try (do s <- Identifier <$> ((:) <$> identLetter <*> many (identLetter <|> digit))- isTypeName <- ask- when (isTypeName s) $- fail "expecting identifier, got type name"- return s)- <?> "identifier"+direct_abstract_declarator :: CParser i m => m (DirectAbstractDeclarator i)+direct_abstract_declarator = do+ ddecltor <- msum+ [ try (ArrayOrProtoHere <$> array_or_proto)+ , AbstractDeclaratorParens <$> parens abstract_declarator+ ] <?> "array, prototype, or parenthesised abstract declarator"+ aops <- many array_or_proto+ return $ foldl ArrayOrProtoThere ddecltor aops ------------------------------------------------------------------------ -- Pretty printing -instance Pretty Identifier where- pretty = PP.text . unIdentifier+instance Pretty CIdentifier where+ pretty = PP.text . unCIdentifier instance Pretty DeclarationSpecifier where pretty dspec = case dspec of@@ -446,7 +532,7 @@ pretty funSpec = case funSpec of INLINE -> "inline" -instance Pretty Declarator where+instance Pretty i => Pretty (Declarator i) where pretty (Declarator ptrs ddecltor) = case ptrs of [] -> pretty ddecltor _:_ -> prettyPointers ptrs <+> pretty ddecltor@@ -458,13 +544,13 @@ instance Pretty Pointer where pretty (Pointer tyQual) = "*" <> hsep (map pretty tyQual) -instance Pretty DirectDeclarator where+instance Pretty i => Pretty (DirectDeclarator i) where pretty decltor = case decltor of DeclaratorRoot x -> pretty x DeclaratorParens x -> "(" <> pretty x <> ")" ArrayOrProto ddecltor aorp -> pretty ddecltor <> pretty aorp -instance Pretty ArrayOrProto where+instance Pretty i => Pretty (ArrayOrProto i) where pretty aorp = case aorp of Array x -> "[" <> pretty x <> "]" Proto x -> "(" <> prettyParams x <> ")"@@ -475,29 +561,29 @@ [x] -> pretty x x : xs'@(_:_) -> pretty x <> "," <+> prettyParams xs' -instance Pretty ArrayType where+instance Pretty i => Pretty (ArrayType i) where pretty at = case at of VariablySized -> "*" SizedByInteger n -> pretty n SizedByIdentifier s -> pretty s Unsized -> "" -instance Pretty ParameterDeclaration where+instance Pretty i => Pretty (ParameterDeclaration i) where pretty (ParameterDeclaration declSpecs decltor) = case declSpecs of [] -> decltorDoc _:_ -> hsep (map pretty declSpecs) <+> decltorDoc where decltorDoc = case decltor of- Left x -> pretty x- Right x -> pretty x+ IsDeclarator x -> pretty x+ IsAbstractDeclarator x -> pretty x -instance Pretty AbstractDeclarator where+instance Pretty i => Pretty (AbstractDeclarator i) where pretty (AbstractDeclarator ptrs mbDecltor) = case (ptrs, mbDecltor) of (_, Nothing) -> prettyPointers ptrs ([], Just x) -> pretty x (_:_, Just x) -> prettyPointers ptrs <+> pretty x -instance Pretty DirectAbstractDeclarator where+instance Pretty i => Pretty (DirectAbstractDeclarator i) where pretty ddecltor = case ddecltor of AbstractDeclaratorParens x -> "(" <> pretty x <> ")" ArrayOrProtoHere aop -> pretty aop@@ -522,30 +608,37 @@ halveSize :: QC.Gen a -> QC.Gen a halveSize m = QC.sized $ \n -> QC.resize (n `div` 2) m -arbitraryIdentifier :: QC.Gen Identifier-arbitraryIdentifier = do- s <- ((:) <$> QC.elements letters <*> QC.listOf (QC.elements (letters ++ digits)))- if HashSet.member s reservedWords- then arbitraryIdentifier- else return $ Identifier s- where- letters = ['a'..'z'] ++ ['A'..'Z'] ++ ['_']- digits = ['0'..'9']+instance QC.Arbitrary CIdentifier where+ arbitrary = do+ s <- ((:) <$> QC.elements cIdentStart <*> QC.listOf (QC.elements cIdentLetter))+ if HashSet.member s cReservedWords+ then QC.arbitrary+ else return $ CIdentifier s -- | Type used to generate an 'QC.Arbitrary' 'ParameterDeclaration' with -- arbitrary allowed type names.-data ParameterDeclarationWithTypeNames = ParameterDeclarationWithTypeNames- { pdwtnTypeNames :: Set.Set Identifier- , pdwtnParameterDeclaration :: ParameterDeclaration+data ParameterDeclarationWithTypeNames i = ParameterDeclarationWithTypeNames+ { pdwtnTypeNames :: HashSet.HashSet CIdentifier+ , pdwtnParameterDeclaration :: (ParameterDeclaration i) } deriving (Typeable, Eq, Show) -instance QC.Arbitrary ParameterDeclarationWithTypeNames where- arbitrary = do- names <- Set.fromList <$> QC.listOf arbitraryIdentifier- decl <- arbitraryParameterDeclarationFrom names+data (QC.Arbitrary i) => ArbitraryContext i = ArbitraryContext+ { acTypeNames :: TypeNames+ , acIdentToString :: i -> String+ }++arbitraryParameterDeclarationWithTypeNames+ :: (QC.Arbitrary i, Hashable i)+ => (i -> String)+ -> QC.Gen (ParameterDeclarationWithTypeNames i)+arbitraryParameterDeclarationWithTypeNames identToString = do+ names <- HashSet.fromList <$> QC.listOf QC.arbitrary+ let ctx = ArbitraryContext names identToString+ decl <- arbitraryParameterDeclarationFrom ctx return $ ParameterDeclarationWithTypeNames names decl -arbitraryDeclarationSpecifierFrom :: Set.Set Identifier -> QC.Gen DeclarationSpecifier+arbitraryDeclarationSpecifierFrom+ :: (QC.Arbitrary i, Hashable i) => ArbitraryContext i -> QC.Gen DeclarationSpecifier arbitraryDeclarationSpecifierFrom typeNames = QC.oneof $ [ StorageClassSpecifier <$> QC.arbitrary , TypeQualifier <$> QC.arbitrary@@ -562,8 +655,8 @@ , return REGISTER ] -arbitraryTypeSpecifierFrom :: Set.Set Identifier -> QC.Gen TypeSpecifier-arbitraryTypeSpecifierFrom typeNames = QC.oneof $+arbitraryTypeSpecifierFrom :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen TypeSpecifier+arbitraryTypeSpecifierFrom ctx = QC.oneof $ [ return VOID , return CHAR , return SHORT@@ -573,10 +666,10 @@ , return DOUBLE , return SIGNED , return UNSIGNED- , Struct <$> arbitraryIdentifierFrom typeNames- , Enum <$> arbitraryIdentifierFrom typeNames- ] ++ if Set.null typeNames then []- else [TypeName <$> QC.elements (Set.toList typeNames)]+ , Struct <$> arbitraryCIdentifierFrom ctx+ , Enum <$> arbitraryCIdentifierFrom ctx+ ] ++ if HashSet.null (acTypeNames ctx) then []+ else [TypeName <$> QC.elements (HashSet.toList (acTypeNames ctx))] instance QC.Arbitrary TypeQualifier where arbitrary = QC.oneof@@ -590,18 +683,26 @@ [ return INLINE ] -arbitraryDeclaratorFrom :: Set.Set Identifier -> QC.Gen Declarator+arbitraryDeclaratorFrom+ :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (Declarator i) arbitraryDeclaratorFrom typeNames = halveSize $ Declarator <$> QC.arbitrary <*> arbitraryDirectDeclaratorFrom typeNames -arbitraryIdentifierFrom :: Set.Set Identifier -> QC.Gen Identifier-arbitraryIdentifierFrom typeNames = do- id' <- arbitraryIdentifier- if Set.member id' typeNames- then arbitraryIdentifierFrom typeNames+arbitraryCIdentifierFrom+ :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen CIdentifier+arbitraryCIdentifierFrom ctx =+ arbitraryIdentifierFrom ctx{acIdentToString = unCIdentifier}++arbitraryIdentifierFrom+ :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen i+arbitraryIdentifierFrom ctx = do+ id' <- QC.arbitrary+ if isTypeName (acTypeNames ctx) (acIdentToString ctx id')+ then arbitraryIdentifierFrom ctx else return id' -arbitraryDirectDeclaratorFrom :: Set.Set Identifier -> QC.Gen DirectDeclarator+arbitraryDirectDeclaratorFrom+ :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (DirectDeclarator i) arbitraryDirectDeclaratorFrom typeNames = halveSize $ oneOfSized $ [ Anyhow $ DeclaratorRoot <$> arbitraryIdentifierFrom typeNames , IfPositive $ DeclaratorParens <$> arbitraryDeclaratorFrom typeNames@@ -610,13 +711,14 @@ <*> arbitraryArrayOrProtoFrom typeNames ] -arbitraryArrayOrProtoFrom :: Set.Set Identifier -> QC.Gen ArrayOrProto+arbitraryArrayOrProtoFrom+ :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ArrayOrProto i) arbitraryArrayOrProtoFrom typeNames = halveSize $ oneOfSized $ [ Anyhow $ Array <$> arbitraryArrayTypeFrom typeNames , IfPositive $ Proto <$> QC.listOf (arbitraryParameterDeclarationFrom typeNames) ] -arbitraryArrayTypeFrom :: Set.Set Identifier -> QC.Gen ArrayType+arbitraryArrayTypeFrom :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ArrayType i) arbitraryArrayTypeFrom typeNames = QC.oneof [ return VariablySized , SizedByInteger . QC.getNonNegative <$> QC.arbitrary@@ -627,16 +729,18 @@ instance QC.Arbitrary Pointer where arbitrary = Pointer <$> QC.arbitrary -arbitraryParameterDeclarationFrom :: Set.Set Identifier -> QC.Gen ParameterDeclaration+arbitraryParameterDeclarationFrom+ :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (ParameterDeclaration i) arbitraryParameterDeclarationFrom typeNames = halveSize $ ParameterDeclaration <$> QC.listOf1 (arbitraryDeclarationSpecifierFrom typeNames) <*> QC.oneof- [ Left <$> arbitraryDeclaratorFrom typeNames- , Right <$> arbitraryAbstractDeclaratorFrom typeNames+ [ IsDeclarator <$> arbitraryDeclaratorFrom typeNames+ , IsAbstractDeclarator <$> arbitraryAbstractDeclaratorFrom typeNames ] -arbitraryAbstractDeclaratorFrom :: Set.Set Identifier -> QC.Gen AbstractDeclarator+arbitraryAbstractDeclaratorFrom+ :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (AbstractDeclarator i) arbitraryAbstractDeclaratorFrom typeNames = halveSize $ do ptrs <- QC.arbitrary decl <- if null ptrs@@ -648,7 +752,7 @@ return $ AbstractDeclarator ptrs decl arbitraryDirectAbstractDeclaratorFrom- :: Set.Set Identifier -> QC.Gen DirectAbstractDeclarator+ :: (Hashable i, QC.Arbitrary i) => ArbitraryContext i -> QC.Gen (DirectAbstractDeclarator i) arbitraryDirectAbstractDeclaratorFrom typeNames = halveSize $ oneOfSized $ [ Anyhow $ ArrayOrProtoHere <$> arbitraryArrayOrProtoFrom typeNames , IfPositive $ AbstractDeclaratorParens <$> arbitraryAbstractDeclaratorFrom typeNames@@ -660,7 +764,7 @@ ------------------------------------------------------------------------ -- Utils -many1 :: CParser m => m a -> m [a]+many1 :: CParser i m => m a -> m [a] many1 p = (:) <$> p <*> many p ------------------------------------------------------------------------@@ -806,3 +910,13 @@ -- printf("\n%*s\n%*s\n", column, "^", column, s); -- } -- @++-- Utils+------------------------------------------------------------------------++identNoLex :: (TokenParsing m, Monad m, IsString s) => IdentifierStyle m -> m s+identNoLex s = fmap fromString $ try $ do+ name <- highlight (_styleHighlight s)+ ((:) <$> _styleStart s <*> many (_styleLetter s) <?> _styleName s)+ when (HashSet.member name (_styleReserved s)) $ unexpected $ "reserved " ++ _styleName s ++ " " ++ show name+ return name
test/Language/C/Inline/ContextSpec.hs view
@@ -90,7 +90,7 @@ x `Hspec.shouldBe` y assertParse p s =- case C.runCParser (isTypeName baseTypes) "spec" s (lift spaces *> p <* lift eof) of+ case C.runCParser (C.cCParserContext (typeNamesFromTypesTable baseTypes)) "spec" s (lift spaces *> p <* lift eof) of Left err -> error $ "Parse error (assertParse): " ++ show err Right x -> x
test/Language/C/Inline/ParseSpec.hs view
@@ -9,23 +9,25 @@ {-# LANGUAGE OverloadedStrings #-} module Language.C.Inline.ParseSpec (spec) where +import Control.Exception (evaluate)+import Control.Monad (void) import Control.Monad.Trans.Class (lift)+import qualified Data.HashSet as HashSet+import Data.Monoid ((<>)) import qualified Test.Hspec as Hspec import Text.Parser.Char import Text.Parser.Combinators import Text.RawString.QQ (r)-import Control.Monad (void)-import Control.Exception (evaluate)-import Data.Monoid ((<>)) import Text.Regex.Posix ((=~)) #if __GLASGOW_HASKELL__ < 710 import Control.Applicative ((<*), (*>)) #endif -import qualified Language.C.Types as C-import Language.C.Inline.Internal import Language.C.Inline.Context+import Language.C.Inline.HaskellIdentifier+import Language.C.Inline.Internal+import qualified Language.C.Types as C spec :: Hspec.SpecWith () spec = do@@ -51,31 +53,53 @@ retType `Hspec.shouldBe` (cty "double (*)(double)") params `shouldMatchParameters` [] cExp `shouldMatchBody` " &cos "+ Hspec.it "parses Haskell identifier (1)" $ do+ (retType, params, cExp) <- goodParse [r| double { $(double x') } |]+ retType `Hspec.shouldBe` (cty "double")+ params `shouldMatchParameters` [(cty "double", Plain "x'")]+ cExp `shouldMatchBody` " x[a-z0-9_]+ "+ Hspec.it "parses Haskell identifier (2)" $ do+ (retType, params, cExp) <- goodParse [r| double { $(double ä') } |]+ retType `Hspec.shouldBe` (cty "double")+ params `shouldMatchParameters` [(cty "double", Plain "ä'")]+ cExp `shouldMatchBody` " [a-z0-9_]+ "+ Hspec.it "parses Haskell identifier (3)" $ do+ (retType, params, cExp) <- goodParse [r| int { $(int Foo.bar) } |]+ retType `Hspec.shouldBe` (cty "int")+ params `shouldMatchParameters` [(cty "int", Plain "Foo.bar")]+ cExp `shouldMatchBody` " Foobar[a-z0-9_]+ "+ Hspec.it "does not parse Haskell identifier in bad position" $ do+ badParse [r| double (*)(double Foo.bar) { 3.0 } |] where ctx = baseCtx <> funCtx - assertParse p s =- case C.runCParser (const False) "spec" s (lift spaces *> p <* lift eof) of+ assertParse ctxF p s =+ case C.runCParser (ctxF HashSet.empty) "spec" s (lift spaces *> p <* lift eof) of Left err -> error $ "Parse error (assertParse): " ++ show err Right x -> x -- We use show + length to fully evaluate the result -- there -- might be exceptions hiding. TODO get rid of exceptions.- strictParse :: String -> IO (C.Type, [(C.Identifier, C.Type, ParameterType)], String)+ strictParse+ :: String+ -> IO (C.Type C.CIdentifier, [(C.CIdentifier, C.Type C.CIdentifier, ParameterType)], String) strictParse s = do let ParseTypedC retType pars body =- assertParse (parseTypedC (ctxAntiQuoters ctx)) s+ assertParse haskellCParserContext (parseTypedC (ctxAntiQuoters ctx)) s void $ evaluate $ length $ show (retType, pars, body) return (retType, pars, body) goodParse = strictParse badParse s = strictParse s `Hspec.shouldThrow` Hspec.anyException - cty :: String -> C.Type- cty s = C.parameterDeclarationType $ assertParse C.parseParameterDeclaration s+ cty :: String -> C.Type C.CIdentifier+ cty s = C.parameterDeclarationType $+ assertParse C.cCParserContext C.parseParameterDeclaration s shouldMatchParameters- :: [(C.Identifier, C.Type, ParameterType)] -> [(C.Type, ParameterType)] -> Hspec.Expectation+ :: [(C.CIdentifier, C.Type C.CIdentifier, ParameterType)]+ -> [(C.Type C.CIdentifier, ParameterType)]+ -> Hspec.Expectation shouldMatchParameters pars pars' = [(x, y) | (_, x, y) <- pars] `Hspec.shouldMatchList` pars'
test/Language/C/Types/ParseSpec.hs view
@@ -8,7 +8,7 @@ import Control.Applicative import Control.Monad.Trans.Class (lift)-import qualified Data.Set as Set+import Data.Hashable (Hashable) import qualified Test.Hspec as Hspec import qualified Test.QuickCheck as QC import Text.Parser.Char@@ -17,30 +17,42 @@ import Language.C.Types.Parse import qualified Language.C.Types as Types+import Language.C.Inline.HaskellIdentifier import Prelude -- Fix for 7.10 unused warnings. spec :: Hspec.SpecWith () spec = do- Hspec.it "parses everything which is pretty-printable (QuickCheck)" $ do- QC.property $ \(ParameterDeclarationWithTypeNames typeNames ty) ->- isGoodType ty QC.==>- let ty' = assertParse (`Set.member` typeNames) parameter_declaration (prettyOneLine ty)+ Hspec.it "parses everything which is pretty-printable (C)" $ do+ QC.property $ do+ ParameterDeclarationWithTypeNames typeNames ty <-+ arbitraryParameterDeclarationWithTypeNames unCIdentifier+ return $ isGoodType ty QC.==>+ let ty' = assertParse (cCParserContext typeNames) parameter_declaration (prettyOneLine ty) in Types.untangleParameterDeclaration ty == Types.untangleParameterDeclaration ty'+ Hspec.it "parses everything which is pretty-printable (Haskell)" $ do+ QC.property $ do+ ParameterDeclarationWithTypeNames typeNames ty <-+ arbitraryParameterDeclarationWithTypeNames unHaskellIdentifier+ return $ isGoodType ty QC.==>+ let ty' = assertParse (haskellCParserContext typeNames) parameter_declaration (prettyOneLine ty)+ in Types.untangleParameterDeclaration ty == Types.untangleParameterDeclaration ty' ------------------------------------------------------------------------ -- Utils -assertParse :: IsTypeName -> (forall m. CParser m => m a) -> String -> a-assertParse isTypeName p s =- case runCParser isTypeName "spec" s (lift spaces *> p <* lift eof) of+assertParse+ :: (Hashable i)+ => CParserContext i -> (forall m. CParser i m => m a) -> String -> a+assertParse ctx p s =+ case runCParser ctx "spec" s (lift spaces *> p <* lift eof) of Left err -> error $ "Parse error (assertParse): " ++ show err Right x -> x prettyOneLine :: PP.Pretty a => a -> String prettyOneLine x = PP.displayS (PP.renderCompact (PP.pretty x)) "" -isGoodType :: ParameterDeclaration -> Bool+isGoodType :: ParameterDeclaration i -> Bool isGoodType ty = case Types.untangleParameterDeclaration ty of Left _ -> False Right _ -> True
test/tests.c view
@@ -15,7 +15,7 @@ int francescos_add(int x, int y) { int z = x + y; return z; } -int inline_c_0_af51326c4d54f2333cd5e65d63fa1335afd44e7f(int x) {+int inline_c_0_23225c6b2d15328585f210dc2f989269e95d08ee(int x) { return x + 3; } @@ -25,17 +25,17 @@ } -int inline_c_2_16f19661d53c3abae15931d85a5e2829ecb039aa(int x_inline_c_0, int y_inline_c_1) {+int inline_c_2_5fdbbe6da0475522165cd251c48497d38f4710fb(int x_inline_c_0, int y_inline_c_1) { return ( x_inline_c_0 + y_inline_c_1 + 5 ); } -int inline_c_3_40bee96de703884c6b206e411631395b9aef5976(int x_inline_c_0, int y_inline_c_1) {+int inline_c_3_856f16273cbef2af269b645953d316cb9426784c(int x_inline_c_0, int y_inline_c_1) { return ( x_inline_c_0 + 10 + y_inline_c_1 ); } -int inline_c_4_e6943496092d6a4a410b30efda2403f1340ee8cc(int x_inline_c_0, int y_inline_c_1) {+int inline_c_4_f58397f6204cd35d25406cea930cdd76127e7a8d(int x_inline_c_0, int y_inline_c_1) { return ( 7 + x_inline_c_0 + y_inline_c_1 ); } @@ -45,32 +45,32 @@ } -ptrdiff_t inline_c_6_205199db60839b9d17460a63202ca3a0d6589aa2(ptrdiff_t x_inline_c_0) {+ptrdiff_t inline_c_6_4475cd73db749194709e394483ff3e5205688ff8(ptrdiff_t x_inline_c_0) { char a[2]; return &a[1] - &a[0] + x_inline_c_0; } -size_t inline_c_7_5640bf10f132d090b52c2634f9fa93226d58c551() {+size_t inline_c_7_9782c357435fb488c3166bf10e839da13328001e() { return ( sizeof (char) ); } -uintmax_t inline_c_8_da095360497f4bbf3922f50d0b0548c2dd7cbed9() {+uintmax_t inline_c_8_c0df91f70bbf1f85671339d1bdc524414e112cc2() { return ( UINTMAX_MAX ); } -int16_t inline_c_9_23a275cc563910c289d0dbf8e770ede22fe97bbb(int16_t x_inline_c_0) {+int16_t inline_c_9_9e29ba00e56a81c765067e09a3136fa5232d49a0(int16_t x_inline_c_0) { return ( 1 + x_inline_c_0 ); } -uint32_t inline_c_10_02eb7fd8875e35241b9f7b725499139c4289aeab(uint32_t y_inline_c_0) {+uint32_t inline_c_10_08a42fa8f755a36db897898b73bb7aab5b1b58e1(uint32_t y_inline_c_0) { return ( y_inline_c_0 * 7 ); } -int inline_c_11_71dfd9b850f6e2091e021139a58b74df94cd7303(int (* ackermannPtr_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) {+int inline_c_11_4ffe4d055df0966eedc85f08247aa8880402694a(int (* ackermannPtr_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) { return ( ackermannPtr_inline_c_0(x_inline_c_1, y_inline_c_2) ); } @@ -80,27 +80,27 @@ } -int inline_c_13_b58cd0af8a50791fe277023774ffe88ee7e037bd(int (* ackermann__inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) {+int inline_c_13_55555bbb777d25d03fef0a6d6ce9193474a74a35(int (* ackermann__inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) { return ( ackermann__inline_c_0(x_inline_c_1, y_inline_c_2) ); } -int inline_c_14_71dfd9b850f6e2091e021139a58b74df94cd7303(int (* ackermannPtr_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) {+int inline_c_14_4ffe4d055df0966eedc85f08247aa8880402694a(int (* ackermannPtr_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) { return ( ackermannPtr_inline_c_0(x_inline_c_1, y_inline_c_2) ); } -int inline_c_15_8ef64f450bca60833a113574529facc22cb4a0a0(int (* ackermann_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) {+int inline_c_15_b7d965842e65c49fcc08b03f70454988290e61e4(int (* ackermann_inline_c_0)(int , int ), int x_inline_c_1, int y_inline_c_2) { return ( ackermann_inline_c_0(x_inline_c_1, y_inline_c_2) ); } -double inline_c_16_05403b76080812d04e00ce2b31b2068dad1b2342(double (* fun_inline_c_0)(double )) {+double inline_c_16_5dce1654ef6186acdb189a6ce36f0a66660eb346(double (* fun_inline_c_0)(double )) { return ( fun_inline_c_0(3.0) ); } -int inline_c_17_963ff572b13b7aaee0f9f8092a567eb35a8c2088(int n_inline_c_0, int * ptr_inline_c_1) {+int inline_c_17_8d0f093895f51773152915c33b75c7aafd8f4f45(int n_inline_c_0, int * ptr_inline_c_1) { int i; int x = 0;@@ -112,7 +112,7 @@ } -int inline_c_18_e2ee2f14cc17b81ea1e818bb96b23439a1810c23(long vec_inline_c_0, int * vec_inline_c_1) {+int inline_c_18_62ce8aade5e693f134c6a5c9add3523edab1a63e(long vec_inline_c_0, int * vec_inline_c_1) { int i; int x = 0;@@ -124,7 +124,7 @@ } -int inline_c_19_17d13d6f2f87c2401476aaf41e06593689723baf(long bs_inline_c_0, char * bs_inline_c_1) {+int inline_c_19_75f1401fb8545756b6d329a5352a252bf52db946(long bs_inline_c_0, char * bs_inline_c_1) { int i, bits = 0; for (i = 0; i < bs_inline_c_0; i++) {@@ -133,5 +133,20 @@ } return bits; +}+++int inline_c_20_6fa3d382d3ab7f6d57eec7fbfe64e87fbc2a0ca9(int x_27_inline_c_0) {+return ( x_27_inline_c_0 );+}+++int inline_c_21_dbf060cb8fa2b86c6c6838ef9b645ac20f38ba79(int _e4_inline_c_0) {+return ( _e4_inline_c_0 );+}+++int inline_c_22_2421969c444755bea2c6f2060e0921ce7f3d16d7(int PreludemaxBound_2e_inline_c_0) {+return ( PreludemaxBound_2e_inline_c_0 ); }
test/tests.hs view
@@ -2,10 +2,12 @@ {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE OverloadedStrings #-}+import Control.Monad (void) import Data.Monoid ((<>)) import qualified Data.Vector.Storable.Mutable as V import Foreign.C.Types import qualified Language.Haskell.TH as TH+import Prelude import qualified Test.Hspec as Hspec import Text.RawString.QQ (r) @@ -184,4 +186,9 @@ return bits; } |] bits `Hspec.shouldBe` 16-+ Hspec.it "Haskell identifiers" $ do+ let x' = 3+ void $ [C.exp| int { $(int x') } |]+ let ä = 3+ void $ [C.exp| int { $(int ä) } |]+ void $ [C.exp| int { $(int Prelude.maxBound) } |]