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);