Text-Sass-XS

 view release on metacpan or  search on metacpan

libsass/old/eval_apply.cpp  view on Meta::CPAN

  using std::cerr; using std::endl;

  static void throw_eval_error(Backtrace& bt, string message, string path, size_t line)
  {
    if (!path.empty() && Prelexer::string_constant(path.c_str()))
      path = path.substr(1, path.size() - 1);

    Backtrace top(&bt, path, line, "");
    message += top.to_string();

    throw Error(Error::evaluation, path, line, message);
  }

  // Expansion function for nodes in an expansion context.
  void expand(Node expr, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx, Backtrace& bt, bool function_name, const Node content)
  {
    switch (expr.type())
    {
      case Node::root: {
        for (size_t i = 0, S = expr.size(); i < S; ++i) {
            if (i == 19) {

          expand(expr[i], prefix, env, f_env, new_Node, ctx, bt, false, content);
            }
            else {
          expand(expr[i], prefix, env, f_env, new_Node, ctx, bt, false, content);
            }
        }
      } break;

      case Node::mixin: { // mixin definition
        env[expr[0].token()] = expr;
      } break;

      case Node::function: { // function definition
        f_env[expr[0].to_string()] = Function(expr);
      } break;

      case Node::mixin_call: { // mixin invocation
        Token name(expr[0].token());
        Node args(expr[1]);
        Node this_content = expr.size() == 3 ? expr[2] : Node();
        if (!this_content.is_null()) expand(this_content, prefix, env, f_env, new_Node, ctx, bt, false, content);
        if (!env.query(name)) throw_eval_error(bt, "mixin " + name.to_string() + " is undefined", expr.path(), expr.line());
        Node mixin(env[name]);
        Backtrace here(&bt, expr.path(), expr.line(), ", in mixin '" + name.to_string() + "'");
        Node expansion(apply_mixin(mixin, args, this_content, prefix, env, f_env, new_Node, ctx, here));
        expr.pop_all();   // pop the mixin metadata
        expr += expansion; // push the expansion
      } break;

      case Node::mixin_content: {
        if (!content.is_null()) {
          expr += new_Node(content);
          for (size_t i = 0, S = expr.size(); i < S; ++i) {
            re_expand(expr[i], prefix, env, f_env, new_Node, ctx, bt, false, content);
          }
        }
      } break;

      case Node::propset: {
        // TO DO: perform the property expansion here, rather than in the emitter (also requires the parser to allow interpolants in the property names)
        expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx, bt);
        expand(expr[1], prefix, env, f_env, new_Node, ctx, bt, false, content);

        // Node block(expr[1]);
        // for (size_t i = 0, S = block.size(); i < S; ++i) {
        //   Node stm(block[i]);
        //   switch (stm.type())
        //   {
        //     case Node::propset:
        //     case Node::mixin_call:
        //     case Node::if_directive:
        //     case Node::for_through_directive:
        //     case Node::for_to_directive:
        //     case Node::each_directive:
        //     case Node::while_directive:
        //     case Node::warning: {
        //       expand(stm, prefix, env, f_env, new_Node, ctx, bt, false, content);
        //     } break;
        //   }
        // }
      } break;

      case Node::ruleset: {
        // if the selector contains interpolants, eval it and re-parse
        if (!expr[0].is_null() && expr[0].type() == Node::selector_schema) {
          Node schema(expr[0]);
          string expansion;
          for (size_t i = 0, S = schema.size(); i < S; ++i) {
            schema[i] = eval(schema[i], prefix, env, f_env, new_Node, ctx, bt);
            if (schema[i].type() == Node::string_constant) {
              expansion += schema[i].token().unquote();
            }
            else {
              expansion += schema[i].to_string();
            }
          }
          // need to re-parse the selector because its structure may have changed
          expansion += " {"; // the parser looks for an lbrace to end a selector
          char* expn_src = new char[expansion.size() + 1];
          strcpy(expn_src, expansion.c_str());
          Document needs_reparsing(Document::make_from_source_chars(ctx, expn_src, schema.path(), true));
          needs_reparsing.line = schema.line(); // set the line number to the original node's line
          expr[0] = needs_reparsing.parse_selector_group();
        }

        // Expand the selector with the prefix and save it in expr[2].
        expr << expand_selector(expr[0], prefix, new_Node);

        expand(expr[1], expr.back(), env, f_env, new_Node, ctx, bt, false, content);
      } break;

      case Node::media_query: {
        Node id(expr[0]);
        if( id.is_schema() || id.should_eval()) {
          expr[0] = eval(id, prefix, env, f_env, new_Node, ctx, bt);
        } else {
          expand(expr[0], prefix, env, f_env, new_Node, ctx, bt, false, content);
        }
        expand(expr[1], prefix, env, f_env, new_Node, ctx, bt, false, content);
        expr << prefix;
      } break;

      case Node::media_expression_group: {
        for (size_t i = 0, S = expr.size(); i < S; ++i) {
          expand(expr[i], prefix, env, f_env, new_Node, ctx, bt, false, content);
        }
      } break;

      case Node::media_expression: {



( run in 1.580 second using v1.01-cache-2.11-cpan-71847e10f99 )