
--==========================================================--
--=== The parser.                                        ===--
--===                                          Parser.hs ===--
--==========================================================--

module Parser where

{- FIX THESE UP -}
--utLookupDef env k def
--   = head ( [ vv | (kk,vv) <- env, kk == k] ++ [def] )
panic = error
{- END FIXUPS -}

--paLiteral :: Parser Literal
paLiteral
   = pgAlts 
     [
        pgApply (LiteralInt.leStringToInt) (pgItem Lintlit),
        pgApply (LiteralChar.head)         (pgItem Lcharlit),
        pgApply LiteralString              (pgItem Lstringlit)
     ]

paExpr
   = pgAlts 
     [
        paCaseExpr, 
        paLetExpr, 
        paLamExpr,
        paIfExpr,
        paUnaryMinusExpr,
        hsDoExpr []
     ]

paUnaryMinusExpr
   = pgThen2
        (\minus (_, aexpr, _) -> 
             ExprApp (ExprApp (ExprVar "-") (ExprLiteral (LiteralInt 0))) aexpr)
        paMinus
        paAExpr

paCaseExpr
   = pgThen4
        (\casee expr off alts -> ExprCase expr alts)
        (pgItem Lcase)
        paExpr
        (pgItem Lof)
        (pgDeclList paAlt)

paAlt
   = pgAlts
     [
        pgThen4
           (\pat arrow expr wheres 
                -> MkExprCaseAlt pat (pa_MakeWhereExpr expr wheres))
           paPat
           (pgItem Larrow)
           paExpr
           (pgOptional paWhereClause),
        pgThen3
           (\pat agrdrhss wheres
                -> MkExprCaseAlt pat
                      (pa_MakeWhereExpr (ExprGuards agrdrhss) wheres))
           paPat
           (pgOneOrMore paGalt)
           (pgOptional paWhereClause)
     ]

paGalt
   = pgThen4
        (\bar guard arrow expr -> (guard, expr))
        (pgItem Lbar)
        paExpr
        (pgItem Larrow)
        paExpr

paLamExpr
   = pgThen4
        (\lam patterns arrow rhs -> ExprLam patterns rhs)
        (pgItem Lslash)
        (pgZeroOrMore paAPat)
        (pgItem Larrow)
        paExpr

paLetExpr
   = pgThen4
        (\lett decls inn rhs -> ExprLetrec decls rhs)
        (pgItem Llet)
        paValdefs
        (pgItem Lin)
        paExpr

paValdefs 
   = pgApply pa_MergeValdefs (pgDeclList paValdef)

pa_MergeValdefs 
   = id

paLhs
   = pgAlts
     [
        pgThen2 (\v ps -> LhsVar v ps) paVar (pgOneOrMore paPat),
        pgApply LhsPat paPat
     ]

paValdef
   = pgAlts
     [
        pgThen4
           (\(line, lhs) eq rhs wheres 
                -> MkValBind line lhs (pa_MakeWhereExpr rhs wheres))
           (pgGetLineNumber paLhs)
           (pgItem Lequals)
           paExpr
           (pgOptional paWhereClause),
        pgThen3
           (\(line, lhs) grdrhss wheres 
                -> MkValBind line lhs 
                      (pa_MakeWhereExpr (ExprGuards grdrhss) wheres))
           (pgGetLineNumber paLhs)
           (pgOneOrMore paGrhs)
           (pgOptional paWhereClause)
     ]

pa_MakeWhereExpr expr Nothing 
   = expr
pa_MakeWhereExpr expr (Just whereClauses) 
   = ExprWhere expr whereClauses

paWhereClause
   = pgThen2 (\x y -> y) (pgItem Lwhere) paValdefs
paGrhs
   = pgThen4
        (\bar guard equals expr -> (guard, expr))
        (pgItem Lbar)
        paExpr
        (pgItem Lequals)
        paExpr
        

paAPat
   = pgAlts
     [
        pgApply PatVar paVar,
        pgApply (\id -> PatCon id []) paCon,
        pgApply (const PatWild) (pgItem Lunder),
        pgApply PatTuple
                (pgThen3 (\l es r -> es)
                         (pgItem Llparen) 
                         (pgTwoOrMoreWithSep paPat (pgItem Lcomma))
                         (pgItem Lrparen)),
        pgApply PatList
                (pgThen3 (\l es r -> es)
                         (pgItem Llbrack) 
                         (pgZeroOrMoreWithSep paPat (pgItem Lcomma))
                         (pgItem Lrbrack)),
        pgThen3 (\l p r -> p)
                (pgItem Llparen)
                paPat
                (pgItem Lrparen)
     ]

paPat
   = pgAlts
     [
        pgThen2 (\c ps -> PatCon c ps)
                paCon
                (pgOneOrMore paAPat),
        pgThen3 (\ap c pa -> PatCon c [ap,pa])
                paAPat
                paConop
                paPat,
        paAPat
     ]


paIfExpr
 = pgThen4
      (\iff c thenn (t,f) -> ExprIf c t f)
      (pgItem Lif)
      paExpr
      (pgItem Lthen)
      (pgThen3
         (\t elsee f -> (t,f))
         paExpr
         (pgItem Lelse)
         paExpr
      )

paAExpr
 = pgApply (\x -> (False, x, []))
   (pgAlts 
    [
       pgApply ExprVar paVar,
       pgApply ExprCon paCon,
       pgApply ExprLiteral paLiteral,
       pgApply ExprList paListExpr,
       pgApply ExprTuple paTupleExpr,
       pgThen3 (\l e r -> e) (pgItem Llparen) paExpr (pgItem Lrparen)
    ]
   )

paListExpr
   = pgThen3 (\l es r -> es) 
             (pgItem Llbrack) 
             (pgZeroOrMoreWithSep paExpr (pgItem Lcomma))
             (pgItem Lrbrack)

paTupleExpr
   = pgThen3 (\l es r -> es) 
             (pgItem Llparen) 
             (pgTwoOrMoreWithSep paExpr (pgItem Lcomma))
             (pgItem Lrparen)

paVar = pgItem Lvar
paCon = pgItem Lcon
paVarop = pgItem Lvarop
paConop = pgItem Lconop
paMinus = pgItem Lminus

paOp
 = pgAlts [
            pgApply (\x -> (True, ExprVar x, x)) paVarop,
            pgApply (\x -> (True, ExprCon x, x)) paConop,
            pgApply (\x -> (True, ExprVar x, x)) paMinus
          ]

