Evil Splicer only *thought* he was evil until this commit happened.

So many nasty hacks!
This commit is contained in:
Joey Hess 2013-04-16 21:47:08 -04:00
parent ce11c339e6
commit 35f2e01c23
2 changed files with 91 additions and 31 deletions

View file

@ -185,11 +185,6 @@ splicesExtractor = rights <$> many extract
- splices on the same line is not currently supported.
- This means that a splice can modify the logical lines within its block
- as it likes, without interfering with the Coords of other splices.
-
- When splicing in declarations, they are not placed on the line
- that defined them, because at least with Yesod, that line has another TH
- splice, and things would get mixed up. Since declarations are stand
- alone, they can go anywhere, and are added to the very end of the file.
-
- As well as expanding splices, this can add a block of imports to the
- file. These are put right before the first line in the file that
@ -201,23 +196,16 @@ applySplices destdir imports splices@(first:_) = do
let dest = (destdir </> f)
lls <- map (++ "\n") . lines <$> readFileStrict f
createDirectoryIfMissing True (parentDir dest)
let newcontent = concat $ addimports $
expanddeclarations declarationsplices $
expandexpressions lls expressionsplices
let newcontent = concat $ addimports $ expand lls splices
oldcontent <- catchMaybeIO $ readFileStrict dest
when (oldcontent /= Just newcontent) $ do
putStrLn $ "splicing " ++ f
writeFile dest newcontent
where
(expressionsplices, declarationsplices) =
partition isExpressionSplice splices
expandexpressions lls [] = lls
expandexpressions lls (s:rest) =
expandexpressions (expandExpressionSplice s lls) rest
expanddeclarations [] lls = lls
expanddeclarations l lls = lls ++ map (mangleCode . splicedCode) l
expand lls [] = lls
expand lls (s:rest)
| isExpressionSplice s = expand (expandExpressionSplice s lls) rest
| otherwise = expand (expandDeclarationSplice s lls) rest
addimports lls = case imports of
Nothing -> lls
@ -231,6 +219,18 @@ applySplices destdir imports splices@(first:_) = do
, end
]
{- Declaration splices are expanded to replace their whole line. -}
expandDeclarationSplice :: Splice -> [String] -> [String]
expandDeclarationSplice s lls = concat [before, [splice], end]
where
cs = spliceStart s
ce = spliceEnd s
(before, rest) = splitAt (coordLine cs - 1) lls
(_oldlines, end) = splitAt (1 + coordLine (offsetCoord ce cs)) rest
splice = mangleCode $ splicedCode s
{- Expression splices are expanded within their line. -}
expandExpressionSplice :: Splice -> [String] -> [String]
expandExpressionSplice s lls = concat [before, spliced:padding, end]
where
@ -290,12 +290,22 @@ expandExpressionSplice s lls = concat [before, spliced:padding, end]
mangleCode :: String -> String
mangleCode = declaration_parens
. remove_declaration_splices
. yesod_url_render_hack
. nested_instances
. fix_bad_escape
. collapse_multiline_strings
. remove_package_version
where
{- GHC may incorrectly escape "}" within a multi-line string. -}
fix_bad_escape = replace " \\}" " }"
{- For some reason, GHC sometimes doesn't like the multiline
- strings it creates. It seems to get hung up on \{ at the
- start of a new line sometimes, wanting it to not be escaped.
-
- To work around what is likely a GHC bug, just collapse
- multiline strings. -}
collapse_multiline_strings = parsecAndReplace $ do
string "\\\n"
many1 $ oneOf " \t"
string "\\"
return ""
{- GHC may output this:
-
@ -328,14 +338,12 @@ mangleCode = declaration_parens
- "blaze-html-0.4.3.1:Text.Blaze.Internal.preEscapedText"
- "ghc-prim:GHC.Types.:"
-}
remove_package_version s = case parse findQualifiedSymbols "" s of
Left e -> s
Right symbols -> concat $
map (either (\c -> [c]) mangleSymbol) symbols
remove_package_version = parsecAndReplace $
mangleSymbol <$> qualifiedSymbol
findQualifiedSymbols :: Parser [Either Char String]
findQualifiedSymbols = many $
try (Right <$> qualifiedSymbol) <|> (Left <$> anyChar)
mangleSymbol "GHC.Types." = ""
mangleSymbol "GHC.Tuple." = ""
mangleSymbol s = s
qualifiedSymbol :: Parser String
qualifiedSymbol = do
@ -346,9 +354,60 @@ mangleCode = declaration_parens
token :: Parser String
token = many1 $ satisfy isAlphaNum <|> oneOf "-.'"
mangleSymbol "GHC.Types." = ""
mangleSymbol "GHC.Tuple.()" = "()"
mangleSymbol s = s
{- This works around a problem in the expanded template haskell for Yesod
- type-safe url rendering.
-
- It generates code like this:
-
- (toHtml
- (\ u_a2ehE -> urender_a2ehD u_a2ehE []
- (CloseAlert aid)))));
-
- Where urender_a2ehD is the function returned by getUrlRenderParams.
- But, that function that only takes 2 params, not 3.
- And toHtml doesn't take a parameter at all!
-
- So, this modifes the code, to look like this:
-
- (toHtml
- (flip urender_a2ehD []
- (CloseAlert aid)))));
-
- FIXME: Investigate and fix this properly.
-}
yesod_url_render_hack :: String -> String
yesod_url_render_hack = parsecAndReplace $ do
string "(toHtml"
whitespace
string "(\\"
whitespace
token
whitespace
string "->"
whitespace
renderer <- token
whitespace
token
whitespace
return $ "(toHtml (flip " ++ renderer ++ " "
where
whitespace :: Parser String
whitespace = many $ oneOf " \t\r\n"
token :: Parser String
token = many1 $ satisfy isAlphaNum <|> oneOf "_"
{- Given a Parser that finds strings it wants to modify,
- and returns the modified string, does a mass
- find and replace throughout the input string.
- Rather slow, but crazy powerful. -}
parsecAndReplace :: Parser String -> String -> String
parsecAndReplace p s = case parse find "" s of
Left e -> s
Right l -> concatMap (either (\c -> [c]) id) l
where
find :: Parser [Either Char String]
find = many $ try (Right <$> p) <|> (Left <$> anyChar)
main :: IO ()
main = go =<< getArgs

View file

@ -5,6 +5,8 @@
-
- ** DO NOT COMMIT **
-}
import qualified Data.Monoid
import qualified Data.Foldable
import qualified Data.Text
import qualified Data.Text.Lazy.Builder
import qualified Text.Shakespeare
@ -12,7 +14,6 @@ import qualified Text.Hamlet
import qualified Text.Julius
import qualified Text.Css
import qualified "blaze-markup" Text.Blaze.Internal
import qualified Data.Monoid
import qualified Yesod.Widget
import qualified Yesod.Routes.TH.Types
{- End EvilSplicer headers. -}