sassc 1.10.1 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -2
- data/ext/libsass/.github/CONTRIBUTING.md +65 -0
- data/ext/libsass/.github/ISSUE_TEMPLATE.md +29 -0
- data/ext/libsass/Makefile +8 -3
- data/ext/libsass/Makefile.conf +28 -22
- data/ext/libsass/Readme.md +14 -7
- data/ext/libsass/configure.ac +5 -8
- data/ext/libsass/docs/api-context-internal.md +3 -0
- data/ext/libsass/docs/api-context.md +7 -0
- data/ext/libsass/docs/api-doc.md +4 -0
- data/ext/libsass/docs/api-importer.md +2 -0
- data/ext/libsass/docs/api-value-example.md +55 -0
- data/ext/libsass/docs/api-value.md +49 -22
- data/ext/libsass/docs/implementations.md +4 -0
- data/ext/libsass/include/sass/base.h +5 -4
- data/ext/libsass/include/sass/context.h +3 -0
- data/ext/libsass/include/sass/values.h +28 -27
- data/ext/libsass/include/sass/version.h +1 -1
- data/ext/libsass/include/sass2scss.h +1 -1
- data/ext/libsass/script/ci-build-libsass +3 -3
- data/ext/libsass/script/ci-install-deps +12 -3
- data/ext/libsass/src/ast.cpp +321 -212
- data/ext/libsass/src/ast.hpp +273 -165
- data/ext/libsass/src/ast_factory.hpp +4 -5
- data/ext/libsass/src/ast_fwd_decl.hpp +8 -7
- data/ext/libsass/src/bind.cpp +2 -7
- data/ext/libsass/src/bind.hpp +0 -1
- data/ext/libsass/src/check_nesting.cpp +379 -0
- data/ext/libsass/src/check_nesting.hpp +60 -0
- data/ext/libsass/src/constants.cpp +7 -6
- data/ext/libsass/src/constants.hpp +2 -1
- data/ext/libsass/src/context.cpp +7 -1
- data/ext/libsass/src/context.hpp +1 -1
- data/ext/libsass/src/cssize.cpp +76 -32
- data/ext/libsass/src/cssize.hpp +7 -8
- data/ext/libsass/src/debugger.hpp +70 -40
- data/ext/libsass/src/error_handling.cpp +15 -2
- data/ext/libsass/src/error_handling.hpp +19 -0
- data/ext/libsass/src/eval.cpp +107 -161
- data/ext/libsass/src/eval.hpp +12 -8
- data/ext/libsass/src/expand.cpp +81 -74
- data/ext/libsass/src/expand.hpp +13 -12
- data/ext/libsass/src/extend.cpp +149 -142
- data/ext/libsass/src/extend.hpp +10 -3
- data/ext/libsass/src/file.cpp +2 -1
- data/ext/libsass/src/functions.cpp +96 -59
- data/ext/libsass/src/functions.hpp +2 -2
- data/ext/libsass/src/inspect.cpp +33 -45
- data/ext/libsass/src/inspect.hpp +7 -7
- data/ext/libsass/src/json.cpp +17 -5
- data/ext/libsass/src/lexer.cpp +3 -3
- data/ext/libsass/src/listize.cpp +10 -10
- data/ext/libsass/src/listize.hpp +3 -3
- data/ext/libsass/src/node.cpp +30 -30
- data/ext/libsass/src/node.hpp +13 -13
- data/ext/libsass/src/operation.hpp +21 -19
- data/ext/libsass/src/output.cpp +48 -103
- data/ext/libsass/src/output.hpp +0 -1
- data/ext/libsass/src/parser.cpp +161 -133
- data/ext/libsass/src/parser.hpp +10 -7
- data/ext/libsass/src/remove_placeholders.cpp +6 -6
- data/ext/libsass/src/remove_placeholders.hpp +1 -1
- data/ext/libsass/src/sass.cpp +21 -0
- data/ext/libsass/src/sass.hpp +8 -1
- data/ext/libsass/src/sass2scss.cpp +14 -3
- data/ext/libsass/src/sass_context.cpp +69 -24
- data/ext/libsass/src/sass_context.hpp +3 -0
- data/ext/libsass/src/source_map.cpp +22 -10
- data/ext/libsass/src/to_value.cpp +2 -2
- data/ext/libsass/src/to_value.hpp +1 -1
- data/ext/libsass/src/units.hpp +3 -1
- data/ext/libsass/src/util.cpp +20 -16
- data/ext/libsass/src/util.hpp +2 -1
- data/ext/libsass/win/libsass.targets +2 -0
- data/ext/libsass/win/libsass.vcxproj.filters +6 -0
- data/lib/sassc/engine.rb +5 -0
- data/lib/sassc/native/native_functions_api.rb +13 -1
- data/lib/sassc/script/value_conversion.rb +11 -1
- data/lib/sassc/script/value_conversion/list.rb +23 -0
- data/lib/sassc/version.rb +1 -1
- data/test/engine_test.rb +18 -2
- data/test/functions_test.rb +30 -0
- data/test/native_test.rb +1 -1
- metadata +8 -3
data/ext/libsass/src/node.hpp
CHANGED
@@ -17,7 +17,7 @@ namespace Sass {
|
|
17
17
|
/*
|
18
18
|
There are a lot of stumbling blocks when trying to port the ruby extend code to C++. The biggest is the choice of
|
19
19
|
data type. The ruby code will pretty seamlessly switch types between an Array<SimpleSequence or Op> (libsass'
|
20
|
-
equivalent is the
|
20
|
+
equivalent is the Sequence_Selector) to a Sequence, which contains more metadata about the sequence than just the
|
21
21
|
selector info. They also have the ability to have arbitrary nestings of arrays like [1, [2]], which is hard to
|
22
22
|
implement using Array equivalents in C++ (like the deque or vector). They also have the ability to include nil
|
23
23
|
in the arrays, like [1, nil, 3], which has potential semantic differences than an empty array [1, [], 3]. To be
|
@@ -26,7 +26,7 @@ namespace Sass {
|
|
26
26
|
more closely match the ruby code, which is a huge benefit when attempting to implement an complex algorithm like
|
27
27
|
the Extend operator.
|
28
28
|
|
29
|
-
Note that the current libsass data model also pairs the combinator with the
|
29
|
+
Note that the current libsass data model also pairs the combinator with the Sequence_Selector that follows it, but
|
30
30
|
ruby sass has no such restriction, so we attempt to create a data structure that can handle them split apart.
|
31
31
|
*/
|
32
32
|
|
@@ -50,18 +50,18 @@ namespace Sass {
|
|
50
50
|
bool isNil() const { return mType == NIL; }
|
51
51
|
bool got_line_feed;
|
52
52
|
|
53
|
-
|
53
|
+
Sequence_Selector::Combinator combinator() const { return mCombinator; }
|
54
54
|
|
55
|
-
|
56
|
-
const
|
55
|
+
Sequence_Selector* selector() { return mpSelector; }
|
56
|
+
const Sequence_Selector* selector() const { return mpSelector; }
|
57
57
|
|
58
58
|
NodeDequePtr collection() { return mpCollection; }
|
59
59
|
const NodeDequePtr collection() const { return mpCollection; }
|
60
60
|
|
61
|
-
static Node createCombinator(const
|
61
|
+
static Node createCombinator(const Sequence_Selector::Combinator& combinator);
|
62
62
|
|
63
63
|
// This method will clone the selector, stripping off the tail and combinator
|
64
|
-
static Node createSelector(
|
64
|
+
static Node createSelector(Sequence_Selector* pSelector, Context& ctx);
|
65
65
|
|
66
66
|
static Node createCollection();
|
67
67
|
static Node createCollection(const NodeDeque& values);
|
@@ -79,7 +79,7 @@ namespace Sass {
|
|
79
79
|
COLLECTION FUNCTIONS
|
80
80
|
|
81
81
|
Most types don't need any helper methods (nil and combinator due to their simplicity and
|
82
|
-
selector due to the fact that we leverage the non-node selector code on the
|
82
|
+
selector due to the fact that we leverage the non-node selector code on the Sequence_Selector
|
83
83
|
whereever possible). The following methods are intended to be called on Node objects whose
|
84
84
|
type is COLLECTION only.
|
85
85
|
*/
|
@@ -97,21 +97,21 @@ namespace Sass {
|
|
97
97
|
// Private constructor; Use the static methods (like createCombinator and createSelector)
|
98
98
|
// to instantiate this object. This is more expressive, and it allows us to break apart each
|
99
99
|
// case into separate functions.
|
100
|
-
Node(const TYPE& type,
|
100
|
+
Node(const TYPE& type, Sequence_Selector::Combinator combinator, Sequence_Selector* pSelector, NodeDequePtr& pCollection);
|
101
101
|
|
102
102
|
TYPE mType;
|
103
103
|
|
104
104
|
// TODO: can we union these to save on memory?
|
105
|
-
|
106
|
-
|
105
|
+
Sequence_Selector::Combinator mCombinator;
|
106
|
+
Sequence_Selector* mpSelector; // this is an AST_Node, so it will be handled by the Memory_Manager
|
107
107
|
NodeDequePtr mpCollection;
|
108
108
|
};
|
109
109
|
|
110
110
|
#ifdef DEBUG
|
111
111
|
std::ostream& operator<<(std::ostream& os, const Node& node);
|
112
112
|
#endif
|
113
|
-
Node complexSelectorToNode(
|
114
|
-
|
113
|
+
Node complexSelectorToNode(Sequence_Selector* pToConvert, Context& ctx);
|
114
|
+
Sequence_Selector* nodeToComplexSelector(const Node& toConvert, Context& ctx);
|
115
115
|
|
116
116
|
bool nodesEqual(const Node& one, const Node& two, bool simpleSelectorOrderDependent);
|
117
117
|
|
@@ -13,12 +13,12 @@ namespace Sass {
|
|
13
13
|
// statements
|
14
14
|
virtual T operator()(Block* x) = 0;
|
15
15
|
virtual T operator()(Ruleset* x) = 0;
|
16
|
-
virtual T operator()(Propset* x) = 0;
|
17
16
|
virtual T operator()(Bubble* x) = 0;
|
17
|
+
virtual T operator()(Trace* x) = 0;
|
18
18
|
virtual T operator()(Supports_Block* x) = 0;
|
19
19
|
virtual T operator()(Media_Block* x) = 0;
|
20
20
|
virtual T operator()(At_Root_Block* x) = 0;
|
21
|
-
virtual T operator()(Directive* x)
|
21
|
+
virtual T operator()(Directive* x) = 0;
|
22
22
|
virtual T operator()(Keyframe_Rule* x) = 0;
|
23
23
|
virtual T operator()(Declaration* x) = 0;
|
24
24
|
virtual T operator()(Assignment* x) = 0;
|
@@ -61,7 +61,7 @@ namespace Sass {
|
|
61
61
|
virtual T operator()(Supports_Interpolation* x) = 0;
|
62
62
|
virtual T operator()(Media_Query* x) = 0;
|
63
63
|
virtual T operator()(Media_Query_Expression* x) = 0;
|
64
|
-
virtual T operator()(At_Root_Query* x)
|
64
|
+
virtual T operator()(At_Root_Query* x) = 0;
|
65
65
|
virtual T operator()(Null* x) = 0;
|
66
66
|
virtual T operator()(Parent_Selector* x) = 0;
|
67
67
|
// parameters and arguments
|
@@ -71,15 +71,16 @@ namespace Sass {
|
|
71
71
|
virtual T operator()(Arguments* x) = 0;
|
72
72
|
// selectors
|
73
73
|
virtual T operator()(Selector_Schema* x) = 0;
|
74
|
-
virtual T operator()(
|
75
|
-
virtual T operator()(
|
76
|
-
virtual T operator()(
|
74
|
+
virtual T operator()(Placeholder_Selector* x) = 0;
|
75
|
+
virtual T operator()(Element_Selector* x) = 0;
|
76
|
+
virtual T operator()(Class_Selector* x) = 0;
|
77
|
+
virtual T operator()(Id_Selector* x) = 0;
|
77
78
|
virtual T operator()(Attribute_Selector* x) = 0;
|
78
79
|
virtual T operator()(Pseudo_Selector* x) = 0;
|
79
80
|
virtual T operator()(Wrapped_Selector* x) = 0;
|
80
|
-
virtual T operator()(
|
81
|
-
virtual T operator()(
|
82
|
-
virtual T operator()(
|
81
|
+
virtual T operator()(SimpleSequence_Selector* x)= 0;
|
82
|
+
virtual T operator()(Sequence_Selector* x) = 0;
|
83
|
+
virtual T operator()(CommaSequence_Selector* x) = 0;
|
83
84
|
|
84
85
|
template <typename U>
|
85
86
|
T fallback(U x) { return T(); }
|
@@ -94,12 +95,12 @@ namespace Sass {
|
|
94
95
|
// statements
|
95
96
|
T operator()(Block* x) { return static_cast<D*>(this)->fallback(x); }
|
96
97
|
T operator()(Ruleset* x) { return static_cast<D*>(this)->fallback(x); }
|
97
|
-
T operator()(Propset* x) { return static_cast<D*>(this)->fallback(x); }
|
98
98
|
T operator()(Bubble* x) { return static_cast<D*>(this)->fallback(x); }
|
99
|
+
T operator()(Trace* x) { return static_cast<D*>(this)->fallback(x); }
|
99
100
|
T operator()(Supports_Block* x) { return static_cast<D*>(this)->fallback(x); }
|
100
101
|
T operator()(Media_Block* x) { return static_cast<D*>(this)->fallback(x); }
|
101
102
|
T operator()(At_Root_Block* x) { return static_cast<D*>(this)->fallback(x); }
|
102
|
-
T operator()(Directive* x)
|
103
|
+
T operator()(Directive* x) { return static_cast<D*>(this)->fallback(x); }
|
103
104
|
T operator()(Keyframe_Rule* x) { return static_cast<D*>(this)->fallback(x); }
|
104
105
|
T operator()(Declaration* x) { return static_cast<D*>(this)->fallback(x); }
|
105
106
|
T operator()(Assignment* x) { return static_cast<D*>(this)->fallback(x); }
|
@@ -142,7 +143,7 @@ namespace Sass {
|
|
142
143
|
T operator()(Supports_Interpolation* x) { return static_cast<D*>(this)->fallback(x); }
|
143
144
|
T operator()(Media_Query* x) { return static_cast<D*>(this)->fallback(x); }
|
144
145
|
T operator()(Media_Query_Expression* x) { return static_cast<D*>(this)->fallback(x); }
|
145
|
-
T operator()(At_Root_Query* x)
|
146
|
+
T operator()(At_Root_Query* x) { return static_cast<D*>(this)->fallback(x); }
|
146
147
|
T operator()(Null* x) { return static_cast<D*>(this)->fallback(x); }
|
147
148
|
T operator()(Parent_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
148
149
|
// parameters and arguments
|
@@ -152,18 +153,19 @@ namespace Sass {
|
|
152
153
|
T operator()(Arguments* x) { return static_cast<D*>(this)->fallback(x); }
|
153
154
|
// selectors
|
154
155
|
T operator()(Selector_Schema* x) { return static_cast<D*>(this)->fallback(x); }
|
155
|
-
T operator()(
|
156
|
-
T operator()(
|
157
|
-
T operator()(
|
156
|
+
T operator()(Placeholder_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
157
|
+
T operator()(Element_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
158
|
+
T operator()(Class_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
159
|
+
T operator()(Id_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
158
160
|
T operator()(Attribute_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
159
161
|
T operator()(Pseudo_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
160
162
|
T operator()(Wrapped_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
161
|
-
T operator()(
|
162
|
-
T operator()(
|
163
|
-
T operator()(
|
163
|
+
T operator()(SimpleSequence_Selector* x){ return static_cast<D*>(this)->fallback(x); }
|
164
|
+
T operator()(Sequence_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
165
|
+
T operator()(CommaSequence_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
164
166
|
|
165
167
|
template <typename U>
|
166
|
-
T fallback(U x)
|
168
|
+
T fallback(U x) { return T(); }
|
167
169
|
};
|
168
170
|
|
169
171
|
}
|
data/ext/libsass/src/output.cpp
CHANGED
@@ -111,77 +111,65 @@ namespace Sass {
|
|
111
111
|
{
|
112
112
|
Selector* s = r->selector();
|
113
113
|
Block* b = r->block();
|
114
|
-
bool decls = false;
|
115
114
|
|
116
115
|
// Filter out rulesets that aren't printable (process its children though)
|
117
116
|
if (!Util::isPrintable(r, output_style())) {
|
118
117
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
119
118
|
Statement* stm = (*b)[i];
|
120
119
|
if (dynamic_cast<Has_Block*>(stm)) {
|
121
|
-
stm
|
120
|
+
if (typeid(*stm) != typeid(Declaration)) {
|
121
|
+
stm->perform(this);
|
122
|
+
}
|
122
123
|
}
|
123
124
|
}
|
124
125
|
return;
|
125
126
|
}
|
126
127
|
|
127
|
-
if (
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
if (
|
149
|
-
|
150
|
-
bPrintExpression = false;
|
151
|
-
}
|
152
|
-
}
|
153
|
-
}
|
154
|
-
else if (dec->value()->concrete_type() == Expression::LIST) {
|
155
|
-
List* list = static_cast<List*>(dec->value());
|
156
|
-
bool all_invisible = true;
|
157
|
-
for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
|
158
|
-
Expression* item = (*list)[list_i];
|
159
|
-
if (!item->is_invisible()) all_invisible = false;
|
128
|
+
if (output_style() == NESTED) indentation += r->tabs();
|
129
|
+
if (opt.source_comments) {
|
130
|
+
std::stringstream ss;
|
131
|
+
append_indentation();
|
132
|
+
std::string path(File::abs2rel(r->pstate().path));
|
133
|
+
ss << "/* line " << r->pstate().line + 1 << ", " << path << " */";
|
134
|
+
append_string(ss.str());
|
135
|
+
append_optional_linefeed();
|
136
|
+
}
|
137
|
+
s->perform(this);
|
138
|
+
append_scope_opener(b);
|
139
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
140
|
+
Statement* stm = (*b)[i];
|
141
|
+
bool bPrintExpression = true;
|
142
|
+
// Check print conditions
|
143
|
+
if (typeid(*stm) == typeid(Declaration)) {
|
144
|
+
Declaration* dec = static_cast<Declaration*>(stm);
|
145
|
+
if (dec->value()->concrete_type() == Expression::STRING) {
|
146
|
+
String_Constant* valConst = static_cast<String_Constant*>(dec->value());
|
147
|
+
std::string val(valConst->value());
|
148
|
+
if (auto qstr = dynamic_cast<String_Quoted*>(valConst)) {
|
149
|
+
if (!qstr->quote_mark() && val.empty()) {
|
150
|
+
bPrintExpression = false;
|
160
151
|
}
|
161
|
-
if (all_invisible) bPrintExpression = false;
|
162
152
|
}
|
163
153
|
}
|
164
|
-
|
165
|
-
|
166
|
-
|
154
|
+
else if (dec->value()->concrete_type() == Expression::LIST) {
|
155
|
+
List* list = static_cast<List*>(dec->value());
|
156
|
+
bool all_invisible = true;
|
157
|
+
for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
|
158
|
+
Expression* item = (*list)[list_i];
|
159
|
+
if (!item->is_invisible()) all_invisible = false;
|
160
|
+
}
|
161
|
+
if (all_invisible) bPrintExpression = false;
|
167
162
|
}
|
168
163
|
}
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
if (b->has_hoistable()) {
|
174
|
-
if (decls) ++indentation;
|
175
|
-
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
176
|
-
Statement* stm = (*b)[i];
|
177
|
-
if (stm->is_hoistable()) {
|
178
|
-
stm->perform(this);
|
179
|
-
}
|
164
|
+
// Print if OK
|
165
|
+
if (bPrintExpression) {
|
166
|
+
stm->perform(this);
|
180
167
|
}
|
181
|
-
if (decls) --indentation;
|
182
168
|
}
|
183
|
-
|
169
|
+
if (output_style() == NESTED) indentation -= r->tabs();
|
170
|
+
append_scope_closer(b);
|
184
171
|
|
172
|
+
}
|
185
173
|
void Output::operator()(Keyframe_Rule* r)
|
186
174
|
{
|
187
175
|
Block* b = r->block();
|
@@ -199,19 +187,9 @@ namespace Sass {
|
|
199
187
|
append_scope_opener();
|
200
188
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
201
189
|
Statement* stm = (*b)[i];
|
202
|
-
|
203
|
-
|
204
|
-
if (i < L - 1) append_special_linefeed();
|
205
|
-
}
|
206
|
-
}
|
207
|
-
|
208
|
-
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
209
|
-
Statement* stm = (*b)[i];
|
210
|
-
if (stm->is_hoistable()) {
|
211
|
-
stm->perform(this);
|
212
|
-
}
|
190
|
+
stm->perform(this);
|
191
|
+
if (i < L - 1) append_special_linefeed();
|
213
192
|
}
|
214
|
-
|
215
193
|
append_scope_closer();
|
216
194
|
}
|
217
195
|
|
@@ -240,33 +218,10 @@ namespace Sass {
|
|
240
218
|
c->perform(this);
|
241
219
|
append_scope_opener();
|
242
220
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
248
|
-
Statement* stm = (*b)[i];
|
249
|
-
if (!stm->is_hoistable()) {
|
250
|
-
stm->perform(this);
|
251
|
-
}
|
252
|
-
}
|
253
|
-
|
254
|
-
append_scope_closer();
|
255
|
-
|
256
|
-
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
257
|
-
Statement* stm = (*b)[i];
|
258
|
-
if (stm->is_hoistable()) {
|
259
|
-
stm->perform(this);
|
260
|
-
}
|
261
|
-
}
|
262
|
-
}
|
263
|
-
else {
|
264
|
-
// JMA - not hoisted, just output in order
|
265
|
-
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
266
|
-
Statement* stm = (*b)[i];
|
267
|
-
stm->perform(this);
|
268
|
-
if (i < L - 1) append_special_linefeed();
|
269
|
-
}
|
221
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
222
|
+
Statement* stm = (*b)[i];
|
223
|
+
stm->perform(this);
|
224
|
+
if (i < L - 1) append_special_linefeed();
|
270
225
|
}
|
271
226
|
|
272
227
|
if (output_style() == NESTED) indentation -= f->tabs();
|
@@ -346,18 +301,8 @@ namespace Sass {
|
|
346
301
|
|
347
302
|
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
348
303
|
Statement* stm = (*b)[i];
|
349
|
-
|
350
|
-
|
351
|
-
if (i < L - 1 && format) append_special_linefeed();
|
352
|
-
}
|
353
|
-
}
|
354
|
-
|
355
|
-
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
356
|
-
Statement* stm = (*b)[i];
|
357
|
-
if (stm->is_hoistable()) {
|
358
|
-
stm->perform(this);
|
359
|
-
if (i < L - 1 && format) append_special_linefeed();
|
360
|
-
}
|
304
|
+
stm->perform(this);
|
305
|
+
if (i < L - 1 && format) append_special_linefeed();
|
361
306
|
}
|
362
307
|
|
363
308
|
append_scope_closer();
|
data/ext/libsass/src/output.hpp
CHANGED
data/ext/libsass/src/parser.cpp
CHANGED
@@ -12,6 +12,18 @@
|
|
12
12
|
#include "sass/functions.h"
|
13
13
|
#include "error_handling.hpp"
|
14
14
|
|
15
|
+
// Notes about delayed: some ast nodes can have delayed evaluation so
|
16
|
+
// they can preserve their original semantics if needed. This is most
|
17
|
+
// prominently exhibited by the division operation, since it is not
|
18
|
+
// only a valid operation, but also a valid css statement (i.e. for
|
19
|
+
// fonts, as in `16px/24px`). When parsing lists and expression we
|
20
|
+
// unwrap single items from lists and other operations. A nested list
|
21
|
+
// must not be delayed, only the items of the first level sometimes
|
22
|
+
// are delayed (as with argument lists). To achieve this we need to
|
23
|
+
// pass status to the list parser, so this can be set correctly.
|
24
|
+
// Another case with delayed values are colors. In compressed mode
|
25
|
+
// only processed values get compressed (other are left as written).
|
26
|
+
|
15
27
|
#include <typeinfo>
|
16
28
|
#include <tuple>
|
17
29
|
|
@@ -21,6 +33,8 @@ namespace Sass {
|
|
21
33
|
|
22
34
|
Parser Parser::from_c_str(const char* beg, Context& ctx, ParserState pstate, const char* source)
|
23
35
|
{
|
36
|
+
pstate.offset.column = 0;
|
37
|
+
pstate.offset.line = 0;
|
24
38
|
Parser p(ctx, pstate);
|
25
39
|
p.source = source ? source : beg;
|
26
40
|
p.position = beg ? beg : p.source;
|
@@ -33,6 +47,8 @@ namespace Sass {
|
|
33
47
|
|
34
48
|
Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate, const char* source)
|
35
49
|
{
|
50
|
+
pstate.offset.column = 0;
|
51
|
+
pstate.offset.line = 0;
|
36
52
|
Parser p(ctx, pstate);
|
37
53
|
p.source = source ? source : beg;
|
38
54
|
p.position = beg ? beg : p.source;
|
@@ -43,7 +59,15 @@ namespace Sass {
|
|
43
59
|
return p;
|
44
60
|
}
|
45
61
|
|
46
|
-
|
62
|
+
void Parser::advanceToNextToken() {
|
63
|
+
lex < css_comments >(false);
|
64
|
+
// advance to position
|
65
|
+
pstate += pstate.offset;
|
66
|
+
pstate.offset.column = 0;
|
67
|
+
pstate.offset.line = 0;
|
68
|
+
}
|
69
|
+
|
70
|
+
CommaSequence_Selector* Parser::parse_selector(const char* beg, Context& ctx, ParserState pstate, const char* source)
|
47
71
|
{
|
48
72
|
Parser p = Parser::from_c_str(beg, ctx, pstate, source);
|
49
73
|
// ToDo: ruby sass errors on parent references
|
@@ -254,7 +278,7 @@ namespace Sass {
|
|
254
278
|
else if (lex< re_prefixed_directive >(true)) { (*block) << parse_prefixed_directive(); }
|
255
279
|
else if (lex< at_keyword >(true)) { (*block) << parse_directive(); }
|
256
280
|
|
257
|
-
else if (block->is_root()) {
|
281
|
+
else if (is_root /* && block->is_root() */) {
|
258
282
|
lex< css_whitespace >();
|
259
283
|
if (position >= end) return true;
|
260
284
|
css_error("Invalid CSS", " after ", ": expected 1 selector or at-rule, was ");
|
@@ -272,7 +296,7 @@ namespace Sass {
|
|
272
296
|
if (decl->is_indented()) ++ indentation;
|
273
297
|
// parse a propset that rides on the declaration's property
|
274
298
|
stack.push_back(Scope::Properties);
|
275
|
-
|
299
|
+
decl->block(parse_block());
|
276
300
|
stack.pop_back();
|
277
301
|
if (decl->is_indented()) -- indentation;
|
278
302
|
}
|
@@ -321,7 +345,7 @@ namespace Sass {
|
|
321
345
|
first = false;
|
322
346
|
} while (lex_css< exactly<','> >());
|
323
347
|
|
324
|
-
if (!peek_css<alternatives<exactly<';'>,end_of_file
|
348
|
+
if (!peek_css< alternatives< exactly<';'>, exactly<'}'>, end_of_file > >()) {
|
325
349
|
List* media_queries = parse_media_queries();
|
326
350
|
imp->media_queries(media_queries);
|
327
351
|
}
|
@@ -391,7 +415,6 @@ namespace Sass {
|
|
391
415
|
if (lex< exactly<':'> >()) { // there's a default value
|
392
416
|
while (lex< block_comment >());
|
393
417
|
val = parse_space_list();
|
394
|
-
val->is_delayed(false);
|
395
418
|
}
|
396
419
|
else if (lex< exactly< ellipsis > >()) {
|
397
420
|
is_rest = true;
|
@@ -430,14 +453,12 @@ namespace Sass {
|
|
430
453
|
ParserState p = pstate;
|
431
454
|
lex_css< exactly<':'> >();
|
432
455
|
Expression* val = parse_space_list();
|
433
|
-
val->is_delayed(false);
|
434
456
|
arg = SASS_MEMORY_NEW(ctx.mem, Argument, p, val, name);
|
435
457
|
}
|
436
458
|
else {
|
437
459
|
bool is_arglist = false;
|
438
460
|
bool is_keyword = false;
|
439
461
|
Expression* val = parse_space_list();
|
440
|
-
val->is_delayed(false);
|
441
462
|
List* l = dynamic_cast<List*>(val);
|
442
463
|
if (lex_css< exactly< ellipsis > >()) {
|
443
464
|
if (val->concrete_type() == Expression::MAP || (
|
@@ -455,6 +476,9 @@ namespace Sass {
|
|
455
476
|
std::string name(Util::normalize_underscores(lexed));
|
456
477
|
ParserState var_source_position = pstate;
|
457
478
|
if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
|
479
|
+
if (peek_css< alternatives < exactly<';'>, end_of_file > >()) {
|
480
|
+
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
481
|
+
}
|
458
482
|
Expression* val;
|
459
483
|
Lookahead lookahead = lookahead_for_value(position);
|
460
484
|
if (lookahead.has_interpolants && lookahead.found) {
|
@@ -462,7 +486,6 @@ namespace Sass {
|
|
462
486
|
} else {
|
463
487
|
val = parse_list();
|
464
488
|
}
|
465
|
-
val->is_delayed(false);
|
466
489
|
bool is_default = false;
|
467
490
|
bool is_global = false;
|
468
491
|
while (peek< alternatives < default_flag, global_flag > >()) {
|
@@ -587,12 +610,12 @@ namespace Sass {
|
|
587
610
|
|
588
611
|
// parse a list of complex selectors
|
589
612
|
// this is the main entry point for most
|
590
|
-
|
613
|
+
CommaSequence_Selector* Parser::parse_selector_list(bool in_root)
|
591
614
|
{
|
592
615
|
bool reloop = true;
|
593
616
|
bool had_linefeed = false;
|
594
|
-
|
595
|
-
|
617
|
+
Sequence_Selector* sel = 0;
|
618
|
+
CommaSequence_Selector* group = SASS_MEMORY_NEW(ctx.mem, CommaSequence_Selector, pstate);
|
596
619
|
group->media_block(last_media_block);
|
597
620
|
|
598
621
|
do {
|
@@ -639,13 +662,16 @@ namespace Sass {
|
|
639
662
|
// complex selector, with one of four combinator operations.
|
640
663
|
// the compound selector (head) is optional, since the combinator
|
641
664
|
// can come first in the whole selector sequence (like `> DIV').
|
642
|
-
|
665
|
+
Sequence_Selector* Parser::parse_complex_selector(bool in_root)
|
643
666
|
{
|
644
667
|
|
645
668
|
String* reference = 0;
|
646
669
|
lex < block_comment >();
|
670
|
+
|
671
|
+
Sequence_Selector* sel = SASS_MEMORY_NEW(ctx.mem, Sequence_Selector, pstate);
|
672
|
+
|
647
673
|
// parse the left hand side
|
648
|
-
|
674
|
+
SimpleSequence_Selector* lhs = 0;
|
649
675
|
// special case if it starts with combinator ([+~>])
|
650
676
|
if (!peek_css< class_char < selector_combinator_ops > >()) {
|
651
677
|
// parse the left hand side
|
@@ -656,28 +682,27 @@ namespace Sass {
|
|
656
682
|
if (peek < end_of_file >()) return 0;
|
657
683
|
|
658
684
|
// parse combinator between lhs and rhs
|
659
|
-
|
660
|
-
if (lex< exactly<'+'> >()) combinator =
|
661
|
-
else if (lex< exactly<'~'> >()) combinator =
|
662
|
-
else if (lex< exactly<'>'> >()) combinator =
|
685
|
+
Sequence_Selector::Combinator combinator;
|
686
|
+
if (lex< exactly<'+'> >()) combinator = Sequence_Selector::ADJACENT_TO;
|
687
|
+
else if (lex< exactly<'~'> >()) combinator = Sequence_Selector::PRECEDES;
|
688
|
+
else if (lex< exactly<'>'> >()) combinator = Sequence_Selector::PARENT_OF;
|
663
689
|
else if (lex< sequence < exactly<'/'>, negate < exactly < '*' > > > >()) {
|
664
690
|
// comments are allowed, but not spaces?
|
665
|
-
combinator =
|
691
|
+
combinator = Sequence_Selector::REFERENCE;
|
666
692
|
if (!lex < re_reference_combinator >()) return 0;
|
667
693
|
reference = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
|
668
694
|
if (!lex < exactly < '/' > >()) return 0; // ToDo: error msg?
|
669
695
|
}
|
670
|
-
else /* if (lex< zero >()) */ combinator =
|
696
|
+
else /* if (lex< zero >()) */ combinator = Sequence_Selector::ANCESTOR_OF;
|
671
697
|
|
672
|
-
if (!lhs && combinator ==
|
698
|
+
if (!lhs && combinator == Sequence_Selector::ANCESTOR_OF) return 0;
|
673
699
|
|
674
700
|
// lex < block_comment >();
|
675
|
-
|
676
|
-
|
677
|
-
Complex_Selector* sel = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pstate, combinator, lhs);
|
701
|
+
sel->head(lhs);
|
702
|
+
sel->combinator(combinator);
|
678
703
|
sel->media_block(last_media_block);
|
679
704
|
|
680
|
-
if (combinator ==
|
705
|
+
if (combinator == Sequence_Selector::REFERENCE) sel->reference(reference);
|
681
706
|
// has linfeed after combinator?
|
682
707
|
sel->has_line_break(peek_newline());
|
683
708
|
// sel->has_line_feed(has_line_feed);
|
@@ -686,20 +711,15 @@ namespace Sass {
|
|
686
711
|
if (!peek_css< class_char < complex_selector_delims > >()) {
|
687
712
|
// parse next selector in sequence
|
688
713
|
sel->tail(parse_complex_selector(true));
|
689
|
-
if (sel->tail()) {
|
690
|
-
// ToDo: move this logic below into tail setter
|
691
|
-
// if (sel->tail()->has_reference()) sel->has_reference(true);
|
692
|
-
if (sel->tail()->has_placeholder()) sel->has_placeholder(true);
|
693
|
-
}
|
694
714
|
}
|
695
715
|
|
696
716
|
// add a parent selector if we are not in a root
|
697
717
|
// also skip adding parent ref if we only have refs
|
698
718
|
if (!sel->has_parent_ref() && !in_at_root && !in_root) {
|
699
719
|
// create the objects to wrap parent selector reference
|
700
|
-
|
720
|
+
SimpleSequence_Selector* head = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, pstate);
|
721
|
+
Parent_Selector* parent = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate, false);
|
701
722
|
parent->media_block(last_media_block);
|
702
|
-
Compound_Selector* head = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pstate);
|
703
723
|
head->media_block(last_media_block);
|
704
724
|
// add simple selector
|
705
725
|
(*head) << parent;
|
@@ -707,13 +727,15 @@ namespace Sass {
|
|
707
727
|
if (!sel->head()) { sel->head(head); }
|
708
728
|
// otherwise we need to create a new complex selector and set the old one as its tail
|
709
729
|
else {
|
710
|
-
sel = SASS_MEMORY_NEW(ctx.mem,
|
730
|
+
sel = SASS_MEMORY_NEW(ctx.mem, Sequence_Selector, pstate, Sequence_Selector::ANCESTOR_OF, head, sel);
|
711
731
|
sel->media_block(last_media_block);
|
712
732
|
}
|
713
733
|
// peek for linefeed and remember result on head
|
714
734
|
// if (peek_newline()) head->has_line_break(true);
|
715
735
|
}
|
716
736
|
|
737
|
+
sel->update_pstate(pstate);
|
738
|
+
|
717
739
|
// complex selector
|
718
740
|
return sel;
|
719
741
|
}
|
@@ -722,10 +744,10 @@ namespace Sass {
|
|
722
744
|
// parse one compound selector, which is basically
|
723
745
|
// a list of simple selectors (directly adjacent)
|
724
746
|
// lex them exactly (without skipping white-space)
|
725
|
-
|
747
|
+
SimpleSequence_Selector* Parser::parse_compound_selector()
|
726
748
|
{
|
727
749
|
// init an empty compound selector wrapper
|
728
|
-
|
750
|
+
SimpleSequence_Selector* seq = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, pstate);
|
729
751
|
seq->media_block(last_media_block);
|
730
752
|
|
731
753
|
// skip initial white-space
|
@@ -763,7 +785,7 @@ namespace Sass {
|
|
763
785
|
// parse type selector
|
764
786
|
else if (lex< re_type_selector >(false))
|
765
787
|
{
|
766
|
-
(*seq) << SASS_MEMORY_NEW(ctx.mem,
|
788
|
+
(*seq) << SASS_MEMORY_NEW(ctx.mem, Element_Selector, pstate, lexed);
|
767
789
|
}
|
768
790
|
// peek for abort conditions
|
769
791
|
else if (peek< spaces >()) break;
|
@@ -791,14 +813,17 @@ namespace Sass {
|
|
791
813
|
Simple_Selector* Parser::parse_simple_selector()
|
792
814
|
{
|
793
815
|
lex < css_comments >(false);
|
794
|
-
if (lex<
|
795
|
-
return SASS_MEMORY_NEW(ctx.mem,
|
816
|
+
if (lex< class_name >()) {
|
817
|
+
return SASS_MEMORY_NEW(ctx.mem, Class_Selector, pstate, lexed);
|
818
|
+
}
|
819
|
+
else if (lex< id_name >()) {
|
820
|
+
return SASS_MEMORY_NEW(ctx.mem, Id_Selector, pstate, lexed);
|
796
821
|
}
|
797
822
|
else if (lex< quoted_string >()) {
|
798
|
-
return SASS_MEMORY_NEW(ctx.mem,
|
823
|
+
return SASS_MEMORY_NEW(ctx.mem, Element_Selector, pstate, unquote(lexed));
|
799
824
|
}
|
800
825
|
else if (lex< alternatives < variable, number, static_reference_combinator > >()) {
|
801
|
-
return SASS_MEMORY_NEW(ctx.mem,
|
826
|
+
return SASS_MEMORY_NEW(ctx.mem, Element_Selector, pstate, lexed);
|
802
827
|
}
|
803
828
|
else if (peek< pseudo_not >()) {
|
804
829
|
return parse_negated_selector();
|
@@ -813,7 +838,7 @@ namespace Sass {
|
|
813
838
|
return parse_attribute_selector();
|
814
839
|
}
|
815
840
|
else if (lex< placeholder >()) {
|
816
|
-
|
841
|
+
Placeholder_Selector* sel = SASS_MEMORY_NEW(ctx.mem, Placeholder_Selector, pstate, lexed);
|
817
842
|
sel->media_block(last_media_block);
|
818
843
|
return sel;
|
819
844
|
}
|
@@ -938,7 +963,6 @@ namespace Sass {
|
|
938
963
|
}
|
939
964
|
else if (lex< sequence< optional< exactly<'*'> >, identifier, zero_plus< block_comment > > >()) {
|
940
965
|
prop = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
|
941
|
-
prop->is_delayed(true);
|
942
966
|
}
|
943
967
|
else {
|
944
968
|
css_error("Invalid CSS", " after ", ": expected \"}\", was ");
|
@@ -959,11 +983,11 @@ namespace Sass {
|
|
959
983
|
if (lookahead.has_interpolants) {
|
960
984
|
value = parse_value_schema(lookahead.found);
|
961
985
|
} else {
|
962
|
-
value = parse_list();
|
986
|
+
value = parse_list(DELAYED);
|
963
987
|
}
|
964
988
|
}
|
965
989
|
else {
|
966
|
-
value = parse_list();
|
990
|
+
value = parse_list(DELAYED);
|
967
991
|
if (List* list = dynamic_cast<List*>(value)) {
|
968
992
|
if (list->length() == 0 && !peek< exactly <'{'> >()) {
|
969
993
|
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
|
@@ -1022,7 +1046,7 @@ namespace Sass {
|
|
1022
1046
|
if (peek_css< exactly<')'> >(position))
|
1023
1047
|
{ break; }
|
1024
1048
|
|
1025
|
-
Expression* key =
|
1049
|
+
Expression* key = parse_space_list();
|
1026
1050
|
if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
|
1027
1051
|
if (!str->quote_mark() && !str->is_delayed()) {
|
1028
1052
|
if (const Color* col = name_to_color(str->value())) {
|
@@ -1035,7 +1059,7 @@ namespace Sass {
|
|
1035
1059
|
}
|
1036
1060
|
|
1037
1061
|
if (!(lex< exactly<':'> >()))
|
1038
|
-
{
|
1062
|
+
{ css_error("Invalid CSS", " after ", ": expected \":\", was "); }
|
1039
1063
|
|
1040
1064
|
Expression* value = parse_space_list();
|
1041
1065
|
|
@@ -1052,14 +1076,13 @@ namespace Sass {
|
|
1052
1076
|
// parse list returns either a space separated list,
|
1053
1077
|
// a comma separated list or any bare expression found.
|
1054
1078
|
// so to speak: we unwrap items from lists if possible here!
|
1055
|
-
Expression* Parser::parse_list()
|
1079
|
+
Expression* Parser::parse_list(bool delayed)
|
1056
1080
|
{
|
1057
|
-
|
1058
|
-
return parse_comma_list();
|
1081
|
+
return parse_comma_list(delayed);
|
1059
1082
|
}
|
1060
1083
|
|
1061
1084
|
// will return singletons unwrapped
|
1062
|
-
Expression* Parser::parse_comma_list()
|
1085
|
+
Expression* Parser::parse_comma_list(bool delayed)
|
1063
1086
|
{
|
1064
1087
|
// check if we have an empty list
|
1065
1088
|
// return the empty list as such
|
@@ -1075,12 +1098,20 @@ namespace Sass {
|
|
1075
1098
|
default_flag,
|
1076
1099
|
global_flag
|
1077
1100
|
> >(position))
|
1078
|
-
{
|
1101
|
+
{
|
1102
|
+
// return an empty list (nothing to delay)
|
1103
|
+
return SASS_MEMORY_NEW(ctx.mem, List, pstate, 0);
|
1104
|
+
}
|
1079
1105
|
|
1080
1106
|
// now try to parse a space list
|
1081
1107
|
Expression* list = parse_space_list();
|
1082
1108
|
// if it's a singleton, return it (don't wrap it)
|
1083
|
-
if (!peek_css< exactly<','> >(position))
|
1109
|
+
if (!peek_css< exactly<','> >(position)) {
|
1110
|
+
// set_delay doesn't apply to list children
|
1111
|
+
// so this will only undelay single values
|
1112
|
+
if (!delayed) list->set_delayed(false);
|
1113
|
+
return list;
|
1114
|
+
}
|
1084
1115
|
|
1085
1116
|
// if we got so far, we actually do have a comma list
|
1086
1117
|
List* comma_list = SASS_MEMORY_NEW(ctx.mem, List, pstate, 2, SASS_COMMA);
|
@@ -1158,6 +1189,8 @@ namespace Sass {
|
|
1158
1189
|
// parse logical OR operation
|
1159
1190
|
Expression* Parser::parse_disjunction()
|
1160
1191
|
{
|
1192
|
+
advanceToNextToken();
|
1193
|
+
ParserState state(pstate);
|
1161
1194
|
// parse the left hand side conjunction
|
1162
1195
|
Expression* conj = parse_conjunction();
|
1163
1196
|
// parse multiple right hand sides
|
@@ -1167,13 +1200,18 @@ namespace Sass {
|
|
1167
1200
|
// if it's a singleton, return it directly
|
1168
1201
|
if (operands.size() == 0) return conj;
|
1169
1202
|
// fold all operands into one binary expression
|
1170
|
-
|
1203
|
+
Expression* ex = fold_operands(conj, operands, { Sass_OP::OR });
|
1204
|
+
state.offset = pstate - state + pstate.offset;
|
1205
|
+
ex->pstate(state);
|
1206
|
+
return ex;
|
1171
1207
|
}
|
1172
1208
|
// EO parse_disjunction
|
1173
1209
|
|
1174
1210
|
// parse logical AND operation
|
1175
1211
|
Expression* Parser::parse_conjunction()
|
1176
1212
|
{
|
1213
|
+
advanceToNextToken();
|
1214
|
+
ParserState state(pstate);
|
1177
1215
|
// parse the left hand side relation
|
1178
1216
|
Expression* rel = parse_relation();
|
1179
1217
|
// parse multiple right hand sides
|
@@ -1183,13 +1221,18 @@ namespace Sass {
|
|
1183
1221
|
// if it's a singleton, return it directly
|
1184
1222
|
if (operands.size() == 0) return rel;
|
1185
1223
|
// fold all operands into one binary expression
|
1186
|
-
|
1224
|
+
Expression* ex = fold_operands(rel, operands, { Sass_OP::AND });
|
1225
|
+
state.offset = pstate - state + pstate.offset;
|
1226
|
+
ex->pstate(state);
|
1227
|
+
return ex;
|
1187
1228
|
}
|
1188
1229
|
// EO parse_conjunction
|
1189
1230
|
|
1190
1231
|
// parse comparison operations
|
1191
1232
|
Expression* Parser::parse_relation()
|
1192
1233
|
{
|
1234
|
+
advanceToNextToken();
|
1235
|
+
ParserState state(pstate);
|
1193
1236
|
// parse the left hand side expression
|
1194
1237
|
Expression* lhs = parse_expression();
|
1195
1238
|
std::vector<Expression*> operands;
|
@@ -1222,8 +1265,15 @@ namespace Sass {
|
|
1222
1265
|
operands.push_back(parse_expression());
|
1223
1266
|
left_ws = peek < css_comments >() != NULL;
|
1224
1267
|
}
|
1225
|
-
//
|
1226
|
-
|
1268
|
+
// we are called recursively for list, so we first
|
1269
|
+
// fold inner binary expression which has delayed
|
1270
|
+
// correctly set to zero. After folding we also unwrap
|
1271
|
+
// single nested items. So we cannot set delay on the
|
1272
|
+
// returned result here, as we have lost nestings ...
|
1273
|
+
Expression* ex = fold_operands(lhs, operands, operators);
|
1274
|
+
state.offset = pstate - state + pstate.offset;
|
1275
|
+
ex->pstate(state);
|
1276
|
+
return ex;
|
1227
1277
|
}
|
1228
1278
|
// parse_relation
|
1229
1279
|
|
@@ -1234,6 +1284,8 @@ namespace Sass {
|
|
1234
1284
|
// parse addition and subtraction operations
|
1235
1285
|
Expression* Parser::parse_expression()
|
1236
1286
|
{
|
1287
|
+
advanceToNextToken();
|
1288
|
+
ParserState state(pstate);
|
1237
1289
|
// parses multiple add and subtract operations
|
1238
1290
|
// NOTE: make sure that identifiers starting with
|
1239
1291
|
// NOTE: dashes do NOT count as subtract operation
|
@@ -1259,7 +1311,6 @@ namespace Sass {
|
|
1259
1311
|
|
1260
1312
|
) {
|
1261
1313
|
|
1262
|
-
|
1263
1314
|
bool right_ws = peek < css_comments >() != NULL;
|
1264
1315
|
operators.push_back({ lexed.to_string() == "+" ? Sass_OP::ADD : Sass_OP::SUB, left_ws, right_ws });
|
1265
1316
|
operands.push_back(parse_operators());
|
@@ -1267,12 +1318,17 @@ namespace Sass {
|
|
1267
1318
|
}
|
1268
1319
|
|
1269
1320
|
if (operands.size() == 0) return lhs;
|
1270
|
-
|
1321
|
+
Expression* ex = fold_operands(lhs, operands, operators);
|
1322
|
+
state.offset = pstate - state + pstate.offset;
|
1323
|
+
ex->pstate(state);
|
1324
|
+
return ex;
|
1271
1325
|
}
|
1272
1326
|
|
1273
1327
|
// parse addition and subtraction operations
|
1274
1328
|
Expression* Parser::parse_operators()
|
1275
1329
|
{
|
1330
|
+
advanceToNextToken();
|
1331
|
+
ParserState state(pstate);
|
1276
1332
|
Expression* factor = parse_factor();
|
1277
1333
|
// if it's a singleton, return it (don't wrap it)
|
1278
1334
|
std::vector<Expression*> operands; // factors
|
@@ -1291,7 +1347,10 @@ namespace Sass {
|
|
1291
1347
|
left_ws = peek < css_comments >();
|
1292
1348
|
}
|
1293
1349
|
// operands and operators to binary expression
|
1294
|
-
|
1350
|
+
Expression* ex = fold_operands(factor, operands, operators);
|
1351
|
+
state.offset = pstate - state + pstate.offset;
|
1352
|
+
ex->pstate(state);
|
1353
|
+
return ex;
|
1295
1354
|
}
|
1296
1355
|
// EO parse_operators
|
1297
1356
|
|
@@ -1307,14 +1366,6 @@ namespace Sass {
|
|
1307
1366
|
// lex the expected closing parenthesis
|
1308
1367
|
if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
|
1309
1368
|
// expression can be evaluated
|
1310
|
-
// make sure wrapped lists and division expressions are non-delayed within parentheses
|
1311
|
-
if (value->concrete_type() == Expression::LIST) {
|
1312
|
-
// List* l = static_cast<List*>(value);
|
1313
|
-
// if (!l->empty()) (*l)[0]->is_delayed(false);
|
1314
|
-
} else if (typeid(*value) == typeid(Binary_Expression)) {
|
1315
|
-
Binary_Expression* b = static_cast<Binary_Expression*>(value);
|
1316
|
-
if (b && b->type() == Sass_OP::DIV) b->set_delayed(false);
|
1317
|
-
}
|
1318
1369
|
return value;
|
1319
1370
|
}
|
1320
1371
|
// string may be interpolated
|
@@ -1350,17 +1401,25 @@ namespace Sass {
|
|
1350
1401
|
return parse_function_call();
|
1351
1402
|
}
|
1352
1403
|
else if (lex< exactly<'+'> >()) {
|
1353
|
-
|
1404
|
+
Unary_Expression* ex = SASS_MEMORY_NEW(ctx.mem, Unary_Expression, pstate, Unary_Expression::PLUS, parse_factor());
|
1405
|
+
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
1406
|
+
return ex;
|
1354
1407
|
}
|
1355
1408
|
else if (lex< exactly<'-'> >()) {
|
1356
|
-
|
1409
|
+
Unary_Expression* ex = SASS_MEMORY_NEW(ctx.mem, Unary_Expression, pstate, Unary_Expression::MINUS, parse_factor());
|
1410
|
+
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
1411
|
+
return ex;
|
1357
1412
|
}
|
1358
1413
|
else if (lex< sequence< kwd_not > >()) {
|
1359
|
-
|
1414
|
+
Unary_Expression* ex = SASS_MEMORY_NEW(ctx.mem, Unary_Expression, pstate, Unary_Expression::NOT, parse_factor());
|
1415
|
+
if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
1416
|
+
return ex;
|
1360
1417
|
}
|
1361
1418
|
else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
|
1362
1419
|
if (parse_number_prefix()) return parse_value(); // prefix is positive
|
1363
|
-
|
1420
|
+
Unary_Expression* ex = SASS_MEMORY_NEW(ctx.mem, Unary_Expression, pstate, Unary_Expression::MINUS, parse_value());;
|
1421
|
+
if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
|
1422
|
+
return ex;
|
1364
1423
|
}
|
1365
1424
|
else {
|
1366
1425
|
return parse_value();
|
@@ -1455,7 +1514,6 @@ namespace Sass {
|
|
1455
1514
|
if (!p) {
|
1456
1515
|
String_Quoted* str_quoted = SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, std::string(i, chunk.end));
|
1457
1516
|
if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
|
1458
|
-
str_quoted->is_delayed(true);
|
1459
1517
|
return str_quoted;
|
1460
1518
|
}
|
1461
1519
|
|
@@ -1510,11 +1568,13 @@ namespace Sass {
|
|
1510
1568
|
{
|
1511
1569
|
lex< static_value >();
|
1512
1570
|
Token str(lexed);
|
1571
|
+
// static values always have trailing white-
|
1572
|
+
// space and end delimiter (\s*[;]$) included
|
1573
|
+
-- pstate.offset.column;
|
1513
1574
|
--str.end;
|
1514
1575
|
--position;
|
1515
1576
|
|
1516
1577
|
String_Constant* str_node = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, str.time_wspace());
|
1517
|
-
str_node->is_delayed(true);
|
1518
1578
|
return str_node;
|
1519
1579
|
}
|
1520
1580
|
|
@@ -1720,7 +1780,7 @@ namespace Sass {
|
|
1720
1780
|
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
|
1721
1781
|
if (j) {
|
1722
1782
|
// parse the interpolant and accumulate it
|
1723
|
-
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
|
1783
|
+
Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list(DELAYED);
|
1724
1784
|
interp_node->is_interpolant(true);
|
1725
1785
|
(*schema) << interp_node;
|
1726
1786
|
// schema->has_interpolants(true);
|
@@ -1844,16 +1904,6 @@ namespace Sass {
|
|
1844
1904
|
|
1845
1905
|
Content* Parser::parse_content_directive()
|
1846
1906
|
{
|
1847
|
-
bool missing_mixin_parent = true;
|
1848
|
-
for (auto parent : stack) {
|
1849
|
-
if (parent == Scope::Mixin) {
|
1850
|
-
missing_mixin_parent = false;
|
1851
|
-
break;
|
1852
|
-
}
|
1853
|
-
}
|
1854
|
-
if (missing_mixin_parent) {
|
1855
|
-
error("@content may only be used within a mixin", pstate);
|
1856
|
-
}
|
1857
1907
|
return SASS_MEMORY_NEW(ctx.mem, Content, pstate);
|
1858
1908
|
}
|
1859
1909
|
|
@@ -1861,9 +1911,9 @@ namespace Sass {
|
|
1861
1911
|
{
|
1862
1912
|
stack.push_back(Scope::Control);
|
1863
1913
|
ParserState if_source_position = pstate;
|
1914
|
+
bool root = block_stack.back()->is_root();
|
1864
1915
|
Expression* predicate = parse_list();
|
1865
|
-
|
1866
|
-
Block* block = parse_block();
|
1916
|
+
Block* block = parse_block(root);
|
1867
1917
|
Block* alternative = 0;
|
1868
1918
|
|
1869
1919
|
// only throw away comment if we parse a case
|
@@ -1873,7 +1923,7 @@ namespace Sass {
|
|
1873
1923
|
(*alternative) << parse_if_directive(true);
|
1874
1924
|
}
|
1875
1925
|
else if (lex_css< kwd_else_directive >()) {
|
1876
|
-
alternative = parse_block();
|
1926
|
+
alternative = parse_block(root);
|
1877
1927
|
}
|
1878
1928
|
stack.pop_back();
|
1879
1929
|
return SASS_MEMORY_NEW(ctx.mem, If, if_source_position, predicate, block, alternative);
|
@@ -1883,18 +1933,17 @@ namespace Sass {
|
|
1883
1933
|
{
|
1884
1934
|
stack.push_back(Scope::Control);
|
1885
1935
|
ParserState for_source_position = pstate;
|
1936
|
+
bool root = block_stack.back()->is_root();
|
1886
1937
|
lex_variable();
|
1887
1938
|
std::string var(Util::normalize_underscores(lexed));
|
1888
1939
|
if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive", pstate);
|
1889
1940
|
Expression* lower_bound = parse_expression();
|
1890
|
-
lower_bound->is_delayed(false);
|
1891
1941
|
bool inclusive = false;
|
1892
1942
|
if (lex< kwd_through >()) inclusive = true;
|
1893
1943
|
else if (lex< kwd_to >()) inclusive = false;
|
1894
1944
|
else error("expected 'through' or 'to' keyword in @for directive", pstate);
|
1895
1945
|
Expression* upper_bound = parse_expression();
|
1896
|
-
|
1897
|
-
Block* body = parse_block();
|
1946
|
+
Block* body = parse_block(root);
|
1898
1947
|
stack.pop_back();
|
1899
1948
|
return SASS_MEMORY_NEW(ctx.mem, For, for_source_position, var, lower_bound, upper_bound, body, inclusive);
|
1900
1949
|
}
|
@@ -1929,6 +1978,7 @@ namespace Sass {
|
|
1929
1978
|
{
|
1930
1979
|
stack.push_back(Scope::Control);
|
1931
1980
|
ParserState each_source_position = pstate;
|
1981
|
+
bool root = block_stack.back()->is_root();
|
1932
1982
|
std::vector<std::string> vars;
|
1933
1983
|
lex_variable();
|
1934
1984
|
vars.push_back(Util::normalize_underscores(lexed));
|
@@ -1938,14 +1988,7 @@ namespace Sass {
|
|
1938
1988
|
}
|
1939
1989
|
if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive", pstate);
|
1940
1990
|
Expression* list = parse_list();
|
1941
|
-
|
1942
|
-
if (list->concrete_type() == Expression::LIST) {
|
1943
|
-
List* l = static_cast<List*>(list);
|
1944
|
-
for (size_t i = 0, L = l->length(); i < L; ++i) {
|
1945
|
-
(*l)[i]->is_delayed(false);
|
1946
|
-
}
|
1947
|
-
}
|
1948
|
-
Block* body = parse_block();
|
1991
|
+
Block* body = parse_block(root);
|
1949
1992
|
stack.pop_back();
|
1950
1993
|
return SASS_MEMORY_NEW(ctx.mem, Each, each_source_position, vars, list, body);
|
1951
1994
|
}
|
@@ -1954,14 +1997,14 @@ namespace Sass {
|
|
1954
1997
|
While* Parser::parse_while_directive()
|
1955
1998
|
{
|
1956
1999
|
stack.push_back(Scope::Control);
|
2000
|
+
bool root = block_stack.back()->is_root();
|
1957
2001
|
// create the initial while call object
|
1958
2002
|
While* call = SASS_MEMORY_NEW(ctx.mem, While, pstate, 0, 0);
|
1959
2003
|
// parse mandatory predicate
|
1960
2004
|
Expression* predicate = parse_list();
|
1961
|
-
predicate->is_delayed(false);
|
1962
2005
|
call->predicate(predicate);
|
1963
2006
|
// parse mandatory block
|
1964
|
-
call->block(parse_block());
|
2007
|
+
call->block(parse_block(root));
|
1965
2008
|
// return ast node
|
1966
2009
|
stack.pop_back();
|
1967
2010
|
// return ast node
|
@@ -1985,22 +2028,22 @@ namespace Sass {
|
|
1985
2028
|
|
1986
2029
|
List* Parser::parse_media_queries()
|
1987
2030
|
{
|
2031
|
+
advanceToNextToken();
|
1988
2032
|
List* media_queries = SASS_MEMORY_NEW(ctx.mem, List, pstate, 0, SASS_COMMA);
|
1989
2033
|
if (!peek_css < exactly <'{'> >()) (*media_queries) << parse_media_query();
|
1990
2034
|
while (lex_css < exactly <','> >()) (*media_queries) << parse_media_query();
|
2035
|
+
media_queries->update_pstate(pstate);
|
1991
2036
|
return media_queries;
|
1992
2037
|
}
|
1993
2038
|
|
1994
2039
|
// Expression* Parser::parse_media_query()
|
1995
2040
|
Media_Query* Parser::parse_media_query()
|
1996
2041
|
{
|
2042
|
+
advanceToNextToken();
|
1997
2043
|
Media_Query* media_query = SASS_MEMORY_NEW(ctx.mem, Media_Query, pstate);
|
2044
|
+
if (lex < kwd_not >()) { media_query->is_negated(true); lex < css_comments >(false); }
|
2045
|
+
else if (lex < kwd_only >()) { media_query->is_restricted(true); lex < css_comments >(false); }
|
1998
2046
|
|
1999
|
-
lex < css_comments >(false);
|
2000
|
-
if (lex < kwd_not >()) media_query->is_negated(true);
|
2001
|
-
else if (lex < kwd_only >()) media_query->is_restricted(true);
|
2002
|
-
|
2003
|
-
lex < css_comments >(false);
|
2004
2047
|
if (lex < identifier_schema >()) media_query->media_type(parse_identifier_schema());
|
2005
2048
|
else if (lex < identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
|
2006
2049
|
else (*media_query) << parse_media_expression();
|
@@ -2014,6 +2057,9 @@ namespace Sass {
|
|
2014
2057
|
media_query->media_type(schema);
|
2015
2058
|
}
|
2016
2059
|
while (lex_css < kwd_and >()) (*media_query) << parse_media_expression();
|
2060
|
+
|
2061
|
+
media_query->update_pstate(pstate);
|
2062
|
+
|
2017
2063
|
return media_query;
|
2018
2064
|
}
|
2019
2065
|
|
@@ -2033,7 +2079,7 @@ namespace Sass {
|
|
2033
2079
|
feature = parse_expression();
|
2034
2080
|
Expression* expression = 0;
|
2035
2081
|
if (lex_css< exactly<':'> >()) {
|
2036
|
-
expression = parse_list();
|
2082
|
+
expression = parse_list(DELAYED);
|
2037
2083
|
}
|
2038
2084
|
if (!lex_css< exactly<')'> >()) {
|
2039
2085
|
error("unclosed parenthesis in media query expression", pstate);
|
@@ -2252,13 +2298,9 @@ namespace Sass {
|
|
2252
2298
|
Directive* directive = SASS_MEMORY_NEW(ctx.mem, Directive, pstate, lexed);
|
2253
2299
|
Expression* val = parse_almost_any_value();
|
2254
2300
|
// strip left and right if they are of type string
|
2255
|
-
// debug_ast(val);
|
2256
|
-
// std::cerr << "HAASDASD\n";
|
2257
2301
|
directive->value(val);
|
2258
2302
|
if (peek< exactly<'{'> >()) {
|
2259
2303
|
directive->block(parse_block());
|
2260
|
-
} else if (!val) {
|
2261
|
-
css_error("most def");
|
2262
2304
|
}
|
2263
2305
|
return directive;
|
2264
2306
|
}
|
@@ -2386,7 +2428,7 @@ namespace Sass {
|
|
2386
2428
|
stack.back() != Scope::Rules) {
|
2387
2429
|
error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
|
2388
2430
|
}
|
2389
|
-
return SASS_MEMORY_NEW(ctx.mem, Warning, pstate, parse_list());
|
2431
|
+
return SASS_MEMORY_NEW(ctx.mem, Warning, pstate, parse_list(DELAYED));
|
2390
2432
|
}
|
2391
2433
|
|
2392
2434
|
Error* Parser::parse_error()
|
@@ -2398,7 +2440,7 @@ namespace Sass {
|
|
2398
2440
|
stack.back() != Scope::Rules) {
|
2399
2441
|
error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
|
2400
2442
|
}
|
2401
|
-
return SASS_MEMORY_NEW(ctx.mem, Error, pstate, parse_list());
|
2443
|
+
return SASS_MEMORY_NEW(ctx.mem, Error, pstate, parse_list(DELAYED));
|
2402
2444
|
}
|
2403
2445
|
|
2404
2446
|
Debug* Parser::parse_debug()
|
@@ -2410,7 +2452,7 @@ namespace Sass {
|
|
2410
2452
|
stack.back() != Scope::Rules) {
|
2411
2453
|
error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
|
2412
2454
|
}
|
2413
|
-
return SASS_MEMORY_NEW(ctx.mem, Debug, pstate, parse_list());
|
2455
|
+
return SASS_MEMORY_NEW(ctx.mem, Debug, pstate, parse_list(DELAYED));
|
2414
2456
|
}
|
2415
2457
|
|
2416
2458
|
Return* Parser::parse_return_directive()
|
@@ -2623,22 +2665,13 @@ namespace Sass {
|
|
2623
2665
|
Expression* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands, Operand op)
|
2624
2666
|
{
|
2625
2667
|
for (size_t i = 0, S = operands.size(); i < S; ++i) {
|
2626
|
-
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, pstate, op, base, operands[i]);
|
2627
|
-
Binary_Expression* b = static_cast<Binary_Expression*>(base);
|
2628
|
-
if (op.operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
2629
|
-
base->is_delayed(true);
|
2630
|
-
}
|
2631
|
-
else if (b && b->op().operand != Sass_OP::DIV) {
|
2632
|
-
b->left()->is_delayed(false);
|
2633
|
-
b->right()->is_delayed(false);
|
2634
|
-
}
|
2668
|
+
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), op, base, operands[i]);
|
2635
2669
|
}
|
2636
2670
|
return base;
|
2637
2671
|
}
|
2638
2672
|
|
2639
2673
|
Expression* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands, std::vector<Operand>& ops, size_t i)
|
2640
2674
|
{
|
2641
|
-
|
2642
2675
|
if (String_Schema* schema = dynamic_cast<String_Schema*>(base)) {
|
2643
2676
|
// return schema;
|
2644
2677
|
if (schema->has_interpolants()) {
|
@@ -2653,10 +2686,8 @@ namespace Sass {
|
|
2653
2686
|
|| (ops[0].operand == Sass_OP::LTE)
|
2654
2687
|
|| (ops[0].operand == Sass_OP::GTE)
|
2655
2688
|
)) {
|
2656
|
-
Expression* rhs = fold_operands(operands[
|
2689
|
+
Expression* rhs = fold_operands(operands[i], operands, ops, i + 1);
|
2657
2690
|
rhs = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[0], schema, rhs);
|
2658
|
-
rhs->set_delayed(false);
|
2659
|
-
rhs->is_delayed(true);
|
2660
2691
|
return rhs;
|
2661
2692
|
}
|
2662
2693
|
// return schema;
|
@@ -2670,12 +2701,9 @@ namespace Sass {
|
|
2670
2701
|
Expression* rhs = fold_operands(operands[i+1], operands, ops, i + 2);
|
2671
2702
|
rhs = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], schema, rhs);
|
2672
2703
|
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], base, rhs);
|
2673
|
-
rhs->is_delayed(true);
|
2674
|
-
base->is_delayed(true);
|
2675
2704
|
return base;
|
2676
2705
|
}
|
2677
2706
|
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
2678
|
-
if (ops[i].operand != Sass_OP::DIV) base->is_delayed(true);
|
2679
2707
|
return base;
|
2680
2708
|
} else {
|
2681
2709
|
base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], base, operands[i]);
|
@@ -2687,11 +2715,11 @@ namespace Sass {
|
|
2687
2715
|
if (b && ops[i].operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
|
2688
2716
|
base->is_delayed(true);
|
2689
2717
|
}
|
2690
|
-
|
2691
|
-
|
2692
|
-
|
2693
|
-
|
2694
|
-
|
2718
|
+
}
|
2719
|
+
// nested binary expression are never to be delayed
|
2720
|
+
if (Binary_Expression* b = dynamic_cast<Binary_Expression*>(base)) {
|
2721
|
+
if (dynamic_cast<Binary_Expression*>(b->left())) base->set_delayed(false);
|
2722
|
+
if (dynamic_cast<Binary_Expression*>(b->right())) base->set_delayed(false);
|
2695
2723
|
}
|
2696
2724
|
return base;
|
2697
2725
|
}
|