packages feed

idris-0.1.3: Idris/Parser.y

{ -- -*-Haskell-*-
{-# OPTIONS_GHC -fglasgow-exts #-}

module Idris.Parser where

import Data.Char
import Ivor.TT
import System.IO.Unsafe
import List
import Control.Monad

import Idris.AbsSyntax
import Idris.Lexer
import Idris.Lib

import Debug.Trace

}

%name mkparse Program
%name mkparseTerm Term
%name mkparseTactic Tactic

%tokentype { Token }
%monad { P } { thenP } { returnP }
%lexer { lexer } { TokenEOF }

-- %expect 0

%token
      name            { TokenName $$ }
      userinfix       { TokenInfixName $$ }
      brackname       { TokenBrackName $$ }
      string          { TokenString $$ }
      int             { TokenInt $$ }
      float           { TokenFloat $$ }
      char            { TokenChar $$ }
      bool            { TokenBool $$ }
      metavar         { TokenMetavar $$ }
      ':'             { TokenColon }
      ';'             { TokenSemi }
      '|'             { TokenBar }
      stars           { TokenStars }
      '\\'            { TokenLambda }
      hashbrack       { TokenHashOB }
      '('             { TokenOB }
      ')'             { TokenCB }
      '{'             { TokenOCB }
      '}'             { TokenCCB }
      '['             { TokenOSB }
      ']'             { TokenCSB }
      oid             { TokenOId }
      cid             { TokenCId }
      lpair           { TokenLPair }
      rpair           { TokenRPair }
      exists          { TokenExists }
      '~'             { TokenTilde }
      '+'             { TokenPlus }
      '-'             { TokenMinus }
      '*'             { TokenTimes }
      '/'             { TokenDivide }
      '='             { TokenEquals }
      mightbe         { TokenMightEqual }
      '<'             { TokenLT }
      '>'             { TokenGT }
      ellipsis        { TokenEllipsis }
      '_'             { TokenUnderscore }
      ','             { TokenComma }
      '&'             { TokenTuple }
      '!'             { TokenBang }
      concat          { TokenConcat }
--      eq              { TokenEQ }
      ge              { TokenGE }
      le              { TokenLE }
      or              { TokenOr }
      and             { TokenAnd }
      arrow           { TokenArrow }
      fatarrow        { TokenFatArrow }
      transarrow      { TokenTransArrow }
      leftarrow       { TokenLeftArrow }
      inttype         { TokenIntType }
      chartype        { TokenCharType }
      floattype       { TokenFloatType }
      stringtype      { TokenStringType }
      handletype      { TokenHandleType }
      ptrtype         { TokenPtrType }
      locktype        { TokenLockType }
      type            { TokenType }
      lazybracket     { TokenLazyBracket }
      data            { TokenDataType }
      infix           { TokenInfix }
      infixl          { TokenInfixL }
      infixr          { TokenInfixR }
      using           { TokenUsing }
      idiom           { TokenIdiom }
      params          { TokenParams }
      noelim          { TokenNoElim }
      collapsible     { TokenCollapsible }
      where           { TokenWhere }
      with            { TokenWith }
      partial         { TokenPartial }
      syntax          { TokenSyntax }
      lazy            { TokenLazy }
      refl            { TokenRefl }
      empty           { TokenEmptyType }
      unit            { TokenUnitType }
      include         { TokenInclude }
      export          { TokenExport }
      inline          { TokenInline }
      do              { TokenDo }
      return          { TokenReturn }
      if              { TokenIf }
      then            { TokenThen }
      else            { TokenElse }
      let             { TokenLet }
      in              { TokenIn }
      proof           { TokenProof }
      intro           { TokenIntro }
      refine          { TokenRefine }
      generalise      { TokenGeneralise }
      reflp           { TokenReflP }
      rewrite         { TokenRewrite }
      rewriteall      { TokenRewriteAll }
      compute         { TokenCompute }
      unfold          { TokenUnfold }
      undo            { TokenUndo }
      induction       { TokenInduction }
      fill            { TokenFill }
      trivial         { TokenTrivial }
      mktac           { TokenMkTac }
      believe         { TokenBelieve }
      use             { TokenUse }
      decide          { TokenDecide }
      abandon         { TokenAbandon }
      qed             { TokenQED }
      latex           { TokenLaTeX }
      nocg            { TokenNoCG }
      eval            { TokenEval }
      spec            { TokenSpec }
      freeze          { TokenFreeze }
      thaw            { TokenThaw }
      transform       { TokenTransform }
      cinclude        { TokenCInclude }
      clib            { TokenCLib }

%nonassoc LAM
%nonassoc let in
%nonassoc '!' '@'
%left or
%left and '&'
%left '=' -- eq
%left userinfix
%left '<' le '>' ge
%left '+' '-'
%left '*' '/'
%left NEG
%left concat
%left '\\'
%right arrow
%left '(' '{' lazybracket
%nonassoc '.'
%right IMP
%nonassoc CONST
-- All the things I don't want to cause a reduction inside a lam...
%nonassoc name inttype chartype floattype stringtype int char string float bool refl do type
          empty unit '_' if then else ptrtype handletype locktype metavar NONE brackname lazy
          oid '[' '~' lpair PAIR return transarrow exists
%left APP


%%

Program :: { [ParseDecl] }
Program: { [] }
       | Declaration Program { $1:$2 }
       | Fixity Program { map RealDecl $1 ++ $2 }
       | include string ';' Program { RealDecl (PInclude $2) : $4 }

{-
{%
	     let rest = $4 in
	     let pt = unsafePerformIO (readLib defaultLibPath $2) in
		case (mkparse pt $2 1 []) of
		   Success x -> returnP (x ++ rest)
		   Failure err file ln -> failP err
	  }
-}

Declaration :: { ParseDecl }
Declaration: Function { $1 }
           | Datatype { RealDecl (DataDecl $1) }
           | Latex { RealDecl $1 }
           | freeze name ';' { RealDecl (Freeze $2) }
           | Using '{' Program '}' { PUsing $1 $3 }
           | DoUsing '{' Program '}' { PDoUsing $1 $3 } 
           | Idiom '{' Program '}' { PIdiom $1 $3 }
           | Params '{' Program '}' { PParams $1 $3 }
           | Transform { RealDecl $1 }
           | syntax Name NamesS '=' Term ';' { PSyntax $2 $3 $5 }
           | cinclude string { RealDecl (CInclude $2) }
           | clib string { RealDecl (CLib $2) }

Transform :: { Decl }
Transform : transform Term fatarrow Term ';' { Transform $2 $4 }

Function :: { ParseDecl }
Function : Name ':' Type Flags File Line ';' { FunType $1 $3 (nub $4) $5 $6 }
         | Name ProofScript ';' { ProofScript $1 $2 }
--         | DefTerm '=' Term Flags ';' { FunClause (mkDef $1) [] $3 $4 }
         | DefTerm WithTerms WithP Term '{' Functions '}' File Line
              { WithClause (mkDef $8 $9 $1) $2 $3 $4 $6 }
         | DefTerm WithTerms mightbe Term ';' '[' Name ']' File Line
              { FunClauseP (mkDef $9 $10 $1) $2 $4 $7 }
         | DefTerm WithTerms '=' Term Flags ';' File Line 
              { FunClause (mkDef $7 $8 $1) $2 $4 (nub $5) }
         | '|' WithTerm '=' Term ';' { FunClause RPlaceholder [$2] $4 [] }
         | '|' WithTerm mightbe Term ';' '[' Name ']' 
              { FunClauseP RPlaceholder [$2] $4 $7 }
         | '|' WithTerm WithP Term '{' Functions '}'
              { WithClause RPlaceholder [$2] $3 $4 $6 }

WithP :: { Bool }
WithP : with { False }
      | with proof { True }

WithTerms :: { [RawTerm] }
WithTerms : '|' WithTerm WithTerms { $2:$3 }
          | { [] }

WithTerm :: { RawTerm }
WithTerm : SimpleAppTerm { $1 }
         | SigmaTerm { $1 }
         | '(' Term ')' { $2 }
         | '(' TermList ')' File Line { pairDesugar $4 $5 (RVar $4 $5 (UN "mkPair")) $2 }

Functions :: { [ParseDecl] }
Functions : Function Functions { $1:$2 }
          | Function { [$1] }

Flags :: { [CGFlag] }
Flags : { [] }
      | Flag Flags { $1 ++ $2 }

Flag :: { [CGFlag] }
Flag : nocg { [NoCG] }
     | eval { [CGEval, Inline] }
     | spec '(' NameInts ')' { [CGSpec $3] }
     | spec { [CGSpec []] }
     | inline { [Inline] }
     | export string { [CExport $2] }

--         | Nameproof Script { ProofScript $2 }

--         | proof '{' Tactics '}' { error "Foo" }

-- Tactics :: { [(ITactic] }
-- Tactics : 

--         | Name '=' Term ';' { RealDecl (TermDef $1 $3) }

Fixity :: { [Decl] }
Fixity : FixDec int UserInfixes ';' { map (\x -> Fixity x $1 $2) $3 }

UserInfixes :: { [String] }
UserInfixes : UserInfix { [$1] }
            | UserInfix ',' UserInfixes { $1:$3 }

-- some annoying special cases so we can have operators with other meanings.

UserInfix :: { String }
UserInfix : userinfix { $1 }
          | '-' { "-" }
          | '<' { "<" }
          | '>' { ">" }

FixDec :: { Fixity }
FixDec : infixl { LeftAssoc }
       | infixr { RightAssoc }
       | infix { NonAssoc }

Latex :: { Decl }
Latex : latex '{' LatexDefs '}' { LatexDefs $3 }

LatexDefs :: { [(Id,String)] }
LatexDefs : Name '=' string { [($1,$3)] }
          | Name '=' string ',' LatexDefs { ($1,$3):$5 }

DefTerm :: { (Id, [(RawTerm, Maybe Id)]) }
DefTerm : Name ArgTerms { ($1, $2) }

ArgTerms :: { [(RawTerm,Maybe Id)] }
ArgTerms : { [] }
      | NoAppTerm ArgTerms { ($1,Nothing):$2 }
      | brackname '}' ArgTerms File Line { (RVar $4 $5 $1, Just $1):$3 }
      | brackname '=' Term '}' ArgTerms { ($3, Just $1):$5 }

Datatype :: { Datatype }
Datatype : data DataOpts Name DefinedData File Line
             { mkDatatype $5 $6 $3 $4 $2 }

DefinedData :: { Either RawTerm ((RawTerm, [(Id, RawTerm)]), [ConParse]) }
DefinedData : DType Constructors ';' { Right ($1,$2) }
            | ':' Type ';' { Left $2 }
            | ';' File Line { Left (RConst $2 $3 TYPE) }

-- Currently just whether to generate an elim rule, this'll need to be
-- a list of options if we ever expand this.

DataOpts :: { [TyOpt] }
DataOpts : { [] }
         | '[' DataOptList ']' { $2 }

DataOptList :: { [TyOpt] }
DataOptList : DataOpt { [$1] }
            | DataOpt ',' DataOptList { $1:$3 }

DataOpt :: { TyOpt }
DataOpt : noelim { NoElim }
        | collapsible { Collapsible }

Name :: { Id }
Name : name { $1 }
     | '(' UserInfix ')' { useropFn $2 }

SimpleAppTerm :: { RawTerm }
SimpleAppTerm : SimpleAppTerm File Line NoAppTerm  %prec APP { RApp $2 $3 $1 $4 }
              | SimpleAppTerm ImplicitTerm '}' File Line %prec APP 
                   { RAppImp $4 $5 (fst $2) $1 (snd $2) }
              | Name File Line { RVar $2 $3 $1 }
              | Constant File Line { RConst $2 $3 $1 }
              | '_' { RPlaceholder }
              | empty File Line { RVar $2 $3 (UN "__Empty") }
              | unit File Line { RVar $2 $3 (UN "__Unit") }

Term :: { RawTerm }
Term : NoAppTerm { $1 }
     | hashbrack TypeTerm ')' { $2 }
     | Term File Line NoAppTerm  %prec APP { RApp $2 $3 $1 $4 }
     | Term ImplicitTerm '}' File Line %prec APP 
                   { RAppImp $4 $5 (fst $2) $1 (snd $2) }
     | lazy Term File Line { RApp $3 $4 (RApp $3 $4 (RVar $3 $4 (UN "__lazy")) RPlaceholder) $2 }
     | '\\' Binds fatarrow Term %prec LAM
                { doBind Lam $2 $4 }
     | let LetBinds in Term
                { doLetBind $2 $4 }
     | InfixTerm { $1 }
     | if Term then Term else Term File Line
       { mkApp $7 $8 (RVar $7 $8 (UN "if_then_else")) [$2,$4,$6] }

Binds :: { [(Id, RawTerm)] }
Binds : Name MaybeType { [($1,$2)] }
      | Name MaybeType ',' Binds { ($1,$2):$4 }

TypedBinds :: { [(Id, RawTerm)] }
TypedBinds : TypedBind ',' TypedBinds { $1 ++ $3 }
           | TypedBind { $1 }

TypedBind :: { [(Id, RawTerm)] }
TypedBind : Name ':' Type { map ( \x -> (x,$3)) [$1] }

Names :: { [Id] }
Names : Name { [$1] }
      | Name ',' Names { $1:$3 }

NameInts :: { [(Id, Int)] }
NameInts : Name int { [($1,$2)] }
         | Name { [($1, 0)] }
         | Name ',' NameInts { ($1,0):$3 }
         | Name int ',' NameInts { ($1,$2):$4 }

BrackNames :: { [Id] }
BrackNames : brackname { [$1] }
      | brackname ',' Names { $1:$3 }

NamesS :: { [Id] }
NamesS : Name { [$1] }
       | Name NamesS { $1:$2 }

LetBinds :: { [(Id, RawTerm, RawTerm)] }
LetBinds : Name MaybeType '=' Term { [($1,$2,$4)] }
         | Name MaybeType '=' Term ',' LetBinds { ($1,$2,$4):$6 }

ImplicitTerm :: { (Id, RawTerm) }
ImplicitTerm : brackname File Line { ($1, RVar $2 $3 $1) }
             | brackname '=' Term { ($1, $3) }

InfixTerm :: { RawTerm }
InfixTerm : '-' Term File Line %prec NEG { RInfix $3 $4 Minus (RConst $3 $4 (Num 0)) $2 }
--          | Term '+' Term File Line { RInfix $4 $5  Plus $1 $3 }
          | Term '-' Term File Line { RUserInfix $4 $5 False "-" $1 $3 }
--          | Term '*' Term File Line { RInfix $4 $5  Times $1 $3 }
--          | Term '/' Term File Line { RInfix $4 $5  Divide $1 $3 }
--          | Term and Term File Line { RInfix $4 $5  OpAnd $1 $3 }
          | Term '&' Term File Line { mkApp $4 $5 (RVar $4 $5 (UN "Pair")) [$1, $3] }
--          | Term or Term File Line { RInfix $4 $5  OpOr $1 $3 }
--          | Term concat Term File Line { RInfix $4 $5  Concat $1 $3 }
--          | Term eq Term File Line { RInfix $4 $5  OpEq $1 $3 }
          | Term '<' Term File Line { RUserInfix $4 $5 False "<" $1 $3 }
--          | Term le Term File Line { RInfix $4 $5  OpLEq $1 $3 }
          | Term '>' Term File Line { RUserInfix $4 $5 False ">" $1 $3 }
--          | Term ge Term File Line { RInfix $4 $5  OpGEq $1 $3 }
          | Term arrow Term File Line { RBind (MN "X" 0) (Pi Ex Eager $1) $3 }
          | UserInfixTerm { $1 }
          | NoAppTerm '=' NoAppTerm File Line { RInfix $4 $5 JMEq $1 $3 }

UserInfixTerm :: { RawTerm }
UserInfixTerm : Term userinfix Term File Line { RUserInfix $4 $5 False $2 $1 $3 }

Section :: { RawTerm }
Section : '(' userinfix Term File Line ')'
               { RBind (MN "X" 0) (Lam RPlaceholder) 
                       (RUserInfix $4 $5 False $2 (RVar $4 $5 (MN "X" 0)) $3) }
        | '(' Term userinfix File Line ')'
               { RBind (MN "X" 0) (Lam RPlaceholder) 
                       (RUserInfix $4 $5 False $3 $2 (RVar $4 $5 (MN "X" 0))) }
        | '(' BuiltinOp Term File Line ')'
               { RBind (MN "X" 0) (Lam RPlaceholder) 
                       (RUserInfix $4 $5 False $2 (RVar $4 $5 (MN "X" 0)) $3) }
        | '(' Term BuiltinOp File Line ')'
               { RBind (MN "X" 0) (Lam RPlaceholder) 
                       (RUserInfix $4 $5 False $3 $2 (RVar $4 $5 (MN "X" 0))) }
        | '(' Term '-' File Line ')'
               { RBind (MN "X" 0) (Lam RPlaceholder) 
                       (RUserInfix $4 $5 False "-" $2 (RVar $4 $5 (MN "X" 0))) }

-- Special cases for ->

        | '(' Term arrow File Line ')'
               { RBind (MN "X" 0) (Lam RPlaceholder) 
                       (RBind (MN "X" 1) (Pi Ex Eager $2) (RVar $4 $5 (MN "X" 0))) }
        | '(' arrow Term File Line ')'
               { RBind (MN "X" 0) (Lam RPlaceholder) 
                       (RBind (MN "X" 1) (Pi Ex Eager (RVar $4 $5 (MN "X" 0))) $3) }       
        | '(' arrow File Line ')'
               { RBind (MN "X" 0) (Lam RPlaceholder)
                       (RBind (MN "X" 1) (Lam RPlaceholder)
                    (RBind (MN "X" 2) (Pi Ex Eager (RVar $3 $4 (MN "X" 0)))
                       (RVar $3 $4 (MN "X" 1)))) }

 -- Special cases for pairing

        | '(' ',' File Line ')' 
              {  RBind (MN "X" 0) (Lam RPlaceholder)
                   (RBind (MN "X" 1) (Lam RPlaceholder)
                       (pairDesugar $3 $4 (RVar $3 $4 (UN "mkPair"))
                                    [RVar $3 $4 (MN "X" 0),
                                     RVar $3 $4 (MN "X" 1)])) }
        | '(' Term ',' File Line ')' 
              {  RBind (MN "X" 0) (Lam RPlaceholder)
                       (pairDesugar $4 $5 (RVar $4 $5 (UN "mkPair"))
                                    [$2,
                                     RVar $4 $5 (MN "X" 0)]) }
        | '(' ',' Term File Line ')' 
              {  RBind (MN "X" 0) (Lam RPlaceholder)
                       (pairDesugar $4 $5 (RVar $4 $5 (UN "mkPair"))
                                    [RVar $4 $5 (MN "X" 0), $3]) }


BuiltinOp :: { String }
BuiltinOp : '<' { "<" }
          | '>' { ">" }

MaybeType :: { RawTerm }
MaybeType : { RPlaceholder}
          | ':' TypeTerm { $2 }

MaybeAType :: { RawTerm }
MaybeAType : { RPlaceholder}
          | ':' TypeTerm { $2 }

-- Term representing a type may begin with implicit argument list

Type :: { RawTerm }
Type : BrackNames MaybeAType '}' arrow Type
               { doBind (Pi Im Eager) (map (\x -> (x, $2)) $1) $5 }
     | TypeTerm { $1 }

TypeTerm :: { RawTerm }
TypeTerm : TypeTerm arrow TypeTerm { RBind (MN "X" 0) (Pi Ex Eager $1) $3 }
         | '(' TypedBinds ')' arrow TypeTerm
                { doBind (Pi Ex Eager) $2 $5 }
         | lazybracket TypedBinds ')' arrow TypeTerm
                { doBind (Pi Ex Lazy) $2 $5 }
         | '(' TypeTerm ')' { bracket $2 }
         | '(' TypeTerm '=' TypeTerm File Line ')' { RInfix $5 $6 JMEq $2 $4 }
         | SimpleAppTerm { $1 }
         | hashbrack Term ')' { $2 }
         | TypeTerm userinfix TypeTerm File Line { RUserInfix $4 $5 False $2 $1 $3 }
         | '(' TypeList ')' File Line { pairDesugar $4 $5 (RVar $4 $5 (UN "Pair")) $2 }
         | SigmaType { $1 }

SigmaType :: { RawTerm }
SigmaType : '(' Name MaybeType stars TypeTerm ')' File Line 
                  { sigDesugar $7 $8 ($2, $3) $5 }
--          | exists Name MaybeType fatarrow SimpleAppTerm File Line
--                  { sigDesugar $6 $7 ($2, $3) $5 }

TypeList :: { [RawTerm] }
         : TypeTerm '&' TypeTerm { $1:$3:[] }
         | TypeTerm '&' TypeList { $1:$3 }

NoAppTerm :: { RawTerm }
NoAppTerm : Name File Line { RVar $2 $3 $1 }
          | return File Line { RReturn $2 $3 }
          | '(' Term ')' { bracket $2 }
          | '~' NoAppTerm { RPure $2 }
          | metavar { RMetavar $1 }
          | '!' Name File Line { RExpVar $3 $4 $2 }
--          | '{' TypedBind '}' arrow NoAppTerm
--                { doBind (Pi Im) $2 $5 }
          | Constant File Line { RConst $2 $3 $1 }
          | refl { RRefl }
          | empty File Line { RVar $2 $3 (UN "__Empty") }
          | unit File Line { RVar $2 $3 (UN "__Unit") }
          | '_' { RPlaceholder }
          | DoBlock { RDo $1 }
          | oid Term cid { RIdiom $2 }
          | '(' TermList ')' File Line { pairDesugar $4 $5 (RVar $4 $5 (UN "mkPair")) $2 }
--          | '[' TermList ']' File Line { pairDesugar $4 $5 (RVar $4 $5 (UN "Exists")) $2 }
--          | '(' TypeList ')' File Line { pairDesugar $4 $5 (RVar $4 $5 (UN "Pair")) $2 }
          | SigmaType { $1 } 
          | Section { $1 }
          | SigmaTerm { $1 }

SigmaTerm :: { RawTerm }
SigmaTerm : lpair Term ',' Term rpair File Line %prec PAIR
                { RApp $6 $7 (RAppImp $6 $7 (UN "a") (RVar $6 $7 (UN "Exists")) $2) $4 }
          | lpair Term rpair File Line %prec PAIR
                { RApp $4 $5 (RVar $4 $5 (UN "Exists")) $2 }

TermList :: { [RawTerm] }
         : Term ',' Term { $1:$3:[] }
         | Term ',' TermList { $1:$3 }


DoBlock :: { [Do] }
DoBlock : do '{' DoBindings '}' { $3 }
-- Next rule is a TMP HACK! So that we can open brackets then have a name immediately.
        | do brackname MaybeType leftarrow Term File Line ';' DoBindings '}'
             { DoBinding $6 $7 $2 $3 $5 : $9 }

DoBindings :: { [Do] }
DoBindings : DoBind DoBindings { $1:$2}
           | DoBind { [$1] }

DoBind :: { Do }
DoBind : Name MaybeType leftarrow Term File Line ';' { DoBinding $5 $6 $1 $2 $4 }
       | let Name MaybeType '=' Term File Line ';' { DoLet $6 $7 $2 $3 $5 }
       | Term File Line ';' { DoExp $2 $3 $1 }

Constant :: { Constant }
Constant : type { TYPE }
         | stringtype { StringType }
         | inttype { IntType }
         | chartype { CharType }
         | floattype { FloatType }
         | ptrtype { PtrType }
         | handletype { Builtin "Handle" }
         | locktype { Builtin "Lock" }
         | int { Num $1 }
         | char { Ch $1 }
         | string { Str $1 }
         | bool { Bo $1 }
         | float { Fl $1 }

-- Whitespace separated term sequences; must be NoAppTerms since obviously
-- application is space separated...

Terms :: { [RawTerm] }
Terms : { [] }
      | NoAppTerm Terms { $1:$2 }

DType :: { (RawTerm, [(Id, RawTerm)]) }
DType : ':' Type Using where { ($2, $3) }
      | '=' File Line { (RConst $2 $3 TYPE, []) }
      | VarList '=' File Line { (mkTyParams $3 $4 $1, []) }

Using :: { [(Id, RawTerm)] }
      : { [] }
      | using '(' UseList ')' { $3 }

DoUsing ::{ (Id,Id) }
        : do using '(' Name ',' Name ')' { ($4,$6) }

Idiom ::{ (Id,Id) }
        : idiom '(' Name ',' Name ')' { ($3,$5) }

        
Params :: { [(Id, RawTerm)] }
       : params '(' UseList ')' { $3 }

UseList :: { [(Id, RawTerm)] }
        : Name ':' Type { [($1, $3)] }
        | Name ':' Type ',' UseList { ($1,$3):$5 }

VarList :: { [Id] }
VarList : Name { [$1] }
        | Name VarList { $1:$2 }

Where : where { $1 }
      | '=' { $1 }

Constructors :: { [ConParse] }
Constructors : { [] } -- None
             | Constructor { [$1] }
             | Constructor '|' Constructors { $1:$3 }

Constructor :: { ConParse }
Constructor : Name CType { Full $1 $2 }
            | Name Terms { Simple $1 $2 }
--            | Name { Simple $1 [] }

CType :: { RawTerm }
CType : ':' Type { $2 }

Tactic :: { ITactic }
Tactic : intro Names { Intro $2 }
       | intro { Intro [] }
       | refine Name { Refine $2 }
       | generalise Term { Generalise $2 }
       | reflp { ReflP }
       | rewrite Term { Rewrite False False $2 }
       | rewrite leftarrow Term { Rewrite False True $3 }
       | rewriteall Term { Rewrite True False $2 }
       | rewriteall leftarrow Term { Rewrite True True $3 }
       | compute { Compute }
       | unfold Name { Unfold $2 }
       | undo { Undo }
       | induction Term { Induction $2 }
       | fill Term { Fill $2 }
       | trivial { Trivial }
       | mktac Term { RunTactic $2 }
       | believe Term { Believe $2 }
       | use Term { Use $2 }
       | decide Term { Decide $2 }
       | abandon { Abandon }
       | qed { Qed }

ProofScript :: { [ITactic] }
ProofScript : proof '{' Tactics '}' { $3 }

Tactics :: { [ITactic] }
Tactics : Tactic ';' { [$1] }
        | Tactic ';' Tactics { $1:$3 }

Line :: { LineNumber }
     : {- empty -}      {% getLineNo }

File :: { String } 
     : {- empty -} %prec NONE  {% getFileName }

Ops :: { Fixities } 
     : {- empty -} %prec NONE  {% getOps }

{

data ConParse = Full Id RawTerm
              | Simple Id [RawTerm]

parse :: String -> FilePath -> Result [Decl]
parse s fn = do ds <- mkparse s fn 1 []
                collectDecls ds

processImports :: [Opt] -> [FilePath] -> Result [Decl] -> 
                  IO ([Decl], [FilePath])
processImports opts imped (Success ds) = pi imped [] ds
  where pi imps decls ((PInclude fp):xs)
           | fp `elem` imps = pi imps decls xs
           | otherwise = do
                 f <- readLibFile defaultLibPath fp
                 when (Verbose `elem` opts) $ putStrLn ("Reading " ++ fp)
                 case parse f fp of
                   Success t -> pi (fp:imps) decls (t++xs)
                   Failure e f l ->
                     fail $ f ++ ":" ++ show l ++ ":" ++ e
        pi imps decls ((Using t ds):xs)
            = do (ds',imps') <- pi imps [] ds
                 pi imps' (decls++[Using t ds']) xs
        pi imps decls ((Params t ds):xs)
            = do (ds',imps') <- pi imps [] ds
                 pi imps' (decls++[Params t ds']) xs
        pi imps decls ((DoUsing b r ds):xs)
            = do (ds',imps') <- pi imps [] ds
                 pi imps' (decls++[DoUsing b r ds']) xs
        pi imps decls ((Idiom b r ds):xs)
            = do (ds',imps') <- pi imps [] ds
                 pi imps' (decls++[Idiom b r ds']) xs
        pi imps decls (x:xs) = pi imps (decls++[x]) xs
        pi imps decls [] = return (decls, imps)

