{- This module was generated from data in the Kate syntax
   highlighting file verilog.xml, version 1.09, by Yevgen Voronenko (ysv22@drexel.edu), Ryan Dalzell (ryan@tullyroan.com) -}

module Text.Highlighting.Kate.Syntax.Verilog
          (highlight, parseExpression, syntaxName, syntaxExtensions)
where
import Text.Highlighting.Kate.Types
import Text.Highlighting.Kate.Common
import qualified Text.Highlighting.Kate.Syntax.Alert
import Text.ParserCombinators.Parsec hiding (State)
import Control.Monad.State
import Data.Char (isSpace)
import qualified Data.Set as Set

-- | Full name of language.
syntaxName :: String
syntaxName = "Verilog"

-- | Filename extensions for this language.
syntaxExtensions :: String
syntaxExtensions = "*.v;*.V;*.vl"

-- | Highlight source code using this syntax definition.
highlight :: String -> [SourceLine]
highlight input = evalState (mapM parseSourceLine $ lines input) startingState

parseSourceLine :: String -> State SyntaxState SourceLine
parseSourceLine = mkParseSourceLine (parseExpression Nothing)

-- | Parse an expression using appropriate local context.
parseExpression :: Maybe (String,String)
                -> KateParser Token
parseExpression mbcontext = do
  (lang,cont) <- maybe currentContext return mbcontext
  result <- parseRules (lang,cont)
  optional $ do eof
                updateState $ \st -> st{ synStPrevChar = '\n' }
                pEndLine
  return result

startingState = SyntaxState {synStContexts = [("Verilog","Normal")], synStLineNumber = 0, synStPrevChar = '\n', synStPrevNonspace = False, synStContinuation = False, synStCaseSensitive = True, synStKeywordCaseSensitive = True, synStCaptures = []}

pEndLine = do
  updateState $ \st -> st{ synStPrevNonspace = False }
  context <- currentContext
  contexts <- synStContexts `fmap` getState
  st <- getState
  if length contexts >= 2
    then case context of
      _ | synStContinuation st -> updateState $ \st -> st{ synStContinuation = False }
      ("Verilog","Normal") -> return ()
      ("Verilog","String") -> (popContext) >> pEndLine
      ("Verilog","Commentar 1") -> (popContext) >> pEndLine
      ("Verilog","Commentar 2") -> return ()
      ("Verilog","Preprocessor") -> (popContext) >> pEndLine
      ("Verilog","Commentar/Preprocessor") -> return ()
      ("Verilog","Some Context") -> (popContext) >> pEndLine
      ("Verilog","Some Context2") -> return ()
      ("Verilog","Block name") -> (popContext) >> pEndLine
      ("Verilog","Port") -> return ()
      _ -> return ()
    else return ()

withAttribute attr txt = do
  when (null txt) $ fail "Parser matched no text"
  updateState $ \st -> st { synStPrevChar = last txt
                          , synStPrevNonspace = synStPrevNonspace st || not (all isSpace txt) }
  return (attr, txt)

list_keywords = Set.fromList $ words $ "macromodule table endtable specify specparam endspecify defparam default if ifnone else forever while for wait repeat disable assign deassign force release always initial edge posedge negedge config endconfig library design liblist cell use instance"
list_beginwords = Set.fromList $ words $ "begin fork module case casex casez task function generate"
list_endwords = Set.fromList $ words $ "end join endmodule endcase endtask endfunction endgenerate"
list_strength = Set.fromList $ words $ "strong0 strong1 pull0 pull1 weak0 weak1 highz0 highz1 small medium large"
list_gates = Set.fromList $ words $ "pullup pulldown cmos rcmos nmos pmos rnmos rpmos and nand or nor xor xnor not buf tran rtran tranif0 tranif1 rtranif0 rtranif1 bufif0 bufif1 notif0 notif1"
list_types = Set.fromList $ words $ "input output inout wire tri tri0 tri1 wand wor triand trior supply0 supply1 reg integer real realtime time vectored scalared trireg parameter event signed automatic genvar localparam"

