Exemplo n.º 1
0
  Statement* Cssize::bubble(Media_Block* m)
  {
    Ruleset* parent = static_cast<Ruleset*>(shallow_copy(this->parent()));

    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, parent->block()->pstate());
    Ruleset* new_rule = SASS_MEMORY_NEW(ctx.mem, Ruleset,
                                        parent->pstate(),
                                        parent->selector(),
                                        bb);
    new_rule->tabs(parent->tabs());

    for (size_t i = 0, L = m->block()->length(); i < L; ++i) {
      *new_rule->block() << (*m->block())[i];
    }

    Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, m->block()->pstate());
    *wrapper_block << new_rule;
    Media_Block* mm = SASS_MEMORY_NEW(ctx.mem, Media_Block,
                                      m->pstate(),
                                      m->media_queries(),
                                      wrapper_block,
                                      0);

    mm->tabs(m->tabs());

    Bubble* bubble = SASS_MEMORY_NEW(ctx.mem, Bubble, mm->pstate(), mm);

    return bubble;
  }
Exemplo n.º 2
0
/*
 * Sets the mission's region. if the region is incompatible with
 * actually carrying out an attack, use the "fallback" region as
 * defined in the ruleset.
 * (this is a slight difference from the original, which just
 * defaulted them to zone[0], North America)
 * @param region the region we want to try to set the mission to.
 * @param rules the ruleset, in case we need to swap out the region.
 */
void AlienMission::setRegion(const std::string &region, const Ruleset &rules)
{
	if (rules.getRegion(region)->getMissionRegion() != "")
	{
		_region = rules.getRegion(region)->getMissionRegion();
	}
	else
	{
		_region = region;
	}
}
Exemplo n.º 3
0
void UnprocessedStatement::process(Ruleset &r) {
  Extension extension;
  Mixin mixin;
  Declaration* declaration;

#ifdef WITH_LIBGLOG
  VLOG(2) << "Statement: " << getTokens()->toString();
#endif
  
  // process extends statement
  if (getExtension(extension.getTarget())) {
    extension.setExtension(r.getSelector());
    getLessRuleset()->getContext()->addExtension(extension);
    return;
  }
  
  mixin.setStylesheet(getLessRuleset()->getLessStylesheet());
  
  // process mixin
  if (mixin.parse(*getTokens()) &&
      mixin.insert(*r.getStylesheet(), *getLessRuleset()->getContext(),
                   &r, getLessRuleset())) {

  } else {
    declaration = r.createDeclaration();
    
    if (processDeclaration(declaration)) {
    
#ifdef WITH_LIBGLOG
      VLOG(2) << "Declaration: " <<
        declaration->getProperty() << ": " << declaration->getValue().toString();
#endif
    
      getLessRuleset()->getContext()->processValue(declaration->getValue());

#ifdef WITH_LIBGLOG
      VLOG(2) << "Processed declaration: " <<
        declaration->getProperty() << ": " << declaration->getValue().toString();
#endif
    
    } else {
      r.deleteDeclaration(*declaration);
      throw new ParseException(getTokens()->toString(),
                               "variable, mixin or declaration.",
                               getTokens()->front().line,
                               getTokens()->front().column,
                               getTokens()->front().source);
    }
  }

#ifdef WITH_LIBGLOG
  VLOG(3) << "Statement done";
#endif
}
Exemplo n.º 4
0
Ruleset* CssParser::parseRuleset () {
  Ruleset* ruleset = NULL;
  Declaration* declaration = NULL;
  Selector* selector = new Selector();

  if (!parseSelector(selector)) {
    delete selector;
    selector = NULL;
    
    if (tokenizer->getTokenType() != Token::BRACKET_OPEN) {
      return NULL;
    } 
  } else if (tokenizer->getTokenType() != Token::BRACKET_OPEN) {
    delete selector;
    throw new ParseException(tokenizer->getToken()->str,
                             "a declaration block ('{...}')");
  }
  tokenizer->readNextToken();

  ruleset = new Ruleset(selector);
  
  skipWhitespace();
  declaration = parseDeclaration();
  if (declaration != NULL)
    ruleset->addDeclaration(declaration);
  
  while (tokenizer->getTokenType() == Token::DELIMITER) {
    tokenizer->readNextToken();
    skipWhitespace();
    declaration = parseDeclaration();
    if (declaration != NULL)
      ruleset->addDeclaration(declaration);
  }
  
  if (tokenizer->getTokenType() != Token::BRACKET_CLOSED) {
    throw new ParseException(tokenizer->getToken()->str,
                             "end of declaration block ('}')");
  } 
  tokenizer->readNextToken();
  skipWhitespace();
  
  return ruleset;
}
Exemplo n.º 5
0
// Rulesets
TEST(CssParserTest, Ruleset) {
  istringstream in("selector {key: value;}");
    
  CssTokenizer t(&in);
  CssParser p(&t);
  Stylesheet s;
  Ruleset* set;
  Declaration* d;

  p.parseStylesheet(&s);
  ASSERT_EQ(1, s.getRulesets()->size());
  set = s.getRulesets()->at(0);
  ASSERT_STREQ("selector", set->getSelector()->toString()->c_str());
  ASSERT_EQ(1, set->getDeclarations()->size());

  d = set->getDeclarations()->at(0);
  ASSERT_STREQ("key", d->getProperty()->c_str());
  ASSERT_STREQ("value", d->getValue()->toString()->c_str());
}
Exemplo n.º 6
0
void MediaQueryRuleset::process(Stylesheet &s, Selector* prefix, ProcessingContext &context) {
  MediaQuery* query;
  Ruleset* target;
  Selector selector;

#ifdef WITH_LIBGLOG
  VLOG(2) << "Processing Less Ruleset: " <<
    getSelector().toString();
#endif
  
  query = s.createMediaQuery();
  selector = getSelector();
  context.interpolate(selector);

  if (query->getSelector().size() > 0) {
    selector.pop_front();

    query->getSelector().push_back(Token(" ", Token::WHITESPACE));
    query->getSelector().push_back(Token("and", Token::IDENTIFIER));
    query->getSelector().insert(query->getSelector().end(),
                                 selector.begin(),
                                 selector.end());
  } else
    query->setSelector(selector);

  if (prefix != NULL) {
    target = query->createRuleset();
    target->setSelector(*prefix);

#ifdef WITH_LIBGLOG
    VLOG(3) << "Interpolating selector " <<
    target->getSelector().toString();
#endif
    context.interpolate(target->getSelector());
  
    insert(NULL, *target, context);
  } else
    insert(NULL, *query, context);
}
Node::Node(const std::string &type, const int level, const std::string &data) : type_(type), level_(level), data_(data)
{
	const int Expected_Height = 5;
	const double Constant_range = 10;
	// Growth
	if (level < Expected_Height)
	{
		Ruleset syntax = Node::GrowthRule(type);
		if (syntax.size())
		{
			const std::size_t index = RandomRange::random<int>(0, syntax.size() - 1);
			need_expand_ = (syntax[index][0] == "Expand" ? true : false);
			for (std::size_t i = 1; i < syntax[index].size(); i += 1)
			{
				if (syntax[index][i] != "null")
				{
					if (syntax[index][i] == "constant")
					{
						std::ostringstream strs;
						strs << RandomRange::random<double>(-Constant_range, Constant_range);
						std::string data = strs.str();
						child_.push_back(Node(syntax[index][i], level + 1, data));
					}
					else
					{
						child_.push_back(Node(syntax[index][i], level + 1));
					}
				}
			}
		}
	}
	// Terminal
	else
	{
		Ruleset syntax = Node::TerminalRule(type);
		if (syntax.size())
		{
			const std::size_t index = RandomRange::random<int>(0, syntax.size() - 1);
			need_expand_ = (syntax[index][0] == "Expand" ? true : false);
			for (std::size_t i = 1; i < syntax[index].size(); i += 1)
			{
				if (syntax[index][i] != "null")
				{
					if (syntax[index][i] == "constant")
					{
						std::ostringstream strs;
						strs << RandomRange::random<double>(-Constant_range, Constant_range);
						std::string data = strs.str();
						child_.push_back(Node(syntax[index][i], level + 1, data));
					}
					else
					{
						child_.push_back(Node(syntax[index][i], level + 1));
					}
				}
			}
		}
	}
}
Exemplo n.º 8
0
/**
 * Loads the UFO from a YAML file.
 * @param node YAML node.
 * @param ruleset The game rules. Use to access the trajectory rules.
 * @param game The game data. Used to find the UFO's mission.
 */
