tlex-th (empty) → 0.1.0.0
raw patch · 12 files changed
+695/−0 lines, 12 filesdep +QuickCheckdep +arraydep +basebuild-type:Customsetup-changed
Dependencies added: QuickCheck, array, base, containers, doctest, ghc-prim, hspec, template-haskell, tlex, tlex-core, tlex-th
Files
- CHANGELOG.md +3/−0
- LICENSE +5/−0
- README.md +1/−0
- Setup.hs +6/−0
- src/Language/Lexer/Tlex/Data/Addr.hs +23/−0
- src/Language/Lexer/Tlex/Data/Bits.hs +17/−0
- src/Language/Lexer/Tlex/Data/TypeableTH.hs +39/−0
- src/Language/Lexer/Tlex/Output/TH.hs +300/−0
- src/Language/Lexer/Tlex/Plugin/TH.hs +118/−0
- test/doctest/Doctest.hs +21/−0
- test/spec/HSpecDriver.hs +1/−0
- tlex-th.cabal +161/−0
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+## 0.1.0.0 -- 2021-01-XX++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,5 @@+Apache-2.0 OR MPL-2.0++---++See https://github.com/mizunashi-mana/tlex/blob/master/LICENSE
+ README.md view
@@ -0,0 +1,1 @@+See https://hackage.haskell.org/package/tlex
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main where++import Distribution.Extra.Doctest (defaultMainWithDoctests)++main :: IO ()+main = defaultMainWithDoctests "doctest"
+ src/Language/Lexer/Tlex/Data/Addr.hs view
@@ -0,0 +1,23 @@+module Language.Lexer.Tlex.Data.Addr (+ addrCodeUnitsLE,+) where++import Language.Lexer.Tlex.Prelude++import qualified Data.Bits as Bits+++addrCodeUnitsLE :: Bits.Bits a => Integral a => Int -> a -> [Word8]+addrCodeUnitsLE us n+ | n >= 0 = take us+ do map+ do \m -> fromInteger do fromIntegral do mod8bit m+ do iterate (`Bits.shiftR` 8) n+ | n == -1 = replicate us 0xFF+ | otherwise = error "unsupported"+ where+ mod8bit = case Bits.bitSizeMaybe n of+ Nothing -> \x -> x `mod` 256+ Just bs+ | bs <= 8 -> \x -> x+ | otherwise -> \x -> x `mod` 256
+ src/Language/Lexer/Tlex/Data/Bits.hs view
@@ -0,0 +1,17 @@+module Language.Lexer.Tlex.Data.Bits (+ maxBitSize,+) where++import Language.Lexer.Tlex.Prelude++import qualified Data.Bits as Bits+++maxBitSize :: Bits.FiniteBits a => Ord a => Num a => a -> Int+maxBitSize n = go 1 2 where+ go i m+ | n < m = i+ | i >= Bits.finiteBitSize n = i+ | otherwise = go+ do i + 1+ do m * 2
+ src/Language/Lexer/Tlex/Data/TypeableTH.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE TemplateHaskell #-}++module Language.Lexer.Tlex.Data.TypeableTH (+ liftTypeFromTypeable,+ tyConToType,+) where++import Prelude++import Data.Foldable (foldl')+import qualified Data.Typeable as Typeable+import qualified Language.Haskell.TH as TH++liftTypeFromTypeable :: Typeable.Typeable a => Typeable.Proxy a -> TH.Q TH.Type+liftTypeFromTypeable p = go do Typeable.typeRep p where+ go r0 =+ let (tyCon, rs) = Typeable.splitTyConApp r0+ in foldl'+ do \tq1 tq2 -> [t|$(tq1) $(tq2)|]+ do tyConToType tyCon+ do [ go r | r <- rs ]++-- |+--+-- TODO: correct reifying+-- NOTICE: introduce @reifyType@ by GHC 8.10+--+tyConToType :: Typeable.TyCon -> TH.Q TH.Type+tyConToType tyCon = do+ mn <- TH.lookupTypeName tyConQualifiedName+ case mn of+ Just n -> pure do TH.ConT n+ Nothing -> case tyConQualifiedName of+ "GHC.Tuple.()" ->+ pure do TH.TupleT 0+ _ ->+ fail do "Missing type: " ++ tyConQualifiedName+ where+ tyConQualifiedName = Typeable.tyConModule tyCon ++ "." ++ Typeable.tyConName tyCon
+ src/Language/Lexer/Tlex/Output/TH.hs view
@@ -0,0 +1,300 @@+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE TemplateHaskell #-}++module Language.Lexer.Tlex.Output.TH (+ TlexContext (..),+ TlexResult (..),+ Runner (..),+ runRunner,+ TlexTransStateSize (..),+ tlexLookupTlexTransTable,+ TlexArray,+ tlexArray,+ tlexArrayIndex,+ OutputContext (..),+ outputDfa,+) where++import Language.Lexer.Tlex.Prelude++import qualified Data.Array as Array+import qualified Data.Bits as Bits+import qualified Data.IntMap.Strict as IntMap+import qualified GHC.Prim as Prim+import qualified GHC.ST as ST+import qualified GHC.Types as Types+import qualified Language.Haskell.TH as TH+import qualified Language.Haskell.TH.Syntax as TH+import qualified Language.Lexer.Tlex.Data.Addr as Addr+import qualified Language.Lexer.Tlex.Data.Bits as Bits+import qualified Language.Lexer.Tlex.Data.EnumMap as EnumMap+import qualified Language.Lexer.Tlex.Machine.DFA as DFA+import qualified Language.Lexer.Tlex.Machine.State as MState+import Language.Lexer.Tlex.Runner+import qualified Language.Lexer.Tlex.Syntax as Tlex+++data TlexTransStateSize+ = TlexTransStateSize8+ | TlexTransStateSize16+ | TlexTransStateSize32+ deriving (Eq, Show, Enum, TH.Lift)++{-# INLINE tlexLookupTlexTransTable #-}+tlexLookupTlexTransTable :: Int -> TlexTransStateSize -> Prim.Addr#+ -> Int -> Int -> Int+tlexLookupTlexTransTable offset unitSize table# s c =+ let !(Types.I# i#) = s `Bits.shiftL` offset + c+ in ST.runST+ do ST.ST \s0# ->+ let !(# s1#, r# #) = case unitSize of+ TlexTransStateSize8 -> Prim.readInt8OffAddr# table# i# s0#+ TlexTransStateSize16 -> Prim.readInt16OffAddr# table# i# s0#+ TlexTransStateSize32 -> Prim.readInt32OffAddr# table# i# s0#+ in (# s1#, Types.I# r# #)++type TlexArray = Array.Array Int++{-# INLINE tlexArray #-}+tlexArray :: Int -> [a] -> TlexArray a+tlexArray l xs = Array.listArray (0,l) xs++{-# INLINE tlexArrayIndex #-}+tlexArrayIndex :: TlexArray a -> Int -> a+tlexArrayIndex arr i = arr Array.! i++{-+type TlexStartState = ...+type TlexSemanticAction = ...+type TlexCodeUnit = ...++tlexScan :: TlexContext s TlexCodeUnit m => TlexStartState -> m (TlexResult s TlexSemanticAction)+tlexScan s0 = runRunner runner s0+ where+ runner = Runner+ { tlexInitial = thTlexInitial+ , tlexAccept = thTlexAccept+ , tlexTrans = thTlexTrans+ }++thTlexInitial :: Int -> Int+thTlexInitial = \x -> tlexArrayIndex tlexInitialTable x+ where+ table :: TlexArray Int+ table = tlexArray 10 [10,...]++thTlexTrans :: Int -> Int -> Int+thTlexTrans = \s c -> tlexLookupTlexTransTable+ 8+ TlexTransTableStateSize8+ "\x02\x00\x00\x00..."#+ s (c - 0)++thTlexAccept :: Int -> Maybe TlexSemanticAction+thTlexAccept = \x -> if x >= 120+ then Nothing+ else tlexArrayIndex table x+ where+ table :: TlexArray (Maybe TlexSemanticAction)+ table = tlexArray 120 [Nothing,...]+-}+data OutputContext = OutputContext+ { outputCtxStartStateTy :: TH.Type+ , outputCtxCodeUnitTy :: TH.Type+ , outputCtxCodeUnitBounds :: (Int, Int)+ , outputCtxSemanticActionTy :: TH.Type+ }+ deriving (Eq, Show)++outputDfa :: OutputContext -> DFA.DFA (TH.Q TH.Exp) -> TH.Q [TH.Dec]+outputDfa ctx dfa = do+ let startStateTyName = TH.mkName "TlexStartState"+ codeUnitTyName = TH.mkName "TlexCodeUnit"+ semanticActionTyName = TH.mkName "TlexSemanticAction"+ tlexScanFnName = TH.mkName "tlexScan"+ thTlexInitialFnName = TH.mkName "thTlexInitial"+ thTlexTransFnName = TH.mkName "thTlexTrans"+ thTlexAcceptFnName = TH.mkName "thTlexAccept"++ let startStateTy = pure @TH.Q do TH.ConT startStateTyName+ codeUnitTy = pure @TH.Q do TH.ConT codeUnitTyName+ semanticActionTy = pure @TH.Q do TH.ConT semanticActionTyName+ thTlexInitialFn = pure @TH.Q do TH.VarE thTlexInitialFnName+ thTlexTransFn = pure @TH.Q do TH.VarE thTlexTransFnName+ thTlexAcceptFn = pure @TH.Q do TH.VarE thTlexAcceptFnName++ sequence+ [ pure do TH.TySynD startStateTyName [] do outputCtxStartStateTy ctx+ , pure do TH.TySynD codeUnitTyName [] do outputCtxCodeUnitTy ctx+ , pure do TH.TySynD semanticActionTyName [] do outputCtxSemanticActionTy ctx++ , TH.SigD tlexScanFnName <$> [t|+ forall s m. TlexContext s $(codeUnitTy) m+ => $(startStateTy) -> m (TlexResult s $(semanticActionTy))+ |]+ , TH.ValD+ do TH.VarP tlexScanFnName+ <$> do TH.NormalB <$> [e|\s0 -> runRunner runner s0|]+ <*> [d|+ runner = Runner+ $(thTlexInitialFn)+ $(thTlexAcceptFn)+ $(thTlexTransFn)+ |]++ , TH.SigD thTlexInitialFnName <$>+ [t|Int -> Int|]+ , outputTlexInitialFn dfa thTlexInitialFnName++ , TH.SigD thTlexTransFnName <$>+ [t|Int -> Int -> Int|]+ , outputTlexTransFn dfa+ do outputCtxCodeUnitBounds ctx+ thTlexTransFnName++ , TH.SigD thTlexAcceptFnName <$>+ [t|Int -> Maybe $(semanticActionTy)|]+ , outputTlexAcceptFn dfa semanticActionTy thTlexAcceptFnName+ ]++outputTlexInitialFn :: DFA.DFA a -> TH.Name -> TH.Q TH.Dec+outputTlexInitialFn DFA.DFA{ dfaInitials } fnName = do+ tableValName <- TH.newName "table"+ TH.ValD+ do TH.VarP fnName+ <$> do TH.NormalB <$>+ [e|\x -> tlexArrayIndex $(pure do TH.VarE tableValName) x|]+ <*> sequence+ [ TH.SigD tableValName <$>+ [t|TlexArray Int|]+ , tableDec tableValName+ ]+ where+ tableDec :: TH.Name -> TH.Q TH.Dec+ tableDec valName = TH.ValD+ do TH.VarP valName+ <$> do TH.NormalB <$> do+ (es, l) <- tableList+ outputTlexArrayLit l es+ <*> pure []++ tableList :: TH.Q ([TH.Exp], Int)+ tableList =+ let (es, l) = sequentialListFromAscList+ [e|-1|]+ [ (fromEnum ss, TH.lift do fromEnum sn)+ | (ss, sn) <- EnumMap.toAscList dfaInitials+ ]+ in do+ es' <- sequence es+ pure (es', l)++outputTlexTransFn :: DFA.DFA a -> (Int, Int) -> TH.Name -> TH.Q TH.Dec+outputTlexTransFn DFA.DFA{ dfaTrans } (minUnitB, maxUnitB) fnName =+ let ubs = Bits.maxBitSize do maxUnitB - minUnitB+ um =+ do 1 `Bits.shiftL` ubs+ - 1+ l = concatMap+ do \dstState ->+ let smDef = case DFA.dstOtherTrans dstState of+ Nothing -> -1+ Just sm -> fromEnum sm+ dstTrans = DFA.dstTrans dstState+ in map+ do \i -> case IntMap.lookup i dstTrans of+ Just sm -> fromEnum sm+ Nothing -> smDef+ [0..um]+ do toList dfaTrans+ sbs = Bits.maxBitSize do length dfaTrans - 1+ sbsEnum = if+ | ubs + sbs > 29 -> error "exceed over bit size limited"+ | otherwise -> stateSize sbs+ in TH.ValD+ do TH.VarP fnName+ <$> do TH.NormalB <$>+ [e|\s c -> tlexLookupTlexTransTable+ $(unitBitSizeExp ubs)+ $(TH.lift sbsEnum)+ $(tableAddrExp sbsEnum l)+ s (c - $(TH.lift minUnitB))+ |]+ <*> pure []+ where+ unitBitSizeExp ubs = pure+ do TH.LitE do TH.IntegerL do fromIntegral ubs++ stateSize sbs+ | sbs <= 8 = TlexTransStateSize8+ | sbs <= 16 = TlexTransStateSize16+ | otherwise = TlexTransStateSize32++ tableAddrExp ss l =+ let us = case ss of+ TlexTransStateSize8 -> 1+ TlexTransStateSize16 -> 2+ TlexTransStateSize32 -> 4+ in pure+ do TH.LitE+ do TH.StringPrimL+ do concatMap+ do \sn -> Addr.addrCodeUnitsLE us+ do fromEnum sn+ do l++outputTlexAcceptFn+ :: DFA.DFA (TH.Q TH.Exp) -> (TH.Q TH.Type) -> TH.Name -> TH.Q TH.Dec+outputTlexAcceptFn DFA.DFA{ dfaTrans } semanticActionTy fnName = do+ tableValName <- TH.newName "table"+ (es, l) <- tableList+ TH.ValD+ do TH.VarP fnName+ <$> do TH.NormalB <$>+ [e|+ \x -> if x >= $(TH.lift l)+ then Nothing+ else tlexArrayIndex $(pure do TH.VarE tableValName) x+ |]+ <*> sequence+ [ TH.SigD tableValName <$>+ [t|TlexArray (Maybe $(semanticActionTy))|]+ , tableDec tableValName es l+ ]+ where+ tableDec valName es l = TH.ValD+ do TH.VarP valName+ <$> do TH.NormalB <$> outputTlexArrayLit l es+ <*> pure []++ tableList :: TH.Q ([TH.Exp], Int)+ tableList =+ let (es, l) = sequentialListFromAscList+ [e|Nothing|]+ do+ (sn, dstSt) <- MState.arrayAssocs dfaTrans+ let accExp = case DFA.dstAccepts dstSt of+ [] -> [e|Nothing|]+ acc:_ -> [e|Just $(Tlex.accSemanticAction acc)|]+ pure (fromEnum sn, accExp)+ in do+ es' <- sequence es+ pure (es', l)++outputTlexArrayLit :: Int -> [TH.Exp] -> TH.Q TH.Exp+outputTlexArrayLit l es =+ [e|tlexArray $(TH.lift l) $(pure do TH.ListE es)|]++sequentialListFromAscList :: a -> [(Int, a)] -> ([a], Int)+sequentialListFromAscList v xs =+ let (l0, m) = foldl'+ do \(l, !pi) (i, x) -> (fillV i pi l . (x:), succ i)+ do (id, 0)+ do xs+ in (l0 [], m)+ where+ fillV i !pi l+ | pi == i = l+ | otherwise = fillV i+ do succ pi+ do l . (v:)
+ src/Language/Lexer/Tlex/Plugin/TH.hs view
@@ -0,0 +1,118 @@+{-# LANGUAGE CPP #-}++module Language.Lexer.Tlex.Plugin.TH (+ TlexTH.TlexContext (..),+ TlexTH.TlexResult (..),+ TlexTH.Runner (..),+ TlexTH.runRunner,+ THScanner (..),+ THScannerBuilderContext,+ THScannerBuilder,+ buildTHScanner,+ buildTHScannerWithReify,+ liftTlexScannerBuilder,+ thLexRule,+ outputScanner,+) where++import Language.Lexer.Tlex.Prelude++import qualified Language.Haskell.TH as TH+import qualified Language.Lexer.Tlex.Data.TypeableTH as TypeableTH+import qualified Language.Lexer.Tlex.Machine.NFA as NFA+import qualified Language.Lexer.Tlex.Output.TH as TlexTH+import qualified Language.Lexer.Tlex.Pipeline.MinDfa as TlexPipeline+import qualified Language.Lexer.Tlex.Pipeline.Nfa2Dfa as TlexPipeline+import qualified Language.Lexer.Tlex.Pipeline.Scanner2Nfa as TlexPipeline+import qualified Language.Lexer.Tlex.Syntax as Tlex++#ifdef DEBUG+import qualified Debug.Trace as Debug+#endif+++data THScanner e = THScanner+ { thScannerOutputCtx :: TlexTH.OutputContext+ , thScannerTlexScanner :: Tlex.Scanner e (TH.Q TH.Exp)+ }++data THScannerBuilderContext s e a = THScannerBuilderContext+ { thScannerBuilderCtxOutputCtx :: TlexTH.OutputContext+ , thScannerBuilderCtxTlexScannerBuilderCtx :: Tlex.ScannerBuilderContext s e (TH.Q TH.Exp)+ }++type THScannerBuilder s e a = State (THScannerBuilderContext s e a)++buildTHScanner :: forall e s a. Enum e => Bounded e+ => TH.Type -> TH.Type -> TH.Type -> THScannerBuilder s e a ()+ -> THScanner e+buildTHScanner codeUnitTy startStateTy actionTy builder =+ let outputCtx = TlexTH.OutputContext+ { outputCtxStartStateTy = startStateTy+ , outputCtxCodeUnitTy = codeUnitTy+ , outputCtxCodeUnitBounds = (+ fromEnum do minBound @e,+ fromEnum do maxBound @e+ )+ , outputCtxSemanticActionTy = actionTy+ }+ tlexScanner = Tlex.buildScanner do+ modify' \ctx0 -> thScannerBuilderCtxTlexScannerBuilderCtx+ do execState builder do+ THScannerBuilderContext+ { thScannerBuilderCtxOutputCtx = outputCtx+ , thScannerBuilderCtxTlexScannerBuilderCtx = ctx0+ }+ in THScanner+ { thScannerOutputCtx = outputCtx+ , thScannerTlexScanner = tlexScanner+ }++buildTHScannerWithReify :: forall s a e.+ Enum e => Bounded e => Typeable e => Typeable s => Typeable a+ => THScannerBuilder s e a () -> TH.Q (THScanner e)+buildTHScannerWithReify builder = do+ startStateTy <- TypeableTH.liftTypeFromTypeable do Proxy @s+ codeUnitTy <- TypeableTH.liftTypeFromTypeable do Proxy @e+ actionTy <- TypeableTH.liftTypeFromTypeable do Proxy @a+ pure do buildTHScanner codeUnitTy startStateTy actionTy builder++liftTlexScannerBuilder :: Enum e => Tlex.ScannerBuilder s e (TH.Q TH.Exp) a -> THScannerBuilder s e f a+liftTlexScannerBuilder builder = do+ ctx0 <- get+ let (x, tlexCtx1) = runState+ do builder+ do thScannerBuilderCtxTlexScannerBuilderCtx ctx0+ put do ctx0+ { thScannerBuilderCtxTlexScannerBuilderCtx = tlexCtx1+ }+ pure x++thLexRule :: Enum e => Enum s => [s] -> Tlex.Pattern e -> TH.Q (TH.TExp a) -> THScannerBuilder s e a ()+thLexRule ss p act = liftTlexScannerBuilder do Tlex.lexRule ss p do TH.unType <$> act+++outputScanner :: Enum e => THScanner e -> TH.Q [TH.Dec]+outputScanner scanner =+ let outputCtx = thScannerOutputCtx scanner+ nfa =+#ifdef DEBUG+ Debug.trace "building NFA..." do+#endif+ NFA.buildNFA do+ TlexPipeline.scanner2Nfa do thScannerTlexScanner scanner+ dfa =+#ifdef DEBUG+ Debug.trace "building DFA..." do+#endif+ TlexPipeline.nfa2Dfa nfa+ minDfa =+#ifdef DEBUG+ Debug.trace "minizing DFA..." do+#endif+ TlexPipeline.minDfa dfa+ in+#ifdef DEBUG+ Debug.trace "outputing DFA..." do+#endif+ TlexTH.outputDfa outputCtx minDfa
+ test/doctest/Doctest.hs view
@@ -0,0 +1,21 @@+module Main where++import Prelude++import qualified Build_doctests as BuildF+import Control.Monad+import qualified System.Environment as IO+import qualified System.IO as IO+import Test.DocTest (doctest)++main :: IO ()+main = forM_ BuildF.components \(BuildF.Component name flags pkgs sources) -> do+ putStrLn "============================================="+ print name+ putStrLn "---------------------------------------------"+ IO.hFlush IO.stdout+ let args = flags ++ pkgs ++ sources+ IO.unsetEnv "GHC_ENVIRONMENT"+ doctest args+ putStrLn "============================================="+ IO.hFlush IO.stdout
+ test/spec/HSpecDriver.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ tlex-th.cabal view
@@ -0,0 +1,161 @@+cabal-version: 3.0+build-type: Custom++name: tlex-th+version: 0.1.0.0+license: Apache-2.0 OR MPL-2.0+license-file: LICENSE+copyright: (c) 2021 Mizunashi Mana+author: Mizunashi Mana+maintainer: mizunashi-mana@noreply.git++category: Parsing+homepage: https://github.com/mizunashi-mana/tlex+bug-reports: https://github.com/mizunashi-mana/tlex/issues+synopsis: TemplateHaskell plugin for Tlex+description:+ Tlex is haskell libraries and toolchains for generating lexical analyzer.+ See also: https://github.com/mizunashi-mana/tlex++extra-source-files:+ README.md+ CHANGELOG.md++source-repository head+ type: git+ location: https://github.com/mizunashi-mana/tlex.git++flag develop+ default: False+ manual: True+ description: Turn on some options for development++common general+ default-language:+ Haskell2010+ default-extensions:+ NoImplicitPrelude+ BangPatterns+ BinaryLiterals+ BlockArguments+ ConstraintKinds+ DataKinds+ DefaultSignatures+ DeriveFoldable+ DeriveFunctor+ DeriveGeneric+ DeriveLift+ DeriveTraversable+ DerivingVia+ DuplicateRecordFields+ EmptyCase+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GADTs+ InstanceSigs+ LambdaCase+ MagicHash+ MultiParamTypeClasses+ MultiWayIf+ NamedFieldPuns+ NegativeLiterals+ NumericUnderscores+ OverloadedLabels+ PackageImports+ PatternSynonyms+ PolyKinds+ RankNTypes+ ScopedTypeVariables+ StandaloneDeriving+ Strict+ TypeApplications+ TypeFamilies+ TypeOperators+ UnboxedSums+ UnboxedTuples++ if flag(develop)+ ghc-options:+ -Wall+ -Wcompat+ -Wincomplete-uni-patterns+ -Wmonomorphism-restriction+ -Wpartial-fields++ -fprint-explicit-foralls+ -frefinement-level-hole-fits=1++ -dcore-lint++ build-depends:+ base >= 4.12.0 && < 4.15,++ -- project depends+ tlex-core >= 0.1.0 && < 0.2,+ tlex >= 0.1.0 && < 0.2,+ ghc-prim >= 0.5.3 && < 0.7,+ template-haskell >= 2.14.0 && < 2.17.0,+ array >= 0.5.3 && < 0.6,+ containers >= 0.6.0 && < 0.7,++ autogen-modules:+ Paths_tlex_th+ other-modules:+ Paths_tlex_th++custom-setup+ setup-depends:+ base,+ Cabal,+ cabal-doctest,++library+ import:+ general,+ hs-source-dirs:+ src+ exposed-modules:+ Language.Lexer.Tlex.Plugin.TH+ Language.Lexer.Tlex.Data.TypeableTH++ -- internals+ Language.Lexer.Tlex.Output.TH+ Language.Lexer.Tlex.Data.Addr+ Language.Lexer.Tlex.Data.Bits++test-suite doctest+ import:+ general,+ type:+ exitcode-stdio-1.0+ hs-source-dirs:+ test/doctest+ main-is:+ Doctest.hs+ build-depends:+ doctest,+ QuickCheck,+ autogen-modules:+ Build_doctests+ other-modules:+ Build_doctests++test-suite spec+ import:+ general,+ type:+ exitcode-stdio-1.0+ hs-source-dirs:+ test/spec+ main-is:+ HSpecDriver.hs+ ghc-options:+ -Wno-missing-home-modules+ build-tool-depends:+ hspec-discover:hspec-discover,+ build-depends:+ tlex-th,++ hspec,+ QuickCheck,