ext/libsass/src/parser.cpp in sassc-1.8.4 vs ext/libsass/src/parser.cpp in sassc-1.8.5

- old
+ new

@@ -198,11 +198,11 @@ else if (lex < kwd_while_directive >(true)) { (*block) << parse_while_directive(); } else if (lex < kwd_return_directive >(true)) { (*block) << parse_return_directive(); } // abort if we are in function context and have nothing parsed yet else if (stack.back() == Scope::Function) { - error("Functions can only contain variable declarations and control directives", pstate); + error("Functions can only contain variable declarations and control directives.", pstate); } // parse imports to process later else if (lex < kwd_import >(true)) { Scope parent = stack.empty() ? Scope::Rules : stack.back(); @@ -219,12 +219,11 @@ (*block) << SASS_MEMORY_NEW(ctx.mem, Import_Stub, pstate, imp->incs()[i]); } } else if (lex < kwd_extend >(true)) { - Scope parent = stack.empty() ? Scope::Rules : stack.back(); - if (parent == Scope::Root) { + if (block->is_root()) { error("Extend directives may only be used within rules.", pstate); } Lookahead lookahead = lookahead_for_include(position); if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was "); @@ -288,16 +287,11 @@ std::vector<std::pair<std::string,Function_Call*>> to_import; bool first = true; do { while (lex< block_comment >()); if (lex< quoted_string >()) { - if (!ctx.call_importers(unquote(std::string(lexed)), path, pstate, imp)) - { - // push single file import - // import_single_file(imp, lexed); - to_import.push_back(std::pair<std::string,Function_Call*>(std::string(lexed), 0)); - } + to_import.push_back(std::pair<std::string,Function_Call*>(std::string(lexed), 0)); } else if (lex< uri_prefix >()) { Arguments* args = SASS_MEMORY_NEW(ctx.mem, Arguments, pstate); Function_Call* result = SASS_MEMORY_NEW(ctx.mem, Function_Call, pstate, "url", args); @@ -331,11 +325,11 @@ } for(auto location : to_import) { if (location.second) { imp->urls().push_back(location.second); - } else { + } else if (!ctx.call_importers(unquote(location.first), path, pstate, imp)) { ctx.import_url(imp, location.first, path); } } return imp; @@ -343,11 +337,16 @@ Definition* Parser::parse_definition(Definition::Type which_type) { Scope parent = stack.empty() ? Scope::Rules : stack.back(); if (parent != Scope::Root && parent != Scope::Rules && parent != Scope::Function) { - error("Functions may not be defined within control directives or other mixins.", pstate); + if (which_type == Definition::FUNCTION) { + error("Functions may not be defined within control directives or other mixins.", pstate); + } else { + error("Mixins may not be defined within control directives or other mixins.", pstate); + } + } std::string which_str(lexed); if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate); std::string name(Util::normalize_underscores(lexed)); if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not")) @@ -613,11 +612,11 @@ had_linefeed = false; while (peek_css< exactly<','> >()) { lex< css_comments >(false); - // consume everything up and including the comma speparator + // consume everything up and including the comma separator reloop = lex< exactly<','> >() != 0; // remember line break (also between some commas) had_linefeed = had_linefeed || peek_newline(); // remember line break (also between some commas) } @@ -717,11 +716,11 @@ return sel; } // EO parse_complex_selector // parse one compound selector, which is basically - // a list of simple selectors (directly adjancent) + // a list of simple selectors (directly adjacent) // lex them exactly (without skipping white-space) Compound_Selector* Parser::parse_compound_selector() { // init an empty compound selector wrapper Compound_Selector* seq = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pstate); @@ -745,11 +744,11 @@ { // this produces a linefeed!? seq->has_parent_reference(true); (*seq) << SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate); // parent selector only allowed at start - // upcoming sass may allow also trailing + // upcoming Sass may allow also trailing if (seq->length() > 1) { ParserState state(pstate); Simple_Selector* cur = (*seq)[seq->length()-1]; Simple_Selector* prev = (*seq)[seq->length()-2]; std::string sel(prev->to_string({ NESTED, 5 })); @@ -832,11 +831,11 @@ name.erase(name.size() - 1); return SASS_MEMORY_NEW(ctx.mem, Wrapped_Selector, nsource_position, name, negated); } // a pseudo selector often starts with one or two colons - // it can contain more selectors inside parantheses + // it can contain more selectors inside parentheses Simple_Selector* Parser::parse_pseudo_selector() { if (lex< sequence< optional < pseudo_prefix >, // we keep the space within the name, strange enough // ToDo: refactor output to schedule the space for it @@ -1211,13 +1210,13 @@ : lex<kwd_neq>() ? Sass_OP::NEQ : lex<kwd_gte>() ? Sass_OP::GTE : lex<kwd_lte>() ? Sass_OP::LTE : lex<kwd_gt>() ? Sass_OP::GT : lex<kwd_lt>() ? Sass_OP::LT - // we checked the possibilites on top of fn + // we checked the possibilities on top of fn : Sass_OP::EQ; - // is directly adjancent to expression? + // is directly adjacent to expression? bool right_ws = peek < css_comments >() != NULL; operators.push_back({ op, left_ws, right_ws }); operands.push_back(parse_expression()); left_ws = peek < css_comments >() != NULL; } @@ -1236,11 +1235,10 @@ // parses multiple add and subtract operations // NOTE: make sure that identifiers starting with // NOTE: dashes do NOT count as subtract operation Expression* lhs = parse_operators(); // if it's a singleton, return it (don't wrap it) - // if it's a singleton, return it (don't wrap it) if (!(peek_css< exactly<'+'> >(position) || // condition is a bit misterious, but some combinations should not be counted as operations (peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) || (peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) || peek< sequence < zero_plus < exactly <'-' > >, identifier > >(position)) @@ -1306,11 +1304,10 @@ Expression* value = parse_map(); // lex the expected closing parenthesis if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate); // expression can be evaluated // make sure wrapped lists and division expressions are non-delayed within parentheses - // make sure wrapped lists and division expressions are non-delayed within parentheses if (value->concrete_type() == Expression::LIST) { // List* l = static_cast<List*>(value); // if (!l->empty()) (*l)[0]->is_delayed(false); } else if (typeid(*value) == typeid(Binary_Expression)) { Binary_Expression* b = static_cast<Binary_Expression*>(value); @@ -1414,11 +1411,11 @@ } if (lex< percentage >()) { return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::PERCENTAGE, lexed); } - // match hex number first because 0x000 looks like a number followed by an indentifier + // match hex number first because 0x000 looks like a number followed by an identifier if (lex< sequence < alternatives< hex, hex0 >, negate < exactly<'-'> > > >()) { return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::HEX, lexed); } if (lex< sequence < exactly <'#'>, identifier > >()) { return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, lexed); } @@ -1596,20 +1593,22 @@ if (peek<exactly<'}'>>()) { css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was "); } const char* e = 0; + const char* ee = end; + end = stop; size_t num_items = 0; bool need_space = false; while (position < stop) { // parse space between tokens if (lex< spaces >() && num_items) { need_space = true; } if (need_space) { need_space = false; - (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " "); + // (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " "); } if ((e = peek< re_functional >()) && e < stop) { (*schema) << parse_function_call(); } // lex an interpolant /#{...}/ @@ -1628,27 +1627,30 @@ (*schema) << ex; // ToDo: no error check here? lex < exactly < rbrace > >(); } // lex some string constants or other valid token - // Note: [-+] chars are left over from ie. `#{3}+3` + // Note: [-+] chars are left over from i.e. `#{3}+3` else if (lex< alternatives < exactly<'%'>, exactly < '-' >, exactly < '+' > > >()) { (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); } - else if (lex< sequence < identifier > >()) { - (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); + // lex a quoted string + else if (lex< quoted_string >()) { + // need_space = true; + // if (schema->length()) (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " "); + // else need_space = true; + (*schema) << parse_string(); if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) { - need_space = true; + // need_space = true; } + if (peek < exactly < '-' > >()) break; } - // lex a quoted string - else if (lex< quoted_string >()) { - (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, lexed, '"'); + else if (lex< sequence < identifier > >()) { + (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) { - need_space = true; + // need_space = true; } - if (peek < exactly < '-' > >()) return schema; } // lex (normalized) variable else if (lex< variable >()) { std::string name(Util::normalize_underscores(lexed)); (*schema) << SASS_MEMORY_NEW(ctx.mem, Variable, pstate, name); @@ -1675,14 +1677,19 @@ // lex a value in parentheses else if (peek< parenthese_scope >()) { (*schema) << parse_factor(); } else { - return schema; + break; } ++num_items; } + if (position != stop) { + (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(position, stop)); + position = stop; + } + end = ee; return schema; } // this parses interpolation outside other strings // means the result must not be quoted again later @@ -1771,18 +1778,23 @@ std::string suffix(""); if (lex< real_uri_suffix >()) { suffix = std::string(lexed); } + std::string uri(""); + if (url_string) { + uri = url_string->to_string({ NESTED, 5 }); + } + if (String_Schema* schema = dynamic_cast<String_Schema*>(url_string)) { String_Schema* res = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate); (*res) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, prefix); (*res) += schema; (*res) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, suffix); return res; } else { - std::string res = prefix + url_string->to_string({ NESTED, 5 }) + suffix; + std::string res = prefix + uri + suffix; return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, res); } } String* Parser::parse_url_function_argument() @@ -1892,22 +1904,22 @@ { // peek for dollar sign first if (!peek< exactly <'$'> >()) { css_error("Invalid CSS", " after ", ": expected \"$\", was "); } - // we expect a simple identfier as the call name + // we expect a simple identifier as the call name if (!lex< sequence < exactly <'$'>, identifier > >()) { lex< exactly <'$'> >(); // move pstate and position up css_error("Invalid CSS", " after ", ": expected identifier, was "); } // return object return token; } // helper to parse identifier Token Parser::lex_identifier() { - // we expect a simple identfier as the call name + // we expect a simple identifier as the call name if (!lex< identifier >()) { // ToDo: pstate wrong? css_error("Invalid CSS", " after ", ": expected identifier, was "); } // return object return token; @@ -2090,11 +2102,11 @@ return SASS_MEMORY_NEW(ctx.mem, Supports_Interpolation, pstate, interp); } // TODO: This needs some major work. Although feature conditions - // look like declarations their semantics differ siginificantly + // look like declarations their semantics differ significantly Supports_Condition* Parser::parse_supports_declaration() { Supports_Condition* cond = 0; // parse something declaration like Declaration* declaration = parse_declaration(); @@ -2130,11 +2142,10 @@ { ParserState at_source_position = pstate; Block* body = 0; At_Root_Expression* expr = 0; Lookahead lookahead_result; - // stack.push_back(Scope::Root); LOCAL_FLAG(in_at_root, true); if (lex< exactly<'('> >()) { expr = parse_at_root_expression(); } if (peek < exactly<'{'> >()) { @@ -2145,11 +2156,10 @@ body = SASS_MEMORY_NEW(ctx.mem, Block, r->pstate(), 1, true); *body << r; } At_Root_Block* at_root = SASS_MEMORY_NEW(ctx.mem, At_Root_Block, at_source_position, body); if (expr) at_root->expression(expr); - // stack.pop_back(); return at_root; } At_Root_Expression* Parser::parse_at_root_expression() { @@ -2257,11 +2267,11 @@ // match in one big "regex" rv.error = p; if (const char* q = peek < alternatives < - // partial bem selector + // partial BEM selector sequence < ampersand, one_plus < exactly < '-' > >, @@ -2298,11 +2308,11 @@ // class match exactly <'.'>, // single or double colon optional < pseudo_prefix > >, - // accept hypens in token + // accept hyphens in token one_plus < sequence < // can start with hyphens zero_plus < exactly<'-'> >, // now the main token alternatives < @@ -2387,23 +2397,31 @@ if (const char* q = peek < non_greedy < alternatives < // consume whitespace - block_comment, spaces, + block_comment, // spaces, // main tokens - interpolant, + sequence < + interpolant, + optional < + quoted_string + > + >, identifier, variable, // issue #442 sequence < parenthese_scope, - interpolant + interpolant, + optional < + quoted_string + > > >, sequence < - optional_spaces, + // optional_spaces, alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > @@ -2422,10 +2440,10 @@ } // store anyway // ToDo: remove rv.position = q; // check expected opening bracket - // only after successfull matching + // only after successful matching if (peek < exactly<'{'> >(q)) rv.found = q; else if (peek < exactly<';'> >(q)) rv.found = q; else if (peek < exactly<'}'> >(q)) rv.found = q; }