{-# LANGUAGE OverloadedStrings #-}
module Ormolu.Processing.Cpp
( cppLines,
)
where
import Data.Char (isSpace)
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
import qualified Data.List as L
import Data.Maybe (isJust)
data State
=
Outside
|
InConditional Int
|
InContinuation
deriving (State -> State -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: State -> State -> Bool
$c/= :: State -> State -> Bool
== :: State -> State -> Bool
$c== :: State -> State -> Bool
Eq, Key -> State -> ShowS
[State] -> ShowS
State -> String
forall a.
(Key -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [State] -> ShowS
$cshowList :: [State] -> ShowS
show :: State -> String
$cshow :: State -> String
showsPrec :: Key -> State -> ShowS
$cshowsPrec :: Key -> State -> ShowS
Show)
cppLines :: String -> IntSet
cppLines :: String -> IntSet
cppLines String
input = [Key] -> IntSet
IntSet.fromAscList forall a b. (a -> b) -> a -> b
$ forall {a}. State -> [(String, a)] -> [a]
go State
Outside (String -> [String]
lines String
input forall a b. [a] -> [b] -> [(a, b)]
`zip` [Key
1 ..])
where
go :: State -> [(String, a)] -> [a]
go State
_ [] = []
go State
state ((String
line, a
i) : [(String, a)]
ls)
| forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any String -> Bool
for [String
"define ", String
"include ", String
"undef "] =
a
i forall a. a -> [a] -> [a]
: State -> [(String, a)] -> [a]
go State
contState [(String, a)]
ls
| forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any String -> Bool
for [String
"ifdef ", String
"ifndef ", String
"if "] =
let state' :: State
state' = case State
state of
InConditional Key
nc -> Key -> State
InConditional (Key
nc forall a. Num a => a -> a -> a
+ Key
1)
State
_ -> Key -> State
InConditional Key
1
in a
i forall a. a -> [a] -> [a]
: State -> [(String, a)] -> [a]
go State
state' [(String, a)]
ls
| String -> Bool
for String
"endif" =
let state' :: State
state' = case State
state of
InConditional Key
nc | Key
nc forall a. Ord a => a -> a -> Bool
> Key
1 -> Key -> State
InConditional (Key
nc forall a. Num a => a -> a -> a
- Key
1)
State
_ -> State
Outside
in a
i forall a. a -> [a] -> [a]
: State -> [(String, a)] -> [a]
go State
state' [(String, a)]
ls
| Bool
otherwise =
let is :: [a]
is = case State
state of
State
Outside -> []
State
_ -> [a
i]
state' :: State
state' = case State
state of
State
InContinuation -> State
contState
State
_ -> State
state
in [a]
is forall a. Semigroup a => a -> a -> a
<> State -> [(String, a)] -> [a]
go State
state' [(String, a)]
ls
where
for :: String -> Bool
for String
directive = forall a. Maybe a -> Bool
isJust forall a b. (a -> b) -> a -> b
$ do
String
s <- forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Eq a => [a] -> [a] -> Maybe [a]
L.stripPrefix String
"#" String
line
forall a. Eq a => [a] -> [a] -> Maybe [a]
L.stripPrefix String
directive String
s
contState :: State
contState =
if String
"\\" forall a. Eq a => [a] -> [a] -> Bool
`L.isSuffixOf` String
line Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
inConditional
then State
InContinuation
else State
Outside
where
inConditional :: Bool
inConditional = case State
state of
InConditional {} -> Bool
True
State
_ -> Bool
False