diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for c-enum
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Yoshikuni Jujo (c) 2021
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Yoshikuni Jujo nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,49 @@
+# c-enum
+
+foo.h
+
+```c
+#ifndef _FOO_H
+#define _FOO_H
+
+typedef enum { FOO_ERROR = - 1, FOO_ZERO, FOO_ONE, FOO_TWO, FOO_THREE } Foo;
+
+#endif
+```
+
+Foo.hsc
+
+```haskell
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}
+
+module Foo where
+
+import Foreign.C.Enum
+
+#include "foo.h"
+
+enum "Foo" ''#{type Foo} [''Show, ''Read, ''Eq] [
+	("FooError", #{const FOO_ERROR}),
+	("FooZero", #{const FOO_ZERO}),
+	("FooOne", #{const FOO_ONE}),
+	("FooTwo", #{const FOO_TWO}),
+	("FooThree", #{const FOO_THREE}) ]
+```
+
+You get patterns FooError, ..., FooThree.
+And `instance Show Foo` and `instance Read Foo` like the following.
+
+```
+> FooOne
+FooOne
+> Foo 1
+FooOne
+> Foo 5
+Foo 5
+> read "FooTwo" :: Foo
+FooTwo
+> read "Foo 3" :: Foo
+FooThree
+```
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/c-enum.cabal b/c-enum.cabal
new file mode 100644
--- /dev/null
+++ b/c-enum.cabal
@@ -0,0 +1,52 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.33.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 6193eeddda031a2998034fae776898c57ad4ef04b7de0f07a6bb1db2721bf951
+
+name:           c-enum
+version:        0.1.0.0
+description:    Please see the README on GitHub at <https://github.com/YoshikuniJujo/c-enum#readme>
+homepage:       https://github.com/YoshikuniJujo/c-enum#readme
+bug-reports:    https://github.com/YoshikuniJujo/c-enum/issues
+author:         Yoshikuni Jujo
+maintainer:     yoshikuni.jujo.pc@gmail.com
+copyright:      2021 Yoshikuni Jujo
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://github.com/YoshikuniJujo/c-enum
+
+library
+  exposed-modules:
+      Foreign.C.Enum
+  other-modules:
+      Paths_c_enum
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4.7 && <5
+    , template-haskell
+  default-language: Haskell2010
+
+test-suite c-enum-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Paths_c_enum
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , c-enum
+    , template-haskell
+  default-language: Haskell2010
diff --git a/src/Foreign/C/Enum.hs b/src/Foreign/C/Enum.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/C/Enum.hs
@@ -0,0 +1,143 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}
+
+module Foreign.C.Enum (enum) where
+
+import Language.Haskell.TH (
+	Name, mkName, newName, Lit(..), clause, cxt, normalB,
+	DecsQ, DecQ, valD, funD, instanceD,
+	patSynSigD, patSynD, prefixPatSyn, explBidir,
+	newtypeD, normalC, derivClause,
+	ExpQ, varE, conE, litE, appE, infixE, listE, lamCaseE,
+	conT, appT, varP, conP, litP, match,
+	doE, bindS, noBindS,
+	bangType, bang, noSourceUnpackedness, noSourceStrictness )
+import Control.Arrow (first)
+import Data.Bool (bool)
+import Data.Maybe (isJust, listToMaybe)
+import Data.List (partition)
+import Text.Read (readPrec, Lexeme(..), step, choice, prec, parens, lexP)
+
+enum :: String -> Name -> [Name] -> [(String, Integer)] -> DecsQ
+enum nt t ds nvs = (\n s r ms -> n : s (r ms))
+	<$> mkNewtype nt t ds'
+	<*> bool (pure id) ((:) <$> mkShow nt ns) bs
+	<*> bool (pure id) ((:) <$> mkRead nt ns) br
+	<*> mkMembers nt nvs
+	where ShowReadClasses bs br ds' = showReadClasses ds; ns = fst <$> nvs
+
+{- ^
+
+Write like the following.
+
+@
+enum Foo ''Int [''Show, ''Read, ''Eq] [
+	("FooError", - 1),
+	("FooZero", 0),
+	("FooOne", 1),
+	("FooTwo", 2) ]
+@
+
+Then you get like the following.
+
+@
+newtype Foo = Foo Int deriving Eq
+
+pattern FooError :: Int -> Foo
+pattern FooError <- Foo (- 1) where
+	FooError = Foo (- 1)
+
+pattern FooZero :: Int -> Foo
+...
+
+
+instance Show Foo where
+	showsPrec = ...
+
+instance Read Foo where
+	readPrec = ...
+@
+
+And you can read and show like the following.
+
+@
+> Foo $ - 1
+FooError
+> FooTwo
+FooTwo
+> Foo 3
+Foo 3
+> read "Foo (- 1)" :: Foo
+FooError
+> read \"FooOne\" :: Foo
+FooOne
+@
+
+-}
+
+data ShowReadClasses = ShowReadClasses {
+	showReadClassesShow :: Bool,
+	showReadClassesRead :: Bool,
+	showReadClassesClasses :: [Name] } deriving Show
+
+showReadClasses :: [Name] -> ShowReadClasses
+showReadClasses ns = ShowReadClasses (isJust s) (isJust r) ns''
+	where (s, ns') = popIt ''Show ns; (r, ns'') = popIt ''Read ns'
+
+popIt :: Eq a => a -> [a] -> (Maybe a, [a])
+popIt x = (listToMaybe `first`) . partition (== x)
+
+mkNewtype :: String -> Name -> [Name] -> DecQ
+mkNewtype nt t ds = newtypeD (cxt []) (mkName nt) [] Nothing
+	(normalC (mkName nt)
+		[bangType
+			(bang noSourceUnpackedness noSourceStrictness)
+			(conT t)])
+	[derivClause Nothing $ conT <$> ds]
+
+mkMembers :: String -> [(String, Integer)] -> DecsQ
+mkMembers t nvs = concat <$> uncurry (mkMember (mkName t)) `mapM` nvs
+
+mkMember :: Name -> String -> Integer -> DecsQ
+mkMember t n v = sequence [
+	patSynSigD (mkName n) (conT t),
+	patSynD (mkName n) (prefixPatSyn [])
+		(explBidir [flip (clause []) []
+			. normalB $ conE t `appE` litE (IntegerL v)])
+		(conP t [litP (IntegerL v)]) ]
+
+mkShow :: String -> [String] -> DecQ
+mkShow t ns = instanceD (cxt [])
+	(conT ''Show `appT` conT (mkName t)) [defineShowsPrec t ns]
+
+defineShowsPrec :: String -> [String] -> DecQ
+defineShowsPrec t ns = newName `mapM` ["d", "n"] >>= \[d, n] ->
+	funD 'showsPrec [clause [varP d] (normalB (lamCaseE (
+		(named <$> ns) ++
+		[match (conP (mkName t) [varP n]) (normalB $ sw d n) []] ))) []]
+	where
+	named f = flip (match $ conP (mkName f) []) [] 
+		. normalB $ litE (StringL f) `p` varE '(++)
+	sw d n = varE 'showParen `appE` (varE d .> litE (IntegerL 10))
+		.$ ((litE (StringL $ t ++ " ") `p` varE '(++)) ...
+			(varE 'showsPrec `appE` litE (IntegerL 11) `appE` varE n))
+
+mkRead :: String -> [String] -> DecQ
+mkRead t ns = instanceD (cxt []) (conT ''Read `appT` conT (mkName t)) . (: [])
+	$ valD (varP 'readPrec) (normalB $ varE 'parens .$ (varE 'choice `appE` listE (
+		(named <$> ns) ++
+		[varE 'prec `appE` litE (IntegerL 10) `appE` doE [
+			bindS (conP 'Ident [litP $ StringL t]) $ varE 'lexP,
+			noBindS $ conE (mkName t) .<$> (varE 'step `appE` varE 'readPrec) ]]
+		))) []
+	where
+	named n = doE [
+		bindS (conP 'Ident [litP $ StringL n]) $ varE 'lexP,
+		noBindS $ varE 'pure `appE` conE (mkName n) ]
+
+(...), (.$), (.<$>), (.>), p :: ExpQ -> ExpQ -> ExpQ
+e1 ... e2 = infixE (Just e1) (varE '(.)) (Just e2)
+e1 .$ e2 = infixE (Just e1) (varE '($)) (Just e2)
+e1 .<$> e2 = infixE (Just e1) (varE '(<$>)) (Just e2)
+e1 .> e2 = infixE (Just e1) (varE '(>)) (Just e2)
+ex `p` op = infixE (Just ex) op Nothing
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