processImports _ imped (Failure e f l) 
    = fail $ show f ++ ":" ++ show l ++ ":" ++ show e


parseTerm :: String -> Result RawTerm
parseTerm s = mkparseTerm s "(input)" 0 []

parseTactic :: String -> Result ITactic
parseTactic s = mkparseTactic s "(tactic)" 0 []

mkCon :: RawTerm -> ConParse -> (Id,RawTerm)
mkCon _ (Full n t) = (n,t)
mkCon ty (Simple n args) = (n, mkConTy args ty)
   where mkConTy [] ty = ty
         mkConTy (a:as) ty = RBind (MN "X" 0) (Pi Ex Eager a) (mkConTy as ty)

mkDef file line (n, tms) = mkImpApp (RVar file line n) tms
   where mkImpApp f [] = f
         mkImpApp f ((tm,Just n):ts) = mkImpApp (RAppImp file line n f tm) ts
         mkImpApp f ((tm, Nothing):ts) = mkImpApp (RApp file line f tm) ts

doBind :: (RawTerm -> RBinder) -> [(Id,RawTerm)] -> RawTerm -> RawTerm
doBind b [] t = t
doBind b ((x,ty):ts) tm = RBind x (b ty) (doBind b ts tm)

doLetBind :: [(Id,RawTerm,RawTerm)] -> RawTerm -> RawTerm
doLetBind [] t = t
doLetBind ((x,ty,val):ts) tm = RBind x (RLet val ty) (doLetBind ts tm)

