summaryrefslogtreecommitdiff
path: root/compiler/parser/ExpPatFrame.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/parser/ExpPatFrame.hs')
-rw-r--r--compiler/parser/ExpPatFrame.hs340
1 files changed, 340 insertions, 0 deletions
diff --git a/compiler/parser/ExpPatFrame.hs b/compiler/parser/ExpPatFrame.hs
new file mode 100644
index 0000000000..e24cd560a2
--- /dev/null
+++ b/compiler/parser/ExpPatFrame.hs
@@ -0,0 +1,340 @@
+{-# LANGUAGE ViewPatterns #-}
+
+module ExpPatFrame (
+
+ -- * The expression/pattern frame
+ ExpPatFrame(..),
+ LExpPatFrame,
+
+ -- * Tuple elements
+ TupArgFrame(..),
+ LTupArgFrame,
+
+ -- * Record elements
+ FrameRecordBinds,
+ FrameRecUpdField,
+ LFrameRecUpdField,
+
+ -- * Match elements
+ FrameMatch(..),
+ LFrameMatch,
+ FrameGRHSs(..),
+ FrameGRHS(..),
+ LFrameGRHS,
+
+ -- * Statements
+ FrameStmt(..),
+ LFrameStmt,
+
+ -- * Conversion
+ fromTupArgPresent,
+ checkExpr,
+ checkExprStmt,
+ checkExprMatch,
+ checkExprGRHSs,
+ checkExprGRHS,
+
+ -- * Construction
+ unguardedFrameRHS
+
+ ) where
+
+import GhcPrelude
+import FastString
+import Outputable
+import SrcLoc
+import Name
+import RdrName
+import BasicTypes
+import HsSyn
+
+type LExpPatFrame = Located ExpPatFrame
+
+{-
+
+There are places in the grammar where we do not know whether we are parsing an
+expression or a pattern without infinite lookahead (which we do not have in
+'happy'):
+
+1. View patterns:
+ f (Con a b ) = ... -- 'Con a b' is a pattern
+ f (Con a b -> x) = ... -- 'Con a b' is an expression
+
+2. do-notation:
+ do { Con a b <- x } -- 'Con a b' is a pattern
+ do { Con a b } -- 'Con a b' is an expression
+
+3. Guards:
+ x | True <- p && q = ... -- 'True' is a pattern
+ x | True = ... -- 'True' is an expression
+
+4. Top-level value/function declarations (FunBind/PatBind):
+ f !a -- TH splice
+ f !a = ... -- function declaration
+ Until we encounter the = sign, we don't know if it's a top-level
+ TemplateHaskell splice where ! is an infix operator, or if it's a function
+ declaration where ! is a strictness annotation.
+
+An ExpPatFrame (expression/pattern frame) is an intermediate data structure for
+parsing expressions and patterns. We convert to HsExpr or HsPat when we can
+resolve the ambiguity.
+
+See https://ghc.haskell.org/trac/ghc/wiki/Design/ExpPatFrame for details.
+
+-}
+data ExpPatFrame
+ = FrameVar RdrName
+ -- ^ Identifier: Just, map, BS.length
+ | FrameIPVar HsIPName
+ -- ^ Implicit parameter: ?x
+ | FrameOverLabel FastString
+ -- ^ Overloaded label: #label
+ | FrameLit (HsLit GhcPs)
+ -- ^ Non-overloaded literal: 'c', "str"
+ | FrameOverLit (HsOverLit GhcPs)
+ -- ^ Overloaded literal: 15, 2.4
+ | FramePar LExpPatFrame
+ -- ^ Parentheses
+ | FrameSum ConTag Arity LExpPatFrame
+ -- ^ Sum: (a||), (|a|), (||a)
+ | FrameTuple [LTupArgFrame] Boxity
+ -- ^ Tuple (section): (a,b) (a,b,c) (a,,) (,a,)
+ | FrameList [LExpPatFrame]
+ -- ^ List: [1, 2, 3]
+ | FrameComp (HsStmtContext Name) [LFrameStmt] LExpPatFrame
+ -- ^ List/monad comprehension: [ a | x <- f n, p, q ]
+ | FrameArithSeq (ArithSeqInfo GhcPs)
+ -- ^ Arithmetic sequence: [1..], [1,2..], [1..5]
+ | FrameWild
+ -- ^ Wildcard: _
+ | FrameSplice (HsSplice GhcPs)
+ -- ^ TH splice: $a, $(expr), $$(expr), [quasi| ... |]
+ | FrameBracket (HsBracket GhcPs)
+ -- ^ TH bracket: [|expr|], [p|pat|], 'x, ''T
+ | FrameArrForm LExpPatFrame [LHsCmdTop GhcPs]
+ -- ^ Command formation (arrows): (| e cmd1 cmd2 cmd3 |)
+ | FrameRecordUpd LExpPatFrame [LFrameRecUpdField]
+ -- ^ Record update: (f x) { a = z }
+ | FrameRecordCon (Located RdrName) FrameRecordBinds
+ -- ^ Record constructor: D { x, y = f t, .. }
+ | FrameAsPat (Located RdrName) LExpPatFrame
+ -- ^ As-pattern: x@(D a b)
+ | FrameLam [LPat GhcPs] LExpPatFrame
+ -- ^ Lambda-expression: \x -> e
+ | FrameLet (LHsLocalBinds GhcPs) LExpPatFrame
+ -- ^ Let-expression: let p = t in e
+ | FrameLamCase [LFrameMatch]
+ -- ^ Lambda-expression: \x -> e
+ | FrameIf LExpPatFrame LExpPatFrame LExpPatFrame
+ -- ^ If-expression: if p then x else y
+ | FrameMultiIf [LFrameGRHS]
+ -- ^ Multi-way if-expression: if | p = x \n | q = x
+ | FrameCase LExpPatFrame [LFrameMatch]
+ -- ^ Case-expression: case x of { p1 -> e1; p2 -> e2 }
+ | FrameDo (HsStmtContext Name) [LFrameStmt]
+ -- ^ Do-expression: do { s1; a <- s2; s3 }
+ | FrameProc (LPat GhcPs) (LHsCmdTop GhcPs)
+ -- ^ Proc-expression: proc p -> cmd
+ | FrameViewPat LExpPatFrame LExpPatFrame
+ -- ^ View pattern: e -> p
+ | FrameTySig LExpPatFrame (LHsSigWcType GhcPs)
+ -- ^ Type signature: x :: ty
+ | FrameArrApp LExpPatFrame LExpPatFrame HsArrAppType Bool
+ -- ^ Arrow application: f -< arg, f -<< arg, arg >- f, arg >>- f
+ | FrameSCC SourceText StringLiteral LExpPatFrame
+ -- ^ SCC annotation: {-# SCC .. #-} e
+ | FrameTickPragma
+ SourceText
+ (StringLiteral,(Int,Int),(Int,Int))
+ ((SourceText,SourceText),(SourceText,SourceText))
+ LExpPatFrame
+ -- ^ Tick pragma: {-# GENERATED .. #-} e
+ | FrameCoreAnn SourceText StringLiteral LExpPatFrame
+ -- ^ Core annotation: {-# CORE .. #-} e
+ | FrameApp LExpPatFrame LExpPatFrame
+ -- ^ Function application: f a
+ | FrameAppType LExpPatFrame (LHsWcType GhcPs)
+ -- ^ Visible type application: f @t
+ | FrameOpApp LExpPatFrame LExpPatFrame LExpPatFrame
+ -- ^ Operator application: x # y
+ | FrameSectionL LExpPatFrame LExpPatFrame
+ -- ^ Left section: (x #)
+ | FrameSectionR LExpPatFrame LExpPatFrame
+ -- ^ Right section: (# y)
+ | FrameNegApp LExpPatFrame
+ -- ^ Prefix negation: -a
+ | FrameLazyPat LExpPatFrame
+ -- ^ Lazy pattern: ~a
+ | FrameStatic LExpPatFrame
+ -- ^ Static expression: static e
+
+instance Outputable ExpPatFrame where
+ ppr = ppr . unLoc . checkExpr . noLoc
+
+type FrameRecordBinds = HsRecFields GhcPs LExpPatFrame
+type FrameRecUpdField = HsRecField' (AmbiguousFieldOcc GhcPs) LExpPatFrame
+type LFrameRecUpdField = Located FrameRecUpdField
+
+type LTupArgFrame = Located TupArgFrame
+
+data TupArgFrame
+ = TupArgFramePresent LExpPatFrame
+ | TupArgFrameMissing
+
+fromTupArgPresent :: TupArgFrame -> Maybe LExpPatFrame
+fromTupArgPresent (TupArgFramePresent e) = Just e
+fromTupArgPresent TupArgFrameMissing = Nothing
+
+type LFrameMatch = Located FrameMatch
+
+data FrameMatch =
+ FrameMatch (HsMatchContext RdrName) [LPat GhcPs] FrameGRHSs
+
+type LFrameStmt = Located FrameStmt
+
+data FrameGRHSs =
+ FrameGRHSs [LFrameGRHS] (LHsLocalBinds GhcPs)
+
+type LFrameGRHS = Located FrameGRHS
+
+data FrameGRHS = FrameGRHS [GuardLStmt GhcPs] LExpPatFrame
+
+data FrameStmt
+ = FrameTransformStmt [LFrameStmt] LExpPatFrame
+ -- ^ TransformListComp statement: then f
+ | FrameTransformByStmt [LFrameStmt] LExpPatFrame LExpPatFrame
+ -- ^ TransformListComp statement: then f by e
+ | FrameGroupUsingStmt [LFrameStmt] LExpPatFrame
+ -- ^ TransformListComp statement: then group using f
+ | FrameGroupByUsingStmt [LFrameStmt] LExpPatFrame LExpPatFrame
+ -- ^ TransformListComp statement: then group by e using f
+ | FrameBindStmt (LPat GhcPs) LExpPatFrame
+ -- ^ Binding statement: p <- e
+ | FrameBodyStmt LExpPatFrame
+ -- ^ Body statement: e
+ | FrameLetStmt (LHsLocalBinds GhcPs)
+ -- ^ Let statement: let p = t
+ | FrameRecStmt [LFrameStmt]
+ -- ^ Rec statement: rec { s1; s2; ... }
+ | FrameParStmt [[LFrameStmt]]
+ -- ^ Parallel statement: s1 | s2
+
+instance Outputable FrameStmt where
+ ppr = ppr . unLoc . checkExprStmt . noLoc
+
+{-
+
+Convert an expression/pattern frame to an expression. In the future, this
+function will perform validation and reject FrameAsPat, FrameViewPat,
+FrameLazyPat, and so on:
+
+ checkExpr :: LExpPatFrame -> P (LHsExpr GhcPs)
+
+-}
+checkExpr :: LExpPatFrame -> LHsExpr GhcPs
+checkExpr (dL->L l epf) = cL l $ case epf of
+ FrameVar name -> HsVar noExt (cL l name)
+ FrameIPVar ipname -> HsIPVar noExt ipname
+ FrameOverLabel str -> HsOverLabel noExt Nothing str
+ FrameLit lit -> HsLit noExt lit
+ FrameOverLit lit -> HsOverLit noExt lit
+ FramePar e -> HsPar noExt (checkExpr e)
+ FrameSum alt arity e -> ExplicitSum noExt alt arity (checkExpr e)
+ FrameTuple args boxity ->
+ ExplicitTuple noExt (map checkExprTupArg args) boxity
+ FrameList xs -> ExplicitList noExt Nothing (map checkExpr xs)
+ FrameComp ctxt quals e ->
+ mkHsComp ctxt (map checkExprStmt quals) (checkExpr e)
+ FrameArithSeq a -> ArithSeq noExt Nothing a
+ FrameWild -> EWildPat noExt
+ FrameSplice splice -> HsSpliceE noExt splice
+ FrameBracket br -> HsBracket noExt br
+ FrameArrForm op cmds -> HsArrForm noExt (checkExpr op) Nothing cmds
+ FrameRecordUpd exp flds ->
+ RecordUpd noExt (checkExpr exp) ((fmap.fmap.fmap) checkExpr flds)
+ FrameRecordCon con flds -> RecordCon noExt con (fmap checkExpr flds)
+ FrameAsPat v e -> EAsPat noExt v (checkExpr e)
+ FrameLam ps e ->
+ HsLam noExt $
+ mkMatchGroup FromSource
+ [cL l $ Match { m_ext = noExt
+ , m_ctxt = LambdaExpr
+ , m_pats = ps
+ , m_grhss = unguardedGRHSs (checkExpr e) }]
+ FrameLet binds expr -> HsLet noExt binds (checkExpr expr)
+ FrameLamCase matches ->
+ HsLamCase noExt $
+ mkMatchGroup FromSource (map checkExprMatch matches)
+ FrameIf c a b -> mkHsIf (checkExpr c) (checkExpr a) (checkExpr b)
+ FrameMultiIf alts -> HsMultiIf noExt (map checkExprGRHS alts)
+ FrameCase scrut matches ->
+ HsCase noExt (checkExpr scrut) $
+ mkMatchGroup FromSource (map checkExprMatch matches)
+ FrameDo ctxt stmts -> mkHsDo ctxt (map checkExprStmt stmts)
+ FrameProc pat cmd -> HsProc noExt pat cmd
+ FrameViewPat p e -> EViewPat noExt (checkExpr p) (checkExpr e)
+ FrameTySig e sig -> ExprWithTySig noExt (checkExpr e) sig
+ FrameArrApp f a haat b ->
+ HsArrApp noExt (checkExpr f) (checkExpr a) haat b
+ FrameSCC src lbl e -> HsSCC noExt src lbl (checkExpr e)
+ FrameTickPragma src info srcInfo e ->
+ HsTickPragma noExt src info srcInfo (checkExpr e)
+ FrameCoreAnn src lbl e -> HsCoreAnn noExt src lbl (checkExpr e)
+ FrameApp f a -> HsApp noExt (checkExpr f) (checkExpr a)
+ FrameAppType f t -> HsAppType noExt (checkExpr f) t
+ FrameOpApp e1 op e2 ->
+ OpApp noExt (checkExpr e1) (checkExpr op) (checkExpr e2)
+ FrameSectionL e1 op -> SectionL noExt (checkExpr e1) (checkExpr op)
+ FrameSectionR op e2 -> SectionR noExt (checkExpr op) (checkExpr e2)
+ FrameNegApp e -> NegApp noExt (checkExpr e) noSyntaxExpr
+ FrameLazyPat p -> ELazyPat noExt (checkExpr p)
+ FrameStatic e -> HsStatic noExt (checkExpr e)
+
+checkExprTupArg :: LTupArgFrame -> LHsTupArg GhcPs
+checkExprTupArg = mapLoc go
+ where
+ go (TupArgFramePresent e) = Present noExt (checkExpr e)
+ go TupArgFrameMissing = Missing noExt
+
+checkExprStmt :: LFrameStmt -> LStmt GhcPs (LHsExpr GhcPs)
+checkExprStmt (dL->L l stmt) = cL l $ case stmt of
+ FrameTransformStmt ss f ->
+ mkTransformStmt (map checkExprStmt ss) (checkExpr f)
+ FrameTransformByStmt ss f e ->
+ mkTransformByStmt (map checkExprStmt ss) (checkExpr f) (checkExpr e)
+ FrameGroupUsingStmt ss f ->
+ mkGroupUsingStmt (map checkExprStmt ss) (checkExpr f)
+ FrameGroupByUsingStmt ss e f ->
+ mkGroupByUsingStmt (map checkExprStmt ss) (checkExpr e) (checkExpr f)
+ FrameBindStmt p e -> mkBindStmt p (checkExpr e)
+ FrameBodyStmt e -> mkBodyStmt (checkExpr e)
+ FrameLetStmt binds -> LetStmt noExt binds
+ FrameRecStmt ss -> mkRecStmt (map checkExprStmt ss)
+ FrameParStmt qss ->
+ ParStmt noExt
+ [ParStmtBlock noExt (map checkExprStmt qs) [] noSyntaxExpr
+ | qs <- qss]
+ noExpr
+ noSyntaxExpr
+
+checkExprMatch :: LFrameMatch -> LMatch GhcPs (LHsExpr GhcPs)
+checkExprMatch (dL->L l match) = cL l $
+ let FrameMatch ctxt pats grhss = match in
+ Match { m_ext = NoExt,
+ m_ctxt = ctxt,
+ m_pats = pats,
+ m_grhss = checkExprGRHSs grhss }
+
+checkExprGRHSs :: FrameGRHSs -> GRHSs GhcPs (LHsExpr GhcPs)
+checkExprGRHSs (FrameGRHSs grhss binds) =
+ GRHSs { grhssExt = noExt
+ , grhssGRHSs = map checkExprGRHS grhss
+ , grhssLocalBinds = binds }
+
+checkExprGRHS :: LFrameGRHS -> LGRHS GhcPs (LHsExpr GhcPs)
+checkExprGRHS (dL->L l grhs) = cL l $
+ let FrameGRHS guards rhs = grhs in
+ GRHS noExt guards (checkExpr rhs)
+
+unguardedFrameRHS :: SrcSpan -> LExpPatFrame -> [LFrameGRHS]
+unguardedFrameRHS loc rhs = [cL loc (FrameGRHS [] rhs)]