+ loc = getSrcLoc tycon
+ data_cons = tyConDataCons tycon
+ (nullary_cons, non_nullary_cons) = partition isNullaryDataCon data_cons
+
+ read_prec = mk_easy_FunMonoBind loc readPrec_RDR [] []
+ (HsApp (HsVar parens_RDR) read_cons)
+
+ read_cons = foldr1 mk_alt (read_nullary_cons ++ read_non_nullary_cons)
+ read_non_nullary_cons = map read_non_nullary_con non_nullary_cons
+
+ read_nullary_cons
+ = case nullary_cons of
+ [] -> []
+ [con] -> [mkHsDo DoExpr [bindLex (ident_pat (data_con_str con)),
+ result_stmt con []] loc]
+ _ -> [HsApp (HsVar choose_RDR)
+ (ExplicitList placeHolderType (map mk_pair nullary_cons))]
+
+ mk_pair con = ExplicitTuple [HsLit (data_con_str con),
+ HsApp (HsVar returnM_RDR) (HsVar (getRdrName con))]
+ Boxed
+
+ read_non_nullary_con data_con
+ = mkHsApps prec_RDR [mkHsIntLit prec, mkHsDo DoExpr stmts loc]
+ where
+ stmts | is_infix = infix_stmts
+ | length labels > 0 = lbl_stmts
+ | otherwise = prefix_stmts
+
+ prefix_stmts -- T a b c
+ = [bindLex (ident_pat (data_con_str data_con))]
+ ++ map read_arg as_needed
+ ++ [result_stmt data_con as_needed]
+
+ infix_stmts -- a %% b
+ = [read_arg a1,
+ bindLex (symbol_pat (data_con_str data_con)),
+ read_arg a2,
+ result_stmt data_con [a1,a2]]
+
+ lbl_stmts -- T { f1 = a, f2 = b }
+ = [bindLex (ident_pat (data_con_str data_con)),
+ read_punc "{"]
+ ++ concat (intersperse [read_punc ","] field_stmts)
+ ++ [read_punc "}", result_stmt data_con as_needed]
+
+ field_stmts = zipWithEqual "lbl_stmts" read_field labels as_needed
+
+ con_arity = dataConSourceArity data_con
+ nullary_con = con_arity == 0
+ labels = dataConFieldLabels data_con
+ lab_fields = length labels
+ dc_nm = getName data_con
+ is_infix = isDataSymOcc (getOccName dc_nm)
+ as_needed = take con_arity as_RDRs
+ (a1:a2:_) = as_needed
+ prec = getPrec is_infix get_fixity dc_nm
+
+ ------------------------------------------------------------------------
+ -- Helpers
+ ------------------------------------------------------------------------
+ mk_alt e1 e2 = genOpApp e1 alt_RDR e2
+ bindLex pat = BindStmt pat (HsVar lexP_RDR) loc
+ result_stmt c as = ResultStmt (HsApp (HsVar returnM_RDR) (con_app c as)) loc
+ con_app c as = mkHsVarApps (getRdrName c) as
+
+ punc_pat s = ConPatIn punc_RDR (PrefixCon [LitPat (mkHsString s)]) -- Punc 'c'
+ ident_pat s = ConPatIn ident_RDR (PrefixCon [LitPat s]) -- Ident "foo"
+ symbol_pat s = ConPatIn symbol_RDR (PrefixCon [LitPat s]) -- Symbol ">>"
+
+ data_con_str con = mkHsString (occNameUserString (getOccName con))
+
+ read_punc c = bindLex (punc_pat c)
+ read_arg a = BindStmt (VarPat a) (mkHsVarApps step_RDR [readPrec_RDR]) loc
+
+ read_field lbl a = read_lbl lbl ++
+ [read_punc "=",
+ BindStmt (VarPat a) (mkHsVarApps reset_RDR [readPrec_RDR]) loc]
+
+ -- When reading field labels we might encounter
+ -- a = 3
+ -- _a = 3
+ -- or (#) = 4
+ -- Note the parens!
+ read_lbl lbl | is_id_start (head lbl_str)
+ = [bindLex (ident_pat lbl_lit)]
+ | otherwise
+ = [read_punc "(",
+ bindLex (symbol_pat lbl_lit),
+ read_punc ")"]
+ where
+ lbl_str = occNameUserString (getOccName (fieldLabelName lbl))
+ lbl_lit = mkHsString lbl_str
+ is_id_start c = isAlpha c || c == '_'