Use ExactPrintFallback for unknown constructs

fixes #11
pull/13/head
Lennart Spitzner 2017-03-06 12:42:27 +01:00
parent 0a907c5594
commit 575d530188
10 changed files with 115 additions and 50 deletions

View File

@ -52,7 +52,9 @@ defaultTestConfig = Config
, _lconfig_altChooser = coerce $ AltChooserBoundedSearch 3 , _lconfig_altChooser = coerce $ AltChooserBoundedSearch 3
, _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7) , _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7)
} }
, _conf_errorHandling = _conf_errorHandling staticDefaultConfig , _conf_errorHandling = (_conf_errorHandling staticDefaultConfig)
{ _econf_ExactPrintFallback = coerce ExactPrintFallbackModeNever
}
, _conf_forward = ForwardOptions , _conf_forward = ForwardOptions
{ _options_ghc = Identity [] { _options_ghc = Identity []
} }

View File

@ -93,6 +93,7 @@ configParser = do
{ _econf_produceOutputOnErrors = wrapLast $ falseToNothing outputOnErrors { _econf_produceOutputOnErrors = wrapLast $ falseToNothing outputOnErrors
, _econf_Werror = wrapLast $ falseToNothing wError , _econf_Werror = wrapLast $ falseToNothing wError
, _econf_CPPMode = mempty , _econf_CPPMode = mempty
, _econf_ExactPrintFallback = mempty
} }
, _conf_forward = ForwardOptions , _conf_forward = ForwardOptions
{ _options_ghc = [ optionsGhc & List.unwords & CmdArgs.splitArgs | not $ null optionsGhc ] { _options_ghc = [ optionsGhc & List.unwords & CmdArgs.splitArgs | not $ null optionsGhc ]

View File

@ -67,6 +67,14 @@ data ErrorHandlingConfigF f = ErrorHandlingConfig
{ _econf_produceOutputOnErrors :: f (Semigroup.Last Bool) { _econf_produceOutputOnErrors :: f (Semigroup.Last Bool)
, _econf_Werror :: f (Semigroup.Last Bool) , _econf_Werror :: f (Semigroup.Last Bool)
, _econf_CPPMode :: f (Semigroup.Last CPPMode) , _econf_CPPMode :: f (Semigroup.Last CPPMode)
, _econf_ExactPrintFallback :: f (Semigroup.Last ExactPrintFallbackMode)
-- ^ Determines when to fall back on the exactprint'ed output when
-- syntactical constructs are encountered which are not yet handled by
-- brittany.
-- Note that the "risky" setting is risky because even with the check of
-- the syntactic validity of the brittany output, at least in theory there
-- may be cases where the output is syntactically/semantically valid but
-- has different semantics that the code pre-transformation.
} }
deriving (Generic) deriving (Generic)
@ -182,6 +190,8 @@ makeFromJSON (ColumnAlignMode)
makeToJSON (ColumnAlignMode) makeToJSON (ColumnAlignMode)
makeFromJSON (CPPMode) makeFromJSON (CPPMode)
makeToJSON (CPPMode) makeToJSON (CPPMode)
makeFromJSON (ExactPrintFallbackMode)
makeToJSON (ExactPrintFallbackMode)
makeFromJSONOption (LayoutConfigF) makeFromJSONOption (LayoutConfigF)
makeFromJSONMaybe (LayoutConfigF) makeFromJSONMaybe (LayoutConfigF)
@ -278,6 +288,15 @@ data CPPMode = CPPModeAbort -- abort program on seeing -XCPP
-- file.) -- file.)
deriving (Show, Generic, Data) deriving (Show, Generic, Data)
data ExactPrintFallbackMode
= ExactPrintFallbackModeNever -- never fall back on exactprinting
| ExactPrintFallbackModeInline -- fall back only if there are no newlines in
-- the exactprint'ed output.
| ExactPrintFallbackModeRisky -- fall back even in the presence of newlines.
-- THIS MAY THEORETICALLY CHANGE SEMANTICS OF
-- A PROGRAM BY TRANSFORMING IT.
deriving (Show, Generic, Data)
staticDefaultConfig :: Config staticDefaultConfig :: Config
staticDefaultConfig = Config staticDefaultConfig = Config
{ _conf_debug = DebugConfig { _conf_debug = DebugConfig
@ -307,6 +326,7 @@ staticDefaultConfig = Config
{ _econf_produceOutputOnErrors = coerce False { _econf_produceOutputOnErrors = coerce False
, _econf_Werror = coerce False , _econf_Werror = coerce False
, _econf_CPPMode = coerce CPPModeAbort , _econf_CPPMode = coerce CPPModeAbort
, _econf_ExactPrintFallback = coerce ExactPrintFallbackModeInline
} }
, _conf_forward = ForwardOptions , _conf_forward = ForwardOptions
{ _options_ghc = Identity [] { _options_ghc = Identity []
@ -347,11 +367,12 @@ instance CZip LayoutConfigF where
(f x8 y8) (f x8 y8)
instance CZip ErrorHandlingConfigF where instance CZip ErrorHandlingConfigF where
cZip f (ErrorHandlingConfig x1 x2 x3) cZip f (ErrorHandlingConfig x1 x2 x3 x4)
(ErrorHandlingConfig y1 y2 y3) = ErrorHandlingConfig (ErrorHandlingConfig y1 y2 y3 y4) = ErrorHandlingConfig
(f x1 y1) (f x1 y1)
(f x2 y2) (f x2 y2)
(f x3 y3) (f x3 y3)
(f x4 y4)
instance CZip ForwardOptionsF where instance CZip ForwardOptionsF where
cZip f (ForwardOptions x1) cZip f (ForwardOptions x1)

View File

@ -36,6 +36,7 @@ module Language.Haskell.Brittany.LayouterBasics
, docSetBaseAndIndent , docSetBaseAndIndent
, briDocByExact , briDocByExact
, briDocByExactNoComment , briDocByExactNoComment
, briDocByExactInlineOnly
, foldedAnnKeys , foldedAnnKeys
, unknownNodeError , unknownNodeError
, appSep , appSep
@ -118,6 +119,10 @@ briDocByExact ast = do
docExt ast anns True docExt ast anns True
-- | Use ExactPrint's output for this node. -- | Use ExactPrint's output for this node.
-- Consider that for multi-line input, the indentation of the code produced
-- by ExactPrint might be different, and even incompatible with the indentation
-- of its surroundings as layouted by brittany. But there are safe uses of
-- this, e.g. for any top-level declarations.
briDocByExactNoComment briDocByExactNoComment
:: (ExactPrint.Annotate.Annotate ast) :: (ExactPrint.Annotate.Annotate ast)
=> GenLocated SrcSpan ast => GenLocated SrcSpan ast
@ -129,6 +134,37 @@ briDocByExactNoComment ast = do
(printTreeWithCustom 100 (customLayouterF anns) ast) (printTreeWithCustom 100 (customLayouterF anns) ast)
docExt ast anns False docExt ast anns False
-- | Use ExactPrint's output for this node, presuming that this output does
-- not contain any newlines. If this property is not met, the semantics
-- depend on the @econf_AllowRiskyExactPrintUse@ config flag.
briDocByExactInlineOnly
:: (ExactPrint.Annotate.Annotate ast, Data ast)
=> String
-> GenLocated SrcSpan ast
-> ToBriDocM BriDocNumbered
briDocByExactInlineOnly infoStr ast = do
anns <- mAsk
traceIfDumpConf "ast"
_dconf_dump_ast_unknown
(printTreeWithCustom 100 (customLayouterF anns) ast)
let exactPrinted = Text.pack $ ExactPrint.exactPrint ast anns
fallbackMode <-
mAsk <&> _conf_errorHandling .> _econf_ExactPrintFallback .> confUnpack
let exactPrintNode = allocateNode $ BDFExternal
(ExactPrint.Types.mkAnnKey ast)
(foldedAnnKeys ast)
False
exactPrinted
let
errorAction = do
mTell $ [LayoutErrorUnknownNode infoStr ast]
docLit $ Text.pack "{- BRITTANY ERROR UNHANDLED SYNTACTICAL CONSTRUCT -}"
case (fallbackMode, Text.lines exactPrinted) of
(ExactPrintFallbackModeNever, _ ) -> errorAction
(_ , [_]) -> exactPrintNode
(ExactPrintFallbackModeRisky, _ ) -> exactPrintNode
_ -> errorAction
rdrNameToText :: RdrName -> Text rdrNameToText :: RdrName -> Text
-- rdrNameToText = Text.pack . show . flip runSDoc unsafeGlobalDynFlags . ppr -- rdrNameToText = Text.pack . show . flip runSDoc unsafeGlobalDynFlags . ppr
rdrNameToText (Unqual occname) = Text.pack $ occNameString occname rdrNameToText (Unqual occname) = Text.pack $ occNameString occname

View File

@ -38,13 +38,13 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
TrueExprHole oname -> docLit $ Text.pack $ occNameString oname TrueExprHole oname -> docLit $ Text.pack $ occNameString oname
HsRecFld{} -> do HsRecFld{} -> do
-- TODO -- TODO
unknownNodeError "HsRecFld" lexpr briDocByExactInlineOnly "HsRecFld" lexpr
HsOverLabel{} -> do HsOverLabel{} -> do
-- TODO -- TODO
unknownNodeError "HsOverLabel{}" lexpr briDocByExactInlineOnly "HsOverLabel{}" lexpr
HsIPVar{} -> do HsIPVar{} -> do
-- TODO -- TODO
unknownNodeError "HsOverLabel{}" lexpr briDocByExactInlineOnly "HsOverLabel{}" lexpr
HsOverLit (OverLit olit _ _ _) -> do HsOverLit (OverLit olit _ _ _) -> do
allocateNode $ overLitValBriDoc olit allocateNode $ overLitValBriDoc olit
HsLit lit -> do HsLit lit -> do
@ -157,10 +157,10 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
] ]
HsAppType{} -> do HsAppType{} -> do
-- TODO -- TODO
unknownNodeError "HsAppType{}" lexpr briDocByExactInlineOnly "HsAppType{}" lexpr
HsAppTypeOut{} -> do HsAppTypeOut{} -> do
-- TODO -- TODO
unknownNodeError "HsAppTypeOut{}" lexpr briDocByExactInlineOnly "HsAppTypeOut{}" lexpr
OpApp expLeft@(L _ OpApp{}) expOp _ expRight -> do OpApp expLeft@(L _ OpApp{}) expOp _ expRight -> do
let gather :: [(LHsExpr RdrName, LHsExpr RdrName)] -> LHsExpr RdrName -> (LHsExpr RdrName, [(LHsExpr RdrName, LHsExpr RdrName)]) let gather :: [(LHsExpr RdrName, LHsExpr RdrName)] -> LHsExpr RdrName -> (LHsExpr RdrName, [(LHsExpr RdrName, LHsExpr RdrName)])
gather opExprList = \case gather opExprList = \case
@ -521,7 +521,7 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
docLit $ Text.pack "[]" docLit $ Text.pack "[]"
ExplicitPArr{} -> do ExplicitPArr{} -> do
-- TODO -- TODO
unknownNodeError "ExplicitPArr{}" lexpr briDocByExactInlineOnly "ExplicitPArr{}" lexpr
RecordCon lname _ _ (HsRecFields [] Nothing) -> do RecordCon lname _ _ (HsRecFields [] Nothing) -> do
let t = lrdrNameToText lname let t = lrdrNameToText lname
docWrapNode lname $ docSeq docWrapNode lname $ docSeq
@ -673,7 +673,7 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
] ]
ExprWithTySigOut{} -> do ExprWithTySigOut{} -> do
-- TODO -- TODO
unknownNodeError "ExprWithTySigOut{}" lexpr briDocByExactInlineOnly "ExprWithTySigOut{}" lexpr
ArithSeq _ Nothing info -> ArithSeq _ Nothing info ->
case info of case info of
From e1 -> do From e1 -> do
@ -717,63 +717,63 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
, docLit $ Text.pack "]" , docLit $ Text.pack "]"
] ]
ArithSeq{} -> ArithSeq{} ->
unknownNodeError "ArithSeq" lexpr briDocByExactInlineOnly "ArithSeq" lexpr
PArrSeq{} -> do PArrSeq{} -> do
-- TODO -- TODO
unknownNodeError "PArrSeq{}" lexpr briDocByExactInlineOnly "PArrSeq{}" lexpr
HsSCC{} -> do HsSCC{} -> do
-- TODO -- TODO
unknownNodeError "HsSCC{}" lexpr briDocByExactInlineOnly "HsSCC{}" lexpr
HsCoreAnn{} -> do HsCoreAnn{} -> do
-- TODO -- TODO
unknownNodeError "HsCoreAnn{}" lexpr briDocByExactInlineOnly "HsCoreAnn{}" lexpr
HsBracket{} -> do HsBracket{} -> do
-- TODO -- TODO
unknownNodeError "HsBracket{}" lexpr briDocByExactInlineOnly "HsBracket{}" lexpr
HsRnBracketOut{} -> do HsRnBracketOut{} -> do
-- TODO -- TODO
unknownNodeError "HsRnBracketOut{}" lexpr briDocByExactInlineOnly "HsRnBracketOut{}" lexpr
HsTcBracketOut{} -> do HsTcBracketOut{} -> do
-- TODO -- TODO
unknownNodeError "HsTcBracketOut{}" lexpr briDocByExactInlineOnly "HsTcBracketOut{}" lexpr
HsSpliceE{} -> do HsSpliceE{} -> do
-- TODO -- TODO
unknownNodeError "HsSpliceE{}" lexpr briDocByExactInlineOnly "HsSpliceE{}" lexpr
HsProc{} -> do HsProc{} -> do
-- TODO -- TODO
unknownNodeError "HsProc{}" lexpr briDocByExactInlineOnly "HsProc{}" lexpr
HsStatic{} -> do HsStatic{} -> do
-- TODO -- TODO
unknownNodeError "HsStatic{}" lexpr briDocByExactInlineOnly "HsStatic{}" lexpr
HsArrApp{} -> do HsArrApp{} -> do
-- TODO -- TODO
unknownNodeError "HsArrApp{}" lexpr briDocByExactInlineOnly "HsArrApp{}" lexpr
HsArrForm{} -> do HsArrForm{} -> do
-- TODO -- TODO
unknownNodeError "HsArrForm{}" lexpr briDocByExactInlineOnly "HsArrForm{}" lexpr
HsTick{} -> do HsTick{} -> do
-- TODO -- TODO
unknownNodeError "HsTick{}" lexpr briDocByExactInlineOnly "HsTick{}" lexpr
HsBinTick{} -> do HsBinTick{} -> do
-- TODO -- TODO
unknownNodeError "HsBinTick{}" lexpr briDocByExactInlineOnly "HsBinTick{}" lexpr
HsTickPragma{} -> do HsTickPragma{} -> do
-- TODO -- TODO
unknownNodeError "HsTickPragma{}" lexpr briDocByExactInlineOnly "HsTickPragma{}" lexpr
EWildPat{} -> do EWildPat{} -> do
docLit $ Text.pack "_" docLit $ Text.pack "_"
EAsPat{} -> do EAsPat{} -> do
-- TODO -- TODO
unknownNodeError "EAsPat{}" lexpr briDocByExactInlineOnly "EAsPat{}" lexpr
EViewPat{} -> do EViewPat{} -> do
-- TODO -- TODO
unknownNodeError "EViewPat{}" lexpr briDocByExactInlineOnly "EViewPat{}" lexpr
ELazyPat{} -> do ELazyPat{} -> do
-- TODO -- TODO
unknownNodeError "ELazyPat{}" lexpr briDocByExactInlineOnly "ELazyPat{}" lexpr
HsWrap{} -> do HsWrap{} -> do
-- TODO -- TODO
unknownNodeError "HsWrap{}" lexpr briDocByExactInlineOnly "HsWrap{}" lexpr
litBriDoc :: HsLit -> BriDocFInt litBriDoc :: HsLit -> BriDocFInt
litBriDoc = \case litBriDoc = \case