regex_begin'5c_'2a'3a = compileRegex True "begin\\ *:"
regex_fork'5c_'2a'3a = compileRegex True "fork\\ *:"
regex_'5b'5cd'5f'5d'2a'27d'5b'5cd'5f'5d'2b = compileRegex True "[\\d_]*'d[\\d_]+"
regex_'5b'5cd'5f'5d'2a'27o'5b0'2d7xXzZ'5f'5d'2b = compileRegex True "[\\d_]*'o[0-7xXzZ_]+"
regex_'5b'5cd'5f'5d'2a'27h'5b'5cda'2dfA'2dFxXzZ'5f'5d'2b = compileRegex True "[\\d_]*'h[\\da-fA-FxXzZ_]+"
regex_'5b'5cd'5f'5d'2a'27b'5b01'5fzZxX'5d'2b = compileRegex True "[\\d_]*'b[01_zZxX]+"
regex_'5ba'2dzA'2dZ0'2d9'5f'2c_'5ct'5d'2b'5cs'2a'3a = compileRegex True "[a-zA-Z0-9_, \\t]+\\s*:"
regex_'5c'60'5ba'2dzA'2dZ'5f'5d'2b'5cw'2a = compileRegex True "\\`[a-zA-Z_]+\\w*"
regex_'5c'24'5ba'2dzA'2dZ'5f'5d'2b'5cw'2a = compileRegex True "\\$[a-zA-Z_]+\\w*"
regex_'23'5b'5cd'5f'5d'2b = compileRegex True "#[\\d_]+"