void Ufo::load(const YAML::Node &node, const Ruleset &ruleset, SavedGame &game)
{
	MovingTarget::load(node);
	node["id"] >> _id;
	node["damage"] >> _damage;
	node["altitude"] >> _altitude;
	node["direction"] >> _direction;
	node["detected"] >> _detected;
	node["hyperDetected"] >> _hyperDetected;
	node["secondsRemaining"] >> _secondsRemaining;
	node["inBattlescape"] >> _inBattlescape;
	double lon, lat;
	node["dest"]["lon"] >> lon;
	node["dest"]["lat"] >> lat;
	_dest = new Waypoint();
	_dest->setLongitude(lon);
	_dest->setLatitude(lat);
	if (_altitude == "STR_GROUND")
	{
		_status = LANDED;
	}
	else
	{
		_status = FLYING;
	}
	if (_damage >= _rules->getMaxDamage())
	{
		_status = DESTROYED;
	}
	else if (_damage >= _rules->getMaxDamage() / 2)
	{
		_status = CRASHED;
	}
	int missionID;
	node["mission"] >> missionID;
	std::vector<AlienMission *>::const_iterator found = std::find_if(game.getAlienMissions().begin(), game.getAlienMissions().end(), matchMissionID(missionID));
	if (found == game.getAlienMissions().end())
	{
		// Corrupt save file.
		throw Exception("Unknown mission, save file is corrupt.");
	}
	_mission = *found;

	std::string tid;
	node["trajectory"] >> tid;
	_trajectory = ruleset.getUfoTrajectory(tid);
	node["trajectoryPoint"] >> _trajectoryPoint;
	if (_inBattlescape)
		setSpeed(0);
}
Exemplo n.º 9
0
void LessDeclaration::process(Ruleset &r, void* context) const {
  Declaration *d = r.createDeclaration();
  d->setProperty(property);
  d->setValue(value);

  ((ProcessingContext*)context)->interpolate(d->getProperty());
  ((ProcessingContext*)context)->processValue(d->getValue());

  // If the `important` flag is set, append '!important'
  if(((ProcessingContext*)context)->isImportant()) {
    
    if (d->getValue().size() < 3 ||
        d->getValue().back() == "important") {
      d->getValue().push_back(Token::BUILTIN_SPACE);
      d->getValue().push_back(Token::BUILTIN_IMPORTANT);
    }
    
  }
}
Exemplo n.º 10
0
  Statement* Cssize::operator()(Ruleset* r)
  {
    p_stack.push_back(r);
    Ruleset* rr = SASS_MEMORY_NEW(ctx.mem, Ruleset,
                                  r->pstate(),
                                  r->selector(),
                                  r->block()->perform(this)->block());
    // rr->tabs(r->block()->tabs());
    p_stack.pop_back();

    Block* props = SASS_MEMORY_NEW(ctx.mem, Block, rr->block()->pstate());
    Block* rules = SASS_MEMORY_NEW(ctx.mem, Block, rr->block()->pstate());
    for (size_t i = 0, L = rr->block()->length(); i < L; i++)
    {
      Statement* s = (*rr->block())[i];
      if (bubblable(s)) *rules << s;
      if (!bubblable(s)) *props << s;
    }

    if (props->length())
    {
      Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, rr->block()->pstate());
      *bb += props;
      rr->block(bb);

      for (size_t i = 0, L = rules->length(); i < L; i++)
      {
        (*rules)[i]->tabs((*rules)[i]->tabs() + 1);
      }

      rules->unshift(rr);
    }

    rules = debubble(rules)->block();

    if (!(!rules->length() ||
          !bubblable(rules->last()) ||
          parent()->statement_type() == Statement::RULESET))
    {
      rules->last()->group_end(true);
    }

    return rules;
  }
