{- This module was generated from data in the Kate syntax
   highlighting file sql-mysql.xml, version 1.16, by Shane Wright (me@shanewright.co.uk) -}

module Text.Highlighting.Kate.Syntax.SqlMysql
          (highlight, parseExpression, syntaxName, syntaxExtensions)
where
import Text.Highlighting.Kate.Types
import Text.Highlighting.Kate.Common
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 = "SQL (MySQL)"

-- | Filename extensions for this language.
syntaxExtensions :: String
syntaxExtensions = "*.sql;*.SQL;*.ddl;*.DDL"

-- | 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 = [("SQL (MySQL)","Normal")], synStLineNumber = 0, synStPrevChar = '\n', synStPrevNonspace = False, synStContinuation = False, synStCaseSensitive = True, synStKeywordCaseSensitive = False, 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 }
      ("SQL (MySQL)","Normal") -> return ()
      ("SQL (MySQL)","String") -> return ()
      ("SQL (MySQL)","String2") -> return ()
      ("SQL (MySQL)","Name") -> return ()
      ("SQL (MySQL)","SingleLineComment") -> (popContext) >> pEndLine
      ("SQL (MySQL)","MultiLineComment") -> return ()
      ("SQL (MySQL)","Preprocessor") -> (popContext) >> pEndLine
      _ -> 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 $ "access add all alter analyze and as asc auto_increment bdb berkeleydb between both by cascade case change charset column columns constraint create cross current_date current_time current_timestamp database databases day_hour day_minute day_second dec default delayed delete desc describe distinct distinctrow drop else enclosed escaped exists explain fields for foreign from fulltext function grant group having high_priority if ignore in index infile inner innodb insert interval into is join key keys kill leading left like limit lines load lock low_priority master_server_id match mrg_myisam national natural not null numeric on optimize option optionally or order outer outfile partial precision primary privileges procedure purge read references regexp rename replace require restrict returns revoke right rlike select set show soname sql_big_result sql_calc_found_rows sql_small_result ssl starting straight_join striped table tables terminated then to trailing truncate type union unique unlock unsigned update usage use user_resources using values varying when where while with write xor year_month zerofill"
list_operators = Set.fromList $ words $ "+ - * / || = != <> < <= > >= ~= ^= := => ** .."
list_functions = Set.fromList $ words $ "ascii bin bit_length char character_length char_length concat concat_ws conv elt export_set field find_in_set hex insert instr lcase left length load_file locate lower lpad ltrim make_set mid oct octet_length ord position quote repeat replace reverse right rpad rtrim soundex space substring substring_index trim ucase upper abs acos asin atan atan2 ceiling cos cot degrees exp floor greatest least ln log log10 log2 mod pi pow power radians rand round sign sin sqrt tan adddate curdate current_date current_time current_timestamp curtime date_add date_format date_sub dayname dayofmonth dayofweek dayofyear extract from_days from_unixtime hour minute month monthname now period_add period_diff quarter second sec_to_time subdate sysdate time_format time_to_sec to_days unix_timestamp week weekday year yearweek cast convert aes_decrypt aes_encrypt benchmark bit_count connection_id database decode des_decrypt des_encrypt encode encrypt format found_rows get_lock inet_aton inet_ntoa is_free_lock last_insert_id master_pos_wait md5 password release_lock session_user sha sha1 system_user user version avg bit_and bit_or count max min std stddev sum"
list_types = Set.fromList $ words $ "binary blob char character enum longblob longtext mediumblob mediumtext text tinyblob tinytext varbinary varchar bigint bit bool boolean dec decimal double fixed float int integer long mediumint middleint numeric tinyint real serial smallint date datetime time timestamp year"

regex_SET'28'3f'3d'5cs'2a'5c'28'29 = compileRegex False "SET(?=\\s*\\()"
regex_'5cbCHARACTER_SET'5cb = compileRegex False "\\bCHARACTER SET\\b"
regex_'25'28'3f'3abulk'5f'28'3f'3aexceptions'7crowcount'29'7cfound'7cisopen'7cnotfound'7crowcount'7crowtype'7ctype'29'5cb = compileRegex False "%(?:bulk_(?:exceptions|rowcount)|found|isopen|notfound|rowcount|rowtype|type)\\b"
regex_rem'5cb = compileRegex False "rem\\b"
regex_'2f'24 = compileRegex False "/$"
regex_'40'40'3f'5b'5e'40_'5ct'5cr'5cn'5d = compileRegex False "@@?[^@ \\t\\r\\n]"

