%{

open Fnlib Config Mixture Const Globals Location Types Asynt Asyntfn;

%}

%token ABSTRACTION ABSTYPE AND ANDALSO AS CASE DATATYPE DO ELSE END
%token EQTYPE EXCEPTION
%token FN FUN HANDLE IF IN INFIX INFIXR LET LOCAL
%token NONFIX OF OP ORELSE RAISE REC SIG SIGNATURE STRUCT STRUCTURE
%token THEN TYPE VAL WHILE WITH WITHTYPE

%token EQUALS
%token COMMA ARROW DARROW BAR STAR HASH
%token LBRACE RBRACE HASHLBRACKET LBRACKET RBRACKET LPAREN RPAREN
%token COLON COLONGT SEMICOLON UNDERBAR DOTDOTDOT

%token OPEN PRIM_VAL PRIM_TYPE PRIM_EQTYPE PRIM_REFTYPE

%token <string> ID
%token <Const.QualifiedIdent> QUAL_ID QUAL_STAR

%token <int> ZDIGIT NZDIGIT ZPOSINT2 NZPOSINT2 NEGINT
%token <word> WORD
%token <char> CHAR
%token <real> REAL
%token <string> STRING

%token QUOTEL
%token <string> QUOTER QUOTEM

%token <string> TYVAR

%token EOF

%right    AND
%nonassoc DARROW
%nonassoc BAR
%nonassoc ELSE
%nonassoc DO
%nonassoc RAISE
%right    HANDLE
%right    ORELSE
%right    ANDALSO
%right    AS

%nonassoc COLON
%right    ARROW
%nonassoc ID EQUALS
%right    STAR

%start ToplevelPhrase
%type <Asynt.Dec * bool> ToplevelPhrase

%start SigFile
%type <Asynt.Sig> SigFile

%start StructFile
%type <Asynt.Struct> StructFile

%type <bool> EOPh
%type <string> Ident EqIdent UnitName
%type <Location.Location * string> IdentWithLoc LocUnitName
%type <Asynt.IdInfo> OpIdent TypeIdent LongTypeIdent
%type <Asynt.IdInfo> LongIdent LongOpIdent LongOpEqIdent
%type <Asynt.TyVar> TyVar
%type <string list> EqIdent_seq1 UnitName_seq1
%type <int> DIGIT_opt Integer NumLabel Arity
%type <unit> SemiEof
%type <Mixture.Lab> Label
%type <Const.SCon> SCon
%type <Asynt.Dec> Dec KWDec_seq1 KWDec
%type <Asynt.Dec list> KWDec_seq
%type <Asynt.ValBind list * Asynt.ValBind list> ValBind AndValBind_opt
%type <Asynt.PrimValBind list> PrimValBind AndPrimValBind_opt
%type <Asynt.ValBind list> FnValBind AndFnValBind_opt
%type <Asynt.TypBind list> TypBind AndTypBind_opt
%type <Asynt.TypDesc list> TypDesc AndTypDesc_opt
%type <Asynt.DatBind list> DatBind AndDatBind_opt
%type <Asynt.ConBind list> ConBind BarConBind_opt
%type <Asynt.TypBind list option> WithType_opt
%type <Asynt.ExBind list> ExBind AndExBind_opt
%type <Asynt.ExDesc list> ExDesc AndExDesc_opt
%type <Asynt.Ty option> OfTy_opt ColonTy_opt
%type <Asynt.FValBind list> FValBind AndFValBind_opt
%type <Asynt.FValBind> FClauseWithLoc
%type <Asynt.FClause list> FClause BarFClause_opt
%type <Asynt.Exp> AtExp Exp
%type <Asynt.Exp list> ExpComma_seq0 ExpComma_seq1 ExpComma_seq2
	QuoteTail ExpQuoteTail 