paDataDecl
   = pgThen2
        (\dataa useful -> useful)
        (pgItem Ldata)
        paDataDecl_main

paDataDecl_main
   = pgThen4
        (\name params eq drhs -> MkDataDecl name (params, drhs))
        paCon
        (pgZeroOrMore paVar)
        (pgItem Lequals)
        (pgOneOrMoreWithSep paConstrs (pgItem Lbar))

paConstrs
   = pgThen2
        (\con texprs -> (con, texprs))
        paCon
        (pgZeroOrMore paAType)

paType 
   = pgAlts
     [
        pgThen3 
           (\atype arrow typee -> TypeArr atype typee)
           paAType
           (pgItem Larrow)
           paType,
        pgThen2
           TypeCon
           paCon
           (pgOneOrMore paAType),
        paAType
     ]

paAType
   = pgAlts
     [
        pgApply TypeVar paVar,
        pgApply (\tycon -> TypeCon tycon []) paCon,
        pgThen3
           (\l t r -> t)
           (pgItem Llparen)
           paType
           (pgItem Lrparen),
        pgThen3
           (\l t r -> TypeList t)
           (pgItem Llbrack)
           paType
           (pgItem Lrbrack),
        pgThen3
           (\l t r -> TypeTuple t)
           (pgItem Llparen)
           (pgTwoOrMoreWithSep paType (pgItem Lcomma))
           (pgItem Lrparen)
     ]

paInfixDecl env toks
  = let dump (ExprVar v) = v
        dump (ExprCon c) = c
    in
    pa_UpdateFixityEnv 
       (pgThen3
          (\assoc prio name -> MkFixDecl name (assoc, prio))
          paInfixWord
          (pgApply leStringToInt (pgItem Lintlit)) 
          (pgApply (\(_, op, _) -> dump op) paOp)
          env 
          toks 
       )

paInfixWord
  = pgAlts
    [
       pgApply (const InfixL) (pgItem Linfixl),
       pgApply (const InfixR) (pgItem Linfixr),
       pgApply (const InfixN) (pgItem Linfix)
    ]

pa_UpdateFixityEnv (PFail tok) 
   = PFail tok

pa_UpdateFixityEnv (POk env toks (MkFixDecl name assoc_prio))
   = let 
         new_env = (name, assoc_prio) : env
     in
         POk new_env toks (MkFixDecl name assoc_prio)

paTopDecl
   = pgAlts
     [
        pgApply MkTopF paInfixDecl,
        pgApply MkTopD paDataDecl,
        pgApply MkTopV paValdef
     ]

paModule
   = pgThen4
        (\modyule name wheree topdecls -> MkModule name topdecls)
        (pgItem Lmodule)
        paCon
        (pgItem Lwhere)
        (pgDeclList paTopDecl)
   
parser_test toks
   = let parser_to_test
            = --paPat
              --paExpr
              --paValdef
              --pgZeroOrMore paInfixDecl
              --paDataDecl
              --paType
              paModule
              --pgTwoOrMoreWithSep (pgItem Lsemi) (pgItem Lcomma)
              
     in
         parser_to_test hsPrecTable toks

--==============================================--
--=== The Operator-Precedence parser (yuck!) ===--
--==============================================--

--
--==========================================================--
--
hsAExprOrOp 
 = pgAlts [paAExpr, paOp]

--hsDoExpr :: [PEntry] -> Parser Expr
-- [PaEntry] is a stack of operators and atomic expressions
-- hsDoExpr uses a parser (hsAexpOrOp :: Parsr PaEntry) for atomic
-- expressions or operators

hsDoExpr stack env toks = 
  let
     (validIn, restIn, parseIn, err)
        = case hsAExprOrOp env toks of
             POk env1 toks1 item1
                -> (True, toks1, item1, panic "hsDoExpr(1)")
             PFail err
                -> (False, panic "hsDoExpr(2)", panic "hsDoExpr(3)", err)
     (opIn, valueIn, nameIn)
        = parseIn
     (assocIn, priorIn)
        = utLookupDef env nameIn (InfixL, 9)
     shift
        = hsDoExpr (parseIn:stack) env restIn
  in 
     case stack of
        s1:s2:s3:ss
           | validIn && opS2 && opIn && priorS2 > priorIn
              -> reduce
           | validIn && opS2 && opIn && priorS2 == priorIn
              -> if assocS2 == InfixL && 
                    assocIn == InfixL 
                 then reduce
             else 
                 if assocS2 == InfixR && 
                    assocIn == InfixR 
                 then shift
             else PFail (head toks) -- Because of ambiguousness 
           | not validIn && opS2
              -> reduce
             where
               (opS1, valueS1, nameS1) = s1
               (opS2, valueS2, nameS2) = s2
               (opS3, valueS3, nameS3) = s3
               (assocS2, priorS2) = utLookupDef env nameS2 (InfixL, 9)
               reduce = hsDoExpr ((False, ExprApp (ExprApp valueS2 valueS3) 
                                                  valueS1, [])
                                  : ss) env toks
        s1:s2:ss
           | validIn && (opS1 || opS2) -> shift
           | otherwise -> reduce
             where
                (opS1, valueS1, nameS1) = s1
                (opS2, valueS2, nameS2) = s2
                reduce = hsDoExpr ((False, ExprApp valueS2 valueS1, []) : ss) 
                                  env toks
        (s1:[])
           | validIn -> shift
           | otherwise -> POk env toks valueS1
             where
                (opS1, valueS1, nameS1) = s1
        []
           | validIn -> shift
           | otherwise -> PFail err

--==========================================================--
--=== end                                      Parser.hs ===--
--==========================================================--


hsPrecTable = [
  ("-",     (InfixL, 6)),
  ("+",     (InfixL, 6)),
  ("*",     (InfixL, 7)),
  ("div",   (InfixN, 7)),
  ("mod",   (InfixN, 7)),

  ("<",     (InfixN, 4)),
  ("<=",    (InfixN, 4)),
  ("==",    (InfixN, 4)),
  ("/=",    (InfixN, 4)),
  (">=",    (InfixN, 4)),
  (">",     (InfixN, 4)),

  ("C:",        (InfixR, 5)),
  ("++",        (InfixR, 5)),
  ("\\",        (InfixN, 5)),
  ("!!",        (InfixL, 9)),
  (".",         (InfixR, 9)),
  ("^",         (InfixR, 8)),
  ("elem",      (InfixN, 4)),
  ("notElem",   (InfixN, 4)),

  ("||",    (InfixR, 2)),
  ("&&",    (InfixR, 3))]

