{- This module was generated from data in the Kate syntax highlighting file javascript.xml, version 1.11,
   by  Anders Lund (anders@alweb.dk), Joseph Wenninger (jowenn@kde.org), Whitehawk Stormchaser (zerokode@gmx.net) -}

module Text.Highlighting.Kate.Syntax.Javascript ( highlight, parseExpression, syntaxName, syntaxExtensions ) where
import Text.Highlighting.Kate.Definitions
import Text.Highlighting.Kate.Common
import qualified Text.Highlighting.Kate.Syntax.Alert
import Text.ParserCombinators.Parsec
import Data.List (nub)
import qualified Data.Set as Set
import Data.Map (fromList)
import Data.Maybe (fromMaybe)

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

-- | Filename extensions for this language.
syntaxExtensions :: String
syntaxExtensions = "*.js"

-- | Highlight source code using this syntax definition.
highlight :: String -> Either String [SourceLine]
highlight input =
  case runParser parseSource startingState "source" input of
    Left err     -> Left $ show err
    Right result -> Right result

-- | Parse an expression using appropriate local context.
parseExpression :: GenParser Char SyntaxState LabeledSource
parseExpression = do
  st <- getState
  let oldLang = synStLanguage st
  setState $ st { synStLanguage = "JavaScript" }
  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 [("JavaScript",["Normal"])], synStLanguage = "JavaScript", synStCurrentLine = "", synStCharsParsedInLine = 0, synStPrevChar = '\n', synStCaseSensitive = True, synStKeywordCaseSensitive = True, synStCaptures = []}

parseSourceLine = manyTill parseExpressionInternal pEndLine

pEndLine = do
  newline <|> (eof >> return '\n')
  context <- currentContext
  case context of
    "Normal" -> return ()
    "String" -> (popContext >> return ())
    "String 1" -> (popContext >> return ())
    "Comment" -> (popContext >> return ())
    "Multi/inline Comment" -> return ()
    "Regular Expression" -> return ()
    "(Internal regex catch)" -> return ()
    "Regular Expression Character Class" -> return ()
    "(regex caret first check)" -> (popContext >> return ())
    "(charclass caret first check)" -> (popContext >> return ())
    "region_marker" -> (popContext >> return ())
    _ -> return ()
  lineContents <- lookAhead wholeLine
  updateState $ \st -> st { synStCurrentLine = lineContents, synStCharsParsedInLine = 0, synStPrevChar = '\n' }

withAttribute attr txt = do
  if null txt
     then fail "Parser matched no text"
     else return ()
  let style = fromMaybe "" $ 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 (nub [style, attr], txt)

styles = [("Normal Text","Normal"),("Keyword","Keyword"),("Function","Function"),("Objects","Keyword"),("Math","Keyword"),("Events","Keyword"),("Data Type","DataType"),("Decimal","DecVal"),("Float","Float"),("Char","Char"),("String","String"),("String Char","Char"),("Comment","Comment"),("Symbol","Normal"),("Regular Expression","Others"),("Pattern Internal Operator","Float"),("Pattern Character Class","BaseN"),("Region Marker","RegionMarker")]

parseExpressionInternal = do
  context <- currentContext
  parseRules context <|> (pDefault >>= withAttribute (fromMaybe "" $ lookup context defaultAttributes))

list_keywords = Set.fromList $ words $ "if else for in while do continue break with try catch finally switch case new var function return delete true false void throw typeof const default"
list_functions = Set.fromList $ words $ "escape isFinite isNaN Number parseFloat parseInt reload taint unescape untaint write"
list_objects = Set.fromList $ words $ "Anchor Applet Area Array Boolean Button Checkbox Date document window Image FileUpload Form Frame Function Hidden Link MimeType Math Max Min Layer navigator Object Password Plugin Radio RegExp Reset Screen Select String Text Textarea this Window"
list_math = Set.fromList $ words $ "abs acos asin atan atan2 ceil cos ctg E exp floor LN2 LN10 log LOG2E LOG10E PI pow round sin sqrt SQRT1_2 SQRT2 tan"
list_events = Set.fromList $ words $ "onAbort onBlur onChange onClick onError onFocus onLoad onMouseOut onMouseOver onReset onSelect onSubmit onUnload"
list_methods = Set.fromList $ words $ "above action alinkColor alert anchor anchors appCodeName applets apply appName appVersion argument arguments arity availHeight availWidth back background below bgColor border big blink blur bold border call caller charAt charCodeAt checked clearInterval clearTimeout click clip close closed colorDepth complete compile constructor confirm cookie current cursor data defaultChecked defaultSelected defaultStatus defaultValue description disableExternalCapture domain elements embeds enabledPlugin enableExternalCapture encoding eval exec fgColor filename find fixed focus fontcolor fontsize form forms formName forward frames fromCharCode getDate getDay getHours getMiliseconds getMinutes getMonth getSeconds getSelection getTime getTimezoneOffset getUTCDate getUTCDay getUTCFullYear getUTCHours getUTCMilliseconds getUTCMinutes getUTCMonth getUTCSeconds getYear global go hash height history home host hostname href hspace ignoreCase images index indexOf innerHeight innerWidth input italics javaEnabled join language lastIndex lastIndexOf lastModified lastParen layers layerX layerY left leftContext length link linkColor links location locationbar load lowsrc match MAX_VALUE menubar method mimeTypes MIN_VALUE modifiers moveAbove moveBelow moveBy moveTo moveToAbsolute multiline name NaN NEGATIVE_INFINITY negative_infinity next open opener options outerHeight outerWidth pageX pageY pageXoffset pageYoffset parent parse pathname personalbar pixelDepth platform plugins pop port POSITIVE_INFINITY positive_infinity preference previous print prompt protocol prototype push referrer refresh releaseEvents reload replace reset resizeBy resizeTo reverse rightContext screenX screenY scroll scrollbar scrollBy scrollTo search select selected selectedIndex self setDate setHours setMinutes setMonth setSeconds setTime setTimeout setUTCDate setUTCDay setUTCFullYear setUTCHours setUTCMilliseconds setUTCMinutes setUTCMonth setUTCSeconds setYear shift siblingAbove siblingBelow small sort source splice split src status statusbar strike sub submit substr substring suffixes sup taintEnabled target test text title toGMTString toLocaleString toLowerCase toolbar toSource toString top toUpperCase toUTCString type URL unshift unwatch userAgent UTC value valueOf visibility vlinkColor vspace width watch which width write writeln x y zIndex"