Exemplo n.º 11
0
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

//    QtQuick2ApplicationViewer viewer;
//    viewer.setMainQmlFile(QStringLiteral("qml/GUI-Scenario/main.qml"));
//    viewer.showExpanded();


    //temp for testing


//    Story* story;
//    Item* hammer = new Item{"hammer"};
//    //story->add_item(hammer);
//    QMap<QString, qint16> attributes;
//    attributes["hp"] = 10;

//    Character player1{};//attributes, 5, story};

////    player1.set_name("player1");
////    player1.add_to_attribute("hp", 10);

//    Character player2;

//      player2.set_name("player2");
////    player2.add_to_attribute("hp", 13);
//    //player1.add_item(1); does not work for some reasaon LOOK IT UP!!!!!

//    QList<Character*> characterlist;

//    //characterlist.append(&player1);
//    characterlist.append(&player2);

//    QMap<quint16, Item*> items;
//    items[1] = hammer;

////    qDebug() << "before add";
////    player1.add_item(1);
////    qDebug() << "after add";
///
///

    //from other main

    QList<QString> attr_list{"health", "armor", "strength"};
    Ruleset *rs;
    rs = new Ruleset(attr_list);

    Story* main_story = new Story(rs);

    QMap<QString, qint16> attr_map{{"health", 10}, {"armor", 2}, {"strength", 5}};
    main_story->add_character(new Character(attr_map, 50, main_story));

    Character* bob = main_story->get_characters().front();
    bob->set_name("BOB!");


    try {
      Item* hammer1 = new Item("Hammer of doom");
      main_story->add_item(hammer1);
      hammer1->set_attribute("Weight", 20);

      Item* hammer2 = new Item("nicer hammah");
      main_story->add_item(hammer2);
      hammer2->set_attribute("Weight", 20);
      hammer2->set_attribute("bonk", 50);
      hammer2->set_attribute("smash", 3000);

      bob->add_item(hammer1->get_id());
      bob->add_item(hammer2->get_id());


      qDebug() << "Bob's stuff:";
      for (auto item_id : bob->inventory.get_items()) {
        qDebug() << main_story->get_items().value(item_id)->get_name();
      }
    }
    catch (const std::out_of_range& e) {
      qDebug() << "out_of_range exception: " << e.what();
    }


    Character* herman = new Character(attr_map, 10, main_story);
    main_story->add_character(herman);
    herman->set_name("Herr Man");

    rs->add_skill(new Skill("Break those cuffs"));
    rs->add_skill(new Skill("Eat horse"));
    rs->get_skills().at(0)->set_modifier("int", 10);
    rs->get_skills().at(0)->set_modifier("str", 11);
    rs->get_skills().at(1)->set_modifier("int" , 5);
    rs->get_skills().at(1)->set_modifier("str", 25);
    bob->add_skill(rs->get_skills().at(0));
    bob->add_skill(rs->get_skills().at(1));


    herman->add_skill(rs->get_skills().at(1));



    //connect signals from QML

