{- This module was generated from data in the Kate syntax highlighting file nasm.xml, version 1.30,
   by  Nicola Gigante (nicola.gigante@gmail.com) -}

module Text.Highlighting.Kate.Syntax.Nasm ( 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
-- | Full name of language.
syntaxName :: String
syntaxName = "Intel x86 (NASM)"

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

-- | 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 = "Intel x86 (NASM)" }
  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 [("Intel x86 (NASM)",["Normal"])], synStLanguage = "Intel x86 (NASM)", synStCurrentLine = "", synStCharsParsedInLine = 0, synStPrevChar = '\n', synStCaseSensitive = True, synStKeywordCaseSensitive = False, synStCaptures = []}

parseSourceLine = manyTill parseExpressionInternal pEndLine

pEndLine = do
  newline <|> (eof >> return '\n')
  context <- currentContext
  case context of
    "Normal" -> return ()
    "Comment" -> (popContext >> return ())
    "Preprocessor" -> (popContext >> return ())
    "String" -> (popContext >> return ())
    _ -> return ()
  lineContents <- lookAhead wholeLine
  updateState $ \st -> st { synStCurrentLine = lineContents, synStCharsParsedInLine = 0, synStPrevChar = '\n' }

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 = [("Registers","kw"),("Instructions","kw"),("NASM Keywords","kw"),("Comment","co"),("Label","fu"),("Data","dt"),("BaseN","bn"),("Float","fl"),("Number","dv"),("Char","ch"),("String","st"),("Preprocessor","ot")]

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