{- FIX THESE UP -}
--utLookupDef env k def
--   = head ( [ vv | (kk,vv) <- env, kk == k] ++ [def] )
panic = error
{- END FIXUPS -}

--paLiteral :: Parser Literal
paLiteral
   = pgAlts 
     [
        pgApply (LiteralInt.leStringToInt) (pgItem Lintlit),
        pgApply (LiteralChar.head)         (pgItem Lcharlit),
        pgApply LiteralString              (pgItem Lstringlit)
     ]

paExpr
   = pgAlts 
     [
        paCaseExpr, 
        paLetExpr, 
        paLamExpr,
        paIfExpr,
        paUnaryMinusExpr,
        hsDoExpr []
     ]

paUnaryMinusExpr
   = pgThen2
        (\minus (_, aexpr, _) -> 
             ExprApp (ExprApp (ExprVar "-") (ExprLiteral (LiteralInt 0))) aexpr)
        paMinus
        paAExpr

paCaseExpr
   = pgThen4
        (\casee expr off alts -> ExprCase expr alts)
        (pgItem Lcase)
        paExpr
        (pgItem Lof)
        (pgDeclList paAlt)

paAlt
   = pgAlts
     [
        pgThen4
           (\pat arrow expr wheres 
                -> MkExprCaseAlt pat (pa_MakeWhereExpr expr wheres))
           paPat
           (pgItem Larrow)
           paExpr
           (pgOptional paWhereClause),
        pgThen3
           (\pat agrdrhss wheres
                -> MkExprCaseAlt pat
                      (pa_MakeWhereExpr (ExprGuards agrdrhss) wheres))
           paPat
           (pgOneOrMore paGalt)
           (pgOptional paWhereClause)
     ]

paGalt
   = pgThen4
        (\bar guard arrow expr -> (guard, expr))
        (pgItem Lbar)
        paExpr
        (pgItem Larrow)
        paExpr

paLamExpr
   = pgThen4
        (\lam patterns arrow rhs -> ExprLam patterns rhs)
        (pgItem Lslash)
        (pgZeroOrMore paAPat)
        (pgItem Larrow)
        paExpr

paLetExpr
   = pgThen4
        (\lett decls inn rhs -> ExprLetrec decls rhs)
        (pgItem Llet)
        paValdefs
        (pgItem Lin)
        paExpr

paValdefs 
   = pgApply pa_MergeValdefs (pgDeclList paValdef)

pa_MergeValdefs 
   = id

paLhs
   = pgAlts
     [
        pgThen2 (\v ps -> LhsVar v ps) paVar (pgOneOrMore paPat),
        pgApply LhsPat paPat
     ]

paValdef
   = pgAlts
     [
        pgThen4
           (\(line, lhs) eq rhs wheres 
                -> MkValBind line lhs (pa_MakeWhereExpr rhs wheres))
           (pgGetLineNumber paLhs)
           (pgItem Lequals)
           paExpr
           (pgOptional paWhereClause),
        pgThen3
           (\(line, lhs) grdrhss wheres 
                -> MkValBind line lhs 
                      (pa_MakeWhereExpr (ExprGuards grdrhss) wheres))
           (pgGetLineNumber paLhs)
           (pgOneOrMore paGrhs)
           (pgOptional paWhereClause)
     ]

pa_MakeWhereExpr expr Nothing 
   = expr
pa_MakeWhereExpr expr (Just whereClauses) 
   = ExprWhere expr whereClauses

paWhereClause
   = pgThen2 (\x y -> y) (pgItem Lwhere) paValdefs
paGrhs
   = pgThen4
        (\bar guard equals expr -> (guard, expr))
        (pgItem Lbar)
        paExpr
        (pgItem Lequals)
        paExpr
        

paAPat
   = pgAlts
     [
        pgApply PatVar paVar,
        pgApply (\id -> PatCon id []) paCon,
        pgApply (const PatWild) (pgItem Lunder),
        pgApply PatTuple
                (pgThen3 (\l es r -> es)
                         (pgItem Llparen) 
                         (pgTwoOrMoreWithSep paPat (pgItem Lcomma))
                         (pgItem Lrparen)),
        pgApply PatList
                (pgThen3 (\l es r -> es)
                         (pgItem Llbrack) 
                         (pgZeroOrMoreWithSep paPat (pgItem Lcomma))
                         (pgItem Lrbrack)),
        pgThen3 (\l p r -> p)
                (pgItem Llparen)
                paPat
                (pgItem Lrparen)
     ]

paPat
   = pgAlts
     [
        pgThen2 (\c ps -> PatCon c ps)
                paCon
                (pgOneOrMore paAPat),
        pgThen3 (\ap c pa -> PatCon c [ap,pa])
                paAPat
                paConop
                paPat,
        paAPat
     ]


paIfExpr
 = pgThen4
      (\iff c thenn (t,f) -> ExprIf c t f)
      (pgItem Lif)
      paExpr
      (pgItem Lthen)
      (pgThen3
         (\t elsee f -> (t,f))
         paExpr
         (pgItem Lelse)
         paExpr
      )

paAExpr
 = pgApply (\x -> (False, x, []))
   (pgAlts 
    [
       pgApply ExprVar paVar,
       pgApply ExprCon paCon,
       pgApply ExprLiteral paLiteral,
       pgApply ExprList paListExpr,
       pgApply ExprTuple paTupleExpr,
       pgThen3 (\l e r -> e) (pgItem Llparen) paExpr (pgItem Lrparen)
    ]
   )

paListExpr
   = pgThen3 (\l es r -> es) 
             (pgItem Llbrack) 
             (pgZeroOrMoreWithSep paExpr (pgItem Lcomma))
             (pgItem Lrbrack)

paTupleExpr
   = pgThen3 (\l es r -> es) 
             (pgItem Llparen) 
             (pgTwoOrMoreWithSep paExpr (pgItem Lcomma))
             (pgItem Lrparen)

paVar = pgItem Lvar
paCon = pgItem Lcon
paVarop = pgItem Lvarop
paConop = pgItem Lconop
paMinus = pgItem Lminus

paOp
 = pgAlts [
            pgApply (\x -> (True, ExprVar x, x)) paVarop,
            pgApply (\x -> (True, ExprCon x, x)) paConop,
            pgApply (\x -> (True, ExprVar x, x)) paMinus
          ]

