sassc 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|