list_registers = Set.fromList $ words $ "eax ax ah al ebx bx bh bl ecx cx ch cl edx dx dh dl ebp bp esi si edi di esp sp cs ds es fs gs ss cr0 cr2 cr3 cr4 dr0 dr1 dr2 dr3 dr6 dr7 st mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7"
list_instructions = Set.fromList $ words $ "aaa aad aam aas adc add addpd addps addsd addss addsubpd addsubps and andnpd andnps andpd andps arpl bound bsf bsr bswap bt btc btr bts call cbw cwde cwd cdq cdqe cqo clc cld clgi cli clts clflush cmc cmova cmovae cmovb cmovbe cmovc cmove cmovg cmovge cmovl cmovle cmovna cmovnae cmovnb cmovnbe cmovnc cmovne cmovng cmovnge cmovnl cmovnle cmovno cmovnp cmovns cmovnz cmovo cmovp cmovpe cmovpo cmovs cmovz cmp cmpeqpd cmpeqps cmpeqsd cmpeqss cmplepd cmpleps cmplesd cmpless cmpltpd cmpltps cmpltsd cmpltss cmpneqpd cmpneqps cmpneqsd cmpneqss cmpnlepd cmpnleps cmpnlesd cmpnless cmpnltpd cmpnltps cmpnltsd cmpnltss cmpordpd cmpordps cmpordsd cmpordss cmppd cmpps cmps cmpsb cmpsd cmpss cmpsw cmpunordpd cmpunordps cmpunordsd cmpunordss cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b comisd comiss cpuid cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtpi2ps cvtps2dq cvtps2pd cvtps2pi cvtsd2si cvtsd2ss cvtsi2sd cvtsi2ss cvtss2sd cvtss2si cvttpd2dq cvttpd2pi cvttps2dq cvttps2pi cvttsd2si cvttss2si daa das dec div divpd divps divsd divss emms enter f2xm1 fabs fadd faddp fbld fbstp fchs fclex fnclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomp fcompp fcomi fcomip fcos fdecstp fdisi feni fdiv fdivr fdivp fdivrp femms ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldl2e fldl2t fldlg2 fldln2 fldcw fldenv fldpi fldz fmul fmulp fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fnwait fpatan fptan fprem fprem1 frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstp fstcw fstenv fstsw fsub fsubr fsubp fsubrp ftst fucom fucomp fucompp fucomi fucomip fwait fxam fxch fxrstor fxsave fxtract fyl2x fyl2xp1 haddpd haddps hlt hsubpd hsubps ibts idiv imul in inc ins insb insd insw int int1 int3 into invd invlpg invlpga iret iretd iretq iretw ja jae jb jbe jc je jg jge jl jle jna jnae jnb jnbe jnc jne jng jnge jnl jnle jno jnp jns jnz jo jp jpe jpo js jz jcxz jecxz jrcxz jmp lahf lar lddqu ldmxcsr lds les lea leave lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lods lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr maskmovdqu maskmovq maxpd maxps maxsd maxss mfence minpd minps minsd minss monitor mov movapd movaps movd movddup movdq2q movdqa movdqu movhlps movhpd movhps movlhps movlpd movlps movmskpd movmskps movntdq movnti movntpd movntps movntq movq movq2dq movs movsb movsd movshdup movsldup movsq movss movsx movsxd movsw movupd movups movzx mul mulpd mulps mulsd mulss mwait neg nop not or orpd orps out outs outsb outsw outsd packssdw packsswb packuswb paddb paddd paddq paddsb paddsw paddusb paddusw paddw pand pandn pause pavgb pavgusb pavgw pcmpeqb pcmpeqw pcmpeqd pcmpgtb pcmpgtw pcmpgtd pdistib pextrw pf2id pf2iw pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfnacc pfpnacc pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pi2fw pinsrw pmachriw pmaddwd pmagw pmaxsw pmaxub pminsw pminub pmovmskb pmulhrw pmulhuw pmulhw pmullw pmuludq pmvgezb pmvlzb pmvnzb pmvzb pop popa popaw popad popf popfw popfd popfq por prefetch prefetchnta prefetcht0 prefetcht1 prefetcht2 prefetchw psadbw pshufd pshufhw pshuflw pshufw pslld pslldq psllq psllw psrad psraw psrld psrldq psrlq psrlw psubb psubd psubq psubsb psubsiw psubsw psubusb psubusw psubw pswapd punpckhbw punpckhdq punpckhqdq punpckhwd punpcklbw punpckldq punpcklqdq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rcpps rcpss rdmsr rdpmc rdshr rdtsc rdtscp ret retf retn rol ror rsdc rsldt rsm rsqrtps rsqrtss rsts sahf sal sar salc sbb scas scasb scasd scasq scasw seta setae setb setbe setc sete setg setge setl setle setna setnae setnb setnbe setnc setne setng setnge setnl setnle setno setnp setns setnz seto setp setpe setpo sets setz sfence sgdt shl shld shr shrd shufpd shufps sidt skinit sldt smi smint smintold smsw sqrtpd sqrtps sqrtsd sqrtss stc std stgi sti stmxcsr stos stosb stosd stosq stosw str sub subpd subps subsd subss svdc svldt svts swapgs syscall sysenter sysexit sysret test ucomisd ucomiss ud0 ud1 ud2 umov unpckhpd unpckhps unpcklpd unpcklps verr verw vmload vmmcall vmrun vmsave wait wbinvd wrmsr wrshr xadd xbts xchg xlat xlatb xor xorpd xorps"
list_Data = Set.fromList $ words $ "times equ db dw dd dq dt resb resw resd resq rest incbin byte word dword qword short ptr"
list_NASM_Keywords = Set.fromList $ words $ "absolute bits common extern global org section seg segment strict use16 use32 wrt struc endstruc istruc at iend align alignb __sect__ __nasm_major__ __nasm_minor__ __nasm_subminor__ ___nasm_patchlevel__ __nasm_version_id__ __nasm_ver__ __file__ __line__"

