module Parser
where
import Data.Maybe
import UU.Parsing
import UU.Parsing.Machine(RealParser(..),RealRecogn(..),anaDynE,mkPR)
import ConcreteSyntax
import CommonTypes
import Patterns
import UU.Pretty(text,PP_Doc,empty,(>-<))
import TokenDef
import Data.List (intersperse)
import Data.Char
import Scanner (Input(..),scanLit,input)
import System.FilePath
import Data.List
import Expression
import Macro --marcos
import UU.Scanner.Token
import UU.Scanner.TokenParser
import UU.Scanner.GenToken
import UU.Scanner.GenTokenOrd
import UU.Scanner.GenTokenParser
import UU.Scanner.Position
import UU.Scanner.TokenShow()
import System.Directory
import System.FilePath
import HsTokenScanner
import Options
import Scanner(lowercaseKeywords)


type AGParser = AnaParser Input  Pair Token Pos

pIdentifier, pIdentifierU, pIdentifierExcl :: AGParser Identifier
pIdentifierU = uncurry Ident <$> pConidPos

-- Jeroen (3-10-2012): for some reason using pKeywordAsIdent
-- drastically slows down parsing of some of my AG files, as
-- in: I thought there was some infinite loop in there, but I
-- guess that eventually it could have given an answer. So
-- probably this does generate a lot of ambiguity.
pIdentifier = pIdentifierExcl -- <|> pKeywordAsIdent
pIdentifierExcl = uncurry Ident <$> pVaridPos

-- see Scanner.lowercaseKeywords for the list of keywords that may
-- be used as an identifier. To prevent ambiguities, it's probably
-- sufficient when the keyword is always followed by a token that
-- can never follow an identifier for any possible prefix.
pKeywordAsIdent :: AGParser Identifier
pKeywordAsIdent = pAny (\nm -> Ident nm <$> pKeyPos nm) lowercaseKeywords

parseAG :: Options -> [FilePath] -> String -> IO (AG,[Message Token Pos])
parseAG opts searchPath file = do
  (es,_,_,_,mesg) <- parseFile False opts searchPath file
  return (AG es, mesg)

--marcos
parseAGI :: Options -> [FilePath] -> String -> IO (AG, Maybe String)
parseAGI opts searchPath file
              = do (es,_,_,ext,_) <- parseFile True opts searchPath file
                   return (AG es, ext)


depsAG :: Options -> [FilePath] -> String -> IO ([String], [Message Token Pos])
depsAG opts searchPath file
  = do let fn = normalise file
       (_,_,fs,_,mesgs) <- parseFile False opts searchPath fn
       return (filter (/= fn) fs, mesgs)

-- marcos: added the parameter 'agi' and the 'ext' part
parseFile :: Bool -> Options -> [FilePath] -> String -> IO  ([Elem],[String],[String], Maybe String,[Message Token Pos ])
parseFile = parseFile' []