parseRules ("Verilog","Normal") =
  (((pDetectSpaces >>= withAttribute NormalTok))
   <|>
   ((pRegExpr regex_begin'5c_'2a'3a >>= withAttribute KeywordTok) >>~ pushContext ("Verilog","Block name"))
   <|>
   ((pRegExpr regex_fork'5c_'2a'3a >>= withAttribute KeywordTok) >>~ pushContext ("Verilog","Block name"))
   <|>
   ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_beginwords >>= withAttribute KeywordTok))
   <|>
   ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_endwords >>= withAttribute KeywordTok))
   <|>
   ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_keywords >>= withAttribute KeywordTok))
   <|>
   ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_types >>= withAttribute DataTypeTok))
   <|>
   ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_strength >>= withAttribute BaseNTok))
   <|>
   ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_gates >>= withAttribute DataTypeTok))
   <|>
   ((pRegExpr regex_'5b'5cd'5f'5d'2a'27d'5b'5cd'5f'5d'2b >>= withAttribute BaseNTok))
   <|>
   ((pRegExpr regex_'5b'5cd'5f'5d'2a'27o'5b0'2d7xXzZ'5f'5d'2b >>= withAttribute BaseNTok))
   <|>
   ((pRegExpr regex_'5b'5cd'5f'5d'2a'27h'5b'5cda'2dfA'2dFxXzZ'5f'5d'2b >>= withAttribute BaseNTok))
   <|>
   ((pRegExpr regex_'5b'5cd'5f'5d'2a'27b'5b01'5fzZxX'5d'2b >>= withAttribute BaseNTok))
   <|>
   ((pFloat >>= withAttribute FloatTok))
   <|>
   ((pInt >>= withAttribute DecValTok))
   <|>
   ((pFirstNonSpace >> pRegExpr regex_'5ba'2dzA'2dZ0'2d9'5f'2c_'5ct'5d'2b'5cs'2a'3a >>= withAttribute DecValTok))
   <|>
   ((pDetectChar False '"' >>= withAttribute StringTok) >>~ pushContext ("Verilog","String"))
   <|>
   ((pDetect2Chars False '/' '/' >>= withAttribute CommentTok) >>~ pushContext ("Verilog","Commentar 1"))
   <|>
   ((pDetect2Chars False '/' '*' >>= withAttribute CommentTok) >>~ pushContext ("Verilog","Commentar 2"))
   <|>
   ((pAnyChar "!%&()+,-<=+/:;>?[]^{|}~@" >>= withAttribute NormalTok))
   <|>
   ((pColumn 0 >> pDetectChar False '`' >>= withAttribute OtherTok) >>~ pushContext ("Verilog","Preprocessor"))
   <|>
   ((pRegExpr regex_'5c'60'5ba'2dzA'2dZ'5f'5d'2b'5cw'2a >>= withAttribute OtherTok))
   <|>
   ((pRegExpr regex_'5c'24'5ba'2dzA'2dZ'5f'5d'2b'5cw'2a >>= withAttribute DataTypeTok))
   <|>
   ((pRegExpr regex_'23'5b'5cd'5f'5d'2b >>= withAttribute BaseNTok))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","Normal")) >> pDefault >>= withAttribute NormalTok))

parseRules ("Verilog","String") =
  (((pLineContinue >>= withAttribute StringTok) >>~ pushContext ("Verilog","Some Context"))
   <|>
   ((pHlCStringChar >>= withAttribute CharTok))
   <|>
   ((pDetectChar False '"' >>= withAttribute StringTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","String")) >> pDefault >>= withAttribute StringTok))

parseRules ("Verilog","Commentar 1") =
  (((Text.Highlighting.Kate.Syntax.Alert.parseExpression (Just ("Alerts","")) >>= ((withAttribute CommentTok) . snd)))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","Commentar 1")) >> pDefault >>= withAttribute CommentTok))

parseRules ("Verilog","Commentar 2") =
  (((Text.Highlighting.Kate.Syntax.Alert.parseExpression (Just ("Alerts","")) >>= ((withAttribute CommentTok) . snd)))
   <|>
   ((pDetect2Chars False '*' '/' >>= withAttribute CommentTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","Commentar 2")) >> pDefault >>= withAttribute CommentTok))

parseRules ("Verilog","Preprocessor") =
  (((pLineContinue >>= withAttribute OtherTok) >>~ pushContext ("Verilog","Some Context"))
   <|>
   ((pRangeDetect '"' '"' >>= withAttribute FloatTok))
   <|>
   ((pRangeDetect '<' '>' >>= withAttribute FloatTok))
   <|>
   ((pDetect2Chars False '/' '/' >>= withAttribute CommentTok) >>~ pushContext ("Verilog","Commentar 1"))
   <|>
   ((pDetect2Chars False '/' '*' >>= withAttribute CommentTok) >>~ pushContext ("Verilog","Commentar/Preprocessor"))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","Preprocessor")) >> pDefault >>= withAttribute OtherTok))

parseRules ("Verilog","Commentar/Preprocessor") =
  (((pDetect2Chars False '*' '/' >>= withAttribute CommentTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","Commentar/Preprocessor")) >> pDefault >>= withAttribute CommentTok))

parseRules ("Verilog","Some Context") =
  (currentContext >>= \x -> guard (x == ("Verilog","Some Context")) >> pDefault >>= withAttribute NormalTok)

parseRules ("Verilog","Some Context2") =
  (((Text.Highlighting.Kate.Syntax.Alert.parseExpression (Just ("Alerts","")) >>= ((withAttribute CommentTok) . snd)))
   <|>
   ((pFirstNonSpace >> pString False "#endif" >>= withAttribute CommentTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","Some Context2")) >> pDefault >>= withAttribute CommentTok))

parseRules ("Verilog","Block name") =
  (((pDetectIdentifier >>= withAttribute DataTypeTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","Block name")) >> pDefault >>= withAttribute DataTypeTok))

parseRules ("Verilog","Port") =
  (((pDetectIdentifier >>= withAttribute NormalTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("Verilog","Port")) >> pDefault >>= withAttribute NormalTok))

parseRules ("Alerts", _) = Text.Highlighting.Kate.Syntax.Alert.parseExpression Nothing

parseRules x = parseRules ("Verilog","Normal") <|> fail ("Unknown context" ++ show x)