%type <Asynt.Exp list> ExpSemicolon_seq2
%type <Asynt.Exp list> AtExp_seq1
%type <Asynt.Exp Mixture.Row> ExpRow_opt ExpRow CommaExpRow_opt
%type <Asynt.Match> Match
%type <Location.Location * Asynt.Match> MatchWithLoc
%type <Asynt.MRule> MRule
%type <Asynt.Pat> Pat AtPat
%type <Asynt.Pat list> AtPat_seq1
%type <Asynt.Pat list> PatComma_seq0 PatComma_seq1 PatComma_seq2
%type <Asynt.Pat Mixture.Row * bool> PatRow_opt PatRow CommaPatRow_opt
%type <Asynt.Pat option> AsPat_opt
%type <Asynt.Ty> Ty Ty_sans_STAR AtomicTy
%type <Asynt.Ty list> TupleTy TyComma_seq2
%type <Asynt.Ty Mixture.Row> TyRow_opt TyRow CommaTyRow_opt
%type <Asynt.TyVar list> TyVarSeq TyVarSeq1 TyVarComma_seq1

%type <Asynt.Spec> Spec KWSpec
%type <Asynt.Spec list> KWSpec_seq
%type <Asynt.ValDesc list> ValDesc AndValDesc_opt

%%

Ident :
    ID          { $1 }
  | STAR        { "*" }
;

IdentWithLoc :
    Ident       { mkLoc($1) }
;

OpIdent :
    Ident       { mkIdInfo (mkLoc { qual="", id=$1 }) false }
  | OP Ident    { mkIdInfo (mkLoc { qual="", id=$2 }) true }
;

EqIdent :
    Ident       { $1 }
  | EQUALS      { "=" }
;

LocUnitName :
    UnitName    { mkLoc($1) }
;

UnitName :
    Ident       { normalizedUnitName $1 }
  | EQUALS      { "=" }
;

TypeIdent :
    ID          { mkIdInfo (mkLoc { qual="", id=$1 }) false }
;

LongTypeIdent :
    TypeIdent   { $1 }
  | QUAL_ID     { mkIdInfo (mkLoc $1) false }
;

LongIdent :
    Ident       { mkIdInfo (mkLoc { qual="", id=$1 }) false }
  | QUAL_ID     { mkIdInfo (mkLoc $1) false }
  | QUAL_STAR   { mkIdInfo (mkLoc $1) false }
;

LongOpIdent :
    LongIdent      { $1 }
  | OP Ident       { mkIdInfo (mkLoc { qual="", id=$2 }) true }
  | OP QUAL_ID     { mkIdInfo (mkLoc $2) true }
  | OP QUAL_STAR   { mkIdInfo (mkLoc $2) true }
;

LongOpEqIdent :
    LongOpIdent    { $1 }
  | EQUALS         { mkIdInfo (mkLoc { qual="", id="=" }) false }
  | OP EQUALS      { mkIdInfo (mkLoc { qual="", id="=" }) true }
;

TyVar :
    TYVAR    { mkIdInfo (mkLoc { qual="", id=$1 }) false }
;

EqIdent_seq1 :
    EqIdent EqIdent_seq1        { $1 :: $2 }
  | EqIdent                     { [$1] }
;

UnitName_seq1 :
    UnitName UnitName_seq1      { $1 :: $2 }
  | UnitName                    { [$1] }
;

DIGIT_opt :
    ZDIGIT      { $1 }
  | NZDIGIT     { $1 }
  | /* */       { 0 }
;

Integer :
    ZPOSINT2    { $1 }
  | NZPOSINT2   { $1 }
  | NEGINT      { $1 }
  | ZDIGIT      { $1 }
  | NZDIGIT     { $1 }
;

NumLabel :
    NZPOSINT2   { $1 }
  | NZDIGIT     { $1 }
;

Label :
    Ident       { STRINGlab $1 }
  | NumLabel    { INTlab $1 }
;

Arity :
    ZPOSINT2    { $1 }
  | NZPOSINT2   { $1 }
  | ZDIGIT      { $1 }
  | NZDIGIT     { $1 }
;

ToplevelPhrase :
    Exp EOPh                    { (mkValIt $1, $2) }
  | KWDec_seq1 EOPh             { ($1, $2) }
  | EOPh                        { (mkLoc(EMPTYdec), $1) }
;

EOPh :
    SEMICOLON		{ false }
  | EOF			{ true }
;

SemiEof :
    SEMICOLON SemiEof   { }
  | EOF			{ }
;

