CSS-Sass

 view release on metacpan or  search on metacpan

libsass/parser.cpp  view on Meta::CPAN

          exactly<'+'>,
          exactly<'~'>,
          exactly<'>'>
        > >())
    // no selector before the combinator
    { lhs = 0; }
    else {
      lhs = parse_simple_selector_sequence();
      sel_source_position = before_token;
      lhs->has_line_break(peek_newline());
    }

    Complex_Selector::Combinator cmb;
    if      (lex< exactly<'+'> >()) cmb = Complex_Selector::ADJACENT_TO;
    else if (lex< exactly<'~'> >()) cmb = Complex_Selector::PRECEDES;
    else if (lex< exactly<'>'> >()) cmb = Complex_Selector::PARENT_OF;
    else                            cmb = Complex_Selector::ANCESTOR_OF;
    bool cpx_lf = peek_newline();

    Complex_Selector* rhs;
    if (peek_css< alternatives <
                exactly<','>,
                exactly<')'>,
                exactly<'{'>,
                exactly<'}'>,
                exactly<';'>,
                optional
        > >())
    // no selector after the combinator
    { rhs = 0; }
    else {
      rhs = parse_selector_combination();
      sel_source_position = before_token;
    }
    if (!sel_source_position.line) sel_source_position = before_token;
    Complex_Selector* cpx = new (ctx.mem) Complex_Selector(ParserState(path, source, sel_source_position), cmb, lhs, rhs);
    cpx->media_block(last_media_block);
    cpx->last_block(block_stack.back());
    if (cpx_lf) cpx->has_line_break(cpx_lf);
    return cpx;
  }

  Compound_Selector* Parser::parse_simple_selector_sequence()
  {
    Compound_Selector* seq = new (ctx.mem) Compound_Selector(pstate);
    seq->media_block(last_media_block);
    seq->last_block(block_stack.back());
    bool sawsomething = false;
    if (lex< exactly<'&'> >()) {
      // check if we have a parent selector on the root level block
      if (block_stack.back() && block_stack.back()->is_root()) {
        //error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate);
      }
      (*seq) << new (ctx.mem) Selector_Reference(pstate);
      sawsomething = true;
      // if you see a space after a &, then you're done
      if(peek< spaces >() || peek< alternatives < spaces, exactly<';'> > >()) {
        return seq;
      }
    }
    if (sawsomething && lex_css< sequence< negate< functional >, alternatives< identifier_alnums, universal, quoted_string, dimension, percentage, number > > >()) {
      // saw an ampersand, then allow type selectors with arbitrary number of hyphens at the beginning
      (*seq) << new (ctx.mem) Type_Selector(pstate, unquote(lexed));
    } else if (lex_css< sequence< negate< functional >, alternatives< type_selector, universal, quoted_string, dimension, percentage, number > > >()) {
      // if you see a type selector
      (*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
      sawsomething = true;
    }
    if (!sawsomething) {
      // don't blindly do this if you saw a & or selector
      (*seq) << parse_simple_selector();
    }

    while (!peek< spaces >(position) &&
           !(peek_css < alternatives <
               exactly<'+'>,
               exactly<'~'>,
               exactly<'>'>,
               exactly<','>,
               exactly<')'>,
               exactly<'{'>,
               exactly<'}'>,
               exactly<';'>
             > >(position))) {
      (*seq) << parse_simple_selector();
    }
    return seq;
  }

  Simple_Selector* Parser::parse_simple_selector()
  {
    lex < css_comments >();
    if (lex< alternatives < id_name, class_name > >()) {
      return new (ctx.mem) Selector_Qualifier(pstate, unquote(lexed));
    }
    else if (lex< quoted_string >()) {
      return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
    }
    else if (lex< alternatives < number, kwd_sel_deep > >()) {
      return new (ctx.mem) Type_Selector(pstate, lexed);
    }
    else if (peek< pseudo_not >()) {
      return parse_negated_selector();
    }
    else if (peek< exactly<':'> >(position) || peek< functional >()) {
      return parse_pseudo_selector();
    }
    else if (peek< exactly<'['> >(position)) {
      return parse_attribute_selector();
    }
    else if (lex< placeholder >()) {
      Selector_Placeholder* sel = new (ctx.mem) Selector_Placeholder(pstate, unquote(lexed));
      sel->media_block(last_media_block);
      sel->last_block(block_stack.back());
      return sel;
    }
    else {
      error("invalid selector after " + lexed.to_string(), pstate);
    }
    // unreachable statement
    return 0;
  }

  Wrapped_Selector* Parser::parse_negated_selector()

libsass/parser.cpp  view on Meta::CPAN

             peek< exactly< webkit_calc_kwd > >()) {
      return parse_calc_function();
    }
    else if (peek< functional_schema >()) {
      return parse_function_call_schema();
    }
    else if (peek< sequence< identifier_schema, negate< exactly<'%'> > > >()) {
      return parse_identifier_schema();
    }
    else if (peek< functional >()) {
      return parse_function_call();
    }
    else if (lex< sequence< exactly<'+'>, optional_css_whitespace, negate< number > > >()) {
      return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::PLUS, parse_factor());
    }
    else if (lex< sequence< exactly<'-'>, optional_css_whitespace, negate< number> > >()) {
      return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_factor());
    }
    else if (lex< sequence< kwd_not, css_whitespace > >()) {
      return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::NOT, parse_factor());
    }
    else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
      if (parse_number_prefix()) return parse_value(); // prefix is positive
      return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_value());
    }
    else {
      return parse_value();
    }
  }

  Expression* Parser::parse_value()
  {
    lex< css_comments >();
    if (lex< ampersand >())
    {
      return new (ctx.mem) Parent_Selector(pstate, parse_selector_group()); }

    if (lex< important >())
    { return new (ctx.mem) String_Constant(pstate, "!important"); }

    const char* stop;
    if ((stop = peek< value_schema >()))
    { return parse_value_schema(stop); }

    if (lex< kwd_true >())
    { return new (ctx.mem) Boolean(pstate, true); }

    if (lex< kwd_false >())
    { return new (ctx.mem) Boolean(pstate, false); }

    if (lex< kwd_null >())
    { return new (ctx.mem) Null(pstate); }

    if (lex< identifier >()) {
      String_Constant* str = new (ctx.mem) String_Quoted(pstate, lexed);
      // Dont' delay this string if it is a name color. Fixes #652.
      str->is_delayed(ctx.names_to_colors.count(unquote(lexed)) == 0);
      return str;
    }

    if (lex< percentage >())
    { return new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed); }

    // match hex number first because 0x000 looks like a number followed by an indentifier
    if (lex< alternatives< hex, hex0 > >())
    { return new (ctx.mem) Textual(pstate, Textual::HEX, lexed); }

    // also handle the 10em- foo special case
    if (lex< sequence< dimension, optional< sequence< exactly<'-'>, negate< digit > > > > >())
    { return new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed); }

    if (lex< number >())
    { return new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed); }

    if (peek< quoted_string >())
    { return parse_string(); }

    if (lex< variable >())
    { return new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed)); }

    // Special case handling for `%` proceeding an interpolant.
    if (lex< sequence< exactly<'%'>, optional< percentage > > >())
    { return new (ctx.mem) String_Quoted(pstate, lexed); }

    error("error reading values after " + lexed.to_string(), pstate);

    // unreachable statement
    return 0;
  }

  // this parses interpolation inside other strings
  // means the result should later be quoted again
  String* Parser::parse_interpolated_chunk(Token chunk, bool constant)
  {
    const char* i = chunk.begin;
    // see if there any interpolants
    const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
    if (!p) {
      String_Quoted* str_quoted = new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
      if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
      str_quoted->is_delayed(true);
      return str_quoted;
    }

    String_Schema* schema = new (ctx.mem) String_Schema(pstate);
    while (i < chunk.end) {
      p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
      if (p) {
        if (i < p) {
          // accumulate the preceding segment if it's nonempty
          (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
        }
        // we need to skip anything inside strings
        // create a new target in parser/prelexer
        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
        if (j) { --j;
          // parse the interpolant and accumulate it
          Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
          interp_node->is_interpolant(true);
          (*schema) << interp_node;
          i = j;
        }
        else {
          // throw an error if the interpolant is unterminated
          error("unterminated interpolant inside string constant " + chunk.to_string(), pstate);
        }
      }
      else { // no interpolants left; add the last segment if nonempty
        // check if we need quotes here (was not sure after merge)
        if (i < chunk.end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
        break;
      }
      ++ i;
    }
    return schema;
  }

  String_Constant* Parser::parse_static_value()
  {
    lex< static_value >();
    Token str(lexed);
    --str.end;

libsass/parser.cpp  view on Meta::CPAN

        if (i < p) {
          (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
        }
        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
        if (j) {
          // parse the interpolant and accumulate it
          Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
          interp_node->is_interpolant(true);
          (*schema) << interp_node;
          i = j;
        }
        else {
          // throw an error if the interpolant is unterminated
          error("unterminated interpolant inside IE function " + str.to_string(), pstate);
        }
      }
      else { // no interpolants left; add the last segment if nonempty
        if (i < str.end) (*schema) << new (ctx.mem) String_Constant(pstate, string(i, str.end));
        break;
      }
    }
    return schema;
  }

  String* Parser::parse_ie_keyword_arg()
  {
    String_Schema* kwd_arg = new (ctx.mem) String_Schema(pstate, 3);
    if (lex< variable >()) {
      *kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
    } else {
      lex< alternatives< identifier_schema, identifier > >();
      *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
    }
    lex< exactly<'='> >();
    *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
    if (peek< variable >()) *kwd_arg << parse_list();
    else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
    else if (lex< alternatives< identifier_schema, identifier, number, hexa, hex > >()) {
      *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
    }
    return kwd_arg;
  }

  String_Schema* Parser::parse_value_schema(const char* stop)
  {
    String_Schema* schema = new (ctx.mem) String_Schema(pstate);
    size_t num_items = 0;
    while (position < stop) {
      if (lex< interpolant >()) {
        Token insides(Token(lexed.begin + 2, lexed.end - 1));
        Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
        interp_node->is_interpolant(true);
        (*schema) << interp_node;
      }
      else if (lex< exactly<'%'> >()) {
        (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
      }
      else if (lex< identifier >()) {
        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
      }
      else if (lex< percentage >()) {
        (*schema) << new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed);
      }
      else if (lex< dimension >()) {
        (*schema) << new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed);
      }
      else if (lex< number >()) {
        (*schema) << new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
      }
      else if (lex< hex >()) {
        (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
      }
      else if (lex< quoted_string >()) {
        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
      }
      else if (lex< variable >()) {
        (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
      }
      else {
        error("error parsing interpolated value", pstate);
      }
      ++num_items;
    }
    return schema;
  }

  /* not used anymore - remove?
  String_Schema* Parser::parse_url_schema()
  {
    String_Schema* schema = new (ctx.mem) String_Schema(pstate);

    while (position < end) {
      if (position[0] == '/') {
        lexed = Token(position, position+1, before_token);
        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
        ++position;
      }
      else if (lex< interpolant >()) {
        Token insides(Token(lexed.begin + 2, lexed.end - 1, before_token));
        Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
        interp_node->is_interpolant(true);
        (*schema) << interp_node;
      }
      else if (lex< sequence< identifier, exactly<':'> > >()) {
        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
      }
      else if (lex< filename >()) {
        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
      }
      else {
        error("error parsing interpolated url", pstate);
      }
    }
    return schema;
  } */

  // this parses interpolation outside other strings
  // means the result must not be quoted again later
  String* Parser::parse_identifier_schema()
  {
    // first lex away whatever we have found

libsass/parser.cpp  view on Meta::CPAN

  }

  At_Rule* Parser::parse_at_rule()
  {
    lex<at_keyword>();
    string kwd(lexed);
    ParserState at_source_position = pstate;
    Selector* sel = 0;
    Expression* val = 0;
    Selector_Lookahead lookahead = lookahead_for_extension_target(position);
    if (lookahead.found) {
      if (lookahead.has_interpolants) {
        sel = parse_selector_schema(lookahead.found);
      }
      else {
        sel = parse_selector_group();
      }
    }
    else if (!(peek<exactly<'{'> >() || peek<exactly<'}'> >() || peek<exactly<';'> >())) {
      val = parse_list();
    }
    Block* body = 0;
    if (peek< exactly<'{'> >()) body = parse_block();
    At_Rule* rule = new (ctx.mem) At_Rule(at_source_position, kwd, sel, body);
    if (!sel) rule->value(val);
    return rule;
  }

  Warning* Parser::parse_warning()
  {
    lex< kwd_warn >();
    return new (ctx.mem) Warning(pstate, parse_list());
  }

  Error* Parser::parse_error()
  {
    lex< kwd_err >();
    return new (ctx.mem) Error(pstate, parse_list());
  }

  Debug* Parser::parse_debug()
  {
    lex< kwd_dbg >();
    return new (ctx.mem) Debug(pstate, parse_list());
  }

  Selector_Lookahead Parser::lookahead_for_selector(const char* start)
  {
    const char* p = start ? start : position;
    const char* q;
    bool saw_stuff = false;
    bool saw_interpolant = false;

    while ((q = peek< identifier >(p))                             ||
           (q = peek< hyphens_and_identifier >(p))                 ||
           (q = peek< hyphens_and_name >(p))                       ||
           (q = peek< type_selector >(p))                          ||
           (q = peek< id_name >(p))                                ||
           (q = peek< class_name >(p))                             ||
           (q = peek< sequence< pseudo_prefix, identifier > >(p))  ||
           (q = peek< percentage >(p))                             ||
           (q = peek< dimension >(p))                              ||
           (q = peek< quoted_string >(p))                          ||
           (q = peek< exactly<'*'> >(p))                           ||
           (q = peek< exactly<sel_deep_kwd> >(p))                           ||
           (q = peek< exactly<'('> >(p))                           ||
           (q = peek< exactly<')'> >(p))                           ||
           (q = peek< exactly<'['> >(p))                           ||
           (q = peek< exactly<']'> >(p))                           ||
           (q = peek< exactly<'+'> >(p))                           ||
           (q = peek< exactly<'~'> >(p))                           ||
           (q = peek< exactly<'>'> >(p))                           ||
           (q = peek< exactly<','> >(p))                           ||
           (saw_stuff && (q = peek< exactly<'-'> >(p)))            ||
           (q = peek< binomial >(p))                               ||
           (q = peek< block_comment >(p))                          ||
           (q = peek< sequence< optional<sign>,
                                zero_plus<digit>,
                                exactly<'n'> > >(p))               ||
           (q = peek< sequence< optional<sign>,
                                one_plus<digit> > >(p))                     ||
           (q = peek< number >(p))                                 ||
           (q = peek< sequence< exactly<'&'>,
                                identifier_alnums > >(p))        ||
           (q = peek< exactly<'&'> >(p))                           ||
           (q = peek< exactly<'%'> >(p))                           ||
           (q = peek< alternatives<exact_match,
                                   class_match,
                                   dash_match,
                                   prefix_match,
                                   suffix_match,
                                   substring_match> >(p))          ||
           (q = peek< sequence< exactly<'.'>, interpolant > >(p))  ||
           (q = peek< sequence< exactly<'#'>, interpolant > >(p))  ||
           (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p))  ||
           (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
           (q = peek< interpolant >(p))) {
      saw_stuff = true;
      p = q;
      if (*(p - 1) == '}') saw_interpolant = true;
    }

    Selector_Lookahead result;
    result.found            = saw_stuff && peek< exactly<'{'> >(p) ? p : 0;
    result.has_interpolants = saw_interpolant;

    return result;
  }

  Selector_Lookahead Parser::lookahead_for_extension_target(const char* start)
  {
    const char* p = start ? start : position;
    const char* q;
    bool saw_interpolant = false;
    bool saw_stuff = false;

    while ((q = peek< identifier >(p))                             ||
           (q = peek< type_selector >(p))                          ||
           (q = peek< id_name >(p))                                ||
           (q = peek< class_name >(p))                             ||
           (q = peek< sequence< pseudo_prefix, identifier > >(p))  ||
           (q = peek< percentage >(p))                             ||
           (q = peek< dimension >(p))                              ||
           (q = peek< quoted_string >(p))                          ||
           (q = peek< exactly<'*'> >(p))                           ||
           (q = peek< exactly<'('> >(p))                           ||
           (q = peek< exactly<')'> >(p))                           ||
           (q = peek< exactly<'['> >(p))                           ||
           (q = peek< exactly<']'> >(p))                           ||
           (q = peek< exactly<'+'> >(p))                           ||
           (q = peek< exactly<'~'> >(p))                           ||
           (q = peek< exactly<'>'> >(p))                           ||
           (q = peek< exactly<','> >(p))                           ||
           (saw_stuff && (q = peek< exactly<'-'> >(p)))            ||
           (q = peek< binomial >(p))                               ||
           (q = peek< block_comment >(p))                          ||
           (q = peek< sequence< optional<sign>,
                                zero_plus<digit>,
                                exactly<'n'> > >(p))               ||
           (q = peek< sequence< optional<sign>,
                                one_plus<digit> > >(p))                     ||
           (q = peek< number >(p))                                 ||
           (q = peek< sequence< exactly<'&'>,
                                identifier_alnums > >(p))        ||
           (q = peek< exactly<'&'> >(p))                           ||
           (q = peek< exactly<'%'> >(p))                           ||
           (q = peek< alternatives<exact_match,
                                   class_match,
                                   dash_match,
                                   prefix_match,
                                   suffix_match,
                                   substring_match> >(p))          ||
           (q = peek< sequence< exactly<'.'>, interpolant > >(p))  ||
           (q = peek< sequence< exactly<'#'>, interpolant > >(p))  ||
           (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p))  ||
           (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
           (q = peek< interpolant >(p))                            ||
           (q = peek< optional >(p))) {
      p = q;
      if (*(p - 1) == '}') saw_interpolant = true;
      saw_stuff = true;
    }

    Selector_Lookahead result;
    result.found            = peek< alternatives< exactly<';'>, exactly<'}'>, exactly<'{'> > >(p) && saw_stuff ? p : 0;
    result.has_interpolants = saw_interpolant;

    return result;
  }

  void Parser::read_bom()
  {
    size_t skip = 0;
    string encoding;
    bool utf_8 = false;
    switch ((unsigned char) source[0]) {
    case 0xEF:
      skip = check_bom_chars(source, end, utf_8_bom, 3);
      encoding = "UTF-8";
      utf_8 = true;
      break;
    case 0xFE:



( run in 0.720 second using v1.01-cache-2.11-cpan-39bf76dae61 )