alex 3.4.0.0 → 3.4.0.1
raw patch · 22 files changed
+290/−461 lines, 22 filesdep ~base
Dependency ranges changed: base
Files
- CHANGELOG.md +9/−0
- alex.cabal +42/−39
- src/AbsSyn.hs +20/−17
- src/CharSet.hs +37/−22
- src/DFA.hs +19/−62
- src/DFAMin.hs +39/−32
- src/DFS.hs +2/−3
- src/Data/Ranged/RangedSet.hs +9/−19
- src/Info.hs +1/−1
- src/Main.hs +18/−50
- src/Map.hs +0/−68
- src/NFA.hs +10/−14
- src/Output.hs +14/−12
- src/ParseMonad.hs +21/−20
- src/Parser.hs +1/−1
- src/Parser.y.boot +1/−1
- src/Scan.hs +16/−9
- src/Scan.x.boot +15/−8
- src/Set.hs +0/−15
- src/Sort.hs +0/−58
- src/UTF8.hs +11/−5
- tests/Makefile +5/−5
CHANGELOG.md view
@@ -1,3 +1,12 @@+## Changes in 3.4.0.1++ * Address new `x-partial` warning of GHC 9.8.+ * Alex 3.4.0.1 needs GHC 8.0 or higher to build.+ The code it generates is the same as 3.4.0.0, so it will likely work for older GHCs.+ * Tested with GHC 8.0 - 9.8.1.++_Andreas Abel, 2023-10-29_+ ## Changes in 3.4.0.0 * New wrappers to lex strict `Text`:
alex.cabal view
@@ -1,6 +1,6 @@ cabal-version: >= 1.10 name: alex-version: 3.4.0.0+version: 3.4.0.1 -- don't forget updating changelog.md! license: BSD3 license-file: LICENSE@@ -22,8 +22,9 @@ build-type: Simple tested-with:- GHC == 9.6.2- GHC == 9.4.5+ GHC == 9.8.1+ GHC == 9.6.3+ GHC == 9.4.7 GHC == 9.2.8 GHC == 9.0.2 GHC == 8.10.7@@ -32,11 +33,6 @@ GHC == 8.4.4 GHC == 8.2.2 GHC == 8.0.2- GHC == 7.10.3- GHC == 7.8.4- GHC == 7.6.3- GHC == 7.4.2- GHC == 7.0.4 data-dir: data/ @@ -104,39 +100,46 @@ hs-source-dirs: src main-is: Main.hs - build-depends: base >= 2.1 && < 5- , array- , containers- , directory-- default-language: Haskell98- default-extensions: CPP- other-extensions: MagicHash+ build-depends:+ base >= 4.9 && < 5+ -- Data.List.NonEmpty enters `base` at 4.9+ , array+ , containers+ , directory - ghc-options: -Wall -rtsopts+ default-language:+ Haskell2010+ default-extensions:+ PatternSynonyms+ ScopedTypeVariables+ TupleSections+ other-extensions:+ CPP+ FlexibleContexts+ MagicHash+ NondecreasingIndentation+ OverloadedLists+ ghc-options: -Wall -Wcompat -rtsopts other-modules:- AbsSyn- CharSet- DFA- DFAMin- DFS- Info- Map- NFA- Output- Paths_alex- Parser- ParseMonad- Scan- Set- Sort- Util- UTF8- Data.Ranged- Data.Ranged.Boundaries- Data.Ranged.RangedSet- Data.Ranged.Ranges+ AbsSyn+ CharSet+ DFA+ DFAMin+ DFS+ Info+ NFA+ Output+ Paths_alex+ Parser+ ParseMonad+ Scan+ Util+ UTF8+ Data.Ranged+ Data.Ranged.Boundaries+ Data.Ranged.RangedSet+ Data.Ranged.Ranges test-suite tests type: exitcode-stdio-1.0@@ -144,6 +147,6 @@ -- This line is important as it ensures that the local `exe:alex` component declared above is built before the test-suite component is invoked, as well as making sure that `alex` is made available on $PATH and `$alex_datadir` is set accordingly before invoking `test.hs` build-tools: alex - default-language: Haskell98+ default-language: Haskell2010 build-depends: base, process
src/AbsSyn.hs view
@@ -23,16 +23,15 @@ StrType(..) ) where -import CharSet ( CharSet, Encoding )-import Map ( Map )-import qualified Map hiding ( Map )-import Data.IntMap (IntMap)-import Sort ( nub' )-import Util ( str, nl )--import Data.Maybe ( fromJust )+import CharSet ( CharSet, Encoding )+import Data.Maybe ( fromJust )+import Data.Map ( Map )+import Data.IntMap ( IntMap )+import Util ( str, nl )+import qualified Data.Map as Map+import qualified Data.Set as Set -infixl 4 :|+infixl 4 :|| infixl 5 :%% -- -----------------------------------------------------------------------------@@ -200,7 +199,7 @@ -- `RExp' provides an abstract syntax for regular expressions. `Eps' will -- match empty strings; `Ch p' matches strings containing a single character -- `c' if `p c' is true; `re1 :%% re2' matches a string if `re1' matches one of--- its prefixes and `re2' matches the rest; `re1 :| re2' matches a string if+-- its prefixes and `re2' matches the rest; `re1 :|| re2' matches a string if -- `re1' or `re2' matches it; `Star re', `Plus re' and `Ques re' can be -- expressed in terms of the other operators. See the definitions of `ARexp' -- for a formal definition of the semantics of these operators.@@ -209,7 +208,7 @@ = Eps -- ^ Empty. | Ch CharSet -- ^ Singleton. | RExp :%% RExp -- ^ Sequence.- | RExp :| RExp -- ^ Alternative.+ | RExp :|| RExp -- ^ Alternative. | Star RExp -- ^ Zero or more repetitions. | Plus RExp -- ^ One or more repetitions. | Ques RExp -- ^ Zero or one repetitions.@@ -218,7 +217,7 @@ showsPrec _ Eps = showString "()" showsPrec _ (Ch _) = showString "[..]" showsPrec _ (l :%% r) = shows l . shows r- showsPrec _ (l :| r) = shows l . ('|':) . shows r+ showsPrec _ (l :|| r) = shows l . ('|':) . shows r showsPrec _ (Star r) = shows r . ('*':) showsPrec _ (Plus r) = shows r . ('+':) showsPrec _ (Ques r) = shows r . ('?':)@@ -228,7 +227,7 @@ nullable Eps = True nullable Ch{} = False nullable (l :%% r) = nullable l && nullable r-nullable (l :| r) = nullable l || nullable r+nullable (l :|| r) = nullable l || nullable r nullable Star{} = True nullable (Plus r) = nullable r nullable Ques{} = True@@ -264,7 +263,7 @@ arexp Eps = eps_ar arexp (Ch p) = ch_ar p arexp (re :%% re') = arexp re `seq_ar` arexp re'-arexp (re :| re') = arexp re `bar_ar` arexp re'+arexp (re :|| re') = arexp re `bar_ar` arexp re' arexp (Star re) = star_ar (arexp re) arexp (Plus re) = plus_ar (arexp re) arexp (Ques re) = ques_ar (arexp re)@@ -330,10 +329,14 @@ code_map = Map.fromList name_code_pairs - name_code_pairs = zip (nub' (<=) nms) [1..]+ name_code_pairs = zip nms [1..] - nms = [nm | RECtx{reCtxStartCodes = scs} <- scannerTokens scan,- (nm,_) <- scs, nm /= "0"]+ nms = Set.toAscList . Set.fromList $+ [ nm+ | RECtx{ reCtxStartCodes = scs } <- scannerTokens scan+ , (nm, _) <- scs+ , nm /= "0"+ ] -- Grab the code fragments for the token actions, and replace them
src/CharSet.hs view
@@ -10,6 +10,8 @@ -- -- ----------------------------------------------------------------------------} +{-# LANGUAGE OverloadedLists #-}+ module CharSet ( setSingleton, @@ -36,19 +38,30 @@ byteSetElem ) where -import Data.Array-import Data.Ranged-import Data.Word-import Data.Maybe (catMaybes)-import Data.Char (chr,ord)-import UTF8+import Data.Array ( Array, array )+import Data.Char ( chr, ord )+import Data.Maybe ( catMaybes )+import Data.Word ( Word8 )+import Data.List.NonEmpty ( pattern (:|), (<|) )+import qualified Data.List.NonEmpty as List1 +import UTF8 ( List1, encode )+import Data.Ranged+ ( Boundary( BoundaryAbove, BoundaryAboveAll, BoundaryBelow, BoundaryBelowAll )+ , DiscreteOrdered, Range( Range ), RSet+ , makeRangedSet+ , rSetDifference, rSetEmpty, rSetHas, rSetNegation, rSetRanges, rSetUnion, rSingleton+ )++-- import Data.Semigroup (sconcat)+-- import qualified Data.Foldable as Fold+ type Byte = Word8 -- Implementation as functions type CharSet = RSet Char type ByteSet = RSet Byte -- type Utf8Set = RSet [Byte]-type Utf8Range = Span [Byte]+type Utf8Range = Span (List1 Byte) data Encoding = Latin1 | UTF8 deriving (Eq, Show)@@ -83,16 +96,19 @@ charSetRange :: Char -> Char -> CharSet charSetRange c1 c2 = makeRangedSet [Range (BoundaryBelow c1) (BoundaryAbove c2)] +{-# INLINE bytes #-}+bytes :: [Byte]+bytes = [minBound..maxBound]+ byteSetToArray :: ByteSet -> Array Byte Bool-byteSetToArray set = array (fst (head ass), fst (last ass)) ass- where ass = [(c,rSetHas set c) | c <- [0..0xff]]+byteSetToArray set = array (minBound, maxBound) [(c, rSetHas set c) | c <- bytes] byteSetElems :: ByteSet -> [Byte]-byteSetElems set = [c | c <- [0 .. 0xff], rSetHas set c]+byteSetElems set = filter (rSetHas set) bytes charToRanges :: Encoding -> CharSet -> [Utf8Range] charToRanges Latin1 =- map (fmap ((: []).fromIntegral.ord)) -- Span [Byte]+ map (fmap ((:| []) . fromIntegral . ord)) -- Span [Byte] . catMaybes . fmap (charRangeToCharSpan False) . rSetRanges@@ -105,20 +121,20 @@ . rSetRanges -- | Turns a range of characters expressed as a pair of UTF-8 byte sequences into a set of ranges, in which each range of the resulting set is between pairs of sequences of the same length-toUtfRange :: Span [Byte] -> [Span [Byte]]-toUtfRange (Span x y) = fix x y+toUtfRange :: Span (List1 Byte) -> [Span (List1 Byte)]+toUtfRange (Span x y) = List1.toList $ fix x y -fix :: [Byte] -> [Byte] -> [Span [Byte]]+fix :: List1 Byte -> List1 Byte -> List1 (Span (List1 Byte)) fix x y | length x == length y = [Span x y]- | length x == 1 = Span x [0x7F] : fix [0xC2,0x80] y- | length x == 2 = Span x [0xDF,0xBF] : fix [0xE0,0x80,0x80] y- | length x == 3 = Span x [0xEF,0xBF,0xBF] : fix [0xF0,0x80,0x80,0x80] y+ | length x == 1 = Span x [0x7F] <| fix [0xC2,0x80] y+ | length x == 2 = Span x [0xDF,0xBF] <| fix [0xE0,0x80,0x80] y+ | length x == 3 = Span x [0xEF,0xBF,0xBF] <| fix [0xF0,0x80,0x80,0x80] y | otherwise = error "fix: incorrect input given" -byteRangeToBytePair :: Span [Byte] -> ([Byte],[Byte])-byteRangeToBytePair (Span x y) = (x,y)+byteRangeToBytePair :: Span a -> (a, a)+byteRangeToBytePair (Span x y) = (x, y) data Span a = Span a a -- lower bound inclusive, higher bound exclusive -- (SDM: upper bound inclusive, surely?)@@ -143,8 +159,8 @@ BoundaryAboveAll | uni -> chr 0x10ffff | otherwise -> chr 0xff -byteRanges :: Encoding -> CharSet -> [([Byte],[Byte])]-byteRanges enc = fmap byteRangeToBytePair . charToRanges enc+byteRanges :: Encoding -> CharSet -> [(List1 Byte, List1 Byte)]+byteRanges enc = fmap byteRangeToBytePair . charToRanges enc byteSetRange :: Byte -> Byte -> ByteSet byteSetRange c1 c2 = makeRangedSet [Range (BoundaryBelow c1) (BoundaryAbove c2)]@@ -164,4 +180,3 @@ quoteH (BoundaryBelow a) = "c < " ++ show a quoteH (BoundaryAboveAll) = "True" quoteH (BoundaryBelowAll) = "False"-
src/DFA.hs view
@@ -13,18 +13,21 @@ -- -- ----------------------------------------------------------------------------} -module DFA(scanner2dfa) where+module DFA (scanner2dfa) where -import AbsSyn-import qualified Map+import Data.Array ( (!) )+import Data.Function ( on )+import Data.Maybe ( fromJust )+ import qualified Data.IntMap as IntMap+import qualified Data.IntSet as IntSet+import qualified Data.Map as Map+import qualified Data.List as List++import AbsSyn import NFA-import Sort ( msort, nub' ) import CharSet -import Data.Array ( (!) )-import Data.Maybe ( fromJust )- {- Defined in the Scan Module -- (This section should logically belong to the DFA module but it has been@@ -128,23 +131,20 @@ | Acc _ _ _ (RightContextRExp s) <- accs ] outs :: [(ByteSet,SNum)]- outs = [ out | s <- ss, out <- nst_outs (nfa!s) ]+ outs = [ out | s <- ss, out <- nst_outs (nfa ! s) ] - accs = sort_accs [acc| s<-ss, acc<-nst_accs (nfa!s)]+ accs = sort_accs [ acc | s <- ss, acc <- nst_accs (nfa ! s) ] -- `sort_accs' sorts a list of accept values into descending order of priority, -- eliminating any elements that follow an unconditional accept value. -sort_accs:: [Accept a] -> [Accept a]-sort_accs accs = foldr chk [] (msort le accs)+sort_accs :: [Accept a] -> [Accept a]+sort_accs accs = foldr chk [] $ List.sortBy (compare `on` accPrio) accs where chk acc@(Acc _ _ Nothing NoRightContext) _ = [acc] chk acc rst = acc:rst - le (Acc{accPrio = n}) (Acc{accPrio=n'}) = n<=n' -- {------------------------------------------------------------------------------ State Sets and Partial DFAs ------------------------------------------------------------------------------}@@ -160,19 +160,17 @@ type StateSet = [SNum] -new_pdfa:: Int -> NFA -> DFA StateSet a+new_pdfa :: Int -> NFA -> DFA StateSet a new_pdfa starts nfa- = DFA { dfa_start_states = start_ss,- dfa_states = Map.empty+ = DFA { dfa_start_states = [ List.sort $ nst_cl $ nfa ! n | n <- [0 .. starts - 1] ]+ , dfa_states = Map.empty }- where- start_ss = [ msort (<=) (nst_cl(nfa!n)) | n <- [0..(starts-1)]] -- starts is the number of start states -- constructs the epsilon-closure of a set of NFA states-mk_ss:: NFA -> [SNum] -> StateSet-mk_ss nfa l = nub' (<=) [s'| s<-l, s'<-nst_cl(nfa!s)]+mk_ss :: NFA -> [SNum] -> StateSet+mk_ss nfa l = IntSet.toAscList $ IntSet.fromList [ s' | s <- l, s' <- nst_cl (nfa ! s) ] add_pdfa:: StateSet -> State StateSet a -> DFA StateSet a -> DFA StateSet a add_pdfa ss pst (DFA st mp) = DFA st (Map.insert ss pst mp)@@ -205,44 +203,3 @@ RightContextRExp s -> RightContextRExp (lookup' (mk_ss nfa [s])) other -> other--{----- `mk_st' constructs a state node from the list of accept values and a list of--- transitions. The transitions list all the valid transitions out of the--- node; all invalid transitions should be represented in the array by state--- -1. `mk_st' has to work out whether the accept states contain an--- unconditional entry, in which case the first field of `St' should be true,--- and which default state to use in constructing the array (the array may span--- a sub-range of the character set, the state number given the third argument--- of `St' being taken as the default if an input character lies outside the--- range). The default values is chosen to minimise the bounds of the array--- and so there are two candidates: the value that 0 maps to (in which case--- some initial segment of the array may be omitted) or the value that 255 maps--- to (in which case a final segment of the array may be omitted), hence the--- calculation of `(df,bds)'.------ Note that empty arrays are avoided as they can cause severe problems for--- some popular Haskell compilers.--mk_st:: [Accept Code] -> [(Char,Int)] -> State Code-mk_st accs as =- if null as- then St accs (-1) (listArray ('0','0') [-1])- else St accs df (listArray bds [arr!c| c<-range bds])- where- bds = if sz==0 then ('0','0') else bds0-- (sz,df,bds0) | sz1 < sz2 = (sz1,df1,bds1)- | otherwise = (sz2,df2,bds2)-- (sz1,df1,bds1) = mk_bds(arr!chr 0)- (sz2,df2,bds2) = mk_bds(arr!chr 255)-- mk_bds df = (t-b, df, (chr b, chr (255-t)))- where- b = length (takeWhile id [arr!c==df| c<-['\0'..'\xff']])- t = length (takeWhile id [arr!c==df| c<-['\xff','\xfe'..'\0']])-- arr = listArray ('\0','\xff') (take 256 (repeat (-1))) // as--}
src/DFAMin.hs view
@@ -1,21 +1,23 @@ {-# OPTIONS_GHC -fno-warn-name-shadowing #-} -{-# LANGUAGE PatternGuards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}+{-# LANGUAGE CPP #-} module DFAMin (minimizeDFA) where import AbsSyn -import Data.Map (Map)-import qualified Data.Map as Map-import Data.IntSet (IntSet)-import qualified Data.IntSet as IS-import Data.IntMap (IntMap)-import qualified Data.IntMap as IM-import qualified Data.List as List+import Data.IntMap ( IntMap )+import Data.IntSet ( IntSet )+import Data.Map ( Map )+#if !MIN_VERSION_containers(0,6,0)+import Data.Maybe ( mapMaybe )+#endif +import qualified Data.Map as Map+import qualified Data.IntSet as IntSet+import qualified Data.IntMap as IntMap+import qualified Data.List as List+ -- % Hopcroft's Algorithm for DFA minimization (cut/pasted from Wikipedia): -- % X refines Y into Y1 and Y2 means -- % Y1 := Y ∩ X@@ -82,7 +84,7 @@ number :: Int -> [EquivalenceClass] -> [(Int, EquivalenceClass)] number _ [] = [] number n (ss:sss) =- case filter (`IS.member` ss) starts of+ case filter (`IntSet.member` ss) starts of [] -> (n,ss) : number (n+1) sss starts' -> map (,ss) starts' ++ number n sss -- if one of the states of the minimized DFA corresponds@@ -91,12 +93,12 @@ states :: [(Int, State Int a)] states = [- let old_states = map (lookup statemap) (IS.toList equiv)- accs = map fix_acc (state_acc (head old_states))+ let old_states = map (lookup statemap) (IntSet.toList equiv)+ accs = map fix_acc (state_acc (headWithDefault undefined old_states)) -- accepts should all be the same- out = IM.fromList [ (b, get_new old)+ out = IntMap.fromList [ (b, get_new old) | State _ out <- old_states,- (b,old) <- IM.toList out ]+ (b,old) <- IntMap.toList out ] in (n, State accs out) | (n, equiv) <- numbered_states ]@@ -116,7 +118,7 @@ old_to_new :: Map Int Int old_to_new = Map.fromList [ (s,n) | (n,ss) <- numbered_states,- s <- IS.toList ss ]+ s <- IntSet.toList ss ] type EquivalenceClass = IntSet @@ -129,7 +131,7 @@ where acc (State as _) = not (List.null as) nonaccepting_states :: EquivalenceClass- nonaccepting_states = IS.fromList (Map.keys nonaccepting)+ nonaccepting_states = IntSet.fromList (Map.keys nonaccepting) -- group the accepting states into equivalence classes accept_map :: Map [Accept a] [Int]@@ -139,11 +141,11 @@ (Map.toList accepting) accept_groups :: [EquivalenceClass]- accept_groups = map IS.fromList (Map.elems accept_map)+ accept_groups = map IntSet.fromList (Map.elems accept_map) init_r, init_q :: [EquivalenceClass] init_r -- Issue #71: each EquivalenceClass needs to be a non-empty set- | IS.null nonaccepting_states = []+ | IntSet.null nonaccepting_states = [] | otherwise = [nonaccepting_states] init_q = accept_groups @@ -155,10 +157,10 @@ -- since a transition function might not be an injective. -- This is a cache of the information needed to compute xs below bigmap :: IntMap (IntMap EquivalenceClass)- bigmap = IM.fromListWith (IM.unionWith IS.union)- [ (i, IM.singleton to (IS.singleton from))+ bigmap = IntMap.fromListWith (IntMap.unionWith IntSet.union)+ [ (i, IntMap.singleton to (IntSet.singleton from)) | (from, state) <- Map.toList statemap,- (i,to) <- IM.toList (state_out state) ]+ (i,to) <- IntMap.toList (state_out state) ] -- The outer loop: recurse on each set in R and Q go :: [EquivalenceClass] -> [EquivalenceClass] -> [EquivalenceClass]@@ -168,18 +170,18 @@ preimage :: IntMap EquivalenceClass -- inversed transition function -> EquivalenceClass -- subset of codomain of original transition function -> EquivalenceClass -- preimage of given subset-#if MIN_VERSION_containers(0, 6, 0)- preimage invMap a = IS.unions (IM.restrictKeys invMap a)+#if MIN_VERSION_containers(0,6,0)+ preimage invMap = IntSet.unions . IntMap.restrictKeys invMap #else- preimage invMap a = IS.unions [IM.findWithDefault IS.empty s invMap | s <- IS.toList a]+ preimage invMap = IntSet.unions . mapMaybe (`IntMap.lookup` invMap) . IntSet.toList #endif xs :: [EquivalenceClass] xs = [ x- | invMap <- IM.elems bigmap+ | invMap <- IntMap.elems bigmap , let x = preimage invMap a- , not (IS.null x)+ , not (IntSet.null x) ] refineWith@@ -187,12 +189,12 @@ -> EquivalenceClass -- input equivalence class -> Maybe (EquivalenceClass, EquivalenceClass) -- refined equivalence class refineWith x y =- if IS.null y1 || IS.null y2+ if IntSet.null y1 || IntSet.null y2 then Nothing else Just (y1, y2) where- y1 = IS.intersection y x- y2 = IS.difference y x+ y1 = IntSet.intersection y x+ y2 = IntSet.difference y x go0 (r,q) x = go1 r [] [] where@@ -201,11 +203,16 @@ go1 (y:r) r' q' = case refineWith x y of Nothing -> go1 r (y:r') q' Just (y1, y2)- | IS.size y1 <= IS.size y2 -> go1 r (y2:r') (y1:q')- | otherwise -> go1 r (y1:r') (y2:q')+ | IntSet.size y1 <= IntSet.size y2 -> go1 r (y2:r') (y1:q')+ | otherwise -> go1 r (y1:r') (y2:q') -- iterates over Q go2 [] q' = q' go2 (y:q) q' = case refineWith x y of Nothing -> go2 q (y:q') Just (y1, y2) -> go2 q (y1:y2:q')++-- To pacify GHC 9.8's warning about 'head'+headWithDefault :: a -> [a] -> a+headWithDefault a [] = a+headWithDefault _ (a:_) = a
src/DFS.hs view
@@ -23,10 +23,9 @@ module DFS where -import Set ( Set )-import qualified Set hiding ( Set )- import Data.Array ( (!), accumArray, listArray )+import Data.Set ( Set )+import qualified Data.Set as Set -- The result of a depth-first search of a graph is a list of trees, -- `GForest'. `post_order' provides a post-order traversal of a forest.
src/Data/Ranged/RangedSet.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CPP #-}+ module Data.Ranged.RangedSet ( -- ** Ranged Set Type RSet,@@ -27,13 +29,11 @@ import Data.Ranged.Boundaries import Data.Ranged.Ranges-#if MIN_VERSION_base(4,9,0) && !MIN_VERSION_base(4,11,0)+#if !MIN_VERSION_base(4,11,0) import Data.Semigroup-#elif !MIN_VERSION_base(4,9,0)-import Data.Monoid #endif -import Data.List hiding (and, null)+import qualified Data.List as List infixl 7 -/\- infixl 6 -\/-, -!-@@ -44,35 +44,25 @@ newtype DiscreteOrdered v => RSet v = RSet {rSetRanges :: [Range v]} deriving (Eq, Show, Ord) -#if MIN_VERSION_base(4,9,0) instance DiscreteOrdered a => Semigroup (RSet a) where (<>) = rSetUnion-#endif instance DiscreteOrdered a => Monoid (RSet a) where-#if MIN_VERSION_base(4,9,0)+ mempty = rSetEmpty mappend = (<>)-#else- mappend = rSetUnion-#endif- mempty = rSetEmpty -- | Determine if the ranges in the list are both in order and non-overlapping. -- If so then they are suitable input for the unsafeRangedSet function. validRangeList :: DiscreteOrdered v => [Range v] -> Bool--validRangeList [] = True-validRangeList [Range lower upper] = lower <= upper-validRangeList rs = and $ zipWith okAdjacent rs (tail rs)- where- okAdjacent (Range lower1 upper1) (Range lower2 upper2) =- lower1 <= upper1 && upper1 <= lower2 && lower2 <= upper2+validRangeList rs = and $+ all (\ (Range lower upper) -> lower <= upper) rs :+ zipWith (\ (Range _ upper1) (Range lower2 _) -> upper1 <= lower2) rs (drop 1 rs) -- | Rearrange and merge the ranges in the list so that they are in order and -- non-overlapping. normaliseRangeList :: DiscreteOrdered v => [Range v] -> [Range v]-normaliseRangeList = normalise . sort . filter (not . rangeIsEmpty)+normaliseRangeList = normalise . List.sort . filter (not . rangeIsEmpty) -- Private routine: normalise a range list that is known to be already sorted.
src/Info.hs view
@@ -11,7 +11,7 @@ module Info (infoDFA) where import AbsSyn-import qualified Map+import qualified Data.Map as Map import qualified Data.IntMap as IntMap import Util
src/Main.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE NondecreasingIndentation #-}+ -- ----------------------------------------------------------------------------- -- -- Main.hs, part of Alex@@ -15,56 +16,39 @@ import DFAMin import NFA import Info-import Map ( Map )-import qualified Map hiding ( Map ) import Output-import ParseMonad ( runP, Warning(..) )+import ParseMonad ( runP, Warning(..) ) import Parser import Scan-import Util ( hline )-import Paths_alex ( version, getDataDir )+import Util ( hline )+import Paths_alex ( version, getDataDir ) -#if __GLASGOW_HASKELL__ < 610-import Control.Exception as Exception ( block, unblock, catch, throw )-#endif-#if __GLASGOW_HASKELL__ >= 610-import Control.Exception ( bracketOnError )-#endif-import Control.Monad ( when, liftM )-import Data.Char ( chr )-import Data.List ( isSuffixOf, nub )-import Data.Version ( showVersion )+import Control.Exception ( bracketOnError )+import Control.Monad ( when, liftM )+import Data.Char ( chr )+import Data.List ( isSuffixOf, nub )+import Data.Map ( Map )+import Data.Version ( showVersion ) import System.Console.GetOpt ( getOpt, usageInfo, ArgOrder(..), OptDescr(..), ArgDescr(..) )-import System.Directory ( removeFile )-import System.Environment ( getProgName, getArgs )-import System.Exit ( ExitCode(..), exitWith )-import System.IO ( stderr, Handle, IOMode(..), openFile, hClose, hPutStr, hPutStrLn )-#if __GLASGOW_HASKELL__ >= 612-import System.IO ( hGetContents, hSetEncoding, utf8 )-#endif+import System.Directory ( removeFile )+import System.Environment ( getProgName, getArgs )+import System.Exit ( ExitCode(..), exitWith )+import System.IO ( stderr, Handle, IOMode(..), openFile, hClose, hPutStr, hPutStrLn+ , hGetContents, hSetEncoding, utf8 )+import qualified Data.Map as Map -- We need to force every file we open to be read in -- as UTF8 alexReadFile :: FilePath -> IO String-#if __GLASGOW_HASKELL__ >= 612-alexReadFile file = do- h <- alexOpenFile file ReadMode- hGetContents h-#else-alexReadFile = readFile-#endif+alexReadFile file = hGetContents =<< alexOpenFile file ReadMode -- We need to force every file we write to be written -- to as UTF8 alexOpenFile :: FilePath -> IOMode -> IO Handle-#if __GLASGOW_HASKELL__ >= 612 alexOpenFile file mode = do h <- openFile file mode hSetEncoding h utf8 return h-#else-alexOpenFile = openFile-#endif -- `main' decodes the command line arguments and calls `alex'. @@ -521,19 +505,3 @@ dieAlex :: String -> IO a dieAlex s = getProgramName >>= \prog -> die (prog ++ ": " ++ s)--#if __GLASGOW_HASKELL__ < 610-bracketOnError- :: IO a -- ^ computation to run first (\"acquire resource\")- -> (a -> IO b) -- ^ computation to run last (\"release resource\")- -> (a -> IO c) -- ^ computation to run in-between- -> IO c -- returns the value from the in-between computation-bracketOnError before after thing =- block (do- a <- before- r <- Exception.catch- (unblock (thing a))- (\e -> do { after a; throw e })- return r- )-#endif
− src/Map.hs
@@ -1,68 +0,0 @@-{-# LANGUAGE CPP #-}-module Map (- Map,- member, lookup, findWithDefault,- empty,- insert, insertWith,- delete,- union, unionWith, unions,- mapWithKey,- elems,- fromList, fromListWith,- toAscList-) where--#if __GLASGOW_HASKELL__ >= 603-import Data.Map-import Prelude ()-#else-import Data.FiniteMap-import Prelude hiding ( lookup )--type Map k a = FiniteMap k a--member :: Ord k => k -> Map k a -> Bool-member = elemFM--lookup :: Ord k => k -> Map k a -> Maybe a-lookup = flip lookupFM--findWithDefault :: Ord k => a -> k -> Map k a -> a-findWithDefault a k m = lookupWithDefaultFM m a k--empty :: Map k a-empty = emptyFM--insert :: Ord k => k -> a -> Map k a -> Map k a-insert k a m = addToFM m k a--insertWith :: Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a-insertWith c k a m = addToFM_C c m k a--delete :: Ord k => k -> Map k a -> Map k a-delete = flip delFromFM--union :: Ord k => Map k a -> Map k a -> Map k a-union = flip plusFM--unionWith :: Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a-unionWith c l r = plusFM_C c r l--unions :: Ord k => [Map k a] -> Map k a-unions = foldl (flip plusFM) emptyFM--mapWithKey :: (k -> a -> b) -> Map k a -> Map k b-mapWithKey = mapFM--elems :: Map k a -> [a]-elems = eltsFM--fromList :: Ord k => [(k,a)] -> Map k a-fromList = listToFM--fromListWith :: Ord k => (a -> a -> a) -> [(k,a)] -> Map k a-fromListWith c = addListToFM_C (flip c) emptyFM--toAscList :: Map k a -> [(k,a)]-toAscList = fmToList-#endif
src/NFA.hs view
@@ -16,18 +16,17 @@ module NFA where +import Control.Monad ( forM_, zipWithM, zipWithM_, when, liftM, ap )+import Data.Array ( Array, (!), array, listArray, assocs, bounds )+import Data.Map ( Map )+import qualified Data.Map as Map+import qualified Data.List.NonEmpty as List1+ import AbsSyn import CharSet-import DFS ( t_close, out )-import Map ( Map )-import qualified Map hiding ( Map )+import DFS ( t_close, out ) import Util ( str, space ) -#if __GLASGOW_HASKELL__ < 710-import Control.Applicative ( Applicative(..) )-#endif-import Control.Monad ( forM_, zipWithM, zipWithM_, when, liftM, ap )-import Data.Array ( Array, (!), array, listArray, assocs, bounds ) -- Each state of a nondeterministic automaton contains a list of `Accept' -- values, a list of epsilon transitions (an epsilon transition represents a@@ -132,7 +131,7 @@ s <- newState rexp2nfa b s re1 rexp2nfa s e re2-rexp2nfa b e (re1 :| re2) = do+rexp2nfa b e (re1 :|| re2) = do rexp2nfa b e re1 rexp2nfa b e re2 rexp2nfa b e (Star re) = do@@ -226,10 +225,8 @@ charEdge from charset to = do -- trace ("charEdge: " ++ (show $ charset) ++ " => " ++ show (byteRanges charset)) $ e <- getEncoding- forM_ (byteRanges e charset) $ \(xs,ys) -> do- bytesEdge from xs ys to--+ forM_ (byteRanges e charset) $ \ (xs, ys) -> do+ bytesEdge from (List1.toList xs) (List1.toList ys) to byteEdge :: SNum -> ByteSet -> SNum -> NFAM () byteEdge from charset to = N $ \s n _ -> (s, addEdge n, ())@@ -260,7 +257,6 @@ Map.insert state (NSt [new_acc] [] []) n Just (NSt acc eps trans) -> Map.insert state (NSt (new_acc:acc) eps trans) n- rctxt_accept :: Accept Code rctxt_accept = Acc 0 Nothing Nothing NoRightContext
src/Output.hs view
@@ -13,7 +13,7 @@ import AbsSyn import CharSet import Util-import qualified Map+import qualified Data.Map as Map import qualified Data.IntMap as IntMap import Control.Monad.ST ( ST, runST )@@ -24,7 +24,8 @@ import Data.Maybe (isJust) import Data.Bits import Data.Char ( ord, chr )-import Data.List ( maximumBy, sortBy, groupBy, mapAccumR )+import Data.List ( maximumBy, sortBy, mapAccumR )+import qualified Data.List.NonEmpty as List1 -- ----------------------------------------------------------------------------- -- Printing the output@@ -399,10 +400,10 @@ best_default :: [(Int,SNum)] -> SNum best_default prod_list | null sorted = -1- | otherwise = snd (head (maximumBy lengths eq))+ | otherwise = snd (List1.head (maximumBy lengths eq)) where sorted = sortBy compareSnds prod_list compareSnds (_,a) (_,b) = compare a b- eq = groupBy (\(_,a) (_,b) -> a == b) sorted+ eq = List1.groupBy (\(_,a) (_,b) -> a == b) sorted lengths a b = length a `compare` length b -- remove all the default productions from the DFA@@ -493,18 +494,19 @@ -> [(Int, Int)] -> ST s Int findFreeOffset off check off_arr state = do- -- offset 0 isn't allowed++ -- offset 0 isn't allowed if off == 0 then try_next else do -- don't use an offset we've used before- b <- readArray off_arr off- if b /= 0 then try_next else do+ b <- readArray off_arr off+ if b /= 0 then try_next else do - -- check whether the actions for this state fit in the table- ok <- fits off state check- if ok then return off else try_next- where- try_next = findFreeOffset (off+1) check off_arr state+ -- check whether the actions for this state fit in the table+ ok <- fits off state check+ if ok then return off else try_next+ where+ try_next = findFreeOffset (off+1) check off_arr state -- This is an inner loop, so we use some strictness hacks, and avoid -- array bounds checks (unsafeRead instead of readArray) to speed
src/ParseMonad.hs view
@@ -14,17 +14,16 @@ setStartCode, getStartCode, getInput, setInput, ) where -import AbsSyn hiding ( StartCode )-import CharSet ( CharSet )-import Map ( Map )-import qualified Map hiding ( Map )+import Control.Monad ( liftM, ap, when )+import Data.Map ( Map )+import Data.List.NonEmpty ( pattern (:|) )+import Data.Word ( Word8 )+import qualified Data.Map as Map++import AbsSyn hiding ( StartCode )+import CharSet ( CharSet ) import UTF8 -#if __GLASGOW_HASKELL__ < 710-import Control.Applicative ( Applicative(..) )-#endif-import Control.Monad ( liftM, ap, when )-import Data.Word (Word8) -- ----------------------------------------------------------------------------- -- The input type --import Codec.Binary.UTF8.Light as UTF8@@ -40,18 +39,20 @@ alexInputPrevChar (_,c,_,_) = c -alexGetChar :: AlexInput -> Maybe (Char,AlexInput)-alexGetChar (_,_,[],[]) = Nothing-alexGetChar (p,_,[],(c:s)) = let p' = alexMove p c in p' `seq`- Just (c, (p', c, [], s))-alexGetChar (_, _ ,_ : _, _) = undefined -- hide compiler warning+alexGetChar :: AlexInput -> Maybe (Char, AlexInput)+alexGetChar (_, _, [], []) = Nothing+alexGetChar (p, _, [], c:s) = p' `seq` Just (c, (p', c, [], s))+ where+ p' = alexMove p c+alexGetChar (_, _ , _:_, _) = undefined -- hide compiler warning -alexGetByte :: AlexInput -> Maybe (Byte,AlexInput)-alexGetByte (p,c,(b:bs),s) = Just (b,(p,c,bs,s))-alexGetByte (_,_,[],[]) = Nothing-alexGetByte (p,_,[],(c:s)) = let p' = alexMove p c- (b:bs) = UTF8.encode c- in p' `seq` Just (b, (p', c, bs, s))+alexGetByte :: AlexInput -> Maybe (Byte, AlexInput)+alexGetByte (p, c, b:bs, s) = Just (b, (p, c, bs, s))+alexGetByte (_, _, [], []) = Nothing+alexGetByte (p, _, [], c:s) = p' `seq` Just (b, (p', c, bs, s))+ where+ p' = alexMove p c+ b :| bs = UTF8.encode c -- ----------------------------------------------------------------------------- -- Token positions
src/Parser.hs view
@@ -724,7 +724,7 @@ = case happyOut24 happy_x_1 of { (HappyWrap24 happy_var_1) -> case happyOut23 happy_x_3 of { (HappyWrap23 happy_var_3) -> happyIn23- (happy_var_1 :| happy_var_3+ (happy_var_1 :|| happy_var_3 )}} happyReduce_41 :: () => Happy_GHC_Exts.Int# -> Token -> Happy_GHC_Exts.Int# -> Happy_IntList -> HappyStk (HappyAbsSyn ) -> P (HappyAbsSyn )
src/Parser.y.boot view
@@ -159,7 +159,7 @@ | {- empty -} { NoRightContext } rexp :: { RExp }- : alt '|' rexp { $1 :| $3 }+ : alt '|' rexp { $1 :|| $3 } | alt { $1 } alt :: { RExp }
src/Scan.hs view
@@ -2,11 +2,18 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE MagicHash #-} {-# LINE 13 "src/Scan.x" #-}+{-# LANGUAGE CPP #-}++-- Switch off partiality warning about 'head' and 'tail'+#if __GLASGOW_HASKELL__ >= 908+{-# OPTIONS_GHC -Wno-x-partial #-}+#endif+ module Scan (lexer, AlexPosn(..), Token(..), Tkn(..), tokPosn, multiplicity) where import Data.Char import ParseMonad---import Debug.Trace+-- import Debug.Trace #if __GLASGOW_HASKELL__ >= 603 #include "ghcconfig.h" #elif defined(__GLASGOW_HASKELL__)@@ -546,7 +553,7 @@ -- match when checking the right context, just -- the first match will do. #endif-{-# LINE 84 "src/Scan.x" #-}+{-# LINE 91 "src/Scan.x" #-} -- ----------------------------------------------------------------------------- -- Token type @@ -587,7 +594,7 @@ string (p,_,str) ln = return $ T p (StringT (extract ln str)) bind (p,_,str) _ = return $ T p (BindT (takeWhile isIdChar str)) escape (p,_,str) _ = return $ T p (CharT (esc str))-decch (p,_,str) ln = return $ T p (CharT (do_ech 10 ln (take (ln-1) (tail str))))+decch (p,_,str) ln = return $ T p (CharT (do_ech 10 ln (take (ln-1) (drop 1 str)))) hexch (p,_,str) ln = return $ T p (CharT (do_ech 16 ln (take (ln-2) (drop 2 str)))) octch (p,_,str) ln = return $ T p (CharT (do_ech 8 ln (take (ln-2) (drop 2 str)))) char (p,_,str) _ = return $ T p (CharT (head str))@@ -607,7 +614,7 @@ isIdChar c = isAlphaNum c || c `elem` "_'" extract :: Int -> String -> String-extract ln str = take (ln-2) (tail str)+extract ln str = take (ln-2) (drop 1 str) do_ech :: Int -> Int -> String -> Char do_ech radix _ln str = chr (parseInt radix str)@@ -640,7 +647,7 @@ -- implementing a large chunk of the Haskell lexical syntax). code :: Action-code (p,_,_inp) _ = do+code (p, _, _inp) _ = do currentInput <- getInput go currentInput 1 "" where@@ -686,10 +693,10 @@ lexError :: String -> P a lexError s = do- (_,_,_,input) <- getInput- failP (s ++ (if (not (null input))- then " at " ++ show (head input)- else " at end of file"))+ (_, _, _, input) <- getInput+ failP $ s ++ " at " ++ case input of+ c:_ -> show c+ [] -> "end of file" lexer :: (Token -> P a) -> P a lexer cont = lexToken >>= cont
src/Scan.x.boot view
@@ -11,11 +11,18 @@ ------------------------------------------------------------------------------- {+{-# LANGUAGE CPP #-}++-- Switch off partiality warning about 'head' and 'tail'+#if __GLASGOW_HASKELL__ >= 908+{-# OPTIONS_GHC -Wno-x-partial #-}+#endif+ module Scan (lexer, AlexPosn(..), Token(..), Tkn(..), tokPosn, multiplicity) where import Data.Char import ParseMonad---import Debug.Trace+-- import Debug.Trace } $digit = 0-9@@ -123,7 +130,7 @@ string (p,_,str) ln = return $ T p (StringT (extract ln str)) bind (p,_,str) _ = return $ T p (BindT (takeWhile isIdChar str)) escape (p,_,str) _ = return $ T p (CharT (esc str))-decch (p,_,str) ln = return $ T p (CharT (do_ech 10 ln (take (ln-1) (tail str))))+decch (p,_,str) ln = return $ T p (CharT (do_ech 10 ln (take (ln-1) (drop 1 str)))) hexch (p,_,str) ln = return $ T p (CharT (do_ech 16 ln (take (ln-2) (drop 2 str)))) octch (p,_,str) ln = return $ T p (CharT (do_ech 8 ln (take (ln-2) (drop 2 str)))) char (p,_,str) _ = return $ T p (CharT (head str))@@ -143,7 +150,7 @@ isIdChar c = isAlphaNum c || c `elem` "_'" extract :: Int -> String -> String-extract ln str = take (ln-2) (tail str)+extract ln str = take (ln-2) (drop 1 str) do_ech :: Int -> Int -> String -> Char do_ech radix _ln str = chr (parseInt radix str)@@ -176,7 +183,7 @@ -- implementing a large chunk of the Haskell lexical syntax). code :: Action-code (p,_,_inp) _ = do+code (p, _, _inp) _ = do currentInput <- getInput go currentInput 1 "" where@@ -222,10 +229,10 @@ lexError :: String -> P a lexError s = do- (_,_,_,input) <- getInput- failP (s ++ (if (not (null input))- then " at " ++ show (head input)- else " at end of file"))+ (_, _, _, input) <- getInput+ failP $ s ++ " at " ++ case input of+ c:_ -> show c+ [] -> "end of file" lexer :: (Token -> P a) -> P a lexer cont = lexToken >>= cont
− src/Set.hs
@@ -1,15 +0,0 @@-{-# LANGUAGE CPP #-}-module Set ( Set, member, empty, insert ) where--import Data.Set--#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 603-member :: Ord a => a -> Set a -> Bool-member = elementOf--empty :: Set a-empty = emptySet--insert :: Ord a => a -> Set a -> Set a-insert = flip addToSet-#endif
− src/Sort.hs
@@ -1,58 +0,0 @@-{------------------------------------------------------------------------------- SORTING LISTS--This module provides a properly parameterised merge sort function, complete-with associated functions. It is based on a Bob Buckley's (Bob Buckley-18-AUG-95) coding of Knuth's natural merge sort (see Vol. 2). It seems to be-fast in the average case; it makes use of natural runs in the data becomming-linear on ordered data; and it completes in worst time O(n.log(n)). It is-divinely elegant.--`nub'' is an n.log(n) version of `nub' and `group_sort' sorts a list into-strictly ascending order, using a combining function in its arguments to-amalgamate duplicates.--Chris Dornan, 14-Aug-93, 17-Nov-94, 29-Dec-95-------------------------------------------------------------------------------}--module Sort where---- Hide (<=) so that we don't get name shadowing warnings for it-import Prelude hiding ((<=))--msort :: (a->a->Bool) -> [a] -> [a]-msort _ [] = [] -- (foldb f []) is undefined-msort (<=) xs = foldb (mrg (<=)) (runs (<=) xs)--runs :: (a->a->Bool) -> [a] -> [[a]]-runs (<=) xs0 = foldr op [] xs0- where- op z xss@(xs@(x:_):xss') | z<=x = (z:xs):xss'- | otherwise = [z]:xss- op z xss = [z]:xss--foldb :: (a->a->a) -> [a] -> a-foldb _ [x] = x-foldb f xs0 = foldb f (fold xs0)- where- fold (x1:x2:xs) = f x1 x2 : fold xs- fold xs = xs--mrg:: (a->a->Bool) -> [a] -> [a] -> [a]-mrg _ [] l = l-mrg _ l@(_:_) [] = l-mrg (<=) l1@(h1:t1) l2@(h2:t2) =- if h1<=h2- then h1:mrg (<=) t1 l2- else h2:mrg (<=) l1 t2---nub':: (a->a->Bool) -> [a] -> [a]-nub' (<=) l = group_sort (<=) const l---group_sort:: (a->a->Bool) -> (a->[a]->b) -> [a] -> [b]-group_sort le cmb l = s_m (msort le l)- where- s_m [] = []- s_m (h:t) = cmb h (takeWhile (`le` h) t):s_m (dropWhile (`le` h) t)
src/UTF8.hs view
@@ -1,9 +1,15 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedLists #-}+ module UTF8 where -import Data.Word-import Data.Bits-import Data.Char+import Data.Word ( Word8 )+import Data.Bits ( (.&.), shiftR )+import Data.Char ( ord ) +import qualified Data.List.NonEmpty as List1+type List1 = List1.NonEmpty+ {- -- Could also be imported: @@ -15,8 +21,8 @@ -} -- | Encode a Haskell String to a list of Word8 values, in UTF8 format.-encode :: Char -> [Word8]-encode = map fromIntegral . go . ord+encode :: Char -> List1 Word8+encode = fmap fromIntegral . go . ord where go oc | oc <= 0x7f = [oc]
tests/Makefile view
@@ -32,14 +32,14 @@ GHC_VERSION_WORDS=$(subst ., ,$(GHC_VERSION)) GHC_MAJOR_VERSION=$(word 1,$(GHC_VERSION_WORDS)) GHC_MINOR_VERSION=$(word 2,$(GHC_VERSION_WORDS))+ # Text dependency comes with GHC from 8.4 onwards GHC_SHIPS_WITH_TEXT:=$(shell if [ $(GHC_MAJOR_VERSION) -gt 8 -o $(GHC_MAJOR_VERSION) -ge 8 -a $(GHC_MINOR_VERSION) -ge 4 ]; then echo "yes"; else echo "no"; fi)-# -fwarn-incomplete-uni-patterns only from 7.4-WARNS_FOR_GHC_GTEQ_7_4=-fwarn-incomplete-uni-patterns-WARNS_FOR_GHC_LT_7_4=-fno-warn-lazy-unlifted-bindings-WARNS_DEP_GHC_GTEQ_7_4:=$(shell if [ $(GHC_MAJOR_VERSION) -gt 7 -o $(GHC_MAJOR_VERSION) -ge 7 -a $(GHC_MINOR_VERSION) -ge 4 ]; then echo "$(WARNS_FOR_GHC_GTEQ_7_4)"; else echo "$(WARNS_FOR_GHC_LT_7_4)"; fi) -HC_OPTS=-Wall $(WARNS_DEP_GHC_GTEQ_7_4) -fno-warn-missing-signatures -fno-warn-unused-imports -fno-warn-tabs -Werror+# Turn off x-partial warning (new in GHC 9.8)+WARNS_DEP_GHC_GTEQ_9_8:=$(shell if [ $(GHC_MAJOR_VERSION) -gt 9 -o $(GHC_MAJOR_VERSION) -ge 9 -a $(GHC_MINOR_VERSION) -ge 8 ]; then echo "-Wno-x-partial"; fi)++HC_OPTS=-Wall $(WARNS_DEP_GHC_GTEQ_9_8) -fwarn-incomplete-uni-patterns -fno-warn-missing-signatures -fno-warn-unused-imports -fno-warn-tabs -Werror .PRECIOUS: %.n.hs %.g.hs %.o %.exe %.bin