regex_'5cs'2a'5bA'2dZa'2dz0'2d9'5f'2e'24'5d'2b'3a = compileRegex "\\s*[A-Za-z0-9_.$]+:"
regex_'28cmov'7cfcmov'7cj'7cloop'7cset'29'28a'7cae'7cb'7cbe'7cc'7ce'7cg'7cge'7cl'7cle'7cna'7cnae'7cnb'7cnbe'7cnc'7cne'7cng'7cnge'7cnl'7cnle'7cno'7cnp'7cns'7cnz'7co'7cp'7cpe'7cpo'7cs'7cz'29 = compileRegex "(cmov|fcmov|j|loop|set)(a|ae|b|be|c|e|g|ge|l|le|na|nae|nb|nbe|nc|ne|ng|nge|nl|nle|no|np|ns|nz|o|p|pe|po|s|z)"
regex_cpu_'28pentium'7cppro'7cp2'7cp3'7ckatmai'7cp4'7cwillamette'7cprescott'7cia64'29'2a = compileRegex "cpu (pentium|ppro|p2|p3|katmai|p4|willamette|prescott|ia64)*"
regex_'28'5e'7c'5b_'5ct'2c'5d'2b'29'28'28'5c'24'7c0x'29'7b1'7d'5b0'2d9'5d'2b'5ba'2df0'2d9'5d'2a'7c'5ba'2df0'2d9'5d'2bh'29'28'5b_'5ct'2c'5d'2b'7c'24'29 = compileRegex "(^|[ \\t,]+)((\\$|0x){1}[0-9]+[a-f0-9]*|[a-f0-9]+h)([ \\t,]+|$)"
regex_'28'5e'7c'5b_'5ct'2c'5d'2b'29'28'5b0'2d7'5d'2b'28q'7co'29'7c'5b01'5d'2bb'29'28'5b_'5ct'2c'5d'2b'7c'24'29 = compileRegex "(^|[ \\t,]+)([0-7]+(q|o)|[01]+b)([ \\t,]+|$)"

defaultAttributes = [("Normal","Normal Text"),("Comment","Comment"),("Preprocessor","Preprocessor"),("String","String")]

parseRules "Normal" = 
  do (attr, result) <- (((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_registers >>= withAttribute "Registers"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_Data >>= withAttribute "Data"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_instructions >>= withAttribute "Instructions"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_NASM_Keywords >>= withAttribute "NASM Keywords"))
                        <|>
                        ((pDetectChar False ';' >>= withAttribute "Comment") >>~ pushContext "Comment")
                        <|>
                        ((pDetectChar False '%' >>= withAttribute "Preprocessor") >>~ pushContext "Preprocessor")
                        <|>
                        ((pAnyChar "\"'" >>= withAttribute "String") >>~ pushContext "String")
                        <|>
                        ((pColumn 0 >> pRegExpr regex_'5cs'2a'5bA'2dZa'2dz0'2d9'5f'2e'24'5d'2b'3a >>= withAttribute "Label"))
                        <|>
                        ((pRegExpr regex_'28cmov'7cfcmov'7cj'7cloop'7cset'29'28a'7cae'7cb'7cbe'7cc'7ce'7cg'7cge'7cl'7cle'7cna'7cnae'7cnb'7cnbe'7cnc'7cne'7cng'7cnge'7cnl'7cnle'7cno'7cnp'7cns'7cnz'7co'7cp'7cpe'7cpo'7cs'7cz'29 >>= withAttribute "Instructions"))
                        <|>
                        ((pRegExpr regex_cpu_'28pentium'7cppro'7cp2'7cp3'7ckatmai'7cp4'7cwillamette'7cprescott'7cia64'29'2a >>= withAttribute "NASM Keywords"))
                        <|>
                        ((pRegExpr regex_'28'5e'7c'5b_'5ct'2c'5d'2b'29'28'28'5c'24'7c0x'29'7b1'7d'5b0'2d9'5d'2b'5ba'2df0'2d9'5d'2a'7c'5ba'2df0'2d9'5d'2bh'29'28'5b_'5ct'2c'5d'2b'7c'24'29 >>= withAttribute "BaseN"))
                        <|>
                        ((pRegExpr regex_'28'5e'7c'5b_'5ct'2c'5d'2b'29'28'5b0'2d7'5d'2b'28q'7co'29'7c'5b01'5d'2bb'29'28'5b_'5ct'2c'5d'2b'7c'24'29 >>= withAttribute "BaseN"))
                        <|>
                        ((pDetectChar False '$' >>= withAttribute "Number"))
                        <|>
                        ((pHlCOct >>= withAttribute "BaseN"))
                        <|>
                        ((pHlCHex >>= withAttribute "BaseN"))
                        <|>
                        ((pFloat >>= withAttribute "Float"))
                        <|>
                        ((pInt >>= withAttribute "Number"))
                        <|>
                        ((pHlCChar >>= withAttribute "Char")))
     return (attr, result)

parseRules "Comment" = 
  pzero

parseRules "Preprocessor" = 
  pzero

parseRules "String" = 
  do (attr, result) <- ((pAnyChar "\"'" >>= withAttribute "String") >>~ (popContext >> return ()))
     return (attr, result)

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