Skip to content

Commit eaf3413

Browse files
committed
Merge pull request #2001 from mgreter/refactor/directive-parsing
Refactor/directive parsing
2 parents 2e97fdd + 83d401b commit eaf3413

31 files changed

+890
-187
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Miscellaneous stuff
22

3+
/sassc
4+
/sass-spec
5+
36
VERSION
47
.DS_Store
58
.sass-cache

src/ast.cpp

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
#include "color_maps.hpp"
88
#include <set>
99
#include <iomanip>
10-
#include <algorithm>
1110
#include <iostream>
11+
#include <algorithm>
12+
#include <functional>
13+
#include <cctype>
14+
#include <locale>
1215

1316
namespace Sass {
1417

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

31+
std::string & str_ltrim(std::string & str)
32+
{
33+
auto it2 = std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
34+
str.erase( str.begin() , it2);
35+
return str;
36+
}
37+
38+
std::string & str_rtrim(std::string & str)
39+
{
40+
auto it1 = std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
41+
str.erase( it1.base() , str.end() );
42+
return str;
43+
}
44+
45+
void String_Constant::rtrim()
46+
{
47+
value_ = str_rtrim(value_);
48+
}
49+
void String_Constant::ltrim()
50+
{
51+
value_ = str_ltrim(value_);
52+
}
53+
void String_Constant::trim()
54+
{
55+
rtrim();
56+
ltrim();
57+
}
58+
59+
void String_Schema::rtrim()
60+
{
61+
if (!empty()) {
62+
if (String* str = dynamic_cast<String*>(last())) str->rtrim();
63+
}
64+
}
65+
void String_Schema::ltrim()
66+
{
67+
if (!empty()) {
68+
if (String* str = dynamic_cast<String*>(first())) str->ltrim();
69+
}
70+
}
71+
void String_Schema::trim()
72+
{
73+
rtrim();
74+
ltrim();
75+
}
76+
77+
bool At_Root_Query::exclude(std::string str)
78+
{
79+
bool with = feature() && unquote(feature()->to_string()).compare("with") == 0;
80+
List* l = static_cast<List*>(value());
81+
std::string v;
82+
83+
if (with)
84+
{
85+
if (!l || l->length() == 0) return str.compare("rule") != 0;
86+
for (size_t i = 0, L = l->length(); i < L; ++i)
87+
{
88+
v = unquote((*l)[i]->to_string());
89+
if (v.compare("all") == 0 || v == str) return false;
90+
}
91+
return true;
92+
}
93+
else
94+
{
95+
if (!l || !l->length()) return str.compare("rule") == 0;
96+
for (size_t i = 0, L = l->length(); i < L; ++i)
97+
{
98+
v = unquote((*l)[i]->to_string());
99+
if (v.compare("all") == 0 || v == str) return true;
100+
}
101+
return false;
102+
}
103+
}
104+
28105
void AST_Node::update_pstate(const ParserState& pstate)
29106
{
30107
pstate_.offset += pstate - pstate_ + pstate.offset;
@@ -60,7 +137,7 @@ namespace Sass {
60137
bool Compound_Selector::has_parent_ref()
61138
{
62139
for (Simple_Selector* s : *this) {
63-
if (s->has_parent_ref()) return true;
140+
if (s && s->has_parent_ref()) return true;
64141
}
65142
return false;
66143
}
@@ -1293,7 +1370,7 @@ namespace Sass {
12931370
bool Selector_List::has_parent_ref()
12941371
{
12951372
for (Complex_Selector* s : *this) {
1296-
if (s->has_parent_ref()) return true;
1373+
if (s && s->has_parent_ref()) return true;
12971374
}
12981375
return false;
12991376
}

src/ast.hpp

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -524,12 +524,12 @@ namespace Sass {
524524
// At-rules -- arbitrary directives beginning with "@" that may have an
525525
// optional statement block.
526526
///////////////////////////////////////////////////////////////////////
527-
class At_Rule : public Has_Block {
527+
class Directive : public Has_Block {
528528
ADD_PROPERTY(std::string, keyword)
529529
ADD_PROPERTY(Selector*, selector)
530530
ADD_PROPERTY(Expression*, value)
531531
public:
532-
At_Rule(ParserState pstate, std::string kwd, Selector* sel = 0, Block* b = 0, Expression* val = 0)
532+
Directive(ParserState pstate, std::string kwd, Selector* sel = 0, Block* b = 0, Expression* val = 0)
533533
: Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed
534534
{ statement_type(DIRECTIVE); }
535535
bool bubbles() { return is_keyframes() || is_media(); }
@@ -1471,6 +1471,9 @@ namespace Sass {
14711471
{ concrete_type(STRING); }
14721472
static std::string type_name() { return "string"; }
14731473
virtual ~String() = 0;
1474+
virtual void rtrim() = 0;
1475+
virtual void ltrim() = 0;
1476+
virtual void trim() = 0;
14741477
virtual bool operator==(const Expression& rhs) const = 0;
14751478
ATTACH_OPERATIONS()
14761479
};
@@ -1499,6 +1502,9 @@ namespace Sass {
14991502
}
15001503
return false;
15011504
}
1505+
virtual void rtrim();
1506+
virtual void ltrim();
1507+
virtual void trim();
15021508

15031509
virtual size_t hash()
15041510
{
@@ -1539,6 +1545,9 @@ namespace Sass {
15391545
std::string type() { return "string"; }
15401546
static std::string type_name() { return "string"; }
15411547
virtual bool is_invisible() const;
1548+
virtual void rtrim();
1549+
virtual void ltrim();
1550+
virtual void trim();
15421551

15431552
virtual size_t hash()
15441553
{
@@ -1696,60 +1705,33 @@ namespace Sass {
16961705
/////////////////////////////////////////////////
16971706
// At root expressions (for use inside @at-root).
16981707
/////////////////////////////////////////////////
1699-
class At_Root_Expression : public Expression {
1708+
class At_Root_Query : public Expression {
17001709
private:
1701-
ADD_PROPERTY(String*, feature)
1710+
ADD_PROPERTY(Expression*, feature)
17021711
ADD_PROPERTY(Expression*, value)
1703-
ADD_PROPERTY(bool, is_interpolated)
17041712
public:
1705-
At_Root_Expression(ParserState pstate, String* f = 0, Expression* v = 0, bool i = false)
1706-
: Expression(pstate), feature_(f), value_(v), is_interpolated_(i)
1713+
At_Root_Query(ParserState pstate, Expression* f = 0, Expression* v = 0, bool i = false)
1714+
: Expression(pstate), feature_(f), value_(v)
17071715
{ }
1708-
bool exclude(std::string str)
1709-
{
1710-
bool with = feature() && unquote(feature()->to_string()).compare("with") == 0;
1711-
List* l = static_cast<List*>(value());
1712-
std::string v;
1713-
1714-
if (with)
1715-
{
1716-
if (!l || l->length() == 0) return str.compare("rule") != 0;
1717-
for (size_t i = 0, L = l->length(); i < L; ++i)
1718-
{
1719-
v = unquote((*l)[i]->to_string());
1720-
if (v.compare("all") == 0 || v == str) return false;
1721-
}
1722-
return true;
1723-
}
1724-
else
1725-
{
1726-
if (!l || !l->length()) return str.compare("rule") == 0;
1727-
for (size_t i = 0, L = l->length(); i < L; ++i)
1728-
{
1729-
v = unquote((*l)[i]->to_string());
1730-
if (v.compare("all") == 0 || v == str) return true;
1731-
}
1732-
return false;
1733-
}
1734-
}
1716+
bool exclude(std::string str);
17351717
ATTACH_OPERATIONS()
17361718
};
17371719

17381720
///////////
17391721
// At-root.
17401722
///////////
17411723
class At_Root_Block : public Has_Block {
1742-
ADD_PROPERTY(At_Root_Expression*, expression)
1724+
ADD_PROPERTY(At_Root_Query*, expression)
17431725
public:
1744-
At_Root_Block(ParserState pstate, Block* b = 0, At_Root_Expression* e = 0)
1726+
At_Root_Block(ParserState pstate, Block* b = 0, At_Root_Query* e = 0)
17451727
: Has_Block(pstate, b), expression_(e)
17461728
{ statement_type(ATROOT); }
17471729
bool is_hoistable() { return true; }
17481730
bool bubbles() { return true; }
17491731
bool exclude_node(Statement* s) {
17501732
if (s->statement_type() == Statement::DIRECTIVE)
17511733
{
1752-
return expression()->exclude(static_cast<At_Rule*>(s)->keyword().erase(0, 1));
1734+
return expression()->exclude(static_cast<Directive*>(s)->keyword().erase(0, 1));
17531735
}
17541736
if (s->statement_type() == Statement::MEDIA)
17551737
{
@@ -1763,7 +1745,7 @@ namespace Sass {
17631745
{
17641746
return expression()->exclude("supports");
17651747
}
1766-
if (static_cast<At_Rule*>(s)->is_keyframes())
1748+
if (static_cast<Directive*>(s)->is_keyframes())
17671749
{
17681750
return expression()->exclude("keyframes");
17691751
}

src/ast_factory.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Sass {
1717
Supports_Query* new_Supports_Query(std::string p, size_t l, Supports_Query* f, Block* b);
1818
Media_Query* new_Media_Query(std::string p, size_t l, List* q, Block* b);
1919
At_Root_Block* new_At_Root_Block(std::string p, size_t l, Selector* sel, Block* b);
20-
At_Rule* new_At_Rule(std::string p, size_t l, std::string kwd, Selector* sel, Block* b);
20+
Directive* new_At_Rule(std::string p, size_t l, std::string kwd, Selector* sel, Block* b);
2121
Keyframe_Rule* new_Keyframe_Rule(std::string p, size_t l, Block* b);
2222
Declaration* new_Declaration(std::string p, size_t l, String* prop, List* vals);
2323
Assignment* new_Assignment(std::string p, size_t l, std::string var, Expression* val, bool guarded = false);

src/ast_fwd_decl.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Sass {
1515
class Bubble;
1616
class Media_Block;
1717
class Supports_Block;
18-
class At_Rule;
18+
class Directive;
1919
class Keyframe_Rule;
2020
class At_Root_Block;
2121
class Declaration;
@@ -62,7 +62,7 @@ namespace Sass {
6262
class Supports_Negation;
6363
class Supports_Declaration;
6464
class Supports_Interpolation;
65-
class At_Root_Expression;
65+
class At_Root_Query;
6666
class Null;
6767
class Parent_Selector;
6868
// parameters and arguments

src/constants.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ namespace Sass {
8989
extern const char expression_kwd[] = "expression";
9090
extern const char calc_fn_kwd[] = "calc";
9191

92+
extern const char almost_any_value_class[] = "\"'#!;{}";
93+
9294
// css selector keywords
9395
extern const char sel_deep_kwd[] = "/deep/";
9496

src/constants.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ namespace Sass {
8989
extern const char expression_kwd[];
9090
extern const char calc_fn_kwd[];
9191

92+
// char classes for "regular expressions"
93+
extern const char almost_any_value_class[];
94+
9295
// css selector keywords
9396
extern const char sel_deep_kwd[];
9497

src/cssize.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,22 @@ namespace Sass {
1313
: ctx(ctx),
1414
block_stack(std::vector<Block*>()),
1515
p_stack(std::vector<Statement*>()),
16+
s_stack(std::vector<Selector_List*>()),
1617
backtrace(bt)
17-
{ }
18+
{
19+
s_stack.push_back(NULL);
20+
}
1821

1922
Statement* Cssize::parent()
2023
{
2124
return p_stack.size() ? p_stack.back() : block_stack.front();
2225
}
2326

27+
Selector_List* Cssize::selector()
28+
{
29+
return s_stack.size() ? s_stack.back() : NULL;
30+
}
31+
2432
Statement* Cssize::operator()(Block* b)
2533
{
2634
Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, b->pstate(), b->length(), b->is_root());
@@ -31,7 +39,7 @@ namespace Sass {
3139
return bb;
3240
}
3341

34-
Statement* Cssize::operator()(At_Rule* r)
42+
Statement* Cssize::operator()(Directive* r)
3543
{
3644
if (!r->block() || !r->block()->length()) return r;
3745

@@ -41,7 +49,7 @@ namespace Sass {
4149
}
4250

4351
p_stack.push_back(r);
44-
At_Rule* rr = SASS_MEMORY_NEW(ctx.mem, At_Rule,
52+
Directive* rr = SASS_MEMORY_NEW(ctx.mem, Directive,
4553
r->pstate(),
4654
r->keyword(),
4755
r->selector(),
@@ -57,15 +65,15 @@ namespace Sass {
5765
else {
5866
s = static_cast<Bubble*>(s)->node();
5967
if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
60-
else directive_exists = (static_cast<At_Rule*>(s)->keyword() == rr->keyword());
68+
else directive_exists = (static_cast<Directive*>(s)->keyword() == rr->keyword());
6169
}
6270

6371
}
6472

6573
Block* result = SASS_MEMORY_NEW(ctx.mem, Block, rr->pstate());
6674
if (!(directive_exists || rr->is_keyframes()))
6775
{
68-
At_Rule* empty_node = static_cast<At_Rule*>(rr);
76+
Directive* empty_node = static_cast<Directive*>(rr);
6977
empty_node->block(SASS_MEMORY_NEW(ctx.mem, Block, rr->block() ? rr->block()->pstate() : rr->pstate()));
7078
*result << empty_node;
7179
}
@@ -93,12 +101,14 @@ namespace Sass {
93101
Statement* Cssize::operator()(Ruleset* r)
94102
{
95103
p_stack.push_back(r);
104+
s_stack.push_back(dynamic_cast<Selector_List*>(r->selector()));
96105
Ruleset* rr = SASS_MEMORY_NEW(ctx.mem, Ruleset,
97106
r->pstate(),
98107
r->selector(),
99108
r->block()->perform(this)->block());
100109
rr->is_root(r->is_root());
101110
// rr->tabs(r->block()->tabs());
111+
s_stack.pop_back();
102112
p_stack.pop_back();
103113

104114
if (!rr->block()) {
@@ -214,7 +224,7 @@ namespace Sass {
214224
return bubble(m);
215225
}
216226

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

229239
Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, m->block() ? m->block()->pstate() : m->pstate());
230240
*wrapper_block << new_rule;
231-
At_Rule* mm = SASS_MEMORY_NEW(ctx.mem, At_Rule,
241+
Directive* mm = SASS_MEMORY_NEW(ctx.mem, Directive,
232242
m->pstate(),
233243
m->keyword(),
234244
m->selector(),
@@ -375,7 +385,7 @@ namespace Sass {
375385
case Statement::BUBBLE:
376386
return SASS_MEMORY_NEW(ctx.mem, Bubble, *static_cast<Bubble*>(s));
377387
case Statement::DIRECTIVE:
378-
return SASS_MEMORY_NEW(ctx.mem, At_Rule, *static_cast<At_Rule*>(s));
388+
return SASS_MEMORY_NEW(ctx.mem, Directive, *static_cast<Directive*>(s));
379389
case Statement::SUPPORTS:
380390
return SASS_MEMORY_NEW(ctx.mem, Supports_Block, *static_cast<Supports_Block*>(s));
381391
case Statement::ATROOT:

0 commit comments

Comments
 (0)