Skip to content

Commit

Permalink
Merge pull request #2001 from mgreter/refactor/directive-parsing
Browse files Browse the repository at this point in the history
Refactor/directive parsing
  • Loading branch information
mgreter committed Apr 23, 2016
2 parents 2e97fdd + 83d401b commit eaf3413
Show file tree
Hide file tree
Showing 31 changed files with 890 additions and 187 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Miscellaneous stuff

/sassc
/sass-spec

VERSION
.DS_Store
.sass-cache
Expand Down
83 changes: 80 additions & 3 deletions src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
#include "color_maps.hpp"
#include <set>
#include <iomanip>
#include <algorithm>
#include <iostream>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

namespace Sass {

Expand All @@ -25,6 +28,80 @@ namespace Sass {
dynamic_cast<Supports_Operator*>(cond);
}

std::string & str_ltrim(std::string & str)
{
auto it2 = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( str.begin() , it2);
return str;
}

std::string & str_rtrim(std::string & str)
{
auto it1 = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
str.erase( it1.base() , str.end() );
return str;
}

void String_Constant::rtrim()
{
value_ = str_rtrim(value_);
}
void String_Constant::ltrim()
{
value_ = str_ltrim(value_);
}
void String_Constant::trim()
{
rtrim();
ltrim();
}

void String_Schema::rtrim()
{
if (!empty()) {
if (String* str = dynamic_cast<String*>(last())) str->rtrim();
}
}
void String_Schema::ltrim()
{
if (!empty()) {
if (String* str = dynamic_cast<String*>(first())) str->ltrim();
}
}
void String_Schema::trim()
{
rtrim();
ltrim();
}

bool At_Root_Query::exclude(std::string str)
{
bool with = feature() && unquote(feature()->to_string()).compare("with") == 0;
List* l = static_cast<List*>(value());
std::string v;

if (with)
{
if (!l || l->length() == 0) return str.compare("rule") != 0;
for (size_t i = 0, L = l->length(); i < L; ++i)
{
v = unquote((*l)[i]->to_string());
if (v.compare("all") == 0 || v == str) return false;
}
return true;
}
else
{
if (!l || !l->length()) return str.compare("rule") == 0;
for (size_t i = 0, L = l->length(); i < L; ++i)
{
v = unquote((*l)[i]->to_string());
if (v.compare("all") == 0 || v == str) return true;
}
return false;
}
}

void AST_Node::update_pstate(const ParserState& pstate)
{
pstate_.offset += pstate - pstate_ + pstate.offset;
Expand Down Expand Up @@ -60,7 +137,7 @@ namespace Sass {
bool Compound_Selector::has_parent_ref()
{
for (Simple_Selector* s : *this) {
if (s->has_parent_ref()) return true;
if (s && s->has_parent_ref()) return true;
}
return false;
}
Expand Down Expand Up @@ -1293,7 +1370,7 @@ namespace Sass {
bool Selector_List::has_parent_ref()
{
for (Complex_Selector* s : *this) {
if (s->has_parent_ref()) return true;
if (s && s->has_parent_ref()) return true;
}
return false;
}
Expand Down
58 changes: 20 additions & 38 deletions src/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,12 +524,12 @@ namespace Sass {
// At-rules -- arbitrary directives beginning with "@" that may have an
// optional statement block.
///////////////////////////////////////////////////////////////////////
class At_Rule : public Has_Block {
class Directive : public Has_Block {
ADD_PROPERTY(std::string, keyword)
ADD_PROPERTY(Selector*, selector)
ADD_PROPERTY(Expression*, value)
public:
At_Rule(ParserState pstate, std::string kwd, Selector* sel = 0, Block* b = 0, Expression* val = 0)
Directive(ParserState pstate, std::string kwd, Selector* sel = 0, Block* b = 0, Expression* val = 0)
: Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed
{ statement_type(DIRECTIVE); }
bool bubbles() { return is_keyframes() || is_media(); }
Expand Down Expand Up @@ -1471,6 +1471,9 @@ namespace Sass {
{ concrete_type(STRING); }
static std::string type_name() { return "string"; }
virtual ~String() = 0;
virtual void rtrim() = 0;
virtual void ltrim() = 0;
virtual void trim() = 0;
virtual bool operator==(const Expression& rhs) const = 0;
ATTACH_OPERATIONS()
};
Expand Down Expand Up @@ -1499,6 +1502,9 @@ namespace Sass {
}
return false;
}
virtual void rtrim();
virtual void ltrim();
virtual void trim();

virtual size_t hash()
{
Expand Down Expand Up @@ -1539,6 +1545,9 @@ namespace Sass {
std::string type() { return "string"; }
static std::string type_name() { return "string"; }
virtual bool is_invisible() const;
virtual void rtrim();
virtual void ltrim();
virtual void trim();

virtual size_t hash()
{
Expand Down Expand Up @@ -1696,60 +1705,33 @@ namespace Sass {
/////////////////////////////////////////////////
// At root expressions (for use inside @at-root).
/////////////////////////////////////////////////
class At_Root_Expression : public Expression {
class At_Root_Query : public Expression {
private:
ADD_PROPERTY(String*, feature)
ADD_PROPERTY(Expression*, feature)
ADD_PROPERTY(Expression*, value)
ADD_PROPERTY(bool, is_interpolated)
public:
At_Root_Expression(ParserState pstate, String* f = 0, Expression* v = 0, bool i = false)
: Expression(pstate), feature_(f), value_(v), is_interpolated_(i)
At_Root_Query(ParserState pstate, Expression* f = 0, Expression* v = 0, bool i = false)
: Expression(pstate), feature_(f), value_(v)
{ }
bool exclude(std::string str)
{
bool with = feature() && unquote(feature()->to_string()).compare("with") == 0;
List* l = static_cast<List*>(value());
std::string v;

if (with)
{
if (!l || l->length() == 0) return str.compare("rule") != 0;
for (size_t i = 0, L = l->length(); i < L; ++i)
{
v = unquote((*l)[i]->to_string());
if (v.compare("all") == 0 || v == str) return false;
}
return true;
}
else
{
if (!l || !l->length()) return str.compare("rule") == 0;
for (size_t i = 0, L = l->length(); i < L; ++i)
{
v = unquote((*l)[i]->to_string());
if (v.compare("all") == 0 || v == str) return true;
}
return false;
}
}
bool exclude(std::string str);
ATTACH_OPERATIONS()
};

///////////
// At-root.
///////////
class At_Root_Block : public Has_Block {
ADD_PROPERTY(At_Root_Expression*, expression)
ADD_PROPERTY(At_Root_Query*, expression)
public:
At_Root_Block(ParserState pstate, Block* b = 0, At_Root_Expression* e = 0)
At_Root_Block(ParserState pstate, Block* b = 0, At_Root_Query* e = 0)
: Has_Block(pstate, b), expression_(e)
{ statement_type(ATROOT); }
bool is_hoistable() { return true; }
bool bubbles() { return true; }
bool exclude_node(Statement* s) {
if (s->statement_type() == Statement::DIRECTIVE)
{
return expression()->exclude(static_cast<At_Rule*>(s)->keyword().erase(0, 1));
return expression()->exclude(static_cast<Directive*>(s)->keyword().erase(0, 1));
}
if (s->statement_type() == Statement::MEDIA)
{
Expand All @@ -1763,7 +1745,7 @@ namespace Sass {
{
return expression()->exclude("supports");
}
if (static_cast<At_Rule*>(s)->is_keyframes())
if (static_cast<Directive*>(s)->is_keyframes())
{
return expression()->exclude("keyframes");
}
Expand Down
2 changes: 1 addition & 1 deletion src/ast_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Sass {
Supports_Query* new_Supports_Query(std::string p, size_t l, Supports_Query* f, Block* b);
Media_Query* new_Media_Query(std::string p, size_t l, List* q, Block* b);
At_Root_Block* new_At_Root_Block(std::string p, size_t l, Selector* sel, Block* b);
At_Rule* new_At_Rule(std::string p, size_t l, std::string kwd, Selector* sel, Block* b);
Directive* new_At_Rule(std::string p, size_t l, std::string kwd, Selector* sel, Block* b);
Keyframe_Rule* new_Keyframe_Rule(std::string p, size_t l, Block* b);
Declaration* new_Declaration(std::string p, size_t l, String* prop, List* vals);
Assignment* new_Assignment(std::string p, size_t l, std::string var, Expression* val, bool guarded = false);
Expand Down
4 changes: 2 additions & 2 deletions src/ast_fwd_decl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Sass {
class Bubble;
class Media_Block;
class Supports_Block;
class At_Rule;
class Directive;
class Keyframe_Rule;
class At_Root_Block;
class Declaration;
Expand Down Expand Up @@ -62,7 +62,7 @@ namespace Sass {
class Supports_Negation;
class Supports_Declaration;
class Supports_Interpolation;
class At_Root_Expression;
class At_Root_Query;
class Null;
class Parent_Selector;
// parameters and arguments
Expand Down
2 changes: 2 additions & 0 deletions src/constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ namespace Sass {
extern const char expression_kwd[] = "expression";
extern const char calc_fn_kwd[] = "calc";

extern const char almost_any_value_class[] = "\"'#!;{}";

// css selector keywords
extern const char sel_deep_kwd[] = "/deep/";

Expand Down
3 changes: 3 additions & 0 deletions src/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ namespace Sass {
extern const char expression_kwd[];
extern const char calc_fn_kwd[];

// char classes for "regular expressions"
extern const char almost_any_value_class[];

// css selector keywords
extern const char sel_deep_kwd[];

Expand Down
26 changes: 18 additions & 8 deletions src/cssize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,22 @@ namespace Sass {
: ctx(ctx),
block_stack(std::vector<Block*>()),
p_stack(std::vector<Statement*>()),
s_stack(std::vector<Selector_List*>()),
backtrace(bt)
{ }
{
s_stack.push_back(NULL);
}

Statement* Cssize::parent()
{
return p_stack.size() ? p_stack.back() : block_stack.front();
}

Selector_List* Cssize::selector()
{
return s_stack.size() ? s_stack.back() : NULL;
}

Statement* Cssize::operator()(Block* b)
{
Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, b->pstate(), b->length(), b->is_root());
Expand All @@ -31,7 +39,7 @@ namespace Sass {
return bb;
}

Statement* Cssize::operator()(At_Rule* r)
Statement* Cssize::operator()(Directive* r)
{
if (!r->block() || !r->block()->length()) return r;

Expand All @@ -41,7 +49,7 @@ namespace Sass {
}

p_stack.push_back(r);
At_Rule* rr = SASS_MEMORY_NEW(ctx.mem, At_Rule,
Directive* rr = SASS_MEMORY_NEW(ctx.mem, Directive,
r->pstate(),
r->keyword(),
r->selector(),
Expand All @@ -57,15 +65,15 @@ namespace Sass {
else {
s = static_cast<Bubble*>(s)->node();
if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
else directive_exists = (static_cast<At_Rule*>(s)->keyword() == rr->keyword());
else directive_exists = (static_cast<Directive*>(s)->keyword() == rr->keyword());
}

}

Block* result = SASS_MEMORY_NEW(ctx.mem, Block, rr->pstate());
if (!(directive_exists || rr->is_keyframes()))
{
At_Rule* empty_node = static_cast<At_Rule*>(rr);
Directive* empty_node = static_cast<Directive*>(rr);
empty_node->block(SASS_MEMORY_NEW(ctx.mem, Block, rr->block() ? rr->block()->pstate() : rr->pstate()));
*result << empty_node;
}
Expand Down Expand Up @@ -93,12 +101,14 @@ namespace Sass {
Statement* Cssize::operator()(Ruleset* r)
{
p_stack.push_back(r);
s_stack.push_back(dynamic_cast<Selector_List*>(r->selector()));
Ruleset* rr = SASS_MEMORY_NEW(ctx.mem, Ruleset,
r->pstate(),
r->selector(),
r->block()->perform(this)->block());
rr->is_root(r->is_root());
// rr->tabs(r->block()->tabs());
s_stack.pop_back();
p_stack.pop_back();

if (!rr->block()) {
Expand Down Expand Up @@ -214,7 +224,7 @@ namespace Sass {
return bubble(m);
}

Statement* Cssize::bubble(At_Rule* m)
Statement* Cssize::bubble(Directive* m)
{
Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, this->parent()->pstate());
Has_Block* new_rule = static_cast<Has_Block*>(shallow_copy(this->parent()));
Expand All @@ -228,7 +238,7 @@ namespace Sass {

Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, m->block() ? m->block()->pstate() : m->pstate());
*wrapper_block << new_rule;
At_Rule* mm = SASS_MEMORY_NEW(ctx.mem, At_Rule,
Directive* mm = SASS_MEMORY_NEW(ctx.mem, Directive,
m->pstate(),
m->keyword(),
m->selector(),
Expand Down Expand Up @@ -375,7 +385,7 @@ namespace Sass {
case Statement::BUBBLE:
return SASS_MEMORY_NEW(ctx.mem, Bubble, *static_cast<Bubble*>(s));
case Statement::DIRECTIVE:
return SASS_MEMORY_NEW(ctx.mem, At_Rule, *static_cast<At_Rule*>(s));
return SASS_MEMORY_NEW(ctx.mem, Directive, *static_cast<Directive*>(s));
case Statement::SUPPORTS:
return SASS_MEMORY_NEW(ctx.mem, Supports_Block, *static_cast<Supports_Block*>(s));
case Statement::ATROOT:
Expand Down
Loading

0 comments on commit eaf3413

Please sign in to comment.