Dec :
    KWDec Dec           { mkLoc(SEQdec($1, $2)) }
  | SEMICOLON Dec       { $2 }
  | /* */               { mkLoc(EMPTYdec) }
;

KWDec_seq1 :
    KWDec KWDec_seq1    { mkLoc(SEQdec($1,$2)) }
  | KWDec               { $1 }
;

StructFile :
    STRUCTURE LocUnitName EQUALS STRUCT KWDec_seq END SemiEof
		{ NamedStruct{locstrid = $2, locsigid = NONE, decs = $5} }
  | STRUCTURE LocUnitName COLONGT LocUnitName EQUALS 
	                                      STRUCT KWDec_seq END SemiEof
		{ Abstraction{locstrid = $2, locsigid = $4, decs = $7} }
  | ABSTRACTION LocUnitName COLON LocUnitName EQUALS 
	                                      STRUCT KWDec_seq END SemiEof
		{ Abstraction{locstrid = $2, locsigid = $4, decs = $7} }
  | KWDec_seq EOF
		{ AnonStruct $1 }
;

KWDec_seq :
    KWDec KWDec_seq		{ $1 :: $2 }
  | SEMICOLON KWDec_seq		{ $2 }
  | /* */			{ [] }
;

KWDec :
    VAL ValBind                 { mkLoc(VALdec ([], $2)) }
  | VAL TyVarSeq1 ValBind       { mkLoc(VALdec ($2, $3)) }
  | PRIM_VAL PrimValBind        { mkLoc(PRIM_VALdec $2) }
  | FUN FValBind                { mkLoc(FUNdec ([], $2)) }
  | FUN TyVarSeq1 FValBind      { mkLoc(FUNdec ($2, $3)) }
  | TYPE TypBind                { mkLoc(TYPEdec $2) }
  | PRIM_TYPE TypDesc           { mkLoc(PRIM_TYPEdec(FALSEequ, $2)) }
  | PRIM_EQTYPE TypDesc         { mkLoc(PRIM_TYPEdec(TRUEequ, $2)) }
  | PRIM_REFTYPE TypDesc        { mkLoc(PRIM_TYPEdec(REFequ, $2)) }
  | DATATYPE DatBind WithType_opt
                                { mkLoc(DATATYPEdec($2,$3)) }
  | ABSTYPE DatBind WithType_opt WITH Dec END
                                { mkLoc(ABSTYPEdec($2,$3,$5)) }
  | EXCEPTION ExBind            { mkLoc(EXCEPTIONdec $2) }
  | LOCAL Dec IN Dec END        { mkLoc(LOCALdec($2,$4)) }
  | OPEN UnitName_seq1          { mkLoc(OPENdec $2) }
  | INFIX DIGIT_opt EqIdent_seq1
                                { mkLoc(FIXITYdec(INFIXst $2, $3)) }
  | INFIXR DIGIT_opt EqIdent_seq1
                                { mkLoc(FIXITYdec(INFIXRst $2, $3)) }
  | NONFIX EqIdent_seq1
                                { mkLoc(FIXITYdec(NONFIXst, $2)) }
;

ValBind :
    Pat EQUALS Exp AndValBind_opt
                { let val (pvbs, rvbs) = $4
                  in (ValBind($1, $3)::pvbs, rvbs) end }
  | REC FnValBind
                { ([], $2) }
;

AndValBind_opt :
    AND ValBind         { $2 }
  | /* */               { ([], []) }
;

PrimValBind :
    OpIdent COLON Ty EQUALS Arity STRING AndPrimValBind_opt
                        { ($1, $3, $5, $6) :: $7 }
;

AndPrimValBind_opt :
    AND PrimValBind     { $2 }
  | /* */               { [] }
;

FnValBind :
    Pat EQUALS Exp AndFnValBind_opt
                        { ValBind($1, $3) :: $4 }
  | REC FnValBind       { $2 }
;

AndFnValBind_opt :
    AND FnValBind       { $2 }
  | /* */               { [] }
;

TypBind :
    TyVarSeq TypeIdent  EQUALS Ty AndTypBind_opt
                        { ($1, $2, $4) :: $5 }
;

