sassc 2.2.1 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +13 -0
- data/Rakefile +1 -3
- data/ext/extconf.rb +13 -5
- data/ext/libsass/VERSION +1 -1
- data/ext/libsass/include/sass/base.h +2 -1
- data/ext/libsass/include/sass/context.h +1 -0
- data/ext/libsass/src/ast.cpp +49 -59
- data/ext/libsass/src/ast.hpp +263 -102
- data/ext/libsass/src/ast_def_macros.hpp +8 -0
- data/ext/libsass/src/ast_fwd_decl.cpp +2 -1
- data/ext/libsass/src/ast_fwd_decl.hpp +40 -116
- data/ext/libsass/src/ast_helpers.hpp +292 -0
- data/ext/libsass/src/ast_sel_cmp.cpp +209 -722
- data/ext/libsass/src/ast_sel_super.cpp +539 -0
- data/ext/libsass/src/ast_sel_unify.cpp +207 -212
- data/ext/libsass/src/ast_sel_weave.cpp +616 -0
- data/ext/libsass/src/ast_selectors.cpp +559 -1001
- data/ext/libsass/src/ast_selectors.hpp +311 -367
- data/ext/libsass/src/ast_supports.cpp +1 -17
- data/ext/libsass/src/ast_values.cpp +216 -29
- data/ext/libsass/src/ast_values.hpp +42 -33
- data/ext/libsass/src/bind.cpp +1 -1
- data/ext/libsass/src/cencode.c +4 -6
- data/ext/libsass/src/check_nesting.cpp +5 -6
- data/ext/libsass/src/check_nesting.hpp +4 -0
- data/ext/libsass/src/color_maps.cpp +11 -10
- data/ext/libsass/src/color_maps.hpp +0 -8
- data/ext/libsass/src/constants.cpp +5 -0
- data/ext/libsass/src/constants.hpp +6 -0
- data/ext/libsass/src/context.cpp +30 -60
- data/ext/libsass/src/context.hpp +8 -20
- data/ext/libsass/src/cssize.cpp +36 -120
- data/ext/libsass/src/cssize.hpp +4 -10
- data/ext/libsass/src/dart_helpers.hpp +199 -0
- data/ext/libsass/src/debugger.hpp +364 -207
- data/ext/libsass/src/emitter.cpp +3 -4
- data/ext/libsass/src/emitter.hpp +0 -2
- data/ext/libsass/src/environment.hpp +5 -0
- data/ext/libsass/src/error_handling.cpp +21 -0
- data/ext/libsass/src/error_handling.hpp +25 -3
- data/ext/libsass/src/eval.cpp +33 -153
- data/ext/libsass/src/eval.hpp +11 -13
- data/ext/libsass/src/eval_selectors.cpp +75 -0
- data/ext/libsass/src/expand.cpp +214 -167
- data/ext/libsass/src/expand.hpp +26 -6
- data/ext/libsass/src/extender.cpp +1186 -0
- data/ext/libsass/src/extender.hpp +399 -0
- data/ext/libsass/src/extension.cpp +43 -0
- data/ext/libsass/src/extension.hpp +89 -0
- data/ext/libsass/src/file.cpp +15 -14
- data/ext/libsass/src/file.hpp +5 -12
- data/ext/libsass/src/fn_colors.cpp +12 -10
- data/ext/libsass/src/fn_lists.cpp +12 -11
- data/ext/libsass/src/fn_miscs.cpp +22 -34
- data/ext/libsass/src/fn_numbers.cpp +13 -6
- data/ext/libsass/src/fn_selectors.cpp +94 -124
- data/ext/libsass/src/fn_strings.cpp +16 -14
- data/ext/libsass/src/fn_utils.cpp +5 -6
- data/ext/libsass/src/fn_utils.hpp +9 -3
- data/ext/libsass/src/inspect.cpp +154 -117
- data/ext/libsass/src/inspect.hpp +10 -8
- data/ext/libsass/src/lexer.cpp +17 -81
- data/ext/libsass/src/lexer.hpp +5 -16
- data/ext/libsass/src/listize.cpp +22 -36
- data/ext/libsass/src/listize.hpp +8 -9
- data/ext/libsass/src/memory/SharedPtr.hpp +39 -5
- data/ext/libsass/src/operation.hpp +27 -17
- data/ext/libsass/src/operators.cpp +1 -0
- data/ext/libsass/src/ordered_map.hpp +112 -0
- data/ext/libsass/src/output.cpp +30 -49
- data/ext/libsass/src/output.hpp +1 -1
- data/ext/libsass/src/parser.cpp +211 -381
- data/ext/libsass/src/parser.hpp +17 -15
- data/ext/libsass/src/parser_selectors.cpp +189 -0
- data/ext/libsass/src/permutate.hpp +140 -0
- data/ext/libsass/src/position.hpp +1 -1
- data/ext/libsass/src/prelexer.cpp +6 -6
- data/ext/libsass/src/remove_placeholders.cpp +55 -56
- data/ext/libsass/src/remove_placeholders.hpp +21 -18
- data/ext/libsass/src/sass.hpp +1 -0
- data/ext/libsass/src/sass2scss.cpp +4 -4
- data/ext/libsass/src/sass_context.cpp +42 -91
- data/ext/libsass/src/sass_context.hpp +2 -2
- data/ext/libsass/src/sass_functions.cpp +1 -1
- data/ext/libsass/src/sass_values.cpp +0 -1
- data/ext/libsass/src/stylesheet.cpp +22 -0
- data/ext/libsass/src/stylesheet.hpp +57 -0
- data/ext/libsass/src/to_value.cpp +2 -2
- data/ext/libsass/src/to_value.hpp +1 -1
- data/ext/libsass/src/units.cpp +5 -3
- data/ext/libsass/src/util.cpp +10 -12
- data/ext/libsass/src/util.hpp +2 -3
- data/ext/libsass/src/util_string.cpp +111 -61
- data/ext/libsass/src/util_string.hpp +61 -8
- data/lib/sassc/engine.rb +5 -3
- data/lib/sassc/functions_handler.rb +8 -8
- data/lib/sassc/native.rb +1 -1
- data/lib/sassc/script.rb +4 -4
- data/lib/sassc/version.rb +1 -1
- data/test/functions_test.rb +18 -1
- data/test/native_test.rb +1 -1
- metadata +17 -12
- data/ext/libsass/src/extend.cpp +0 -2132
- data/ext/libsass/src/extend.hpp +0 -86
- data/ext/libsass/src/node.cpp +0 -322
- data/ext/libsass/src/node.hpp +0 -118
- data/ext/libsass/src/paths.hpp +0 -71
- data/ext/libsass/src/sass_util.cpp +0 -152
- data/ext/libsass/src/sass_util.hpp +0 -256
- data/ext/libsass/src/subset_map.cpp +0 -58
- data/ext/libsass/src/subset_map.hpp +0 -76
@@ -1,9 +1,14 @@
|
|
1
1
|
#ifndef SASS_OPERATION_H
|
2
2
|
#define SASS_OPERATION_H
|
3
3
|
|
4
|
+
// sass.hpp must go before all system headers to get the
|
5
|
+
// __EXTENSIONS__ fix on Solaris.
|
6
|
+
#include "sass.hpp"
|
7
|
+
|
4
8
|
// base classes to implement curiously recurring template pattern (CRTP)
|
5
9
|
// https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
|
6
10
|
|
11
|
+
#include <typeinfo>
|
7
12
|
#include <stdexcept>
|
8
13
|
|
9
14
|
#include "ast_fwd_decl.hpp"
|
@@ -47,7 +52,9 @@ namespace Sass {
|
|
47
52
|
virtual T operator()(Bubble* x) = 0;
|
48
53
|
virtual T operator()(Trace* x) = 0;
|
49
54
|
virtual T operator()(Supports_Block* x) = 0;
|
50
|
-
virtual T operator()(
|
55
|
+
virtual T operator()(MediaRule* x) = 0;
|
56
|
+
virtual T operator()(CssMediaRule* x) = 0;
|
57
|
+
virtual T operator()(CssMediaQuery* x) = 0;
|
51
58
|
virtual T operator()(At_Root_Block* x) = 0;
|
52
59
|
virtual T operator()(Directive* x) = 0;
|
53
60
|
virtual T operator()(Keyframe_Rule* x) = 0;
|
@@ -65,7 +72,7 @@ namespace Sass {
|
|
65
72
|
virtual T operator()(While* x) = 0;
|
66
73
|
virtual T operator()(Return* x) = 0;
|
67
74
|
virtual T operator()(Content* x) = 0;
|
68
|
-
virtual T operator()(
|
75
|
+
virtual T operator()(ExtendRule* x) = 0;
|
69
76
|
virtual T operator()(Definition* x) = 0;
|
70
77
|
virtual T operator()(Mixin_Call* x) = 0;
|
71
78
|
// expressions
|
@@ -92,10 +99,9 @@ namespace Sass {
|
|
92
99
|
virtual T operator()(Supports_Negation* x) = 0;
|
93
100
|
virtual T operator()(Supports_Declaration* x) = 0;
|
94
101
|
virtual T operator()(Supports_Interpolation* x) = 0;
|
95
|
-
virtual T operator()(Media_Query* x)
|
102
|
+
virtual T operator()(Media_Query* x) = 0;
|
96
103
|
virtual T operator()(Media_Query_Expression* x) = 0;
|
97
104
|
virtual T operator()(At_Root_Query* x) = 0;
|
98
|
-
virtual T operator()(Parent_Selector* x) = 0;
|
99
105
|
virtual T operator()(Parent_Reference* x) = 0;
|
100
106
|
// parameters and arguments
|
101
107
|
virtual T operator()(Parameter* x) = 0;
|
@@ -110,16 +116,18 @@ namespace Sass {
|
|
110
116
|
virtual T operator()(Id_Selector* x) = 0;
|
111
117
|
virtual T operator()(Attribute_Selector* x) = 0;
|
112
118
|
virtual T operator()(Pseudo_Selector* x) = 0;
|
113
|
-
virtual T operator()(
|
114
|
-
virtual T operator()(
|
115
|
-
virtual T operator()(
|
116
|
-
virtual T operator()(
|
119
|
+
virtual T operator()(SelectorComponent* x) = 0;
|
120
|
+
virtual T operator()(SelectorCombinator* x) = 0;
|
121
|
+
virtual T operator()(CompoundSelector* x) = 0;
|
122
|
+
virtual T operator()(ComplexSelector* x) = 0;
|
123
|
+
virtual T operator()(SelectorList* x) = 0;
|
124
|
+
|
117
125
|
};
|
118
126
|
|
119
127
|
// example: Operation_CRTP<Expression*, Eval>
|
120
128
|
// T is the base return type of all visitors
|
121
129
|
// D is the class derived visitor class
|
122
|
-
//
|
130
|
+
// normally you want to implement all operators
|
123
131
|
template <typename T, typename D>
|
124
132
|
class Operation_CRTP : public Operation<T> {
|
125
133
|
public:
|
@@ -130,7 +138,9 @@ namespace Sass {
|
|
130
138
|
T operator()(Bubble* x) { return static_cast<D*>(this)->fallback(x); }
|
131
139
|
T operator()(Trace* x) { return static_cast<D*>(this)->fallback(x); }
|
132
140
|
T operator()(Supports_Block* x) { return static_cast<D*>(this)->fallback(x); }
|
133
|
-
T operator()(
|
141
|
+
T operator()(MediaRule* x) { return static_cast<D*>(this)->fallback(x); }
|
142
|
+
T operator()(CssMediaRule* x) { return static_cast<D*>(this)->fallback(x); }
|
143
|
+
T operator()(CssMediaQuery* x) { return static_cast<D*>(this)->fallback(x); }
|
134
144
|
T operator()(At_Root_Block* x) { return static_cast<D*>(this)->fallback(x); }
|
135
145
|
T operator()(Directive* x) { return static_cast<D*>(this)->fallback(x); }
|
136
146
|
T operator()(Keyframe_Rule* x) { return static_cast<D*>(this)->fallback(x); }
|
@@ -148,7 +158,7 @@ namespace Sass {
|
|
148
158
|
T operator()(While* x) { return static_cast<D*>(this)->fallback(x); }
|
149
159
|
T operator()(Return* x) { return static_cast<D*>(this)->fallback(x); }
|
150
160
|
T operator()(Content* x) { return static_cast<D*>(this)->fallback(x); }
|
151
|
-
T operator()(
|
161
|
+
T operator()(ExtendRule* x) { return static_cast<D*>(this)->fallback(x); }
|
152
162
|
T operator()(Definition* x) { return static_cast<D*>(this)->fallback(x); }
|
153
163
|
T operator()(Mixin_Call* x) { return static_cast<D*>(this)->fallback(x); }
|
154
164
|
// expressions
|
@@ -178,7 +188,6 @@ namespace Sass {
|
|
178
188
|
T operator()(Media_Query* x) { return static_cast<D*>(this)->fallback(x); }
|
179
189
|
T operator()(Media_Query_Expression* x) { return static_cast<D*>(this)->fallback(x); }
|
180
190
|
T operator()(At_Root_Query* x) { return static_cast<D*>(this)->fallback(x); }
|
181
|
-
T operator()(Parent_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
182
191
|
T operator()(Parent_Reference* x) { return static_cast<D*>(this)->fallback(x); }
|
183
192
|
// parameters and arguments
|
184
193
|
T operator()(Parameter* x) { return static_cast<D*>(this)->fallback(x); }
|
@@ -193,14 +202,15 @@ namespace Sass {
|
|
193
202
|
T operator()(Id_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
194
203
|
T operator()(Attribute_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
195
204
|
T operator()(Pseudo_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
196
|
-
T operator()(
|
197
|
-
T operator()(
|
198
|
-
T operator()(
|
199
|
-
T operator()(
|
205
|
+
T operator()(SelectorComponent* x) { return static_cast<D*>(this)->fallback(x); }
|
206
|
+
T operator()(SelectorCombinator* x) { return static_cast<D*>(this)->fallback(x); }
|
207
|
+
T operator()(CompoundSelector* x) { return static_cast<D*>(this)->fallback(x); }
|
208
|
+
T operator()(ComplexSelector* x) { return static_cast<D*>(this)->fallback(x); }
|
209
|
+
T operator()(SelectorList* x) { return static_cast<D*>(this)->fallback(x); }
|
200
210
|
|
201
211
|
// fallback with specific type U
|
202
212
|
// will be called if not overloaded
|
203
|
-
template <typename U> T fallback(U x)
|
213
|
+
template <typename U> inline T fallback(U x)
|
204
214
|
{
|
205
215
|
throw std::runtime_error(
|
206
216
|
std::string(typeid(*this).name()) + ": CRTP not implemented for " + typeid(x).name());
|
@@ -0,0 +1,112 @@
|
|
1
|
+
#ifndef SASS_ORDERED_MAP_H
|
2
|
+
#define SASS_ORDERED_MAP_H
|
3
|
+
|
4
|
+
namespace Sass {
|
5
|
+
|
6
|
+
// ##########################################################################
|
7
|
+
// Very simple and limited container for insert ordered hash map.
|
8
|
+
// Piggy-back implementation on std::unordered_map and std::vector
|
9
|
+
// ##########################################################################
|
10
|
+
template<
|
11
|
+
class Key,
|
12
|
+
class T,
|
13
|
+
class Hash = std::hash<Key>,
|
14
|
+
class KeyEqual = std::equal_to<Key>,
|
15
|
+
class Allocator = std::allocator<std::pair<const Key, T>>
|
16
|
+
>
|
17
|
+
class ordered_map {
|
18
|
+
|
19
|
+
private:
|
20
|
+
|
21
|
+
using map_type = typename std::unordered_map< Key, T, Hash, KeyEqual, Allocator>;
|
22
|
+
using map_iterator = typename std::unordered_map< Key, T, Hash, KeyEqual, Allocator>::iterator;
|
23
|
+
using map_const_iterator = typename std::unordered_map< Key, T, Hash, KeyEqual, Allocator>::const_iterator;
|
24
|
+
|
25
|
+
// The main unordered map
|
26
|
+
map_type _map;
|
27
|
+
|
28
|
+
// Keep insertion order
|
29
|
+
std::vector<Key> _keys;
|
30
|
+
std::vector<T> _values;
|
31
|
+
|
32
|
+
const KeyEqual _keyEqual;
|
33
|
+
|
34
|
+
public:
|
35
|
+
|
36
|
+
ordered_map() :
|
37
|
+
_keyEqual(KeyEqual())
|
38
|
+
{
|
39
|
+
}
|
40
|
+
|
41
|
+
ordered_map& operator= (const ordered_map& other) {
|
42
|
+
_map = other._map;
|
43
|
+
_keys = other._keys;
|
44
|
+
_values = other._values;
|
45
|
+
return *this;
|
46
|
+
}
|
47
|
+
|
48
|
+
std::pair<Key, T> front() {
|
49
|
+
return std::make_pair(
|
50
|
+
_keys.front(),
|
51
|
+
_values.front()
|
52
|
+
);
|
53
|
+
}
|
54
|
+
|
55
|
+
bool empty() const {
|
56
|
+
return _keys.empty();
|
57
|
+
}
|
58
|
+
|
59
|
+
void insert(const Key& key, const T& val) {
|
60
|
+
if (!hasKey(key)) {
|
61
|
+
_values.push_back(val);
|
62
|
+
_keys.push_back(key);
|
63
|
+
}
|
64
|
+
_map[key] = val;
|
65
|
+
}
|
66
|
+
|
67
|
+
bool hasKey(const Key& key) const {
|
68
|
+
return _map.find(key) != _map.end();
|
69
|
+
}
|
70
|
+
|
71
|
+
bool erase(const Key& key) {
|
72
|
+
_map.erase(key);
|
73
|
+
// find the position in the array
|
74
|
+
for (size_t i = 0; i < _keys.size(); i += 1) {
|
75
|
+
if (_keyEqual(key, _keys[i])) {
|
76
|
+
_keys.erase(_keys.begin() + i);
|
77
|
+
_values.erase(_values.begin() + i);
|
78
|
+
return true;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
return false;
|
82
|
+
}
|
83
|
+
|
84
|
+
const std::vector<Key>& keys() const { return _keys; }
|
85
|
+
const std::vector<T>& values() const { return _values; }
|
86
|
+
|
87
|
+
const T& get(const Key& key) {
|
88
|
+
if (hasKey(key)) {
|
89
|
+
return _map[key];
|
90
|
+
}
|
91
|
+
throw std::runtime_error("Key does not exist");
|
92
|
+
}
|
93
|
+
|
94
|
+
using iterator = typename std::vector<Key>::iterator;
|
95
|
+
using const_iterator = typename std::vector<Key>::const_iterator;
|
96
|
+
using reverse_iterator = typename std::vector<Key>::reverse_iterator;
|
97
|
+
using const_reverse_iterator = typename std::vector<Key>::const_reverse_iterator;
|
98
|
+
|
99
|
+
typename std::vector<Key>::iterator end() { return _keys.end(); }
|
100
|
+
typename std::vector<Key>::iterator begin() { return _keys.begin(); }
|
101
|
+
typename std::vector<Key>::reverse_iterator rend() { return _keys.rend(); }
|
102
|
+
typename std::vector<Key>::reverse_iterator rbegin() { return _keys.rbegin(); }
|
103
|
+
typename std::vector<Key>::const_iterator end() const { return _keys.end(); }
|
104
|
+
typename std::vector<Key>::const_iterator begin() const { return _keys.begin(); }
|
105
|
+
typename std::vector<Key>::const_reverse_iterator rend() const { return _keys.rend(); }
|
106
|
+
typename std::vector<Key>::const_reverse_iterator rbegin() const { return _keys.rbegin(); }
|
107
|
+
|
108
|
+
};
|
109
|
+
|
110
|
+
}
|
111
|
+
|
112
|
+
#endif
|
data/ext/libsass/src/output.cpp
CHANGED
@@ -113,13 +113,15 @@ namespace Sass {
|
|
113
113
|
|
114
114
|
void Output::operator()(Ruleset* r)
|
115
115
|
{
|
116
|
-
|
117
|
-
|
116
|
+
Block_Obj b = r->block();
|
117
|
+
SelectorListObj s = r->selector();
|
118
|
+
|
119
|
+
if (!s || s->empty()) return;
|
118
120
|
|
119
121
|
// Filter out rulesets that aren't printable (process its children though)
|
120
122
|
if (!Util::isPrintable(r, output_style())) {
|
121
123
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
122
|
-
const Statement_Obj& stm = b->
|
124
|
+
const Statement_Obj& stm = b->get(i);
|
123
125
|
if (Cast<Has_Block>(stm)) {
|
124
126
|
if (!Cast<Declaration>(stm)) {
|
125
127
|
stm->perform(this);
|
@@ -129,7 +131,9 @@ namespace Sass {
|
|
129
131
|
return;
|
130
132
|
}
|
131
133
|
|
132
|
-
if (output_style() == NESTED)
|
134
|
+
if (output_style() == NESTED) {
|
135
|
+
indentation += r->tabs();
|
136
|
+
}
|
133
137
|
if (opt.source_comments) {
|
134
138
|
std::stringstream ss;
|
135
139
|
append_indentation();
|
@@ -142,13 +146,13 @@ namespace Sass {
|
|
142
146
|
if (s) s->perform(this);
|
143
147
|
append_scope_opener(b);
|
144
148
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
145
|
-
Statement_Obj stm = b->
|
149
|
+
Statement_Obj stm = b->get(i);
|
146
150
|
bool bPrintExpression = true;
|
147
151
|
// Check print conditions
|
148
152
|
if (Declaration* dec = Cast<Declaration>(stm)) {
|
149
|
-
if (String_Constant* valConst = Cast<String_Constant>(dec->value())) {
|
150
|
-
std::string val
|
151
|
-
if (String_Quoted* qstr = Cast<String_Quoted>(valConst)) {
|
153
|
+
if (const String_Constant* valConst = Cast<String_Constant>(dec->value())) {
|
154
|
+
const std::string& val = valConst->value();
|
155
|
+
if (const String_Quoted* qstr = Cast<const String_Quoted>(valConst)) {
|
152
156
|
if (!qstr->quote_mark() && val.empty()) {
|
153
157
|
bPrintExpression = false;
|
154
158
|
}
|
@@ -157,7 +161,7 @@ namespace Sass {
|
|
157
161
|
else if (List* list = Cast<List>(dec->value())) {
|
158
162
|
bool all_invisible = true;
|
159
163
|
for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
|
160
|
-
Expression* item = list->
|
164
|
+
Expression* item = list->get(list_i);
|
161
165
|
if (!item->is_invisible()) all_invisible = false;
|
162
166
|
}
|
163
167
|
if (all_invisible && !list->is_bracketed()) bPrintExpression = false;
|
@@ -188,7 +192,7 @@ namespace Sass {
|
|
188
192
|
|
189
193
|
append_scope_opener();
|
190
194
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
191
|
-
Statement_Obj stm = b->
|
195
|
+
Statement_Obj stm = b->get(i);
|
192
196
|
stm->perform(this);
|
193
197
|
if (i < L - 1) append_special_linefeed();
|
194
198
|
}
|
@@ -205,7 +209,7 @@ namespace Sass {
|
|
205
209
|
// Filter out feature blocks that aren't printable (process its children though)
|
206
210
|
if (!Util::isPrintable(f, output_style())) {
|
207
211
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
208
|
-
Statement_Obj stm = b->
|
212
|
+
Statement_Obj stm = b->get(i);
|
209
213
|
if (Cast<Has_Block>(stm)) {
|
210
214
|
stm->perform(this);
|
211
215
|
}
|
@@ -221,7 +225,7 @@ namespace Sass {
|
|
221
225
|
append_scope_opener();
|
222
226
|
|
223
227
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
224
|
-
Statement_Obj stm = b->
|
228
|
+
Statement_Obj stm = b->get(i);
|
225
229
|
stm->perform(this);
|
226
230
|
if (i < L - 1) append_special_linefeed();
|
227
231
|
}
|
@@ -232,41 +236,21 @@ namespace Sass {
|
|
232
236
|
|
233
237
|
}
|
234
238
|
|
235
|
-
void Output::operator()(
|
239
|
+
void Output::operator()(CssMediaRule* rule)
|
236
240
|
{
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
//
|
242
|
-
if (
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
return;
|
241
|
+
// Avoid null pointer exception
|
242
|
+
if (rule == nullptr) return;
|
243
|
+
// Skip empty/invisible rule
|
244
|
+
if (rule->isInvisible()) return;
|
245
|
+
// Avoid null pointer exception
|
246
|
+
if (rule->block() == nullptr) return;
|
247
|
+
// Skip empty/invisible rule
|
248
|
+
if (rule->block()->isInvisible()) return;
|
249
|
+
// Skip if block is empty/invisible
|
250
|
+
if (Util::isPrintable(rule, output_style())) {
|
251
|
+
// Let inspect do its magic
|
252
|
+
Inspect::operator()(rule);
|
250
253
|
}
|
251
|
-
if (output_style() == NESTED) indentation += m->tabs();
|
252
|
-
append_indentation();
|
253
|
-
append_token("@media", m);
|
254
|
-
append_mandatory_space();
|
255
|
-
in_media_block = true;
|
256
|
-
m->media_queries()->perform(this);
|
257
|
-
in_media_block = false;
|
258
|
-
append_scope_opener();
|
259
|
-
|
260
|
-
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
261
|
-
if (b->at(i)) {
|
262
|
-
Statement_Obj stm = b->at(i);
|
263
|
-
stm->perform(this);
|
264
|
-
}
|
265
|
-
if (i < L - 1) append_special_linefeed();
|
266
|
-
}
|
267
|
-
|
268
|
-
if (output_style() == NESTED) indentation -= m->tabs();
|
269
|
-
append_scope_closer();
|
270
254
|
}
|
271
255
|
|
272
256
|
void Output::operator()(Directive* a)
|
@@ -304,7 +288,7 @@ namespace Sass {
|
|
304
288
|
bool format = kwd != "@font-face";;
|
305
289
|
|
306
290
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
307
|
-
Statement_Obj stm = b->
|
291
|
+
Statement_Obj stm = b->get(i);
|
308
292
|
stm->perform(this);
|
309
293
|
if (i < L - 1 && format) append_special_linefeed();
|
310
294
|
}
|
@@ -326,9 +310,6 @@ namespace Sass {
|
|
326
310
|
void Output::operator()(String_Constant* s)
|
327
311
|
{
|
328
312
|
std::string value(s->value());
|
329
|
-
if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
|
330
|
-
value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
|
331
|
-
}
|
332
313
|
if (!in_comment && !in_custom_property) {
|
333
314
|
append_token(string_to_output(value), s);
|
334
315
|
} else {
|
data/ext/libsass/src/output.hpp
CHANGED
@@ -29,7 +29,7 @@ namespace Sass {
|
|
29
29
|
virtual void operator()(Map*);
|
30
30
|
virtual void operator()(Ruleset*);
|
31
31
|
virtual void operator()(Supports_Block*);
|
32
|
-
virtual void operator()(
|
32
|
+
virtual void operator()(CssMediaRule*);
|
33
33
|
virtual void operator()(Directive*);
|
34
34
|
virtual void operator()(Keyframe_Rule*);
|
35
35
|
virtual void operator()(Import*);
|
data/ext/libsass/src/parser.cpp
CHANGED
@@ -3,14 +3,7 @@
|
|
3
3
|
#include "sass.hpp"
|
4
4
|
|
5
5
|
#include "parser.hpp"
|
6
|
-
#include "file.hpp"
|
7
|
-
#include "inspect.hpp"
|
8
|
-
#include "constants.hpp"
|
9
|
-
#include "util.hpp"
|
10
|
-
#include "prelexer.hpp"
|
11
6
|
#include "color_maps.hpp"
|
12
|
-
#include "sass/functions.h"
|
13
|
-
#include "error_handling.hpp"
|
14
7
|
#include "util_string.hpp"
|
15
8
|
|
16
9
|
// Notes about delayed: some ast nodes can have delayed evaluation so
|
@@ -25,10 +18,6 @@
|
|
25
18
|
// Another case with delayed values are colors. In compressed mode
|
26
19
|
// only processed values get compressed (other are left as written).
|
27
20
|
|
28
|
-
#include <cstdlib>
|
29
|
-
#include <iostream>
|
30
|
-
#include <vector>
|
31
|
-
#include <typeinfo>
|
32
21
|
|
33
22
|
namespace Sass {
|
34
23
|
using namespace Constants;
|
@@ -70,11 +59,11 @@ namespace Sass {
|
|
70
59
|
pstate.offset.line = 0;
|
71
60
|
}
|
72
61
|
|
73
|
-
|
62
|
+
SelectorListObj Parser::parse_selector(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source, bool allow_parent)
|
74
63
|
{
|
75
64
|
Parser p = Parser::from_c_str(beg, ctx, traces, pstate, source, allow_parent);
|
76
65
|
// ToDo: remap the source-map entries somehow
|
77
|
-
return p.
|
66
|
+
return p.parseSelectorList(false);
|
78
67
|
}
|
79
68
|
|
80
69
|
bool Parser::peek_newline(const char* start)
|
@@ -261,16 +250,23 @@ namespace Sass {
|
|
261
250
|
else if (lex < kwd_extend >(true)) {
|
262
251
|
Lookahead lookahead = lookahead_for_include(position);
|
263
252
|
if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was ");
|
264
|
-
|
253
|
+
SelectorListObj target;
|
265
254
|
if (!lookahead.has_interpolants) {
|
266
|
-
|
255
|
+
LOCAL_FLAG(allow_parent, false);
|
256
|
+
auto selector = parseSelectorList(true);
|
257
|
+
auto extender = SASS_MEMORY_NEW(ExtendRule, pstate, selector);
|
258
|
+
extender->isOptional(selector && selector->is_optional());
|
259
|
+
block->append(extender);
|
267
260
|
}
|
268
261
|
else {
|
269
|
-
|
270
|
-
|
262
|
+
LOCAL_FLAG(allow_parent, false);
|
263
|
+
auto selector = parse_selector_schema(lookahead.found, true);
|
264
|
+
auto extender = SASS_MEMORY_NEW(ExtendRule, pstate, selector);
|
265
|
+
// A schema is not optional yet, check once it is evaluated
|
266
|
+
// extender->isOptional(selector && selector->is_optional());
|
267
|
+
block->append(extender);
|
271
268
|
}
|
272
269
|
|
273
|
-
block->append(SASS_MEMORY_NEW(Extension, pstate, target));
|
274
270
|
}
|
275
271
|
|
276
272
|
// selector may contain interpolations which need delayed evaluation
|
@@ -283,7 +279,7 @@ namespace Sass {
|
|
283
279
|
}
|
284
280
|
|
285
281
|
// parse multiple specific keyword directives
|
286
|
-
else if (lex < kwd_media >(true)) { block->append(
|
282
|
+
else if (lex < kwd_media >(true)) { block->append(parseMediaRule()); }
|
287
283
|
else if (lex < kwd_at_root >(true)) { block->append(parse_at_root_block()); }
|
288
284
|
else if (lex < kwd_include_directive >(true)) { block->append(parse_include_directive()); }
|
289
285
|
else if (lex < kwd_content_directive >(true)) { block->append(parse_content_directive()); }
|
@@ -294,9 +290,9 @@ namespace Sass {
|
|
294
290
|
// ignore the @charset directive for now
|
295
291
|
else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
|
296
292
|
|
293
|
+
else if (lex < exactly < else_kwd >>(true)) { error("Invalid CSS: @else must come after @if"); }
|
294
|
+
|
297
295
|
// generic at keyword (keep last)
|
298
|
-
else if (lex< re_special_directive >(true)) { block->append(parse_special_directive()); }
|
299
|
-
else if (lex< re_prefixed_directive >(true)) { block->append(parse_prefixed_directive()); }
|
300
296
|
else if (lex< at_keyword >(true)) { block->append(parse_directive()); }
|
301
297
|
|
302
298
|
else if (is_root && stack.back() != Scope::AtRoot /* && block->is_root() */) {
|
@@ -530,10 +526,13 @@ namespace Sass {
|
|
530
526
|
// create the connector object (add parts later)
|
531
527
|
Ruleset_Obj ruleset = SASS_MEMORY_NEW(Ruleset, pstate);
|
532
528
|
// parse selector static or as schema to be evaluated later
|
533
|
-
if (lookahead.parsable)
|
529
|
+
if (lookahead.parsable) {
|
530
|
+
ruleset->selector(parseSelectorList(false));
|
531
|
+
}
|
534
532
|
else {
|
535
|
-
|
536
|
-
|
533
|
+
SelectorListObj list = SASS_MEMORY_NEW(SelectorList, pstate);
|
534
|
+
auto sc = parse_selector_schema(lookahead.position, false);
|
535
|
+
ruleset->schema(sc);
|
537
536
|
ruleset->selector(list);
|
538
537
|
}
|
539
538
|
// then parse the inner block
|
@@ -563,11 +562,10 @@ namespace Sass {
|
|
563
562
|
// the selector schema is pretty much just a wrapper for the string schema
|
564
563
|
Selector_Schema_Obj selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema);
|
565
564
|
selector_schema->connect_parent(chroot == false);
|
566
|
-
selector_schema->media_block(last_media_block);
|
567
565
|
|
568
566
|
// process until end
|
569
567
|
while (i < end_of_selector) {
|
570
|
-
// try to parse
|
568
|
+
// try to parse multiple interpolants
|
571
569
|
if (const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, end_of_selector)) {
|
572
570
|
// accumulate the preceding segment if the position has advanced
|
573
571
|
if (i < p) {
|
@@ -674,213 +672,8 @@ namespace Sass {
|
|
674
672
|
}
|
675
673
|
// EO parse_include_directive
|
676
674
|
|
677
|
-
// parse a list of complex selectors
|
678
|
-
// this is the main entry point for most
|
679
|
-
Selector_List_Obj Parser::parse_selector_list(bool chroot)
|
680
|
-
{
|
681
|
-
bool reloop;
|
682
|
-
bool had_linefeed = false;
|
683
|
-
NESTING_GUARD(nestings);
|
684
|
-
Complex_Selector_Obj sel;
|
685
|
-
Selector_List_Obj group = SASS_MEMORY_NEW(Selector_List, pstate);
|
686
|
-
group->media_block(last_media_block);
|
687
|
-
|
688
|
-
if (peek_css< alternatives < end_of_file, exactly <'{'>, exactly <','> > >()) {
|
689
|
-
css_error("Invalid CSS", " after ", ": expected selector, was ");
|
690
|
-
}
|
691
|
-
|
692
|
-
do {
|
693
|
-
reloop = false;
|
694
|
-
|
695
|
-
had_linefeed = had_linefeed || peek_newline();
|
696
|
-
|
697
|
-
if (peek_css< alternatives < class_char < selector_list_delims > > >())
|
698
|
-
break; // in case there are superfluous commas at the end
|
699
|
-
|
700
|
-
// now parse the complex selector
|
701
|
-
sel = parse_complex_selector(chroot);
|
702
|
-
|
703
|
-
if (!sel) return group.detach();
|
704
|
-
|
705
|
-
sel->has_line_feed(had_linefeed);
|
706
|
-
|
707
|
-
had_linefeed = false;
|
708
|
-
|
709
|
-
while (peek_css< exactly<','> >())
|
710
|
-
{
|
711
|
-
lex< css_comments >(false);
|
712
|
-
// consume everything up and including the comma separator
|
713
|
-
reloop = lex< exactly<','> >() != 0;
|
714
|
-
// remember line break (also between some commas)
|
715
|
-
had_linefeed = had_linefeed || peek_newline();
|
716
|
-
// remember line break (also between some commas)
|
717
|
-
}
|
718
|
-
group->append(sel);
|
719
|
-
}
|
720
|
-
while (reloop);
|
721
|
-
while (lex_css< kwd_optional >()) {
|
722
|
-
group->is_optional(true);
|
723
|
-
}
|
724
|
-
// update for end position
|
725
|
-
group->update_pstate(pstate);
|
726
|
-
if (sel) sel->mutable_last()->has_line_break(false);
|
727
|
-
return group.detach();
|
728
|
-
}
|
729
|
-
// EO parse_selector_list
|
730
675
|
|
731
|
-
|
732
|
-
// complex selector, with one of four combinator operations.
|
733
|
-
// the compound selector (head) is optional, since the combinator
|
734
|
-
// can come first in the whole selector sequence (like `> DIV').
|
735
|
-
Complex_Selector_Obj Parser::parse_complex_selector(bool chroot)
|
736
|
-
{
|
737
|
-
|
738
|
-
NESTING_GUARD(nestings);
|
739
|
-
String_Obj reference;
|
740
|
-
lex < block_comment >();
|
741
|
-
advanceToNextToken();
|
742
|
-
Complex_Selector_Obj sel = SASS_MEMORY_NEW(Complex_Selector, pstate);
|
743
|
-
|
744
|
-
if (peek < end_of_file >()) return {};
|
745
|
-
|
746
|
-
// parse the left hand side
|
747
|
-
Compound_Selector_Obj lhs;
|
748
|
-
// special case if it starts with combinator ([+~>])
|
749
|
-
if (!peek_css< class_char < selector_combinator_ops > >()) {
|
750
|
-
// parse the left hand side
|
751
|
-
lhs = parse_compound_selector();
|
752
|
-
}
|
753
|
-
|
754
|
-
|
755
|
-
// parse combinator between lhs and rhs
|
756
|
-
Complex_Selector::Combinator combinator = Complex_Selector::ANCESTOR_OF;
|
757
|
-
if (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO;
|
758
|
-
else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES;
|
759
|
-
else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF;
|
760
|
-
else if (lex< sequence < exactly<'/'>, negate < exactly < '*' > > > >()) {
|
761
|
-
// comments are allowed, but not spaces?
|
762
|
-
combinator = Complex_Selector::REFERENCE;
|
763
|
-
if (!lex < re_reference_combinator >()) return {};
|
764
|
-
reference = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
|
765
|
-
if (!lex < exactly < '/' > >()) return {}; // ToDo: error msg?
|
766
|
-
}
|
767
|
-
|
768
|
-
if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return {};
|
769
|
-
|
770
|
-
// lex < block_comment >();
|
771
|
-
sel->head(lhs);
|
772
|
-
sel->combinator(combinator);
|
773
|
-
sel->media_block(last_media_block);
|
774
|
-
|
775
|
-
if (combinator == Complex_Selector::REFERENCE) sel->reference(reference);
|
776
|
-
// has linfeed after combinator?
|
777
|
-
sel->has_line_break(peek_newline());
|
778
|
-
// sel->has_line_feed(has_line_feed);
|
779
|
-
|
780
|
-
// check if we got the abort condition (ToDo: optimize)
|
781
|
-
if (!peek_css< class_char < complex_selector_delims > >()) {
|
782
|
-
// parse next selector in sequence
|
783
|
-
sel->tail(parse_complex_selector(true));
|
784
|
-
}
|
785
|
-
|
786
|
-
// add a parent selector if we are not in a root
|
787
|
-
// also skip adding parent ref if we only have refs
|
788
|
-
if (!sel->has_parent_ref() && !chroot) {
|
789
|
-
// create the objects to wrap parent selector reference
|
790
|
-
Compound_Selector_Obj head = SASS_MEMORY_NEW(Compound_Selector, pstate);
|
791
|
-
Parent_Selector* parent = SASS_MEMORY_NEW(Parent_Selector, pstate, false);
|
792
|
-
parent->media_block(last_media_block);
|
793
|
-
head->media_block(last_media_block);
|
794
|
-
// add simple selector
|
795
|
-
head->append(parent);
|
796
|
-
// selector may not have any head yet
|
797
|
-
if (!sel->head()) { sel->head(head); }
|
798
|
-
// otherwise we need to create a new complex selector and set the old one as its tail
|
799
|
-
else {
|
800
|
-
sel = SASS_MEMORY_NEW(Complex_Selector, pstate, Complex_Selector::ANCESTOR_OF, head, sel);
|
801
|
-
sel->media_block(last_media_block);
|
802
|
-
}
|
803
|
-
// peek for linefeed and remember result on head
|
804
|
-
// if (peek_newline()) head->has_line_break(true);
|
805
|
-
}
|
806
|
-
|
807
|
-
sel->update_pstate(pstate);
|
808
|
-
// complex selector
|
809
|
-
return sel;
|
810
|
-
}
|
811
|
-
// EO parse_complex_selector
|
812
|
-
|
813
|
-
// parse one compound selector, which is basically
|
814
|
-
// a list of simple selectors (directly adjacent)
|
815
|
-
// lex them exactly (without skipping white-space)
|
816
|
-
Compound_Selector_Obj Parser::parse_compound_selector()
|
817
|
-
{
|
818
|
-
// init an empty compound selector wrapper
|
819
|
-
Compound_Selector_Obj seq = SASS_MEMORY_NEW(Compound_Selector, pstate);
|
820
|
-
seq->media_block(last_media_block);
|
821
|
-
|
822
|
-
// skip initial white-space
|
823
|
-
lex< css_whitespace >();
|
824
|
-
|
825
|
-
// parse list
|
826
|
-
while (true)
|
827
|
-
{
|
828
|
-
// remove all block comments (don't skip white-space)
|
829
|
-
lex< delimited_by< slash_star, star_slash, false > >(false);
|
830
|
-
// parse functional
|
831
|
-
if (match < re_pseudo_selector >())
|
832
|
-
{
|
833
|
-
seq->append(parse_simple_selector());
|
834
|
-
}
|
835
|
-
// parse parent selector
|
836
|
-
else if (lex< exactly<'&'> >(false))
|
837
|
-
{
|
838
|
-
if (!allow_parent) error("Parent selectors aren't allowed here.");
|
839
|
-
// this produces a linefeed!?
|
840
|
-
seq->has_parent_reference(true);
|
841
|
-
seq->append(SASS_MEMORY_NEW(Parent_Selector, pstate));
|
842
|
-
// parent selector only allowed at start
|
843
|
-
// upcoming Sass may allow also trailing
|
844
|
-
if (seq->length() > 1) {
|
845
|
-
ParserState state(pstate);
|
846
|
-
Simple_Selector_Obj cur = (*seq)[seq->length()-1];
|
847
|
-
Simple_Selector_Obj prev = (*seq)[seq->length()-2];
|
848
|
-
std::string sel(prev->to_string({ NESTED, 5 }));
|
849
|
-
std::string found(cur->to_string({ NESTED, 5 }));
|
850
|
-
if (lex < identifier >()) { found += std::string(lexed); }
|
851
|
-
error("Invalid CSS after \"" + sel + "\": expected \"{\", was \"" + found + "\"\n\n"
|
852
|
-
"\"" + found + "\" may only be used at the beginning of a compound selector.", state);
|
853
|
-
}
|
854
|
-
}
|
855
|
-
// parse type selector
|
856
|
-
else if (lex< re_type_selector >(false))
|
857
|
-
{
|
858
|
-
seq->append(SASS_MEMORY_NEW(Type_Selector, pstate, lexed));
|
859
|
-
}
|
860
|
-
// peek for abort conditions
|
861
|
-
else if (peek< spaces >()) break;
|
862
|
-
else if (peek< end_of_file >()) { break; }
|
863
|
-
else if (peek_css < class_char < selector_combinator_ops > >()) break;
|
864
|
-
else if (peek_css < class_char < complex_selector_delims > >()) break;
|
865
|
-
// otherwise parse another simple selector
|
866
|
-
else {
|
867
|
-
Simple_Selector_Obj sel = parse_simple_selector();
|
868
|
-
if (!sel) return {};
|
869
|
-
seq->append(sel);
|
870
|
-
}
|
871
|
-
}
|
872
|
-
|
873
|
-
if (seq && !peek_css<alternatives<end_of_file,exactly<'{'>>>()) {
|
874
|
-
seq->has_line_break(peek_newline());
|
875
|
-
}
|
876
|
-
|
877
|
-
// EO while true
|
878
|
-
return seq;
|
879
|
-
|
880
|
-
}
|
881
|
-
// EO parse_compound_selector
|
882
|
-
|
883
|
-
Simple_Selector_Obj Parser::parse_simple_selector()
|
676
|
+
SimpleSelectorObj Parser::parse_simple_selector()
|
884
677
|
{
|
885
678
|
lex < css_comments >(false);
|
886
679
|
if (lex< class_name >()) {
|
@@ -893,7 +686,7 @@ namespace Sass {
|
|
893
686
|
return SASS_MEMORY_NEW(Type_Selector, pstate, lexed);
|
894
687
|
}
|
895
688
|
else if (peek< pseudo_not >()) {
|
896
|
-
return
|
689
|
+
return parse_negated_selector2();
|
897
690
|
}
|
898
691
|
else if (peek< re_pseudo_selector >()) {
|
899
692
|
return parse_pseudo_selector();
|
@@ -905,9 +698,7 @@ namespace Sass {
|
|
905
698
|
return parse_attribute_selector();
|
906
699
|
}
|
907
700
|
else if (lex< placeholder >()) {
|
908
|
-
|
909
|
-
sel->media_block(last_media_block);
|
910
|
-
return sel;
|
701
|
+
return SASS_MEMORY_NEW(Placeholder_Selector, pstate, lexed);
|
911
702
|
}
|
912
703
|
else {
|
913
704
|
css_error("Invalid CSS", " after ", ": expected selector, was ");
|
@@ -916,71 +707,104 @@ namespace Sass {
|
|
916
707
|
return {};
|
917
708
|
}
|
918
709
|
|
919
|
-
|
710
|
+
Pseudo_Selector_Obj Parser::parse_negated_selector2()
|
920
711
|
{
|
921
712
|
lex< pseudo_not >();
|
922
713
|
std::string name(lexed);
|
923
714
|
ParserState nsource_position = pstate;
|
924
|
-
|
715
|
+
SelectorListObj negated = parseSelectorList(true);
|
925
716
|
if (!lex< exactly<')'> >()) {
|
926
717
|
error("negated selector is missing ')'");
|
927
718
|
}
|
928
719
|
name.erase(name.size() - 1);
|
929
|
-
|
720
|
+
|
721
|
+
Pseudo_Selector* sel = SASS_MEMORY_NEW(Pseudo_Selector, nsource_position, name.substr(1));
|
722
|
+
sel->selector(negated);
|
723
|
+
return sel;
|
930
724
|
}
|
931
725
|
|
726
|
+
// Helper to clean binominal string
|
727
|
+
bool BothAreSpaces(char lhs, char rhs) { return isspace(lhs) && isspace(rhs); }
|
728
|
+
|
932
729
|
// a pseudo selector often starts with one or two colons
|
933
730
|
// it can contain more selectors inside parentheses
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
731
|
+
SimpleSelectorObj Parser::parse_pseudo_selector() {
|
732
|
+
|
733
|
+
// Lex one or two colon characters
|
734
|
+
if (lex<pseudo_prefix>()) {
|
735
|
+
std::string colons(lexed);
|
736
|
+
// Check if it is a pseudo element
|
737
|
+
bool element = colons.size() == 2;
|
738
|
+
|
739
|
+
if (lex< sequence<
|
740
|
+
// we keep the space within the name, strange enough
|
741
|
+
// ToDo: refactor output to schedule the space for it
|
742
|
+
// or do we really want to keep the real white-space?
|
743
|
+
sequence< identifier, optional < block_comment >, exactly<'('> >
|
744
|
+
> >())
|
745
|
+
{
|
947
746
|
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
return SASS_MEMORY_NEW(Pseudo_Selector, p, name, expr);
|
747
|
+
std::string name(lexed);
|
748
|
+
name.erase(name.size() - 1);
|
749
|
+
ParserState p = pstate;
|
750
|
+
|
751
|
+
// specially parse nth-child pseudo selectors
|
752
|
+
if (lex_css < sequence < binomial, word_boundary >>()) {
|
753
|
+
std::string parsed(lexed); // always compacting binominals (as dart-sass)
|
754
|
+
parsed.erase(std::unique(parsed.begin(), parsed.end(), BothAreSpaces), parsed.end());
|
755
|
+
String_Constant_Obj arg = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
|
756
|
+
Pseudo_Selector* pseudo = SASS_MEMORY_NEW(Pseudo_Selector, p, name, element);
|
757
|
+
if (lex < sequence < css_whitespace, insensitive < of_kwd >>>(false)) {
|
758
|
+
pseudo->selector(parseSelectorList(true));
|
759
|
+
}
|
760
|
+
pseudo->argument(arg);
|
761
|
+
if (lex_css< exactly<')'> >()) {
|
762
|
+
return pseudo;
|
763
|
+
}
|
966
764
|
}
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
765
|
+
else {
|
766
|
+
if (peek_css< exactly<')'>>() && Util::equalsLiteral("nth-", name.substr(0, 4))) {
|
767
|
+
css_error("Invalid CSS", " after ", ": expected An+B expression, was ");
|
768
|
+
}
|
769
|
+
|
770
|
+
std::string unvendored = Util::unvendor(name);
|
771
|
+
|
772
|
+
if (unvendored == "not" || unvendored == "matches" || unvendored == "current" || unvendored == "any" || unvendored == "has" || unvendored == "host" || unvendored == "host-context" || unvendored == "slotted") {
|
773
|
+
if (SelectorListObj wrapped = parseSelectorList(true)) {
|
774
|
+
if (wrapped && lex_css< exactly<')'> >()) {
|
775
|
+
Pseudo_Selector* pseudo = SASS_MEMORY_NEW(Pseudo_Selector, p, name, element);
|
776
|
+
pseudo->selector(wrapped);
|
777
|
+
return pseudo;
|
778
|
+
}
|
779
|
+
}
|
780
|
+
} else {
|
781
|
+
String_Schema_Obj arg = parse_css_variable_value();
|
782
|
+
Pseudo_Selector* pseudo = SASS_MEMORY_NEW(Pseudo_Selector, p, name, element);
|
783
|
+
pseudo->argument(arg);
|
784
|
+
|
785
|
+
if (lex_css< exactly<')'> >()) {
|
786
|
+
return pseudo;
|
787
|
+
}
|
788
|
+
}
|
971
789
|
}
|
790
|
+
|
972
791
|
}
|
792
|
+
// EO if pseudo selector
|
973
793
|
|
974
|
-
|
975
|
-
|
794
|
+
else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
|
795
|
+
return SASS_MEMORY_NEW(Pseudo_Selector, pstate, lexed, element);
|
796
|
+
}
|
797
|
+
else if (lex < pseudo_prefix >()) {
|
798
|
+
css_error("Invalid CSS", " after ", ": expected pseudoclass or pseudoelement, was ");
|
799
|
+
}
|
976
800
|
|
977
|
-
else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
|
978
|
-
return SASS_MEMORY_NEW(Pseudo_Selector, pstate, lexed);
|
979
801
|
}
|
980
|
-
else
|
981
|
-
|
802
|
+
else {
|
803
|
+
lex < identifier >(); // needed for error message?
|
804
|
+
css_error("Invalid CSS", " after ", ": expected selector, was ");
|
982
805
|
}
|
983
806
|
|
807
|
+
|
984
808
|
css_error("Invalid CSS", " after ", ": expected \")\", was ");
|
985
809
|
|
986
810
|
// unreachable statement
|
@@ -1038,7 +862,7 @@ namespace Sass {
|
|
1038
862
|
}
|
1039
863
|
|
1040
864
|
/* parse block comment and add to block */
|
1041
|
-
void Parser::parse_block_comments()
|
865
|
+
void Parser::parse_block_comments(bool store)
|
1042
866
|
{
|
1043
867
|
Block_Obj block = block_stack.back();
|
1044
868
|
|
@@ -1046,7 +870,7 @@ namespace Sass {
|
|
1046
870
|
bool is_important = lexed.begin[2] == '!';
|
1047
871
|
// flag on second param is to skip loosely over comments
|
1048
872
|
String_Obj contents = parse_interpolated_chunk(lexed, true, false);
|
1049
|
-
block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
|
873
|
+
if (store) block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
|
1050
874
|
}
|
1051
875
|
}
|
1052
876
|
|
@@ -1104,23 +928,6 @@ namespace Sass {
|
|
1104
928
|
}
|
1105
929
|
}
|
1106
930
|
|
1107
|
-
// parse +/- and return false if negative
|
1108
|
-
// this is never hit via spec tests
|
1109
|
-
bool Parser::parse_number_prefix()
|
1110
|
-
{
|
1111
|
-
bool positive = true;
|
1112
|
-
while(true) {
|
1113
|
-
if (lex < block_comment >()) continue;
|
1114
|
-
if (lex < number_prefix >()) continue;
|
1115
|
-
if (lex < exactly < '-' > >()) {
|
1116
|
-
positive = !positive;
|
1117
|
-
continue;
|
1118
|
-
}
|
1119
|
-
break;
|
1120
|
-
}
|
1121
|
-
return positive;
|
1122
|
-
}
|
1123
|
-
|
1124
931
|
Expression_Obj Parser::parse_map()
|
1125
932
|
{
|
1126
933
|
NESTING_GUARD(nestings);
|
@@ -1393,7 +1200,7 @@ namespace Sass {
|
|
1393
1200
|
Expression_Obj lhs = parse_operators();
|
1394
1201
|
// if it's a singleton, return it (don't wrap it)
|
1395
1202
|
if (!(peek_css< exactly<'+'> >(position) ||
|
1396
|
-
// condition is a bit
|
1203
|
+
// condition is a bit mysterious, but some combinations should not be counted as operations
|
1397
1204
|
(peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
|
1398
1205
|
(peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
|
1399
1206
|
peek< sequence < zero_plus < exactly <'-' > >, identifier > >(position))
|
@@ -1530,13 +1337,6 @@ namespace Sass {
|
|
1530
1337
|
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
1531
1338
|
return ex;
|
1532
1339
|
}
|
1533
|
-
// this whole branch is never hit via spec tests
|
1534
|
-
else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
|
1535
|
-
if (parse_number_prefix()) return parse_value(); // prefix is positive
|
1536
|
-
Unary_Expression* ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_value());
|
1537
|
-
if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
1538
|
-
return ex;
|
1539
|
-
}
|
1540
1340
|
else {
|
1541
1341
|
return parse_value();
|
1542
1342
|
}
|
@@ -2326,20 +2126,107 @@ namespace Sass {
|
|
2326
2126
|
return call.detach();
|
2327
2127
|
}
|
2328
2128
|
|
2329
|
-
|
2330
|
-
|
2129
|
+
|
2130
|
+
std::vector<CssMediaQuery_Obj> Parser::parseCssMediaQueries()
|
2331
2131
|
{
|
2332
|
-
|
2333
|
-
|
2132
|
+
std::vector<CssMediaQuery_Obj> result;
|
2133
|
+
do {
|
2134
|
+
if (auto query = parseCssMediaQuery()) {
|
2135
|
+
result.push_back(query);
|
2136
|
+
}
|
2137
|
+
} while (lex<exactly<','>>());
|
2138
|
+
return result;
|
2139
|
+
}
|
2140
|
+
|
2141
|
+
std::string Parser::parseIdentifier()
|
2142
|
+
{
|
2143
|
+
if (lex < identifier >(false)) {
|
2144
|
+
return std::string(lexed);
|
2145
|
+
}
|
2146
|
+
return std::string();
|
2147
|
+
}
|
2334
2148
|
|
2335
|
-
|
2149
|
+
CssMediaQuery_Obj Parser::parseCssMediaQuery()
|
2150
|
+
{
|
2151
|
+
CssMediaQuery_Obj result = SASS_MEMORY_NEW(CssMediaQuery, pstate);
|
2152
|
+
lex<css_comments>(false);
|
2153
|
+
|
2154
|
+
// Check if any tokens are to parse
|
2155
|
+
if (!peek_css<exactly<'('>>()) {
|
2156
|
+
|
2157
|
+
std::string token1(parseIdentifier());
|
2158
|
+
lex<css_comments>(false);
|
2159
|
+
|
2160
|
+
if (token1.empty()) {
|
2161
|
+
return {};
|
2162
|
+
}
|
2336
2163
|
|
2337
|
-
|
2338
|
-
|
2339
|
-
|
2340
|
-
|
2164
|
+
std::string token2(parseIdentifier());
|
2165
|
+
lex<css_comments>(false);
|
2166
|
+
|
2167
|
+
if (Util::equalsLiteral("and", token2)) {
|
2168
|
+
result->type(token1);
|
2169
|
+
}
|
2170
|
+
else {
|
2171
|
+
if (token2.empty()) {
|
2172
|
+
result->type(token1);
|
2173
|
+
}
|
2174
|
+
else {
|
2175
|
+
result->modifier(token1);
|
2176
|
+
result->type(token2);
|
2177
|
+
}
|
2178
|
+
|
2179
|
+
if (lex < kwd_and >()) {
|
2180
|
+
lex<css_comments>(false);
|
2181
|
+
}
|
2182
|
+
else {
|
2183
|
+
return result;
|
2184
|
+
}
|
2185
|
+
|
2186
|
+
}
|
2187
|
+
|
2188
|
+
}
|
2189
|
+
|
2190
|
+
std::vector<std::string> queries;
|
2191
|
+
|
2192
|
+
do {
|
2193
|
+
lex<css_comments>(false);
|
2194
|
+
|
2195
|
+
if (lex<exactly<'('>>()) {
|
2196
|
+
// In dart sass parser returns a pure string
|
2197
|
+
if (lex < skip_over_scopes < exactly < '(' >, exactly < ')' > > >()) {
|
2198
|
+
std::string decl("(" + std::string(lexed));
|
2199
|
+
queries.push_back(decl);
|
2200
|
+
}
|
2201
|
+
// Should be: parseDeclarationValue;
|
2202
|
+
if (!lex<exactly<')'>>()) {
|
2203
|
+
// Should we throw an error here?
|
2204
|
+
}
|
2205
|
+
}
|
2206
|
+
} while (lex < kwd_and >());
|
2207
|
+
|
2208
|
+
result->features(queries);
|
2209
|
+
|
2210
|
+
if (result->features().empty()) {
|
2211
|
+
if (result->type().empty()) {
|
2212
|
+
return {};
|
2213
|
+
}
|
2214
|
+
}
|
2215
|
+
|
2216
|
+
return result;
|
2217
|
+
}
|
2218
|
+
|
2219
|
+
|
2220
|
+
// EO parse_while_directive
|
2221
|
+
MediaRule_Obj Parser::parseMediaRule()
|
2222
|
+
{
|
2223
|
+
MediaRule_Obj rule = SASS_MEMORY_NEW(MediaRule, pstate);
|
2224
|
+
stack.push_back(Scope::Media);
|
2225
|
+
rule->schema(parse_media_queries());
|
2226
|
+
parse_block_comments(false);
|
2227
|
+
rule->block(parse_css_block());
|
2341
2228
|
stack.pop_back();
|
2342
|
-
return
|
2229
|
+
return rule;
|
2343
2230
|
}
|
2344
2231
|
|
2345
2232
|
List_Obj Parser::parse_media_queries()
|
@@ -2558,68 +2445,6 @@ namespace Sass {
|
|
2558
2445
|
return cond;
|
2559
2446
|
}
|
2560
2447
|
|
2561
|
-
Directive_Obj Parser::parse_special_directive()
|
2562
|
-
{
|
2563
|
-
std::string kwd(lexed);
|
2564
|
-
|
2565
|
-
if (lexed == "@else") error("Invalid CSS: @else must come after @if");
|
2566
|
-
|
2567
|
-
// this whole branch is never hit via spec tests
|
2568
|
-
|
2569
|
-
Directive* at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
|
2570
|
-
Lookahead lookahead = lookahead_for_include(position);
|
2571
|
-
if (lookahead.found && !lookahead.has_interpolants) {
|
2572
|
-
at_rule->selector(parse_selector_list(false));
|
2573
|
-
}
|
2574
|
-
|
2575
|
-
lex < css_comments >(false);
|
2576
|
-
|
2577
|
-
if (lex < static_property >()) {
|
2578
|
-
at_rule->value(parse_interpolated_chunk(Token(lexed)));
|
2579
|
-
} else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
|
2580
|
-
at_rule->value(parse_list());
|
2581
|
-
}
|
2582
|
-
|
2583
|
-
lex < css_comments >(false);
|
2584
|
-
|
2585
|
-
if (peek< exactly<'{'> >()) {
|
2586
|
-
at_rule->block(parse_block());
|
2587
|
-
}
|
2588
|
-
|
2589
|
-
return at_rule;
|
2590
|
-
}
|
2591
|
-
|
2592
|
-
// this whole branch is never hit via spec tests
|
2593
|
-
Directive_Obj Parser::parse_prefixed_directive()
|
2594
|
-
{
|
2595
|
-
std::string kwd(lexed);
|
2596
|
-
|
2597
|
-
if (lexed == "@else") error("Invalid CSS: @else must come after @if");
|
2598
|
-
|
2599
|
-
Directive_Obj at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
|
2600
|
-
Lookahead lookahead = lookahead_for_include(position);
|
2601
|
-
if (lookahead.found && !lookahead.has_interpolants) {
|
2602
|
-
at_rule->selector(parse_selector_list(false));
|
2603
|
-
}
|
2604
|
-
|
2605
|
-
lex < css_comments >(false);
|
2606
|
-
|
2607
|
-
if (lex < static_property >()) {
|
2608
|
-
at_rule->value(parse_interpolated_chunk(Token(lexed)));
|
2609
|
-
} else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
|
2610
|
-
at_rule->value(parse_list());
|
2611
|
-
}
|
2612
|
-
|
2613
|
-
lex < css_comments >(false);
|
2614
|
-
|
2615
|
-
if (peek< exactly<'{'> >()) {
|
2616
|
-
at_rule->block(parse_block());
|
2617
|
-
}
|
2618
|
-
|
2619
|
-
return at_rule;
|
2620
|
-
}
|
2621
|
-
|
2622
|
-
|
2623
2448
|
Directive_Obj Parser::parse_directive()
|
2624
2449
|
{
|
2625
2450
|
Directive_Obj directive = SASS_MEMORY_NEW(Directive, pstate, lexed);
|
@@ -2660,6 +2485,7 @@ namespace Sass {
|
|
2660
2485
|
lex <
|
2661
2486
|
one_plus <
|
2662
2487
|
alternatives <
|
2488
|
+
exactly <'>'>,
|
2663
2489
|
sequence <
|
2664
2490
|
exactly <'\\'>,
|
2665
2491
|
any_char
|
@@ -2826,7 +2652,7 @@ namespace Sass {
|
|
2826
2652
|
rv.error = q;
|
2827
2653
|
rv.position = q;
|
2828
2654
|
// check expected opening bracket
|
2829
|
-
// only after
|
2655
|
+
// only after successful matching
|
2830
2656
|
if (peek < exactly<'{'> >(q)) rv.found = q;
|
2831
2657
|
// else if (peek < end_of_file >(q)) rv.found = q;
|
2832
2658
|
else if (peek < exactly<'('> >(q)) rv.found = q;
|
@@ -3068,6 +2894,10 @@ namespace Sass {
|
|
3068
2894
|
Position p(pos.line ? pos : before_token);
|
3069
2895
|
ParserState pstate(path, source, p, Offset(0, 0));
|
3070
2896
|
// `pstate.src` may not outlive stack unwind so we must copy it.
|
2897
|
+
// This is needed since we often parse dynamically generated code,
|
2898
|
+
// e.g. for interpolations, and we normally don't want to keep this
|
2899
|
+
// memory around after we parsed the AST tree successfully. Only on
|
2900
|
+
// errors we want to preserve them for better error reporting.
|
3071
2901
|
char *src_copy = sass_copy_c_string(pstate.src);
|
3072
2902
|
pstate.src = src_copy;
|
3073
2903
|
traces.push_back(Backtrace(pstate));
|
@@ -3094,7 +2924,7 @@ namespace Sass {
|
|
3094
2924
|
}
|
3095
2925
|
// backup position to last significant char
|
3096
2926
|
while (trim && last_pos > source && last_pos < end) {
|
3097
|
-
if (!
|
2927
|
+
if (!Util::ascii_isspace(static_cast<unsigned char>(*last_pos))) break;
|
3098
2928
|
utf8::prior(last_pos, source);
|
3099
2929
|
}
|
3100
2930
|
|