regex_'2f'2fEND = compileRegex "//END"
regex_'5b'3d'3f'3a'5d = compileRegex "[=?:]"
regex_'5c'28 = compileRegex "\\("
regex_'2f'5big'5d'7b0'2c2'7d = compileRegex "/[ig]{0,2}"
regex_'5c'7b'5b'5cd'2c_'5d'2b'5c'7d = compileRegex "\\{[\\d, ]+\\}"
regex_'5c'5c'5bbB'5d = compileRegex "\\\\[bB]"
regex_'5c'5c'5bnrtvfDdSsWw'5d = compileRegex "\\\\[nrtvfDdSsWw]"
regex_'5c'5c'2e = compileRegex "\\\\."
regex_'5c'24'28'3f'3d'2f'29 = compileRegex "\\$(?=/)"
regex_'2f'2f'28'3f'3d'3b'29 = compileRegex "//(?=;)"
regex_'5c'5c'5b'5c'5b'5c'5d'5d = compileRegex "\\\\[\\[\\]]"

defaultAttributes = [("Normal","Normal Text"),("String","String"),("String 1","String Char"),("Comment","Comment"),("Multi/inline Comment","Comment"),("Regular Expression","Regular Expression"),("(Internal regex catch)","Normal Text"),("Regular Expression Character Class","Pattern Character Class"),("(regex caret first check)","Pattern Internal Operator"),("(charclass caret first check)","Pattern Internal Operator"),("region_marker","Region Marker")]