paDataDecl
   = pgThen2
        (\dataa useful -> useful)
        (pgItem Ldata)
        paDataDecl_main

paDataDecl_main
   = pgThen4
        (\name params eq drhs -> MkDataDecl name (params, drhs))
        paCon
        (pgZeroOrMore paVar)
        (pgItem Lequals)
        (pgOneOrMoreWithSep paConstrs (pgItem Lbar))

paConstrs
   = pgThen2
        (\con texprs -> (con, texprs))
        paCon
        (pgZeroOrMore paAType)

paType 
   = pgAlts
     [
        pgThen3 
           (\atype arrow typee -> TypeArr atype typee)
           paAType
           (pgItem Larrow)
           paType,
        pgThen2
           TypeCon
           paCon
           (pgOneOrMore paAType),
        paAType
     ]

paAType
   = pgAlts
     [
        pgApply TypeVar paVar,
        pgApply (\tycon -> TypeCon tycon []) paCon,
        pgThen3
           (\l t r -> t)
           (pgItem Llparen)
           paType
           (pgItem Lrparen),
        pgThen3
           (\l t r -> TypeList t)
           (pgItem Llbrack)
           paType
           (pgItem Lrbrack),
        pgThen3
           (\l t r -> TypeTuple t)
           (pgItem Llparen)
           (pgTwoOrMoreWithSep paType (pgItem Lcomma))
           (pgItem Lrparen)
     ]

paInfixDecl env toks
  = let dump (ExprVar v) = v
        dump (ExprCon c) = c
    in
    pa_UpdateFixityEnv 
       (pgThen3
          (\assoc prio name -> MkFixDecl name (assoc, prio))
          paInfixWord
          (pgApply leStringToInt (pgItem Lintlit)) 
          (pgApply (\(_, op, _) -> dump op) paOp)
          env 
          toks 
       )

paInfixWord
  = pgAlts
    [
       pgApply (const InfixL) (pgItem Linfixl),
       pgApply (const InfixR) (pgItem Linfixr),
       pgApply (const InfixN) (pgItem Linfix)
    ]

pa_UpdateFixityEnv (PFail tok) 
   = PFail tok

pa_UpdateFixityEnv (POk env toks (MkFixDecl name assoc_prio))
   = let 
         new_env = (name, assoc_prio) : env
     in
         POk new_env toks (MkFixDecl name assoc_prio)

paTopDecl
   = pgAlts
     [
        pgApply MkTopF paInfixDecl,
        pgApply MkTopD paDataDecl,
        pgApply MkTopV paValdef
     ]

paModule
   = pgThen4
        (\modyule name wheree topdecls -> MkModule name topdecls)
        (pgItem Lmodule)
        paCon
        (pgItem Lwhere)
        (pgDeclList paTopDecl)
   
parser_test toks
   = let parser_to_test
            = --paPat
              --paExpr
              --paValdef
              --pgZeroOrMore paInfixDecl
              --paDataDecl
              --paType
              paModule
              --pgTwoOrMoreWithSep (pgItem Lsemi) (pgItem Lcomma)
              
     in
         parser_to_test hsPrecTable toks

--==============================================--
--=== The Operator-Precedence parser (yuck!) ===--
--==============================================--

--
--==========================================================--
--
hsAExprOrOp 
 = pgAlts [paAExpr, paOp]

--hsDoExpr :: [PEntry] -> Parser Expr
-- [PaEntry] is a stack of operators and atomic expressions
-- hsDoExpr uses a parser (hsAexpOrOp :: Parsr PaEntry) for atomic
-- expressions or operators

hsDoExpr stack env toks = 
  let
     (validIn, restIn, parseIn, err)
        = case hsAExprOrOp env toks of
             POk env1 toks1 item1
                -> (True, toks1, item1, panic "hsDoExpr(1)")
             PFail err
                -> (False, panic "hsDoExpr(2)", panic "hsDoExpr(3)", err)
     (opIn, valueIn, nameIn)
        = parseIn
     (assocIn, priorIn)
        = utLookupDef env nameIn (InfixL, 9)
     shift
        = hsDoExpr (parseIn:stack) env restIn
  in 
     case stack of
        s1:s2:s3:ss
           | validIn && opS2 && opIn && priorS2 > priorIn
              -> reduce
           | validIn && opS2 && opIn && priorS2 == priorIn
              -> if assocS2 == InfixL && 
                    assocIn == InfixL 
                 then reduce
             else 
                 if assocS2 == InfixR && 
                    assocIn == InfixR 
                 then shift
             else PFail (head toks) -- Because of ambiguousness 
           | not validIn && opS2
              -> reduce
             where
               (opS1, valueS1, nameS1) = s1
               (opS2, valueS2, nameS2) = s2
               (opS3, valueS3, nameS3) = s3
               (assocS2, priorS2) = utLookupDef env nameS2 (InfixL, 9)
               reduce = hsDoExpr ((False, ExprApp (ExprApp valueS2 valueS3) 
                                                  valueS1, [])
                                  : ss) env toks
        s1:s2:ss
           | validIn && (opS1 || opS2) -> shift
           | otherwise -> reduce
             where
                (opS1, valueS1, nameS1) = s1
                (opS2, valueS2, nameS2) = s2
                reduce = hsDoExpr ((False, ExprApp valueS2 valueS1, []) : ss) 
                                  env toks
        (s1:[])
           | validIn -> shift
           | otherwise -> POk env toks valueS1
             where
                (opS1, valueS1, nameS1) = s1
        []
           | validIn -> shift
           | otherwise -> PFail err

--==========================================================--
--=== end                                      Parser.hs ===--
--==========================================================--


hsPrecTable = [
  ("-",     (InfixL, 6)),
  ("+",     (InfixL, 6)),
  ("*",     (InfixL, 7)),
  ("div",   (InfixN, 7)),
  ("mod",   (InfixN, 7)),

  ("<",     (InfixN, 4)),
  ("<=",    (InfixN, 4)),
  ("==",    (InfixN, 4)),
  ("/=",    (InfixN, 4)),
  (">=",    (InfixN, 4)),
  (">",     (InfixN, 4)),

  ("C:",        (InfixR, 5)),
  ("++",        (InfixR, 5)),
  ("\\",        (InfixN, 5)),
  ("!!",        (InfixL, 9)),
  (".",         (InfixR, 9)),
  ("^",         (InfixR, 8)),
  ("elem",      (InfixN, 4)),
  ("notElem",   (InfixN, 4)),

  ("||",    (InfixR, 2)),
  ("&&",    (InfixR, 3))]