//    QObject::connect((QObject*)viewer.rootObject(), SIGNAL(testSignal(QString)),&controller, SLOT(oklart(QString)));
//    QObject::connect((QObject*)viewer.rootObject(), SIGNAL(setDropAreaParent(int)),&controller, SLOT(set_active_block_number_(int)));
//    QObject::connect((QObject*)viewer.rootObject(), SIGNAL(setDropAreaSide(QString)),&controller, SLOT(set_active_block_side(QString)));
//    QObject::connect((QObject*)viewer.rootObject(), SIGNAL(add_block(int, QString)),&controller, SLOT(add_block(int,QString)));
//    QObject::connect((QObject*)viewer.rootObject(), SIGNAL(editValueBlock(QString, bool, int)),&controller, SLOT(edit_valueblock(QString, bool, int)));
//    QObject::connect((QObject*)viewer.rootObject(), SIGNAL(setCompareBlockValue(int)),&controller, SLOT(set_compareblock_value(int)));
//    QObject::connect((QObject*)viewer.rootObject(), SIGNAL(editDamageBlock(QString, bool, int)),&controller, SLOT(edit_damageblock(QString, bool, int)));

//    //TODO: complete signals below
//    QObject::connect((QObject*)viewer.rootObject(), SIGNAL(editCompareBlock(QString, bool, int)),&controller, SLOT(edit_compareblock(QString, bool, int)));

//    QStringList dataList;
//    dataList.append("Item 1");
//    dataList.append("Item 2");
//    dataList.append("Item 3");
//    dataList.append("Item 4");
//    dataList.append("Item 1");
//    dataList.append("Item 2");
//    dataList.append("Item 3");
//    dataList.append("Item 4");
//    dataList.append("Item 1");
//    dataList.append("Item 2");
//    dataList.append("Item 3");
//    dataList.append("Item 4");
//    dataList.append("Item 1");
//    dataList.append("Item 2");
//    dataList.append("Item 3");
//    dataList.append("Item 4");

//    // export instance to qml
//    QQmlContext *ctxt = viewer.rootContext();
//    ctxt->setContextProperty("controller", &controller);

    //ctxt->setContextProperty("dataList", QVariant::fromValue(dataList));

    //ctxt->setContextProperty("sController", &controller);

    //QML

    QtQuick2ApplicationViewer viewer;

    // create a controller
    ScenarioController controller{herman, main_story->get_characters(),main_story->get_items(),rs->get_skills(),rs->get_attributes()};

    // export instance to qml
    QQmlContext *ctxt = viewer.rootContext();
    ctxt->setContextProperty("controller", &controller);
    viewer.setMainQmlFile(QStringLiteral("qml/GUI-Scenario/main.qml"));
    viewer.showExpanded();



    return app.exec();
}
Exemplo n.º 12
0
/**
 * Loads the UFO from a YAML file.
 * @param node YAML node.
 * @param ruleset The game rules. Use to access the trajectory rules.
 * @param game The game data. Used to find the UFO's mission.
 */