AndTypBind_opt :
    AND TypBind         { $2 }
  | /* */               { [] }
;

DatBind :
    TyVarSeq TypeIdent EQUALS ConBind AndDatBind_opt
                        { ($1, $2, $4) :: $5 }
;

AndDatBind_opt :
    AND DatBind         { $2 }
  | /* */               { [] }
;

ConBind :
    OpIdent OfTy_opt BarConBind_opt     { ConBind($1, $2) :: $3 }
;

BarConBind_opt :
    BAR ConBind         { $2 }
  | /* */               { [] }
;

WithType_opt :
    WITHTYPE TypBind    { SOME $2 }
  | /* */               { NONE }

ExBind :
    OpIdent OfTy_opt AndExBind_opt              { EXDECexbind($1,$2) :: $3 }
  | OpIdent EQUALS LongOpEqIdent AndExBind_opt  { EXEQUALexbind($1,$3) :: $4 }
;

AndExBind_opt :
    AND ExBind          { $2 }
  | /* */               { [] }
;

ExDesc :
    OpIdent OfTy_opt AndExDesc_opt              { ($1,$2) :: $3 }
;

AndExDesc_opt :
    AND ExDesc          { $2 }
  | /* */               { [] }
;

ColonTy_opt :
    COLON Ty    { SOME $2 }
  | /* */       { NONE }

OfTy_opt :
    OF Ty       { SOME $2 }
  | /* */       { NONE }
;

FValBind :
    FClauseWithLoc AndFValBind_opt     { $1 :: $2 }
;

AndFValBind_opt :
    AND FValBind        { $2 }
  | /* */               { [] }
;

FClauseWithLoc :
    FClause             { mkLoc $1 }
;

FClause :
    AtPat_seq1 ColonTy_opt EQUALS Exp BarFClause_opt
        { let val rhs = (case $2 of
                             SOME ty => (xxLR ty $4, TYPEDexp($4,ty))
                           | NONE => $4)
          in FClause($1, rhs) :: $5 end }
;

BarFClause_opt :
    BAR FClause         { $2 }
  | /* */               { [] }
;

SCon :
    Integer     { INTscon $1 }
  | WORD        { WORDscon $1 }
  | CHAR        { CHARscon $1 }
  | REAL        { REALscon $1 }
  | STRING      { STRINGscon $1 }
;

AtExp :
    SCon                { mkLoc(SCONexp($1, ref NONE)) }
  | LongOpEqIdent       { mkLoc(VARexp(ref (RESve $1))) }
  | LET Dec IN Exp END  { mkLoc(LETexp($2,$4)) }
  | HASH Label          { hashLabelExp(mkLoc $2) }
  | LPAREN Exp RPAREN   { mkLoc(PARexp $2) }
  | LPAREN RPAREN       { tupleExp(mkLoc []) }
  | LPAREN ExpComma_seq2 RPAREN
                        { tupleExp(mkLoc $2) }
  | LPAREN ExpSemicolon_seq2 RPAREN
                        { seqExp $2 }
  | LBRACE ExpRow_opt RBRACE
                        { mkLoc(RECexp(ref (RECre $2))) }
  | LET Dec IN ExpSemicolon_seq2 END
                        { mkLoc(LETexp($2, seqExp $4)) }
  | LBRACKET ExpComma_seq0 RBRACKET
                        { listExp(mkLoc $2) }
  | HASHLBRACKET ExpComma_seq0 RBRACKET
                        { mkLoc(VECexp $2) }
  | QUOTEL QuoteTail
      { listExp(mkLoc $2) }
;

QuoteTail :
    QUOTER
      { [quoteExp(mkLoc(SCONexp(STRINGscon $1, ref NONE)))] }
  | QUOTEM ExpQuoteTail
      { quoteExp(mkLoc(SCONexp(STRINGscon $1, ref NONE))) :: $2 }
;

ExpQuoteTail :
    Exp QuoteTail       { antiquoteExp($1) :: $2 }
;

ExpComma_seq0 :
    ExpComma_seq1               { $1 }
  | /* */                       { [] }
;

ExpComma_seq1 :
    Exp COMMA ExpComma_seq1     { $1 :: $3 }
  | Exp                         { [$1] }