{- FIX THESE UP -}
--utLookupDef env k def
--   = head ( [ vv | (kk,vv) <- env, kk == k] ++ [def] )
panic = error
{- END FIXUPS -}

--paLiteral :: Parser Literal
paLiteral
   = pgAlts 
     [
        pgApply (LiteralInt.leStringToInt) (pgItem Lintlit),
        pgApply (LiteralChar.head)         (pgItem Lcharlit),
        pgApply LiteralString              (pgItem Lstringlit)
     ]

paExpr
   = pgAlts 
     [
        paCaseExpr, 
        paLetExpr, 
        paLamExpr,
        paIfExpr,
        paUnaryMinusExpr,
        hsDoExpr []
     ]

paUnaryMinusExpr
   = pgThen2
        (\minus (_, aexpr, _) -> 
             ExprApp (ExprApp (ExprVar "-") (ExprLiteral (LiteralInt 0))) aexpr)
        paMinus
        paAExpr

paCaseExpr
   = pgThen4
        (\casee expr off alts -> ExprCase expr alts)
        (pgItem Lcase)
        paExpr
        (pgItem Lof)
        (pgDeclList paAlt)

paAlt
   = pgAlts
     [
        pgThen4
           (\pat arrow expr wheres 
                -> MkExprCaseAlt pat (pa_MakeWhereExpr expr wheres))
           paPat
           (pgItem Larrow)
           paExpr
           (pgOptional paWhereClause),
        pgThen3
           (\pat agrdrhss wheres
                -> MkExprCaseAlt pat
                      (pa_MakeWhereExpr (ExprGuards agrdrhss) wheres))
           paPat
           (pgOneOrMore paGalt)
           (pgOptional paWhereClause)
     ]

paGalt
   = pgThen4
        (\bar guard arrow expr -> (guard, expr))
        (pgItem Lbar)
        paExpr
        (pgItem Larrow)
        paExpr

paLamExpr
   = pgThen4
        (\lam patterns arrow rhs -> ExprLam patterns rhs)
        (pgItem Lslash)
        (pgZeroOrMore paAPat)
        (pgItem Larrow)
        paExpr

paLetExpr
   = pgThen4
        (\lett decls inn rhs -> ExprLetrec decls rhs)
        (pgItem Llet)
        paValdefs
        (pgItem Lin)
        paExpr

paValdefs 
   = pgApply pa_MergeValdefs (pgDeclList paValdef)

pa_MergeValdefs 
   = id

paLhs
   = pgAlts
     [
        pgThen2 (\v ps -> LhsVar v ps) paVar (pgOneOrMore paPat),
        pgApply LhsPat paPat
     ]

paValdef
   = pgAlts
     [
        pgThen4
           (\(line, lhs) eq rhs wheres 
                -> MkValBind line lhs (pa_MakeWhereExpr rhs wheres))
           (pgGetLineNumber paLhs)
           (pgItem Lequals)
           paExpr
           (pgOptional paWhereClause),
        pgThen3
           (\(line, lhs) grdrhss wheres 
                -> MkValBind line lhs 
                      (pa_MakeWhereExpr (ExprGuards grdrhss) wheres))
           (pgGetLineNumber paLhs)
           (pgOneOrMore paGrhs)
           (pgOptional paWhereClause)
     ]

pa_MakeWhereExpr expr Nothing 
   = expr
pa_MakeWhereExpr expr (Just whereClauses) 
   = ExprWhere expr whereClauses

paWhereClause
   = pgThen2 (\x y -> y) (pgItem Lwhere) paValdefs
paGrhs
   = pgThen4
        (\bar guard equals expr -> (guard, expr))
        (pgItem Lbar)
        paExpr
        (pgItem Lequals)
        paExpr
        

paAPat
   = pgAlts
     [
        pgApply PatVar paVar,
        pgApply (\id -> PatCon id []) paCon,
        pgApply (const PatWild) (pgItem Lunder),
        pgApply PatTuple
                (pgThen3 (\l es r -> es)
                         (pgItem Llparen) 
                         (pgTwoOrMoreWithSep paPat (pgItem Lcomma))
                         (pgItem Lrparen)),
        pgApply PatList
                (pgThen3 (\l es r -> es)
                         (pgItem Llbrack) 
                         (pgZeroOrMoreWithSep paPat (pgItem Lcomma))
                         (pgItem Lrbrack)),
        pgThen3 (\l p r -> p)
                (pgItem Llparen)
                paPat
                (pgItem Lrparen)
     ]

paPat
   = pgAlts
     [
        pgThen2 (\c ps -> PatCon c ps)
                paCon
                (pgOneOrMore paAPat),
        pgThen3 (\ap c pa -> PatCon c [ap,pa])
                paAPat
                paConop
                paPat,
        paAPat
     ]


paIfExpr
 = pgThen4
      (\iff c thenn (t,f) -> ExprIf c t f)
      (pgItem Lif)
      paExpr
      (pgItem Lthen)
      (pgThen3
         (\t elsee f -> (t,f))
         paExpr
         (pgItem Lelse)
         paExpr
      )

paAExpr
 = pgApply (\x -> (False, x, []))
   (pgAlts 
    [
       pgApply ExprVar paVar,
       pgApply ExprCon paCon,
       pgApply ExprLiteral paLiteral,
       pgApply ExprList paListExpr,
       pgApply ExprTuple paTupleExpr,
       pgThen3 (\l e r -> e) (pgItem Llparen) paExpr (pgItem Lrparen)
    ]
   )

paListExpr
   = pgThen3 (\l es r -> es) 
             (pgItem Llbrack) 
             (pgZeroOrMoreWithSep paExpr (pgItem Lcomma))
             (pgItem Lrbrack)

paTupleExpr
   = pgThen3 (\l es r -> es) 
             (pgItem Llparen) 
             (pgTwoOrMoreWithSep paExpr (pgItem Lcomma))
             (pgItem Lrparen)

paVar = pgItem Lvar
paCon = pgItem Lcon
paVarop = pgItem Lvarop
paConop = pgItem Lconop
paMinus = pgItem Lminus

paOp
 = pgAlts [
            pgApply (\x -> (True, ExprVar x, x)) paVarop,
            pgApply (\x -> (True, ExprCon x, x)) paConop,
            pgApply (\x -> (True, ExprVar x, x)) paMinus
          ]

paDataDecl
   = pgThen2
        (\dataa useful -> useful)
        (pgItem Ldata)
        paDataDecl_main