parseFile' :: [String] -> Bool -> Options -> [FilePath] -> String -> IO  ([Elem],[String],[String], Maybe String,[Message Token Pos ])
parseFile' parsedfiles agi opts searchPath filename
 = do file <- normalise `fmap` resolveFile opts searchPath filename
      if file `elem` parsedfiles
        then return ([], [], parsedfiles, Nothing, [])
        else do
        txt <- readFile file
        let searchPath' = takeDirectory file : searchPath  -- search first relative to the including file
            litMode = ".lag" `isSuffixOf` file
            (files,text) = if litMode then scanLit txt
                           else ([],txt)
            tokens       = input opts (initPos file) text

            steps = parse (pElemsFiles agi) tokens
            stop (_,fs,_,_,_) = null fs
            cont (es,f:fs,allfs,ext,msg)
              = do (ess,fss,allfss,_, msgs) <- parseFile' allfs agi opts searchPath' f
                   return (ess ++ es, fss ++ fs, allfss, ext, msg ++ msgs)
        let (Pair (es,fls,ext) _ ,mesg) = evalStepsMessages steps
        loopp stop cont (es,files ++ fls,file : parsedfiles, ext,mesg)
 where

    --
    -- Option dependent AG Parsers inlined here
    -- to have access to the opts
    -- while retaining sharing
    --

    pElemsFiles :: Bool -> AGParser ([Elem],[String],Maybe String)
    pElemsFiles agi = pFoldr (($),([],[],Nothing)) pElem'
       where pElem' =  addElem <$> pElem
                   <|> pINCLUDE *> (addInc <$> pStringPos)
                   <|> pEXTENDS *> (addExt <$> pStringPos)
             addElem e      (es,fs,ext) = (e:es,   fs, ext)
             addInc  (fn,_) (es,fs,ext)
               | noIncludes opts = (es, fs, ext)  -- skip includes
               | otherwise       = (es,normalise fn:fs, ext)
             addExt  (fn,_) (es,fs,ext)
               | noIncludes opts = (es, fs, ext)  -- skip includes
               | otherwise       = if agi then (es,fs, Just fn') else (es,fn':fs, ext) --marcos
               where fn' = normalise fn

    pCodescrapL = (\(ValToken _ str pos) -> (str, pos))<$>
                        parseScrapL <?> "a code block"

    parseScrapL :: AGParser Token
    parseScrapL
               = let p acc =  (\k (Input pos str next) ->
                               let (sc,rest) = case next of
                                     Just (t@(ValToken TkTextln _ _), rs) -> (t,rs)
                                     _ -> let (tok,p2,inp2) = codescrapL pos str
                                          in (tok, input opts p2 inp2)
                                   steps   = k ( rest)
                               in  (val (acc sc)  steps)
                          )
                 in anaDynE  (mkPR (P (p  ), R (p (const id))))

    pElems :: AGParser Elems
    pElems = pList_ng pElem

    pComplexType =  List   <$> pBracks pTypeEncapsulated
               <|> Maybe  <$ pMAYBE <*> pType
               <|> Either <$ pEITHER <*> pType <*> pType
               <|> Map    <$ pMAP <*> pTypePrimitive <*> pType
               <|> IntMap <$ pINTMAP <*> pType
               <|> OrdSet <$ pSET <*> pType
               <|> IntSet <$ pINTSET
               <|> tuple  <$> pParens (pListSep pComma field)
      where field = (,) <$> ((Just <$> pIdentifier <* pTypeColon) `opt` Nothing) <*> pTypeEncapsulated
            tuple xs = Tuple [(fromMaybe (Ident ("x"++show n) noPos) f, t)
                             | (n,(f,t)) <- zip [1..] xs
                             ]

    pOptClassContext' :: AGParser ClassContext
    pOptClassContext'
      | ocaml opts = pSucceed []
      | otherwise  = pOptClassContext

    pTyVars :: AGParser [Identifier]
    pTyVars
      | ocaml opts = return <$> pTypeVar
                     <|> pSucceed []
                     <|> pParens (pListSep pComma pTypeVar)
      | otherwise  = pList pIdentifier

    pElem :: AGParser Elem
    pElem
         =  (\(pos, ct) -> Data pos ct)
                 <$> (    (\x -> (x, DataConstructor))   <$> (pDATA <|> pTYPE)
                     <|>  (\x -> (x, RecordConstructor)) <$> pRECORD
                     )
                 <*> pOptClassContext'
                 <*> pNontSet
                 <*> pTyVars
                 <*> pOptAttrs
                 <*> pAlts
                 <*> pSucceed False
        <|> Attr <$> pATTR
                 <*> pOptClassContext'
                 <*> pNontSet
                 <*> pOptQuantifiers
                 <*> pAttrs
        <|> Type <$> pTYPE
                 <*> pOptClassContext'
                 <*> pTypeCon
                 <*> pTyVars
                 <*  pEquals
                 <*> pComplexType
        <|> Sem  <$> pSEM
                 <*> pOptClassContext'
                 <*> pNontSet
                 <*> pOptAttrs
                 <*> pOptQuantifiers
                 <*> pSemAlts
        <|> Set  <$> pSET
                 <*> pTypeCon
                 <*> (   False <$ pEquals
                     <|> True  <$ pColon
                     )
                 <*> pNontSet
        <|> Deriving
                 <$> pDERIVING
                 <*> pNontSet
                 <*  pColon
                 <*> pListSep pComma pIdentifierU
        <|> Wrapper
                 <$> pWRAPPER
                 <*> pNontSet
        <|> Nocatas
                 <$> pNOCATAS
                 <*> pNontSet
        <|> Pragma
                 <$> pPRAGMA
                 <*> pList1 pIdentifier
        <|> Module
                 <$> pMODULE
                 <*> pCodescrap'
                 <*> pCodescrap'
                 <*> pCodescrap'
        <|> codeBlock <$> pBlockKind <*> ((Just <$ pATTACH <*> pTypeCon) <|> pSucceed Nothing) <*> pCodeBlock <?> "a statement"
              where codeBlock knd mbNt (txt,pos) = Txt pos knd mbNt (lines txt)

    pBlockKind :: AGParser BlockKind
    pBlockKind =
          BlockPragma <$ pOPTPRAGMAS
      <|> BlockImport <$ pIMPORTS
      <|> BlockMain   <$ pTOPLEVEL   -- block is moved to the toplevel ("main") module when "sepsemmods" is used
      <|> BlockData   <$ pDATABLOCK
      <|> BlockRec    <$ pRECBLOCK
      <|> pSucceed BlockOther

    pAttrs :: AGParser Attrs
    pAttrs
        = Attrs <$> pOBrackPos <*> (concat <$> pList pInhAttrNames <?> "inherited attribute declarations")
                                  <* pBar    <*> (concat <$> pList pAttrNames <?> "chained attribute declarations"  )
                                  <* pBar    <*> (concat <$> pList pAttrNames <?> "synthesised attribute declarations"  )
                   <*  pCBrack
           <|> (\ds -> Attrs (fst $ head ds) [n | (_,(nms,_,_)) <- ds, n <- nms] [n | (_,(_,nms,_)) <- ds, n <- nms] [n | (_,(_,_,nms)) <- ds, n <- nms]) <$> pList1 pSingleAttrDefs

    pSingleAttrDefs :: AGParser (Pos, (AttrNames, AttrNames, AttrNames))
    pSingleAttrDefs
      =    (\p is -> (p, (is,[],[]))) <$> pINH <*> pList1Sep pComma pSingleInhAttrDef
      <|>  (\p is -> (p, ([],[],is))) <$> pSYN <*> pList1Sep pComma pSingleSynAttrDef
      <|>  (\p is -> (p, ([],is,[]))) <$> pCHN <*> pList1Sep pComma pSingleChnAttrDef

    pSingleInhAttrDef :: AGParser (Identifier,Type,(String,String,String))
    pSingleInhAttrDef
      = (\v tp -> (v,tp,("","",""))) <$> pAttrIdentifier <* pTypeColon <*> pTypeOrSelf <?> "inh attribute declaration"

    pSingleSynAttrDef :: AGParser (Identifier,Type,(String,String,String))
    pSingleSynAttrDef
      = (\v u tp -> (v,tp,u)) <$> pAttrIdentifier <*> pUse <* pTypeColon <*> pTypeOrSelf <?> "syn attribute declaration"

    pSingleChnAttrDef :: AGParser (Identifier,Type,(String,String,String))
    pSingleChnAttrDef
      = (\v tp -> (v,tp,("","",""))) <$> pAttrIdentifier <* pTypeColon <*> pTypeOrSelf <?> "chn attribute declaration"

    pOptAttrs :: AGParser Attrs
    pOptAttrs = pAttrs `opt` Attrs noPos [] [] []

    pInhAttrNames :: AGParser AttrNames
    pInhAttrNames
                   = (\vs tp -> map (\v -> (v,tp,("","",""))) vs)
                      <$> pAttrIdentifiers <*  pTypeColon <*> pTypeOrSelf <?> "attribute declarations"

    pAttrNames :: AGParser AttrNames
    pAttrNames
             = (\vs use tp -> map (\v -> (v,tp,use)) vs)
                 <$> pAttrIdentifiers <*> pUse <* pTypeColon <*> pTypeOrSelf <?> "attribute declarations"

    pAlt :: AGParser Alt
    pAlt =   (Alt <$> pBar <*> pSimpleConstructorSet <*> (pList1_ng pTypeVar <* pDot <|> pSucceed []) <*> pFields <*> pMaybeMacro <?> "a datatype alternative")

    pAlts :: AGParser Alts
    pAlts =  pList_ng pAlt <?> "datatype alternatives"

    pFields :: AGParser Fields
    pFields = concat <$> pList_ng pField <?> "fields"

    pField :: AGParser Fields
    pField
           =   (\nms tp -> map (\nm -> FChild nm tp) nms) <$> pAttrIdentifiers <* pTypeColon <*> pType
           <|> (\s   -> [FChild (Ident (mklower $ getName s) (getPos s)) (NT s [] False)]) <$> pIdentifierU
           <|> (\t   -> [FCtx [t]]) <$ pSmallerEqual <*> pTypePrimitive

    pSemAlt :: AGParser SemAlt
    pSemAlt = SemAlt <$> pBar <*> pConstructorSet <*> pSemDefs <?> "SEM alternative"

    pSemAlts :: AGParser SemAlts
    pSemAlts =  pList pSemAlt <?> "SEM alternatives"

    pSemDef :: AGParser [SemDef]
    pSemDef
          =   (\x y fs -> map (\f -> f x y) fs) <$> pMaybeRuleName <*> pFieldIdentifier <*> pList1 pAttrDef
          <|>                            pLOC              *> pList1 pLocDecl
          <|>                            pINST             *> pList1 pInstDecl
          <|>  pSEMPRAGMA *> pList1 (SemPragma <$> pNames)
          <|> (\n e -> [AugmentDef n e]) <$ pAugmentToken <*> pAttrIdentifier <* pAssign <*> pExpr
          <|> (\n e -> [AroundDef n e]) <$ pAROUND <*> pAttrIdentifier <* pAssign <*> pExpr
          <|> (\a b -> [AttrOrderBefore a [b]]) <$> pList1 pAttrOrIdent <* pSmaller <*> pAttrOrIdent
          <|> (\sources target nt expr -> [MergeDef target nt sources expr]) <$ pMERGE <*> (pList1_ng pIdentifier <* pAS <|> pSucceed []) <*> pIdentifier <* pTypeColon <*> pIdentifierU <* pAssign <*> pExpr
          <|> (\mbNm pat (owrt,pos,pur,eager) exp -> [Def pos mbNm (pat ()) exp owrt pur eager]) <$> pMaybeRuleName <*> pPattern (const <$> pAttr) <*> pRuleSym <*> pExpr

    pMaybeRuleName :: AGParser (Maybe Identifier)
    pMaybeRuleName
      =   (Just <$> pIdentifier <* pColon <?> "rule name")
      <|> pSucceed Nothing

    pAttrDef :: AGParser (Maybe Identifier -> Identifier -> SemDef)
    pAttrDef
      = (\pat (owrt,pos,pur,eager) exp mbNm fld -> Def pos mbNm (pat fld) exp owrt pur eager)
               <$ pDot <*> pattern <*> pRuleSym <*> pExpr
      where pattern =  pPattern pVar
                   <|> (\ir a fld -> ir $ Alias fld a (Underscore noPos)) <$> ((Irrefutable <$ pTilde) `opt` id) <*> pAttrIdentifier

    pLocDecl :: AGParser SemDef
    pLocDecl = pDot <**> (pIdentifier <**> (pTypeColon <**> (   (\(tp,pos) _ ident _  -> TypeDef pos ident tp) <$> pLocType
                                                            <|> (\ref _ ident _ -> UniqueDef ident ref) <$ pUNIQUEREF <*> pIdentifier )))

    pLocType :: AGParser (Type, Pos)
    pLocType = (\u -> (Haskell $ getName u, getPos u)) <$> pTypeCon
       <|> (\(s,p) -> (Haskell s,p)) <$> pCodescrap  <?> "a type"

    pInstDecl :: AGParser SemDef
    pInstDecl = (\ident tp -> TypeDef (getPos ident) ident tp)
                  <$ pDot <*> pIdentifier <* pTypeColon <*> pTypeNt

    pSemDefs :: AGParser SemDefs
    pSemDefs =  concat <$> pList_ng pSemDef <?> "attribute rules"

    pExpr :: AGParser Expression
    pExpr = (\(str,pos) ->  Expression pos (lexTokens opts pos str)) <$> pCodescrapL <?> "an expression"

    pTypeColon :: AGParser Pos
    pTypeColon
      = if doubleColons opts
        then pDoubleColon
        else pColon

    --marcos
    pMaybeMacro :: AGParser MaybeMacro
    pMaybeMacro  =  Just <$ pDoubleArrow <*>  pMacro
                <|> pSucceed Nothing

    pMacro :: AGParser Macro
    pMacro
          =  Macro <$> pIdentifierU
                   <*> pList1 pMacroChild
                   <?> "macro"

    pMacroChild :: AGParser MacroChild
    pMacroChild
          =  (pIdentifier <* pEquals) <**>
             (flip RuleChild   <$> pMacro       <|>
              flip ChildChild  <$> pIdentifier  <|>
              flip ValueChild  <$> pCodescrap' )

    pTypeNt :: AGParser Type
    pTypeNt
      =   ((\nt -> mkNtType nt []) <$> pTypeCon <?> "nonterminal name (no brackets)")
      <|> (pParens (mkNtType <$> pTypeCon <*> pList pTypeHaskellAnyAsString) <?> "nonterminal name with parameters (using parenthesis)")

    pTypeCon :: AGParser Identifier
    pTypeCon
      | ocaml opts = pIdentifierExcl
      | otherwise  = pIdentifierU

    pTypeVar :: AGParser Identifier
    pTypeVar
      | ocaml opts = (\(nm, pos) -> Ident nm pos) <$> pTextnmPos
      | otherwise  = pIdentifier

    pTypeHaskellAnyAsString :: AGParser String
    pTypeHaskellAnyAsString
      =   getName <$> pTypeVar
      <|> getName <$> pTypeCon
      <|> pCodescrap' <?> "a type"

    -- if the type is within some kind of parentheses or brackets (then we allow lowercase identifiers as well)
    pTypeEncapsulated :: AGParser Type
    pTypeEncapsulated
      =   pParens pTypeEncapsulated
      <|> mkNtType <$> pTypeCon <*> pList pTypeHaskellAnyAsString
      <|> (Haskell . getName) <$> pTypeVar
      <|> pTypePrimitive

    pTypePrimitive :: AGParser Type
    pTypePrimitive
      = Haskell <$> pCodescrap'  <?> "a type"

    pType :: AGParser Type
    pType =  pTypeNt
          <|> pTypePrimitive

    pTypeOrSelf :: AGParser Type
    pTypeOrSelf = pType <|> Self <$ pSELF

    pOptClassContext :: AGParser ClassContext
    pOptClassContext
      =   pClassContext <* pDoubleArrow
      <|> pSucceed []

    pClassContext :: AGParser ClassContext
    pClassContext
      = pListSep pComma ((,) <$> pIdentifierU <*> pList pTypeHaskellAnyAsString)

    pNontSet = set0 where
        set0 = pChainr (Intersect <$ pIntersect) set1
        set1 = pChainl (Difference <$ pMinus) set2
        set2 = pChainr (pSucceed Union) set3
        set3 = pTypeCon <**> opt (flip Path <$ pArrow <*> pTypeCon) NamedSet
            <|> All <$ pStar
            <|> pParens set0

    --
    -- End of AG Parser
    --

resolveFile :: Options -> [FilePath] -> FilePath -> IO FilePath
resolveFile opts path fname = search (path ++ ["."])
 where search (p:ps) = do let filename = joinPath [p, fname]
                          fExists <- doesFileExist filename
                          if fExists
                            then return filename
                            else do let filename' = joinPath [p, replaceExtension fname "ag"]
                                    fExists' <- doesFileExist filename'
                                    if fExists'
                                      then return filename'
                                      else search ps
       search []     = do
         outputStr opts ("File: " ++ show fname ++ " not found in search path: " ++ show (concat (intersperse ";" (path ++ ["."]))) ++ "\n")
         failWithCode opts 1
         return (error "resolveFile: file not found")

evalStepsMessages :: (Eq s, Show s, Show p) => Steps a s p -> (a,[Message s p])
evalStepsMessages steps = case steps of
  OkVal v        rest -> let (arg,ms) = evalStepsMessages rest
                         in (v arg,ms)
  Ok             rest -> evalStepsMessages rest
  Cost  _        rest -> evalStepsMessages rest
  StRepair _ msg rest -> let (v,ms) = evalStepsMessages rest
                         in (v, msg:ms)
  Best _   rest   _   -> evalStepsMessages rest
  NoMoreSteps v       -> (v,[])

loopp ::(a->Bool) -> (a->IO a) -> a ->  IO a
loopp pred cont x | pred x = return x
                  | otherwise = do x' <- cont x
                                   loopp pred cont x'

codescrapL p []                 = (valueToken TkTextln "" p,p,[])
codescrapL p (x:xs) | isSpace x = (updPos'  x p)  codescrapL xs
                    | otherwise = let refcol = column p
                                      (p',sc,rest) = scrapL refcol p  (x:xs)
                                  in (valueToken TkTextln sc p,p',rest)

scrapL ref p (x:xs) | isSpace x || column p >= ref =
                          let (p'',sc,inp) = updPos'  x p (scrapL ref)  xs
                          in  (p'',x:sc,inp)
                    | otherwise       =(p,[],x:xs)
scrapL ref p []     = (p,[],[])

pNames :: AGParser [Identifier]
pNames = pIdentifiers


-- Insertion is expensive for pCodeBlock in order to prevent infinite inserts.
pCodeBlock ::  AGParser (String,Pos)
pCodeBlock   = pCostValToken 90 TkTextln "" <?> "a code block"

pOptQuantifiers :: AGParser [String]
pOptQuantifiers = (return <$ pDoubleColon <*> pCodescrap') `opt` []

pIdentifiers :: AGParser [Identifier]
pIdentifiers =  pList1Sep pComma pIdentifier <?> "lowercase identifiers"

pAttrIdentifier :: AGParser Identifier
pAttrIdentifier = pIdentifier
                  <|> (\pos -> Ident "imports" pos) <$> pIMPORTS
                  <|> (\pos -> Ident "toplevel" pos) <$> pTOPLEVEL

pAttrIdentifiers :: AGParser [Identifier]
pAttrIdentifiers = pList1Sep pComma pAttrIdentifier <?> "lowercase identifiers"

pUse :: AGParser (String,String,String)
pUse = (  (\u x y->(x,y,show u)) <$> pUSE <*> pCodescrap'  <*> pCodescrap') `opt` ("","","") <?> "USE declaration"

mklower :: String -> String
mklower (x:xs) = toLower x : xs
mklower []     = []

pSimpleConstructorSet :: AGParser ConstructorSet
pSimpleConstructorSet =  CName <$> pIdentifierU
                     <|> CAll  <$  pStar
                     <|> pParens pConstructorSet

pConstructorSet :: AGParser ConstructorSet
pConstructorSet =  pChainl (CDifference <$ pMinus) term2
  where term2 =  pChainr (pSucceed CUnion) term1
        term1 =  CName <$> pIdentifierU
             <|> CAll  <$  pStar

pFieldIdentifier :: AGParser Identifier
pFieldIdentifier =  pIdentifier
                <|> Ident "lhs"  <$> pLHS
                <|> Ident "loc"  <$> pLOC
                <|> Ident "inst" <$> pINST

pAugmentToken :: AGParser ()
pAugmentToken = () <$ (pAUGMENT <|> pPlus)

pAttr = (,) <$> pFieldIdentifier <* pDot <*> pAttrIdentifier

pAttrOrIdent
  = OccAttr <$> pFieldIdentifier <* pDot <*> pAttrIdentifier
  <|> OccRule <$> pIdentifier

nl2sp :: Char -> Char
nl2sp '\n' = ' '
nl2sp '\r' = ' '
nl2sp x = x

pVar :: AGParser (Identifier -> (Identifier, Identifier))
pVar = (\att fld -> (fld,att)) <$> pAttrIdentifier

pAssign :: AGParser Bool
pAssign =  False <$ pReserved "="
       <|> True  <$ pReserved ":="

pRuleSym :: AGParser (Bool, Pos, Bool, Bool)
pRuleSym  =     (\p -> (False, p, True, False)) <$> pReserved "="
            <|> (\p -> (True,  p, True, False)) <$> pReserved ":="
            <|> (\p -> (False, p, True, False)) <$> pReserved "<-"
            <|> (\p -> (False, p, True, True))  <$> pReserved "<<-"

pPattern :: AGParser (a -> (Identifier,Identifier)) -> AGParser (a -> Pattern)
pPattern pvar = pPattern2 where
  pPattern0 =  (\i pats a -> Constr i (map ($ a) pats))
               <$> pIdentifierU <*> pList  pPattern1
               <|> pPattern1 <?> "a pattern"
  pPattern1 =  pvariable
           <|> pPattern2
  pvariable = (\ir var pat a -> case var a of (fld,att) -> ir $ Alias fld att (pat a))
           <$> ((Irrefutable <$ pTilde) `opt` id) <*> pvar <*> ((pAt *> pPattern1) `opt` const (Underscore noPos))
  pPattern2 = (mkTuple <$> pOParenPos <*> pListSep pComma pPattern0 <* pCParen )
          <|> (const . Underscore) <$> pUScore <?> "a pattern"
    where mkTuple _ [x] a = x a
          mkTuple p xs  a = Product p (map ($ a) xs)

pCostSym' c t = pCostSym c t t

pCodescrap' ::  AGParser String
pCodescrap' = fst <$> pCodescrap

pCodescrap ::  AGParser (String,Pos)
pCodescrap   = pCodeBlock

pSEM, pATTR, pDATA, pRECORD, pUSE, pLOC,pINCLUDE, pTYPE, pEquals, pColonEquals, pTilde,
      pEXTENDS, --marcos
      pBar, pColon, pLHS,pINST,pSET,pDERIVING,pMinus,pIntersect,pDoubleArrow,pArrow,
      pDot, pUScore, pEXT,pAt,pStar, pSmaller, pWRAPPER, pNOCATAS, pPRAGMA, pMAYBE, pEITHER, pMAP, pINTMAP,
      pMODULE, pATTACH, pUNIQUEREF, pINH, pSYN, pAUGMENT, pPlus, pAROUND, pSEMPRAGMA, pMERGE, pAS, pSELF,
      pIMPORTS, pOPTPRAGMAS, pSmallerEqual, pINTSET, pDATABLOCK, pRECBLOCK
      :: AGParser Pos
pSET         = pCostReserved 90 "SET"     <?> "SET"
pDERIVING    = pCostReserved 90 "DERIVING"<?> "DERIVING"
pWRAPPER     = pCostReserved 90 "WRAPPER" <?> "WRAPPER"
pNOCATAS     = pCostReserved 90 "NOCATAS" <?> "NOCATAS"
pPRAGMA      = pCostReserved 90 "PRAGMA"  <?> "PRAGMA"
pSEMPRAGMA   = pCostReserved 90 "SEMPRAGMA" <?> "SEMPRAGMA"
pATTACH      = pCostReserved 90 "ATTACH"  <?> "ATTACH"
pDATA        = pCostReserved 90 "DATA"    <?> "DATA"
pRECORD      = pCostReserved 90 "RECORD"  <?> "RECORD"
pEXT         = pCostReserved 90 "EXT"     <?> "EXT"
pATTR        = pCostReserved 90 "ATTR"    <?> "ATTR"
pSEM         = pCostReserved 90 "SEM"     <?> "SEM"
pINCLUDE     = pCostReserved 90 "INCLUDE" <?> "INCLUDE"
pEXTENDS     = pCostReserved 90 "EXTENDS" <?> "EXTENDS" --marcos
pTYPE        = pCostReserved 90 "TYPE"    <?> "TYPE"
pINH         = pCostReserved 90 "INH"     <?> "INH"
pSYN         = pCostReserved 90 "SYN"     <?> "SYN"
pCHN         = pCostReserved 90 "CHN"     <?> "CHN"
pMAYBE       = pCostReserved 5  "MAYBE"   <?> "MAYBE"
pEITHER      = pCostReserved 5  "EITHER"  <?> "EITHER"
pMAP         = pCostReserved 5  "MAP"     <?> "MAP"
pINTMAP      = pCostReserved 5  "INTMAP"  <?> "INTMAP"
pINTSET      = pCostReserved 5  "INTSET"  <?> "INTSET"
pUSE         = pCostReserved 5  "USE"     <?> "USE"
pLOC         = pCostReserved 5  "loc"     <?> "loc"
pLHS         = pCostReserved 5  "lhs"     <?> "loc"
pINST        = pCostReserved 5  "inst"    <?> "inst"
pAt          = pCostReserved 5  "@"       <?> "@"
pDot         = pCostReserved 5  "."       <?> "."
pUScore      = pCostReserved 5  "_"       <?> "_"
pColon       = pCostReserved 5  ":"       <?> ":"
pDoubleColon = pCostReserved 5  "::"      <?> "::"
pEquals      = pCostReserved 5  "="       <?> "="
pColonEquals = pCostReserved 5  ":="      <?> ":="
pTilde       = pCostReserved 5  "~"       <?> "~"
pPlus        = pCostReserved 5  "+"       <?> "+"
pBar         = pCostReserved 5  "|"       <?> "|"
pIntersect   = pCostReserved 5  "/\\"     <?> "/\\"
pMinus       = pCostReserved 5  "-"       <?> "-"
pDoubleArrow = pCostReserved 5  "=>"      <?> "=>"
pSmallerEqual= pCostReserved 5  "<="      <?> "<="
pArrow       = pCostReserved 5  "->"      <?> "->"
pStar        = pCostReserved 5  "*"       <?> "*"
pSmaller     = pCostReserved 5  "<"       <?> "<"
pMODULE      = pCostReserved 5  "MODULE"  <?> "MODULE"
pUNIQUEREF   = pCostReserved 5  "UNIQUEREF" <?> "UNIQUEREF"
pAUGMENT     = pCostReserved 5  "AUGMENT" <?> "AUGMENT"
pAROUND      = pCostReserved 5  "AROUND" <?> "AROUND"
pMERGE       = pCostReserved 5  "MERGE" <?> "MERGE"
pAS          = pCostReserved 5  "AS" <?> "AS"
pSELF        = pCostReserved 5  "SELF" <?> "SELF"
pIMPORTS     = pCostReserved 5  "imports" <?> "imports"
pOPTPRAGMAS  = pCostReserved 5  "optpragmas" <?> "optpragmas"
pTOPLEVEL    = pCostReserved 5  "toplevel" <?> "toplevel"
pDATABLOCK   = pCostReserved 5  "datablock" <?> "datadecl block"
pRECBLOCK    = pCostReserved 5  "recblock" <?> "recursive block"