mkTyApp :: String -> Int -> Id -> RawTerm -> RawTerm
mkTyApp file line n ty = mkApp file line (RVar file line n) (getTyArgs ty)
   where getTyArgs (RBind n _ t) = (RVar file line n):(getTyArgs t)
         getTyArgs x = []

mkTyParams :: String -> Int -> [Id] -> RawTerm
mkTyParams f l [] = RConst f l TYPE
mkTyParams f l (x:xs) = RBind x (Pi Ex Eager (RConst f l TYPE)) (mkTyParams f l xs)

mkDatatype :: String -> Int ->
              Id -> Either RawTerm ((RawTerm, [(Id, RawTerm)]), [ConParse]) -> 
                    [TyOpt] -> Datatype
mkDatatype file line n (Right ((t, using), cons)) opts
    = Datatype n t (map (mkCon (mkTyApp file line n t)) cons) using opts file line 
mkDatatype file line n (Left t) opts
    = Latatype n t file line

bracket (RUserInfix f l _ op x y) = RUserInfix f l True op x y
bracket x = x

pairDesugar :: String -> Int -> RawTerm -> [RawTerm] -> RawTerm
pairDesugar file line pair [x,y] = mkApp file line pair [x,y]
pairDesugar file line pair (x:y:xs) 
    = pairDesugar file line pair ((mkApp file line pair [x,y]):xs)

sigDesugar :: String -> Int -> (Id, RawTerm) -> RawTerm -> RawTerm
sigDesugar file line (n, tm) sc
    = mkApp file line (RVar file line (UN "Sigma")) [tm, lam]
   where lam = RBind n (Lam tm) sc

}