;

ExpComma_seq2 :
    Exp COMMA ExpComma_seq1     { $1 :: $3 }
;

ExpSemicolon_seq2 :
    Exp SEMICOLON ExpSemicolon_seq2     { $1 :: $3 }
  | Exp SEMICOLON Exp                   { [$1, $3] }

AtExp_seq1 :
    AtExp AtExp_seq1            { $1 :: $2 }
  | AtExp                       { [$1] }
;

ExpRow_opt :
    ExpRow      { $1 }
  | /* */       { [] }
;

ExpRow :
    Label EQUALS Exp CommaExpRow_opt    { ($1,$3)::$4 }
;

CommaExpRow_opt :
    COMMA ExpRow        { $2 }
  | /* */               { [] }
;

Exp :
    AtExp_seq1                  { mkLoc(INFIXexp $1) }
  | Exp COLON Ty                { mkLoc(TYPEDexp($1,$3)) }
  | Exp ANDALSO Exp             { mkLoc(ANDALSOexp($1,$3)) }
  | Exp ORELSE Exp              { mkLoc(ORELSEexp($1,$3)) }
  | Exp HANDLE Match            { mkLoc(HANDLEexp($1,$3)) }
  | RAISE Exp                   { mkLoc(RAISEexp $2) }
  | IF Exp THEN Exp ELSE Exp    { mkLoc(IFexp($2,$4,$6)) }
  | WHILE Exp DO Exp            { mkLoc(WHILEexp($2,$4)) }
  | CASE Exp OF MatchWithLoc
        { let val (loc, mrules) = $4
          in mkLoc(APPexp((loc, FNexp mrules), $2)) end }
  | FN Match                    { mkLoc(FNexp $2) }
;

MatchWithLoc :
    Match       { mkLoc $1 }
;

Match :
    MRule BAR Match             { $1 :: $3 }
  | MRule       %prec DARROW    { [$1] }
;

MRule :
    Pat DARROW Exp      { MRule([$1],$3) }
;

Pat :
    AtPat_seq1          { mkLoc(INFIXpat $1) }
  | Pat COLON Ty        { mkLoc(TYPEDpat($1,$3)) }
  | Pat AS Pat          { mkLoc(LAYEREDpat($1,$3)) }
;

AtPat :
    UNDERBAR                    { mkLoc(WILDCARDpat) }
  | SCon                        { mkLoc(SCONpat($1, ref NONE)) }
  | LongOpIdent                 { mkLoc(VARpat $1) }
  | LBRACE PatRow_opt RBRACE
        { let val (fs, flexible) = $2 in
            if flexible then
              mkLoc(RECpat(ref (RECrp(fs, SOME (fresh3DotType())))))
            else
              mkLoc(RECpat(ref (RECrp(fs, NONE))))
          end }
  | LPAREN Pat RPAREN           { mkLoc(PARpat $2) }
  | LPAREN RPAREN               { tuplePat(mkLoc []) }
  | LPAREN PatComma_seq2 RPAREN
                        { tuplePat(mkLoc $2) }
  | LBRACKET PatComma_seq0 RBRACKET
                        { listPat(mkLoc $2) }
  | HASHLBRACKET PatComma_seq0 RBRACKET
                        { mkLoc(VECpat $2) }
;

PatRow_opt :
    PatRow      { $1 }
  | /* */       { ([], false) }
;

PatRow :
    DOTDOTDOT   { ([],true) }
  | Label EQUALS Pat CommaPatRow_opt
        { let val (fs, flexible) = $4
          in (($1,$3)::fs, flexible) end }
  | IdentWithLoc ColonTy_opt AsPat_opt CommaPatRow_opt
        { let val (fs, flexible) = $4
          in (mkLabPatOfId $1 $2 $3::fs, flexible) end }
;

AsPat_opt :
    AS Pat      { SOME $2 }
  | /* */       { NONE }
;

CommaPatRow_opt :
    COMMA PatRow        { $2 }
  | /* */               { ([], false) }
;

AtPat_seq1 :
    AtPat AtPat_seq1            { $1 :: $2 }
  | AtPat                       { [$1] }
;

