[project @ 1999-01-14 17:58:41 by sof]
[ghc-hetmet.git] / ghc / compiler / parser / hsparser.y
index 5c3910a..7e18245 100644 (file)
@@ -50,10 +50,9 @@ extern list Lnil;
 extern list reverse_list();
 extern tree root;
 
-/* For FN, PREVPATT and SAMEFN macros */
+/* For FN, SAMEFN macros */
 extern qid     fns[];
 extern BOOLEAN samefn[];
-extern tree    prevpatt[];
 extern short   icontexts;
 
 /* Line Numbers */
@@ -75,8 +74,8 @@ static int Fixity = 0, Precedence = 0;
 char *ineg PROTO((char *));
 
 long    source_version = 0;
+BOOLEAN pat_check=TRUE;
 
-BOOLEAN inpat;
 %}
 
 %union {
@@ -85,7 +84,9 @@ BOOLEAN inpat;
        ttype uttype;
        constr uconstr;
        binding ubinding;
-       pbinding upbinding;
+        match umatch;
+        gdexp ugdexp;
+        grhsb ugrhsb;
        entidt uentid;
        id uid;
        qid uqid;
@@ -127,7 +128,8 @@ BOOLEAN inpat;
 
 %token OCURLY          CCURLY          VCCURLY 
 %token  COMMA          SEMI            OBRACK          CBRACK
-%token WILDCARD        BQUOTE          OPAREN          CPAREN
+%token BQUOTE          OPAREN          CPAREN
+%token  OUNBOXPAREN     CUNBOXPAREN
 
 
 /**********************************************************************
@@ -162,6 +164,9 @@ BOOLEAN inpat;
 %token  SCC
 %token CCALL           CCALL_GC        CASM            CASM_GC
 
+%token DOT             FORALL
+%token  EXPORT          UNSAFE          STDCALL                C_CALL   LABEL
+%token  PASCAL         FASTCALL        FOREIGN         DYNAMIC
 
 /**********************************************************************
 *                                                                     *
@@ -184,7 +189,7 @@ BOOLEAN inpat;
 **********************************************************************/
 
 %token  INTERFACE_UPRAGMA SPECIALISE_UPRAGMA
-%token  INLINE_UPRAGMA MAGIC_UNFOLDING_UPRAGMA
+%token  INLINE_UPRAGMA NOINLINE_UPRAGMA MAGIC_UNFOLDING_UPRAGMA
 %token  END_UPRAGMA 
 %token  SOURCE_UPRAGMA
 
@@ -223,58 +228,65 @@ BOOLEAN inpat;
 **********************************************************************/
 
 
-%type <ulist>   caserest alts alt quals
+%type <ulist>   caserest alts quals
                dorest stmts stmt
                rbinds rbinds1 rpats rpats1 list_exps list_rest
                qvarsk qvars_list
-               constrs constr1 fields 
-               types atypes batypes
+               constrs fields conargatypes
+               tautypes atypes
                types_and_maybe_ids
-               pats simple_context simple_context_list 
+               pats simple_context simple_context_list
                export_list enames
                import_list inames
                impdecls maybeimpdecls impdecl
-               maybefixes fixes fix ops
                dtyclses dtycls_list
-               gdrhs gdpat valrhs
-               lampats cexps gd
+               gdrhs gdpat 
+               lampats cexps gd texps
+               tyvars1 constr_context forall
 
-%type <umaybe>  maybeexports impspec deriving
+%type <umatch>  alt
+
+%type <ugrhsb>  valrhs altrhs
+
+%type <umaybe>  maybeexports impspec deriving 
+               ext_name opt_sig opt_asig
 
 %type <uliteral> lit_constant
 
-%type <utree>  exp oexp dexp kexp fexp aexp rbind texps
+%type <utree>  exp oexp dexp kexp fexp aexp rbind
                expL oexpL kexpL expLno oexpLno dexpLno kexpLno
-               vallhs funlhs qual leftexp
-               pat cpat bpat apat apatc conpat rpat
-                       patk bpatk apatck conpatk
+               funlhs funlhs1 funlhs2 funlhs3 qual leftexp
+               pat dpat cpat bpat apat apatc conpat rpat
+               patk bpatk apatck conpatk
 
 
 %type <uid>    MINUS PLUS DARROW AS LAZY
                VARID CONID VARSYM CONSYM 
                var con varop conop op
                vark varid varsym varsym_nominus
-               tycon modid ccallid
+               tycon modid ccallid tyvar
+               varid_noforall
 
 %type <uqid>   QVARID QCONID QVARSYM QCONSYM 
                qvarid qconid qvarsym qconsym
                qvar qcon qvarop qconop qop
                qvark qconk qtycon qtycls
                gcon gconk gtycon itycon qop1 qvarop1 
-               ename iname 
-
-%type <ubinding>  topdecl topdecls letdecls
-                 typed datad newtd classd instd defaultd
-                 decl decls valdef instdef instdefs
-                 maybe_where cbody rinst type_and_maybe_id
+               ename iname
 
-%type <upbinding> valrhs1 altrest
+%type <ubinding>  topdecl topdecls topdecls1 letdecls
+                 typed datad newtd classd instd defaultd foreignd
+                 decl decls decls1 fixdecl fix_op fix_ops valdef
+                 maybe_where type_and_maybe_id
 
-%type <uttype>    ctype sigtype sigarrowtype type atype bigatype btype
-                 bbtype batype bxtype wierd_atype
-                 simple_con_app simple_con_app1 tyvar contype inst_type
+%type <uttype>    polytype
+                 conargatype conapptype
+                 tautype
+                 apptype
+                 atype polyatype
+                 simple_con_app simple_con_app1 inst_type
 
-%type <uconstr>          constr constr_after_context field
+%type <uconstr>          constr constr_after_context field constr1
 
 %type <ustring>   FLOAT INTEGER INTPRIM
                  FLOATPRIM DOUBLEPRIM CLITLIT
@@ -284,6 +296,7 @@ BOOLEAN inpat;
 %type <uentid>   export import
 
 %type <ulong>     commas importkey get_line_no
+                 unsafe_flag callconv
 
 /**********************************************************************
 *                                                                     *
@@ -311,38 +324,27 @@ module    :  modulekey modid maybeexports
           body
        ;
 
-body   :  ocurly { setstartlineno(); } interface_pragma orestm
-       |  vocurly interface_pragma vrestm
+body   :  ocurly { setstartlineno(); } main_body ccurly
+        |  vocurly                      main_body vccurly
        ;
 
-interface_pragma : /* empty */
-       | INTERFACE_UPRAGMA INTEGER END_UPRAGMA SEMI
-              {
-                source_version = atoi($2);
-              }
-        ;
-
-orestm  :  maybeimpdecls maybefixes topdecls ccurly
+main_body  :  interface_pragma maybeimpdecls topdecls
               {
-                root = mkhmodule(the_module_name,$1,module_exports,
-                                 $2,$3,source_version,modulelineno);
+                root = mkhmodule(the_module_name, $2, module_exports,
+                                 $3, source_version,modulelineno);
               }
-       |  impdecls ccurly
+          |  interface_pragma impdecls
               {
-                root = mkhmodule(the_module_name,$1,module_exports,
-                                 Lnil,mknullbind(),source_version,modulelineno);
+                root = mkhmodule(the_module_name, $2, module_exports,
+                                 mknullbind(), source_version, modulelineno);
               }
 
-vrestm  :  maybeimpdecls maybefixes topdecls vccurly
-              {
-                root = mkhmodule(the_module_name,$1,module_exports,
-                                 $2,$3,source_version,modulelineno);
-              }
-       |  impdecls vccurly
+interface_pragma : /* empty */
+       | INTERFACE_UPRAGMA INTEGER END_UPRAGMA SEMI
               {
-                root = mkhmodule(the_module_name,$1,module_exports,
-                                 Lnil,mknullbind(),source_version,modulelineno);
+                source_version = atoi($2);
               }
+        ;
 
 maybeexports : /* empty */                     { $$ = mknothing(); }
        |  OPAREN export_list CPAREN            { $$ = mkjust($2); }
@@ -366,7 +368,7 @@ enames  :  ename                            { $$ = lsing($1); }
        |  enames COMMA ename                   { $$ = lapp($1,$3); }
        ;
 ename   :  qvar
-       |  qcon
+       |  gcon
        ;
 
 
@@ -385,14 +387,17 @@ impdecl   :  importkey modid impspec
                { $$ = lsing(mkimport($3,1,mknothing(),$4,$1,startlineno)); }
        |  importkey QUALIFIED modid AS modid impspec
                { $$ = lsing(mkimport($3,1,mkjust($5),$6,$1,startlineno)); }
+       |  importkey modid AS modid impspec
+               { $$ = lsing(mkimport($3,1,mkjust($4),$5,$1,startlineno)); }
        ;
 
 impspec        :  /* empty */                            { $$ = mknothing(); }
-       |  OPAREN CPAREN                          { $$ = mkjust(mkleft(Lnil)); }
-       |  OPAREN import_list CPAREN              { $$ = mkjust(mkleft($2));   }
-       |  OPAREN import_list COMMA CPAREN        { $$ = mkjust(mkleft($2));   }
-       |  HIDING OPAREN import_list CPAREN       { $$ = mkjust(mkright($3));  }
-       |  HIDING OPAREN import_list COMMA CPAREN { $$ = mkjust(mkright($3));  }
+       |  OPAREN CPAREN                          { $$ = mkjust(mkleft(Lnil));  }
+       |  OPAREN import_list CPAREN              { $$ = mkjust(mkleft($2));    }
+       |  OPAREN import_list COMMA CPAREN        { $$ = mkjust(mkleft($2));    }
+       |  HIDING OPAREN CPAREN                   { $$ = mkjust(mkright(Lnil)); }
+       |  HIDING OPAREN import_list CPAREN       { $$ = mkjust(mkright($3));   }
+       |  HIDING OPAREN import_list COMMA CPAREN { $$ = mkjust(mkright($3));   }
        ;
 
 import_list:
@@ -428,34 +433,10 @@ iname   :  var                                    { $$ = mknoqual($1); }
 *                                                                     *
 **********************************************************************/
 
-maybefixes:  /* empty */               { $$ = Lnil; }
-       |  fixes SEMI                   { $$ = $1; }
-       ;
-
-fixes  :  fix                          { $$ = $1; }
-       |  fixes SEMI fix               { $$ = lconc($1,$3); }
-       ;
-
-fix    :  INFIXL INTEGER       { Precedence = checkfixity($2); Fixity = INFIXL; }
-          ops                  { $$ = $4; }
-       |  INFIXR INTEGER       { Precedence = checkfixity($2); Fixity = INFIXR; }
-          ops                  { $$ = $4; }
-       |  INFIX  INTEGER       { Precedence = checkfixity($2); Fixity = INFIX; }
-          ops                  { $$ = $4; }
-       |  INFIXL               { Fixity = INFIXL; Precedence = 9; }
-          ops                  { $$ = $3; }
-       |  INFIXR               { Fixity = INFIXR; Precedence = 9; }
-          ops                  { $$ = $3; }
-       |  INFIX                { Fixity = INFIX; Precedence = 9; }
-          ops                  { $$ = $3; }
-       ;
-
-ops    :  op            { $$ = lsing(mkfixop(mknoqual($1),infixint(Fixity),Precedence,startlineno)); }
-       |  ops COMMA op  { $$ = lapp($1,mkfixop(mknoqual($3),infixint(Fixity),Precedence,startlineno)); }
-       ;
+topdecls: topdecls1 opt_semi   { $$ = $1; }
 
-topdecls:  topdecl
-       |  topdecls SEMI topdecl
+topdecls1:  topdecl
+        |  topdecls1 SEMI topdecl
                {
                  if($1 != NULL)
                    if($3 != NULL)
@@ -480,10 +461,11 @@ topdecl   :  typed                                { $$ = $1; FN = NULL; SAMEFN = 0; }
        |  classd                               { $$ = $1; FN = NULL; SAMEFN = 0; }
        |  instd                                { $$ = $1; FN = NULL; SAMEFN = 0; }
        |  defaultd                             { $$ = $1; FN = NULL; SAMEFN = 0; }
+       |  foreignd                             { $$ = $1; FN = NULL; SAMEFN = 0; }
        |  decl                                 { $$ = $1; }
        ;
 
-typed  :  typekey simple_con_app EQUAL type            { $$ = mknbind($2,$4,startlineno); }
+typed  :  typekey simple_con_app EQUAL tautype         { $$ = mknbind($2,$4,startlineno); }
        ;
 
 
@@ -494,48 +476,70 @@ datad     :  datakey simple_con_app EQUAL constrs deriving
        ;
 
 newtd  :  newtypekey simple_con_app EQUAL constr1 deriving
-               { $$ = mkntbind(Lnil,$2,$4,$5,startlineno); }
+               { $$ = mkntbind(Lnil,$2,lsing($4),$5,startlineno); }
        |  newtypekey simple_context DARROW simple_con_app EQUAL constr1 deriving
-               { $$ = mkntbind($2,$4,$6,$7,startlineno); }
+               { $$ = mkntbind($2,$4,lsing($6),$7,startlineno); }
        ;
 
 deriving: /* empty */                          { $$ = mknothing(); }
         | DERIVING dtyclses                     { $$ = mkjust($2); }
        ;
 
-classd :  classkey simple_context DARROW simple_con_app1 cbody
-               { $$ = mkcbind($2,$4,$5,startlineno); }
-       |  classkey simple_con_app1 cbody                       
-               { $$ = mkcbind(Lnil,$2,$3,startlineno); }
-       ;
-
-cbody  :  /* empty */                          { $$ = mknullbind(); }
-       |  WHERE ocurly decls ccurly            { checkorder($3); $$ = $3; }
-       |  WHERE vocurly decls vccurly          { checkorder($3); $$ = $3; }
+classd :  classkey apptype DARROW simple_con_app1 maybe_where
+               /* Context can now be more than simple_context */
+               { $$ = mkcbind(type2context($2),$4,$5,startlineno); }
+       |  classkey apptype maybe_where
+               /* We have to say apptype rather than simple_con_app1, else
+                  we get reduce/reduce errs */
+               { check_class_decl_head($2);
+                 $$ = mkcbind(Lnil,$2,$3,startlineno); }
        ;
 
-instd  :  instkey inst_type rinst              { $$ = mkibind($2,$3,startlineno); }
+instd  :  instkey inst_type maybe_where        { $$ = mkibind($2,$3,startlineno); }
        ;
 
-/* Compare ctype */
-inst_type : type DARROW type                   { is_context_format( $3, 0 );   /* Check the instance head */
-                                                 $$ = mkcontext(type2context($1),$3); }
-         | type                                { is_context_format( $1, 0 );   /* Check the instance head */
+/* Compare polytype */
+/* [July 98: first production was tautype DARROW tautype, but I can't see why.] */
+inst_type : apptype DARROW apptype             { is_context_format( $3, 0 );   /* Check the instance head */
+                                                 $$ = mkforall(Lnil,type2context($1),$3); }
+         | apptype                             { is_context_format( $1, 0 );   /* Check the instance head */
                                                  $$ = $1; }
          ;
 
 
-rinst  :  /* empty */                                          { $$ = mknullbind(); }
-       |  WHERE ocurly  instdefs ccurly                        { $$ = $3; }
-       |  WHERE vocurly instdefs vccurly                       { $$ = $3; }
+defaultd:  defaultkey OPAREN tautypes CPAREN       { $$ = mkdbind($3,startlineno); }
+       |  defaultkey OPAREN CPAREN             { $$ = mkdbind(Lnil,startlineno); }
        ;
 
-defaultd:  defaultkey OPAREN types CPAREN       { $$ = mkdbind($3,startlineno); }
-       |  defaultkey OPAREN CPAREN             { $$ = mkdbind(Lnil,startlineno); }
+/* FFI primitive declarations - GHC/Hugs specific */
+foreignd:  foreignkey IMPORT callconv ext_name unsafe_flag qvarid DCOLON tautype
+                   { $$ = mkfobind($6,$8,$4,$5,$3,FOREIGN_IMPORT,startlineno); }
+        |  foreignkey EXPORT callconv ext_name qvarid DCOLON tautype
+                   { $$ = mkfobind($5,$7,$4,0,$3,FOREIGN_EXPORT,startlineno); }
+        |  foreignkey LABEL ext_name qvarid DCOLON tautype
+                   { $$ = mkfobind($4,$6,$3,0,-1,FOREIGN_LABEL,startlineno); }
        ;
 
-decls  : decl
-       | decls SEMI decl
+callconv: STDCALL      { $$ = CALLCONV_STDCALL;  }
+       | C_CALL        { $$ = CALLCONV_CCALL;    }
+       | PASCAL        { $$ = CALLCONV_PASCAL;   }
+       | FASTCALL      { $$ = CALLCONV_FASTCALL; }
+/* If you leave out the specification of a calling convention, you'll (probably) get C's. */
+        | /*empty*/     { $$ = CALLCONV_NONE;    }
+       ;
+
+ext_name: STRING       { $$ = mkjust(lsing($1)); }
+       | STRING STRING { $$ = mkjust(mklcons ($1,lsing($2))); }
+        | DYNAMIC       { $$ = mknothing();   }
+
+unsafe_flag: UNSAFE    { $$ = 1; }
+          | /*empty*/  { $$ = 0; }
+          ;
+
+decls  : decls1 opt_semi { $$ = $1; }
+
+decls1 : decl
+       | decls1 SEMI decl
                {
                  if(SAMEFN)
                    {
@@ -547,15 +551,26 @@ decls     : decl
                }
        ;
 
+opt_semi : /*empty*/
+        | SEMI 
+        ;
+
 /*
     Note: if there is an iclasop_pragma here, then we must be
     doing a class-op in an interface -- unless the user is up
     to real mischief (ugly, but likely to work).
 */
 
-decl   : qvarsk DCOLON sigtype
+decl   : fixdecl
+
+        | qvarsk DCOLON polytype
                { $$ = mksbind($1,$3,startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
+                 FN = NULL; SAMEFN = 0;
+               }
+
+        | qvark DCOLON polytype
+               { $$ = mksbind(lsing($1),$3,startlineno);
+                 FN = NULL; SAMEFN = 0;
                }
 
        /* User-specified pragmas come in as "signatures"...
@@ -568,41 +583,68 @@ decl      : qvarsk DCOLON sigtype
        |  SPECIALISE_UPRAGMA qvark DCOLON types_and_maybe_ids END_UPRAGMA
                {
                  $$ = mkvspec_uprag($2, $4, startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
+                 FN = NULL; SAMEFN = 0;
                }
 
        |  SPECIALISE_UPRAGMA INSTANCE gtycon atype END_UPRAGMA
                {
                  $$ = mkispec_uprag($3, $4, startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
+                 FN = NULL; SAMEFN = 0;
                }
 
        |  SPECIALISE_UPRAGMA DATA gtycon atypes END_UPRAGMA
                {
                  $$ = mkdspec_uprag($3, $4, startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
+                 FN = NULL; SAMEFN = 0;
                }
 
        |  INLINE_UPRAGMA qvark END_UPRAGMA
                {
                  $$ = mkinline_uprag($2, startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
+                 FN = NULL; SAMEFN = 0;
+               }
+
+       |  NOINLINE_UPRAGMA qvark END_UPRAGMA
+               {
+                 $$ = mknoinline_uprag($2, startlineno);
+                 FN = NULL; SAMEFN = 0;
                }
 
        |  MAGIC_UNFOLDING_UPRAGMA qvark vark END_UPRAGMA
                {
                  $$ = mkmagicuf_uprag($2, $3, startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
+                 FN = NULL; SAMEFN = 0;
                }
 
        /* end of user-specified pragmas */
 
        |  valdef
-       |  /* empty */ { $$ = mknullbind(); PREVPATT = NULL; FN = NULL; SAMEFN = 0; }
        ;
 
+fixdecl        :  INFIXL INTEGER       { Precedence = checkfixity($2); Fixity = INFIXL; }
+          fix_ops              { $$ = $4; }
+       |  INFIXR INTEGER       { Precedence = checkfixity($2); Fixity = INFIXR; }
+          fix_ops              { $$ = $4; }
+       |  INFIX  INTEGER       { Precedence = checkfixity($2); Fixity = INFIX; }
+          fix_ops              { $$ = $4; }
+       |  INFIXL               { Fixity = INFIXL; Precedence = 9; }
+          fix_ops              { $$ = $3; }
+       |  INFIXR               { Fixity = INFIXR; Precedence = 9; }
+          fix_ops              { $$ = $3; }
+       |  INFIX                { Fixity = INFIX; Precedence = 9; }
+          fix_ops              { $$ = $3; }
+       ;
+
+/* Grotesque global-variable hack to
+   make a separate fixity decl for each op */
+fix_ops        :  fix_op
+        |  fix_ops COMMA fix_op { $$ = mkabind($1,$3); }
+       ;
+
+fix_op  : op                    { $$ = mkfixd(mknoqual($1),infixint(Fixity),Precedence,startlineno); }
+        ;
+
 qvarsk :  qvark COMMA qvars_list               { $$ = mklcons($1,$3); }
-       |  qvark                                { $$ = lsing($1); }
        ;
 
 qvars_list: qvar                               { $$ = lsing($1); }
@@ -615,8 +657,8 @@ types_and_maybe_ids :
        ;
 
 type_and_maybe_id :
-          type                                 { $$ = mkvspec_ty_and_id($1,mknothing()); }
-       |  type EQUAL qvark                     { $$ = mkvspec_ty_and_id($1,mkjust($3)); }
+          tautype                              { $$ = mkvspec_ty_and_id($1,mknothing()); }
+       |  tautype EQUAL qvark                  { $$ = mkvspec_ty_and_id($1,mkjust($3)); }
 
 
 /**********************************************************************
@@ -627,55 +669,70 @@ type_and_maybe_id :
 *                                                                     *
 **********************************************************************/
 
-/*  "DCOLON context => type" vs "DCOLON type" is a problem,
+/*  "DCOLON context => tautype" vs "DCOLON tautype" is a problem,
     because you can't distinguish between
 
        foo :: (Baz a, Baz a)
        bar :: (Baz a, Baz a) => [a] -> [a] -> [a]
 
-    with one token of lookahead.  The HACK is to have "DCOLON ttype"
-    [tuple type] in the first case, then check that it has the right
+    with one token of lookahead.  The HACK is to have "DCOLON apptype"
+    in the first case, then check that it has the right
     form C a, or (C1 a, C2 b, ... Cn z) and convert it into a
     context.  Blaach!
 */
 
-/* A sigtype is a rank 2 type; it can have for-alls as function args:
-       f :: All a => (All b => ...) -> Int
-*/
-sigtype        : type DARROW sigarrowtype              { $$ = mkcontext(type2context($1),$3); }
-       | sigarrowtype 
-       ;
+/* --------------------------- */
 
-sigarrowtype : bigatype RARROW sigarrowtype    { $$ = mktfun($1,$3); }
-            | btype RARROW sigarrowtype        { $$ = mktfun($1,$3); }
-            | btype
-            ;
+polyatype : atype
+          ;
 
-/* A "big" atype can be a forall-type in brackets.  */
-bigatype: OPAREN type DARROW type CPAREN       { $$ = mkcontext(type2context($2),$4); }
-       ;
+polytype : FORALL tyvars1 DOT
+                  apptype DARROW tautype       { $$ = mkforall($2,   type2context($4), $6); }
+         | FORALL tyvars1 DOT tautype           { $$ = mkforall($2,   Lnil,             $4); }
+         |        apptype DARROW tautype       { $$ = mkforall(Lnil, type2context($1), $3); }
+         | tautype
+        ;
 
-       /* 1 S/R conflict at DARROW -> shift */
-ctype   : type DARROW type                     { $$ = mkcontext(type2context($1),$3); }
-       | type
-       ;
+/* --------------------------- */
+/* tautype is just a monomorphic type.
+   But it may have nested for-alls if we're in a rank-2 type */
 
-       /* 1 S/R conflict at RARROW -> shift */
-type   :  btype RARROW type                    { $$ = mktfun($1,$3); }
-       |  btype                                { $$ = $1; }
+tautype :  apptype RARROW tautype              { $$ = mktfun($1,$3); }
+       |  apptype                              { $$ = $1; }
        ;
 
-btype  :  btype atype                          { $$ = mktapp($1,$2); }
+tautypes :  tautype                            { $$ = lsing($1); }
+        |  tautypes COMMA tautype              { $$ = lapp($1,$3); }
+        ;
+
+/* --------------------------- */
+/* apptype: type application */
+
+apptype        :  apptype atype                        { $$ = mktapp($1,$2); }
        |  atype                                { $$ = $1; }
        ;
 
-atype          :  gtycon                               { $$ = mktname($1); }
-       |  tyvar                                { $$ = $1; }
-       |  OPAREN type COMMA types CPAREN       { $$ = mkttuple(mklcons($2,$4)); }
-       |  OBRACK type CBRACK                   { $$ = mktllist($2); }
-       |  OPAREN type CPAREN                   { $$ = $2; }
-        ;
+/* --------------------------- */
+/* atype: an atomic or bracketed type: T, x, [ty], tuple ty */
+
+atypes :  atype                                        { $$ = lsing($1); }
+         |  atype atypes                       { $$ = mklcons($1,$2); }
+         ;
+
+atype   :  gtycon                              { $$ = mktname($1); }
+       |  tyvar                                { $$ = mknamedtvar($1); }
+
+       |  OPAREN tautype COMMA
+                 tautypes CPAREN               { $$ = mkttuple(mklcons($2,$4)); }
+
+       |  OUNBOXPAREN tautype COMMA 
+                      tautypes CUNBOXPAREN     { $$ = mktutuple(mklcons($2,$4)); }
+
+       |  OBRACK tautype CBRACK                { $$ = mktllist($2); }
+        |  OPAREN polytype CPAREN              { $$ = $2; }
+       ;
 
+/* --------------------------- */
 gtycon :  qtycon
        |  OPAREN RARROW CPAREN                 { $$ = creategid(ARROWGID); }
        |  OBRACK CBRACK                        { $$ = creategid(NILGID); }         
@@ -683,14 +740,6 @@ gtycon     :  qtycon
        |  OPAREN commas CPAREN                 { $$ = creategid($2); }
        ;
 
-atypes :  atype                                { $$ = lsing($1); }
-       |  atypes atype                         { $$ = lapp($1,$2); }
-       ;
-
-types  :  type                                 { $$ = lsing($1); }
-       |  types COMMA type                     { $$ = lapp($1,$3); }
-       ;
-
 commas : COMMA                                 { $$ = 1; }
        | commas COMMA                          { $$ = $1 + 1; }
        ;
@@ -705,19 +754,22 @@ commas    : COMMA                                 { $$ = 1; }
 
 /* C a b c, where a,b,c are type variables */
 /* C can be a class or tycon */
+
+/* simple_con_app can have no args; simple_con_app1 must have at least one */
 simple_con_app: gtycon                          { $$ = mktname($1); }
         |  simple_con_app1                      { $$ = $1; }
        ;
    
-simple_con_app1:  gtycon tyvar                 { $$ = mktapp(mktname($1),$2); }
-       |  simple_con_app tyvar                 { $$ = mktapp($1, $2); } 
+simple_con_app1:  gtycon tyvar                 { $$ = mktapp(mktname($1),mknamedtvar($2)); }
+       |  simple_con_app1 tyvar                { $$ = mktapp($1, mknamedtvar($2)); } 
        ;
 
 simple_context :  OPAREN simple_context_list CPAREN            { $$ = $2; }
+       | OPAREN CPAREN                                         { $$ = Lnil; }
        |  simple_con_app1                                      { $$ = lsing($1); }
        ;
 
-simple_context_list:  simple_con_app1                          { $$ = lsing($1); }
+simple_context_list :  simple_con_app1                         { $$ = lsing($1); }
        |  simple_context_list COMMA simple_con_app1            { $$ = lapp($1,$3); }
        ;
 
@@ -725,8 +777,17 @@ constrs    :  constr                               { $$ = lsing($1); }
        |  constrs VBAR constr                  { $$ = lapp($1,$3); }
        ;
 
-constr :  constr_after_context
-       |  type DARROW constr_after_context     { $$ = mkconstrcxt ( type2context($1), $3 ); }
+constr :  forall constr_context DARROW constr_after_context    { $$ = mkconstrex ( $1, $2, $4 ); }
+        |  forall constr_after_context                         { $$ = mkconstrex ( $1, Lnil, $2 ); }
+       ;
+
+forall :                                                { $$ = Lnil }
+       | FORALL tyvars1 DOT                             { $$ = $2; }
+       ;
+
+constr_context
+       : conapptype conargatype        { $$ = type2context( mktapp($1,$2) ); }
+       | conargatype                   { $$ = type2context( $1 ); }
        ;
 
 constr_after_context :
@@ -744,65 +805,46 @@ constr_after_context :
        */
 
 /* Con !Int (Tree a) */
-          contype                              { qid tyc; list tys;
+          conapptype                           { qid tyc; list tys;
                                                  splittyconapp($1, &tyc, &tys);
                                                  $$ = mkconstrpre(tyc,tys,hsplineno); }
 
-/* !Int `Con` Tree a */
-       |  bbtype qconop bbtype                 { $$ = mkconstrinf($1,$2,$3,hsplineno); }
-
 /* (::) (Tree a) Int */
-       |  OPAREN qconsym CPAREN batypes        { $$ = mkconstrpre($2,$4,hsplineno); }
+       |  OPAREN qconsym CPAREN conargatypes   { $$ = mkconstrpre($2,$4,hsplineno); }
+
+/* !Int `Con` Tree a */
+       |  conargatype qconop conargatype       { $$ = mkconstrinf($1,$2,$3,hsplineno); }
 
 /* Con { op1 :: Int } */
-       |  gtycon OCURLY fields CCURLY          { $$ = mkconstrrec($1,$3,hsplineno); }
+       | qtycon OCURLY CCURLY                  { $$ = mkconstrrec($1,Lnil,hsplineno); }
+       | qtycon OCURLY fields CCURLY           { $$ = mkconstrrec($1,$3,hsplineno); }
+       | OPAREN qconsym CPAREN OCURLY fields CCURLY { $$ = mkconstrrec($2,$5,hsplineno); }
        ;
                /* 1 S/R conflict on OCURLY -> shift */
 
 
-/* contype has to reduce to a btype unless there are !'s, so that
-   we don't get reduce/reduce conflicts with the second production of constr.
-   But as soon as we see a ! we must switch to using bxtype. */
+conapptype : gtycon                            { $$ = mktname($1); }
+          | conapptype conargatype             { $$ = mktapp($1, $2); }
+          ;
 
-contype : btype                                        { $$ = $1; }
-       | bxtype                                { $$ = $1; }
-       ;
-
-/* S !Int Bool; at least one ! */
-bxtype : btype wierd_atype                     { $$ = mktapp($1, $2); }
-       | bxtype batype                         { $$ = mktapp($1, $2); }
-       ;
-
-bbtype :  btype                                { $$ = $1; }
-       |  wierd_atype                          { $$ = $1; }
-       ;
-
-batype :  atype                                { $$ = $1; }
-       |  wierd_atype                          { $$ = $1; }
-       ;
-
-/* A wierd atype is one that isn't a regular atype;
-   it starts with a "!", or with a forall. */
-wierd_atype : BANG bigatype                    { $$ = mktbang( $2 ); }
-           | BANG atype                        { $$ = mktbang( $2 ); }
-           | bigatype 
+conargatype : polyatype                                { $$ = $1; }
+           | BANG polyatype                    { $$ = mktbang( $2 ); }
            ;
 
-batypes        :                                       { $$ = Lnil; }
-       |  batypes batype                       { $$ = lapp($1,$2); }
-       ;
-
+conargatypes :                                 { $$ = Lnil; }
+         |  conargatype conargatypes           { $$ = mklcons($1,$2); }
+         ;
 
 fields : field                                 { $$ = lsing($1); }
        | fields COMMA field                    { $$ = lapp($1,$3); }
        ;
 
-field  :  qvars_list DCOLON ctype              { $$ = mkfield($1,$3); }
-       |  qvars_list DCOLON BANG atype         { $$ = mkfield($1,mktbang($4)); }
-       |  qvars_list DCOLON BANG bigatype      { $$ = mkfield($1,mktbang($4)); }
+field  :  qvars_list DCOLON polytype           { $$ = mkfield($1,$3); }
+       |  qvars_list DCOLON BANG polyatype     { $$ = mkfield($1,mktbang($4)); }
        ; 
 
-constr1 :  gtycon atype                                { $$ = lsing(mkconstrnew($1,$2,hsplineno)); }
+constr1 : gtycon conargatype                       { $$ = mkconstrnew($1,$2,mknothing(),hsplineno); }
+       | gtycon OCURLY qvar DCOLON polytype CCURLY { $$ = mkconstrnew($1,$5,mkjust($3),hsplineno); }
        ;
 
 
@@ -815,117 +857,65 @@ dtycls_list:  qtycls                             { $$ = lsing($1); }
        |  dtycls_list COMMA qtycls             { $$ = lapp($1,$3); }
        ;
 
-instdefs : /* empty */                         { $$ = mknullbind(); }
-        | instdef                              { $$ = $1; }
-        | instdefs SEMI instdef
-               {
-                 if(SAMEFN)
-                   {
-                     extendfn($1,$3);
-                     $$ = $1;
-                   }
-                 else
-                   $$ = mkabind($1,$3);
-               }
-       ;
-
-/* instdef: same as valdef, except certain user-pragmas may appear */
-instdef :
-          SPECIALISE_UPRAGMA qvark DCOLON types_and_maybe_ids END_UPRAGMA
-               {
-                 $$ = mkvspec_uprag($2, $4, startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
-               }
-
-       |  INLINE_UPRAGMA qvark END_UPRAGMA
-               {
-                 $$ = mkinline_uprag($2, startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
-               }
-
-       |  MAGIC_UNFOLDING_UPRAGMA qvark vark END_UPRAGMA
-               {
-                 $$ = mkmagicuf_uprag($2, $3, startlineno);
-                 PREVPATT = NULL; FN = NULL; SAMEFN = 0;
-               }
-
-       |  valdef
-       ;
-
-
-valdef :  vallhs
+valdef :  funlhs opt_sig       { checksamefn($1); }    
+          get_line_no valrhs   { $$ = mkfbind( lsing(mkpmatch( lsing($1), $2, $5 )), $4); }
 
-               {
-                 tree fn = function($1);
-                 PREVPATT = $1;
-
-                 if(ttree(fn) == ident)
-                   {
-                     qid fun_id = gident((struct Sident *) fn);
-                     checksamefn(fun_id);
-                     FN = fun_id;
-                   }
+/* Special case for  f :: type = e
+   We treat it as a special kind of pattern binding */
+        |  qvark DCOLON tautype 
+           get_line_no valrhs   { $$ = mkpbind( mkrestr( mkident($1), $3 ), $5, $4 ); 
+                                  FN = NULL; SAMEFN = 0; }
 
-                 else if (ttree(fn) == infixap)
-                   {
-                     qid fun_id = ginffun((struct Sinfixap *) fn); 
-                     checksamefn(fun_id);
-                     FN = fun_id;
-                   }
-
-                 else if(etags)
-#if 1/*etags*/
-                   printf("%u\n",startlineno);
-#else
-                   fprintf(stderr,"%u\tvaldef\n",startlineno);
-#endif
-               }       
-
-          get_line_no
-          valrhs
-               {
-                 if ( lhs_is_patt($1) )
-                   {
-                     $$ = mkpbind($4, $3);
-                     FN = NULL;
-                     SAMEFN = 0;
-                   }
-                 else
-                   $$ = mkfbind($4, $3);
-
-                 PREVPATT = NULL;
-               }
-       ;
+        |  patk                 
+           get_line_no valrhs   { $$ = mkpbind($1, $3, $2);
+                                 FN = NULL; SAMEFN = 0; }
 
-get_line_no :                                  { $$ = startlineno }
+get_line_no :                                  { $$ = hsplineno; /* startlineno; */ }
            ;
+/* This grammar still isn't quite right
+   If you say
+      (x + 2) y = e
+   you should get a function binding, but actually the (x+3) will
+   parse as a pattern, and you'll get a parse error. */
+
+funlhs  : patk qvarop cpat                     { $$ = mkinfixap($2,$1,$3); }
+        | funlhs1 apat                          { $$ = mkap( $1, $2 ); }
+
+funlhs1 : oparenkey funlhs2 CPAREN              { $$ = mkpar($2); }
+        | funlhs1 apat                          { $$ = mkap( $1, $2 ); }
+        | qvark                                 { $$ = mkident($1); }
+        ;
 
-vallhs  : patk                                 { $$ = $1; }
-       | patk qvarop pat                       { $$ = mkinfixap($2,$1,$3); }
-       | funlhs                                { $$ = $1; }
-       ;
+funlhs2 : cpat qvarop cpat                     { $$ = mkinfixap($2,$1,$3); }
+        | funlhs3 apat                          { $$ = mkap( $1, $2 ); }
 
-funlhs :  qvark apat                           { $$ = mkap(mkident($1),$2); }
-       |  funlhs apat                          { $$ = mkap($1,$2); }
-       ;
+funlhs3 : OPAREN funlhs2 CPAREN                 { $$ = mkpar($2); }
+        | funlhs3 apat                          { $$ = mkap( $1, $2 ); }
+        | qvar                                  { $$ = mkident($1); }
+        ;
 
+opt_sig :                                       { $$ = mknothing(); }
+        |  DCOLON tautype                       { $$ = mkjust($2); }
+        ;
 
-valrhs :  valrhs1 maybe_where                  { $$ = lsing(createpat($1, $2)); }
-       ;
+/* opt_asig is the same, but with a parenthesised type */
+opt_asig :                                       { $$ = mknothing(); }
+         |  DCOLON atype                         { $$ = mkjust($2); }
+         ;
 
-valrhs1        :  gdrhs                                { $$ = mkpguards($1); }
-       |  EQUAL exp                            { $$ = mkpnoguards($2); }
+valrhs :  EQUAL get_line_no exp maybe_where    { $$ = mkpnoguards($2, $3, $4); }
+        |  gdrhs maybe_where                   { $$ = mkpguards($1, $2); }
        ;
 
-gdrhs  :  gd EQUAL exp                         { $$ = lsing(mkpgdexp($1,$3)); }
-       |  gd EQUAL exp gdrhs                   { $$ = mklcons(mkpgdexp($1,$3),$4); }
+gdrhs  :  gd EQUAL get_line_no exp             { $$ = lsing(mkpgdexp($1,$3,$4)); }
+       |  gd EQUAL get_line_no exp gdrhs       { $$ = mklcons(mkpgdexp($1,$3,$4),$5); }
        ;
 
 maybe_where:
           WHERE ocurly decls ccurly            { $$ = $3; }
        |  WHERE vocurly decls vccurly          { $$ = $3; }
            /* A where containing no decls is OK */
-       |  WHERE SEMI                           { $$ = mknullbind(); }
+       |  WHERE                                { $$ = mknullbind(); }
        |  /* empty */                          { $$ = mknullbind(); }
        ;
 
@@ -941,7 +931,7 @@ gd  :  VBAR quals                           { $$ = $2; }
 *                                                                     *
 **********************************************************************/
 
-exp    :  oexp DCOLON ctype                    { $$ = mkrestr($1,$3); }
+exp    :  oexp DCOLON polytype                 { $$ = mkrestr($1,$3); }
        |  oexp
        ;
 
@@ -949,8 +939,8 @@ exp :  oexp DCOLON ctype                    { $$ = mkrestr($1,$3); }
   Operators must be left-associative at the same precedence for
   precedence parsing to work.
 */
-       /* 8 S/R conflicts on qop -> shift */
-oexp   :  oexp qop oexp %prec MINUS            { $$ = mkinfixap($2,$1,$3); }
+       /* 10 S/R conflicts on qop -> shift */
+oexp   :  oexp qop dexp %prec MINUS            { $$ = mkinfixap($2,$1,$3); }
        |  dexp
        ;
 
@@ -964,10 +954,10 @@ dexp      :  MINUS kexp                           { $$ = mknegate($2); }
 
 /*
   We need to factor out a leading let expression so we can set
-  inpat=TRUE when parsing (non let) expressions inside stmts and quals
+  pat_check=FALSE when parsing (non let) expressions inside stmts and quals
 */
-expLno         :  oexpLno DCOLON ctype                 { $$ = mkrestr($1,$3); }
-       |  oexpLno
+expLno         : oexpLno DCOLON polytype               { $$ = mkrestr($1,$3); }
+       | oexpLno
        ;
 oexpLno        :  oexpLno qop oexp %prec MINUS         { $$ = mkinfixap($2,$1,$3); }
        |  dexpLno
@@ -976,7 +966,7 @@ dexpLno     :  MINUS kexp                           { $$ = mknegate($2); }
        |  kexpLno
        ;
 
-expL   :  oexpL DCOLON ctype                   { $$ = mkrestr($1,$3); }
+expL   :  oexpL DCOLON polytype                { $$ = mkrestr($1,$3); }
        |  oexpL
        ;
 oexpL  :  oexpL qop oexp %prec MINUS           { $$ = mkinfixap($2,$1,$3); }
@@ -999,15 +989,12 @@ kexpL     :  letdecls IN exp                      { $$ = mklet($1,$3); }
 kexpLno        :  LAMBDA
                { hsincindent();        /* push new context for FN = NULL;        */
                  FN = NULL;            /* not actually concerned about indenting */
-                 $<ulong>$ = hsplineno; /* remember current line number           */
-               }
-          lampats
-               { hsendindent();
-               }
-          RARROW exp                   /* lambda abstraction */
-               {
-                 $$ = mklambda($3, $6, $<ulong>2);
                }
+          lampats opt_asig
+               { hsendindent(); }
+
+          RARROW get_line_no exp       /* lambda abstraction */
+               { $$ = mklambda( mkpmatch( $3, $4, mkpnoguards( $7, $8, mknullbind() ) ) ); }
 
        /* If Expression */
        |  IF {$<ulong>$ = hsplineno;}
@@ -1063,10 +1050,10 @@ aexp    :  qvar                                 { $$ = mkident($1); }
        |  OPAREN exp CPAREN                    { $$ = mkpar($2); }         /* mkpar: stop infix parsing at ()'s */
        |  qcon OCURLY rbinds CCURLY            { $$ = mkrecord($1,$3); }   /* 1 S/R conflict on OCURLY -> shift */
        |  OBRACK list_exps CBRACK              { $$ = mkllist($2); }
-       |  OPAREN exp COMMA texps CPAREN        { if (ttree($4) == tuple)
-                                                    $$ = mktuple(mklcons($2, gtuplelist((struct Stuple *) $4)));
-                                                 else
-                                                    $$ = mktuple(ldub($2, $4)); }
+       |  OPAREN exp COMMA texps CPAREN        { $$ = mktuple(mklcons($2,$4)); }
+        /* unboxed tuples */
+       |  OUNBOXPAREN exp COMMA texps CUNBOXPAREN 
+                                               { $$ = mkutuple(mklcons($2,$4)); }
 
        /* only in expressions ... */
        |  aexp OCURLY rbinds1 CCURLY           { $$ = mkrupdate($1,$3); }
@@ -1082,7 +1069,6 @@ aexp      :  qvar                                 { $$ = mkident($1); }
        /* these add 2 S/R conflict with with  aexp . OCURLY rbinds CCURLY */
        |  qvar AT aexp                         { checkinpat(); $$ = mkas($1,$3); }
        |  LAZY aexp                            { checkinpat(); $$ = mklazyp($2); }
-       |  WILDCARD                             { checkinpat(); $$ = mkwildp();   }
        ;
 
        /* ccall arguments */
@@ -1093,7 +1079,7 @@ cexps     :  cexps aexp                           { $$ = lapp($1,$2); }
 caserest:  ocurly alts ccurly                  { $$ = $2; }
        |  vocurly alts vccurly                 { $$ = $2; }
 
-dorest  :  ocurly stmts ccurly                 { checkdostmts($2); $$ = $2; }
+dorest  :  ocurly stmts ccurly                 { checkdostmts($2); $$ = $2; }
        |  vocurly stmts vccurly                { checkdostmts($2); $$ = $2; }
        ;
 
@@ -1105,19 +1091,11 @@ rbinds1 :  rbind                                { $$ = lsing($1); }
        |  rbinds1 COMMA rbind                  { $$ = lapp($1,$3); }
        ;
 
-rbind          :  qvar                                 { $$ = mkrbind($1,mknothing()); }
-       |  qvar EQUAL exp                       { $$ = mkrbind($1,mkjust($3)); }
-       ;
+rbind          :  qvar EQUAL exp                       { $$ = mkrbind($1,mkjust($3)); }
+;      
 
-texps  :  exp  { $$ = mkpar($1); }     /* mkpar: so we don't flatten last element in tuple */
-       |  exp COMMA texps
-               { if (ttree($3) == tuple)
-                   $$ = mktuple(mklcons($1, gtuplelist((struct Stuple *) $3)));
-                 else if (ttree($3) == par)
-                   $$ = mktuple(ldub($1, gpare((struct Spar *) $3)));
-                 else
-                   hsperror("hsparser:texps: panic");
-               }
+texps  :  exp                                  { $$ = lsing($1); }
+       |  exp COMMA texps                      { $$ = mklcons($1, $3) }
        /* right recursion? WDP */
        ;
 
@@ -1149,62 +1127,94 @@ list_rest :     exp                             { $$ = lsing($1); }
           at it, it *will* do the wrong thing [WDP 94/06])
        */
 
-letdecls:  LET ocurly decls ccurly             { $$ = $3; }
-       |  LET vocurly decls vccurly            { $$ = $3; }
+letdecls:  LET { pat_check = TRUE; } ocurly decls ccurly               { $$ = $4; }
+       |  LET { pat_check = TRUE; } vocurly decls vccurly              { $$ = $4; }
        ;
 
-quals  :  qual                                 { $$ = lsing($1); }
-       |  quals COMMA qual                     { $$ = lapp($1,$3); }
-       ;
+/*
+ When parsing patterns inside do stmt blocks or quals, we have
+ to tentatively parse them as expressions, since we don't know at
+ the time of parsing `p' whether it will be part of "p <- e" (pat)
+ or "p" (expr). When we eventually can tell the difference, the parse
+ of `p' is examined to see if it consitutes a syntactically legal pattern
+ or expression.
+
+ The expr rule used to parse the pattern/expression do contain
+ pattern-special productions (e.g., _ , a@pat, etc.), which are
+ illegal in expressions. Since we don't know whether what
+ we're parsing is an expression rather than a pattern, we turn off
+ the check and instead do it later.
+ The rather clumsy way that this check is turned on/off is there
+ to work around a Bison feature/shortcoming. Turning the flag 
+ on/off just around the relevant nonterminal by decorating it
+ with simple semantic actions, e.g.,
+
+    {pat_check = FALSE; } expLNo { pat_check = TRUE; }
+
+ causes Bison to generate a parser where in one state it either
+ has to reduce/perform a semantic action ( { pat_check = FALSE; })
+ or reduce an error (the error production used to implement
+ vccurly.) Bison picks the semantic action, which it ideally shouldn't.
+ The work around is to lift out the setting of { pat_check = FALSE; }
+ and then later reset pat_check. Not pretty.
 
-qual   :  letdecls                             { $$ = mkseqlet($1); }
-       |  expL                                 { $$ = $1; }
-       |  {inpat=TRUE;} expLno 
-          {inpat=FALSE;} leftexp
-               { if ($4 == NULL) {
-                     expORpat(LEGIT_EXPR,$2);
-                     $$ = mkguard($2);
-                 } else {
-                     expORpat(LEGIT_PATT,$2);
-                     $$ = mkqual($2,$4);
-                 }
-               }
+*/
+
+
+quals  :  { pat_check = FALSE;} qual              { pat_check = TRUE; $$ = lsing($2); }
+       |  quals COMMA { pat_check = FALSE; } qual { pat_check = TRUE; $$ = lapp($1,$4); }
        ;
 
-alts   :  alt                                  { $$ = $1; }
-       |  alts SEMI alt                        { $$ = lconc($1,$3); }
+qual   :  letdecls                             { $$ = mkseqlet($1); }
+       |  expL                                 { expORpat(LEGIT_EXPR,$1); $$ = $1; }
+       |  expLno { pat_check = TRUE; } leftexp
+                                               { if ($3 == NULL) {
+                                                    expORpat(LEGIT_EXPR,$1);
+                                                    $$ = mkguard($1);
+                                                 } else {
+                                                    expORpat(LEGIT_PATT,$1);
+                                                    $$ = mkqual($1,$3);
+                                                 }
+                                               }
        ;
 
-alt    :  pat { PREVPATT = $1; } altrest       { $$ = lsing($3); PREVPATT = NULL; }
-       |  /* empty */                          { $$ = Lnil; }
+alts   :  /* empty */                          { $$ = Lnil; }
+        |  alt                                 { $$ = lsing($1); }
+       |  alt SEMI alts                        { $$ = mklcons($1,$3); }
+        |  SEMI alts                            { $$ = $2; }
        ;
 
-altrest        :  gdpat maybe_where                    { $$ = createpat(mkpguards($1), $2); }
-       |  RARROW exp maybe_where               { $$ = createpat(mkpnoguards($2),$3); }
+alt    :  dpat opt_sig altrhs                  { $$ = mkpmatch( lsing($1), $2, $3 ); }
        ;
 
-gdpat  :  gd RARROW exp                        { $$ = lsing(mkpgdexp($1,$3)); }
-       |  gd RARROW exp gdpat                  { $$ = mklcons(mkpgdexp($1,$3),$4);  }
+altrhs :  RARROW get_line_no exp maybe_where   { $$ = mkpnoguards($2, $3, $4); }
+       |  gdpat maybe_where                    { $$ = mkpguards($1, $2); }
+       ;  
+
+gdpat  :  gd RARROW get_line_no exp            { $$ = lsing(mkpgdexp($1,$3,$4)); }
+       |  gd RARROW get_line_no exp gdpat      { $$ = mklcons(mkpgdexp($1,$3,$4),$5);  }
        ;
 
-stmts  :  stmt                                 { $$ = $1; }
-       |  stmts SEMI stmt                      { $$ = lconc($1,$3); }
+stmts  :  {pat_check = FALSE;} stmt          {pat_check=TRUE; $$ = $2; }
+       |  stmts SEMI {pat_check=FALSE;} stmt {pat_check=TRUE; $$ = lconc($1,$4); }
        ;
 
-stmt   :  /* empty */                          { $$ = Lnil; }
-       |  letdecls                             { $$ = lsing(mkseqlet($1)); }
-       |  expL                                 { $$ = lsing(mkdoexp($1,hsplineno)); }
-       |  {inpat=TRUE;} expLno {inpat=FALSE;} leftexp
-               { if ($4 == NULL) {
-                     expORpat(LEGIT_EXPR,$2);
-                     $$ = lsing(mkdoexp($2,endlineno));
-                 } else {
-                     expORpat(LEGIT_PATT,$2);
-                     $$ = lsing(mkdobind($2,$4,endlineno));
-                 }
-               }
+stmt   : /* empty */                           { $$ = Lnil; } 
+       | letdecls                              { $$ = lsing(mkseqlet($1)); }
+       | expL                                  { expORpat(LEGIT_EXPR,$1); $$ = lsing(mkdoexp($1,hsplineno)); }
+       | expLno {pat_check=TRUE;} leftexp
+                                               { if ($3 == NULL) {
+                                                    expORpat(LEGIT_EXPR,$1);
+                                                    $$ = lsing(mkdoexp($1,endlineno));
+                                                 } else {
+                                                    expORpat(LEGIT_PATT,$1);
+                                                    $$ = lsing(mkdobind($1,$3,endlineno));
+                                                 }
+                                               }
        ;
 
+
 leftexp        :  LARROW exp                           { $$ = $2; }
         |  /* empty */                         { $$ = NULL; }
        ;
@@ -1217,7 +1227,11 @@ leftexp  :  LARROW exp                           { $$ = $2; }
 *                                                                     *
 **********************************************************************/
 
-pat    :  qvar PLUS INTEGER                    { $$ = mkplusp($1, mkinteger($3)); }
+pat     :  dpat DCOLON tautype                  { $$ = mkrestr($1,$3); }
+        |  dpat
+        ;
+
+dpat   :  qvar PLUS INTEGER                    { $$ = mkplusp($1, mkinteger($3)); }
        |  cpat
        ;
 
@@ -1244,9 +1258,9 @@ apat      :  gcon                                 { $$ = mkident($1); }
 apatc  :  qvar                                 { $$ = mkident($1); }
        |  qvar AT apat                         { $$ = mkas($1,$3); }
        |  lit_constant                         { $$ = mklit($1); }
-       |  WILDCARD                             { $$ = mkwildp(); }
        |  OPAREN pat CPAREN                    { $$ = mkpar($2); }
        |  OPAREN pat COMMA pats CPAREN         { $$ = mktuple(mklcons($2,$4)); }
+       |  OUNBOXPAREN pat COMMA pats CUNBOXPAREN { $$ = mkutuple(mklcons($2,$4)); }
        |  OBRACK pats CBRACK                   { $$ = mkllist($2); }
        |  LAZY apat                            { $$ = mklazyp($2); }
        ;
@@ -1264,16 +1278,19 @@ lit_constant:
        |  CLITLIT /* yurble yurble */          { $$ = mkclitlit($1); }
        ;
 
+/* Sequence of apats for a lambda abstraction */
 lampats        :  apat lampats                         { $$ = mklcons($1,$2); }
        |  apat                                 { $$ = lsing($1); }
        /* right recursion? (WDP) */
        ;
 
+/* Comma-separated sequence of pats */
 pats   :  pat COMMA pats                       { $$ = mklcons($1, $3); }
        |  pat                                  { $$ = lsing($1); }
        /* right recursion? (WDP) */
        ;
 
+/* Comma separated sequence of record patterns, each of form 'field=pat' */
 rpats  : /* empty */                           { $$ = Lnil; }
        | rpats1
        ;
@@ -1282,11 +1299,14 @@ rpats1  : rpat                                  { $$ = lsing($1); }
        | rpats1 COMMA rpat                     { $$ = lapp($1,$3); }
        ;
 
-rpat   :  qvar                                 { $$ = mkrbind($1,mknothing()); }
-       |  qvar EQUAL pat                       { $$ = mkrbind($1,mkjust($3)); }
+rpat   :  qvar EQUAL pat                       { $$ = mkrbind($1,mkjust($3)); }
        ;
 
 
+/* I can't figure out just what these ...k patterns are for.
+   It seems to have something to do with recording the line number */
+
+/* Corresponds to a cpat */
 patk   :  patk qconop bpat                     { $$ = mkinfixap($2,$1,$3); }
        |  bpatk
        ;
@@ -1305,9 +1325,10 @@ conpatk  :  gconk                                { $$ = mkident($1); }
 apatck :  qvark                                { $$ = mkident($1); }
        |  qvark AT apat                        { $$ = mkas($1,$3); }
        |  lit_constant                         { $$ = mklit($1); setstartlineno(); }
-       |  WILDCARD                             { $$ = mkwildp(); setstartlineno(); }
        |  oparenkey pat CPAREN                 { $$ = mkpar($2); }
        |  oparenkey pat COMMA pats CPAREN      { $$ = mktuple(mklcons($2,$4)); }
+       |  ounboxparenkey pat COMMA pats CUNBOXPAREN
+                                               { $$ = mkutuple(mklcons($2,$4)); }
        |  obrackkey pats CBRACK                { $$ = mkllist($2); }
        |  lazykey apat                         { $$ = mklazyp($2); }
        ;
@@ -1381,6 +1402,9 @@ instkey   :   INSTANCE    { setstartlineno();
 defaultkey: DEFAULT    { setstartlineno(); }
        ;
 
+foreignkey: FOREIGN             { setstartlineno();  }
+         ;
+
 classkey:   CLASS      { setstartlineno();
                          if(etags)
 #if 1/*etags*/
@@ -1404,6 +1428,9 @@ modulekey:  MODULE        { setstartlineno();
 oparenkey:  OPAREN     { setstartlineno(); }
        ;
 
+ounboxparenkey: OUNBOXPAREN { setstartlineno(); }
+        ;
+
 obrackkey:  OBRACK     { setstartlineno(); }
        ;
 
@@ -1503,32 +1530,46 @@ varsym  :  varsym_nominus
 varsym_nominus : VARSYM
        |  PLUS                         { $$ = install_literal("+"); }
        |  BANG                         { $$ = install_literal("!"); }  
+       |  DOT                          { $$ = install_literal("."); }
        ;
 
 /* AS HIDING QUALIFIED are valid varids */
-varid   :  VARID
+varid   :  varid_noforall
+        |  FORALL                       { $$ = install_literal("forall"); }
+       ;
+
+varid_noforall
+       :  VARID
        |  AS                           { $$ = install_literal("as"); }
        |  HIDING                       { $$ = install_literal("hiding"); }
        |  QUALIFIED                    { $$ = install_literal("qualified"); }
+/* The rest of these guys are used by the FFI decls, a ghc (and hugs) extension. */
+       |  EXPORT                       { $$ = install_literal("export"); }
+       |  UNSAFE                       { $$ = install_literal("unsafe"); }
+       |  DYNAMIC                      { $$ = install_literal("dynamic"); }
+       |  LABEL                        { $$ = install_literal("label"); }
+       |  C_CALL                       { $$ = install_literal("ccall"); }
+       |  STDCALL                      { $$ = install_literal("stdcall"); }
+       |  PASCAL                       { $$ = install_literal("pascal"); }
        ;
 
-
 ccallid        :  VARID
        |  CONID
        ;
 
-tyvar  :  varid                        { $$ = mknamedtvar(mknoqual($1)); }
-       ;
 tycon  :  CONID
        ;
 modid  :  CONID
        ;
 
-/*
-tyvar_list: tyvar                      { $$ = lsing($1); }
-       |  tyvar_list COMMA tyvar       { $$ = lapp($1,$3); }
+/* ---------------------------------------------- */
+tyvar  :  varid_noforall               { $$ = $1; }
+       ;
+
+/* tyvars1: At least one tyvar */
+tyvars1 : tyvar                                { $$ = lsing($1); }
+       | tyvar tyvars1                 { $$ = mklcons($1,$2); }
        ;
-*/
 
 /**********************************************************************
 *                                                                     *
@@ -1549,7 +1590,7 @@ layout    :                                       { hsindentoff(); }
 ccurly :
         CCURLY
                {
-                 FN = NULL; SAMEFN = 0; PREVPATT = NULL;
+                 FN = NULL; SAMEFN = 0;
                  hsendindent();
                }
        ;
@@ -1560,16 +1601,16 @@ vccurly :  { expect_ccurly = 1; }  vccurly1  { expect_ccurly = 0; }
 vccurly1:
         VCCURLY
                {
-                 FN = NULL; SAMEFN = 0; PREVPATT = NULL;
+                 FN = NULL; SAMEFN = 0;
                  hsendindent();
                }
        | error
                {
                  yyerrok;
-                 FN = NULL; SAMEFN = 0; PREVPATT = NULL;
+                 FN = NULL; SAMEFN = 0;
                  hsendindent();
                }
-       ;
+       ;
 
 %%
 
@@ -1581,14 +1622,14 @@ vccurly1:
 *                                                                     *
 **********************************************************************/
 
+
 void
 checkinpat()
 {
-  if(!inpat)
+  if(pat_check)
     hsperror("pattern syntax used in expression");
 }
 
-
 /* The parser calls "hsperror" when it sees a
    `report this and die' error.  It sets the stage
    and calls "yyerror".
@@ -1624,7 +1665,7 @@ yyerror(s)
     /* We want to be able to distinguish 'error'-raised yyerrors
        from yyerrors explicitly coded by the parser hacker.
     */
-    if (expect_ccurly && ! error_and_I_mean_it ) {
+    if ( expect_ccurly && ! error_and_I_mean_it ) {
        /*NOTHING*/;
 
     } else {