parseRules ("SQL (MySQL)","Normal") =
  (((pDetectSpaces >>= withAttribute NormalTok))
   <|>
   ((pRegExpr regex_SET'28'3f'3d'5cs'2a'5c'28'29 >>= withAttribute DataTypeTok))
   <|>
   ((pRegExpr regex_'5cbCHARACTER_SET'5cb >>= withAttribute KeywordTok))
   <|>
   ((pKeyword " \n\t(),%&;?[]{}\\" list_keywords >>= withAttribute KeywordTok))
   <|>
   ((pKeyword " \n\t(),%&;?[]{}\\" list_operators >>= withAttribute NormalTok))
   <|>
   ((pKeyword " \n\t(),%&;?[]{}\\" list_functions >>= withAttribute FunctionTok))
   <|>
   ((pKeyword " \n\t(),%&;?[]{}\\" list_types >>= withAttribute DataTypeTok))
   <|>
   ((pDetectIdentifier >>= withAttribute NormalTok))
   <|>
   ((pRegExpr regex_'25'28'3f'3abulk'5f'28'3f'3aexceptions'7crowcount'29'7cfound'7cisopen'7cnotfound'7crowcount'7crowtype'7ctype'29'5cb >>= withAttribute DataTypeTok))
   <|>
   ((pHlCHex >>= withAttribute BaseNTok))
   <|>
   ((pFloat >>= withAttribute FloatTok))
   <|>
   ((pInt >>= withAttribute DecValTok))
   <|>
   ((pDetectChar False '\'' >>= withAttribute StringTok) >>~ pushContext ("SQL (MySQL)","String"))
   <|>
   ((pDetectChar False '"' >>= withAttribute StringTok) >>~ pushContext ("SQL (MySQL)","String2"))
   <|>
   ((pDetectChar False '`' >>= withAttribute StringTok) >>~ pushContext ("SQL (MySQL)","Name"))
   <|>
   ((pDetectChar False '#' >>= withAttribute CommentTok) >>~ pushContext ("SQL (MySQL)","SingleLineComment"))
   <|>
   ((pDetect2Chars False '-' '-' >>= withAttribute CommentTok) >>~ pushContext ("SQL (MySQL)","SingleLineComment"))
   <|>
   ((pDetect2Chars False '/' '*' >>= withAttribute CommentTok) >>~ pushContext ("SQL (MySQL)","MultiLineComment"))
   <|>
   ((pColumn 0 >> pRegExpr regex_rem'5cb >>= withAttribute CommentTok) >>~ pushContext ("SQL (MySQL)","SingleLineComment"))
   <|>
   ((pAnyChar ":&" >>= withAttribute CharTok))
   <|>
   ((pColumn 0 >> pRegExpr regex_'2f'24 >>= withAttribute CharTok))
   <|>
   ((pColumn 0 >> pRegExpr regex_'40'40'3f'5b'5e'40_'5ct'5cr'5cn'5d >>= withAttribute OtherTok) >>~ pushContext ("SQL (MySQL)","Preprocessor"))
   <|>
   ((pDetectChar False '.' >>= withAttribute CharTok))
   <|>
   (currentContext >>= \x -> guard (x == ("SQL (MySQL)","Normal")) >> pDefault >>= withAttribute NormalTok))

parseRules ("SQL (MySQL)","String") =
  (((pLineContinue >>= withAttribute StringTok) >>~ (popContext))
   <|>
   ((pHlCStringChar >>= withAttribute CharTok))
   <|>
   ((pDetectChar False '&' >>= withAttribute CharTok))
   <|>
   ((pDetectChar False '\'' >>= withAttribute StringTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("SQL (MySQL)","String")) >> pDefault >>= withAttribute StringTok))

parseRules ("SQL (MySQL)","String2") =
  (((pLineContinue >>= withAttribute StringTok) >>~ (popContext))
   <|>
   ((pHlCStringChar >>= withAttribute CharTok))
   <|>
   ((pDetectChar False '&' >>= withAttribute CharTok))
   <|>
   ((pDetectChar False '"' >>= withAttribute StringTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("SQL (MySQL)","String2")) >> pDefault >>= withAttribute StringTok))

parseRules ("SQL (MySQL)","Name") =
  (((pLineContinue >>= withAttribute StringTok) >>~ (popContext))
   <|>
   ((pHlCStringChar >>= withAttribute CharTok))
   <|>
   ((pDetectChar False '`' >>= withAttribute StringTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("SQL (MySQL)","Name")) >> pDefault >>= withAttribute StringTok))

parseRules ("SQL (MySQL)","SingleLineComment") =
  (currentContext >>= \x -> guard (x == ("SQL (MySQL)","SingleLineComment")) >> pDefault >>= withAttribute CommentTok)

parseRules ("SQL (MySQL)","MultiLineComment") =
  (((pLineContinue >>= withAttribute CommentTok) >>~ (popContext))
   <|>
   ((pDetect2Chars False '*' '/' >>= withAttribute CommentTok) >>~ (popContext))
   <|>
   (currentContext >>= \x -> guard (x == ("SQL (MySQL)","MultiLineComment")) >> pDefault >>= withAttribute CommentTok))

parseRules ("SQL (MySQL)","Preprocessor") =
  (currentContext >>= \x -> guard (x == ("SQL (MySQL)","Preprocessor")) >> pDefault >>= withAttribute OtherTok)


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