ext/libsass/src/parser.cpp in sassc-1.9.0 vs ext/libsass/src/parser.cpp in sassc-1.10.0
- old
+ new
@@ -248,11 +248,13 @@
// ignore the @charset directive for now
else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
// generic at keyword (keep last)
- else if (lex< at_keyword >(true)) { (*block) << parse_at_rule(); }
+ else if (lex< re_special_directive >(true)) { (*block) << parse_special_directive(); }
+ else if (lex< re_prefixed_directive >(true)) { (*block) << parse_prefixed_directive(); }
+ else if (lex< at_keyword >(true)) { (*block) << parse_directive(); }
else if (block->is_root()) {
lex< css_whitespace >();
if (position >= end) return true;
css_error("Invalid CSS", " after ", ": expected 1 selector or at-rule, was ");
@@ -1323,14 +1325,11 @@
return parse_ie_property();
}
else if (peek< ie_keyword_arg >()) {
return parse_ie_keyword_arg();
}
- else if (peek< exactly< calc_kwd > >() ||
- peek< exactly< moz_calc_kwd > >() ||
- peek< exactly< ms_calc_kwd > >() ||
- peek< exactly< webkit_calc_kwd > >()) {
+ else if (peek< sequence < calc_fn_call, exactly <'('> > >()) {
return parse_calc_function();
}
else if (lex < functional_schema >()) {
return parse_function_call_schema();
}
@@ -1771,10 +1770,11 @@
std::string prefix("");
if (lex< uri_prefix >()) {
prefix = std::string(lexed);
}
+ lex < optional_spaces >();
String* url_string = parse_url_function_argument();
std::string suffix("");
if (lex< real_uri_suffix >()) {
suffix = std::string(lexed);
@@ -1807,11 +1807,11 @@
}
if (peek< exactly< hash_lbrace > >()) {
const char* pp = position;
// TODO: error checking for unclosed interpolants
- while (peek< exactly< hash_lbrace > >(pp)) {
+ while (pp && peek< exactly< hash_lbrace > >(pp)) {
pp = sequence< interpolant, real_uri_value >(pp);
}
position = pp;
return parse_interpolated_chunk(Token(p, position));
}
@@ -2140,17 +2140,18 @@
At_Root_Block* Parser::parse_at_root_block()
{
ParserState at_source_position = pstate;
Block* body = 0;
- At_Root_Expression* expr = 0;
+ At_Root_Query* expr = 0;
Lookahead lookahead_result;
LOCAL_FLAG(in_at_root, true);
- if (lex< exactly<'('> >()) {
- expr = parse_at_root_expression();
+ if (lex_css< exactly<'('> >()) {
+ expr = parse_at_root_query();
}
- if (peek < exactly<'{'> >()) {
+ if (peek_css < exactly<'{'> >()) {
+ lex <optional_spaces>();
body = parse_block(true);
}
else if ((lookahead_result = lookahead_for_selector(position)).found) {
Ruleset* r = parse_ruleset(lookahead_result, false);
body = SASS_MEMORY_NEW(ctx.mem, Block, r->pstate(), 1, true);
@@ -2159,41 +2160,43 @@
At_Root_Block* at_root = SASS_MEMORY_NEW(ctx.mem, At_Root_Block, at_source_position, body);
if (expr) at_root->expression(expr);
return at_root;
}
- At_Root_Expression* Parser::parse_at_root_expression()
+ At_Root_Query* Parser::parse_at_root_query()
{
if (peek< exactly<')'> >()) error("at-root feature required in at-root expression", pstate);
if (!peek< alternatives< kwd_with_directive, kwd_without_directive > >()) {
css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
}
- Declaration* declaration = parse_declaration();
- List* value = SASS_MEMORY_NEW(ctx.mem, List, declaration->value()->pstate(), 1);
+ Expression* feature = parse_list();
+ if (!lex_css< exactly<':'> >()) error("style declaration must contain a value", pstate);
+ Expression* expression = parse_list();
+ List* value = SASS_MEMORY_NEW(ctx.mem, List, feature->pstate(), 1);
- if (declaration->value()->concrete_type() == Expression::LIST) {
- value = static_cast<List*>(declaration->value());
+ if (expression->concrete_type() == Expression::LIST) {
+ value = static_cast<List*>(expression);
}
- else *value << declaration->value();
+ else *value << expression;
- At_Root_Expression* cond = SASS_MEMORY_NEW(ctx.mem, At_Root_Expression,
- declaration->pstate(),
- declaration->property(),
- value);
- if (!lex< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
+ At_Root_Query* cond = SASS_MEMORY_NEW(ctx.mem, At_Root_Query,
+ value->pstate(),
+ feature,
+ value);
+ if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
return cond;
}
- At_Rule* Parser::parse_at_rule()
+ Directive* Parser::parse_special_directive()
{
std::string kwd(lexed);
if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
- At_Rule* at_rule = SASS_MEMORY_NEW(ctx.mem, At_Rule, pstate, kwd);
+ Directive* at_rule = SASS_MEMORY_NEW(ctx.mem, Directive, pstate, kwd);
Lookahead lookahead = lookahead_for_include(position);
if (lookahead.found && !lookahead.has_interpolants) {
at_rule->selector(parse_selector_list(true));
}
@@ -2212,10 +2215,170 @@
}
return at_rule;
}
+ Directive* Parser::parse_prefixed_directive()
+ {
+ std::string kwd(lexed);
+
+ if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
+
+ Directive* at_rule = SASS_MEMORY_NEW(ctx.mem, Directive, pstate, kwd);
+ Lookahead lookahead = lookahead_for_include(position);
+ if (lookahead.found && !lookahead.has_interpolants) {
+ at_rule->selector(parse_selector_list(true));
+ }
+
+ lex < css_comments >(false);
+
+ if (lex < static_property >()) {
+ at_rule->value(parse_interpolated_chunk(Token(lexed)));
+ } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
+ at_rule->value(parse_list());
+ }
+
+ lex < css_comments >(false);
+
+ if (peek< exactly<'{'> >()) {
+ at_rule->block(parse_block());
+ }
+
+ return at_rule;
+ }
+
+
+ Directive* Parser::parse_directive()
+ {
+ Directive* directive = SASS_MEMORY_NEW(ctx.mem, Directive, pstate, lexed);
+ Expression* val = parse_almost_any_value();
+ // strip left and right if they are of type string
+ // debug_ast(val);
+ // std::cerr << "HAASDASD\n";
+ directive->value(val);
+ if (peek< exactly<'{'> >()) {
+ directive->block(parse_block());
+ } else if (!val) {
+ css_error("most def");
+ }
+ return directive;
+ }
+
+ Expression* Parser::lex_interpolation()
+ {
+ if (lex < interpolant >(true) != NULL) {
+ return parse_interpolated_chunk(lexed, true);
+ }
+ return 0;
+ }
+
+ Expression* Parser::lex_interp_uri()
+ {
+ // create a string schema by lexing optional interpolations
+ return lex_interp< re_string_uri_open, re_string_uri_close >();
+ }
+
+ Expression* Parser::lex_interp_string()
+ {
+ Expression* rv = 0;
+ if ((rv = lex_interp< re_string_double_open, re_string_double_close >()) != NULL) return rv;
+ if ((rv = lex_interp< re_string_single_open, re_string_single_close >()) != NULL) return rv;
+ return rv;
+ }
+
+ Expression* Parser::lex_almost_any_value_chars()
+ {
+ const char* match =
+ lex <
+ one_plus <
+ alternatives <
+ sequence <
+ exactly <'\\'>,
+ any_char
+ >,
+ sequence <
+ negate <
+ sequence <
+ exactly < url_kwd >,
+ exactly <'('>
+ >
+ >,
+ neg_class_char <
+ almost_any_value_class
+ >
+ >,
+ sequence <
+ exactly <'/'>,
+ negate <
+ alternatives <
+ exactly <'/'>,
+ exactly <'*'>
+ >
+ >
+ >,
+ sequence <
+ exactly <'\\'>,
+ exactly <'#'>,
+ negate <
+ exactly <'{'>
+ >
+ >,
+ sequence <
+ exactly <'!'>,
+ negate <
+ alpha
+ >
+ >
+ >
+ >
+ >(false);
+ if (match) {
+ // std::cerr << "[[" << std::string(lexed) << "]\n";
+ return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
+ }
+ return NULL;
+ }
+
+ Expression* Parser::lex_almost_any_value_token()
+ {
+ Expression* rv = 0;
+ if (*position == 0) return 0;
+ if ((rv = lex_almost_any_value_chars()) != NULL) return rv;
+ // if ((rv = lex_block_comment()) != NULL) return rv;
+ // if ((rv = lex_single_line_comment()) != NULL) return rv;
+ if ((rv = lex_interp_string()) != NULL) return rv;
+ if ((rv = lex_interp_uri()) != NULL) return rv;
+ if ((rv = lex_interpolation()) != NULL) return rv;
+ return rv;
+ }
+
+ String_Schema* Parser::parse_almost_any_value()
+ {
+
+ String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
+ if (*position == 0) return 0;
+ lex < spaces >(false);
+ Expression* token = lex_almost_any_value_token();
+ if (!token) return 0;
+ // std::cerr << "LEX [" << std::string(lexed) << "]\n";
+ *schema << token;
+ if (*position == 0) {
+ schema->rtrim();
+ return schema;
+ }
+
+ while ((token = lex_almost_any_value_token())) {
+ *schema << token;
+ }
+
+ lex < css_whitespace >();
+
+ schema->rtrim();
+
+ return schema;
+ }
+
Warning* Parser::parse_warning()
{
if (stack.back() != Scope::Root &&
stack.back() != Scope::Function &&
stack.back() != Scope::Mixin &&
@@ -2266,76 +2429,11 @@
const char* p = start ? start : position;
// match in one big "regex"
rv.error = p;
if (const char* q =
peek <
- alternatives <
- // partial BEM selector
- sequence <
- ampersand,
- one_plus <
- exactly < '-' >
- >,
- word_boundary
- >,
- // main selector matching
- one_plus <
- alternatives <
- // consume whitespace and comments
- spaces, block_comment, line_comment,
- // match `/deep/` selector (pass-trough)
- // there is no functionality for it yet
- schema_reference_combinator,
- // match selector ops /[*&%,()\[\]]/
- class_char < selector_lookahead_ops >,
- // match selector combinators /[>+~]/
- class_char < selector_combinator_ops >,
- // match attribute compare operators
- alternatives <
- exact_match, class_match, dash_match,
- prefix_match, suffix_match, substring_match
- >,
- // main selector match
- sequence <
- // allow namespace prefix
- optional < namespace_schema >,
- // modifiers prefixes
- alternatives <
- sequence <
- exactly <'#'>,
- // not for interpolation
- negate < exactly <'{'> >
- >,
- // class match
- exactly <'.'>,
- // single or double colon
- optional < pseudo_prefix >
- >,
- // accept hyphens in token
- one_plus < sequence <
- // can start with hyphens
- zero_plus < exactly<'-'> >,
- // now the main token
- alternatives <
- kwd_optional,
- exactly <'*'>,
- quoted_string,
- interpolant,
- identifier,
- variable,
- percentage,
- binomial,
- dimension,
- alnum
- >
- > >,
- // can also end with hyphens
- zero_plus < exactly<'-'> >
- >
- >
- >
- >
+ re_selector_list
>(p)
) {
while (p < q) {
// did we have interpolations?
if (*p == '#' && *(p+1) == '{') {
@@ -2351,10 +2449,11 @@
rv.error = q;
rv.position = q;
// check expected opening bracket
// only after successfull matching
if (peek < exactly<'{'> >(q)) rv.found = q;
+ else if (peek < exactly<'('> >(q)) rv.found = q;
// else if (peek < exactly<';'> >(q)) rv.found = q;
// else if (peek < exactly<'}'> >(q)) rv.found = q;
if (rv.found || *p == 0) rv.error = 0;
}
@@ -2364,10 +2463,10 @@
return rv;
}
// EO lookahead_for_selector
- // used in parse_block_nodes and parse_at_rule
+ // used in parse_block_nodes and parse_special_directive
// ToDo: actual usage is still not really clear to me?
Lookahead Parser::lookahead_for_include(const char* start)
{
// we actually just lookahead for a selector
Lookahead rv = lookahead_for_selector(start);