parseRules "Normal" = 
  do (attr, result) <- (((pDetectSpaces >>= withAttribute "Normal Text"))
                        <|>
                        ((pString False "//BEGIN" >>= withAttribute "Region Marker") >>~ pushContext "region_marker")
                        <|>
                        ((pRegExpr regex_'2f'2fEND >>= withAttribute "Region Marker") >>~ pushContext "region_marker")
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_keywords >>= withAttribute "Keyword"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_functions >>= withAttribute "Function"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_objects >>= withAttribute "Objects"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_math >>= withAttribute "Math"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_events >>= withAttribute "Events"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_methods >>= withAttribute "Data Type"))
                        <|>
                        ((pDetectIdentifier >>= withAttribute "Normal Text"))
                        <|>
                        ((pFloat >>= withAttribute "Float"))
                        <|>
                        ((pInt >>= withAttribute "Decimal"))
                        <|>
                        ((pDetectChar False '"' >>= withAttribute "String") >>~ pushContext "String")
                        <|>
                        ((pDetectChar False '\'' >>= withAttribute "String") >>~ pushContext "String 1")
                        <|>
                        ((pDetect2Chars False '/' '/' >>= withAttribute "Comment") >>~ pushContext "Comment")
                        <|>
                        ((pDetect2Chars False '/' '*' >>= withAttribute "Comment") >>~ pushContext "Multi/inline Comment")
                        <|>
                        ((pRegExpr regex_'5b'3d'3f'3a'5d >>= withAttribute "Normal Text") >>~ pushContext "(Internal regex catch)")
                        <|>
                        ((pRegExpr regex_'5c'28 >>= withAttribute "Normal Text") >>~ pushContext "(Internal regex catch)")
                        <|>
                        ((pDetectChar False '{' >>= withAttribute "Symbol"))
                        <|>
                        ((pDetectChar False '}' >>= withAttribute "Symbol"))
                        <|>
                        ((pAnyChar ":!%&+,-/.*<=>?[]|~^;" >>= withAttribute "Symbol")))
     return (attr, result)

parseRules "String" = 
  do (attr, result) <- (((pDetectIdentifier >>= withAttribute "String"))
                        <|>
                        ((pHlCStringChar >>= withAttribute "String Char"))
                        <|>
                        ((pDetectChar False '"' >>= withAttribute "String") >>~ (popContext >> return ())))
     return (attr, result)

parseRules "String 1" = 
  do (attr, result) <- (((pDetectIdentifier >>= withAttribute "String Char"))
                        <|>
                        ((pDetectChar False '"' >>= withAttribute "String") >>~ pushContext "String")
                        <|>
                        ((pDetectChar False '\'' >>= withAttribute "String Char") >>~ (popContext >> return ())))
     return (attr, result)

parseRules "Comment" = 
  do (attr, result) <- (((pDetectSpaces >>= withAttribute "Comment"))
                        <|>
                        ((Text.Highlighting.Kate.Syntax.Alert.parseExpression >>= ((withAttribute "") . snd)))
                        <|>
                        ((pDetectIdentifier >>= withAttribute "Comment")))
     return (attr, result)

parseRules "Multi/inline Comment" = 
  do (attr, result) <- (((Text.Highlighting.Kate.Syntax.Alert.parseExpression >>= ((withAttribute "") . snd)))
                        <|>
                        ((pDetect2Chars False '*' '/' >>= withAttribute "Comment") >>~ (popContext >> return ())))
     return (attr, result)

parseRules "Regular Expression" = 
  do (attr, result) <- (((pRegExpr regex_'2f'5big'5d'7b0'2c2'7d >>= withAttribute "Regular Expression") >>~ (popContext >> popContext >> popContext >> return ()))
                        <|>
                        ((pRegExpr regex_'5c'7b'5b'5cd'2c_'5d'2b'5c'7d >>= withAttribute "Pattern Internal Operator"))
                        <|>
                        ((pRegExpr regex_'5c'5c'5bbB'5d >>= withAttribute "Pattern Internal Operator"))
                        <|>
                        ((pRegExpr regex_'5c'5c'5bnrtvfDdSsWw'5d >>= withAttribute "Pattern Character Class"))
                        <|>
                        ((pDetectChar False '[' >>= withAttribute "Pattern Character Class") >>~ pushContext "(charclass caret first check)")
                        <|>
                        ((pRegExpr regex_'5c'5c'2e >>= withAttribute "Pattern Internal Operator"))
                        <|>
                        ((pRegExpr regex_'5c'24'28'3f'3d'2f'29 >>= withAttribute "Pattern Internal Operator"))
                        <|>
                        ((pAnyChar "?+*()|" >>= withAttribute "Pattern Internal Operator")))
     return (attr, result)

parseRules "(Internal regex catch)" = 
  do (attr, result) <- (((pDetectSpaces >>= withAttribute "Normal Text"))
                        <|>
                        ((pRegExpr regex_'2f'2f'28'3f'3d'3b'29 >>= withAttribute "Regular Expression") >>~ (popContext >> return ()))
                        <|>
                        ((pDetect2Chars False '/' '/' >>= withAttribute "Comment") >>~ pushContext "Comment")
                        <|>
                        ((pDetect2Chars False '/' '*' >>= withAttribute "Comment") >>~ pushContext "Multi/inline Comment")
                        <|>
                        ((pDetectChar False '/' >>= withAttribute "Regular Expression") >>~ pushContext "(regex caret first check)")
                        <|>
                        ((popContext >> return ()) >> return ([], "")))
     return (attr, result)

parseRules "Regular Expression Character Class" = 
  do (attr, result) <- (((pRegExpr regex_'5c'5c'5b'5c'5b'5c'5d'5d >>= withAttribute "Pattern Character Class"))
                        <|>
                        ((pDetectChar False ']' >>= withAttribute "Pattern Character Class") >>~ (popContext >> popContext >> return ())))
     return (attr, result)

parseRules "(regex caret first check)" = 
  do (attr, result) <- (((pDetectChar False '^' >>= withAttribute "Pattern Internal Operator") >>~ pushContext "Regular Expression")
                        <|>
                        (pushContext "Regular Expression" >> return ([], "")))
     return (attr, result)

parseRules "(charclass caret first check)" = 
  do (attr, result) <- (((pDetectChar False '^' >>= withAttribute "Pattern Internal Operator") >>~ pushContext "Regular Expression Character Class")
                        <|>
                        (pushContext "Regular Expression Character Class" >> return ([], "")))
     return (attr, result)

parseRules "region_marker" = 
  do (attr, result) <- (((pDetectIdentifier >>= withAttribute "Region Marker"))
                        <|>
                        ((pDetectSpaces >>= withAttribute "Region Marker")))
     return (attr, result)

parseRules x = fail $ "Unknown context" ++ x