Commit 8bc10a48 authored by Taddeüs Kroes's avatar Taddeüs Kroes

Added support for @font-face, @namespace, @keyframes + some general lexer/parser improvements

parent 79865573
...@@ -44,6 +44,34 @@ let name = nmchar+ ...@@ -44,6 +44,34 @@ let name = nmchar+
let num = ['0'-'9']+ | ['0'-'9']*'.'['0'-'9']+ let num = ['0'-'9']+ | ['0'-'9']*'.'['0'-'9']+
let url = (['!' '#' '$' '%' '&' '*'-'~'] | nonascii | escape)* let url = (['!' '#' '$' '%' '&' '*'-'~'] | nonascii | escape)*
let A = ['a' 'A']
let B = ['b' 'B']
let C = ['c' 'C']
let D = ['d' 'D']
let E = ['e' 'E']
let F = ['f' 'F']
let G = ['g' 'G']
let H = ['h' 'H']
let I = ['i' 'I']
let J = ['j' 'J']
let K = ['k' 'K']
let L = ['l' 'L']
let M = ['m' 'M']
let N = ['n' 'N']
let O = ['o' 'O']
let P = ['p' 'P']
let Q = ['q' 'Q']
let R = ['r' 'R']
let S = ['s' 'S']
let T = ['t' 'T']
let U = ['u' 'U']
let V = ['v' 'V']
let W = ['w' 'W']
let X = ['x' 'X']
let Y = ['y' 'Y']
let Z = ['z' 'Z']
rule token = parse rule token = parse
| s { S } | s { S }
...@@ -60,21 +88,27 @@ rule token = parse ...@@ -60,21 +88,27 @@ rule token = parse
| '#' (name as nm) { HASH nm } | '#' (name as nm) { HASH nm }
| "@import" { IMPORT_SYM } | '@' I M P O R T { IMPORT_SYM }
| "@page" { PAGE_SYM } | '@' P A G E { PAGE_SYM }
| "@media" { MEDIA_SYM } | '@' M E D I A { MEDIA_SYM }
| "@charset" { CHARSET_SYM } | "@charset " { CHARSET_SYM }
| '@' F O N T '-' F A C E { FONT_FACE_SYM }
| '@' N A M E S P A C E { NAMESPACE_SYM }
| '@' K E Y F R A M E S { KEYFRAMES_SYM }
| "only" { ONLY } | O N L Y { ONLY }
| "not" { NOT } | N O T { NOT }
| "and" { AND } | A N D { AND }
| F R O M { FROM }
| T O { TO }
| ident as id { IDENT id } | ident as id { IDENT id }
| '!' (w | comment)* "important" { IMPORTANT_SYM } | '!' (w | comment)* I M P O R T A N T { IMPORTANT_SYM }
| (num as n) ("em"|"ex"|"px"|"cm"|"mm"|"in"|"pt"|"pc"|"deg"|"rad"|"grad"| | (num as n) '%' { PERCENTAGE (float_of_string n) }
"ms"|"s"|"hz"|"khz"|"%"|"dpi"|"dpcm"|ident as u) | (num as n) (E M | E X | P X | C M | M M | I N | P T | P C | D E G |
G? R A D | M? S | K? H Z | D P (I | C M) | ident as u)
{ UNIT_VALUE (float_of_string n, u) } { UNIT_VALUE (float_of_string n, u) }
| num as n { NUMBER (float_of_string n) } | num as n { NUMBER (float_of_string n) }
......
...@@ -32,7 +32,7 @@ let parse_args () = ...@@ -32,7 +32,7 @@ let parse_args () =
let main () = let main () =
let args = parse_args () in let args = parse_args () in
try try
let css = let stylesheet =
match args.infiles with match args.infiles with
| [] -> | [] ->
let input = Util.input_buffered stdin 512 in let input = Util.input_buffered stdin 512 in
...@@ -42,12 +42,14 @@ let main () = ...@@ -42,12 +42,14 @@ let main () =
| [] -> [] | [] -> []
| filename :: tl -> | filename :: tl ->
let input = Util.input_all (open_in filename) in let input = Util.input_all (open_in filename) in
let css = Parse.parse_input filename input in let stylesheet = Parse.parse_input filename input in
css @ loop tl stylesheet @ loop tl
in in
loop files loop files
in in
Util.print_css css; print_endline (Stringify.string_of_stylesheet stylesheet);
print_endline "\n";
print_endline (Stringify.minify_stylesheet stylesheet);
exit 0 exit 0
with with
| LocError (loc, msg) -> | LocError (loc, msg) ->
......
...@@ -43,13 +43,13 @@ ...@@ -43,13 +43,13 @@
%} %}
(* Tokens *) (* Tokens *)
%token S CDO CDC IMPORT_SYM PAGE_SYM MEDIA_SYM CHARSET_SYM %token S CDO CDC IMPORT_SYM PAGE_SYM MEDIA_SYM CHARSET_SYM FONT_FACE_SYM
%token IMPORTANT_SYM %token NAMESPACE_SYM KEYFRAMES_SYM IMPORTANT_SYM
%token <float> NUMBER %token <float> PERCENTAGE NUMBER
%token <float * string> UNIT_VALUE %token <float * string> UNIT_VALUE
%token <string> COMBINATOR RELATION STRING IDENT HASH URI FUNCTION %token <string> COMBINATOR RELATION STRING IDENT HASH URI FUNCTION
%token LPAREN RPAREN LBRACE RBRACE LBRACK RBRACK SEMICOL COLON COMMA DOT PLUS %token LPAREN RPAREN LBRACE RBRACE LBRACK RBRACK SEMICOL COLON COMMA DOT PLUS
%token MINUS SLASH STAR ONLY AND NOT EOF %token MINUS SLASH STAR ONLY AND NOT FROM TO EOF
(* Start symbol *) (* Start symbol *)
%type <Types.stylesheet> stylesheet %type <Types.stylesheet> stylesheet
...@@ -66,17 +66,18 @@ cd: CDO S? | CDC S? {} ...@@ -66,17 +66,18 @@ cd: CDO S? | CDC S? {}
stylesheet: stylesheet:
| charset = charset? S? cd* | charset = charset? S? cd*
imports = terminated(import, cd*)* imports = terminated(import, cd*)*
namespaces = terminated(namespace, cd*)*
statements = terminated(statement, cd*)* statements = terminated(statement, cd*)*
EOF EOF
{ let charset = match charset with None -> [] | Some c -> [c] in { let charset = match charset with None -> [] | Some c -> [c] in
charset @ imports @ statements } charset @ imports @ namespaces @ statements }
statement: statement:
| s=ruleset | s=media | s=page | s=ruleset | s=media | s=page | s=font_face | s=keyframes
{ s } { s }
charset: charset:
| CHARSET_SYM S? name=STRING S? SEMICOL | CHARSET_SYM name=STRING S? SEMICOL
{ Charset name } { Charset name }
import: import:
...@@ -86,6 +87,13 @@ import: ...@@ -86,6 +87,13 @@ import:
| str=STRING { Strlit str } | str=STRING { Strlit str }
| uri=URI { Uri uri } | uri=URI { Uri uri }
namespace:
| NAMESPACE_SYM S? prefix=terminated(namespace_prefix, S?)? ns=string_or_uri S? SEMICOL S?
{ Namespace (prefix, ns) }
%inline namespace_prefix:
| prefix=IDENT
{ prefix }
media: media:
| MEDIA_SYM queries=media_query_list LBRACE S? rulesets=ruleset* RBRACE S? | MEDIA_SYM queries=media_query_list LBRACE S? rulesets=ruleset* RBRACE S?
{ Media (queries, rulesets) } { Media (queries, rulesets) }
...@@ -113,11 +121,29 @@ media_expr: ...@@ -113,11 +121,29 @@ media_expr:
page: page:
| PAGE_SYM S? pseudo=pseudo_page? decls=decls_block | PAGE_SYM S? pseudo=pseudo_page? decls=decls_block
{ Page (pseudo, decls) } { Page (pseudo, decls) }
pseudo_page: pseudo_page:
| COLON pseudo=IDENT S? | COLON pseudo=IDENT S?
{ pseudo } { pseudo }
font_face:
| FONT_FACE_SYM S? LBRACE S? hd=descriptor_declaration?
tl=wspreceded(SEMICOL, descriptor_declaration?)* RBRACE S?
{ Font_face (filter_none (hd :: tl)) }
descriptor_declaration:
| name=property COLON S? value=expr
{ (name, value) }
keyframes:
| KEYFRAMES_SYM S? id=IDENT S? LBRACE S? rules=keyframe_ruleset* RBRACE S?
{ Keyframes (id, rules) }
keyframe_ruleset:
| selector=keyframe_selector S? decls=decls_block
{ (selector, decls) }
keyframe_selector:
| FROM { Ident "from" }
| TO { Ident "to" }
| n=PERCENTAGE { Number (n, Some "%") }
%inline decls_block: %inline decls_block:
| LBRACE S? hd=declaration? tl=wspreceded(SEMICOL, declaration?)* RBRACE S? | LBRACE S? hd=declaration? tl=wspreceded(SEMICOL, declaration?)* RBRACE S?
{ filter_none (hd :: tl) } { filter_none (hd :: tl) }
...@@ -172,8 +198,9 @@ pseudo: ...@@ -172,8 +198,9 @@ pseudo:
":" ^ f ^ "(" ^ arg ^ ")" } ":" ^ f ^ "(" ^ arg ^ ")" }
declaration: declaration:
| name=IDENT S? COLON S? value=expr important=boption(pair(IMPORTANT_SYM, S?)) | name=property S? COLON S? value=expr important=boption(pair(IMPORTANT_SYM, S?))
{ (String.lowercase name, value, important) } { (String.lowercase name, value, important) }
%inline property: name=IDENT { name }
expr: expr:
| l=exprl { concat_terms l } | l=exprl { concat_terms l }
...@@ -187,28 +214,21 @@ expr: ...@@ -187,28 +214,21 @@ expr:
| COMMA S? { "," } | COMMA S? { "," }
term: term:
| op=unary_operator n=NUMBER S? | op=unary_operator v=numval S? { Unary (op, v) }
{ Unary (op, Number (n, None)) } | v=numval S? { v }
| op=unary_operator v=UNIT_VALUE S? | str=STRING S? { Strlit str }
{ let (n, u) = v in Unary (op, Number (n, Some u)) } | id=IDENT S? { Ident id }
| n=NUMBER S? | uri=URI S? { Uri uri }
{ Number (n, None) } | fn=FUNCTION arg=expr RPAREN S? { Function (fn, arg) }
| v=UNIT_VALUE S?
{ let (n, u) = v in Number (n, Some u) }
| str=STRING S?
{ Strlit str }
| id=IDENT S?
{ Ident id }
| uri=URI S?
{ Uri uri }
| fn=FUNCTION arg=expr RPAREN S?
{ Function (fn, arg) }
| hex=HASH S? | hex=HASH S?
{ let h = "[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]" in { let h = "[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]" in
if Str.string_match (Str.regexp ("^" ^ h ^ "\\(" ^ h ^ "\\)?$")) hex 0 if Str.string_match (Str.regexp ("^" ^ h ^ "\\(" ^ h ^ "\\)?$")) hex 0
then Hexcolor (String.lowercase hex) then Hexcolor (String.lowercase hex)
else raise (SyntaxError ("invalid color #" ^ hex)) } else raise (SyntaxError ("invalid color #" ^ hex)) }
unary_operator: unary_operator:
| MINUS { "-" } | MINUS { "-" }
| PLUS { "+" } | PLUS { "+" }
%inline numval:
| n=NUMBER { Number (n, None) }
| v=UNIT_VALUE { let n, u = v in Number (n, Some u) }
| n=PERCENTAGE { Number (n, Some "%") }
...@@ -68,7 +68,7 @@ let string_of_media_query query = ...@@ -68,7 +68,7 @@ let string_of_media_query query =
| (Some pre, None, _) -> | (Some pre, None, _) ->
failwith "unexpected media query prefix \"" ^ pre ^ "\"" failwith "unexpected media query prefix \"" ^ pre ^ "\""
let block body = " {\n" ^ indent body ^ "\n}" let block = function "" -> " {}" | body -> " {\n" ^ indent body ^ "\n}"
let rec string_of_statement = function let rec string_of_statement = function
| Ruleset (selectors, decls) -> | Ruleset (selectors, decls) ->
...@@ -87,12 +87,20 @@ let rec string_of_statement = function ...@@ -87,12 +87,20 @@ let rec string_of_statement = function
"@page" ^ block (cat "\n" string_of_declaration decls) "@page" ^ block (cat "\n" string_of_declaration decls)
| Page (Some pseudo, decls) -> | Page (Some pseudo, decls) ->
"@page :" ^ pseudo ^ block (cat "\n" string_of_declaration decls) "@page :" ^ pseudo ^ block (cat "\n" string_of_declaration decls)
| Fontface decls -> | Font_face decls ->
"@font-face " ^ block (cat "\n" string_of_declaration decls) let string_of_descriptor_declaration (name, value) =
name ^ ": " ^ string_of_expr value ^ ";"
in
"@font-face" ^ block (cat "\n" string_of_descriptor_declaration decls)
| Namespace (None, uri) -> | Namespace (None, uri) ->
"@namespace \"" ^ uri ^ "\";" "@namespace " ^ string_of_expr uri ^ ";"
| Namespace (Some prefix, uri) -> | Namespace (Some prefix, uri) ->
"@namespace " ^ prefix ^ " \"" ^ uri ^ "\";" "@namespace " ^ prefix ^ " " ^ string_of_expr uri ^ ";"
| Keyframes (id, rules) ->
let string_of_keyframe_ruleset (expr, decls) =
string_of_expr expr ^ block (cat "\n" string_of_declaration decls)
in
"@keyframes " ^ id ^ block (cat "\n\n" string_of_keyframe_ruleset rules)
let string_of_stylesheet = cat "\n\n" string_of_statement let string_of_stylesheet = cat "\n\n" string_of_statement
...@@ -133,10 +141,10 @@ let minify_media_query query = ...@@ -133,10 +141,10 @@ let minify_media_query query =
let rec minify_statement = function let rec minify_statement = function
| Ruleset (selectors, decls) -> | Ruleset (selectors, decls) ->
cat "," minify_selector selectors ^ cat "," minify_selector selectors ^
"{" ^ (cat ";" minify_declaration decls) ^ "}" "{" ^ cat ";" minify_declaration decls ^ "}"
| Media (queries, rulesets) -> | Media (queries, rulesets) ->
"@media" ^ prefix_space (cat "," minify_media_query queries) ^ "@media" ^ prefix_space (cat "," minify_media_query queries) ^
"{" ^ (cat "" minify_statement rulesets) ^ "}" "{" ^ cat "" minify_statement rulesets ^ "}"
| Import (target, []) -> | Import (target, []) ->
"@import " ^ string_of_expr target ^ ";" "@import " ^ string_of_expr target ^ ";"
| Import (target, queries) -> | Import (target, queries) ->
...@@ -145,8 +153,16 @@ let rec minify_statement = function ...@@ -145,8 +153,16 @@ let rec minify_statement = function
"@page{" ^ cat "" minify_declaration decls ^ "}" "@page{" ^ cat "" minify_declaration decls ^ "}"
| Page (Some pseudo, decls) -> | Page (Some pseudo, decls) ->
"@page :" ^ pseudo ^ "{" ^ cat "" minify_declaration decls ^ "}" "@page :" ^ pseudo ^ "{" ^ cat "" minify_declaration decls ^ "}"
| Fontface decls -> | Font_face decls ->
"@font-face{" ^ cat "" minify_declaration decls ^ "}" let minify_descriptor_declaration (name, value) =
name ^ ":" ^ string_of_expr value
in
"@font-face{" ^ cat ";" minify_descriptor_declaration decls ^ "}"
| Keyframes (id, rules) ->
let minify_keyframe_ruleset (expr, decls) =
minify_expr expr ^ "{" ^ cat ";" minify_declaration decls ^ "}"
in
"@keyframes " ^ id ^ "{" ^ cat "" minify_keyframe_ruleset rules ^ "}"
| statement -> string_of_statement statement | statement -> string_of_statement statement
let minify_stylesheet = cat "" minify_statement let minify_stylesheet = cat "" minify_statement
...@@ -18,6 +18,10 @@ type selector = ...@@ -18,6 +18,10 @@ type selector =
type media_expr = string * expr option type media_expr = string * expr option
type media_query = string option * string option * media_expr list type media_query = string option * string option * media_expr list
type descriptor_declaration = string * expr
type keyframe_ruleset = expr * declaration list
type statement = type statement =
| Ruleset of selector list * declaration list | Ruleset of selector list * declaration list
(* <selectors> { <declarations> } *) (* <selectors> { <declarations> } *)
...@@ -29,11 +33,12 @@ type statement = ...@@ -29,11 +33,12 @@ type statement =
(* @charset "<charset>"; *) (* @charset "<charset>"; *)
| Page of string option * declaration list | Page of string option * declaration list
(* @page [<pseudo_page>] { <declarations> } *) (* @page [<pseudo_page>] { <declarations> } *)
| Fontface of declaration list | Font_face of descriptor_declaration list
(* @font-face { <declarations> } *) (* @font-face { <declarations> } *)
| Namespace of string option * string | Namespace of string option * expr
(* @namespace [<prefix>] "<uri>"; *) (* @namespace [<prefix>] "<uri>"; *)
(* TODO: @document, @keyframes, @supports *) | Keyframes of string * keyframe_ruleset list
(* TODO: @document, @supports *)
type stylesheet = statement list type stylesheet = statement list
......
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