content: module BNFC.Backend.Java.RegToAntlrLexer (printRegJLex, escapeCharInSingleQuotes) where
  
  -- modified from RegToJLex.hs
  
  import Data.Char (ord)
  import Numeric (showHex)
  
  import BNFC.Abs
  
  -- the top-level printing method
  printRegJLex :: Reg -> String
  printRegJLex = render . prt 0
  
  -- you may want to change render and parenth
  
  render :: [String] -> String
  render = rend (0 :: Int) where
    rend i ss = case ss of
      "["      :ts -> cons "["  $ rend i ts
      "("      :ts -> cons "("  $ rend i ts
      t  : "," :ts -> cons t    $ space "," $ rend i ts
      t  : ")" :ts -> cons t    $ cons ")"  $ rend i ts
      t  : "]" :ts -> cons t    $ cons "]"  $ rend i ts
      t        :ts -> space t   $ rend i ts
      _            -> ""
    cons s t  = s ++ t
    space t s = if null s then t else t ++ s
  
  parenth :: [String] -> [String]
  parenth ss = ["("] ++ ss ++ [")"]
  
  -- the printer class does the job
  class Print a where
    prt :: Int -> a -> [String]
  
  -- | Print char according to ANTLR regex format.
  escapeChar :: [Char] -> Char -> String
  escapeChar reserved x
    | x `elem` reserved  = '\\' : [x]
    | i >= 65536         = "\\u{" ++ h ++ "}"
    | i >= 256 || i < 32 = "\\u" ++ replicate (4 - length h) '0' ++ h
    | otherwise          = [x]  -- issue #329, don't escape in the usual way!
    where
    i = ord x
    h = showHex i ""
  
  -- | Escape character for use inside single quotes.
  escapeCharInSingleQuotes :: Char -> String
  escapeCharInSingleQuotes = escapeChar ['\'','\\']
  
  -- The ANTLR definition of what can be in a [char set] is here:
  -- https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md#lexer-rule-elements
  -- > The following escaped characters are interpreted as single special characters:
  -- > \n, \r, \b, \t, \f, \uXXXX, and \u{XXXXXX}.
  -- > To get ], \, or - you must escape them with \.
  
  -- | Escape character for use inside @[char set]@.
  escapeInCharSet :: Char -> String
  escapeInCharSet = escapeChar [ ']', '\\', '-' ]
  
  prPrec :: Int -> Int -> [String] -> [String]
  prPrec i j = if j<i then parenth else id
  
  instance Print Identifier where
    prt _ (Identifier (_, i)) = [i]
  
  instance Print Reg where
    prt i e = case e of
     RSeq reg0 reg
                -> prPrec i 2 (concat [prt 2 reg0 , [" "], prt 3 reg])
     RAlt reg0 reg
                -> prPrec i 1 (concat [prt 1 reg0 , ["|"] , prt 2 reg])
     RMinus reg0 REps -> prt i reg0 -- REps is identity for set difference
     RMinus RAny (RChar c)
                -> ["~'", escapeCharInSingleQuotes c, "'"]
     RMinus RAny (RAlts str)
                -> concat [["~["], map escapeInCharSet str ,["]"]]
     RMinus _ _ -> error "Antlr does not support general set difference"
     RStar reg  -> concat [prt 3 reg , ["*"]]
     RPlus reg  -> concat [prt 3 reg , ["+"]]
     ROpt reg   -> concat [prt 3 reg , ["?"]]
     REps       -> [""]
     RChar c    -> ["'", escapeCharInSingleQuotes c, "'"]
     RAlts str  -> concat [ ["["], map escapeInCharSet str, ["]"] ]
     RSeqs str  -> prPrec i 2 $ map show str
     RDigit     -> ["DIGIT"]
     RLetter    -> ["LETTER"]
     RUpper     -> ["CAPITAL"]
     RLower     -> ["SMALL"]
     RAny       -> ["[\\u0000-\\u00FF]"]
  