{- This module was generated from data in the Kate syntax highlighting file metafont.xml, version 0.9,
   by  Yedvilun (yedvilun@gmail.com) -}

module Text.Highlighting.Kate.Syntax.Metafont ( 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 = "Metapost/Metafont"

-- | Filename extensions for this language.
syntaxExtensions :: String
syntaxExtensions = "*.mp;*.mps;*.mpost;*.mf"

-- | 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 = "Metapost/Metafont" }
  context <- currentContext <|> (pushContext "Normal Text" >> 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 [("Metapost/Metafont",["Normal Text"])], synStLanguage = "Metapost/Metafont", synStCurrentLine = "", synStCharsParsedInLine = 0, synStPrevChar = '\n', synStCaseSensitive = True, synStKeywordCaseSensitive = False, synStCaptures = []}

parseSourceLine = manyTill parseExpressionInternal pEndLine

pEndLine = do
  lookAhead $ newline <|> (eof >> return '\n')
  context <- currentContext
  case context of
    "Normal Text" -> return () >> pHandleEndLine
    "string" -> return () >> pHandleEndLine
    "TeXMode" -> return () >> pHandleEndLine
    "ContrSeq" -> (popContext) >> pEndLine
    "ToEndOfLine" -> (popContext) >> pEndLine
    "Verb" -> (popContext >> popContext) >> pEndLine
    "VerbEnd" -> (popContext >> popContext >> popContext) >> pEndLine
    "MathMode" -> return () >> pHandleEndLine
    "MathContrSeq" -> (popContext) >> pEndLine
    "Comment" -> (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 = [("Comment","co"),("Error","al"),("String","st"),("Alert","al"),("Macro","kw"),("Operator","kw"),("Special","kw"),("Conditional","kw"),("BoolExp","kw"),("NumExp","fu"),("Variable","kw"),("Identifier","kw"),("Type","dt"),("Decimal","dv"),("Octal","bn"),("Hex","bn"),("Float","fl")]

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

list_mfBoolExp = Set.fromList $ words $ "true false known unknown odd charexists not and or"
list_mfNumExp = Set.fromList $ words $ "normaldeviate length ascii oct hex angle turningnumber totalweight directiontime xpart ypart xxpart xypart yxpart yypart sqrt sind cosd mlog mexp floor uniformdeviate abs div dotprod max min mod ceiling"
list_mfInternal = Set.fromList $ words $ "tracingtitles tracingequations tracingcapsules tracingchoices tracingspecs tracingpens tracingcommands tracingrestores tracingmacros tracingedges tracingoutput tracingonline tracingstats pausing showstopping fontmaking proofing turningcheck warningcheck smoothing autorounding granularity fillin year month day time charcode charext charwd charht chardp charic chardx chardy designsize hppp vppp xoffset yoffset boundarychar"
list_mfPairExp = Set.fromList $ words $ "point of precontrol postcontrol penoffset rotated scaled shifted slanted transformed xscaled yscaled zscaled"
list_mfPathExp = Set.fromList $ words $ "makepath reverse subpath curl tension atleast controls cycle"
list_mfPenExp = Set.fromList $ words $ "nullpen pencircle makepen"
list_mfPicExp = Set.fromList $ words $ "nullpicture"
list_mfStringExp = Set.fromList $ words $ "jobname readstring str char decimal substring"
list_mfCommand = Set.fromList $ words $ "end dump save interim newinternal randomseed let delimiters outer everyjob show showvariable showtoken showdependencies showstats message errmessage errhelp batchmode nonstopmode scrollmode errorstopmode addto also contour doublepath withpen withweight cull keeping dropping display inwindow openwindow at from to shipout special numspecial"
list_mfType = Set.fromList $ words $ "boolean numeric pair path pen picture string transform"
list_mfDefinition = Set.fromList $ words $ "expr suffix text primary secondary tertiary primarydef secondarydef tertiarydef"
list_mfCondition = Set.fromList $ words $ "else elseif step until upto exitif"
list_mfPrimitive = Set.fromList $ words $ "charlist endinput expandafter extensible fontdimen headerbyte inner input intersectiontimes kern ligtable quote scantokens skipto"
list_mfMacro = Set.fromList $ words $ "addto_currentpicture aspect_ratio base_name base_version blacker blankpicture bot bye byte capsule_def change_width clear_pen_memory clearit clearpen clearxy counterclockwise culldraw cullit currentpen currentpen_path currentpicture currenttransform currentwindow cutdraw cutoff d decr define_blacker_pixels define_corrected_pixels define_good_x_pixels define_good_y_pixels define_horizontal_corrected_pixels define_pixels define_whole_blacker_pixels define_whole_pixels define_whole_vertical_blacker_pixels define_whole_vertical_pixels dir direction directionpoint displaying ditto down downto draw drawdot eps epsilon extra_setup erase exitunless fill filldraw fix_units flex font_coding_scheme font_extra_space font_identifier font_normal_shrink font_normal_space font_normal_stretch font_quad font_setup font_size font_slant font_x_height fullcircle generate gfcorners gobble gobbled grayfont h halfcircle hide hround identity image_rules incr infinity interact interpath intersectionpoint inverse italcorr join_radius killtext labelfont labels left lft localfont loggingall lowres lowres_fix mag magstep makebox makegrid makelabel maketicks mode mode_def mode_name mode_setup nodisplays notransforms number_of_modes numtok o_correction openit origin pen_bot pen_lft pen_rt pen_top penlabels penpos penrazor penspeck pensquare penstroke pickup pixels_per_inch proof proofoffset proofrule proofrulethickness quartercircle range reflectedabout relax right rotatedabout rotatedaround round rt rulepen savepen screenchars screen_rows screen_cols screenrule screenstrokes shipit showit slantfont smode smoke softjoin solve stop superellipse takepower tensepath titlefont tolerance top tracingall tracingnone undraw undrawdot unfill unfilldraw unitpixel unitsquare unitvector up upto vround w whatever"
list_mpInternal = Set.fromList $ words $ "bluepart clip color dashed fontsize greenpart infont linecap linejoin llcorner lrcorner miterlimit mpxbreak prologues redpart setbounds tracinglostchars truecorners ulcorner urcorner withcolor"
list_notDefined = Set.fromList $ words $ "autorounding chardx chardy fillin granularity hppp proofing smoothing tracingedges tracingpens turningcheck vppp xoffset yoffset"
list_mpMacro = Set.fromList $ words $ "ahangle ahlength background bbox bboxmargin beveled black blue buildcycle butt center cutafter cutbefore cuttings dashpattern defaultfont defaultpen defaultscale dotlabel dotlabels drawarrow drawdblarrow drawoptions evenly green label labeloffset mitered red rounded squared thelabel white base_name base_version upto downto exitunless relax gobble gobbled interact loggingall tracingall tracingnone eps epsilon infinity right left up down origin quartercircle halfcircle fullcircle unitsquare identity blankpicture withdots ditto eof pensquare penrazor penspeck whatever round byte dir unitvector inverse counterclockwise tensepath takepower direction directionpoint intersectionpoint softjoin incr decr reflectedabout rotatedaround rotatedabout flex superellipse interpath magstep currentpen currentpen_path currentpicture fill draw filldraw drawdot unfill undraw unfilldraw undrawdot erase cutdraw image pickup numeric_pickup pen_lft pen_rt pen_top pen_bot savepen clearpen clear_pen_memory lft rt top bot ulft urt llft lrt penpos penstroke arrowhead makelabel labels penlabel range numtok thru clearxy clearit clearpen pickup shipit bye hide stop solve blacker capsule_def change_width define_blacker_pixels define_corrected_pixels define_good_x_pixels define_good_y_pixels define_horizontal_corrected_pixels define_pixels define_whole_blacker_pixels define_whole_vertical_blacker_pixels define_whole_vertical_pixels extra_setup font_coding_scheme font_extra_space font_identifier font_normal_shrink font_normal_space font_normal_stretch font_quad font_size font_slant font_x_height italcorr labelfont makebox makegrid maketicks mode_def mode_setup o_correction proofrule proofrulethickness rulepen smode cullit currenttransform gfcorners grayfont hround imagerules lowres_fix nodisplays notransforms openit proofoffset screenchars screenrule screenstrokes showit slantfont titlefont unitpixel vround circmargin defaultdx defaultdy boxit boxjoin bpath circleit drawboxed drawboxes drawunboxed fixpos fixsize pic"
list_EnvDelimiters = Set.fromList $ words $ "beginchar endchar extra_beginchar extra_endchar beginlogochar beginfig endfig extra_beginfig extra_endfig"

regex_'28'5c'2b'7c'5c'2d'7c'5c'2a'7c'5c'2f'7c'5c'3d'7c'5c'3a'5c'3d'29 = compileRegex "(\\+|\\-|\\*|\\/|\\=|\\:\\=)"
regex_'5cb'28bp'7ccc'7ccm'7cdd'7cin'7cmm'7cpc'7cpt'29'5cb = compileRegex "\\b(bp|cc|cm|dd|in|mm|pc|pt)\\b"
regex_'5cb'2d'3f'5cd'2b'28bp'7ccc'7ccm'7cdd'7cin'7cmm'7cpc'7cpt'29'23'3f'5cb = compileRegex "\\b-?\\d+(bp|cc|cm|dd|in|mm|pc|pt)#?\\b"
regex_'5cb'2d'3f'5c'2e'5cd'2b'28bp'7ccc'7ccm'7cdd'7cin'7cmm'7cpc'7cpt'29'23'3f'5cb = compileRegex "\\b-?\\.\\d+(bp|cc|cm|dd|in|mm|pc|pt)#?\\b"
regex_'5cb'2d'3f'5cd'2b'5c'2e'5cd'2b'28bp'7ccc'7ccm'7cdd'7cin'7cmm'7cpc'7cpt'29'23'3f'5cb = compileRegex "\\b-?\\d+\\.\\d+(bp|cc|cm|dd|in|mm|pc|pt)#?\\b"
regex_'5cb'5bxy'5d'5cd'28'5cw'7c'5c'27'29'2a = compileRegex "\\b[xy]\\d(\\w|\\')*"
regex_'5cbz'5cd'28'5cw'7c'5c'27'29'2a = compileRegex "\\bz\\d(\\w|\\')*"
regex_'5cbp'5cd'28'5cw'7c'5c'27'29'2a = compileRegex "\\bp\\d(\\w|\\')*"
regex_'5cb'28verbatimtex'7cbtex'29'5cb = compileRegex "\\b(verbatimtex|btex)\\b"
regex_'5cbbegin'28group'7cfig'7cchar'29'5cb = compileRegex "\\bbegin(group|fig|char)\\b"
regex_'5cbend'28group'7cfig'7cchar'29'5cb = compileRegex "\\bend(group|fig|char)\\b"
regex_'5cbextra'5fbegin'28group'7cfig'7cchar'29'5cb = compileRegex "\\bextra_begin(group|fig|char)\\b"
regex_'5cbextra'5fend'28group'7cfig'7cchar'29'5cb = compileRegex "\\bextra_end(group|fig|char)\\b"
regex_'5cb'28def'7cvardef'29'5cb = compileRegex "\\b(def|vardef)\\b"
regex_'5cbenddef'5cb = compileRegex "\\benddef\\b"
regex_'5cbif'5cb = compileRegex "\\bif\\b"
regex_'5cbfi'5cb = compileRegex "\\bfi\\b"
regex_'5cb'28for'7cforsuffixes'7cforever'29'5cb = compileRegex "\\b(for|forsuffixes|forever)\\b"
regex_'5cbendfor'5cb = compileRegex "\\bendfor\\b"
regex_'5cbetex'5cb = compileRegex "\\betex\\b"
regex_verb'28'3f'3d'5b'5ea'2dzA'2dZ'5d'29 = compileRegex "verb(?=[^a-zA-Z])"
regex_'5ba'2dzA'2dZ'5d'2b'28'5c'2b'3f'7c'5c'2a'7b0'2c3'7d'29 = compileRegex "[a-zA-Z]+(\\+?|\\*{0,3})"
regex_'5b'5ea'2dzA'2dZ'5d = compileRegex "[^a-zA-Z]"
regex_'5ba'2dzA'2dZ'5d'2b'5c'2a'3f = compileRegex "[a-zA-Z]+\\*?"
regex_'28FIXME'7cTODO'29'3a'3f = compileRegex "(FIXME|TODO):?"

