Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/directive parsing #2001

Merged
merged 2 commits into from
Apr 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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