paDataDecl_main
   = pgThen4
        (\name params eq drhs -> MkDataDecl name (params, drhs))
        paCon
        (pgZeroOrMore paVar)
        (pgItem Lequals)
        (pgOneOrMoreWithSep paConstrs (pgItem Lbar))

paConstrs
   = pgThen2
        (\con texprs -> (con, texprs))
        paCon
        (pgZeroOrMore paAType)

paType 
   = pgAlts
     [
        pgThen3 
           (\atype arrow typee -> TypeArr atype typee)
           paAType
           (pgItem Larrow)
           paType,
        pgThen2
           TypeCon
           paCon
           (pgOneOrMore paAType),
        paAType
     ]

paAType
   = pgAlts
     [
        pgApply TypeVar paVar,
        pgApply (\tycon -> TypeCon tycon []) paCon,
        pgThen3
           (\l t r -> t)
           (pgItem Llparen)
           paType
           (pgItem Lrparen),
        pgThen3
           (\l t r -> TypeList t)
           (pgItem Llbrack)
           paType
           (pgItem Lrbrack),
        pgThen3
           (\l t r -> TypeTuple t)
           (pgItem Llparen)
           (pgTwoOrMoreWithSep paType (pgItem Lcomma))
           (pgItem Lrparen)
     ]

paInfixDecl env toks
  = let dump (ExprVar v) = v
        dump (ExprCon c) = c
    in
    pa_UpdateFixityEnv 
       (pgThen3
          (\assoc prio name -> MkFixDecl name (assoc, prio))
          paInfixWord
          (pgApply leStringToInt (pgItem Lintlit)) 
          (pgApply (\(_, op, _) -> dump op) paOp)
          env 
          toks 
       )

paInfixWord
  = pgAlts
    [
       pgApply (const InfixL) (pgItem Linfixl),
       pgApply (const InfixR) (pgItem Linfixr),
       pgApply (const InfixN) (pgItem Linfix)
    ]

pa_UpdateFixityEnv (PFail tok) 
   = PFail tok

pa_UpdateFixityEnv (POk env toks (MkFixDecl name assoc_prio))
   = let 
         new_env = (name, assoc_prio) : env
     in
         POk new_env toks (MkFixDecl name assoc_prio)

paTopDecl
   = pgAlts
     [
        pgApply MkTopF paInfixDecl,
        pgApply MkTopD paDataDecl,
        pgApply MkTopV paValdef
     ]

paModule
   = pgThen4
        (\modyule name wheree topdecls -> MkModule name topdecls)
        (pgItem Lmodule)
        paCon
        (pgItem Lwhere)
        (pgDeclList paTopDecl)
   
parser_test toks
   = let parser_to_test
            = --paPat
              --paExpr
              --paValdef
              --pgZeroOrMore paInfixDecl
              --paDataDecl
              --paType
              paModule
              --pgTwoOrMoreWithSep (pgItem Lsemi) (pgItem Lcomma)
              
     in
         parser_to_test hsPrecTable toks

--==============================================--
--=== The Operator-Precedence parser (yuck!) ===--
--==============================================--

--
--==========================================================--
--
hsAExprOrOp 
 = pgAlts [paAExpr, paOp]

--hsDoExpr :: [PEntry] -> Parser Expr
-- [PaEntry] is a stack of operators and atomic expressions
-- hsDoExpr uses a parser (hsAexpOrOp :: Parsr PaEntry) for atomic
-- expressions or operators

hsDoExpr stack env toks = 
  let
     (validIn, restIn, parseIn, err)
        = case hsAExprOrOp env toks of
             POk env1 toks1 item1
                -> (True, toks1, item1, panic "hsDoExpr(1)")
             PFail err
                -> (False, panic "hsDoExpr(2)", panic "hsDoExpr(3)", err)
     (opIn, valueIn, nameIn)
        = parseIn
     (assocIn, priorIn)
        = utLookupDef env nameIn (InfixL, 9)
     shift
        = hsDoExpr (parseIn:stack) env restIn
  in 
     case stack of
        s1:s2:s3:ss
           | validIn && opS2 && opIn && priorS2 > priorIn
              -> reduce
           | validIn && opS2 && opIn && priorS2 == priorIn
              -> if assocS2 == InfixL && 
                    assocIn == InfixL 
                 then reduce
             else 
                 if assocS2 == InfixR && 
                    assocIn == InfixR 
                 then shift
             else PFail (head toks) -- Because of ambiguousness 
           | not validIn && opS2
              -> reduce
             where
               (opS1, valueS1, nameS1) = s1
               (opS2, valueS2, nameS2) = s2
               (opS3, valueS3, nameS3) = s3
               (assocS2, priorS2) = utLookupDef env nameS2 (InfixL, 9)
               reduce = hsDoExpr ((False, ExprApp (ExprApp valueS2 valueS3) 
                                                  valueS1, [])
                                  : ss) env toks
        s1:s2:ss
           | validIn && (opS1 || opS2) -> shift
           | otherwise -> reduce
             where
                (opS1, valueS1, nameS1) = s1
                (opS2, valueS2, nameS2) = s2
                reduce = hsDoExpr ((False, ExprApp valueS2 valueS1, []) : ss) 
                                  env toks
        (s1:[])
           | validIn -> shift
           | otherwise -> POk env toks valueS1
             where
                (opS1, valueS1, nameS1) = s1
        []
           | validIn -> shift
           | otherwise -> PFail err

--==========================================================--
--=== end                                      Parser.hs ===--
--==========================================================--


hsPrecTable = [
  ("-",     (InfixL, 6)),
  ("+",     (InfixL, 6)),
  ("*",     (InfixL, 7)),
  ("div",   (InfixN, 7)),
  ("mod",   (InfixN, 7)),

  ("<",     (InfixN, 4)),
  ("<=",    (InfixN, 4)),
  ("==",    (InfixN, 4)),
  ("/=",    (InfixN, 4)),
  (">=",    (InfixN, 4)),
  (">",     (InfixN, 4)),

  ("C:",        (InfixR, 5)),
  ("++",        (InfixR, 5)),
  ("\\",        (InfixN, 5)),
  ("!!",        (InfixL, 9)),
  (".",         (InfixR, 9)),
  ("^",         (InfixR, 8)),
  ("elem",      (InfixN, 4)),
  ("notElem",   (InfixN, 4)),

  ("||",    (InfixR, 2)),
  ("&&",    (InfixR, 3))]

