Commit 90db3f19 authored by Taddeüs Kroes's avatar Taddeüs Kroes

Fixed parsing conflicts and stringification issues with @supports

parent 5d9a7709
......@@ -97,10 +97,13 @@ rule token = parse
| '@' K E Y F R A M E S { KEYFRAMES_SYM }
| '@' S U P P O R T S { SUPPORTS_SYM }
| (w | comment)* w A N D w (w | comment)* { SUPPORTS_AND }
| (w | comment)* w O R w (w | comment)* { SUPPORTS_OR }
| O N L Y { ONLY }
| N O T { NOT }
| A N D { AND }
| O R { OR }
(*| O R { OR } removed in favor of SUPPORTS_OR *)
| F R O M { FROM }
| T O { TO }
......
......@@ -53,7 +53,8 @@
%token <float * string> UNIT_VALUE
%token <string> COMBINATOR RELATION STRING IDENT HASH URI FUNCTION
%token LPAREN RPAREN LBRACE RBRACE LBRACK RBRACK SEMICOL COLON COMMA DOT PLUS
%token MINUS SLASH STAR ONLY AND OR NOT FROM TO EOF
%token MINUS SLASH STAR ONLY AND (*OR*) NOT FROM TO EOF
%token SUPPORTS_AND SUPPORTS_OR
(* Start symbol *)
%type <Types.stylesheet> stylesheet
......@@ -62,8 +63,12 @@
%%
(* list with arbitrary whitespace between elements and separators *)
%inline ig2(a, b): a b {}
%inline ig3(a, b, c): a b c {}
%inline wslist(sep, x): S* l=separated_list(sep, terminated(x, S*)) { l }
%inline wspreceded(prefix, x): p=preceded(pair(prefix, S*), x) { p }
%inline wspreceded(prefix, x): p=preceded(ig2(prefix, S*), x) { p }
%inline all_and: AND | SUPPORTS_AND {}
cd: CDO S* | CDC S* {}
......@@ -112,9 +117,9 @@ media_query_list:
| S* hd=media_query tl=wspreceded(COMMA, media_query)*
{ hd :: tl }
media_query:
| prefix=only_or_not? typ=media_type S* feat=wspreceded(AND, media_expr)*
| prefix=only_or_not? typ=media_type S* feat=wspreceded(all_and, media_expr)*
{ (prefix, Some typ, feat) }
| hd=media_expr tl=wspreceded(AND, media_expr)*
| hd=media_expr tl=wspreceded(all_and, media_expr)*
{ (None, None, (hd :: tl)) }
%inline only_or_not:
| ONLY S* { "only" }
......@@ -171,18 +176,21 @@ supports_negation:
| NOT S+ c=supports_condition_in_parens
{ Not c }
supports_conjunction:
| hd=supports_condition_in_parens tl=preceded(delimited(S+, AND, S+), supports_condition_in_parens)+
| hd=supports_condition_in_parens tl=preceded(SUPPORTS_AND, supports_condition_in_parens)+
{ And (hd :: tl) }
supports_disjunction:
| hd=supports_condition_in_parens tl=preceded(delimited(S+, OR, S+), supports_condition_in_parens)+
| hd=supports_condition_in_parens tl=preceded(SUPPORTS_OR, supports_condition_in_parens)+
{ Or (hd :: tl) }
supports_declaration_condition:
| LPAREN S* decl=declaration RPAREN
| LPAREN S* decl=supports_declaration RPAREN
{ Decl decl }
supports_declaration:
| name=property S* COLON S* value=expr
{ (name, value) }
(*XXX:
general_enclosed:
| ( FUNCTION | LPAREN ) ( any | unused )* RPAREN
{ }
{ Enclosed expr }
any:
[ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
......@@ -248,7 +256,7 @@ pseudo:
":" ^ f ^ "(" ^ arg ^ ")" }
declaration:
| name=property S* COLON S* value=expr important=boption(pair(IMPORTANT_SYM, S*))
| name=property S* COLON S* value=expr important=boption(ig2(IMPORTANT_SYM, S*))
{ (String.lowercase name, value, important) }
%inline property: name=IDENT { name }
......
......@@ -27,8 +27,7 @@ let rec filter_none = function
let add_parens s =
let l = String.length s in
if l > 0 & s.[0] = '(' & s.[l - 1] = ')'
then String.sub s 1 (l - 2)
else s
then s else "(" ^ s ^ ")"
(*
* Pretty-printing
......@@ -76,12 +75,24 @@ let string_of_media_query query =
| (Some pre, None, _) ->
failwith "unexpected media query prefix \"" ^ pre ^ "\""
let rec string_of_condition = function
| Not c -> "not " ^ add_parens (string_of_condition c)
| And c -> cat " and " (add_parens @@ string_of_condition) c
| Or c -> cat " or " (add_parens @@ string_of_condition) c
| Decl (name, value, false) -> "(" ^ name ^ ": " ^ string_of_expr value ^ ")"
| Decl (_, _, true) -> failwith "unexpected \"!important\""
let stringify_condition w c =
let rec transform =
let p c = `Parens (transform c) in
function
| Not c -> `Not (p c)
| And c -> `And (List.map p c)
| Or c -> `Or (List.map p c)
| Decl (name, value) -> `Decl (name, value)
in
let rec str = function
| `Not c -> "not " ^ str c
| `And c -> cat " and " str c
| `Or c -> cat " or " str c
| `Decl (name, value) -> "(" ^ name ^ ":" ^ w ^ string_of_expr value ^ ")"
| `Parens (`Decl _ as d) -> str d
| `Parens c -> "(" ^ str c ^ ")"
in
str (transform c)
let block = function "" -> " {}" | body -> " {\n" ^ indent body ^ "\n}"
......@@ -117,7 +128,7 @@ let rec string_of_statement = function
in
"@keyframes " ^ id ^ block (cat "\n\n" string_of_keyframe_ruleset rules)
| Supports (condition, statements) ->
"@supports " ^ string_of_condition condition ^
"@supports " ^ stringify_condition " " condition ^
block (cat "\n\n" string_of_statement statements)
let string_of_stylesheet = cat "\n\n" string_of_statement
......@@ -158,10 +169,9 @@ let minify_media_query query =
let rec minify_condition = function
| Not c -> "not " ^ add_parens (minify_condition c)
| And c -> cat "and " (add_parens @@ minify_condition) c
| Or c -> cat "or " (add_parens @@ minify_condition) c
| Decl (name, value, false) -> "(" ^ name ^ ":" ^ minify_expr value ^ ")"
| Decl (_, _, true) -> failwith "unexpected \"!important\""
| And c -> cat " and " (add_parens @@ minify_condition) c
| Or c -> cat " or " (add_parens @@ minify_condition) c
| Decl (name, value) -> "(" ^ name ^ ":" ^ minify_expr value ^ ")"
let rec minify_statement = function
| Ruleset (selectors, decls) ->
......@@ -189,7 +199,7 @@ let rec minify_statement = function
in
"@keyframes " ^ id ^ "{" ^ cat "" minify_keyframe_ruleset rules ^ "}"
| Supports (condition, statements) ->
"@supports " ^ minify_condition condition ^
"@supports " ^ stringify_condition "" condition ^
"{" ^ cat "" minify_statement statements ^ "}"
| statement -> string_of_statement statement
......
......@@ -22,11 +22,13 @@ type descriptor_declaration = string * expr
type keyframe_ruleset = expr * declaration list
type supports_declaration = string * expr
type condition =
| Not of condition
| And of condition list
| Or of condition list
| Decl of declaration
| Decl of supports_declaration
(*XXX: | Enclosed of expr*)
type statement =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment