/[james]/factorcss/FactorCSS.hs
ViewVC logotype

Diff of /factorcss/FactorCSS.hs

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 62 by james, Mon Dec 27 19:11:07 2004 UTC revision 67 by james, Thu Dec 30 23:22:02 2004 UTC
# Line 1  Line 1 
1  -- Factor a CSS stylesheet  --
2    -- This file is part of FactorCSS
3    -- Licensed under the MIT License,
4    --                http://www.opensource.org/licenses/mit-license
5    -- Copyright 2004 James Bursa <james@semichrome.net>
6    --
7    
8    -- Factor a CSS stylesheet.
9    --
10    -- This tool takes a CSS stylesheet on input and produces an almost equivalent
11    -- stylesheet on output, but with rulesets split, combined, and reordered to
12    -- "factor out" common declarations. This helps reveal shared components. The
13    -- resulting stylesheet may also be smaller.
14    --
15    -- The only known case where the output is not equivalent to the input is when
16    -- the stylesheet depends on the order of rules (see CSS 2.1 6.4.1).
17    
18  import List  import List
19    import System
20  import Tokeniser  import Tokeniser
21  import Parser  import Parser
22  import CSS  import CSS
23    
24    -- Program entry function.
25    main :: IO ()
26  main = do  main = do
27          s <- getContents          args <- getArgs
28  --      print (alexScanTokens s)          interact (run args)
29  --      (print . process . parser . alexScanTokens) s  
30          (putStr . unlines . show_stylesheet . process .  -- Produce output from arguments and input.
31                          parser . alexScanTokens) s  run :: [String] -> String -> String
32    run args input
33            | argument "help" args          = usage
34            | null args                     = go factor
35            | argument "factor" args        = go factor
36            | argument "explode" args       = go (concatMap explode)
37            | argument "identity" args      = go id
38            | argument "tree" args          = show stylesheet ++ "\n"
39            | argument "statistics" args    = stats stylesheet ++ "\n"
40            | otherwise                     = usage
41            where   go f = (unlines . show_stylesheet . process f) stylesheet
42                    stylesheet = (parser . alexScanTokens) input
43    
44    -- Check an argument list for an argument in short or long form.
45    argument :: String -> [String] -> Bool
46    argument long args = elem short shorts || elem ("--" ++ long) args
47                    where   short = head long
48                            shorts = (concat . filter is_short) args
49                            is_short ('-':'-':_) = False
50                            is_short ('-':_) = True
51                            is_short _ = False
52    
53    -- Usage help string.
54    usage :: String
55    usage = unlines ["Usage: factorcss [OPTION]... <FILE",
56                    "\"Factor out\" common declarations in a CSS stylesheet by splitting, reordering,",
57                    "and combining rulesets.",
58                    "The stylesheet is read from standard input, and the result is produced on",
59                    "standard output.",
60                    "",
61                    "Output mode:",
62                    "  -f, --factor      factor out common declarations (default)",
63                    "  -e, --explode     produce rulesets with one selector and declaration each",
64                    "  -i, --identity    just parse and output unmodified",
65                    "  -t, --tree        parse and display parse tree",
66                    "  -s, --statistics  count rulesets, selectors, and declarations",
67                    "",
68                    "  -h, --help        display this help and exit"]
69    
70  -- Process a Stylesheet.  -- Process a Stylesheet.
71  process :: Stylesheet -> Stylesheet  process :: ([Statement] -> [Statement]) -> Stylesheet -> Stylesheet
72  process (Stylesheet charset imports stmts) =  process f (Stylesheet charset imports stmts) =
73                  Stylesheet charset imports (process_stmts stmts)                  Stylesheet charset imports (process_stmts f stmts)
74    
75  -- Process a list of Statements.  -- Process a list of Statements.
76  process_stmts :: [Statement] -> [Statement]  process_stmts :: ([Statement] -> [Statement]) -> [Statement] -> [Statement]
77  process_stmts stmts = (factor . filter is_ruleset) stmts ++  process_stmts f stmts = (f . filter is_ruleset) stmts ++
78                  (map process_media . filter is_media) stmts ++                  (map (process_media f) . filter is_media) stmts ++
79                  filter is_page stmts                  filter is_page stmts
80    
81  -- Process a Media Statement.  -- Process a Media Statement.
82  process_media :: Statement -> Statement  process_media :: ([Statement] -> [Statement]) -> Statement -> Statement
83  process_media (Media media stmts) = Media media (factor stmts)  process_media f (Media media stmts) = Media media (f stmts)
84    
85  -- Factor a list of Ruleset Statements.  -- Factor a list of Ruleset Statements.
86  factor :: [Statement] -> [Statement]  factor :: [Statement] -> [Statement]
# Line 72  cmp_decl (Ruleset sels0 (decl0:decls0)) Line 127  cmp_decl (Ruleset sels0 (decl0:decls0))
127  eq_sel :: Statement -> Statement -> Bool  eq_sel :: Statement -> Statement -> Bool
128  eq_sel z = (== EQ) . cmp_sel z  eq_sel z = (== EQ) . cmp_sel z
129    
130  -- Compare two Ruleset Statements for equality by the first declaration in each.  -- Compare two Ruleset Statements for equality by the first declaration in
131    -- each.
132  eq_decl :: Statement -> Statement -> Bool  eq_decl :: Statement -> Statement -> Bool
133  eq_decl z = (== EQ) . cmp_decl z  eq_decl z = (== EQ) . cmp_decl z
134    
# Line 86  eq_decl z = (== EQ) . cmp_decl z Line 142  eq_decl z = (== EQ) . cmp_decl z
142  implode_sel :: [Statement] -> Statement  implode_sel :: [Statement] -> Statement
143  implode_sel ((Ruleset sels decls):stmts) =  implode_sel ((Ruleset sels decls):stmts) =
144                  Ruleset sels (concat (decls:(map declarations stmts)))                  Ruleset sels (concat (decls:(map declarations stmts)))
         where   declarations :: Statement -> [Declaration]  
                 declarations (Ruleset s d) = d  