{- FIX THESE UP -}
--utLookupDef env k def
--   = head ( [ vv | (kk,vv) <- env, kk == k] ++ [def] )
panic = error
{- END FIXUPS -}

--paLiteral :: Parser Literal
paLiteral
   = pgAlts 
     [
        pgApply (LiteralInt.leStringToInt) (pgItem Lintlit),
        pgApply (LiteralChar.head)         (pgItem Lcharlit),
        pgApply LiteralString              (pgItem Lstringlit)
     ]

paExpr
   = pgAlts 
     [
        paCaseExpr, 
        paLetExpr, 
        paLamExpr,
        paIfExpr,
        paUnaryMinusExpr,
        hsDoExpr []
     ]

paUnaryMinusExpr
   = pgThen2
        (\minus (_, aexpr, _) -> 
             ExprApp (ExprApp (ExprVar "-") (ExprLiteral (LiteralInt 0))) aexpr)
        paMinus
        paAExpr

paCaseExpr
   = pgThen4
        (\casee expr off alts -> ExprCase expr alts)
        (pgItem Lcase)
        paExpr
        (pgItem Lof)
        (pgDeclList paAlt)

paAlt
   = pgAlts
     [
        pgThen4
           (\pat arrow expr wheres 
                -> MkExprCaseAlt pat (pa_MakeWhereExpr expr wheres))
           paPat
           (pgItem Larrow)
           paExpr
           (pgOptional paWhereClause),
        pgThen3
           (\pat agrdrhss wheres
                -> MkExprCaseAlt pat
                      (pa_MakeWhereExpr (ExprGuards agrdrhss) wheres))
           paPat
           (pgOneOrMore paGalt)
           (pgOptional paWhereClause)
     ]

paGalt
   = pgThen4
        (\bar guard arrow expr -> (guard, expr))
        (pgItem Lbar)
        paExpr
        (pgItem Larrow)
        paExpr

paLamExpr
   = pgThen4
        (\lam patterns arrow rhs -> ExprLam patterns rhs)
        (pgItem Lslash)
        (pgZeroOrMore paAPat)
        (pgItem Larrow)
        paExpr

paLetExpr
   = pgThen4
        (\lett decls inn rhs -> ExprLetrec decls rhs)
        (pgItem Llet)
        paValdefs
        (pgItem Lin)
        paExpr

paValdefs 
   = pgApply pa_MergeValdefs (pgDeclList paValdef)

pa_MergeValdefs 
   = id

paLhs
   = pgAlts
     [
        pgThen2 (\v ps -> LhsVar v ps) paVar (pgOneOrMore paPat),
        pgApply LhsPat paPat
     ]

paValdef
   = pgAlts
     [
        pgThen4
           (\(line, lhs) eq rhs wheres 
                -> MkValBind line lhs (pa_MakeWhereExpr rhs wheres))
           (pgGetLineNumber paLhs)
           (pgItem Lequals)
           paExpr
           (pgOptional paWhereClause),
        pgThen3
           (\(line, lhs) grdrhss wheres 
                -> MkValBind line lhs 
                      (pa_MakeWhereExpr (ExprGuards grdrhss) wheres))
           (pgGetLineNumber paLhs)
           (pgOneOrMore paGrhs)
           (pgOptional paWhereClause)
     ]

pa_MakeWhereExpr expr Nothing 
   = expr
pa_MakeWhereExpr expr (Just whereClauses) 
   = ExprWhere expr whereClauses

paWhereClause
   = pgThen2 (\x y -> y) (pgItem Lwhere) paValdefs
paGrhs
   = pgThen4
        (\bar guard equals expr -> (guard, expr))
        (pgItem Lbar)
        paExpr
        (pgItem Lequals)
        paExpr
        

paAPat
   = pgAlts
     [
        pgApply PatVar paVar,
        pgApply (\id -> PatCon id []) paCon,
        pgApply (const PatWild) (pgItem Lunder),
        pgApply PatTuple
                (pgThen3 (\l es r -> es)
                         (pgItem Llparen) 
                         (pgTwoOrMoreWithSep paPat (pgItem Lcomma))
                         (pgItem Lrparen)),
        pgApply PatList
                (pgThen3 (\l es r -> es)
                         (pgItem Llbrack) 
                         (pgZeroOrMoreWithSep paPat (pgItem Lcomma))
                         (pgItem Lrbrack)),
        pgThen3 (\l p r -> p)
                (pgItem Llparen)
                paPat
                (pgItem Lrparen)
     ]

paPat
   = pgAlts
     [
        pgThen2 (\c ps -> PatCon c ps)
                paCon
                (pgOneOrMore paAPat),
        pgThen3 (\ap c pa -> PatCon c [ap,pa])
                paAPat
                paConop
                paPat,
        paAPat
     ]


paIfExpr
 = pgThen4
      (\iff c thenn (t,f) -> ExprIf c t f)
      (pgItem Lif)
      paExpr
      (pgItem Lthen)
      (pgThen3
         (\t elsee f -> (t,f))
         paExpr
         (pgItem Lelse)
         paExpr
      )

paAExpr
 = pgApply (\x -> (False, x, []))
   (pgAlts 
    [
       pgApply ExprVar paVar,
       pgApply ExprCon paCon,
       pgApply ExprLiteral paLiteral,
       pgApply ExprList paListExpr,
       pgApply ExprTuple paTupleExpr,
       pgThen3 (\l e r -> e) (pgItem Llparen) paExpr (pgItem Lrparen)
    ]
   )

paListExpr
   = pgThen3 (\l es r -> es) 
             (pgItem Llbrack) 
             (pgZeroOrMoreWithSep paExpr (pgItem Lcomma))
             (pgItem Lrbrack)

paTupleExpr
   = pgThen3 (\l es r -> es) 
             (pgItem Llparen) 
             (pgTwoOrMoreWithSep paExpr (pgItem Lcomma))
             (pgItem Lrparen)

paVar = pgItem Lvar
paCon = pgItem Lcon
paVarop = pgItem Lvarop
paConop = pgItem Lconop
paMinus = pgItem Lminus

paOp
 = pgAlts [
            pgApply (\x -> (True, ExprVar x, x)) paVarop,
            pgApply (\x -> (True, ExprCon x, x)) paConop,
            pgApply (\x -> (True, ExprVar x, x)) paMinus
          ]

paDataDecl
   = pgThen2
        (\dataa useful -> useful)
        (pgItem Ldata)
        paDataDecl_main

