{
module Parser where

import ParseTree
import Lexer 
import Control.Monad.Error

}

%name parseProg Prog
%name parseExp  Exp

%monad { Either String } { (>>=) } { return }

%tokentype { Lexer.PToken } 

%token '='     { (_,TkEq) }
       '('     { (_,TkLPar) }
       ')'     { (_,TkRPar) }
       ','     { (_,TkComma) }
       '@'     { (_,TkAt) }
       integer { (_,TkInt _) }
       ident   { (_,TkIdent _) }
       cident  { (_,TkCIdent _) }

%%


Prog :: { [Declaration AlexPosn] }
: Decl Prog { $1:$2 }
|           { [] }

Decl :: { Declaration AlexPosn }
: LHS '=' RHS              { Decl ($1,$3,[]) (-1) }
| LHS '=' RHS '@' integer  { Decl ($1,$3,[]) (intValue (body $5)) }

LHS  :: { SymbolTree AlexPosn }
: ident '(' Patterns ')' { SNode (Function (strValue $ body $1) (pos $1)) $3 }

Patterns :: { [SymbolTree AlexPosn] }
: Pattern               { [$1] }
| Pattern ',' Patterns  { $1:$3 }

Pattern :: { SymbolTree AlexPosn }
: cident '(' Patterns ')' { SNode (Constructor (strValue $ body $1) (pos $1)) $3 }
| cident                  { SNode (Constructor (strValue $ body $1) (pos $1)) [] }
| ident                   { SNode (Variable (strValue $ body $1) (pos $1)) [] }


RHS  :: { SymbolTree AlexPosn }
: cident '(' RHSs ')' { SNode (Constructor (strValue $ body $1) (pos $1)) $3 }
| cident              { SNode (Constructor (strValue $ body $1) (pos $1)) [] }
| ident               { SNode (Variable (strValue $ body $1) (pos $1)) [] }
| ident '(' ARGs ')'  { SNode (Function (strValue $ body $1) (pos $1)) $3 }

RHSs :: { [SymbolTree AlexPosn] }
: RHS ',' RHSs { $1:$3 }
| RHS          { [$1] }


ARG  :: { SymbolTree AlexPosn }
: ident        { SNode (Variable (strValue $ body $1) (pos $1)) [] }

ARGs :: { [SymbolTree AlexPosn] }
: ARG ',' ARGs { $1:$3 }
| ARG          { [$1] }
|              { [] }



Exp :: { SymbolTree AlexPosn }
: cident '(' Exps ')' { SNode (Constructor (strValue $ body $1) (pos $1)) $3 }
| cident              { SNode (Constructor (strValue $ body $1) (pos $1)) [] }
| ident '(' Exps ')'  { SNode (Function (strValue $ body $1) (pos $1)) $3 }

Exps :: { [SymbolTree AlexPosn] }
: Exp ',' Exps { $1:$3 }
| Exp          { [$1] }
|              { [] }


{
happyError tokens =
    if length tokens > 0 then 
        throwError $ "ParseError at " ++ (p tokens)
    else
        throwError $ "ParseError at " ++ "Unknown Position"
    where p (( (AlexPn a n c),  t ):_) = "Line: " ++ show n ++ ", Column: "++show c

}