View File

@ -129,7 +129,7 @@ layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of
-- #else -- #else
-- VarPat n -> return $ stringLayouter lpat $ rdrNameToText n -- VarPat n -> return $ stringLayouter lpat $ rdrNameToText n
-- #endif -- #endif
_ -> fmap return $ unknownNodeError "" lpat _ -> fmap return $ briDocByExactInlineOnly "some unknown pattern" lpat
colsWrapPat :: Seq BriDocNumbered -> ToBriDocM BriDocNumbered colsWrapPat :: Seq BriDocNumbered -> ToBriDocM BriDocNumbered
colsWrapPat = docCols ColPatterns . fmap return . Foldable.toList colsWrapPat = docCols ColPatterns . fmap return . Foldable.toList

View File

@ -74,4 +74,4 @@ layoutStmt lstmt@(L _ stmt) = docWrapNode lstmt $ case stmt of
BodyStmt expr _ _ _ -> do BodyStmt expr _ _ _ -> do
expDoc <- docSharedWrapper layoutExpr expr expDoc <- docSharedWrapper layoutExpr expr
docAddBaseY BrIndentRegular $ expDoc docAddBaseY BrIndentRegular $ expDoc
_ -> unknownNodeError "" lstmt _ -> briDocByExactInlineOnly "some unknown statement" lstmt

