--- factorcss/FactorCSS.hs 2004/12/19 22:10:41 61 +++ factorcss/FactorCSS.hs 2004/12/27 19:11:07 62 @@ -1,3 +1,6 @@ +-- Factor a CSS stylesheet + +import List import Tokeniser import Parser import CSS @@ -5,5 +8,96 @@ main = do s <- getContents -- print (alexScanTokens s) --- print (parser (alexScanTokens s)) - putStr (unlines (show_stylesheet (parser (alexScanTokens s)))) +-- (print . process . parser . alexScanTokens) s + (putStr . unlines . show_stylesheet . process . + parser . alexScanTokens) s + +-- Process a Stylesheet. +process :: Stylesheet -> Stylesheet +process (Stylesheet charset imports stmts) = + Stylesheet charset imports (process_stmts stmts) + +-- Process a list of Statements. +process_stmts :: [Statement] -> [Statement] +process_stmts stmts = (factor . filter is_ruleset) stmts ++ + (map process_media . filter is_media) stmts ++ + filter is_page stmts + +-- Process a Media Statement. +process_media :: Statement -> Statement +process_media (Media media stmts) = Media media (factor stmts) + +-- Factor a list of Ruleset Statements. +factor :: [Statement] -> [Statement] +factor = map implode_sel . groupBy eq_sel . + sortBy cmp_sel . + map implode_decl . groupBy eq_decl . + sortBy cmp_decl . sortBy cmp_sel . + concat . map explode + +-- Explode a Ruleset Statement into an equivalent list of Ruleset Statements +-- with one Selector and one Declaration per Ruleset. +-- +-- For example (in CSS syntax), +-- explode "h1, em { color: red; background-color: blue }" = +-- "h1 { color: red } +-- h1 { background-color: blue } +-- em { color: red } +-- em { background-color: blue }" +-- +-- [length (explode (Ruleset sels decls)) == length sels * length decls] +explode :: Statement -> [Statement] +explode (Ruleset sels decls) = + concat (map (\s -> map (\d -> Ruleset [s] [d]) decls) sels) + +-- Compare two Ruleset Statements by the Selectors in each. +cmp_sel :: Statement -> Statement -> Ordering +cmp_sel (Ruleset sels0 decls0) (Ruleset sels1 decls1) + | a < b = LT + | a == b = EQ + | a > b = GT + where a = show_selectors sels0 + b = show_selectors sels1 + +-- Compare two Ruleset Statements by the first Declaration in each. +cmp_decl :: Statement -> Statement -> Ordering +cmp_decl (Ruleset sels0 (decl0:decls0)) (Ruleset sels1 (decl1:decls1)) + | a < b = LT + | a == b = EQ + | a > b = GT + where a = show_declaration decl0 + b = show_declaration decl1 + +-- Compare two Ruleset Statements for equality by the Selectors in each. +eq_sel :: Statement -> Statement -> Bool +eq_sel z = (== EQ) . cmp_sel z + +-- Compare two Ruleset Statements for equality by the first declaration in each. +eq_decl :: Statement -> Statement -> Bool +eq_decl z = (== EQ) . cmp_decl z + +-- Implode a list of Ruleset Statements with equal lists of Selectors to a +-- single equivalent Ruleset Statement. +-- +-- For example, +-- implode_sel "h1, em { color: red } +-- h1, em { background-color: blue }" = +-- "h1, em { color: red; background-color: blue }" +implode_sel :: [Statement] -> Statement +implode_sel ((Ruleset sels decls):stmts) = + Ruleset sels (concat (decls:(map declarations stmts))) + where declarations :: Statement -> [Declaration] + declarations (Ruleset s d) = d + +-- Implode a list of Ruleset Statements with equal lists of Declarations to a +-- single equivalent Ruleset Statement. +-- +-- For example, +-- implode_decl "h1 { color: red } +-- em { color: red }" = +-- "h1, em { color: red }" +implode_decl :: [Statement] -> Statement +implode_decl ((Ruleset sels decls):stmts) = + Ruleset (concat (sels:(map selectors stmts))) decls + where selectors :: Statement -> [Selector] + selectors (Ruleset s d) = s