{-# LANGUAGE DeriveGeneric #-}

module Scrappy.Grep.DSL
  ( ParserExpr(..)
  , MatchResult(..)
  , containsRef
  , extractRefs
  ) where

import GHC.Generics (Generic)

-- | AST representation of the parsec-grep DSL
data ParserExpr
  -- Primitives
  = PChar Char              -- char 'x'
  | PString String          -- string "abc"
  | PAnyChar                -- anyChar
  | PDigit                  -- digit
  | PLetter                 -- letter
  | PAlphaNum               -- alphaNum
  | PSpace                  -- space
  | PSpaces                 -- spaces
  | PNewline                -- newline
  | POneOf String           -- oneOf "abc"
  | PNoneOf String          -- noneOf "abc"

  -- Combinators
  | PSeq ParserExpr ParserExpr       -- p1 >> p2 (sequence, return second)
  | PSeqConcat ParserExpr ParserExpr -- p1 <+> p2 (sequence, concatenate results)
  | PAlt ParserExpr ParserExpr       -- p1 <|> p2 (alternative)
  | PMany ParserExpr                 -- many p (zero or more)
  | PSome ParserExpr                 -- some p (one or more)
  | POptional ParserExpr             -- optional p (zero or one)
  | PTry ParserExpr                  -- try p (backtracking)
  | PBetween Char Char ParserExpr    -- between '(' ')' p
  | PCount Int ParserExpr            -- count 3 p
  | PManyTill ParserExpr ParserExpr  -- manyTill p end (non-greedy)

  -- References to named parsers (from config file)
  | PRef String                      -- ref "email"
  deriving (Int -> ParserExpr -> ShowS
[ParserExpr] -> ShowS
ParserExpr -> String
(Int -> ParserExpr -> ShowS)
-> (ParserExpr -> String)
-> ([ParserExpr] -> ShowS)
-> Show ParserExpr
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ParserExpr -> ShowS
showsPrec :: Int -> ParserExpr -> ShowS
$cshow :: ParserExpr -> String
show :: ParserExpr -> String
$cshowList :: [ParserExpr] -> ShowS
showList :: [ParserExpr] -> ShowS
Show, ParserExpr -> ParserExpr -> Bool
(ParserExpr -> ParserExpr -> Bool)
-> (ParserExpr -> ParserExpr -> Bool) -> Eq ParserExpr
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ParserExpr -> ParserExpr -> Bool
== :: ParserExpr -> ParserExpr -> Bool
$c/= :: ParserExpr -> ParserExpr -> Bool
/= :: ParserExpr -> ParserExpr -> Bool
Eq, (forall x. ParserExpr -> Rep ParserExpr x)
-> (forall x. Rep ParserExpr x -> ParserExpr) -> Generic ParserExpr
forall x. Rep ParserExpr x -> ParserExpr
forall x. ParserExpr -> Rep ParserExpr x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ParserExpr -> Rep ParserExpr x
from :: forall x. ParserExpr -> Rep ParserExpr x
$cto :: forall x. Rep ParserExpr x -> ParserExpr
to :: forall x. Rep ParserExpr x -> ParserExpr
Generic)

-- | A match result with position information
data MatchResult = MatchResult
  { MatchResult -> String
mrFilePath  :: FilePath
  , MatchResult -> Int
mrLine      :: Int       -- Starting line (1-indexed)
  , MatchResult -> Int
mrCol       :: Int       -- Starting column (1-indexed)
  , MatchResult -> String
mrMatchText :: String    -- The matched text (may contain newlines)
  } deriving (Int -> MatchResult -> ShowS
[MatchResult] -> ShowS
MatchResult -> String
(Int -> MatchResult -> ShowS)
-> (MatchResult -> String)
-> ([MatchResult] -> ShowS)
-> Show MatchResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MatchResult -> ShowS
showsPrec :: Int -> MatchResult -> ShowS
$cshow :: MatchResult -> String
show :: MatchResult -> String
$cshowList :: [MatchResult] -> ShowS
showList :: [MatchResult] -> ShowS
Show, MatchResult -> MatchResult -> Bool
(MatchResult -> MatchResult -> Bool)
-> (MatchResult -> MatchResult -> Bool) -> Eq MatchResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MatchResult -> MatchResult -> Bool
== :: MatchResult -> MatchResult -> Bool
$c/= :: MatchResult -> MatchResult -> Bool
/= :: MatchResult -> MatchResult -> Bool
Eq, (forall x. MatchResult -> Rep MatchResult x)
-> (forall x. Rep MatchResult x -> MatchResult)
-> Generic MatchResult
forall x. Rep MatchResult x -> MatchResult
forall x. MatchResult -> Rep MatchResult x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. MatchResult -> Rep MatchResult x
from :: forall x. MatchResult -> Rep MatchResult x
$cto :: forall x. Rep MatchResult x -> MatchResult
to :: forall x. Rep MatchResult x -> MatchResult
Generic)

-- | Check if a ParserExpr contains any PRef nodes
containsRef :: ParserExpr -> Bool
containsRef :: ParserExpr -> Bool
containsRef ParserExpr
expr = case ParserExpr
expr of
  PRef String
_           -> Bool
True
  PSeq ParserExpr
a ParserExpr
b         -> ParserExpr -> Bool
containsRef ParserExpr
a Bool -> Bool -> Bool
|| ParserExpr -> Bool
containsRef ParserExpr
b
  PSeqConcat ParserExpr
a ParserExpr
b   -> ParserExpr -> Bool
containsRef ParserExpr
a Bool -> Bool -> Bool
|| ParserExpr -> Bool
containsRef ParserExpr
b
  PAlt ParserExpr
a ParserExpr
b         -> ParserExpr -> Bool
containsRef ParserExpr
a Bool -> Bool -> Bool
|| ParserExpr -> Bool
containsRef ParserExpr
b
  PMany ParserExpr
a          -> ParserExpr -> Bool
containsRef ParserExpr
a
  PSome ParserExpr
a          -> ParserExpr -> Bool
containsRef ParserExpr
a
  POptional ParserExpr
a      -> ParserExpr -> Bool
containsRef ParserExpr
a
  PTry ParserExpr
a           -> ParserExpr -> Bool
containsRef ParserExpr
a
  PBetween Char
_ Char
_ ParserExpr
a   -> ParserExpr -> Bool
containsRef ParserExpr
a
  PCount Int
_ ParserExpr
a       -> ParserExpr -> Bool
containsRef ParserExpr
a
  PManyTill ParserExpr
a ParserExpr
b    -> ParserExpr -> Bool
containsRef ParserExpr
a Bool -> Bool -> Bool
|| ParserExpr -> Bool
containsRef ParserExpr
b
  ParserExpr
_                -> Bool
False

-- | Extract all ref names from a ParserExpr
extractRefs :: ParserExpr -> [String]
extractRefs :: ParserExpr -> [String]
extractRefs ParserExpr
expr = case ParserExpr
expr of
  PRef String
name        -> [String
name]
  PSeq ParserExpr
a ParserExpr
b         -> ParserExpr -> [String]
extractRefs ParserExpr
a [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ ParserExpr -> [String]
extractRefs ParserExpr
b
  PSeqConcat ParserExpr
a ParserExpr
b   -> ParserExpr -> [String]
extractRefs ParserExpr
a [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ ParserExpr -> [String]
extractRefs ParserExpr
b
  PAlt ParserExpr
a ParserExpr
b         -> ParserExpr -> [String]
extractRefs ParserExpr
a [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ ParserExpr -> [String]
extractRefs ParserExpr
b
  PMany ParserExpr
a          -> ParserExpr -> [String]
extractRefs ParserExpr
a
  PSome ParserExpr
a          -> ParserExpr -> [String]
extractRefs ParserExpr
a
  POptional ParserExpr
a      -> ParserExpr -> [String]
extractRefs ParserExpr
a
  PTry ParserExpr
a           -> ParserExpr -> [String]
extractRefs ParserExpr
a
  PBetween Char
_ Char
_ ParserExpr
a   -> ParserExpr -> [String]
extractRefs ParserExpr
a
  PCount Int
_ ParserExpr
a       -> ParserExpr -> [String]
extractRefs ParserExpr
a
  PManyTill ParserExpr
a ParserExpr
b    -> ParserExpr -> [String]
extractRefs ParserExpr
a [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ ParserExpr -> [String]
extractRefs ParserExpr
b
  ParserExpr
_                -> []