View File

@ -185,8 +185,8 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of
] ]
) )
] ]
x@(HsQualTy (L _ []) _) -> (HsQualTy (L _ []) _) ->
unknownNodeError "HsQualTy [] _" x briDocByExactInlineOnly "HsQualTy [] _" ltype
HsQualTy lcntxts@(L _ cntxts@(_:_)) typ1 -> do HsQualTy lcntxts@(L _ cntxts@(_:_)) typ1 -> do
typeDoc <- docSharedWrapper layoutType typ1 typeDoc <- docSharedWrapper layoutType typ1
cntxtDocs <- cntxts `forM` docSharedWrapper layoutType cntxtDocs <- cntxts `forM` docSharedWrapper layoutType
@ -396,7 +396,7 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of
(docLines $ (docAddBaseY (BrIndentSpecial 2) <$> lines) ++ [end]) (docLines $ (docAddBaseY (BrIndentSpecial 2) <$> lines) ++ [end])
] ]
HsOpTy{} -> -- TODO HsOpTy{} -> -- TODO
unknownNodeError "HsOpTy{}" ltype briDocByExactInlineOnly "HsOpTy{}" ltype
-- HsOpTy typ1 opName typ2 -> do -- HsOpTy typ1 opName typ2 -> do
-- -- TODO: these need some proper fixing. precedences don't add up. -- -- TODO: these need some proper fixing. precedences don't add up.
-- -- maybe the parser just returns some trivial right recursion -- -- maybe the parser just returns some trivial right recursion
@ -511,7 +511,7 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of
]) ])
] ]
HsBangTy{} -> -- TODO HsBangTy{} -> -- TODO
unknownNodeError "HsBangTy{}" ltype briDocByExactInlineOnly "HsBangTy{}" ltype
-- HsBangTy bang typ1 -> do -- HsBangTy bang typ1 -> do
-- let bangStr = case bang of -- let bangStr = case bang of
-- HsSrcBang _ unpackness strictness -> -- HsSrcBang _ unpackness strictness ->
@ -563,11 +563,11 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of
-- , _layouter_ast = ltype -- , _layouter_ast = ltype
-- } -- }
HsSpliceTy{} -> -- TODO HsSpliceTy{} -> -- TODO
unknownNodeError "" ltype briDocByExactInlineOnly "" ltype
HsDocTy{} -> -- TODO HsDocTy{} -> -- TODO
unknownNodeError "" ltype briDocByExactInlineOnly "" ltype
HsRecTy{} -> -- TODO HsRecTy{} -> -- TODO
unknownNodeError "" ltype briDocByExactInlineOnly "" ltype
HsExplicitListTy _ typs -> do HsExplicitListTy _ typs -> do
typDocs <- docSharedWrapper layoutType `mapM` typs typDocs <- docSharedWrapper layoutType `mapM` typs
docAlt docAlt
@ -578,10 +578,10 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of
-- TODO -- TODO
] ]
HsExplicitTupleTy{} -> -- TODO HsExplicitTupleTy{} -> -- TODO
unknownNodeError "" ltype briDocByExactInlineOnly "" ltype
HsTyLit{} -> -- TODO HsTyLit{} -> -- TODO
unknownNodeError "" ltype briDocByExactInlineOnly "" ltype
HsCoreTy{} -> -- TODO HsCoreTy{} -> -- TODO
unknownNodeError "" ltype briDocByExactInlineOnly "" ltype
HsWildCardTy _ -> HsWildCardTy _ ->
docLit $ Text.pack "_" docLit $ Text.pack "_"

