Blame src/AbsSyn.hs

Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
--
Packit 2cbdf3
-- AbsSyn.hs, part of Alex
Packit 2cbdf3
--
Packit 2cbdf3
-- (c) Chris Dornan 1995-2000, Simon Marlow 2003
Packit 2cbdf3
--
Packit 2cbdf3
-- This module provides a concrete representation for regular expressions and
Packit 2cbdf3
-- scanners.  Scanners are used for tokenising files in preparation for parsing.
Packit 2cbdf3
--
Packit 2cbdf3
-- ----------------------------------------------------------------------------}
Packit 2cbdf3
Packit 2cbdf3
module AbsSyn (
Packit 2cbdf3
  Code, Directive(..), Scheme(..),
Packit 2cbdf3
  wrapperName,
Packit 2cbdf3
  Scanner(..),
Packit 2cbdf3
  RECtx(..),
Packit 2cbdf3
  RExp(..),
Packit 2cbdf3
  DFA(..), State(..), SNum, StartCode, Accept(..),
Packit 2cbdf3
  RightContext(..), showRCtx, strtype,
Packit 2cbdf3
  encodeStartCodes, extractActions,
Packit 2cbdf3
  Target(..),
Packit 2cbdf3
  UsesPreds(..), usesPreds,
Packit 2cbdf3
  StrType(..)
Packit 2cbdf3
  ) where