void Ufo::load(const YAML::Node &node, const Ruleset &ruleset, SavedGame &game)
{
	MovingTarget::load(node);
	_id = node["id"].as<int>(_id);
	_crashId = node["crashId"].as<int>(_crashId);
	_landId = node["landId"].as<int>(_landId);
	_damage = node["damage"].as<int>(_damage);
	_altitude = node["altitude"].as<std::string>(_altitude);
	_direction = node["direction"].as<std::string>(_direction);
	_detected = node["detected"].as<bool>(_detected);
	_hyperDetected = node["hyperDetected"].as<bool>(_hyperDetected);
	_secondsRemaining = node["secondsRemaining"].as<size_t>(_secondsRemaining);
	_inBattlescape = node["inBattlescape"].as<bool>(_inBattlescape);
	double lon = _lon;
	double lat = _lat;
	if (const YAML::Node &dest = node["dest"])
	{
		lon = dest["lon"].as<double>();
		lat = dest["lat"].as<double>();
	}
	_dest = new Waypoint();
	_dest->setLongitude(lon);
	_dest->setLatitude(lat);
	if (const YAML::Node &status = node["status"])
	{
		_status = (UfoStatus)status.as<int>();
	}
	else
	{
		if (_damage >= _rules->getMaxDamage())
		{
			_status = DESTROYED;
		}
		else if (_damage >= _rules->getMaxDamage() / 2)
		{
			_status = CRASHED;
		}
		else if (_altitude == "STR_GROUND")
		{
			_status = LANDED;
		}
		else
		{
			_status = FLYING;
		}
	}
	if (game.getMonthsPassed() != -1)
	{
		int missionID = node["mission"].as<int>();
		std::vector<AlienMission *>::const_iterator found = std::find_if (game.getAlienMissions().begin(), game.getAlienMissions().end(), matchMissionID(missionID));
		if (found == game.getAlienMissions().end())
		{
			// Corrupt save file.
			throw Exception("Unknown mission, save file is corrupt.");
		}
		_mission = *found;

		std::string tid = node["trajectory"].as<std::string>();
		_trajectory = ruleset.getUfoTrajectory(tid);
		_trajectoryPoint = node["trajectoryPoint"].as<size_t>(_trajectoryPoint);
	}
	_fireCountdown = node["fireCountdown"].as<int>(_fireCountdown);
	_escapeCountdown = node["escapeCountdown"].as<int>(_escapeCountdown);
	if (_inBattlescape)
		setSpeed(0);
}
Exemplo n.º 13
0
inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
{
  if (node == 0) return;
  if (ind == "") cerr << "####################################################################\n";
  if (dynamic_cast<Bubble*>(node)) {
    Bubble* bubble = dynamic_cast<Bubble*>(node);
    cerr << ind << "Bubble " << bubble << " " << bubble->tabs() << endl;
  } else if (dynamic_cast<At_Root_Block*>(node)) {
    At_Root_Block* root_block = dynamic_cast<At_Root_Block*>(node);
    cerr << ind << "At_Root_Block " << root_block << " " << root_block->tabs() << endl;
    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Selector_List*>(node)) {
    Selector_List* selector = dynamic_cast<Selector_List*>(node);

    cerr << ind << "Selector_List " << selector
      << " [block:" << selector->last_block() << "]"
      << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
      << " [@media:" << selector->media_block() << "]"
      << (selector->is_optional() ? " [is_optional]": " -")
      << (selector->has_line_break() ? " [line-break]": " -")
      << (selector->has_line_feed() ? " [line-feed]": " -")
    << endl;

    for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }

//  } else if (dynamic_cast<Expression*>(node)) {
//    Expression* expression = dynamic_cast<Expression*>(node);
//    cerr << ind << "Expression " << expression << " " << expression->concrete_type() << endl;

  } else if (dynamic_cast<Parent_Selector*>(node)) {
    Parent_Selector* selector = dynamic_cast<Parent_Selector*>(node);
    cerr << ind << "Parent_Selector " << selector;
    cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
    debug_ast(selector->selector(), ind + "->", env);

  } else if (dynamic_cast<Complex_Selector*>(node)) {
    Complex_Selector* selector = dynamic_cast<Complex_Selector*>(node);
    cerr << ind << "Complex_Selector " << selector
      << " [block:" << selector->last_block() << "]"
      << " [weight:" << longToHex(selector->specificity()) << "]"
      << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
      << " [@media:" << selector->media_block() << "]"
      << (selector->is_optional() ? " [is_optional]": " -")
      << (selector->has_line_break() ? " [line-break]": " -")
      << (selector->has_line_feed() ? " [line-feed]": " -") << " -> ";
      switch (selector->combinator()) {
        case Complex_Selector::PARENT_OF:   cerr << "{>}"; break;
        case Complex_Selector::PRECEDES:    cerr << "{~}"; break;
        case Complex_Selector::ADJACENT_TO: cerr << "{+}"; break;
        case Complex_Selector::ANCESTOR_OF: cerr << "{ }"; break;
      }
    cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
    debug_ast(selector->head(), ind + " ", env);
    debug_ast(selector->tail(), ind + "-", env);
  } else if (dynamic_cast<Compound_Selector*>(node)) {
    Compound_Selector* selector = dynamic_cast<Compound_Selector*>(node);
    cerr << ind << "Compound_Selector " << selector;
    cerr << " [block:" << selector->last_block() << "]";
    cerr << " [weight:" << longToHex(selector->specificity()) << "]";
    // cerr << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "");
    cerr << " [@media:" << selector->media_block() << "]";
    cerr << (selector->is_optional() ? " [is_optional]": " -");
    cerr << (selector->has_line_break() ? " [line-break]": " -");
    cerr << (selector->has_line_feed() ? " [line-feed]": " -");
    cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
    for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Propset*>(node)) {
    Propset* selector = dynamic_cast<Propset*>(node);
    cerr << ind << "Propset " << selector << " " << selector->tabs() << endl;
    if (selector->block()) for(auto i : selector->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Wrapped_Selector*>(node)) {
    Wrapped_Selector* selector = dynamic_cast<Wrapped_Selector*>(node);
    cerr << ind << "Wrapped_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
    debug_ast(selector->selector(), ind + " () ", env);
  } else if (dynamic_cast<Pseudo_Selector*>(node)) {
    Pseudo_Selector* selector = dynamic_cast<Pseudo_Selector*>(node);
    cerr << ind << "Pseudo_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
    debug_ast(selector->expression(), ind + " <= ", env);
  } else if (dynamic_cast<Attribute_Selector*>(node)) {
    Attribute_Selector* selector = dynamic_cast<Attribute_Selector*>(node);
    cerr << ind << "Attribute_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
    debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env);
  } else if (dynamic_cast<Selector_Qualifier*>(node)) {
    Selector_Qualifier* selector = dynamic_cast<Selector_Qualifier*>(node);
    cerr << ind << "Selector_Qualifier " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
  } else if (dynamic_cast<Type_Selector*>(node)) {
    Type_Selector* selector = dynamic_cast<Type_Selector*>(node);
    cerr << ind << "Type_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") <<
      " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
  } else if (dynamic_cast<Selector_Placeholder*>(node)) {

    Selector_Placeholder* selector = dynamic_cast<Selector_Placeholder*>(node);
    cerr << ind << "Selector_Placeholder [" << selector->name() << "] " << selector
      << " [block:" << selector->last_block() << "]"
      << " [@media:" << selector->media_block() << "]"
      << (selector->is_optional() ? " [is_optional]": " -")
      << (selector->has_line_break() ? " [line-break]": " -")
      << (selector->has_line_feed() ? " [line-feed]": " -")
    << endl;

  } else if (dynamic_cast<Selector_Reference*>(node)) {
    Selector_Reference* selector = dynamic_cast<Selector_Reference*>(node);
    cerr << ind << "Selector_Reference " << selector << " @ref " << selector->selector() << endl;
  } else if (dynamic_cast<Simple_Selector*>(node)) {
    Simple_Selector* selector = dynamic_cast<Simple_Selector*>(node);
    cerr << ind << "Simple_Selector " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;

  } else if (dynamic_cast<Selector_Schema*>(node)) {
    Selector_Schema* selector = dynamic_cast<Selector_Schema*>(node);
    cerr << ind << "Selector_Schema " << selector
      << " [block:" << selector->last_block() << "]"
      << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
      << " [@media:" << selector->media_block() << "]"
      << (selector->has_line_break() ? " [line-break]": " -")
      << (selector->has_line_feed() ? " [line-feed]": " -")
    << endl;

    debug_ast(selector->contents(), ind + " ");
    // for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }

  } else if (dynamic_cast<Selector*>(node)) {
    Selector* selector = dynamic_cast<Selector*>(node);
    cerr << ind << "Selector " << selector
      << (selector->has_line_break() ? " [line-break]": " -")
      << (selector->has_line_feed() ? " [line-feed]": " -")
    << endl;

  } else if (dynamic_cast<Media_Query_Expression*>(node)) {
    Media_Query_Expression* block = dynamic_cast<Media_Query_Expression*>(node);
    cerr << ind << "Media_Query_Expression " << block
      << (block->is_interpolated() ? " [is_interpolated]": " -")
    << endl;
    debug_ast(block->feature(), ind + " f) ");
    debug_ast(block->value(), ind + " v) ");

  } else if (dynamic_cast<Media_Query*>(node)) {
    Media_Query* block = dynamic_cast<Media_Query*>(node);
    cerr << ind << "Media_Query " << block
      << (block->is_negated() ? " [is_negated]": " -")
      << (block->is_restricted() ? " [is_restricted]": " -")
    << endl;
    debug_ast(block->media_type(), ind + " ");
    for(auto i : block->elements()) { debug_ast(i, ind + " ", env); }

  } else if (dynamic_cast<Media_Block*>(node)) {
    Media_Block* block = dynamic_cast<Media_Block*>(node);
    cerr << ind << "Media_Block " << block << " " << block->tabs() << endl;
    debug_ast(block->media_queries(), ind + " =@ ");
    debug_ast(block->selector(), ind + " -@ ");
    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Feature_Block*>(node)) {
    Feature_Block* block = dynamic_cast<Feature_Block*>(node);
    cerr << ind << "Feature_Block " << block << " " << block->tabs() << endl;
    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Block*>(node)) {
    Block* root_block = dynamic_cast<Block*>(node);
    cerr << ind << "Block " << root_block << " " << root_block->tabs() << endl;
    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Warning*>(node)) {
    Warning* block = dynamic_cast<Warning*>(node);
    cerr << ind << "Warning " << block << " " << block->tabs() << endl;
  } else if (dynamic_cast<Error*>(node)) {
    Error* block = dynamic_cast<Error*>(node);
    cerr << ind << "Error " << block << " " << block->tabs() << endl;
  } else if (dynamic_cast<Debug*>(node)) {
    Debug* block = dynamic_cast<Debug*>(node);
    cerr << ind << "Debug " << block << " " << block->tabs() << endl;
  } else if (dynamic_cast<Comment*>(node)) {
    Comment* block = dynamic_cast<Comment*>(node);
    cerr << ind << "Comment " << block << " " << block->tabs() <<
      " <" << prettyprint(block->pstate().token.ws_before()) << ">" << endl;
    debug_ast(block->text(), ind + "// ", env);
  } else if (dynamic_cast<If*>(node)) {
    If* block = dynamic_cast<If*>(node);
    cerr << ind << "If " << block << " " << block->tabs() << endl;
  } else if (dynamic_cast<Return*>(node)) {
    Return* block = dynamic_cast<Return*>(node);
    cerr << ind << "Return " << block << " " << block->tabs() << endl;
  } else if (dynamic_cast<Extension*>(node)) {
    Extension* block = dynamic_cast<Extension*>(node);
    cerr << ind << "Extension " << block << " " << block->tabs() << endl;
    debug_ast(block->selector(), ind + "-> ", env);
  } else if (dynamic_cast<Content*>(node)) {
    Content* block = dynamic_cast<Content*>(node);
    cerr << ind << "Content " << block << " " << block->tabs() << endl;
  } else if (dynamic_cast<Import_Stub*>(node)) {
    Import_Stub* block = dynamic_cast<Import_Stub*>(node);
    cerr << ind << "Import_Stub " << block << " " << block->tabs() << endl;
  } else if (dynamic_cast<Import*>(node)) {
    Import* block = dynamic_cast<Import*>(node);
    cerr << ind << "Import " << block << " " << block->tabs() << endl;
    // vector<string>         files_;
    for (auto imp : block->urls()) debug_ast(imp, "@ ", env);
  } else if (dynamic_cast<Assignment*>(node)) {
    Assignment* block = dynamic_cast<Assignment*>(node);
    cerr << ind << "Assignment " << block << " <<" << block->variable() << ">> " << block->tabs() << endl;
    debug_ast(block->value(), ind + "=", env);
  } else if (dynamic_cast<Declaration*>(node)) {
    Declaration* block = dynamic_cast<Declaration*>(node);
    cerr << ind << "Declaration " << block << " " << block->tabs() << endl;
    debug_ast(block->property(), ind + " prop: ", env);
    debug_ast(block->value(), ind + " value: ", env);
  } else if (dynamic_cast<Keyframe_Rule*>(node)) {
    Keyframe_Rule* has_block = dynamic_cast<Keyframe_Rule*>(node);
    cerr << ind << "Keyframe_Rule " << has_block << " " << has_block->tabs() << endl;
    if (has_block->selector()) debug_ast(has_block->selector(), ind + "@");
    if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<At_Rule*>(node)) {
    At_Rule* block = dynamic_cast<At_Rule*>(node);
    cerr << ind << "At_Rule " << block << " [" << block->keyword() << "] " << block->tabs() << endl;
    debug_ast(block->value(), ind + "+", env);
    debug_ast(block->selector(), ind + "~", env);
    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Each*>(node)) {
    Each* block = dynamic_cast<Each*>(node);
    cerr << ind << "Each " << block << " " << block->tabs() << endl;
    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<For*>(node)) {
    For* block = dynamic_cast<For*>(node);
    cerr << ind << "For " << block << " " << block->tabs() << endl;
    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<While*>(node)) {
    While* block = dynamic_cast<While*>(node);
    cerr << ind << "While " << block << " " << block->tabs() << endl;
    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Definition*>(node)) {
    Definition* block = dynamic_cast<Definition*>(node);
    cerr << ind << "Definition " << block << " " << block->tabs() << endl;
    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Mixin_Call*>(node)) {
    Mixin_Call* block = dynamic_cast<Mixin_Call*>(node);
    cerr << ind << "Mixin_Call " << block << " " << block->tabs() << endl;
    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Ruleset*>(node)) {
    Ruleset* ruleset = dynamic_cast<Ruleset*>(node);
    cerr << ind << "Ruleset " << ruleset << " " << ruleset->tabs() << endl;
    debug_ast(ruleset->selector(), ind + " ");
    if (ruleset->block()) for(auto i : ruleset->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Block*>(node)) {
    Block* block = dynamic_cast<Block*>(node);
    cerr << ind << "Block " << block << " " << block->tabs() << endl;
    for(auto i : block->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Textual*>(node)) {
    Textual* expression = dynamic_cast<Textual*>(node);
    cerr << ind << "Textual ";
    if (expression->type() == Textual::NUMBER) cerr << " [NUMBER]";
    else if (expression->type() == Textual::PERCENTAGE) cerr << " [PERCENTAGE]";
    else if (expression->type() == Textual::DIMENSION) cerr << " [DIMENSION]";
    else if (expression->type() == Textual::HEX) cerr << " [HEX]";
    cerr << expression << " [" << expression->value() << "]" << endl;
  } else if (dynamic_cast<Variable*>(node)) {
    Variable* expression = dynamic_cast<Variable*>(node);
    cerr << ind << "Variable " << expression << " [" << expression->name() << "]" << endl;
    string name(expression->name());
    if (env && env->has(name)) debug_ast(static_cast<Expression*>((*env)[name]), ind + " -> ", env);
  } else if (dynamic_cast<Function_Call_Schema*>(node)) {
    Function_Call_Schema* expression = dynamic_cast<Function_Call_Schema*>(node);
    cerr << ind << "Function_Call_Schema " << expression << "]" << endl;
    debug_ast(expression->name(), ind + "name: ", env);
    debug_ast(expression->arguments(), ind + " args: ", env);
  } else if (dynamic_cast<Function_Call*>(node)) {
    Function_Call* expression = dynamic_cast<Function_Call*>(node);
    cerr << ind << "Function_Call " << expression << " [" << expression->name() << "]" << endl;
    debug_ast(expression->arguments(), ind + " args: ", env);
  } else if (dynamic_cast<Arguments*>(node)) {
    Arguments* expression = dynamic_cast<Arguments*>(node);
    cerr << ind << "Arguments " << expression << "]" << endl;
    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Argument*>(node)) {
    Argument* expression = dynamic_cast<Argument*>(node);
    cerr << ind << "Argument " << expression << " [" << expression->value() << "]" << endl;
    debug_ast(expression->value(), ind + " value: ", env);
  } else if (dynamic_cast<Unary_Expression*>(node)) {
    Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node);
    cerr << ind << "Unary_Expression " << expression << " [" << expression->type() << "]" << endl;
    debug_ast(expression->operand(), ind + " operand: ", env);
  } else if (dynamic_cast<Binary_Expression*>(node)) {
    Binary_Expression* expression = dynamic_cast<Binary_Expression*>(node);
    cerr << ind << "Binary_Expression " << expression << " [" << expression->type() << "]" << endl;
    debug_ast(expression->left(), ind + " left:  ", env);
    debug_ast(expression->right(), ind + " right: ", env);
  } else if (dynamic_cast<Map*>(node)) {
    Map* expression = dynamic_cast<Map*>(node);
    cerr << ind << "Map " << expression << " [Hashed]" << endl;
  } else if (dynamic_cast<List*>(node)) {
    List* expression = dynamic_cast<List*>(node);
    cerr << ind << "List " << expression << " (" << expression->length() << ") " <<
      (expression->separator() == Sass::List::Separator::COMMA ? "Comma " : "Space ") <<
      " [delayed: " << expression->is_delayed() << "] " <<
      " [interpolant: " << expression->is_interpolant() << "] " <<
      endl;
    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Content*>(node)) {
    Content* expression = dynamic_cast<Content*>(node);
    cerr << ind << "Content " << expression << " [Statement]" << endl;
  } else if (dynamic_cast<Boolean*>(node)) {
    Boolean* expression = dynamic_cast<Boolean*>(node);
    cerr << ind << "Boolean " << expression << " [" << expression->value() << "]" << endl;
  } else if (dynamic_cast<Color*>(node)) {
    Color* expression = dynamic_cast<Color*>(node);
    cerr << ind << "Color " << expression << " [" << expression->r() << ":"  << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << endl;
  } else if (dynamic_cast<Number*>(node)) {
    Number* expression = dynamic_cast<Number*>(node);
    cerr << ind << "Number " << expression << " [" << expression->value() << expression->unit() << "]" << endl;
  } else if (dynamic_cast<String_Quoted*>(node)) {
    String_Quoted* expression = dynamic_cast<String_Quoted*>(node);
    cerr << ind << "String_Quoted : " << expression << " [" << prettyprint(expression->value()) << "]" <<
      (expression->is_delayed() ? " {delayed}" : "") <<
      (expression->sass_fix_1291() ? " {sass_fix_1291}" : "") <<
      (expression->quote_mark() != 0 ? " {qm:" + string(1, expression->quote_mark()) + "}" : "") <<
      " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
  } else if (dynamic_cast<String_Constant*>(node)) {
    String_Constant* expression = dynamic_cast<String_Constant*>(node);
    cerr << ind << "String_Constant : " << expression << " [" << prettyprint(expression->value()) << "]" <<
      (expression->is_delayed() ? " {delayed}" : "") <<
      (expression->sass_fix_1291() ? " {sass_fix_1291}" : "") <<
      " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
  } else if (dynamic_cast<String_Schema*>(node)) {
    String_Schema* expression = dynamic_cast<String_Schema*>(node);
    cerr << ind << "String_Schema " << expression << " " << expression->concrete_type() <<
      (expression->has_interpolants() ? " {has_interpolants}" : "") <<
      endl;
    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<String*>(node)) {
    String* expression = dynamic_cast<String*>(node);
    cerr << ind << "String " << expression << expression->concrete_type() <<
      " " << (expression->sass_fix_1291() ? "{sass_fix_1291}" : "") <<
      endl;
  } else if (dynamic_cast<Expression*>(node)) {
    Expression* expression = dynamic_cast<Expression*>(node);
    cerr << ind << "Expression " << expression;
    switch (expression->concrete_type()) {
      case Expression::Concrete_Type::NONE: cerr << " [NONE]"; break;
      case Expression::Concrete_Type::BOOLEAN: cerr << " [BOOLEAN]"; break;
      case Expression::Concrete_Type::NUMBER: cerr << " [NUMBER]"; break;
      case Expression::Concrete_Type::COLOR: cerr << " [COLOR]"; break;
      case Expression::Concrete_Type::STRING: cerr << " [STRING]"; break;
      case Expression::Concrete_Type::LIST: cerr << " [LIST]"; break;
      case Expression::Concrete_Type::MAP: cerr << " [MAP]"; break;
      case Expression::Concrete_Type::SELECTOR: cerr << " [SELECTOR]"; break;
      case Expression::Concrete_Type::NULL_VAL: cerr << " [NULL_VAL]"; break;
      case Expression::Concrete_Type::NUM_TYPES: cerr << " [NUM_TYPES]"; break;
    }
    cerr << endl;
  } else if (dynamic_cast<Has_Block*>(node)) {
    Has_Block* has_block = dynamic_cast<Has_Block*>(node);
    cerr << ind << "Has_Block " << has_block << " " << has_block->tabs() << endl;
    if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
  } else if (dynamic_cast<Statement*>(node)) {
    Statement* statement = dynamic_cast<Statement*>(node);
    cerr << ind << "Statement " << statement << " " << statement->tabs() << endl;
  }

  if (ind == "") cerr << "####################################################################\n";
}