content: {-# LANGUAGE LambdaCase #-}
  -- | @since 1.4.2
  
  module Test.Tasty.Patterns.Printer
    ( printAwkExpr
    )
    where
  
  import Prelude hiding (LT, GT, EQ)
  import Test.Tasty.Patterns.Types
  
  -- | @since 1.4.2
  printAwkExpr :: Expr -> String
  printAwkExpr e = go 0 e ""
  
  go :: Int -> Expr -> ShowS
  go p = \case
    NF -> showString "NF"
    IntLit n -> showsPrec p n
    StringLit xs -> showChar '"' . showString (escapeString xs) . showChar '"'
    ERE xs -> showChar '/' . showString (escapeERE xs) . showChar '/'
  
    Field x -> showParen (p >= 9) $ showChar '$' . go 9 x
  
    -- Cf. comment for Test.Tasty.Patterns.Parser.expr2 to understand
    -- why we put showParens when precedence is 6 not 8.
    Neg x -> showParen (p >= 6) $ showChar '-' . go 8 x
    Not x -> showParen (p >= 8) $ showChar '!' . go 8 x
  
    Add x y -> showParen (p >= 7) $ go 7 x . showChar '+' . go 7 y
    Sub x y -> showParen (p >= 7) $ go 7 x . showChar '-' . go 7 y
  
    Concat x y -> showParen (p >= 6) $ go 6 x . showChar ' ' . go 6 y
  
    LT x y -> showParen (p >= 5) $ go 5 x . showChar '<'    . go 5 y
    LE x y -> showParen (p >= 5) $ go 5 x . showString "<=" . go 5 y
    GT x y -> showParen (p >= 5) $ go 5 x . showChar '>'    . go 5 y
    GE x y -> showParen (p >= 5) $ go 5 x . showString ">=" . go 5 y
    EQ x y -> showParen (p >= 5) $ go 5 x . showString "==" . go 5 y
    NE x y -> showParen (p >= 5) $ go 5 x . showString "!=" . go 5 y
  
    Match x y   -> showParen (p >= 4) $ go 4 x . showChar '~'    . go 4 (ERE y)
    NoMatch x y -> showParen (p >= 4) $ go 4 x . showString "!~" . go 4 (ERE y)
  
    And x y -> showParen (p >= 2) $ go 2 x . showString "&&" . go 2 y
  
    Or x y -> showParen (p >= 1) $ go 1 x . showString "||" . go 1 y
  
    If c t f -> showParen (p >= 0) $ go 0 c . showChar '?' . go 0 t . showChar ':' . go 0 f
  
    ToUpperFn x -> showString "toupper(" . go 0 x . showChar ')'
    ToLowerFn x -> showString "tolower(" . go 0 x . showChar ')'
  
    LengthFn Nothing  -> showString "length()"
    LengthFn (Just x) -> showString "length(" . go 0 x . showChar ')'
  
    SubstrFn x y Nothing  -> showString "substr(" . go 0 x . showChar ',' . go 0 y . showChar ')'
    SubstrFn x y (Just z) -> showString "substr(" . go 0 x . showChar ',' . go 0 y . showChar ',' . go 0 z . showChar ')'
  
    MatchFn x y -> showString "match(" . go 0 x . showChar ',' . go 0 (ERE y) . showChar ')'
  
  escapeString :: String -> String
  escapeString = concatMap $ \c -> (if c `elem` "\\\"" then ('\\' :) else id) [c]
  
  escapeERE :: String -> String
  escapeERE = concatMap $ \c -> (if c `elem` "\\/" then ('\\' :) else id) [c]
  