paDataDecl_main
   = pgThen4
        (\name params eq drhs -> MkDataDecl name (params, drhs))
        paCon
        (pgZeroOrMore paVar)
        (pgItem Lequals)
        (pgOneOrMoreWithSep paConstrs (pgItem Lbar))

paConstrs
   = pgThen2
        (\con texprs -> (con, texprs))
        paCon
        (pgZeroOrMore paAType)

paType 
   = pgAlts
     [
        pgThen3 
           (\atype arrow typee -> TypeArr atype typee)
           paAType
           (pgItem Larrow)
           paType,
        pgThen2
           TypeCon
           paCon
           (pgOneOrMore paAType),
        paAType
     ]

paAType
   = pgAlts
     [
        pgApply TypeVar paVar,
        pgApply (\tycon -> TypeCon tycon []) paCon,
        pgThen3
           (\l t r -> t)
           (pgItem Llparen)
           paType
           (pgItem Lrparen),
        pgThen3
           (\l t r -> TypeList t)
           (pgItem Llbrack)
           paType
           (pgItem Lrbrack),
        pgThen3
           (\l t r -> TypeTuple t)
           (pgItem Llparen)
           (pgTwoOrMoreWithSep paType (pgItem Lcomma))
           (pgItem Lrparen)
     ]

paInfixDecl env toks
  = let dump (ExprVar v) = v
        dump (ExprCon c) = c
    in
    pa_UpdateFixityEnv 
       (pgThen3
          (\assoc prio name -> MkFixDecl name (assoc, prio))
          paInfixWord
          (pgApply leStringToInt (pgItem Lintlit)) 
          (pgApply (\(_, op, _) -> dump op) paOp)
          env 
          toks 
       )

paInfixWord
  = pgAlts
    [
       pgApply (const InfixL) (pgItem Linfixl),
       pgApply (const InfixR) (pgItem Linfixr),
       pgApply (const InfixN) (pgItem Linfix)
    ]

pa_UpdateFixityEnv (PFail tok) 
   = PFail tok

pa_UpdateFixityEnv (POk env toks (MkFixDecl name assoc_prio))
   = let 
         new_env = (name, assoc_prio) : env
     in
         POk new_env toks (MkFixDecl name assoc_prio)

paTopDecl
   = pgAlts
     [
        pgApply MkTopF paInfixDecl,
        pgApply MkTopD paDataDecl,
        pgApply MkTopV paValdef
     ]

paModule
   = pgThen4
        (\modyule name wheree topdecls -> MkModule name topdecls)
        (pgItem Lmodule)
        paCon
        (pgItem Lwhere)
        (pgDeclList paTopDecl)
   
parser_test toks
   = let parser_to_test
            = --paPat
              --paExpr
              --paValdef
              --pgZeroOrMore paInfixDecl
              --paDataDecl
              --paType
              paModule
              --pgTwoOrMoreWithSep (pgItem Lsemi) (pgItem Lcomma)
              
     in
         parser_to_test hsPrecTable toks

--==============================================--
--=== The Operator-Precedence parser (yuck!) ===--
--==============================================--

--
--==========================================================--
--
hsAExprOrOp 
 = pgAlts [paAExpr, paOp]

--hsDoExpr :: [PEntry] -> Parser Expr
-- [PaEntry] is a stack of operators and atomic expressions
-- hsDoExpr uses a parser (hsAexpOrOp :: Parsr PaEntry) for atomic
-- expressions or operators

hsDoExpr stack env toks = 
  let
     (validIn, restIn, parseIn, err)
        = case hsAExprOrOp env toks of
             POk env1 toks1 item1
                -> (True, toks1, item1, panic "hsDoExpr(1)")
             PFail err
                -> (False, panic "hsDoExpr(2)", panic "hsDoExpr(3)", err)
     (opIn, valueIn, nameIn)
        = parseIn
     (assocIn, priorIn)
        = utLookupDef env nameIn (InfixL, 9)
     shift
        = hsDoExpr (parseIn:stack) env restIn
  in 
     case stack of
        s1:s2:s3:ss
           | validIn && opS2 && opIn && priorS2 > priorIn
              -> reduce
           | validIn && opS2 && opIn && priorS2 == priorIn
              -> if assocS2 == InfixL && 
                    assocIn == InfixL 
                 then reduce
             else 
                 if assocS2 == InfixR && 
                    assocIn == InfixR 
                 then shift
             else PFail (head toks) -- Because of ambiguousness 
           | not validIn && opS2
              -> reduce
             where
               (opS1, valueS1, nameS1) = s1
               (opS2, valueS2, nameS2) = s2
               (opS3, valueS3, nameS3) = s3
               (assocS2, priorS2) = utLookupDef env nameS2 (InfixL, 9)
               reduce = hsDoExpr ((False, ExprApp (ExprApp valueS2 valueS3) 
                                                  valueS1, [])
                                  : ss) env toks
        s1:s2:ss
           | validIn && (opS1 || opS2) -> shift
           | otherwise -> reduce
             where
                (opS1, valueS1, nameS1) = s1
                (opS2, valueS2, nameS2) = s2
                reduce = hsDoExpr ((False, ExprApp valueS2 valueS1, []) : ss) 
                                  env toks
        (s1:[])
           | validIn -> shift
           | otherwise -> POk env toks valueS1
             where
                (opS1, valueS1, nameS1) = s1
        []
           | validIn -> shift
           | otherwise -> PFail err

--==========================================================--
--=== end                                      Parser.hs ===--
--==========================================================--


hsPrecTable = [
  ("-",     (InfixL, 6)),
  ("+",     (InfixL, 6)),
  ("*",     (InfixL, 7)),
  ("div",   (InfixN, 7)),
  ("mod",   (InfixN, 7)),

  ("<",     (InfixN, 4)),
  ("<=",    (InfixN, 4)),
  ("==",    (InfixN, 4)),
  ("/=",    (InfixN, 4)),
  (">=",    (InfixN, 4)),
  (">",     (InfixN, 4)),

  ("C:",        (InfixR, 5)),
  ("++",        (InfixR, 5)),
  ("\\",        (InfixN, 5)),
  ("!!",        (InfixL, 9)),
  (".",         (InfixR, 9)),
  ("^",         (InfixR, 8)),
  ("elem",      (InfixN, 4)),
  ("notElem",   (InfixN, 4)),

  ("||",    (InfixR, 2)),
  ("&&",    (InfixR, 3))]

#