defaultAttributes = [("Normal Text","Normal Text"),("string","String"),("TeXMode","Tex"),("ContrSeq","Keyword"),("ToEndOfLine","Normal Text"),("Verb","Verbatim"),("VerbEnd","Verbatim"),("MathMode","Math"),("MathContrSeq","Keyword Mathmode"),("Comment","Comment")]

parseRules "Normal Text" = 
  do (attr, result) <- (((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfBoolExp >>= withAttribute "BoolExp"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfNumExp >>= withAttribute "NumExp"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfInternal >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfPairExp >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfPathExp >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfPenExp >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfPicExp >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfStringExp >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfCommand >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfType >>= withAttribute "Type"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" Set.empty >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfDefinition >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfCondition >>= withAttribute "Conditional"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfPrimitive >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mfMacro >>= withAttribute "Macro"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mpInternal >>= withAttribute "Statement"))
                        <|>
                        ((pKeyword " \n\t.():!+,-<=>%&*/;?[]^{|}~\\" list_mpMacro >>= withAttribute "Macro"))
                        <|>
                        ((pDetectChar False '%' >>= withAttribute "Comment") >>~ pushContext "Comment")
                        <|>
                        ((pDetectChar False '"' >>= withAttribute "String") >>~ pushContext "string")
                        <|>
                        ((pRegExpr regex_'28'5c'2b'7c'5c'2d'7c'5c'2a'7c'5c'2f'7c'5c'3d'7c'5c'3a'5c'3d'29 >>= withAttribute "Operator"))
                        <|>
                        ((pDetect2Chars False '.' '.' >>= withAttribute "Operator"))
                        <|>
                        ((pHlCOct >>= withAttribute "Octal"))
                        <|>
                        ((pHlCHex >>= withAttribute "Hex"))
                        <|>
                        ((pFloat >>= withAttribute "Float"))
                        <|>
                        ((pInt >>= withAttribute "Decimal"))
                        <|>
                        ((pRegExpr regex_'5cb'28bp'7ccc'7ccm'7cdd'7cin'7cmm'7cpc'7cpt'29'5cb >>= withAttribute "Float"))
                        <|>
                        ((pRegExpr regex_'5cb'2d'3f'5cd'2b'28bp'7ccc'7ccm'7cdd'7cin'7cmm'7cpc'7cpt'29'23'3f'5cb >>= withAttribute "Float"))
                        <|>
                        ((pRegExpr regex_'5cb'2d'3f'5c'2e'5cd'2b'28bp'7ccc'7ccm'7cdd'7cin'7cmm'7cpc'7cpt'29'23'3f'5cb >>= withAttribute "Float"))
                        <|>
                        ((pRegExpr regex_'5cb'2d'3f'5cd'2b'5c'2e'5cd'2b'28bp'7ccc'7ccm'7cdd'7cin'7cmm'7cpc'7cpt'29'23'3f'5cb >>= withAttribute "Float"))
                        <|>
                        ((pRegExpr regex_'5cb'5bxy'5d'5cd'28'5cw'7c'5c'27'29'2a >>= withAttribute "Variable"))
                        <|>
                        ((pRegExpr regex_'5cbz'5cd'28'5cw'7c'5c'27'29'2a >>= withAttribute "Variable"))
                        <|>
                        ((pRegExpr regex_'5cbp'5cd'28'5cw'7c'5c'27'29'2a >>= withAttribute "Variable"))
                        <|>
                        ((pDetectChar False '$' >>= withAttribute "Special"))
                        <|>
                        ((pRegExpr regex_'5cb'28verbatimtex'7cbtex'29'5cb >>= withAttribute "Identifier") >>~ pushContext "TeXMode")
                        <|>
                        ((pRegExpr regex_'5cbbegin'28group'7cfig'7cchar'29'5cb >>= withAttribute "Identifier"))
                        <|>
                        ((pRegExpr regex_'5cbend'28group'7cfig'7cchar'29'5cb >>= withAttribute "Identifier"))
                        <|>
                        ((pRegExpr regex_'5cbextra'5fbegin'28group'7cfig'7cchar'29'5cb >>= withAttribute "Identifier"))
                        <|>
                        ((pRegExpr regex_'5cbextra'5fend'28group'7cfig'7cchar'29'5cb >>= withAttribute "Identifier"))
                        <|>
                        ((pRegExpr regex_'5cb'28def'7cvardef'29'5cb >>= withAttribute "Identifier"))
                        <|>
                        ((pRegExpr regex_'5cbenddef'5cb >>= withAttribute "Identifier"))
                        <|>
                        ((pRegExpr regex_'5cbif'5cb >>= withAttribute "Conditional"))
                        <|>
                        ((pRegExpr regex_'5cbfi'5cb >>= withAttribute "Conditional"))
                        <|>
                        ((pRegExpr regex_'5cb'28for'7cforsuffixes'7cforever'29'5cb >>= withAttribute "Conditional"))
                        <|>
                        ((pRegExpr regex_'5cbendfor'5cb >>= withAttribute "Conditional")))
     return (attr, result)

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

parseRules "TeXMode" = 
  do (attr, result) <- (((pDetectChar False '\\' >>= withAttribute "Keyword") >>~ pushContext "ContrSeq")
                        <|>
                        ((pDetectChar False '$' >>= withAttribute "Math") >>~ pushContext "MathMode")
                        <|>
                        ((pString False "\\(" >>= withAttribute "Math") >>~ pushContext "MathMode")
                        <|>
                        ((pRegExpr regex_'5cbetex'5cb >>= withAttribute "Identifier") >>~ (popContext)))
     return (attr, result)

parseRules "ContrSeq" = 
  do (attr, result) <- (((pString False "verb*" >>= withAttribute "Keyword") >>~ pushContext "Verb")
                        <|>
                        ((pRegExpr regex_verb'28'3f'3d'5b'5ea'2dzA'2dZ'5d'29 >>= withAttribute "Keyword") >>~ pushContext "Verb")
                        <|>
                        ((pDetectChar False '\215' >>= withAttribute "Bullet"))
                        <|>
                        ((pRegExpr regex_'5ba'2dzA'2dZ'5d'2b'28'5c'2b'3f'7c'5c'2a'7b0'2c3'7d'29 >>= withAttribute "Keyword") >>~ (popContext))
                        <|>
                        ((pRegExpr regex_'5b'5ea'2dzA'2dZ'5d >>= withAttribute "Keyword") >>~ (popContext)))
     return (attr, result)

parseRules "ToEndOfLine" = 
  pzero

parseRules "Verb" = 
  do (attr, result) <- ((pRegExprDynamic "(.)" >>= withAttribute "Normal Text") >>~ pushContext "VerbEnd")
     return (attr, result)

parseRules "VerbEnd" = 
  do (attr, result) <- (((pString True "%1" >>= withAttribute "Normal Text") >>~ (popContext >> popContext >> popContext))
                        <|>
                        ((pDetectChar False '\215' >>= withAttribute "Bullet"))
                        <|>
                        ((pRegExprDynamic "[^%1\\xd7]*" >>= withAttribute "Verbatim")))
     return (attr, result)

parseRules "MathMode" = 
  do (attr, result) <- (((pString False "$$" >>= withAttribute "Error"))
                        <|>
                        ((pDetectChar False '\\' >>= withAttribute "Keyword Mathmode") >>~ pushContext "MathContrSeq")
                        <|>
                        ((pDetectChar False '$' >>= withAttribute "Math") >>~ (popContext))
                        <|>
                        ((pDetect2Chars False '\\' ')' >>= withAttribute "Math") >>~ (popContext))
                        <|>
                        ((pDetect2Chars False '\\' ']' >>= withAttribute "Error")))
     return (attr, result)

parseRules "MathContrSeq" = 
  do (attr, result) <- (((pDetectChar False '\215' >>= withAttribute "Bullet"))
                        <|>
                        ((pRegExpr regex_'5ba'2dzA'2dZ'5d'2b'5c'2a'3f >>= withAttribute "Keyword Mathmode") >>~ (popContext))
                        <|>
                        ((pRegExpr regex_'5b'5ea'2dzA'2dZ'5d >>= withAttribute "Keyword Mathmode") >>~ (popContext)))
     return (attr, result)

parseRules "Comment" = 
  do (attr, result) <- (((pRegExpr regex_'28FIXME'7cTODO'29'3a'3f >>= withAttribute "Alert"))
                        <|>
                        ((pDetectChar False '\215' >>= withAttribute "Bullet")))
     return (attr, result)

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