diff options
author | Shayne Fletcher <shayne@shaynefletcher.org> | 2021-02-21 11:48:17 -0500 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2021-03-06 19:27:04 -0500 |
commit | cf65cf16c89414273c4f6b2d090d4b2fffb90759 (patch) | |
tree | 57d893535444c2face265c12ade95f0ef3f0ceba /compiler/Language | |
parent | 9e0c0c3a7b6cad8c08e5de7e2a27cf2cb2d2368f (diff) | |
download | haskell-cf65cf16c89414273c4f6b2d090d4b2fffb90759.tar.gz |
Implement record dot syntaxwip/joachim/bump-haddock
Diffstat (limited to 'compiler/Language')
-rw-r--r-- | compiler/Language/Haskell/Syntax/Expr.hs | 135 | ||||
-rw-r--r-- | compiler/Language/Haskell/Syntax/Extension.hs | 2 |
2 files changed, 136 insertions, 1 deletions
diff --git a/compiler/Language/Haskell/Syntax/Expr.hs b/compiler/Language/Haskell/Syntax/Expr.hs index 3d6500d342..9967a78314 100644 --- a/compiler/Language/Haskell/Syntax/Expr.hs +++ b/compiler/Language/Haskell/Syntax/Expr.hs @@ -40,6 +40,7 @@ import Language.Haskell.Syntax.Binds -- others: import GHC.Tc.Types.Evidence import GHC.Core +import GHC.Core.DataCon (FieldLabelString) import GHC.Types.Name import GHC.Types.Basic import GHC.Types.Fixity @@ -59,6 +60,110 @@ import qualified Data.Data as Data (Fixity(..)) import GHCi.RemoteTypes ( ForeignRef ) import qualified Language.Haskell.TH as TH (Q) +{- Note [RecordDotSyntax field updates] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The extensions @OverloadedRecordDot@ @OverloadedRecordUpdate@ together +enable record updates like @a{foo.bar.baz = 1}@. Introducing this +syntax slightly complicates parsing. This note explains how it's done. + +In the event a record is being constructed or updated, it's this +production that's in play: +@ +aexp1 -> aexp1 '{' fbinds '}' { + ... + mkHsRecordPV ... $1 (snd $3) +} +@ +@fbinds@ is a list of field bindings. @mkHsRecordPV@ is a function of +the @DisambECP b@ typeclass, see Note [Ambiguous syntactic +categories]. + +The "normal" rules for an @fbind@ are: +@ +fbind + : qvar '=' texp + | qvar +@ +These rules compute values of @LHsRecField GhcPs (Located b)@. They +apply in the context of record construction, record updates, record +patterns and record expressions. That is, @b@ ranges over @HsExpr +GhcPs@, @HsPat GhcPs@ and @HsCmd GhcPs@. + +When @OverloadedRecordDot@ and @OverloadedRecordUpdate@ are both +enabled, two additional @fbind@ rules are admitted: +@ + | field TIGHT_INFIX_PROJ fieldToUpdate '=' texp + | field TIGHT_INFIX_PROJ fieldToUpdate +@ + +These rules only make sense when parsing record update expressions +(that is, patterns and commands cannot be parsed by these rules and +neither record constructions). + +The results of these new rules cannot be represented by @LHsRecField +GhcPs (LHsExpr GhcPs)@ values as the type is defined today. We +minimize modifying existing code by having these new rules calculate +@LHsRecProj GhcPs (Located b)@ ("record projection") values instead: +@ +newtype FieldLabelStrings = FieldLabelStrings [Located FieldLabelString] +type RecProj arg = HsRecField' FieldLabelStrings arg +type LHsRecProj p arg = Located (RecProj arg) +@ + +The @fbind@ rule is then given the type @fbind :: { forall b. +DisambECP b => PV (Fbind b) }@ accomodating both alternatives: +@ +type Fbind b = Either + (LHsRecField GhcPs (Located b)) + ( LHsRecProj GhcPs (Located b)) +@ + +In @data HsExpr p@, the @RecordUpd@ constuctor indicates regular +updates vs. projection updates by means of the @rupd_flds@ member +type, an @Either@ instance: +@ + | RecordUpd + { rupd_ext :: XRecordUpd p + , rupd_expr :: LHsExpr p + , rupd_flds :: Either [LHsRecUpdField p] [LHsRecUpdProj p] + } +@ +Here, +@ +type RecUpdProj p = RecProj (LHsExpr p) +type LHsRecUpdProj p = Located (RecUpdProj p) +@ +and @Left@ values indicating regular record update, @Right@ values +updates desugared to @setField@s. + +If @OverloadedRecordUpdate@ is enabled, any updates parsed as +@LHsRecField GhcPs@ values are converted to @LHsRecUpdProj GhcPs@ +values (see function @mkRdrRecordUpd@ in 'GHC.Parser.PostProcess'). +-} + +-- | RecordDotSyntax field updates + +newtype FieldLabelStrings = + FieldLabelStrings [Located FieldLabelString] + deriving (Data) + +instance Outputable FieldLabelStrings where + ppr (FieldLabelStrings flds) = + hcat (punctuate dot (map (ppr . unLoc) flds)) + +-- Field projection updates (e.g. @foo.bar.baz = 1@). See Note +-- [RecordDotSyntax field updates]. +type RecProj arg = HsRecField' FieldLabelStrings arg + +-- The phantom type parameter @p@ is for symmetry with @LHsRecField p +-- arg@ in the definition of @data Fbind@ (see GHC.Parser.Process). +type LHsRecProj p arg = Located (RecProj arg) + +-- These two synonyms are used in the definition of syntax @RecordUpd@ +-- below. +type RecUpdProj p = RecProj (LHsExpr p) +type LHsRecUpdProj p = Located (RecUpdProj p) + {- ************************************************************************ * * @@ -356,16 +461,44 @@ data HsExpr p -- -- - 'GHC.Parser.Annotation.AnnKeywordId' : 'GHC.Parser.Annotation.AnnOpen' @'{'@, -- 'GHC.Parser.Annotation.AnnDotdot','GHC.Parser.Annotation.AnnClose' @'}'@ + -- 'GHC.Parser.Annotation.AnnComma, 'GHC.Parser.Annotation.AnnDot', + -- 'GHC.Parser.Annotation.AnnClose' @'}'@ -- For details on above see note [Api annotations] in GHC.Parser.Annotation | RecordUpd { rupd_ext :: XRecordUpd p , rupd_expr :: LHsExpr p - , rupd_flds :: [LHsRecUpdField p] + , rupd_flds :: Either [LHsRecUpdField p] [LHsRecUpdProj p] } -- For a type family, the arg types are of the *instance* tycon, -- not the family tycon + -- | Record field selection e.g @z.x@. + -- + -- - 'GHC.Parser.Annotation.AnnKeywordId' : 'GHC.Parser.Annotation.AnnDot' + -- + -- This case only arises when the OverloadedRecordDot langauge + -- extension is enabled. + + | HsGetField { + gf_ext :: XGetField p + , gf_expr :: LHsExpr p + , gf_field :: Located FieldLabelString + } + + -- | Record field selector. e.g. @(.x)@ or @(.x.y)@ + -- + -- - 'GHC.Parser.Annotation.AnnKeywordId' : 'GHC.Parser.Annotation.AnnOpenP' + -- 'GHC.Parser.Annotation.AnnDot', 'GHC.Parser.Annotation.AnnCloseP' + -- + -- This case only arises when the OverloadedRecordDot langauge + -- extensions is enabled. + + | HsProjection { + proj_ext :: XProjection p + , proj_flds :: [Located FieldLabelString] + } + -- | Expression with an explicit type signature. @e :: type@ -- -- - 'GHC.Parser.Annotation.AnnKeywordId' : 'GHC.Parser.Annotation.AnnDcolon' diff --git a/compiler/Language/Haskell/Syntax/Extension.hs b/compiler/Language/Haskell/Syntax/Extension.hs index 16b11b3e30..f843bee1a2 100644 --- a/compiler/Language/Haskell/Syntax/Extension.hs +++ b/compiler/Language/Haskell/Syntax/Extension.hs @@ -387,6 +387,8 @@ type family XDo x type family XExplicitList x type family XRecordCon x type family XRecordUpd x +type family XGetField x +type family XProjection x type family XExprWithTySig x type family XArithSeq x type family XBracket x |