diff options
author | Tobias Dammers <tdammers@gmail.com> | 2017-10-25 19:09:03 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2017-10-25 19:18:42 -0400 |
commit | dbd81f7e86514498218572b9d978373b1699cc5b (patch) | |
tree | 5c4527f5405e67d0de0006fc07dd132162c3b96d /libraries/base/GHC/Read.hs | |
parent | 4c06ccb71737b77a8165e888ad75417a425549dd (diff) | |
download | haskell-dbd81f7e86514498218572b9d978373b1699cc5b.tar.gz |
Factor out readField (#14364)
Improves compiler performance of deriving Read instances, as suggested
in the issue.
Additionally, we introduce `readSymField`, a companion to `readField`
that parses symbol-type fields (where the field name is a symbol, e.g.
`(#)`, rather than an alphanumeric identifier. The decision between
these two functions is made a compile time, because we already know
which one we need based on the field name.
Reviewers: austin, hvr, bgamari, RyanGlScott
Reviewed By: bgamari
Subscribers: RyanGlScott, rwbarton, thomie
Differential Revision: https://phabricator.haskell.org/D4108
Diffstat (limited to 'libraries/base/GHC/Read.hs')
-rw-r--r-- | libraries/base/GHC/Read.hs | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/libraries/base/GHC/Read.hs b/libraries/base/GHC/Read.hs index ad29cc5c40..2d8ee3de51 100644 --- a/libraries/base/GHC/Read.hs +++ b/libraries/base/GHC/Read.hs @@ -36,6 +36,8 @@ module GHC.Read , choose , readListDefault, readListPrecDefault , readNumber + , readField + , readSymField -- Temporary , readParen @@ -359,6 +361,50 @@ choose sps = foldr ((+++) . try_one) pfail sps L.Symbol s' | s==s' -> p _other -> pfail } +-- See Note [Why readField] + +-- | 'Read' parser for a record field, of the form @fieldName=value@. The +-- @fieldName@ must be an alphanumeric identifier; for symbols (operator-style) +-- field names, e.g. @(#)@, use 'readSymField'). The second argument is a +-- parser for the field value. +readField :: String -> ReadPrec a -> ReadPrec a +readField fieldName readVal = do + expectP (L.Ident fieldName) + expectP (L.Punc "=") + readVal +{-# NOINLINE readField #-} + +-- See Note [Why readField] + +-- | 'Read' parser for a symbol record field, of the form @(###)=value@ (where +-- @###@ is the field name). The field name must be a symbol (operator-style), +-- e.g. @(#)@. For regular (alphanumeric) field names, use 'readField'. The +-- second argument is a parser for the field value. +readSymField :: String -> ReadPrec a -> ReadPrec a +readSymField fieldName readVal = do + expectP (L.Punc "(") + expectP (L.Symbol fieldName) + expectP (L.Punc ")") + expectP (L.Punc "=") + readVal +{-# NOINLINE readSymField #-} + + +-- Note [Why readField] +-- +-- Previousy, the code for automatically deriving Read instance (in +-- typecheck/TcGenDeriv.hs) would generate inline code for parsing fields; +-- this, however, turned out to produce massive amounts of intermediate code, +-- and produced a considerable performance hit in the code generator. +-- Since Read instances are not generally supposed to be perfomance critical, +-- the readField and readSymField functions have been factored out, and the +-- code generator now just generates calls rather than manually inlining the +-- parsers. For large record types (e.g. 500 fields), this produces a +-- significant performance boost. +-- +-- See also Trac #14364. + + -------------------------------------------------------------- -- Simple instances of Read -------------------------------------------------------------- |