module Text.Highlighting.Kate.Syntax.Verilog ( highlight, parseExpression, syntaxName, syntaxExtensions ) where
import Text.Highlighting.Kate.Definitions
import Text.Highlighting.Kate.Common
import Text.ParserCombinators.Parsec
import Control.Monad (when)
import Data.Map (fromList)
import Data.Maybe (fromMaybe, maybeToList)
import qualified Data.Set as Set
syntaxName :: String
syntaxName = "Verilog"
syntaxExtensions :: String
syntaxExtensions = "*.v;*.V;*.vl"
highlight :: String -> Either String [SourceLine]
highlight input =
case runParser parseSource startingState "source" input of
Left err -> Left $ show err
Right result -> Right result
parseExpression :: GenParser Char SyntaxState LabeledSource
parseExpression = do
st <- getState
let oldLang = synStLanguage st
setState $ st { synStLanguage = "Verilog" }
context <- currentContext <|> (pushContext "Normal" >> currentContext)
result <- parseRules context
updateState $ \st -> st { synStLanguage = oldLang }
return result
parseSource = do
lineContents <- lookAhead wholeLine
updateState $ \st -> st { synStCurrentLine = lineContents }
result <- manyTill parseSourceLine eof
return $ map normalizeHighlighting result
startingState = SyntaxState {synStContexts = fromList [("Verilog",["Normal"])], synStLanguage = "Verilog", synStCurrentLine = "", synStCharsParsedInLine = 0, synStPrevChar = '\n', synStCaseSensitive = True, synStKeywordCaseSensitive = True, synStCaptures = []}
parseSourceLine = manyTill parseExpressionInternal pEndLine
pEndLine = do
lookAhead $ newline <|> (eof >> return '\n')
context <- currentContext
case context of
"Normal" -> return () >> pHandleEndLine
"String" -> (popContext) >> pEndLine
"Commentar 1" -> (popContext) >> pEndLine
"Commentar 2" -> return () >> pHandleEndLine
"Preprocessor" -> (popContext) >> pEndLine
"Commentar/Preprocessor" -> return () >> pHandleEndLine
"Some Context" -> (popContext) >> pEndLine
"Some Context2" -> return () >> pHandleEndLine
"Block name" -> (popContext) >> pEndLine
_ -> pHandleEndLine
withAttribute attr txt = do
when (null txt) $ fail "Parser matched no text"
let labs = attr : maybeToList (lookup attr styles)
st <- getState
let oldCharsParsed = synStCharsParsedInLine st
let prevchar = if null txt then '\n' else last txt
updateState $ \st -> st { synStCharsParsedInLine = oldCharsParsed + length txt, synStPrevChar = prevchar }
return (labs, txt)
styles = [("Keyword","kw"),("Data Type","dt"),("Decimal","bn"),("Octal","bn"),("Hex","bn"),("Binary","bn"),("Float","fl"),("String","st"),("String Char","ch"),("Comment","co"),("Alert","al"),("Preprocessor","ot"),("Prep. Lib","fl"),("System Task","dt"),("Integer","dv"),("Delay","bn"),("Block name","dt"),("Drive/charge strength","bn"),("Gate instantiation","dt"),("Port connection","dt")]
parseExpressionInternal = do
context <- currentContext
parseRules context <|> (pDefault >>= withAttribute (fromMaybe "" $ lookup context defaultAttributes))
list_keywords = Set.fromList $ words $ "macromodule task endtask function endfunction table endtable specify specparam endspecify case casex casez endcase fork join defparam default if ifnone else forever while for wait repeat disable assign deassign force release always initial edge posedge negedge"
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"
list_begin = Set.fromList $ words $ "begin"
list_end = Set.fromList $ words $ "end"
list_module = Set.fromList $ words $ "module"
list_endmodule = Set.fromList $ words $ "endmodule"
regex_begin'5c_'2a'3a = compileRegex "begin\\ *:"
regex_'5ba'2dzA'2dZ'5d'2b'5b'5cw'24'5d'2a = compileRegex "[a-zA-Z]+[\\w$]*"
regex_'5c'5c'5b'5e_'5d'2b_ = compileRegex "\\\\[^ ]+ "
regex_'5b'5cd'5f'5d'2a'27d'5b'5cd'5f'5d'2b = compileRegex "[\\d_]*'d[\\d_]+"
regex_'5b'5cd'5f'5d'2a'27o'5b0'2d7xXzZ'5f'5d'2b = compileRegex "[\\d_]*'o[0-7xXzZ_]+"
regex_'5b'5cd'5f'5d'2a'27h'5b'5cda'2dfA'2dFxXzZ'5f'5d'2b = compileRegex "[\\d_]*'h[\\da-fA-FxXzZ_]+"
regex_'5b'5cd'5f'5d'2a'27b'5b01'5fzZxX'5d'2b = compileRegex "[\\d_]*'b[01_zZxX]+"
regex_'5b'5e'5cw'24'5d'5c'2e'5ba'2dzA'2dZ'5d'2b'5b'5cw'24'5d'2a = compileRegex "[^\\w$]\\.[a-zA-Z]+[\\w$]*"
regex_'5c'60'5ba'2dzA'2dZ'5f'5d'2b'5cw'2a = compileRegex "\\`[a-zA-Z_]+\\w*"
regex_'5c'24'5ba'2dzA'2dZ'5f'5d'2b'5cw'2a = compileRegex "\\$[a-zA-Z_]+\\w*"
regex_'23'5b'5cd'5f'5d'2b = compileRegex "#[\\d_]+"
regex_'28FIXME'7cTODO'29 = compileRegex "(FIXME|TODO)"
regex_'5b'5e_'5d'2b = compileRegex "[^ ]+"
defaultAttributes = [("Normal","Normal Text"),("String","String"),("Commentar 1","Comment"),("Commentar 2","Comment"),("Preprocessor","Preprocessor"),("Commentar/Preprocessor","Comment"),("Some Context","Normal Text"),("Some Context2","Comment"),("Block name","Block name")]
parseRules "Normal" =
do (attr, result) <- (((pRegExpr regex_begin'5c_'2a'3a >>= withAttribute "Keyword") >>~ pushContext "Block name")
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_begin >>= withAttribute "Keyword"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_end >>= withAttribute "Keyword"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_module >>= withAttribute "Keyword"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_endmodule >>= withAttribute "Keyword"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_keywords >>= withAttribute "Keyword"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_types >>= withAttribute "Data Type"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_strength >>= withAttribute "Drive/charge strength"))
<|>
((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_gates >>= withAttribute "Gate instantiation"))
<|>
((pRegExpr regex_'5ba'2dzA'2dZ'5d'2b'5b'5cw'24'5d'2a >>= withAttribute "Normal Text"))
<|>
((pRegExpr regex_'5c'5c'5b'5e_'5d'2b_ >>= withAttribute "Normal Text"))
<|>
((pRegExpr regex_'5b'5cd'5f'5d'2a'27d'5b'5cd'5f'5d'2b >>= withAttribute "Decimal"))
<|>
((pRegExpr regex_'5b'5cd'5f'5d'2a'27o'5b0'2d7xXzZ'5f'5d'2b >>= withAttribute "Octal"))
<|>
((pRegExpr regex_'5b'5cd'5f'5d'2a'27h'5b'5cda'2dfA'2dFxXzZ'5f'5d'2b >>= withAttribute "Hex"))
<|>
((pRegExpr regex_'5b'5cd'5f'5d'2a'27b'5b01'5fzZxX'5d'2b >>= withAttribute "Binary"))
<|>
((pFloat >>= withAttribute "Float"))
<|>
((pInt >>= withAttribute "Integer"))
<|>
((pRegExpr regex_'5b'5e'5cw'24'5d'5c'2e'5ba'2dzA'2dZ'5d'2b'5b'5cw'24'5d'2a >>= withAttribute "Port connection"))
<|>
((pDetectChar False '"' >>= withAttribute "String") >>~ pushContext "String")
<|>
((pDetect2Chars False '/' '/' >>= withAttribute "Comment") >>~ pushContext "Commentar 1")
<|>
((pDetect2Chars False '/' '*' >>= withAttribute "Comment") >>~ pushContext "Commentar 2")
<|>
((pAnyChar "!%&()+,-<=+/:;>?[]^{|}~@" >>= withAttribute "Symbol"))
<|>
((pFirstNonSpace >> pString False "#if 0" >>= withAttribute "Comment") >>~ pushContext "Some Context2")
<|>
((pColumn 0 >> pDetectChar False '`' >>= withAttribute "Preprocessor") >>~ pushContext "Preprocessor")
<|>
((pRegExpr regex_'5c'60'5ba'2dzA'2dZ'5f'5d'2b'5cw'2a >>= withAttribute "Preprocessor"))
<|>
((pRegExpr regex_'5c'24'5ba'2dzA'2dZ'5f'5d'2b'5cw'2a >>= withAttribute "System Task"))
<|>
((pRegExpr regex_'23'5b'5cd'5f'5d'2b >>= withAttribute "Delay")))
return (attr, result)
parseRules "String" =
do (attr, result) <- (((pLineContinue >>= withAttribute "String") >>~ pushContext "Some Context")
<|>
((pHlCStringChar >>= withAttribute "String Char"))
<|>
((pDetectChar False '"' >>= withAttribute "String") >>~ (popContext)))
return (attr, result)
parseRules "Commentar 1" =
do (attr, result) <- ((pRegExpr regex_'28FIXME'7cTODO'29 >>= withAttribute "Alert"))
return (attr, result)
parseRules "Commentar 2" =
do (attr, result) <- (((pRegExpr regex_'28FIXME'7cTODO'29 >>= withAttribute "Alert"))
<|>
((pDetect2Chars False '*' '/' >>= withAttribute "Comment") >>~ (popContext)))
return (attr, result)
parseRules "Preprocessor" =
do (attr, result) <- (((pLineContinue >>= withAttribute "Preprocessor") >>~ pushContext "Some Context")
<|>
((pRangeDetect '"' '"' >>= withAttribute "Prep. Lib"))
<|>
((pRangeDetect '<' '>' >>= withAttribute "Prep. Lib"))
<|>
((pDetect2Chars False '/' '/' >>= withAttribute "Comment") >>~ pushContext "Commentar 1")
<|>
((pDetect2Chars False '/' '*' >>= withAttribute "Comment") >>~ pushContext "Commentar/Preprocessor"))
return (attr, result)
parseRules "Commentar/Preprocessor" =
do (attr, result) <- ((pDetect2Chars False '*' '/' >>= withAttribute "Comment") >>~ (popContext))
return (attr, result)
parseRules "Some Context" =
pzero
parseRules "Some Context2" =
do (attr, result) <- (((pRegExpr regex_'28FIXME'7cTODO'29 >>= withAttribute "Alert"))
<|>
((pFirstNonSpace >> pString False "#endif" >>= withAttribute "Comment") >>~ (popContext)))
return (attr, result)
parseRules "Block name" =
do (attr, result) <- ((pRegExpr regex_'5b'5e_'5d'2b >>= withAttribute "Data Type") >>~ (popContext))
return (attr, result)
parseRules "" = parseRules "Normal"
parseRules x = fail $ "Unknown context" ++ x