> { > ----------------------------------------------------------------------------- > -- | > -- Module : Language.Haskell.Parser > -- Copyright : (c) Simon Marlow, Sven Panne 1997-2000 > -- License : BSD-style (see the file libraries/base/LICENSE) > -- > -- Maintainer : libraries@haskell.org > -- Stability : experimental > -- Portability : portable > -- > -- Haskell parser. > -- > ----------------------------------------------------------------------------- > > module Language.Haskell.Parser ( > parseModule, parseModuleWithMode, > ParseMode(..), defaultParseMode, ParseResult(..)) where > > import Language.Haskell.Syntax > import Language.Haskell.ParseMonad > import Language.Haskell.Lexer > import Language.Haskell.ParseUtils > } ToDo: Check exactly which names must be qualified with Prelude (commas and friends) ToDo: Inst (MPCs?) ToDo: Polish constr a bit ToDo: Ugly: exp0b is used for lhs, pat, exp0, ... ToDo: Differentiate between record updates and labeled construction. ----------------------------------------------------------------------------- Conflicts: 2 shift/reduce 2 for ambiguity in 'case x of y | let z = y in z :: Bool -> b' (don't know whether to reduce 'Bool' as a btype or shift the '->'. Similarly lambda and if. The default resolution in favour of the shift means that a guard can never end with a type signature. In mitigation: it's a rare case and no Haskell implementation allows these, because it would require unbounded lookahead.) There are 2 conflicts rather than one because contexts are parsed as btypes (cf ctype). ----------------------------------------------------------------------------- > %token > VARID { VarId $$ } > QVARID { QVarId $$ } > CONID { ConId $$ } > QCONID { QConId $$ } > VARSYM { VarSym $$ } > CONSYM { ConSym $$ } > QVARSYM { QVarSym $$ } > QCONSYM { QConSym $$ } > INT { IntTok $$ } > RATIONAL { FloatTok $$ } > CHAR { Character $$ } > STRING { StringTok $$ } Symbols > '(' { LeftParen } > ')' { RightParen } > ';' { SemiColon } > '{' { LeftCurly } > '}' { RightCurly } > vccurly { VRightCurly } -- a virtual close brace > '[' { LeftSquare } > ']' { RightSquare } > ',' { Comma } > '_' { Underscore } > '`' { BackQuote } Reserved operators > '..' { DotDot } > ':' { Colon } > '::' { DoubleColon } > '=' { Equals } > '\\' { Backslash } > '|' { Bar } > '<-' { LeftArrow } > '->' { RightArrow } > '@' { At } > '~' { Tilde } > '=>' { DoubleArrow } > '-' { Minus } > '!' { Exclamation } Reserved Ids > 'case' { KW_Case } > 'class' { KW_Class } > 'data' { KW_Data } > 'default' { KW_Default } > 'deriving' { KW_Deriving } > 'do' { KW_Do } > 'else' { KW_Else } > 'foreign' { KW_Foreign } > 'if' { KW_If } > 'import' { KW_Import } > 'in' { KW_In } > 'infix' { KW_Infix } > 'infixl' { KW_InfixL } > 'infixr' { KW_InfixR } > 'instance' { KW_Instance } > 'let' { KW_Let } > 'module' { KW_Module } > 'newtype' { KW_NewType } > 'of' { KW_Of } > 'then' { KW_Then } > 'type' { KW_Type } > 'where' { KW_Where } Special Ids > 'as' { KW_As } > 'export' { KW_Export } > 'hiding' { KW_Hiding } > 'qualified' { KW_Qualified } > 'safe' { KW_Safe } > 'unsafe' { KW_Unsafe } > %monad { P } > %lexer { lexer } { EOF } > %name parse > %tokentype { Token } > %% ----------------------------------------------------------------------------- Module Header > module :: { HsModule } > : srcloc 'module' modid maybeexports 'where' body > { HsModule $1 $3 $4 (fst $6) (snd $6) } > | srcloc body > { HsModule $1 main_mod (Just [HsEVar (UnQual main_name)]) > (fst $2) (snd $2) } > body :: { ([HsImportDecl],[HsDecl]) } > : '{' bodyaux '}' { $2 } > | open bodyaux close { $2 } > bodyaux :: { ([HsImportDecl],[HsDecl]) } > : optsemis impdecls semis topdecls { (reverse $2, $4) } > | optsemis topdecls { ([], $2) } > | optsemis impdecls optsemis { (reverse $2, []) } > | optsemis { ([], []) } > semis :: { () } > : optsemis ';' { () } > optsemis :: { () } > : semis { () } > | {- empty -} { () } ----------------------------------------------------------------------------- The Export List > maybeexports :: { Maybe [HsExportSpec] } > : exports { Just $1 } > | {- empty -} { Nothing } > exports :: { [HsExportSpec] } > : '(' exportlist optcomma ')' { reverse $2 } > | '(' optcomma ')' { [] } > optcomma :: { () } > : ',' { () } > | {- empty -} { () } > exportlist :: { [HsExportSpec] } > : exportlist ',' export { $3 : $1 } > | export { [$1] } > export :: { HsExportSpec } > : qvar { HsEVar $1 } > | qtyconorcls { HsEAbs $1 } > | qtyconorcls '(' '..' ')' { HsEThingAll $1 } > | qtyconorcls '(' ')' { HsEThingWith $1 [] } > | qtyconorcls '(' cnames ')' { HsEThingWith $1 (reverse $3) } > | 'module' modid { HsEModuleContents $2 } ----------------------------------------------------------------------------- Import Declarations > impdecls :: { [HsImportDecl] } > : impdecls semis impdecl { $3 : $1 } > | impdecl { [$1] } > impdecl :: { HsImportDecl } > : srcloc 'import' optqualified modid maybeas maybeimpspec > { HsImportDecl $1 $4 $3 $5 $6 } > optqualified :: { Bool } > : 'qualified' { True } > | {- empty -} { False } > maybeas :: { Maybe Module } > : 'as' modid { Just $2 } > | {- empty -} { Nothing } > maybeimpspec :: { Maybe (Bool, [HsImportSpec]) } > : impspec { Just $1 } > | {- empty -} { Nothing } > impspec :: { (Bool, [HsImportSpec]) } > : opthiding '(' importlist optcomma ')' { ($1, reverse $3) } > | opthiding '(' optcomma ')' { ($1, []) } > opthiding :: { Bool } > : 'hiding' { True } > | {- empty -} { False } > importlist :: { [HsImportSpec] } > : importlist ',' importspec { $3 : $1 } > | importspec { [$1] } > importspec :: { HsImportSpec } > : var { HsIVar $1 } > | tyconorcls { HsIAbs $1 } > | tyconorcls '(' '..' ')' { HsIThingAll $1 } > | tyconorcls '(' ')' { HsIThingWith $1 [] } > | tyconorcls '(' cnames ')' { HsIThingWith $1 (reverse $3) } > cnames :: { [HsCName] } > : cnames ',' cname { $3 : $1 } > | cname { [$1] } > cname :: { HsCName } > : var { HsVarName $1 } > | con { HsConName $1 } ----------------------------------------------------------------------------- Fixity Declarations > fixdecl :: { HsDecl } > : srcloc infix prec ops { HsInfixDecl $1 $2 $3 (reverse $4) } > prec :: { Int } > : {- empty -} { 9 } > | INT {% checkPrec $1 } > infix :: { HsAssoc } > : 'infix' { HsAssocNone } > | 'infixl' { HsAssocLeft } > | 'infixr' { HsAssocRight } > ops :: { [HsOp] } > : ops ',' op { $3 : $1 } > | op { [$1] } ----------------------------------------------------------------------------- Top-Level Declarations Note: The report allows topdecls to be empty. This would result in another shift/reduce-conflict, so we don't handle this case here, but in bodyaux. > topdecls :: { [HsDecl] } > : topdecls1 optsemis {% checkRevDecls $1 } > topdecls1 :: { [HsDecl] } > : topdecls1 semis topdecl { $3 : $1 } > | topdecl { [$1] } > topdecl :: { HsDecl } > : srcloc 'type' simpletype '=' type > { HsTypeDecl $1 (fst $3) (snd $3) $5 } > | srcloc 'data' ctype '=' constrs deriving > {% do { (cs,c,t) <- checkDataHeader $3; > return (HsDataDecl $1 cs c t (reverse $5) $6) } } > | srcloc 'newtype' ctype '=' constr deriving > {% do { (cs,c,t) <- checkDataHeader $3; > return (HsNewTypeDecl $1 cs c t $5 $6) } } > | srcloc 'class' ctype optcbody > {% do { (cs,c,vs) <- checkClassHeader $3; > return (HsClassDecl $1 cs c vs $4) } } > | srcloc 'instance' ctype optvaldefs > {% do { (cs,c,ts) <- checkInstHeader $3; > return (HsInstDecl $1 cs c ts $4) } } > | srcloc 'default' '(' typelist ')' > { HsDefaultDecl $1 $4 } > | foreigndecl { $1 } > | decl { $1 } > typelist :: { [HsType] } > : types { reverse $1 } > | type { [$1] } > | {- empty -} { [] } > decls :: { [HsDecl] } > : optsemis decls1 optsemis {% checkRevDecls $2 } > | optsemis { [] } > decls1 :: { [HsDecl] } > : decls1 semis decl { $3 : $1 } > | decl { [$1] } > decl :: { HsDecl } > : signdecl { $1 } > | fixdecl { $1 } > | valdef { $1 } > decllist :: { [HsDecl] } > : '{' decls '}' { $2 } > | open decls close { $2 } > signdecl :: { HsDecl } > : srcloc vars '::' ctype { HsTypeSig $1 (reverse $2) $4 } ATTENTION: Dirty Hackery Ahead! If the second alternative of vars is var instead of qvar, we get another shift/reduce-conflict. Consider the following programs: { (+) :: ... } only var { (+) x y = ... } could (incorrectly) be qvar We re-use expressions for patterns, so a qvar would be allowed in patterns instead of a var only (which would be correct). But deciding what the + is, would require more lookahead. So let's check for ourselves... > vars :: { [HsName] } > : vars ',' var { $3 : $1 } > | qvar {% do { n <- checkUnQual $1; > return [n] } } Foreign declarations - calling conventions are uninterpreted - external entities are not parsed - special ids are not allowed as internal names > foreigndecl :: { HsDecl } > : srcloc 'foreign' 'import' VARID optsafety optentity fvar '::' type > { HsForeignImport $1 $4 $5 $6 $7 $9 } > | srcloc 'foreign' 'export' VARID optentity fvar '::' type > { HsForeignExport $1 $4 $5 $6 $8 } > optsafety :: { HsSafety } > : 'safe' { HsSafe } > | 'unsafe' { HsUnsafe } > | {- empty -} { HsSafe } > optentity :: { String } > : STRING { $1 } > | {- empty -} { "" } > fvar :: { HsName } > : VARID { HsIdent $1 } > | '(' varsym ')' { $2 } ----------------------------------------------------------------------------- Types > type :: { HsType } > : btype '->' type { HsTyFun $1 $3 } > | btype { $1 } > btype :: { HsType } > : btype atype { HsTyApp $1 $2 } > | atype { $1 } > atype :: { HsType } > : gtycon { HsTyCon $1 } > | tyvar { HsTyVar $1 } > | '(' types ')' { HsTyTuple (reverse $2) } > | '[' type ']' { HsTyApp list_tycon $2 } > | '(' type ')' { $2 } > gtycon :: { HsQName } > : qconid { $1 } > | '(' ')' { unit_tycon_name } > | '(' '->' ')' { fun_tycon_name } > | '[' ']' { list_tycon_name } > | '(' commas ')' { tuple_tycon_name $2 } (Slightly edited) Comment from GHC's hsparser.y: "context => type" vs "type" 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 parse the context as a btype (more specifically as a tuple type), then check that it has the right form C a, or (C1 a, C2 b, ... Cn z) and convert it into a context. Blaach! > ctype :: { HsQualType } > : context '=>' type { HsQualType $1 $3 } > | type { HsQualType [] $1 } > context :: { HsContext } > : btype {% checkContext $1 } > types :: { [HsType] } > : types ',' type { $3 : $1 } > | type ',' type { [$3, $1] } > simpletype :: { (HsName, [HsName]) } > : tycon tyvars { ($1,reverse $2) } > tyvars :: { [HsName] } > : tyvars tyvar { $2 : $1 } > | {- empty -} { [] } ----------------------------------------------------------------------------- Datatype declarations > constrs :: { [HsConDecl] } > : constrs '|' constr { $3 : $1 } > | constr { [$1] } > constr :: { HsConDecl } > : srcloc scontype { HsConDecl $1 (fst $2) (snd $2) } > | srcloc sbtype conop sbtype { HsConDecl $1 $3 [$2,$4] } > | srcloc con '{' '}' { HsRecDecl $1 $2 [] } > | srcloc con '{' fielddecls '}' { HsRecDecl $1 $2 (reverse $4) } > scontype :: { (HsName, [HsBangType]) } > : btype {% do { (c,ts) <- splitTyConApp $1; > return (c,map HsUnBangedTy ts) } } > | scontype1 { $1 } > scontype1 :: { (HsName, [HsBangType]) } > : btype '!' atype {% do { (c,ts) <- splitTyConApp $1; > return (c,map HsUnBangedTy ts++ > [HsBangedTy $3]) } } > | scontype1 satype { (fst $1, snd $1 ++ [$2] ) } > satype :: { HsBangType } > : atype { HsUnBangedTy $1 } > | '!' atype { HsBangedTy $2 } > sbtype :: { HsBangType } > : btype { HsUnBangedTy $1 } > | '!' atype { HsBangedTy $2 } > fielddecls :: { [([HsName],HsBangType)] } > : fielddecls ',' fielddecl { $3 : $1 } > | fielddecl { [$1] } > fielddecl :: { ([HsName],HsBangType) } > : vars '::' stype { (reverse $1, $3) } > stype :: { HsBangType } > : type { HsUnBangedTy $1 } > | '!' atype { HsBangedTy $2 } > deriving :: { [HsQName] } > : {- empty -} { [] } > | 'deriving' qtycls { [$2] } > | 'deriving' '(' ')' { [] } > | 'deriving' '(' dclasses ')' { reverse $3 } > dclasses :: { [HsQName] } > : dclasses ',' qtycls { $3 : $1 } > | qtycls { [$1] } ----------------------------------------------------------------------------- Class declarations > optcbody :: { [HsDecl] } > : 'where' decllist {% checkClassBody $2 } > | {- empty -} { [] } ----------------------------------------------------------------------------- Instance declarations > optvaldefs :: { [HsDecl] } > : 'where' '{' valdefs '}' {% checkClassBody $3 } > | 'where' open valdefs close {% checkClassBody $3 } > | {- empty -} { [] } > valdefs :: { [HsDecl] } > : optsemis valdefs1 optsemis {% checkRevDecls $2 } > | optsemis { [] } > valdefs1 :: { [HsDecl] } > : valdefs1 semis valdef { $3 : $1 } > | valdef { [$1] } ----------------------------------------------------------------------------- Value definitions > valdef :: { HsDecl } > : srcloc exp0b rhs optwhere {% checkValDef $1 $2 $3 $4 } > optwhere :: { [HsDecl] } > : 'where' decllist { $2 } > | {- empty -} { [] } > rhs :: { HsRhs } > : '=' exp {% do { e <- checkExpr $2; > return (HsUnGuardedRhs e) } } > | gdrhs { HsGuardedRhss (reverse $1) } > gdrhs :: { [HsGuardedRhs] } > : gdrhs gdrh { $2 : $1 } > | gdrh { [$1] } > gdrh :: { HsGuardedRhs } > : srcloc '|' exp0 '=' exp {% do { g <- checkExpr $3; > e <- checkExpr $5; > return (HsGuardedRhs $1 g e) } } ----------------------------------------------------------------------------- Expressions Note: The Report specifies a meta-rule for lambda, let and if expressions (the exp's that end with a subordinate exp): they extend as far to the right as possible. That means they cannot be followed by a type signature or infix application. To implement this without shift/reduce conflicts, we split exp10 into these expressions (exp10a) and the others (exp10b). That also means that only an exp0 ending in an exp10b (an exp0b) can followed by a type signature or infix application. So we duplicate the exp0 productions to distinguish these from the others (exp0a). > exp :: { HsExp } > : exp0b '::' srcloc ctype { HsExpTypeSig $3 $1 $4 } > | exp0 { $1 } > exp0 :: { HsExp } > : exp0a { $1 } > | exp0b { $1 } > exp0a :: { HsExp } > : exp0b qop exp10a { HsInfixApp $1 $2 $3 } > | exp10a { $1 } > exp0b :: { HsExp } > : exp0b qop exp10b { HsInfixApp $1 $2 $3 } > | exp10b { $1 } > exp10a :: { HsExp } > : '\\' srcloc apats '->' exp { HsLambda $2 (reverse $3) $5 } > | 'let' decllist 'in' exp { HsLet $2 $4 } > | 'if' exp 'then' exp 'else' exp { HsIf $2 $4 $6 } > exp10b :: { HsExp } > : 'case' exp 'of' altslist { HsCase $2 $4 } > | '-' fexp { HsNegApp $2 } > | 'do' stmtlist { HsDo $2 } > | fexp { $1 } > fexp :: { HsExp } > : fexp aexp { HsApp $1 $2 } > | aexp { $1 } > apats :: { [HsPat] } > : apats apat { $2 : $1 } > | apat { [$1] } > apat :: { HsPat } > : aexp {% checkPattern $1 } UGLY: Because patterns and expressions are mixed, aexp has to be split into two rules: One right-recursive and one left-recursive. Otherwise we get two reduce/reduce-errors (for as-patterns and irrefutable patters). Even though the variable in an as-pattern cannot be qualified, we use qvar here to avoid a shift/reduce conflict, and then check it ourselves (as for vars above). > aexp :: { HsExp } > : qvar '@' aexp {% do { n <- checkUnQual $1; > return (HsAsPat n $3) } } > | '~' aexp { HsIrrPat $2 } > | aexp1 { $1 } Note: The first two alternatives of aexp1 are not necessarily record updates: they could be labeled constructions. > aexp1 :: { HsExp } > : aexp1 '{' '}' {% mkRecConstrOrUpdate $1 [] } > | aexp1 '{' fbinds '}' {% mkRecConstrOrUpdate $1 (reverse $3) } > | aexp2 { $1 } According to the Report, the left section (e op) is legal iff (e op x) parses equivalently to ((e) op x). Thus e must be an exp0b. > aexp2 :: { HsExp } > : qvar { HsVar $1 } > | gcon { $1 } > | literal { HsLit $1 } > | '(' exp ')' { HsParen $2 } > | '(' texps ')' { HsTuple (reverse $2) } > | '[' list ']' { $2 } > | '(' exp0b qop ')' { HsLeftSection $2 $3 } > | '(' qopm exp0 ')' { HsRightSection $2 $3 } > | '_' { HsWildCard } > commas :: { Int } > : commas ',' { $1 + 1 } > | ',' { 1 } > texps :: { [HsExp] } > : texps ',' exp { $3 : $1 } > | exp ',' exp { [$3,$1] } ----------------------------------------------------------------------------- List expressions The rules below are little bit contorted to keep lexps left-recursive while avoiding another shift/reduce-conflict. > list :: { HsExp } > : exp { HsList [$1] } > | lexps { HsList (reverse $1) } > | exp '..' { HsEnumFrom $1 } > | exp ',' exp '..' { HsEnumFromThen $1 $3 } > | exp '..' exp { HsEnumFromTo $1 $3 } > | exp ',' exp '..' exp { HsEnumFromThenTo $1 $3 $5 } > | exp '|' quals { HsListComp $1 (reverse $3) } > lexps :: { [HsExp] } > : lexps ',' exp { $3 : $1 } > | exp ',' exp { [$3,$1] } ----------------------------------------------------------------------------- List comprehensions > quals :: { [HsStmt] } > : quals ',' qual { $3 : $1 } > | qual { [$1] } > qual :: { HsStmt } > : pat srcloc '<-' exp { HsGenerator $2 $1 $4 } > | exp { HsQualifier $1 } > | 'let' decllist { HsLetStmt $2 } ----------------------------------------------------------------------------- Case alternatives > altslist :: { [HsAlt] } > : '{' alts '}' { $2 } > | open alts close { $2 } > alts :: { [HsAlt] } > : optsemis alts1 optsemis { reverse $2 } > alts1 :: { [HsAlt] } > : alts1 semis alt { $3 : $1 } > | alt { [$1] } > alt :: { HsAlt } > : srcloc pat ralt optwhere { HsAlt $1 $2 $3 $4 } > ralt :: { HsGuardedAlts } > : '->' exp { HsUnGuardedAlt $2 } > | gdpats { HsGuardedAlts (reverse $1) } > gdpats :: { [HsGuardedAlt] } > : gdpats gdpat { $2 : $1 } > | gdpat { [$1] } > gdpat :: { HsGuardedAlt } > : srcloc '|' exp0 '->' exp { HsGuardedAlt $1 $3 $5 } > pat :: { HsPat } > : exp0b {% checkPattern $1 } ----------------------------------------------------------------------------- Statement sequences As per the Report, but with stmt expanded to simplify building the list without introducing conflicts. This also ensures that the last stmt is an expression. > stmtlist :: { [HsStmt] } > : '{' stmts '}' { $2 } > | open stmts close { $2 } > stmts :: { [HsStmt] } > : 'let' decllist ';' stmts { HsLetStmt $2 : $4 } > | pat srcloc '<-' exp ';' stmts { HsGenerator $2 $1 $4 : $6 } > | exp ';' stmts { HsQualifier $1 : $3 } > | ';' stmts { $2 } > | exp ';' { [HsQualifier $1] } > | exp { [HsQualifier $1] } ----------------------------------------------------------------------------- Record Field Update/Construction > fbinds :: { [HsFieldUpdate] } > : fbinds ',' fbind { $3 : $1 } > | fbind { [$1] } > fbind :: { HsFieldUpdate } > : qvar '=' exp { HsFieldUpdate $1 $3 } ----------------------------------------------------------------------------- Variables, Constructors and Operators. > gcon :: { HsExp } > : '(' ')' { unit_con } > | '[' ']' { HsList [] } > | '(' commas ')' { tuple_con $2 } > | qcon { HsCon $1 } > var :: { HsName } > : varid { $1 } > | '(' varsym ')' { $2 } > qvar :: { HsQName } > : qvarid { $1 } > | '(' qvarsym ')' { $2 } > con :: { HsName } > : conid { $1 } > | '(' consym ')' { $2 } > qcon :: { HsQName } > : qconid { $1 } > | '(' gconsym ')' { $2 } > varop :: { HsName } > : varsym { $1 } > | '`' varid '`' { $2 } > qvarop :: { HsQName } > : qvarsym { $1 } > | '`' qvarid '`' { $2 } > qvaropm :: { HsQName } > : qvarsymm { $1 } > | '`' qvarid '`' { $2 } > conop :: { HsName } > : consym { $1 } > | '`' conid '`' { $2 } > qconop :: { HsQName } > : gconsym { $1 } > | '`' qconid '`' { $2 } > op :: { HsOp } > : varop { HsVarOp $1 } > | conop { HsConOp $1 } > qop :: { HsQOp } > : qvarop { HsQVarOp $1 } > | qconop { HsQConOp $1 } > qopm :: { HsQOp } > : qvaropm { HsQVarOp $1 } > | qconop { HsQConOp $1 } > gconsym :: { HsQName } > : ':' { list_cons_name } > | qconsym { $1 } ----------------------------------------------------------------------------- Identifiers and Symbols > qvarid :: { HsQName } > : varid { UnQual $1 } > | QVARID { Qual (Module (fst $1)) (HsIdent (snd $1)) } > varid :: { HsName } > : VARID { HsIdent $1 } > | 'as' { HsIdent "as" } > | 'export' { HsIdent "export" } > | 'hiding' { HsIdent "hiding" } > | 'qualified' { HsIdent "qualified" } > | 'safe' { HsIdent "safe" } > | 'unsafe' { HsIdent "unsafe" } > qconid :: { HsQName } > : conid { UnQual $1 } > | QCONID { Qual (Module (fst $1)) (HsIdent (snd $1)) } > conid :: { HsName } > : CONID { HsIdent $1 } > qconsym :: { HsQName } > : consym { UnQual $1 } > | QCONSYM { Qual (Module (fst $1)) (HsSymbol (snd $1)) } > consym :: { HsName } > : CONSYM { HsSymbol $1 } > qvarsym :: { HsQName } > : varsym { UnQual $1 } > | qvarsym1 { $1 } > qvarsymm :: { HsQName } > : varsymm { UnQual $1 } > | qvarsym1 { $1 } > varsym :: { HsName } > : VARSYM { HsSymbol $1 } > | '-' { HsSymbol "-" } > | '!' { HsSymbol "!" } > varsymm :: { HsName } -- varsym not including '-' > : VARSYM { HsSymbol $1 } > | '!' { HsSymbol "!" } > qvarsym1 :: { HsQName } > : QVARSYM { Qual (Module (fst $1)) (HsSymbol (snd $1)) } > literal :: { HsLiteral } > : INT { HsInt $1 } > | CHAR { HsChar $1 } > | RATIONAL { HsFrac $1 } > | STRING { HsString $1 } > srcloc :: { SrcLoc } : {% getSrcLoc } ----------------------------------------------------------------------------- Layout > open :: { () } : {% pushCurrentContext } > close :: { () } > : vccurly { () } -- context popped in lexer. > | error {% popContext } ----------------------------------------------------------------------------- Miscellaneous (mostly renamings) > modid :: { Module } > : CONID { Module $1 } > | QCONID { Module (fst $1 ++ '.':snd $1) } > tyconorcls :: { HsName } > : conid { $1 } > tycon :: { HsName } > : conid { $1 } > qtyconorcls :: { HsQName } > : qconid { $1 } > qtycls :: { HsQName } > : qconid { $1 } > tyvar :: { HsName } > : varid { $1 } ----------------------------------------------------------------------------- > { > happyError :: P a > happyError = fail "Parse error" > -- | Parse of a string, which should contain a complete Haskell 98 module. > parseModule :: String -> ParseResult HsModule > parseModule = runParser parse > -- | Parse of a string, which should contain a complete Haskell 98 module. > parseModuleWithMode :: ParseMode -> String -> ParseResult HsModule > parseModuleWithMode mode = runParserWithMode mode parse > }