View File

@ -450,9 +450,9 @@ getSpacing !bridoc = rec bridoc
VerticalSpacingParNone -> mVs VerticalSpacingParNone -> mVs
_ -> LineModeInvalid _ -> LineModeInvalid
BDFForwardLineMode bd -> rec bd BDFForwardLineMode bd -> rec bd
BDFExternal{} -> return BDFExternal _ _ _ txt -> return $ LineModeValid $ case Text.lines txt of
$ LineModeValid [t] -> VerticalSpacing (Text.length t) VerticalSpacingParNone False
$ VerticalSpacing 999 VerticalSpacingParNone False x -> traceShow x $ VerticalSpacing 999 VerticalSpacingParNone False
BDFAnnotationPrior _annKey bd -> rec bd BDFAnnotationPrior _annKey bd -> rec bd
BDFAnnotationKW _annKey _kw bd -> rec bd BDFAnnotationKW _annKey _kw bd -> rec bd
BDFAnnotationRest _annKey bd -> rec bd BDFAnnotationRest _annKey bd -> rec bd
@ -663,6 +663,8 @@ getSpacings limit bridoc = preFilterLimit <$> rec bridoc
mVs <- filterAndLimit <$> rec bd mVs <- filterAndLimit <$> rec bd
return $ filter ((==VerticalSpacingParNone) . _vs_paragraph) mVs return $ filter ((==VerticalSpacingParNone) . _vs_paragraph) mVs
BDFForwardLineMode bd -> rec bd BDFForwardLineMode bd -> rec bd
BDFExternal _ _ _ txt | [t] <- Text.lines txt ->
return $ [VerticalSpacing (Text.length t) VerticalSpacingParNone False]
BDFExternal{} -> BDFExternal{} ->
return $ [] -- yes, we just assume that we cannot properly layout return $ [] -- yes, we just assume that we cannot properly layout
-- this. -- this.

View File

@ -787,3 +787,6 @@ import Control.Monad.Trans.Maybe ( MaybeT (..)
) )
import Language.Haskell.Brittany.Prelude import Language.Haskell.Brittany.Prelude
import Data.Data ( toConstr
)