sassc 1.10.1 → 1.11.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/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
|
}
|