145    
146  -- Implode a list of Ruleset Statements with equal lists of Declarations to a  -- Implode a list of Ruleset Statements with equal lists of Declarations to a
147  -- single equivalent Ruleset Statement.  -- single equivalent Ruleset Statement.
# Line 99  implode_sel ((Ruleset sels decls):stmts) Line 153  implode_sel ((Ruleset sels decls):stmts)
153  implode_decl :: [Statement] -> Statement  implode_decl :: [Statement] -> Statement
154  implode_decl ((Ruleset sels decls):stmts) =  implode_decl ((Ruleset sels decls):stmts) =
155                  Ruleset (concat (sels:(map selectors stmts))) decls                  Ruleset (concat (sels:(map selectors stmts))) decls
156          where   selectors :: Statement -> [Selector]  
157                  selectors (Ruleset s d) = s  -- Count rulesets, selectors, and declarations in a Stylesheet.
158    stats :: Stylesheet -> String
159    stats (Stylesheet charset imports stmts)
160            | n == 0        = "0 rulesets"
161            | otherwise     = "rulesets " ++ show n ++
162                              ", selectors min " ++ show s0 ++
163                              " max " ++ show s1 ++
164                              " mean " ++ take 5 (
165                                    show (fromIntegral sn / fromIntegral n)) ++
166                              ", declarations min " ++ show d0 ++
167                              " max " ++ show d1 ++
168                              " mean " ++ take 5 (
169                                    show (fromIntegral dn / fromIntegral n))
170            where [n, s0, s1, sn, d0, d1, dn] = stats_stmts stmts
171    
172    -- Count rulesets, selectors, and declarations in a list of Statements.
173    stats_stmts :: [Statement] -> [Int]
174    stats_stmts stmts = stats_rulesets (filter is_ruleset stmts ++
175                    (concatMap get_stmts (filter is_media stmts)))
176                    where   get_stmts (Media media stmts) = stmts
177    
178    -- Count rulesets, selectors, and declarations in a list of Ruleset Statements.
179    stats_rulesets :: [Statement] -> [Int]
180    stats_rulesets stmts = [length stmts,
181                    minimum sel_lengths, maximum sel_lengths, sum sel_lengths,
182                    minimum decl_lengths, maximum decl_lengths, sum decl_lengths]
183                    where   sel_lengths = map (length . selectors) stmts
184                            decl_lengths = map (length . declarations) stmts
185    
186    -- Extract the list of Selectors from a Ruleset Statement.
187    selectors :: Statement -> [Selector]
188    selectors (Ruleset s d) = s
189    
190    -- Extract the list of Declarations from a Ruleset Statement.
191    declarations :: Statement -> [Declaration]
192    declarations (Ruleset s d) = d

Legend:
Removed from v.62  
changed lines
  Added in v.67

  ViewVC Help
Powered by ViewVC 1.1.26