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. - splices on the same line is not currently supported.
- This means that a splice can modify the logical lines within its block - This means that a splice can modify the logical lines within its block
- as it likes, without interfering with the Coords of other splices. - 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 - 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 - 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) let dest = (destdir </> f)
lls <- map (++ "\n") . lines <$> readFileStrict f lls <- map (++ "\n") . lines <$> readFileStrict f
createDirectoryIfMissing True (parentDir dest) createDirectoryIfMissing True (parentDir dest)
let newcontent = concat $ addimports $ let newcontent = concat $ addimports $ expand lls splices
expanddeclarations declarationsplices $
expandexpressions lls expressionsplices
oldcontent <- catchMaybeIO $ readFileStrict dest oldcontent <- catchMaybeIO $ readFileStrict dest
when (oldcontent /= Just newcontent) $ do when (oldcontent /= Just newcontent) $ do
putStrLn $ "splicing " ++ f putStrLn $ "splicing " ++ f
writeFile dest newcontent writeFile dest newcontent
where where
(expressionsplices, declarationsplices) = expand lls [] = lls
partition isExpressionSplice splices expand lls (s:rest)
| isExpressionSplice s = expand (expandExpressionSplice s lls) rest
expandexpressions lls [] = lls | otherwise = expand (expandDeclarationSplice s lls) rest
expandexpressions lls (s:rest) =
expandexpressions (expandExpressionSplice s lls) rest
expanddeclarations [] lls = lls
expanddeclarations l lls = lls ++ map (mangleCode . splicedCode) l
addimports lls = case imports of addimports lls = case imports of
Nothing -> lls Nothing -> lls
@ -231,6 +219,18 @@ applySplices destdir imports splices@(first:_) = do
, end , 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 :: Splice -> [String] -> [String]
expandExpressionSplice s lls = concat [before, spliced:padding, end] expandExpressionSplice s lls = concat [before, spliced:padding, end]
where where
@ -290,12 +290,22 @@ expandExpressionSplice s lls = concat [before, spliced:padding, end]
mangleCode :: String -> String mangleCode :: String -> String
mangleCode = declaration_parens mangleCode = declaration_parens
. remove_declaration_splices . remove_declaration_splices
. yesod_url_render_hack
. nested_instances . nested_instances
. fix_bad_escape . collapse_multiline_strings
. remove_package_version . remove_package_version
where where
{- GHC may incorrectly escape "}" within a multi-line string. -} {- For some reason, GHC sometimes doesn't like the multiline
fix_bad_escape = replace " \\}" " }" - 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: {- GHC may output this:
- -
@ -328,14 +338,12 @@ mangleCode = declaration_parens
- "blaze-html-0.4.3.1:Text.Blaze.Internal.preEscapedText" - "blaze-html-0.4.3.1:Text.Blaze.Internal.preEscapedText"
- "ghc-prim:GHC.Types.:" - "ghc-prim:GHC.Types.:"
-} -}
remove_package_version s = case parse findQualifiedSymbols "" s of remove_package_version = parsecAndReplace $
Left e -> s mangleSymbol <$> qualifiedSymbol
Right symbols -> concat $
map (either (\c -> [c]) mangleSymbol) symbols
findQualifiedSymbols :: Parser [Either Char String] mangleSymbol "GHC.Types." = ""
findQualifiedSymbols = many $ mangleSymbol "GHC.Tuple." = ""
try (Right <$> qualifiedSymbol) <|> (Left <$> anyChar) mangleSymbol s = s
qualifiedSymbol :: Parser String qualifiedSymbol :: Parser String
qualifiedSymbol = do qualifiedSymbol = do
@ -346,9 +354,60 @@ mangleCode = declaration_parens
token :: Parser String token :: Parser String
token = many1 $ satisfy isAlphaNum <|> oneOf "-.'" token = many1 $ satisfy isAlphaNum <|> oneOf "-.'"
mangleSymbol "GHC.Types." = "" {- This works around a problem in the expanded template haskell for Yesod
mangleSymbol "GHC.Tuple.()" = "()" - type-safe url rendering.
mangleSymbol s = s -
- 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 :: IO ()
main = go =<< getArgs main = go =<< getArgs

View file

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