PatComma_seq0 :
    PatComma_seq1               { $1 }
  | /* */                       { [] }
;

PatComma_seq1 :
    Pat COMMA PatComma_seq1     { $1 :: $3 }
  | Pat                         { [$1] }
;

PatComma_seq2 :
    Pat COMMA PatComma_seq1     { $1 :: $3 }
;

Ty :
    TupleTy ARROW Ty    { mkLoc(FNty( tupleTy $1, $3)) }
  | TupleTy             { tupleTy $1 }
;

TupleTy :
    Ty_sans_STAR                { [$1] }
  | Ty_sans_STAR STAR TupleTy   { $1 :: $3 }
;

Ty_sans_STAR :
    LPAREN TyComma_seq2 RPAREN LongTypeIdent    { mkLoc(CONty($2, $4)) }
  | Ty_sans_STAR LongTypeIdent                  { mkLoc(CONty([$1], $2)) }
  | AtomicTy                                    { $1 }
;

TyComma_seq2 :
    Ty COMMA TyComma_seq2       { $1 :: $3 }
  | Ty COMMA Ty                 { [$1, $3] }
;

AtomicTy :
    LongTypeIdent               { mkLoc(CONty([], $1)) }
  | TyVar                       { mkLoc(TYVARty $1) }
  | LBRACE TyRow_opt RBRACE     { mkLoc(RECty $2) }
  | LPAREN Ty RPAREN            { $2 }
;

TyRow_opt :
    TyRow       { $1 }
  | /* */       { [] }
;

TyRow :
    Label COLON Ty CommaTyRow_opt       { ($1,$3)::$4 }
;

CommaTyRow_opt :
    COMMA TyRow         { $2 }
  | /* */               { [] }
;

TyVarSeq :
    TyVarSeq1                           { $1 }
  | /* */                               { [] }
;

TyVarSeq1 :
    TyVar                               { [$1] }
  | LPAREN TyVarComma_seq1 RPAREN       { $2 }
;

TyVarComma_seq1 :
    TyVar COMMA TyVarComma_seq1         { $1 :: $3 }
  | TyVar                               { [$1] }
;

Spec :
    KWSpec Spec         { mkLoc(SEQspec($1, $2)) }
  | SEMICOLON Spec      { $2 }
  | /* */               { mkLoc(EMPTYspec) }
;

SigFile :
    SIGNATURE LocUnitName EQUALS SIG KWSpec_seq END SemiEof
                        { NamedSig{locsigid = $2, specs = $5 } }
  | KWSpec_seq EOF	{ AnonSig $1 }
;

KWSpec_seq :
    KWSpec KWSpec_seq		{ $1 :: $2 }
  | SEMICOLON KWSpec_seq	{ $2 }
  | /* */			{ [] }
;

KWSpec :
    VAL ValDesc                 { mkLoc(VALspec $2) }
  | PRIM_VAL PrimValBind        { mkLoc(PRIM_VALspec $2) }
  | TYPE TypBind                { mkLoc(TYPEspec $2) }
  | TYPE TypDesc                { mkLoc(TYPEDESCspec(FALSEequ, $2)) }
  | EQTYPE TypDesc              { mkLoc(TYPEDESCspec(TRUEequ, $2)) }
  | PRIM_REFTYPE TypDesc        { mkLoc(TYPEDESCspec(REFequ, $2)) }
  | DATATYPE DatBind WithType_opt
                                { mkLoc(DATATYPEspec($2,$3)) }
  | EXCEPTION ExDesc            { mkLoc(EXCEPTIONspec $2) }
  | LOCAL Spec IN Spec END      { mkLoc(LOCALspec($2,$4)) }
  | OPEN UnitName_seq1          { mkLoc(OPENspec $2) }
;

ValDesc :
    OpIdent COLON Ty AndValDesc_opt
                        { ($1, $3) :: $4 }
;

AndValDesc_opt :
    AND ValDesc         { $2 }
  | /* */               { [] }
;

TypDesc :
    TyVarSeq TypeIdent AndTypDesc_opt
                        { ($1, $2) :: $3 }
;

AndTypDesc_opt :
    AND TypDesc         { $2 }
  | /* */               { [] }
;
