Commit b8630d7c by Aaron Leung

Handling pseudo-class and pseudo-elements.

parent 34346f60
...@@ -105,6 +105,7 @@ namespace Sass { ...@@ -105,6 +105,7 @@ namespace Sass {
Node parse_selector(); Node parse_selector();
Node parse_simple_selector_sequence(); Node parse_simple_selector_sequence();
Node parse_simple_selector(); Node parse_simple_selector();
Node parse_pseudo();
Node parse_attribute_selector(); Node parse_attribute_selector();
Node parse_block(); Node parse_block();
Node parse_rule(); Node parse_rule();
......
...@@ -89,11 +89,47 @@ namespace Sass { ...@@ -89,11 +89,47 @@ namespace Sass {
if (lex< id_name >() || lex< class_name >()) { if (lex< id_name >() || lex< class_name >()) {
return Node(line_number, Node::simple_selector, lexed); return Node(line_number, Node::simple_selector, lexed);
} }
else if (peek< exactly<':'> >(position)) {
return parse_pseudo();
}
else if (peek< exactly<'['> >(position)) { else if (peek< exactly<'['> >(position)) {
return parse_attribute_selector(); return parse_attribute_selector();
} }
} }
Node Document::parse_pseudo() {
if (lex< sequence< pseudo_prefix, functional > >()) {
Node pseudo(line_number, Node::functional_pseudo, 2);
pseudo << Node(line_number, Node::value, lexed);
if (lex< alternatives< even, odd > >()) {
pseudo << Node(line_number, Node::value, lexed);
}
else if (peek< binomial >(position)) {
lex< coefficient >();
pseudo << Node(line_number, Node::value, lexed);
lex< exactly<'n'> >();
pseudo << Node(line_number, Node::value, lexed);
lex< sign >();
pseudo << Node(line_number, Node::value, lexed);
lex< digits >();
pseudo << Node(line_number, Node::value, lexed);
}
else if (lex< sequence< optional<sign>,
optional<digits>,
exactly<'n'> > >()) {
pseudo << Node(line_number, Node::value, lexed);
}
else if (lex< sequence< optional<sign>, digits > >()) {
pseudo << Node(line_number, Node::value, lexed);
}
lex< exactly<')'> >();
return pseudo;
}
else if (lex < sequence< pseudo_prefix, identifier > >()) {
return Node(line_number, Node::pseudo, lexed);
}
}
Node Document::parse_attribute_selector() Node Document::parse_attribute_selector()
{ {
Node attr_sel(line_number, Node::attribute_selector, 3); Node attr_sel(line_number, Node::attribute_selector, 3);
......
...@@ -21,6 +21,8 @@ namespace Sass { ...@@ -21,6 +21,8 @@ namespace Sass {
type_selector, type_selector,
class_selector, class_selector,
id_selector, id_selector,
pseudo,
functional_pseudo,
attribute_selector, attribute_selector,
block, block,
rule, rule,
...@@ -144,6 +146,14 @@ namespace Sass { ...@@ -144,6 +146,14 @@ namespace Sass {
} }
return result; return result;
} }
else if (type == functional_pseudo) {
string result(string(children->at(0)));
for (int i = 1; i < children->size(); ++i) {
result += string(children->at(i));
}
result += ')';
return result;
}
else if (type == attribute_selector) { else if (type == attribute_selector) {
string result("["); string result("[");
result += string(children->at(0)); result += string(children->at(0));
......
...@@ -105,7 +105,10 @@ namespace Sass { ...@@ -105,7 +105,10 @@ namespace Sass {
return sequence<exactly<'.'>, identifier>(src); return sequence<exactly<'.'>, identifier>(src);
} }
// Match CSS numeric constants. // Match CSS numeric constants.
extern const char sign[] = "-+"; extern const char sign_chars[] = "-+";
char* sign(char* src) {
return class_char<sign_chars>(src);
}
char* unsigned_number(char* src) { char* unsigned_number(char* src) {
return alternatives<sequence< zero_plus<digits>, return alternatives<sequence< zero_plus<digits>,
exactly<'.'>, exactly<'.'>,
...@@ -113,7 +116,18 @@ namespace Sass { ...@@ -113,7 +116,18 @@ namespace Sass {
digits>(src); digits>(src);
} }
char* number(char* src) { char* number(char* src) {
return sequence< optional< class_char<sign> >, unsigned_number>(src); return sequence< optional<sign>, unsigned_number>(src);
}
char* coefficient(char* src) {
return alternatives< sequence< optional<sign>, digits >,
sign >(src);
}
char* binomial(char* src) {
return sequence< optional<sign>,
optional<digits>,
exactly<'n'>, optional_spaces,
sign, optional_spaces,
digits >(src);
} }
char* percentage(char* src) { char* percentage(char* src) {
return sequence< number, exactly<'%'> >(src); return sequence< number, exactly<'%'> >(src);
...@@ -135,10 +149,23 @@ namespace Sass { ...@@ -135,10 +149,23 @@ namespace Sass {
optional<spaces>, optional<spaces>,
exactly<')'> >(src); exactly<')'> >(src);
} }
// Match CSS pseudo-class/element prefixes.
char* pseudo_prefix(char* src) {
return sequence< exactly<':'>, optional< exactly<':'> > >(src);
}
// Match CSS function call openers. // Match CSS function call openers.
char* function(char* src) { char* functional(char* src) {
return sequence< identifier, exactly<'('> >(src); return sequence< identifier, exactly<'('> >(src);
} }
// Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
extern const char even_chars[] = "even";
extern const char odd_chars[] = "odd";
char* even(char* src) {
return exactly<even_chars>(src);
}
char* odd(char* src) {
return exactly<odd_chars>(src);
}
// Match CSS attribute-matching operators. // Match CSS attribute-matching operators.
extern const char tilde_equal[] = "~="; extern const char tilde_equal[] = "~=";
extern const char pipe_equal[] = "|="; extern const char pipe_equal[] = "|=";
......
...@@ -178,6 +178,32 @@ namespace Sass { ...@@ -178,6 +178,32 @@ namespace Sass {
return rslt; return rslt;
} }
// Same as above, but with 6 arguments.
template <prelexer mx1, prelexer mx2,
prelexer mx3, prelexer mx4,
prelexer mx5, prelexer mx6>
char* sequence(char* src) {
char* rslt = src;
(rslt = mx1(rslt)) && (rslt = mx2(rslt)) &&
(rslt = mx3(rslt)) && (rslt = mx4(rslt)) &&
(rslt = mx5(rslt)) && (rslt = mx6(rslt));
return rslt;
}
// Same as above, but with 7 arguments.
template <prelexer mx1, prelexer mx2,
prelexer mx3, prelexer mx4,
prelexer mx5, prelexer mx6,
prelexer mx7>
char* sequence(char* src) {
char* rslt = src;
(rslt = mx1(rslt)) && (rslt = mx2(rslt)) &&
(rslt = mx3(rslt)) && (rslt = mx4(rslt)) &&
(rslt = mx5(rslt)) && (rslt = mx6(rslt)) &&
(rslt = mx7(rslt));
return rslt;
}
// Match a pattern or not. Always succeeds. // Match a pattern or not. Always succeeds.
template <prelexer mx> template <prelexer mx>
char* optional(char* src) { char* optional(char* src) {
...@@ -249,15 +275,23 @@ namespace Sass { ...@@ -249,15 +275,23 @@ namespace Sass {
// Match CSS class names. // Match CSS class names.
char* class_name(char* src); char* class_name(char* src);
// Match CSS numeric constants. // Match CSS numeric constants.
char* sign(char* src);
char* unsigned_number(char* src); char* unsigned_number(char* src);
char* number(char* src); char* number(char* src);
char* coefficient(char* src);
char* binomial(char* src);
char* percentage(char* src); char* percentage(char* src);
char* dimension(char* src); char* dimension(char* src);
char* hex(char* src); char* hex(char* src);
// Match CSS uri specifiers. // Match CSS uri specifiers.
char* uri(char* src); char* uri(char* src);
// Match CSS pseudo-class/element prefixes
char* pseudo_prefix(char* src);
// Match CSS function call openers. // Match CSS function call openers.
char* function(char* src); char* functional(char* src);
// Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
char* even(char* src);
char* odd(char* src);
// Match CSS attribute-matching operators. // Match CSS attribute-matching operators.
char* exact_match(char* src); char* exact_match(char* src);
char* class_match(char* src); char* class_match(char* src);
......
a b {
color: red;
:first-child, :nth-of-type( -2n+1 ) {
.foo#bar:nth-child(even) {
hoo: goo;
}
blah: bloo;
::after {
content: "glux";
color: green;
}
}
}
\ No newline at end of file
Original Sass and libsass can produce different output for functional pseudo-classes. Original Sass does not normalize whitespace contained within an expression, and it also accepts invalid expressions. Libsass is stricter, and removes superfluous whitespace. E.g., on the following selector:
nth-child( 2n + 3 )
Original Sass produces:
nth-child(2n + 3)
whereas libsass produces:
nth-child(2n+3)
\ No newline at end of file
a b {
color: red; }
a b :first-child, a b :nth-of-type(-2n+1) {
blah: bloo; }
a b :first-child .foo#bar:nth-child(even), a b :nth-of-type(-2n+1) .foo#bar:nth-child(even) {
hoo: goo; }
a b :first-child ::after, a b :nth-of-type(-2n+1) ::after {
content: "glux";
color: green; }
...@@ -51,6 +51,9 @@ char var1[] = "$hello blah"; ...@@ -51,6 +51,9 @@ char var1[] = "$hello blah";
char nonvar1[] = "$ hello"; char nonvar1[] = "$ hello";
char anc1[] = " div {"; char anc1[] = " div {";
char nonanc1[] = " { blah"; char nonanc1[] = " { blah";
char bi1[] = "+2n + 42";
char bi2[] = "23n+1";
char nonbi1[] = "- n+2";
extern const char slash_star[] = "/*"; extern const char slash_star[] = "/*";
...@@ -84,7 +87,7 @@ int main() { ...@@ -84,7 +87,7 @@ int main() {
check_twice(percentage, percent1, dim1); check_twice(percentage, percent1, dim1);
check_twice(dimension, dim1, percent1); check_twice(dimension, dim1, percent1);
check_twice(uri, uri1, ident2); check_twice(uri, uri1, ident2);
check_twice(function, func1, ident2); check_twice(functional, func1, ident2);
check_twice(exact_match, exact1, inc1); check_twice(exact_match, exact1, inc1);
check_twice(class_match, inc1, pre1); check_twice(class_match, inc1, pre1);
check_twice(dash_match, dash1, suf1); check_twice(dash_match, dash1, suf1);
...@@ -96,6 +99,8 @@ int main() { ...@@ -96,6 +99,8 @@ int main() {
check_twice(hex, hex2, nonhex2); check_twice(hex, hex2, nonhex2);
check_twice(variable, var1, nonvar1); check_twice(variable, var1, nonvar1);
check_twice(ancestor_of, anc1, nonanc1); check_twice(ancestor_of, anc1, nonanc1);
check_twice(binomial, bi1, nonbi1);
check_twice(binomial, bi2, nonbi1);
cout << count_interval<'\n'>(ws1, spaces_and_comments(ws1)) << endl; cout << count_interval<'\n'>(ws1, spaces_and_comments(ws1)) << endl;
cout << count_interval<'*'>(ws1, spaces_and_comments(ws1)) << endl; cout << count_interval<'*'>(ws1, spaces_and_comments(ws1)) << endl;
cout << count_interval<exactly<slash_star> >(ws1, spaces_and_comments(ws1)) << endl; cout << count_interval<exactly<slash_star> >(ws1, spaces_and_comments(ws1)) << endl;
......
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