diff --git a/Makefile b/Makefile index 404517de9bad6f0e3e512c4283ccb26bbea00de0..d8cd24373e7418038cec2af596c4cd148cf5a272 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ RESULT := mincss PRE_TGTS := types -MODULES := color_names util stringify parser lexer parse color shorthand main +MODULES := color_names util stringify parser lexer parse color \ + shorthand main ALL_NAMES := $(PRE_TGTS) $(MODULES) OCAMLCFLAGS := -g diff --git a/parser.mly b/parser.mly index 3dac561b11e0a2085ef5f17ef355ca86b3410dc1..4b05e3f4e93a17f5a2369b38d62424b93e1b0f6f 100644 --- a/parser.mly +++ b/parser.mly @@ -37,6 +37,18 @@ | Unary ("-", Number (n, u)) -> Number (-.n, u) | Unary ("+", (Number _ as n)) -> n | value -> value + + let rec append_addons base = function + | [] -> + base + | `Id id :: tl -> + append_addons (Id (base, id)) tl + | `Class cls :: tl -> + append_addons (Class (base, cls)) tl + | `Attribute (attr, value) :: tl -> + append_addons (Attribute (base, attr, value)) tl + | `Pseudo (f, args) :: tl -> + append_addons (Pseudo (base, f, args)) tl %} (* Tokens *) @@ -207,39 +219,44 @@ ruleset: selector: | simple=simple_selector S* - { Simple simple } + { simple } | left=simple_selector S+ right=selector - { Combinator (Simple left, " ", right) } + { Combinator (left, " ", right) } | left=simple_selector S* com=combinator right=selector - { Combinator (Simple left, com, right) } + { Combinator (left, com, right) } %inline combinator: | PLUS S* { "+" } | c=COMBINATOR S* { c } simple_selector: | elem=element_name addons=element_addon* - { elem ^ String.concat "" addons } + { append_addons elem addons } | addons=element_addon+ - { String.concat "" addons } -%inline element_addon: a=HASH | a=cls | a=attrib | a=pseudo { a } + { append_addons No_element addons } +%inline element_addon: + | id=HASH { `Id id } + | addon=cls + | addon=attrib + | addon=pseudo { addon } element_name: - | tag=IDENT { String.lowercase tag } - | STAR { "*" } + | tag=IDENT { Element (String.lowercase tag) } + | STAR { All_elements } cls: | DOT name=IDENT - { "." ^ name } + { `Class name } attrib: - | LBRACK S* left=IDENT S* right=pair(RELATION, rel_value)? RBRACK - { let right = match right with None -> "" | Some (op, term) -> op ^ term in - "[" ^ String.lowercase left ^ right ^ "]" } + | LBRACK S* left=IDENT S* RBRACK + { `Attribute (String.lowercase left, None) } + | LBRACK S* left=IDENT S* op=RELATION right=rel_value RBRACK + { `Attribute (String.lowercase left, Some (op, right)) } %inline rel_value: - | S* id=IDENT S* { id } - | S* s=STRING S* { "\"" ^ s ^ "\"" } + | S* id=IDENT S* { Ident id } + | S* s=STRING S* { Strlit s } pseudo: | COLON id=IDENT - { ":" ^ (String.lowercase id) } + { `Pseudo (String.lowercase id, None) } | COLON f=FUNCTION args=wslist(COMMA, simple_selector) RPAREN - { ":" ^ String.lowercase f ^ "(" ^ String.concat "," args ^ ")" } + { `Pseudo (String.lowercase f, Some args) } declaration: | name=property S* COLON S* value=expr important=boption(ig2(IMPORTANT_SYM, S*)) diff --git a/stringify.ml b/stringify.ml index ad89086a00bbd13c269852945e7192c7e3e3c199..5e115d2c374c921fac7489040598437828f79ee2 100644 --- a/stringify.ml +++ b/stringify.ml @@ -39,12 +39,30 @@ let string_of_declaration (name, value, important) = let imp = if important then " !important" else "" in name ^ ": " ^ string_of_expr value ^ imp ^ ";" -let rec string_of_selector = function - | Simple simple -> simple +let rec stringify_selector w selector = + let str = stringify_selector w in + match selector with + | No_element -> "" + | All_elements -> "*" + | Element elem -> elem + | Id (base, id) -> + str base ^ "#" ^ id + | Class (base, cls) -> + str base ^ "." ^ cls + | Attribute (base, attr, None) -> + str base ^ "[" ^ attr ^ "]" + | Attribute (base, attr, Some (op, value)) -> + str base ^ "[" ^ attr ^ w ^ op ^ w ^ string_of_expr value ^ "]" + | Pseudo (base, sel, None) -> + str base ^ ":" ^ sel + | Pseudo (base, fn, Some args) -> + str base ^ ":" ^ fn ^ "(" ^ cat ("," ^ w) str args ^ ")" | Combinator (left, " ", right) -> - string_of_selector left ^ " " ^ string_of_selector right + str left ^ " " ^ str right | Combinator (left, com, right) -> - string_of_selector left ^ " " ^ com ^ " " ^ string_of_selector right + str left ^ w ^ com ^ w ^ str right + +let string_of_selector = stringify_selector " " let string_of_media_expr = function | (feature, None) -> "(" ^ feature ^ ")" @@ -140,10 +158,7 @@ let minify_declaration (name, value, important) = let imp = if important then "!important" else "" in name ^ ":" ^ minify_expr value ^ imp -let rec minify_selector = function - | Simple simple -> simple - | Combinator (left, com, right) -> - minify_selector left ^ com ^ minify_selector right +let rec minify_selector = stringify_selector "" let minify_media_feature = function | (feature, None) -> "(" ^ feature ^ ")" diff --git a/types.ml b/types.ml index fd2c87a0330ee9e3132cf3650543e213f3b04bac..657e5b70c310219f1f1649a87e89eb85ae5a4554 100644 --- a/types.ml +++ b/types.ml @@ -11,9 +11,21 @@ type expr = type declaration = string * expr * bool +type selector = + | No_element + | All_elements + | Element of string + | Id of selector * string + | Class of selector * string + | Pseudo of selector * string * selector list option + | Attribute of selector * string * (string * expr) option + | Combinator of selector * string * selector + + (* type selector = | Simple of string | Combinator of selector * string * selector + *) type media_expr = string * expr option type media_query = string option * string option * media_expr list diff --git a/util.ml b/util.ml index c4cd3e8a83e44018f2f2eb120340a6d2e06ab6b6..8d88d82804c998ead11b9417ed7fc0b0c61f2ced 100644 --- a/util.ml +++ b/util.ml @@ -132,12 +132,26 @@ let transform_stylesheet f stylesheet = in let TRAV_ALL(declaration, Declaration) in - let trav_selector = function - | Simple _ as s -> f (Selector s) + let rec trav_selector = function + | (No_element | All_elements | Element _) as elem -> + f (Selector elem) + | Id (base, id) -> + f (Selector (Id (expect_selector base, id))) + | Class (base, cls) -> + f (Selector (Class (expect_selector base, cls))) + | Attribute (base, attr, value) -> + f (Selector (Attribute (expect_selector base, attr, value))) + | Pseudo (base, sel, None) -> + f (Selector (Pseudo (expect_selector base, sel, None))) + | Pseudo (base, fn, Some args) -> + let args = trav_all_selector args in + f (Selector (Pseudo (expect_selector base, fn, Some args))) | Combinator (left, com, right) -> + let left = expect_selector left in + let right = expect_selector right in f (Selector (Combinator (left, com, right))) - in - let TRAV_ALL(selector, Selector) in + and EXPECT(selector, Selector) + and TRAV_ALL(selector, Selector) in let trav_media_expr = function | (_, None) as value ->