Packit 2cbdf3
Packit 2cbdf3
import CharSet ( CharSet, Encoding )
Packit 2cbdf3
import Map ( Map )
Packit 2cbdf3
import qualified Map hiding ( Map )
Packit 2cbdf3
import Data.IntMap (IntMap)
Packit 2cbdf3
import Sort ( nub' )
Packit 2cbdf3
import Util ( str, nl )
Packit 2cbdf3
Packit 2cbdf3
import Data.Maybe ( fromJust )
Packit 2cbdf3
Packit 2cbdf3
infixl 4 :|
Packit 2cbdf3
infixl 5 :%%
Packit 2cbdf3
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
-- Abstract Syntax for Alex scripts
Packit 2cbdf3
Packit 2cbdf3
type Code = String
Packit 2cbdf3
Packit 2cbdf3
data Directive
Packit 2cbdf3
   = WrapperDirective String            -- use this wrapper
Packit 2cbdf3
   | EncodingDirective Encoding         -- use this encoding
Packit 2cbdf3
   | ActionType String                  -- Type signature of actions,
Packit 2cbdf3
                                        -- with optional typeclasses
Packit 2cbdf3
   | TypeClass String
Packit 2cbdf3
   | TokenType String
Packit 2cbdf3
   deriving Show
Packit 2cbdf3
Packit 2cbdf3
data StrType = Str | Lazy | Strict
Packit 2cbdf3
Packit 2cbdf3
instance Show StrType where
Packit 2cbdf3
  show Str = "String"
Packit 2cbdf3
  show Lazy = "ByteString.ByteString"
Packit 2cbdf3
  show Strict = "ByteString.ByteString"
Packit 2cbdf3
Packit 2cbdf3
data Scheme
Packit 2cbdf3
  = Default { defaultTypeInfo :: Maybe (Maybe String, String) }
Packit 2cbdf3
  | GScan { gscanTypeInfo :: Maybe (Maybe String, String) }
Packit 2cbdf3
  | Basic { basicStrType :: StrType,
Packit 2cbdf3
            basicTypeInfo :: Maybe (Maybe String, String) }
Packit 2cbdf3
  | Posn { posnByteString :: Bool,
Packit 2cbdf3
           posnTypeInfo :: Maybe (Maybe String, String) }
Packit 2cbdf3
  | Monad { monadByteString :: Bool, monadUserState :: Bool,
Packit 2cbdf3
            monadTypeInfo :: Maybe (Maybe String, String) }
Packit 2cbdf3
Packit 2cbdf3
strtype :: Bool -> String
Packit 2cbdf3
strtype True = "ByteString.ByteString"
Packit 2cbdf3
strtype False = "String"
Packit 2cbdf3
Packit 2cbdf3
wrapperName :: Scheme -> Maybe String
Packit 2cbdf3
wrapperName Default {} = Nothing
Packit 2cbdf3
wrapperName GScan {} = Just "gscan"
Packit 2cbdf3
wrapperName Basic { basicStrType = Str } = Just "basic"
Packit 2cbdf3
wrapperName Basic { basicStrType = Lazy } = Just "basic-bytestring"
Packit 2cbdf3
wrapperName Basic { basicStrType = Strict } = Just "strict-bytestring"
Packit 2cbdf3
wrapperName Posn { posnByteString = False } = Just "posn"
Packit 2cbdf3
wrapperName Posn { posnByteString = True } = Just "posn-bytestring"
Packit 2cbdf3
wrapperName Monad { monadByteString = False,
Packit 2cbdf3
                    monadUserState = False } = Just "monad"
Packit 2cbdf3
wrapperName Monad { monadByteString = True,
Packit 2cbdf3
                    monadUserState = False } = Just "monad-bytestring"
Packit 2cbdf3
wrapperName Monad { monadByteString = False,
Packit 2cbdf3
                    monadUserState = True } = Just "monadUserState"
Packit 2cbdf3
wrapperName Monad { monadByteString = True,
Packit 2cbdf3
                    monadUserState = True } = Just "monadUserState-bytestring"
Packit 2cbdf3
Packit 2cbdf3
-- TODO: update this comment
Packit 2cbdf3
--
Packit 2cbdf3
-- A `Scanner' consists of an association list associating token names with
Packit 2cbdf3
-- regular expressions with context.  The context may include a list of start
Packit 2cbdf3
-- codes, some leading context to test the character immediately preceding the
Packit 2cbdf3
-- token and trailing context to test the residual input after the token.
Packit 2cbdf3
--
Packit 2cbdf3
-- The start codes consist of the names and numbers of the start codes;
Packit 2cbdf3
-- initially the names only will be generated by the parser, the numbers being
Packit 2cbdf3
-- allocated at a later stage.  Start codes become meaningful when scanners are
Packit 2cbdf3
-- converted to DFAs; see the DFA section of the Scan module for details.
Packit 2cbdf3
Packit 2cbdf3
data Scanner = Scanner { scannerName   :: String,
Packit 2cbdf3
                         scannerTokens :: [RECtx] }
Packit 2cbdf3
  deriving Show
Packit 2cbdf3
Packit 2cbdf3
data RECtx = RECtx { reCtxStartCodes :: [(String,StartCode)],
Packit 2cbdf3
                     reCtxPreCtx     :: Maybe CharSet,
Packit 2cbdf3
                     reCtxRE         :: RExp,
Packit 2cbdf3
                     reCtxPostCtx    :: RightContext RExp,
Packit 2cbdf3
                     reCtxCode       :: Maybe Code
Packit 2cbdf3
                   }
Packit 2cbdf3
Packit 2cbdf3
data RightContext r
Packit 2cbdf3
  = NoRightContext
Packit 2cbdf3
  | RightContextRExp r
Packit 2cbdf3
  | RightContextCode Code
Packit 2cbdf3
  deriving (Eq,Ord)
Packit 2cbdf3
Packit 2cbdf3
instance Show RECtx where
Packit 2cbdf3
  showsPrec _ (RECtx scs _ r rctx code) =
Packit 2cbdf3
        showStarts scs . shows r . showRCtx rctx . showMaybeCode code
Packit 2cbdf3
Packit 2cbdf3
showMaybeCode :: Maybe String -> String -> String
Packit 2cbdf3
showMaybeCode Nothing = id
Packit 2cbdf3
showMaybeCode (Just code) = showCode code
Packit 2cbdf3
Packit 2cbdf3
showCode :: String -> String -> String
Packit 2cbdf3
showCode code = showString " { " . showString code . showString " }"
Packit 2cbdf3
Packit 2cbdf3
showStarts :: [(String, StartCode)] -> String -> String
Packit 2cbdf3
showStarts [] = id
Packit 2cbdf3
showStarts scs = shows scs
Packit 2cbdf3
Packit 2cbdf3
showRCtx :: Show r => RightContext r -> String -> String
Packit 2cbdf3
showRCtx NoRightContext = id
Packit 2cbdf3
showRCtx (RightContextRExp r) = ('\\':) . shows r
Packit 2cbdf3
showRCtx (RightContextCode code) = showString "\\ " . showCode code
Packit 2cbdf3
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
-- DFAs
Packit 2cbdf3
Packit 2cbdf3
data DFA s a = DFA
Packit 2cbdf3
  { dfa_start_states :: [s],
Packit 2cbdf3
    dfa_states       :: Map s (State s a)
Packit 2cbdf3
  }
Packit 2cbdf3
Packit 2cbdf3
data State s a = State { state_acc :: [Accept a],
Packit 2cbdf3
                         state_out :: IntMap s -- 0..255 only
Packit 2cbdf3
                       }
Packit 2cbdf3
Packit 2cbdf3
type SNum = Int
Packit 2cbdf3
Packit 2cbdf3
data Accept a
Packit 2cbdf3
  = Acc { accPrio       :: Int,
Packit 2cbdf3
          accAction     :: Maybe a,
Packit 2cbdf3
          accLeftCtx    :: Maybe CharSet, -- cannot be converted to byteset at this point.
Packit 2cbdf3
          accRightCtx   :: RightContext SNum
Packit 2cbdf3
    }
Packit 2cbdf3
    deriving (Eq,Ord)
Packit 2cbdf3
Packit 2cbdf3
-- debug stuff
Packit 2cbdf3
instance Show (Accept a) where
Packit 2cbdf3
  showsPrec _ (Acc p _act _lctx _rctx) = shows p --TODO
Packit 2cbdf3
Packit 2cbdf3
type StartCode = Int
Packit 2cbdf3
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
-- Predicates / contexts
Packit 2cbdf3
Packit 2cbdf3
-- we can generate somewhat faster code in the case that
Packit 2cbdf3
-- the lexer doesn't use predicates
Packit 2cbdf3
data UsesPreds = UsesPreds | DoesntUsePreds
Packit 2cbdf3
Packit 2cbdf3
usesPreds :: DFA s a -> UsesPreds
Packit 2cbdf3
usesPreds dfa
Packit 2cbdf3
    | any acceptHasCtx [ acc | st  <- Map.elems (dfa_states dfa)
Packit 2cbdf3
                             , acc <- state_acc st ]
Packit 2cbdf3
    = UsesPreds
Packit 2cbdf3
    | otherwise
Packit 2cbdf3
    = DoesntUsePreds
Packit 2cbdf3
  where
Packit 2cbdf3
    acceptHasCtx Acc { accLeftCtx  = Nothing
Packit 2cbdf3
                     , accRightCtx = NoRightContext } = False
Packit 2cbdf3
    acceptHasCtx _                                    = True
Packit 2cbdf3
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
-- Regular expressions
Packit 2cbdf3
Packit 2cbdf3
-- `RExp' provides an abstract syntax for regular expressions.  `Eps' will
Packit 2cbdf3
-- match empty strings; `Ch p' matches strings containinng a single character
Packit 2cbdf3
-- `c' if `p c' is true; `re1 :%% re2' matches a string if `re1' matches one of
Packit 2cbdf3
-- its prefixes and `re2' matches the rest; `re1 :| re2' matches a string if
Packit 2cbdf3
-- `re1' or `re2' matches it; `Star re', `Plus re' and `Ques re' can be
Packit 2cbdf3
-- expressed in terms of the other operators.  See the definitions of `ARexp'
Packit 2cbdf3
-- for a formal definition of the semantics of these operators.
Packit 2cbdf3
Packit 2cbdf3
data RExp
Packit 2cbdf3
  = Eps
Packit 2cbdf3
  | Ch CharSet
Packit 2cbdf3
  | RExp :%% RExp
Packit 2cbdf3
  | RExp :| RExp
Packit 2cbdf3
  | Star RExp
Packit 2cbdf3
  | Plus RExp
Packit 2cbdf3
  | Ques RExp
Packit 2cbdf3
Packit 2cbdf3
instance Show RExp where
Packit 2cbdf3
  showsPrec _ Eps = showString "()"
Packit 2cbdf3
  showsPrec _ (Ch _) = showString "[..]"
Packit 2cbdf3
  showsPrec _ (l :%% r)  = shows l . shows r
Packit 2cbdf3
  showsPrec _ (l :| r)  = shows l . ('|':) . shows r
Packit 2cbdf3
  showsPrec _ (Star r) = shows r . ('*':)
Packit 2cbdf3
  showsPrec _ (Plus r) = shows r . ('+':)
Packit 2cbdf3
  showsPrec _ (Ques r) = shows r . ('?':)
Packit 2cbdf3
Packit 2cbdf3
{------------------------------------------------------------------------------
Packit 2cbdf3
                          Abstract Regular Expression
Packit 2cbdf3
------------------------------------------------------------------------------}
Packit 2cbdf3
Packit 2cbdf3
Packit 2cbdf3
-- This section contains demonstrations; it is not part of Alex.
Packit 2cbdf3
Packit 2cbdf3
{-
Packit 2cbdf3
-- This function illustrates `ARexp'. It returns true if the string in its
Packit 2cbdf3
-- argument is matched by the regular expression.
Packit 2cbdf3
Packit 2cbdf3
recognise:: RExp -> String -> Bool
Packit 2cbdf3
recognise re inp = any (==len) (ap_ar (arexp re) inp)
Packit 2cbdf3
        where
Packit 2cbdf3
        len = length inp
Packit 2cbdf3
Packit 2cbdf3
Packit 2cbdf3
-- `ARexp' provides an regular expressions in abstract format.  Here regular
Packit 2cbdf3
-- expressions are represented by a function that takes the string to be
Packit 2cbdf3
-- matched and returns the sizes of all the prefixes matched by the regular
Packit 2cbdf3
-- expression (the list may contain duplicates).  Each of the `RExp' operators
Packit 2cbdf3
-- are represented by similarly named functions over ARexp.  The `ap' function
Packit 2cbdf3
-- takes an `ARExp', a string and returns the sizes of all the prefixes
Packit 2cbdf3
-- matching that regular expression.  `arexp' converts an `RExp' to an `ARexp'.
Packit 2cbdf3
Packit 2cbdf3
Packit 2cbdf3
arexp:: RExp -> ARexp
Packit 2cbdf3
arexp Eps = eps_ar
Packit 2cbdf3
arexp (Ch p) = ch_ar p
Packit 2cbdf3
arexp (re :%% re') = arexp re `seq_ar` arexp re'
Packit 2cbdf3
arexp (re :| re') = arexp re `bar_ar` arexp re'
Packit 2cbdf3
arexp (Star re) = star_ar (arexp re)
Packit 2cbdf3
arexp (Plus re) = plus_ar (arexp re)
Packit 2cbdf3
arexp (Ques re) = ques_ar (arexp re)
Packit 2cbdf3
Packit 2cbdf3
Packit 2cbdf3
star_ar:: ARexp -> ARexp
Packit 2cbdf3
star_ar sc =  eps_ar `bar_ar` plus_ar sc
Packit 2cbdf3
Packit 2cbdf3
plus_ar:: ARexp -> ARexp
Packit 2cbdf3
plus_ar sc = sc `seq_ar` star_ar sc
Packit 2cbdf3
Packit 2cbdf3
ques_ar:: ARexp -> ARexp
Packit 2cbdf3
ques_ar sc = eps_ar `bar_ar` sc
Packit 2cbdf3
Packit 2cbdf3
Packit 2cbdf3
-- Hugs abstract type definition -- not for GHC.
Packit 2cbdf3
Packit 2cbdf3
type ARexp = String -> [Int]
Packit 2cbdf3
--      in ap_ar, eps_ar, ch_ar, seq_ar, bar_ar
Packit 2cbdf3
Packit 2cbdf3
ap_ar:: ARexp -> String -> [Int]
Packit 2cbdf3
ap_ar sc = sc
Packit 2cbdf3
Packit 2cbdf3
eps_ar:: ARexp
Packit 2cbdf3
eps_ar inp = [0]
Packit 2cbdf3
Packit 2cbdf3
ch_ar:: (Char->Bool) -> ARexp
Packit 2cbdf3
ch_ar p "" = []
Packit 2cbdf3
ch_ar p (c:rst) = if p c then [1] else []
Packit 2cbdf3
Packit 2cbdf3
seq_ar:: ARexp -> ARexp -> ARexp
Packit 2cbdf3
seq_ar sc sc' inp = [n+m| n<-sc inp, m<-sc' (drop n inp)]
Packit 2cbdf3
Packit 2cbdf3
bar_ar:: ARexp -> ARexp -> ARexp
Packit 2cbdf3
bar_ar sc sc' inp = sc inp ++ sc' inp
Packit 2cbdf3
-}
Packit 2cbdf3
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
-- Utils
Packit 2cbdf3
Packit 2cbdf3
-- Map the available start codes onto [1..]
Packit 2cbdf3
Packit 2cbdf3
encodeStartCodes:: Scanner -> (Scanner,[StartCode],ShowS)
Packit 2cbdf3
encodeStartCodes scan = (scan', 0 : map snd name_code_pairs, sc_hdr)
Packit 2cbdf3
        where
Packit 2cbdf3
        scan' = scan{ scannerTokens = map mk_re_ctx (scannerTokens scan) }
Packit 2cbdf3
Packit 2cbdf3
        mk_re_ctx (RECtx scs lc re rc code)
Packit 2cbdf3
          = RECtx (map mk_sc scs) lc re rc code
Packit 2cbdf3
Packit 2cbdf3
        mk_sc (nm,_) = (nm, if nm=="0" then 0
Packit 2cbdf3
                                       else fromJust (Map.lookup nm code_map))
Packit 2cbdf3
Packit 2cbdf3
        sc_hdr tl =
Packit 2cbdf3
                case name_code_pairs of
Packit 2cbdf3
                  [] -> tl
Packit 2cbdf3
                  (nm,_):rst -> "\n" ++ nm ++ foldr f t rst
Packit 2cbdf3
                        where
Packit 2cbdf3
                        f (nm', _) t' = "," ++ nm' ++ t'
Packit 2cbdf3
                        t = " :: Int\n" ++ foldr fmt_sc tl name_code_pairs
Packit 2cbdf3
                where
Packit 2cbdf3
                fmt_sc (nm,sc) t = nm ++ " = " ++ show sc ++ "\n" ++ t
Packit 2cbdf3
Packit 2cbdf3
        code_map = Map.fromList name_code_pairs
Packit 2cbdf3
Packit 2cbdf3
        name_code_pairs = zip (nub' (<=) nms) [1..]
Packit 2cbdf3
Packit 2cbdf3
        nms = [nm | RECtx{reCtxStartCodes = scs} <- scannerTokens scan,
Packit 2cbdf3
                    (nm,_) <- scs, nm /= "0"]
Packit 2cbdf3
Packit 2cbdf3
Packit 2cbdf3
-- Grab the code fragments for the token actions, and replace them
Packit 2cbdf3
-- with function names of the form alex_action_$n$.  We do this
Packit 2cbdf3
-- because the actual action fragments might be duplicated in the
Packit 2cbdf3
-- generated file.
Packit 2cbdf3
Packit 2cbdf3
extractActions :: Scheme -> Scanner -> (Scanner,ShowS)
Packit 2cbdf3
extractActions scheme scanner = (scanner{scannerTokens = new_tokens}, decl_str)
Packit 2cbdf3
 where
Packit 2cbdf3
  (new_tokens, decls) = unzip (zipWith f (scannerTokens scanner) act_names)
Packit 2cbdf3
Packit 2cbdf3
  f r@RECtx{ reCtxCode = Just code } name
Packit 2cbdf3
        = (r{reCtxCode = Just name}, Just (mkDecl name code))
Packit 2cbdf3
  f r@RECtx{ reCtxCode = Nothing } _
Packit 2cbdf3
        = (r{reCtxCode = Nothing}, Nothing)
Packit 2cbdf3
Packit 2cbdf3
  gscanActionType res =
Packit 2cbdf3
      str "AlexPosn -> Char -> String -> Int -> ((Int, state) -> "
Packit 2cbdf3
    . str res . str ") -> (Int, state) -> " . str res
Packit 2cbdf3
Packit 2cbdf3
  mkDecl fun code = case scheme of
Packit 2cbdf3
    Default { defaultTypeInfo = Just (Nothing, actionty) } ->
Packit 2cbdf3
        str fun . str " :: " . str actionty . str "\n"
Packit 2cbdf3
      . str fun . str " = " . str code . nl
Packit 2cbdf3
    Default { defaultTypeInfo = Just (Just tyclasses, actionty) } ->
Packit 2cbdf3
      str fun . str " :: (" . str tyclasses . str ") => " .
Packit 2cbdf3
      str actionty . str "\n" .
Packit 2cbdf3
      str fun . str " = " . str code . nl
Packit 2cbdf3
    GScan { gscanTypeInfo = Just (Nothing, tokenty) } ->
Packit 2cbdf3
        str fun . str " :: " . gscanActionType tokenty . str "\n"
Packit 2cbdf3
      . str fun . str " = " . str code . nl
Packit 2cbdf3
    GScan { gscanTypeInfo = Just (Just tyclasses, tokenty) } ->
Packit 2cbdf3
      str fun . str " :: (" . str tyclasses . str ") => " .
Packit 2cbdf3
      gscanActionType tokenty . str "\n" .
Packit 2cbdf3
      str fun . str " = " . str code . nl
Packit 2cbdf3
    Basic { basicStrType = strty, basicTypeInfo = Just (Nothing, tokenty) } ->
Packit 2cbdf3
      str fun . str " :: " . str (show strty) . str " -> "
Packit 2cbdf3
      . str tokenty . str "\n"
Packit 2cbdf3
      . str fun . str " = " . str code . nl
Packit 2cbdf3
    Basic { basicStrType = strty,
Packit 2cbdf3
            basicTypeInfo = Just (Just tyclasses, tokenty) } ->
Packit 2cbdf3
      str fun . str " :: (" . str tyclasses . str ") => " .
Packit 2cbdf3
      str (show strty) . str " -> " . str tokenty . str "\n" .
Packit 2cbdf3
      str fun . str " = " . str code . nl
Packit 2cbdf3
    Posn { posnByteString = isByteString,
Packit 2cbdf3
           posnTypeInfo = Just (Nothing, tokenty) } ->
Packit 2cbdf3
      str fun . str " :: AlexPosn -> " . str (strtype isByteString) . str " -> "
Packit 2cbdf3
      . str tokenty . str "\n"
Packit 2cbdf3
      . str fun . str " = " . str code . nl
Packit 2cbdf3
    Posn { posnByteString = isByteString,
Packit 2cbdf3
           posnTypeInfo = Just (Just tyclasses, tokenty) } ->
Packit 2cbdf3
      str fun . str " :: (" . str tyclasses . str ") => AlexPosn -> " .
Packit 2cbdf3
      str (strtype isByteString) . str " -> " . str tokenty . str "\n" .
Packit 2cbdf3
      str fun . str " = " . str code . nl
Packit 2cbdf3
    Monad { monadByteString = isByteString,
Packit 2cbdf3
            monadTypeInfo = Just (Nothing, tokenty) } ->
Packit 2cbdf3
      let
Packit 2cbdf3
        actintty = if isByteString then "Int64" else "Int"
Packit 2cbdf3
      in
Packit 2cbdf3
        str fun . str " :: AlexInput -> " . str actintty . str " -> Alex ("
Packit 2cbdf3
      . str tokenty . str ")\n"
Packit 2cbdf3
      . str fun . str " = " . str code . nl
Packit 2cbdf3
    Monad { monadByteString = isByteString,
Packit 2cbdf3
            monadTypeInfo = Just (Just tyclasses, tokenty) } ->
Packit 2cbdf3
      let
Packit 2cbdf3
        actintty = if isByteString then "Int64" else "Int"
Packit 2cbdf3
      in
Packit 2cbdf3
        str fun . str " :: (" . str tyclasses . str ") => "
Packit 2cbdf3
      . str " AlexInput -> " . str actintty
Packit 2cbdf3
      . str " -> Alex (" . str tokenty . str ")\n"
Packit 2cbdf3
      . str fun . str " = " . str code . nl
Packit 2cbdf3
    _ -> str fun . str " = " . str code . nl
Packit 2cbdf3
Packit 2cbdf3
  act_names = map (\n -> "alex_action_" ++ show (n::Int)) [0..]
Packit 2cbdf3
Packit 2cbdf3
  decl_str = foldr (.) id [ decl | Just decl <- decls ]
Packit 2cbdf3
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
-- Code generation targets
Packit 2cbdf3
Packit 2cbdf3
data Target = GhcTarget | HaskellTarget