sassc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +24 -0
  8. data/Rakefile +21 -0
  9. data/ext/libsass/.editorconfig +15 -0
  10. data/ext/libsass/.gitattributes +2 -0
  11. data/ext/libsass/.gitignore +61 -0
  12. data/ext/libsass/.travis.yml +38 -0
  13. data/ext/libsass/COPYING +25 -0
  14. data/ext/libsass/INSTALL +1 -0
  15. data/ext/libsass/LICENSE +25 -0
  16. data/ext/libsass/Makefile +223 -0
  17. data/ext/libsass/Makefile.am +145 -0
  18. data/ext/libsass/Readme.md +93 -0
  19. data/ext/libsass/appveyor.yml +76 -0
  20. data/ext/libsass/ast.cpp +581 -0
  21. data/ext/libsass/ast.hpp +1949 -0
  22. data/ext/libsass/ast_def_macros.hpp +16 -0
  23. data/ext/libsass/ast_factory.hpp +87 -0
  24. data/ext/libsass/ast_fwd_decl.hpp +72 -0
  25. data/ext/libsass/b64/cencode.h +32 -0
  26. data/ext/libsass/b64/encode.h +77 -0
  27. data/ext/libsass/backtrace.hpp +81 -0
  28. data/ext/libsass/base64vlq.cpp +43 -0
  29. data/ext/libsass/base64vlq.hpp +28 -0
  30. data/ext/libsass/bind.cpp +187 -0
  31. data/ext/libsass/bind.hpp +18 -0
  32. data/ext/libsass/cencode.c +102 -0
  33. data/ext/libsass/color_names.hpp +324 -0
  34. data/ext/libsass/configure.ac +130 -0
  35. data/ext/libsass/constants.cpp +144 -0
  36. data/ext/libsass/constants.hpp +145 -0
  37. data/ext/libsass/context.cpp +507 -0
  38. data/ext/libsass/context.hpp +150 -0
  39. data/ext/libsass/contextualize.cpp +157 -0
  40. data/ext/libsass/contextualize.hpp +65 -0
  41. data/ext/libsass/copy_c_str.cpp +13 -0
  42. data/ext/libsass/copy_c_str.hpp +5 -0
  43. data/ext/libsass/debug.hpp +39 -0
  44. data/ext/libsass/environment.hpp +75 -0
  45. data/ext/libsass/error_handling.cpp +28 -0
  46. data/ext/libsass/error_handling.hpp +28 -0
  47. data/ext/libsass/eval.cpp +1149 -0
  48. data/ext/libsass/eval.hpp +80 -0
  49. data/ext/libsass/expand.cpp +430 -0
  50. data/ext/libsass/expand.hpp +77 -0
  51. data/ext/libsass/extconf.rb +6 -0
  52. data/ext/libsass/extend.cpp +1962 -0
  53. data/ext/libsass/extend.hpp +50 -0
  54. data/ext/libsass/file.cpp +291 -0
  55. data/ext/libsass/file.hpp +18 -0
  56. data/ext/libsass/functions.cpp +1565 -0
  57. data/ext/libsass/functions.hpp +187 -0
  58. data/ext/libsass/inspect.cpp +727 -0
  59. data/ext/libsass/inspect.hpp +108 -0
  60. data/ext/libsass/json.cpp +1411 -0
  61. data/ext/libsass/json.hpp +117 -0
  62. data/ext/libsass/kwd_arg_macros.hpp +23 -0
  63. data/ext/libsass/m4/.gitkeep +0 -0
  64. data/ext/libsass/mapping.hpp +17 -0
  65. data/ext/libsass/memory_manager.hpp +54 -0
  66. data/ext/libsass/node.cpp +251 -0
  67. data/ext/libsass/node.hpp +122 -0
  68. data/ext/libsass/operation.hpp +153 -0
  69. data/ext/libsass/output_compressed.cpp +401 -0
  70. data/ext/libsass/output_compressed.hpp +95 -0
  71. data/ext/libsass/output_nested.cpp +364 -0
  72. data/ext/libsass/output_nested.hpp +108 -0
  73. data/ext/libsass/parser.cpp +2016 -0
  74. data/ext/libsass/parser.hpp +264 -0
  75. data/ext/libsass/paths.hpp +69 -0
  76. data/ext/libsass/position.hpp +22 -0
  77. data/ext/libsass/posix/getopt.c +562 -0
  78. data/ext/libsass/posix/getopt.h +95 -0
  79. data/ext/libsass/prelexer.cpp +688 -0
  80. data/ext/libsass/prelexer.hpp +513 -0
  81. data/ext/libsass/remove_placeholders.cpp +59 -0
  82. data/ext/libsass/remove_placeholders.hpp +43 -0
  83. data/ext/libsass/res/resource.rc +35 -0
  84. data/ext/libsass/sass.cpp +33 -0
  85. data/ext/libsass/sass.h +60 -0
  86. data/ext/libsass/sass2scss.cpp +834 -0
  87. data/ext/libsass/sass2scss.h +110 -0
  88. data/ext/libsass/sass_context.cpp +709 -0
  89. data/ext/libsass/sass_context.h +120 -0
  90. data/ext/libsass/sass_functions.cpp +137 -0
  91. data/ext/libsass/sass_functions.h +90 -0
  92. data/ext/libsass/sass_interface.cpp +277 -0
  93. data/ext/libsass/sass_interface.h +97 -0
  94. data/ext/libsass/sass_util.cpp +136 -0
  95. data/ext/libsass/sass_util.hpp +259 -0
  96. data/ext/libsass/sass_values.cpp +337 -0
  97. data/ext/libsass/sass_values.h +124 -0
  98. data/ext/libsass/script/bootstrap +10 -0
  99. data/ext/libsass/script/branding +10 -0
  100. data/ext/libsass/script/ci-build-libsass +72 -0
  101. data/ext/libsass/script/ci-install-compiler +4 -0
  102. data/ext/libsass/script/ci-install-deps +19 -0
  103. data/ext/libsass/script/ci-report-coverage +25 -0
  104. data/ext/libsass/script/coveralls-debug +32 -0
  105. data/ext/libsass/script/spec +5 -0
  106. data/ext/libsass/script/tap-driver +652 -0
  107. data/ext/libsass/script/tap-runner +1 -0
  108. data/ext/libsass/source_map.cpp +133 -0
  109. data/ext/libsass/source_map.hpp +46 -0
  110. data/ext/libsass/subset_map.hpp +145 -0
  111. data/ext/libsass/support/libsass.pc.in +11 -0
  112. data/ext/libsass/test-driver +127 -0
  113. data/ext/libsass/test/test_node.cpp +98 -0
  114. data/ext/libsass/test/test_paths.cpp +29 -0
  115. data/ext/libsass/test/test_selector_difference.cpp +28 -0
  116. data/ext/libsass/test/test_specificity.cpp +28 -0
  117. data/ext/libsass/test/test_subset_map.cpp +472 -0
  118. data/ext/libsass/test/test_superselector.cpp +71 -0
  119. data/ext/libsass/test/test_unification.cpp +33 -0
  120. data/ext/libsass/to_c.cpp +61 -0
  121. data/ext/libsass/to_c.hpp +44 -0
  122. data/ext/libsass/to_string.cpp +29 -0
  123. data/ext/libsass/to_string.hpp +32 -0
  124. data/ext/libsass/token.hpp +32 -0
  125. data/ext/libsass/units.cpp +54 -0
  126. data/ext/libsass/units.hpp +10 -0
  127. data/ext/libsass/utf8.h +34 -0
  128. data/ext/libsass/utf8/checked.h +327 -0
  129. data/ext/libsass/utf8/core.h +329 -0
  130. data/ext/libsass/utf8/unchecked.h +228 -0
  131. data/ext/libsass/utf8_string.cpp +102 -0
  132. data/ext/libsass/utf8_string.hpp +36 -0
  133. data/ext/libsass/util.cpp +189 -0
  134. data/ext/libsass/util.hpp +26 -0
  135. data/ext/libsass/win/libsass.filters +291 -0
  136. data/ext/libsass/win/libsass.sln +28 -0
  137. data/ext/libsass/win/libsass.vcxproj +255 -0
  138. data/lib/sassc.rb +6 -0
  139. data/lib/sassc/engine.rb +13 -0
  140. data/lib/sassc/native.rb +44 -0
  141. data/lib/sassc/native/native_context_api.rb +140 -0
  142. data/lib/sassc/native/native_functions_api.rb +41 -0
  143. data/lib/sassc/native/sass_input_style.rb +11 -0
  144. data/lib/sassc/native/sass_output_style.rb +10 -0
  145. data/lib/sassc/native/sass_value.rb +95 -0
  146. data/lib/sassc/native/string_list.rb +8 -0
  147. data/lib/sassc/version.rb +3 -0
  148. data/sassc.gemspec +43 -0
  149. data/test/smoke_test.rb +171 -0
  150. data/test/test_helper.rb +4 -0
  151. metadata +281 -0
@@ -0,0 +1,1949 @@
1
+ #define SASS_AST
2
+
3
+ #include <string>
4
+ #include <sstream>
5
+ #include <vector>
6
+ #include <set>
7
+ #include <algorithm>
8
+ #include <deque>
9
+ #include <unordered_map>
10
+
11
+ #ifdef __clang__
12
+
13
+ /*
14
+ * There are some overloads used here that trigger the clang overload
15
+ * hiding warning. Specifically:
16
+ *
17
+ * Type type() which hides string type() from Expression
18
+ *
19
+ * and
20
+ *
21
+ * Block* block() which hides virtual Block* block() from Statement
22
+ *
23
+ */
24
+
25
+ #pragma clang diagnostic push
26
+ #pragma clang diagnostic ignored "-Woverloaded-virtual"
27
+
28
+ #endif
29
+
30
+ #ifndef SASS_CONSTANTS
31
+ #include "constants.hpp"
32
+ #endif
33
+
34
+ #ifndef SASS_OPERATION
35
+ #include "operation.hpp"
36
+ #endif
37
+
38
+ #ifndef SASS_TOKEN
39
+ #include "token.hpp"
40
+ #endif
41
+
42
+ #ifndef SASS_ENVIRONMENT
43
+ #include "environment.hpp"
44
+ #endif
45
+
46
+ #include "sass.h"
47
+ #include "sass_values.h"
48
+ #include "sass_functions.h"
49
+
50
+ #include "units.hpp"
51
+
52
+ #ifndef SASS_ERROR_HANDLING
53
+ #include "error_handling.hpp"
54
+ #endif
55
+
56
+ #include "ast_def_macros.hpp"
57
+ #include "inspect.hpp"
58
+
59
+ #include <sstream>
60
+ #include <iostream>
61
+ #include <typeinfo>
62
+
63
+ #ifndef SASS_POSITION
64
+ #include "position.hpp"
65
+ #endif
66
+
67
+
68
+ namespace Sass {
69
+ using namespace std;
70
+
71
+ //////////////////////////////////////////////////////////
72
+ // Abstract base class for all abstract syntax tree nodes.
73
+ //////////////////////////////////////////////////////////
74
+ class Block;
75
+ class Statement;
76
+ class Expression;
77
+ class Selector;
78
+ class AST_Node {
79
+ ADD_PROPERTY(string, path);
80
+ ADD_PROPERTY(Position, position);
81
+ public:
82
+ AST_Node(string path, Position position) : path_(path), position_(position) { }
83
+ virtual ~AST_Node() = 0;
84
+ // virtual Block* block() { return 0; }
85
+ ATTACH_OPERATIONS();
86
+ };
87
+ inline AST_Node::~AST_Node() { }
88
+
89
+
90
+ //////////////////////////////////////////////////////////////////////
91
+ // Abstract base class for expressions. This side of the AST hierarchy
92
+ // represents elements in value contexts, which exist primarily to be
93
+ // evaluated and returned.
94
+ //////////////////////////////////////////////////////////////////////
95
+ class Expression : public AST_Node {
96
+ public:
97
+ enum Concrete_Type {
98
+ NONE,
99
+ BOOLEAN,
100
+ NUMBER,
101
+ COLOR,
102
+ STRING,
103
+ LIST,
104
+ MAP,
105
+ NULL_VAL,
106
+ NUM_TYPES
107
+ };
108
+ private:
109
+ // expressions in some contexts shouldn't be evaluated
110
+ ADD_PROPERTY(bool, is_delayed);
111
+ ADD_PROPERTY(bool, is_expanded);
112
+ ADD_PROPERTY(bool, is_interpolant);
113
+ ADD_PROPERTY(Concrete_Type, concrete_type);
114
+ public:
115
+ Expression(string path, Position position,
116
+ bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
117
+ : AST_Node(path, position),
118
+ is_delayed_(d), is_expanded_(d), is_interpolant_(i), concrete_type_(ct)
119
+ { }
120
+ virtual operator bool() { return true; }
121
+ virtual ~Expression() { };
122
+ virtual string type() { return ""; /* TODO: raise an error? */ }
123
+ virtual bool is_invisible() { return false; }
124
+ static string type_name() { return ""; }
125
+ virtual bool is_false() { return false; }
126
+ virtual bool operator==( Expression& rhs) const { return false; }
127
+ virtual size_t hash() { return 0; }
128
+ };
129
+ }
130
+
131
+
132
+ /////////////////////////////////////////////////////////////////////////////
133
+ // Hash method specializations for unordered_map to work with Sass::Expression
134
+ /////////////////////////////////////////////////////////////////////////////
135
+
136
+ namespace std {
137
+ template<>
138
+ struct hash<Sass::Expression*>
139
+ {
140
+ size_t operator()(Sass::Expression* s) const
141
+ {
142
+ return s->hash();
143
+ }
144
+ };
145
+ template<>
146
+ struct equal_to<Sass::Expression*>
147
+ {
148
+ bool operator()( Sass::Expression* lhs, Sass::Expression* rhs) const
149
+ {
150
+ return *lhs == *rhs;
151
+ }
152
+ };
153
+ }
154
+
155
+ namespace Sass {
156
+ using namespace std;
157
+
158
+ /////////////////////////////////////////////////////////////////////////////
159
+ // Mixin class for AST nodes that should behave like vectors. Uses the
160
+ // "Template Method" design pattern to allow subclasses to adjust their flags
161
+ // when certain objects are pushed.
162
+ /////////////////////////////////////////////////////////////////////////////
163
+ template <typename T>
164
+ class Vectorized {
165
+ vector<T> elements_;
166
+ protected:
167
+ size_t hash_;
168
+ void reset_hash() { hash_ = 0; }
169
+ virtual void adjust_after_pushing(T element) { }
170
+ public:
171
+ Vectorized(size_t s = 0) : elements_(vector<T>())
172
+ { elements_.reserve(s); }
173
+ virtual ~Vectorized() = 0;
174
+ size_t length() const { return elements_.size(); }
175
+ bool empty() const { return elements_.empty(); }
176
+ T& operator[](size_t i) { return elements_[i]; }
177
+ const T& operator[](size_t i) const { return elements_[i]; }
178
+ Vectorized& operator<<(T element)
179
+ {
180
+ reset_hash();
181
+ elements_.push_back(element);
182
+ adjust_after_pushing(element);
183
+ return *this;
184
+ }
185
+ Vectorized& operator+=(Vectorized* v)
186
+ {
187
+ for (size_t i = 0, L = v->length(); i < L; ++i) *this << (*v)[i];
188
+ return *this;
189
+ }
190
+ vector<T>& elements() { return elements_; }
191
+ const vector<T>& elements() const { return elements_; }
192
+ vector<T>& elements(vector<T>& e) { elements_ = e; return elements_; }
193
+ };
194
+ template <typename T>
195
+ inline Vectorized<T>::~Vectorized() { }
196
+
197
+ /////////////////////////////////////////////////////////////////////////////
198
+ // Mixin class for AST nodes that should behave like ahash table. Uses an
199
+ // extra <vector> internally to maintain insertion order for interation.
200
+ /////////////////////////////////////////////////////////////////////////////
201
+ class Hashed {
202
+ private:
203
+ unordered_map<Expression*, Expression*> elements_;
204
+ vector<Expression*> list_;
205
+ protected:
206
+ size_t hash_;
207
+ Expression* duplicate_key_;
208
+ void reset_hash() { hash_ = 0; }
209
+ void reset_duplicate_key() { duplicate_key_ = 0; }
210
+ virtual void adjust_after_pushing(std::pair<Expression*, Expression*> p) { }
211
+ public:
212
+ Hashed(size_t s = 0) : elements_(unordered_map<Expression*, Expression*>(s)), list_(vector<Expression*>())
213
+ { elements_.reserve(s); list_.reserve(s); reset_duplicate_key(); }
214
+ virtual ~Hashed();
215
+ size_t length() const { return list_.size(); }
216
+ bool empty() const { return list_.empty(); }
217
+ bool has(Expression* k) const { return elements_.count(k) == 1; }
218
+ Expression* at(Expression* k) const { return elements_.at(k); }
219
+ bool has_duplicate_key() const { return duplicate_key_ != 0; }
220
+ Expression* get_duplicate_key() const { return duplicate_key_; }
221
+ Hashed& operator<<(pair<Expression*, Expression*> p)
222
+ {
223
+ reset_hash();
224
+
225
+ if (!has(p.first)) list_.push_back(p.first);
226
+ else if (!duplicate_key_) duplicate_key_ = p.first;
227
+
228
+ elements_[p.first] = p.second;
229
+
230
+ adjust_after_pushing(p);
231
+ return *this;
232
+ }
233
+ Hashed& operator+=(Hashed* h)
234
+ {
235
+ if (length() == 0) {
236
+ this->elements_ = h->elements_;
237
+ this->list_ = h->list_;
238
+ return *this;
239
+ }
240
+
241
+ for (auto key : h->keys()) {
242
+ *this << make_pair(key, h->at(key));
243
+ }
244
+
245
+ reset_duplicate_key();
246
+ return *this;
247
+ }
248
+ const unordered_map<Expression*, Expression*>& pairs() const { return elements_; }
249
+ const vector<Expression*>& keys() const { return list_; }
250
+ };
251
+ inline Hashed::~Hashed() { }
252
+
253
+
254
+ /////////////////////////////////////////////////////////////////////////
255
+ // Abstract base class for statements. This side of the AST hierarchy
256
+ // represents elements in expansion contexts, which exist primarily to be
257
+ // rewritten and macro-expanded.
258
+ /////////////////////////////////////////////////////////////////////////
259
+ class Statement : public AST_Node {
260
+ public:
261
+ Statement(string path, Position position) : AST_Node(path, position) { }
262
+ virtual ~Statement() = 0;
263
+ // needed for rearranging nested rulesets during CSS emission
264
+ virtual bool is_hoistable() { return false; }
265
+ virtual Block* block() { return 0; }
266
+ };
267
+ inline Statement::~Statement() { }
268
+
269
+ ////////////////////////
270
+ // Blocks of statements.
271
+ ////////////////////////
272
+ class Block : public Statement, public Vectorized<Statement*> {
273
+ ADD_PROPERTY(bool, is_root);
274
+ // needed for properly formatted CSS emission
275
+ ADD_PROPERTY(bool, has_hoistable);
276
+ ADD_PROPERTY(bool, has_non_hoistable);
277
+ protected:
278
+ void adjust_after_pushing(Statement* s)
279
+ {
280
+ if (s->is_hoistable()) has_hoistable_ = true;
281
+ else has_non_hoistable_ = true;
282
+ };
283
+ public:
284
+ Block(string path, Position position, size_t s = 0, bool r = false)
285
+ : Statement(path, position),
286
+ Vectorized<Statement*>(s),
287
+ is_root_(r), has_hoistable_(false), has_non_hoistable_(false)
288
+ { }
289
+ Block* block() { return this; }
290
+ ATTACH_OPERATIONS();
291
+ };
292
+
293
+ ////////////////////////////////////////////////////////////////////////
294
+ // Abstract base class for statements that contain blocks of statements.
295
+ ////////////////////////////////////////////////////////////////////////
296
+ class Has_Block : public Statement {
297
+ ADD_PROPERTY(Block*, block);
298
+ public:
299
+ Has_Block(string path, Position position, Block* b)
300
+ : Statement(path, position), block_(b)
301
+ { }
302
+ virtual ~Has_Block() = 0;
303
+ };
304
+ inline Has_Block::~Has_Block() { }
305
+
306
+ /////////////////////////////////////////////////////////////////////////////
307
+ // Rulesets (i.e., sets of styles headed by a selector and containing a block
308
+ // of style declarations.
309
+ /////////////////////////////////////////////////////////////////////////////
310
+ class Selector;
311
+ class Ruleset : public Has_Block {
312
+ ADD_PROPERTY(Selector*, selector);
313
+ public:
314
+ Ruleset(string path, Position position, Selector* s, Block* b)
315
+ : Has_Block(path, position, b), selector_(s)
316
+ { }
317
+ // nested rulesets need to be hoisted out of their enclosing blocks
318
+ bool is_hoistable() { return true; }
319
+ ATTACH_OPERATIONS();
320
+ };
321
+
322
+ /////////////////////////////////////////////////////////
323
+ // Nested declaration sets (i.e., namespaced properties).
324
+ /////////////////////////////////////////////////////////
325
+ class String;
326
+ class Propset : public Has_Block {
327
+ ADD_PROPERTY(String*, property_fragment);
328
+ public:
329
+ Propset(string path, Position position, String* pf, Block* b = 0)
330
+ : Has_Block(path, position, b), property_fragment_(pf)
331
+ { }
332
+ ATTACH_OPERATIONS();
333
+ };
334
+
335
+ /////////////////
336
+ // Media queries.
337
+ /////////////////
338
+ class List;
339
+ class Media_Block : public Has_Block {
340
+ ADD_PROPERTY(List*, media_queries);
341
+ ADD_PROPERTY(Selector*, selector);
342
+ public:
343
+ Media_Block(string path, Position position, List* mqs, Block* b)
344
+ : Has_Block(path, position, b), media_queries_(mqs), selector_(0)
345
+ { }
346
+ bool is_hoistable() { return true; }
347
+ ATTACH_OPERATIONS();
348
+ };
349
+
350
+ ///////////////////
351
+ // Feature queries.
352
+ ///////////////////
353
+ class Feature_Block : public Has_Block {
354
+ ADD_PROPERTY(Feature_Query*, feature_queries);
355
+ ADD_PROPERTY(Selector*, selector);
356
+ public:
357
+ Feature_Block(string path, Position position, Feature_Query* fqs, Block* b)
358
+ : Has_Block(path, position, b), feature_queries_(fqs), selector_(0)
359
+ { }
360
+ bool is_hoistable() { return true; }
361
+ ATTACH_OPERATIONS();
362
+ };
363
+
364
+ ///////////////////////////////////////////////////////////////////////
365
+ // At-rules -- arbitrary directives beginning with "@" that may have an
366
+ // optional statement block.
367
+ ///////////////////////////////////////////////////////////////////////
368
+ class At_Rule : public Has_Block {
369
+ ADD_PROPERTY(string, keyword);
370
+ ADD_PROPERTY(Selector*, selector);
371
+ ADD_PROPERTY(Expression*, value);
372
+ public:
373
+ At_Rule(string path, Position position, string kwd, Selector* sel = 0, Block* b = 0)
374
+ : Has_Block(path, position, b), keyword_(kwd), selector_(sel), value_(0) // set value manually if needed
375
+ { }
376
+ ATTACH_OPERATIONS();
377
+ };
378
+
379
+ ////////////////////////////////////////////////////////////////////////
380
+ // Declarations -- style rules consisting of a property name and values.
381
+ ////////////////////////////////////////////////////////////////////////
382
+ class Declaration : public Statement {
383
+ ADD_PROPERTY(String*, property);
384
+ ADD_PROPERTY(Expression*, value);
385
+ ADD_PROPERTY(bool, is_important);
386
+ public:
387
+ Declaration(string path, Position position,
388
+ String* prop, Expression* val, bool i = false)
389
+ : Statement(path, position), property_(prop), value_(val), is_important_(i)
390
+ { }
391
+ ATTACH_OPERATIONS();
392
+ };
393
+
394
+ /////////////////////////////////////
395
+ // Assignments -- variable and value.
396
+ /////////////////////////////////////
397
+ class Variable;
398
+ class Expression;
399
+ class Assignment : public Statement {
400
+ ADD_PROPERTY(string, variable);
401
+ ADD_PROPERTY(Expression*, value);
402
+ ADD_PROPERTY(bool, is_guarded);
403
+ ADD_PROPERTY(bool, is_global);
404
+ public:
405
+ Assignment(string path, Position position,
406
+ string var, Expression* val,
407
+ bool guarded = false,
408
+ bool global = false)
409
+ : Statement(path, position), variable_(var), value_(val), is_guarded_(guarded), is_global_(global)
410
+ { }
411
+ ATTACH_OPERATIONS();
412
+ };
413
+
414
+ ////////////////////////////////////////////////////////////////////////////
415
+ // Import directives. CSS and Sass import lists can be intermingled, so it's
416
+ // necessary to store a list of each in an Import node.
417
+ ////////////////////////////////////////////////////////////////////////////
418
+ class Import : public Statement {
419
+ vector<string> files_;
420
+ vector<Expression*> urls_;
421
+ public:
422
+ Import(string path, Position position)
423
+ : Statement(path, position),
424
+ files_(vector<string>()), urls_(vector<Expression*>())
425
+ { }
426
+ vector<string>& files() { return files_; }
427
+ vector<Expression*>& urls() { return urls_; }
428
+ ATTACH_OPERATIONS();
429
+ };
430
+
431
+ class Import_Stub : public Statement {
432
+ ADD_PROPERTY(string, file_name);
433
+ public:
434
+ Import_Stub(string path, Position position, string f)
435
+ : Statement(path, position), file_name_(f)
436
+ { }
437
+ ATTACH_OPERATIONS();
438
+ };
439
+
440
+ //////////////////////////////
441
+ // The Sass `@warn` directive.
442
+ //////////////////////////////
443
+ class Warning : public Statement {
444
+ ADD_PROPERTY(Expression*, message);
445
+ public:
446
+ Warning(string path, Position position, Expression* msg)
447
+ : Statement(path, position), message_(msg)
448
+ { }
449
+ ATTACH_OPERATIONS();
450
+ };
451
+
452
+ ///////////////////////////////
453
+ // The Sass `@error` directive.
454
+ ///////////////////////////////
455
+ class Error : public Statement {
456
+ ADD_PROPERTY(Expression*, message);
457
+ public:
458
+ Error(string path, Position position, Expression* msg)
459
+ : Statement(path, position), message_(msg)
460
+ { }
461
+ ATTACH_OPERATIONS();
462
+ };
463
+
464
+ ///////////////////////////////
465
+ // The Sass `@debug` directive.
466
+ ///////////////////////////////
467
+ class Debug : public Statement {
468
+ ADD_PROPERTY(Expression*, value);
469
+ public:
470
+ Debug(string path, Position position, Expression* val)
471
+ : Statement(path, position), value_(val)
472
+ { }
473
+ ATTACH_OPERATIONS();
474
+ };
475
+
476
+ ///////////////////////////////////////////
477
+ // CSS comments. These may be interpolated.
478
+ ///////////////////////////////////////////
479
+ class Comment : public Statement {
480
+ ADD_PROPERTY(String*, text);
481
+ public:
482
+ Comment(string path, Position position, String* txt)
483
+ : Statement(path, position), text_(txt)
484
+ { }
485
+ ATTACH_OPERATIONS();
486
+ };
487
+
488
+ ////////////////////////////////////
489
+ // The Sass `@if` control directive.
490
+ ////////////////////////////////////
491
+ class If : public Statement {
492
+ ADD_PROPERTY(Expression*, predicate);
493
+ ADD_PROPERTY(Block*, consequent);
494
+ ADD_PROPERTY(Block*, alternative);
495
+ public:
496
+ If(string path, Position position, Expression* pred, Block* con, Block* alt = 0)
497
+ : Statement(path, position), predicate_(pred), consequent_(con), alternative_(alt)
498
+ { }
499
+ ATTACH_OPERATIONS();
500
+ };
501
+
502
+ /////////////////////////////////////
503
+ // The Sass `@for` control directive.
504
+ /////////////////////////////////////
505
+ class For : public Has_Block {
506
+ ADD_PROPERTY(string, variable);
507
+ ADD_PROPERTY(Expression*, lower_bound);
508
+ ADD_PROPERTY(Expression*, upper_bound);
509
+ ADD_PROPERTY(bool, is_inclusive);
510
+ public:
511
+ For(string path, Position position,
512
+ string var, Expression* lo, Expression* hi, Block* b, bool inc)
513
+ : Has_Block(path, position, b),
514
+ variable_(var), lower_bound_(lo), upper_bound_(hi), is_inclusive_(inc)
515
+ { }
516
+ ATTACH_OPERATIONS();
517
+ };
518
+
519
+ //////////////////////////////////////
520
+ // The Sass `@each` control directive.
521
+ //////////////////////////////////////
522
+ class Each : public Has_Block {
523
+ ADD_PROPERTY(vector<string>, variables);
524
+ ADD_PROPERTY(Expression*, list);
525
+ public:
526
+ Each(string path, Position position, vector<string> vars, Expression* lst, Block* b)
527
+ : Has_Block(path, position, b), variables_(vars), list_(lst)
528
+ { }
529
+ ATTACH_OPERATIONS();
530
+ };
531
+
532
+ ///////////////////////////////////////
533
+ // The Sass `@while` control directive.
534
+ ///////////////////////////////////////
535
+ class While : public Has_Block {
536
+ ADD_PROPERTY(Expression*, predicate);
537
+ public:
538
+ While(string path, Position position, Expression* pred, Block* b)
539
+ : Has_Block(path, position, b), predicate_(pred)
540
+ { }
541
+ ATTACH_OPERATIONS();
542
+ };
543
+
544
+ /////////////////////////////////////////////////////////////
545
+ // The @return directive for use inside SassScript functions.
546
+ /////////////////////////////////////////////////////////////
547
+ class Return : public Statement {
548
+ ADD_PROPERTY(Expression*, value);
549
+ public:
550
+ Return(string path, Position position, Expression* val)
551
+ : Statement(path, position), value_(val)
552
+ { }
553
+ ATTACH_OPERATIONS();
554
+ };
555
+
556
+ ////////////////////////////////
557
+ // The Sass `@extend` directive.
558
+ ////////////////////////////////
559
+ class Extension : public Statement {
560
+ ADD_PROPERTY(Selector*, selector);
561
+ public:
562
+ Extension(string path, Position position, Selector* s)
563
+ : Statement(path, position), selector_(s)
564
+ { }
565
+ ATTACH_OPERATIONS();
566
+ };
567
+
568
+ /////////////////////////////////////////////////////////////////////////////
569
+ // Definitions for both mixins and functions. The two cases are distinguished
570
+ // by a type tag.
571
+ /////////////////////////////////////////////////////////////////////////////
572
+ struct Context;
573
+ struct Backtrace;
574
+ class Parameters;
575
+ typedef Environment<AST_Node*> Env;
576
+ typedef const char* Signature;
577
+ typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, const string&, Position, Backtrace*);
578
+ typedef const char* Signature;
579
+ class Definition : public Has_Block {
580
+ public:
581
+ enum Type { MIXIN, FUNCTION };
582
+ ADD_PROPERTY(string, name);
583
+ ADD_PROPERTY(Parameters*, parameters);
584
+ ADD_PROPERTY(Env*, environment);
585
+ ADD_PROPERTY(Type, type);
586
+ ADD_PROPERTY(Native_Function, native_function);
587
+ ADD_PROPERTY(Sass_C_Function, c_function);
588
+ ADD_PROPERTY(void*, cookie);
589
+ ADD_PROPERTY(bool, is_overload_stub);
590
+ ADD_PROPERTY(Signature, signature);
591
+ public:
592
+ Definition(string path,
593
+ Position position,
594
+ string n,
595
+ Parameters* params,
596
+ Block* b,
597
+ Type t)
598
+ : Has_Block(path, position, b),
599
+ name_(n),
600
+ parameters_(params),
601
+ environment_(0),
602
+ type_(t),
603
+ native_function_(0),
604
+ c_function_(0),
605
+ cookie_(0),
606
+ is_overload_stub_(false),
607
+ signature_(0)
608
+ { }
609
+ Definition(string path,
610
+ Position position,
611
+ Signature sig,
612
+ string n,
613
+ Parameters* params,
614
+ Native_Function func_ptr,
615
+ bool overload_stub = false)
616
+ : Has_Block(path, position, 0),
617
+ name_(n),
618
+ parameters_(params),
619
+ environment_(0),
620
+ type_(FUNCTION),
621
+ native_function_(func_ptr),
622
+ c_function_(0),
623
+ cookie_(0),
624
+ is_overload_stub_(overload_stub),
625
+ signature_(sig)
626
+ { }
627
+ Definition(string path,
628
+ Position position,
629
+ Signature sig,
630
+ string n,
631
+ Parameters* params,
632
+ Sass_C_Function func_ptr,
633
+ void* cookie,
634
+ bool whatever,
635
+ bool whatever2)
636
+ : Has_Block(path, position, 0),
637
+ name_(n),
638
+ parameters_(params),
639
+ environment_(0),
640
+ type_(FUNCTION),
641
+ native_function_(0),
642
+ c_function_(func_ptr),
643
+ cookie_(cookie),
644
+ is_overload_stub_(false),
645
+ signature_(sig)
646
+ { }
647
+ ATTACH_OPERATIONS();
648
+ };
649
+
650
+ //////////////////////////////////////
651
+ // Mixin calls (i.e., `@include ...`).
652
+ //////////////////////////////////////
653
+ class Arguments;
654
+ class Mixin_Call : public Has_Block {
655
+ ADD_PROPERTY(string, name);
656
+ ADD_PROPERTY(Arguments*, arguments);
657
+ public:
658
+ Mixin_Call(string path, Position position, string n, Arguments* args, Block* b = 0)
659
+ : Has_Block(path, position, b), name_(n), arguments_(args)
660
+ { }
661
+ ATTACH_OPERATIONS();
662
+ };
663
+
664
+ ///////////////////////////////////////////////////
665
+ // The @content directive for mixin content blocks.
666
+ ///////////////////////////////////////////////////
667
+ class Content : public Statement {
668
+ public:
669
+ Content(string path, Position position) : Statement(path, position) { }
670
+ ATTACH_OPERATIONS();
671
+ };
672
+
673
+ ///////////////////////////////////////////////////////////////////////
674
+ // Lists of values, both comma- and space-separated (distinguished by a
675
+ // type-tag.) Also used to represent variable-length argument lists.
676
+ ///////////////////////////////////////////////////////////////////////
677
+ class List : public Expression, public Vectorized<Expression*> {
678
+ void adjust_after_pushing(Expression* e) { is_expanded(false); }
679
+ public:
680
+ enum Separator { SPACE, COMMA };
681
+ private:
682
+ ADD_PROPERTY(Separator, separator);
683
+ ADD_PROPERTY(bool, is_arglist);
684
+ public:
685
+ List(string path, Position position,
686
+ size_t size = 0, Separator sep = SPACE, bool argl = false)
687
+ : Expression(path, position),
688
+ Vectorized<Expression*>(size),
689
+ separator_(sep), is_arglist_(argl)
690
+ { concrete_type(LIST); }
691
+ string type() { return is_arglist_ ? "arglist" : "list"; }
692
+ static string type_name() { return "list"; }
693
+ bool is_invisible() { return !length(); }
694
+ Expression* value_at_index(size_t i);
695
+
696
+ virtual bool operator==(Expression& rhs) const
697
+ {
698
+ try
699
+ {
700
+ List& l = dynamic_cast<List&>(rhs);
701
+ if (!(l && length() == l.length() && separator() == l.separator())) return false;
702
+ for (size_t i = 0, L = l.length(); i < L; ++i)
703
+ if (!(*(elements()[i]) == *(l[i]))) return false;
704
+ return true;
705
+ }
706
+ catch (std::bad_cast&)
707
+ {
708
+ return false;
709
+ }
710
+ catch (...) { throw; }
711
+
712
+ }
713
+
714
+ virtual size_t hash()
715
+ {
716
+ if (hash_ > 0) return hash_;
717
+
718
+ hash_ = std::hash<string>()(separator() == COMMA ? "comma" : "space");
719
+
720
+ for (size_t i = 0, L = length(); i < L; ++i)
721
+ hash_ ^= (elements()[i])->hash();
722
+
723
+ return hash_;
724
+ }
725
+
726
+ ATTACH_OPERATIONS();
727
+ };
728
+
729
+ ///////////////////////////////////////////////////////////////////////
730
+ // Key value paris.
731
+ ///////////////////////////////////////////////////////////////////////
732
+
733
+ class Map : public Expression, public Hashed {
734
+ void adjust_after_pushing(std::pair<Expression*, Expression*> p) { is_expanded(false); }
735
+ public:
736
+ Map(string path, Position position,
737
+ size_t size = 0)
738
+ : Expression(path, position),
739
+ Hashed(size)
740
+ { concrete_type(MAP); }
741
+ string type() { return "map"; }
742
+ static string type_name() { return "map"; }
743
+ bool is_invisible() { return !length(); }
744
+
745
+ virtual bool operator==(Expression& rhs) const
746
+ {
747
+ try
748
+ {
749
+ Map& m = dynamic_cast<Map&>(rhs);
750
+ if (!(m && length() == m.length())) return false;
751
+ for (auto key : keys())
752
+ if (!(*at(key) == *m.at(key))) return false;
753
+ return true;
754
+ }
755
+ catch (std::bad_cast&)
756
+ {
757
+ return false;
758
+ }
759
+ catch (...) { throw; }
760
+ }
761
+
762
+ virtual size_t hash()
763
+ {
764
+ if (hash_ > 0) return hash_;
765
+
766
+ for (auto key : keys())
767
+ hash_ ^= key->hash() ^ at(key)->hash();
768
+
769
+ return hash_;
770
+ }
771
+
772
+ ATTACH_OPERATIONS();
773
+ };
774
+
775
+
776
+
777
+ //////////////////////////////////////////////////////////////////////////
778
+ // Binary expressions. Represents logical, relational, and arithmetic
779
+ // operations. Templatized to avoid large switch statements and repetitive
780
+ // subclassing.
781
+ //////////////////////////////////////////////////////////////////////////
782
+ class Binary_Expression : public Expression {
783
+ public:
784
+ enum Type {
785
+ AND, OR, // logical connectives
786
+ EQ, NEQ, GT, GTE, LT, LTE, // arithmetic relations
787
+ ADD, SUB, MUL, DIV, MOD, // arithmetic functions
788
+ NUM_OPS // so we know how big to make the op table
789
+ };
790
+ private:
791
+ ADD_PROPERTY(Type, type);
792
+ ADD_PROPERTY(Expression*, left);
793
+ ADD_PROPERTY(Expression*, right);
794
+ public:
795
+ Binary_Expression(string path, Position position,
796
+ Type t, Expression* lhs, Expression* rhs)
797
+ : Expression(path, position), type_(t), left_(lhs), right_(rhs)
798
+ { }
799
+ ATTACH_OPERATIONS();
800
+ };
801
+
802
+ ////////////////////////////////////////////////////////////////////////////
803
+ // Arithmetic negation (logical negation is just an ordinary function call).
804
+ ////////////////////////////////////////////////////////////////////////////
805
+ class Unary_Expression : public Expression {
806
+ public:
807
+ enum Type { PLUS, MINUS, NOT };
808
+ private:
809
+ ADD_PROPERTY(Type, type);
810
+ ADD_PROPERTY(Expression*, operand);
811
+ public:
812
+ Unary_Expression(string path, Position position, Type t, Expression* o)
813
+ : Expression(path, position), type_(t), operand_(o)
814
+ { }
815
+ ATTACH_OPERATIONS();
816
+ };
817
+
818
+ ////////////////////////////////////////////////////////////
819
+ // Individual argument objects for mixin and function calls.
820
+ ////////////////////////////////////////////////////////////
821
+ class Argument : public Expression {
822
+ ADD_PROPERTY(Expression*, value);
823
+ ADD_PROPERTY(string, name);
824
+ ADD_PROPERTY(bool, is_rest_argument);
825
+ ADD_PROPERTY(bool, is_keyword_argument);
826
+ size_t hash_;
827
+ public:
828
+ Argument(string p, Position pos, Expression* val, string n = "", bool rest = false, bool keyword = false)
829
+ : Expression(p, pos), value_(val), name_(n), is_rest_argument_(rest), is_keyword_argument_(keyword), hash_(0)
830
+ {
831
+ if (!name_.empty() && is_rest_argument_) {
832
+ error("variable-length argument may not be passed by name", path(), position());
833
+ }
834
+ }
835
+
836
+ virtual bool operator==(Expression& rhs) const
837
+ {
838
+ try
839
+ {
840
+ Argument& m = dynamic_cast<Argument&>(rhs);
841
+ if (!(m && name() == m.name())) return false;
842
+ return *value() == *value();
843
+ }
844
+ catch (std::bad_cast&)
845
+ {
846
+ return false;
847
+ }
848
+ catch (...) { throw; }
849
+ }
850
+
851
+ virtual size_t hash()
852
+ {
853
+ if (hash_ > 0) return hash_;
854
+
855
+ hash_ = std::hash<string>()(name()) ^ value()->hash();
856
+
857
+ return hash_;
858
+ }
859
+
860
+ ATTACH_OPERATIONS();
861
+ };
862
+
863
+ ////////////////////////////////////////////////////////////////////////
864
+ // Argument lists -- in their own class to facilitate context-sensitive
865
+ // error checking (e.g., ensuring that all ordinal arguments precede all
866
+ // named arguments).
867
+ ////////////////////////////////////////////////////////////////////////
868
+ class Arguments : public Expression, public Vectorized<Argument*> {
869
+ ADD_PROPERTY(bool, has_named_arguments);
870
+ ADD_PROPERTY(bool, has_rest_argument);
871
+ ADD_PROPERTY(bool, has_keyword_argument);
872
+ protected:
873
+ void adjust_after_pushing(Argument* a)
874
+ {
875
+ if (!a->name().empty()) {
876
+ if (has_rest_argument_ || has_keyword_argument_) {
877
+ error("named arguments must precede variable-length argument", a->path(), a->position());
878
+ }
879
+ has_named_arguments_ = true;
880
+ }
881
+ else if (a->is_rest_argument()) {
882
+ if (has_rest_argument_) {
883
+ error("functions and mixins may only be called with one variable-length argument", a->path(), a->position());
884
+ }
885
+ if (has_keyword_argument_) {
886
+ error("only keyword arguments may follow variable arguments", a->path(), a->position());
887
+ }
888
+ has_rest_argument_ = true;
889
+ }
890
+ else if (a->is_keyword_argument()) {
891
+ if (has_keyword_argument_) {
892
+ error("functions and mixins may only be called with one keyword argument", a->path(), a->position());
893
+ }
894
+ has_keyword_argument_ = true;
895
+ }
896
+ else {
897
+ if (has_rest_argument_) {
898
+ error("ordinal arguments must precede variable-length arguments", a->path(), a->position());
899
+ }
900
+ if (has_named_arguments_) {
901
+ error("ordinal arguments must precede named arguments", a->path(), a->position());
902
+ }
903
+ }
904
+ }
905
+ public:
906
+ Arguments(string path, Position position)
907
+ : Expression(path, position),
908
+ Vectorized<Argument*>(),
909
+ has_named_arguments_(false),
910
+ has_rest_argument_(false),
911
+ has_keyword_argument_(false)
912
+ { }
913
+ ATTACH_OPERATIONS();
914
+ };
915
+
916
+ //////////////////
917
+ // Function calls.
918
+ //////////////////
919
+ class Function_Call : public Expression {
920
+ ADD_PROPERTY(string, name);
921
+ ADD_PROPERTY(Arguments*, arguments);
922
+ ADD_PROPERTY(void*, cookie);
923
+ size_t hash_;
924
+ public:
925
+ Function_Call(string path, Position position, string n, Arguments* args, void* cookie)
926
+ : Expression(path, position), name_(n), arguments_(args), cookie_(cookie), hash_(0)
927
+ { concrete_type(STRING); }
928
+ Function_Call(string path, Position position, string n, Arguments* args)
929
+ : Expression(path, position), name_(n), arguments_(args), cookie_(0), hash_(0)
930
+ { concrete_type(STRING); }
931
+
932
+ virtual bool operator==(Expression& rhs) const
933
+ {
934
+ try
935
+ {
936
+ Function_Call& m = dynamic_cast<Function_Call&>(rhs);
937
+ if (!(m && name() == m.name())) return false;
938
+ if (!(m && arguments()->length() == m.arguments()->length())) return false;
939
+ for (size_t i =0, L = arguments()->length(); i < L; ++i)
940
+ if (!((*arguments())[i] == (*m.arguments())[i])) return false;
941
+ return true;
942
+ }
943
+ catch (std::bad_cast&)
944
+ {
945
+ return false;
946
+ }
947
+ catch (...) { throw; }
948
+ }
949
+
950
+ virtual size_t hash()
951
+ {
952
+ if (hash_ > 0) return hash_;
953
+
954
+ hash_ = std::hash<string>()(name());
955
+ for (auto argument : arguments()->elements())
956
+ hash_ ^= argument->hash();
957
+
958
+ return hash_;
959
+ }
960
+
961
+ ATTACH_OPERATIONS();
962
+ };
963
+
964
+ /////////////////////////
965
+ // Function call schemas.
966
+ /////////////////////////
967
+ class Function_Call_Schema : public Expression {
968
+ ADD_PROPERTY(String*, name);
969
+ ADD_PROPERTY(Arguments*, arguments);
970
+ public:
971
+ Function_Call_Schema(string path, Position position, String* n, Arguments* args)
972
+ : Expression(path, position), name_(n), arguments_(args)
973
+ { concrete_type(STRING); }
974
+ ATTACH_OPERATIONS();
975
+ };
976
+
977
+ ///////////////////////
978
+ // Variable references.
979
+ ///////////////////////
980
+ class Variable : public Expression {
981
+ ADD_PROPERTY(string, name);
982
+ public:
983
+ Variable(string path, Position position, string n)
984
+ : Expression(path, position), name_(n)
985
+ { }
986
+
987
+ virtual bool operator==(Expression& rhs) const
988
+ {
989
+ try
990
+ {
991
+ Variable& e = dynamic_cast<Variable&>(rhs);
992
+ return e && name() == e.name();
993
+ }
994
+ catch (std::bad_cast&)
995
+ {
996
+ return false;
997
+ }
998
+ catch (...) { throw; }
999
+ }
1000
+
1001
+ virtual size_t hash()
1002
+ {
1003
+ return std::hash<string>()(name());
1004
+ }
1005
+
1006
+ ATTACH_OPERATIONS();
1007
+ };
1008
+
1009
+ ////////////////////////////////////////////////////////////////////////////
1010
+ // Textual (i.e., unevaluated) numeric data. Variants are distinguished with
1011
+ // a type tag.
1012
+ ////////////////////////////////////////////////////////////////////////////
1013
+ class Textual : public Expression {
1014
+ public:
1015
+ enum Type { NUMBER, PERCENTAGE, DIMENSION, HEX };
1016
+ private:
1017
+ ADD_PROPERTY(Type, type);
1018
+ ADD_PROPERTY(string, value);
1019
+ size_t hash_;
1020
+ public:
1021
+ Textual(string path, Position position, Type t, string val)
1022
+ : Expression(path, position, true), type_(t), value_(val),
1023
+ hash_(0)
1024
+ { }
1025
+
1026
+ virtual bool operator==(Expression& rhs) const
1027
+ {
1028
+ try
1029
+ {
1030
+ Textual& e = dynamic_cast<Textual&>(rhs);
1031
+ return e && value() == e.value() && type() == e.type();
1032
+ }
1033
+ catch (std::bad_cast&)
1034
+ {
1035
+ return false;
1036
+ }
1037
+ catch (...) { throw; }
1038
+ }
1039
+
1040
+ virtual size_t hash()
1041
+ {
1042
+ if (hash_ == 0) hash_ = std::hash<string>()(value_) ^ std::hash<int>()(type_);
1043
+ return hash_;
1044
+ }
1045
+
1046
+ ATTACH_OPERATIONS();
1047
+ };
1048
+
1049
+ ////////////////////////////////////////////////
1050
+ // Numbers, percentages, dimensions, and colors.
1051
+ ////////////////////////////////////////////////
1052
+ class Number : public Expression {
1053
+ ADD_PROPERTY(double, value);
1054
+ ADD_PROPERTY(bool, zero);
1055
+ vector<string> numerator_units_;
1056
+ vector<string> denominator_units_;
1057
+ size_t hash_;
1058
+ public:
1059
+ Number(string path, Position position, double val, string u = "", bool zero = true)
1060
+ : Expression(path, position),
1061
+ value_(val),
1062
+ zero_(zero),
1063
+ numerator_units_(vector<string>()),
1064
+ denominator_units_(vector<string>()),
1065
+ hash_(0)
1066
+ {
1067
+ if (!u.empty()) numerator_units_.push_back(u);
1068
+ concrete_type(NUMBER);
1069
+ }
1070
+ bool zero() { return zero_; }
1071
+ vector<string>& numerator_units() { return numerator_units_; }
1072
+ vector<string>& denominator_units() { return denominator_units_; }
1073
+ string type() { return "number"; }
1074
+ static string type_name() { return "number"; }
1075
+ string unit() const
1076
+ {
1077
+ stringstream u;
1078
+ for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
1079
+ if (i) u << '*';
1080
+ u << numerator_units_[i];
1081
+ }
1082
+ if (!denominator_units_.empty()) u << '/';
1083
+ for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
1084
+ if (i) u << '*';
1085
+ u << denominator_units_[i];
1086
+ }
1087
+ return u.str();
1088
+ }
1089
+ bool is_unitless()
1090
+ { return numerator_units_.empty() && denominator_units_.empty(); }
1091
+ void normalize(string to = "")
1092
+ {
1093
+ // (multiple passes because I'm too tired to think up something clever)
1094
+ // Find a unit to convert everything to, if one isn't provided.
1095
+ if (to.empty()) {
1096
+ for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
1097
+ string u(numerator_units_[i]);
1098
+ if (string_to_unit(u) == INCOMMENSURABLE) {
1099
+ continue;
1100
+ }
1101
+ else {
1102
+ to = u;
1103
+ break;
1104
+ }
1105
+ }
1106
+ }
1107
+ if (to.empty()) {
1108
+ for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
1109
+ string u(denominator_units_[i]);
1110
+ if (string_to_unit(u) == INCOMMENSURABLE) {
1111
+ continue;
1112
+ }
1113
+ else {
1114
+ to = u;
1115
+ break;
1116
+ }
1117
+ }
1118
+ }
1119
+ // Now loop through again and do all the conversions.
1120
+ for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
1121
+ string from(numerator_units_[i]);
1122
+ if (string_to_unit(from) == INCOMMENSURABLE) continue;
1123
+ value_ *= conversion_factor(from, to);
1124
+ numerator_units_[i] = to;
1125
+ }
1126
+ for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
1127
+ string from(denominator_units_[i]);
1128
+ if (string_to_unit(from) == INCOMMENSURABLE) continue;
1129
+ value_ /= conversion_factor(from, to);
1130
+ denominator_units_[i] = to;
1131
+ }
1132
+ // Now divide out identical units in the numerator and denominator.
1133
+ vector<string> ncopy;
1134
+ ncopy.reserve(numerator_units_.size());
1135
+ for (vector<string>::iterator n = numerator_units_.begin();
1136
+ n != numerator_units_.end();
1137
+ ++n) {
1138
+ vector<string>::iterator d = find(denominator_units_.begin(),
1139
+ denominator_units_.end(),
1140
+ *n);
1141
+ if (d != denominator_units_.end()) {
1142
+ denominator_units_.erase(d);
1143
+ }
1144
+ else {
1145
+ ncopy.push_back(*n);
1146
+ }
1147
+ }
1148
+ numerator_units_ = ncopy;
1149
+ // Sort the units to make them pretty and, well, normal.
1150
+ sort(numerator_units_.begin(), numerator_units_.end());
1151
+ sort(denominator_units_.begin(), denominator_units_.end());
1152
+ }
1153
+ // useful for making one number compatible with another
1154
+ string find_convertible_unit() const
1155
+ {
1156
+ for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
1157
+ string u(numerator_units_[i]);
1158
+ if (string_to_unit(u) != INCOMMENSURABLE) return u;
1159
+ }
1160
+ for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
1161
+ string u(denominator_units_[i]);
1162
+ if (string_to_unit(u) != INCOMMENSURABLE) return u;
1163
+ }
1164
+ return string();
1165
+ }
1166
+
1167
+ virtual bool operator==(Expression& rhs) const
1168
+ {
1169
+ try
1170
+ {
1171
+ Number& e(dynamic_cast<Number&>(rhs));
1172
+ if (!e) return false;
1173
+ e.normalize(find_convertible_unit());
1174
+ return unit() == e.unit() && value() == e.value();
1175
+ }
1176
+ catch (std::bad_cast&)
1177
+ {
1178
+ return false;
1179
+ }
1180
+ catch (...) { throw; }
1181
+ }
1182
+
1183
+ virtual size_t hash()
1184
+ {
1185
+ if (hash_ == 0) hash_ = std::hash<double>()(value_);
1186
+ return hash_;
1187
+ }
1188
+
1189
+ ATTACH_OPERATIONS();
1190
+ };
1191
+
1192
+ //////////
1193
+ // Colors.
1194
+ //////////
1195
+ class Color : public Expression {
1196
+ ADD_PROPERTY(double, r);
1197
+ ADD_PROPERTY(double, g);
1198
+ ADD_PROPERTY(double, b);
1199
+ ADD_PROPERTY(double, a);
1200
+ ADD_PROPERTY(bool, sixtuplet);
1201
+ ADD_PROPERTY(string, disp);
1202
+ size_t hash_;
1203
+ public:
1204
+ Color(string path, Position position, double r, double g, double b, double a = 1, bool sixtuplet = true, const string disp = "")
1205
+ : Expression(path, position), r_(r), g_(g), b_(b), a_(a), sixtuplet_(sixtuplet), disp_(disp),
1206
+ hash_(0)
1207
+ { concrete_type(COLOR); }
1208
+ string type() { return "color"; }
1209
+ static string type_name() { return "color"; }
1210
+
1211
+ virtual bool operator==(Expression& rhs) const
1212
+ {
1213
+ try
1214
+ {
1215
+ Color& c = (dynamic_cast<Color&>(rhs));
1216
+ return c && r() == c.r() && g() == c.g() && b() == c.b() && a() == c.a();
1217
+ }
1218
+ catch (std::bad_cast&)
1219
+ {
1220
+ return false;
1221
+ }
1222
+ catch (...) { throw; }
1223
+ }
1224
+
1225
+ virtual size_t hash()
1226
+ {
1227
+ if (hash_ == 0) hash_ = std::hash<double>()(r_) ^ std::hash<double>()(g_) ^ std::hash<double>()(b_) ^ std::hash<double>()(a_);
1228
+ return hash_;
1229
+ }
1230
+
1231
+ ATTACH_OPERATIONS();
1232
+ };
1233
+
1234
+ ////////////
1235
+ // Booleans.
1236
+ ////////////
1237
+ class Boolean : public Expression {
1238
+ ADD_PROPERTY(bool, value);
1239
+ size_t hash_;
1240
+ public:
1241
+ Boolean(string path, Position position, bool val)
1242
+ : Expression(path, position), value_(val),
1243
+ hash_(0)
1244
+ { concrete_type(BOOLEAN); }
1245
+ virtual operator bool() { return value_; }
1246
+ string type() { return "bool"; }
1247
+ static string type_name() { return "bool"; }
1248
+ virtual bool is_false() { return !value_; }
1249
+
1250
+ virtual bool operator==(Expression& rhs) const
1251
+ {
1252
+ try
1253
+ {
1254
+ Boolean& e = dynamic_cast<Boolean&>(rhs);
1255
+ return e && value() == e.value();
1256
+ }
1257
+ catch (std::bad_cast&)
1258
+ {
1259
+ return false;
1260
+ }
1261
+ catch (...) { throw; }
1262
+ }
1263
+
1264
+ virtual size_t hash()
1265
+ {
1266
+ if (hash_ == 0) hash_ = std::hash<bool>()(value_);
1267
+ return hash_;
1268
+ }
1269
+
1270
+ ATTACH_OPERATIONS();
1271
+ };
1272
+
1273
+ ////////////////////////////////////////////////////////////////////////
1274
+ // Abstract base class for Sass string values. Includes interpolated and
1275
+ // "flat" strings.
1276
+ ////////////////////////////////////////////////////////////////////////
1277
+ class String : public Expression {
1278
+ ADD_PROPERTY(bool, needs_unquoting);
1279
+ public:
1280
+ String(string path, Position position, bool unq = false, bool delayed = false)
1281
+ : Expression(path, position, delayed), needs_unquoting_(unq)
1282
+ { concrete_type(STRING); }
1283
+ static string type_name() { return "string"; }
1284
+ virtual ~String() = 0;
1285
+ ATTACH_OPERATIONS();
1286
+ };
1287
+ inline String::~String() { };
1288
+
1289
+ ///////////////////////////////////////////////////////////////////////
1290
+ // Interpolated strings. Meant to be reduced to flat strings during the
1291
+ // evaluation phase.
1292
+ ///////////////////////////////////////////////////////////////////////
1293
+ class String_Schema : public String, public Vectorized<Expression*> {
1294
+ ADD_PROPERTY(char, quote_mark);
1295
+ ADD_PROPERTY(bool, has_interpolants);
1296
+ size_t hash_;
1297
+ public:
1298
+ String_Schema(string path, Position position, size_t size = 0, bool unq = false, char qm = '\0', bool i = false)
1299
+ : String(path, position, unq), Vectorized<Expression*>(size), quote_mark_(qm), has_interpolants_(i), hash_(0)
1300
+ { }
1301
+ string type() { return "string"; }
1302
+ static string type_name() { return "string"; }
1303
+
1304
+ virtual bool operator==(Expression& rhs) const
1305
+ {
1306
+ try
1307
+ {
1308
+ String_Schema& e = dynamic_cast<String_Schema&>(rhs);
1309
+ if (!(e && length() == e.length())) return false;
1310
+ for (size_t i = 0, L = length(); i < L; ++i)
1311
+ if (!((*this)[i] == e[i])) return false;
1312
+ return true;
1313
+ }
1314
+ catch (std::bad_cast&)
1315
+ {
1316
+ return false;
1317
+ }
1318
+ catch (...) { throw; }
1319
+ }
1320
+
1321
+ virtual size_t hash()
1322
+ {
1323
+ if (hash_ > 0) return hash_;
1324
+
1325
+ for (auto string : elements())
1326
+ hash_ ^= string->hash();
1327
+
1328
+ return hash_;
1329
+ }
1330
+
1331
+ ATTACH_OPERATIONS();
1332
+ };
1333
+
1334
+ ////////////////////////////////////////////////////////
1335
+ // Flat strings -- the lowest level of raw textual data.
1336
+ ////////////////////////////////////////////////////////
1337
+ class String_Constant : public String {
1338
+ ADD_PROPERTY(string, value);
1339
+ string unquoted_;
1340
+ size_t hash_;
1341
+ public:
1342
+ String_Constant(string path, Position position, string val, bool unq = false)
1343
+ : String(path, position, unq, true), value_(val), hash_(0)
1344
+ { unquoted_ = unquote(value_); }
1345
+ String_Constant(string path, Position position, const char* beg, bool unq = false)
1346
+ : String(path, position, unq, true), value_(string(beg)), hash_(0)
1347
+ { unquoted_ = unquote(value_); }
1348
+ String_Constant(string path, Position position, const char* beg, const char* end, bool unq = false)
1349
+ : String(path, position, unq, true), value_(string(beg, end-beg)), hash_(0)
1350
+ { unquoted_ = unquote(value_); }
1351
+ String_Constant(string path, Position position, const Token& tok, bool unq = false)
1352
+ : String(path, position, unq, true), value_(string(tok.begin, tok.end)), hash_(0)
1353
+ { unquoted_ = unquote(value_); }
1354
+ string type() { return "string"; }
1355
+ static string type_name() { return "string"; }
1356
+
1357
+ virtual bool operator==(Expression& rhs) const
1358
+ {
1359
+ try
1360
+ {
1361
+ String_Constant& e = dynamic_cast<String_Constant&>(rhs);
1362
+ return e && unquoted_ == e.unquoted_;
1363
+ }
1364
+ catch (std::bad_cast&)
1365
+ {
1366
+ return false;
1367
+ }
1368
+ catch (...) { throw; }
1369
+ }
1370
+
1371
+ virtual size_t hash()
1372
+ {
1373
+ if (hash_ == 0) hash_ = std::hash<string>()(unquoted_);
1374
+ return hash_;
1375
+ }
1376
+
1377
+ static char single_quote() { return '\''; }
1378
+ static char double_quote() { return '"'; }
1379
+
1380
+ bool is_quoted() { return value_.length() && (value_[0] == '"' || value_[0] == '\''); }
1381
+ char quote_mark() { return is_quoted() ? value_[0] : '\0'; }
1382
+ ATTACH_OPERATIONS();
1383
+ };
1384
+
1385
+ /////////////////
1386
+ // Media queries.
1387
+ /////////////////
1388
+ class Media_Query : public Expression,
1389
+ public Vectorized<Media_Query_Expression*> {
1390
+ ADD_PROPERTY(String*, media_type);
1391
+ ADD_PROPERTY(bool, is_negated);
1392
+ ADD_PROPERTY(bool, is_restricted);
1393
+ public:
1394
+ Media_Query(string path, Position position,
1395
+ String* t = 0, size_t s = 0, bool n = false, bool r = false)
1396
+ : Expression(path, position), Vectorized<Media_Query_Expression*>(s),
1397
+ media_type_(t), is_negated_(n), is_restricted_(r)
1398
+ { }
1399
+ ATTACH_OPERATIONS();
1400
+ };
1401
+
1402
+ ////////////////////////////////////////////////////
1403
+ // Media expressions (for use inside media queries).
1404
+ ////////////////////////////////////////////////////
1405
+ class Media_Query_Expression : public Expression {
1406
+ ADD_PROPERTY(Expression*, feature);
1407
+ ADD_PROPERTY(Expression*, value);
1408
+ ADD_PROPERTY(bool, is_interpolated);
1409
+ public:
1410
+ Media_Query_Expression(string path, Position position,
1411
+ Expression* f, Expression* v, bool i = false)
1412
+ : Expression(path, position), feature_(f), value_(v), is_interpolated_(i)
1413
+ { }
1414
+ ATTACH_OPERATIONS();
1415
+ };
1416
+
1417
+ ///////////////////
1418
+ // Feature queries.
1419
+ ///////////////////
1420
+ class Feature_Query : public Expression, public Vectorized<Feature_Query_Condition*> {
1421
+ public:
1422
+ Feature_Query(string path, Position position, size_t s = 0)
1423
+ : Expression(path, position), Vectorized<Feature_Query_Condition*>(s)
1424
+ { }
1425
+ ATTACH_OPERATIONS();
1426
+ };
1427
+
1428
+ ////////////////////////////////////////////////////////
1429
+ // Feature expressions (for use inside feature queries).
1430
+ ////////////////////////////////////////////////////////
1431
+ class Feature_Query_Condition : public Expression, public Vectorized<Feature_Query_Condition*> {
1432
+ public:
1433
+ enum Operand { NONE, AND, OR, NOT };
1434
+ private:
1435
+ ADD_PROPERTY(String*, feature);
1436
+ ADD_PROPERTY(Expression*, value);
1437
+ ADD_PROPERTY(Operand, operand);
1438
+ ADD_PROPERTY(bool, is_root);
1439
+ public:
1440
+ Feature_Query_Condition(string path, Position position, size_t s = 0, String* f = 0,
1441
+ Expression* v = 0, Operand o = NONE, bool r = false)
1442
+ : Expression(path, position), Vectorized<Feature_Query_Condition*>(s),
1443
+ feature_(f), value_(v), operand_(o), is_root_(r)
1444
+ { }
1445
+ ATTACH_OPERATIONS();
1446
+ };
1447
+
1448
+ //////////////////
1449
+ // The null value.
1450
+ //////////////////
1451
+ class Null : public Expression {
1452
+ public:
1453
+ Null(string path, Position position) : Expression(path, position) { concrete_type(NULL_VAL); }
1454
+ string type() { return "null"; }
1455
+ static string type_name() { return "null"; }
1456
+ bool is_invisible() { return true; }
1457
+ operator bool() { return false; }
1458
+ bool is_false() { return true; }
1459
+
1460
+ virtual bool operator==(Expression& rhs) const
1461
+ {
1462
+ return rhs.concrete_type() == NULL_VAL;
1463
+ }
1464
+
1465
+ virtual size_t hash()
1466
+ {
1467
+ return 0;
1468
+ }
1469
+
1470
+ ATTACH_OPERATIONS();
1471
+ };
1472
+
1473
+ /////////////////////////////////
1474
+ // Thunks for delayed evaluation.
1475
+ /////////////////////////////////
1476
+ class Thunk : public Expression {
1477
+ ADD_PROPERTY(Expression*, expression);
1478
+ ADD_PROPERTY(Env*, environment);
1479
+ public:
1480
+ Thunk(string path, Position position, Expression* exp, Env* env = 0)
1481
+ : Expression(path, position), expression_(exp), environment_(env)
1482
+ { }
1483
+ };
1484
+
1485
+ /////////////////////////////////////////////////////////
1486
+ // Individual parameter objects for mixins and functions.
1487
+ /////////////////////////////////////////////////////////
1488
+ class Parameter : public AST_Node {
1489
+ ADD_PROPERTY(string, name);
1490
+ ADD_PROPERTY(Expression*, default_value);
1491
+ ADD_PROPERTY(bool, is_rest_parameter);
1492
+ public:
1493
+ Parameter(string p, Position pos,
1494
+ string n, Expression* def = 0, bool rest = false)
1495
+ : AST_Node(p, pos), name_(n), default_value_(def), is_rest_parameter_(rest)
1496
+ {
1497
+ if (default_value_ && is_rest_parameter_) {
1498
+ error("variable-length parameter may not have a default value", path(), position());
1499
+ }
1500
+ }
1501
+ ATTACH_OPERATIONS();
1502
+ };
1503
+
1504
+ /////////////////////////////////////////////////////////////////////////
1505
+ // Parameter lists -- in their own class to facilitate context-sensitive
1506
+ // error checking (e.g., ensuring that all optional parameters follow all
1507
+ // required parameters).
1508
+ /////////////////////////////////////////////////////////////////////////
1509
+ class Parameters : public AST_Node, public Vectorized<Parameter*> {
1510
+ ADD_PROPERTY(bool, has_optional_parameters);
1511
+ ADD_PROPERTY(bool, has_rest_parameter);
1512
+ protected:
1513
+ void adjust_after_pushing(Parameter* p)
1514
+ {
1515
+ if (p->default_value()) {
1516
+ if (has_rest_parameter_) {
1517
+ error("optional parameters may not be combined with variable-length parameters", p->path(), p->position());
1518
+ }
1519
+ has_optional_parameters_ = true;
1520
+ }
1521
+ else if (p->is_rest_parameter()) {
1522
+ if (has_rest_parameter_) {
1523
+ error("functions and mixins cannot have more than one variable-length parameter", p->path(), p->position());
1524
+ }
1525
+ if (has_optional_parameters_) {
1526
+ error("optional parameters may not be combined with variable-length parameters", p->path(), p->position());
1527
+ }
1528
+ has_rest_parameter_ = true;
1529
+ }
1530
+ else {
1531
+ if (has_rest_parameter_) {
1532
+ error("required parameters must precede variable-length parameters", p->path(), p->position());
1533
+ }
1534
+ if (has_optional_parameters_) {
1535
+ error("required parameters must precede optional parameters", p->path(), p->position());
1536
+ }
1537
+ }
1538
+ }
1539
+ public:
1540
+ Parameters(string path, Position position)
1541
+ : AST_Node(path, position),
1542
+ Vectorized<Parameter*>(),
1543
+ has_optional_parameters_(false),
1544
+ has_rest_parameter_(false)
1545
+ { }
1546
+ ATTACH_OPERATIONS();
1547
+ };
1548
+
1549
+ //////////////////////////////////////////////////////////////////////////////////////////
1550
+ // Additional method on Lists to retrieve values directly or from an encompassed Argument.
1551
+ //////////////////////////////////////////////////////////////////////////////////////////
1552
+ inline Expression* List::value_at_index(size_t i) { return is_arglist_ ? ((Argument*)(*this)[i])->value() : (*this)[i]; }
1553
+
1554
+ /////////////////////////////////////////
1555
+ // Abstract base class for CSS selectors.
1556
+ /////////////////////////////////////////
1557
+ class Selector : public AST_Node {
1558
+ ADD_PROPERTY(bool, has_reference);
1559
+ ADD_PROPERTY(bool, has_placeholder);
1560
+ public:
1561
+ Selector(string path, Position position, bool r = false, bool h = false)
1562
+ : AST_Node(path, position), has_reference_(r), has_placeholder_(h)
1563
+ { }
1564
+ virtual ~Selector() = 0;
1565
+ virtual Selector_Placeholder* find_placeholder();
1566
+ virtual int specificity() { return Constants::SPECIFICITY_BASE; }
1567
+ };
1568
+ inline Selector::~Selector() { }
1569
+
1570
+ /////////////////////////////////////////////////////////////////////////
1571
+ // Interpolated selectors -- the interpolated String will be expanded and
1572
+ // re-parsed into a normal selector class.
1573
+ /////////////////////////////////////////////////////////////////////////
1574
+ class Selector_Schema : public Selector {
1575
+ ADD_PROPERTY(String*, contents);
1576
+ public:
1577
+ Selector_Schema(string path, Position position, String* c)
1578
+ : Selector(path, position), contents_(c)
1579
+ { }
1580
+ ATTACH_OPERATIONS();
1581
+ };
1582
+
1583
+ ////////////////////////////////////////////
1584
+ // Abstract base class for simple selectors.
1585
+ ////////////////////////////////////////////
1586
+ class Simple_Selector : public Selector {
1587
+ public:
1588
+ Simple_Selector(string path, Position position)
1589
+ : Selector(path, position)
1590
+ { }
1591
+ virtual ~Simple_Selector() = 0;
1592
+ virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
1593
+ virtual bool is_pseudo_element() { return false; }
1594
+
1595
+ bool operator==(const Simple_Selector& rhs) const;
1596
+ inline bool operator!=(const Simple_Selector& rhs) const { return !(*this == rhs); }
1597
+
1598
+ bool operator<(const Simple_Selector& rhs) const;
1599
+ };
1600
+ inline Simple_Selector::~Simple_Selector() { }
1601
+
1602
+ /////////////////////////////////////
1603
+ // Parent references (i.e., the "&").
1604
+ /////////////////////////////////////
1605
+ class Selector_Reference : public Simple_Selector {
1606
+ ADD_PROPERTY(Selector*, selector);
1607
+ public:
1608
+ Selector_Reference(string path, Position position, Selector* r = 0)
1609
+ : Simple_Selector(path, position), selector_(r)
1610
+ { has_reference(true); }
1611
+ virtual int specificity()
1612
+ {
1613
+ if (selector()) return selector()->specificity();
1614
+ else return 0;
1615
+ }
1616
+ ATTACH_OPERATIONS();
1617
+ };
1618
+
1619
+ /////////////////////////////////////////////////////////////////////////
1620
+ // Placeholder selectors (e.g., "%foo") for use in extend-only selectors.
1621
+ /////////////////////////////////////////////////////////////////////////
1622
+ class Selector_Placeholder : public Simple_Selector {
1623
+ ADD_PROPERTY(string, name);
1624
+ public:
1625
+ Selector_Placeholder(string path, Position position, string n)
1626
+ : Simple_Selector(path, position), name_(n)
1627
+ { has_placeholder(true); }
1628
+ virtual Selector_Placeholder* find_placeholder();
1629
+ ATTACH_OPERATIONS();
1630
+ };
1631
+
1632
+ /////////////////////////////////////////////////////////////////////
1633
+ // Type selectors (and the universal selector) -- e.g., div, span, *.
1634
+ /////////////////////////////////////////////////////////////////////
1635
+ class Type_Selector : public Simple_Selector {
1636
+ ADD_PROPERTY(string, name);
1637
+ public:
1638
+ Type_Selector(string path, Position position, string n)
1639
+ : Simple_Selector(path, position), name_(n)
1640
+ { }
1641
+ virtual int specificity()
1642
+ {
1643
+ if (name() == "*") return 0;
1644
+ else return 1;
1645
+ }
1646
+ virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
1647
+ ATTACH_OPERATIONS();
1648
+ };
1649
+
1650
+ ////////////////////////////////////////////////
1651
+ // Selector qualifiers -- i.e., classes and ids.
1652
+ ////////////////////////////////////////////////
1653
+ class Selector_Qualifier : public Simple_Selector {
1654
+ ADD_PROPERTY(string, name);
1655
+ public:
1656
+ Selector_Qualifier(string path, Position position, string n)
1657
+ : Simple_Selector(path, position), name_(n)
1658
+ { }
1659
+ virtual int specificity()
1660
+ {
1661
+ if (name()[0] == '#') return Constants::SPECIFICITY_BASE * Constants::SPECIFICITY_BASE;
1662
+ else return Constants::SPECIFICITY_BASE;
1663
+ }
1664
+ virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
1665
+ ATTACH_OPERATIONS();
1666
+ };
1667
+
1668
+ ///////////////////////////////////////////////////
1669
+ // Attribute selectors -- e.g., [src*=".jpg"], etc.
1670
+ ///////////////////////////////////////////////////
1671
+ class Attribute_Selector : public Simple_Selector {
1672
+ ADD_PROPERTY(string, name);
1673
+ ADD_PROPERTY(string, matcher);
1674
+ ADD_PROPERTY(String*, value); // might be interpolated
1675
+ public:
1676
+ Attribute_Selector(string path, Position position, string n, string m, String* v)
1677
+ : Simple_Selector(path, position), name_(n), matcher_(m), value_(v)
1678
+ { }
1679
+ ATTACH_OPERATIONS();
1680
+ };
1681
+
1682
+ //////////////////////////////////////////////////////////////////
1683
+ // Pseudo selectors -- e.g., :first-child, :nth-of-type(...), etc.
1684
+ //////////////////////////////////////////////////////////////////
1685
+ class Pseudo_Selector : public Simple_Selector {
1686
+ ADD_PROPERTY(string, name);
1687
+ ADD_PROPERTY(String*, expression);
1688
+ public:
1689
+ Pseudo_Selector(string path, Position position, string n, String* expr = 0)
1690
+ : Simple_Selector(path, position), name_(n), expression_(expr)
1691
+ { }
1692
+ virtual int specificity()
1693
+ {
1694
+ // TODO: clean up the pseudo-element checking
1695
+ if (name() == ":before" || name() == "::before" ||
1696
+ name() == ":after" || name() == "::after" ||
1697
+ name() == ":first-line" || name() == "::first-line" ||
1698
+ name() == ":first-letter" || name() == "::first-letter")
1699
+ return 1;
1700
+ else
1701
+ return Constants::SPECIFICITY_BASE;
1702
+ }
1703
+ virtual bool is_pseudo_element()
1704
+ {
1705
+ if (name() == ":before" || name() == "::before" ||
1706
+ name() == ":after" || name() == "::after" ||
1707
+ name() == ":first-line" || name() == "::first-line" ||
1708
+ name() == ":first-letter" || name() == "::first-letter") {
1709
+ return true;
1710
+ }
1711
+ else {
1712
+ // If it's not a known pseudo-element, check whether it looks like one. This is similar to the type method on the Pseudo class in ruby sass.
1713
+ return name().find("::") == 0;
1714
+ }
1715
+ }
1716
+ virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
1717
+ ATTACH_OPERATIONS();
1718
+ };
1719
+
1720
+ /////////////////////////////////////////////////
1721
+ // Wrapped selector -- pseudo selector that takes a list of selectors as argument(s) e.g., :not(:first-of-type), :-moz-any(ol p.blah, ul, menu, dir)
1722
+ /////////////////////////////////////////////////
1723
+ class Wrapped_Selector : public Simple_Selector {
1724
+ ADD_PROPERTY(string, name);
1725
+ ADD_PROPERTY(Selector*, selector);
1726
+ public:
1727
+ Wrapped_Selector(string path, Position position, string n, Selector* sel)
1728
+ : Simple_Selector(path, position), name_(n), selector_(sel)
1729
+ { }
1730
+ ATTACH_OPERATIONS();
1731
+ };
1732
+
1733
+ struct Complex_Selector_Pointer_Compare {
1734
+ bool operator() (const Complex_Selector* const pLeft, const Complex_Selector* const pRight) const;
1735
+ };
1736
+
1737
+ ////////////////////////////////////////////////////////////////////////////
1738
+ // Simple selector sequences. Maintains flags indicating whether it contains
1739
+ // any parent references or placeholders, to simplify expansion.
1740
+ ////////////////////////////////////////////////////////////////////////////
1741
+ typedef set<Complex_Selector*, Complex_Selector_Pointer_Compare> SourcesSet;
1742
+ class Compound_Selector : public Selector, public Vectorized<Simple_Selector*> {
1743
+ private:
1744
+ SourcesSet sources_;
1745
+ protected:
1746
+ void adjust_after_pushing(Simple_Selector* s)
1747
+ {
1748
+ if (s->has_reference()) has_reference(true);
1749
+ if (s->has_placeholder()) has_placeholder(true);
1750
+ }
1751
+ public:
1752
+ Compound_Selector(string path, Position position, size_t s = 0)
1753
+ : Selector(path, position),
1754
+ Vectorized<Simple_Selector*>(s)
1755
+ { }
1756
+
1757
+ Compound_Selector* unify_with(Compound_Selector* rhs, Context& ctx);
1758
+ virtual Selector_Placeholder* find_placeholder();
1759
+ Simple_Selector* base()
1760
+ {
1761
+ // Implement non-const in terms of const. Safe to const_cast since this method is non-const
1762
+ return const_cast<Simple_Selector*>(static_cast<const Compound_Selector*>(this)->base());
1763
+ }
1764
+ const Simple_Selector* base() const {
1765
+ if (length() > 0 && typeid(*(*this)[0]) == typeid(Type_Selector))
1766
+ return (*this)[0];
1767
+ return 0;
1768
+ }
1769
+ bool is_superselector_of(Compound_Selector* rhs);
1770
+ virtual int specificity()
1771
+ {
1772
+ int sum = 0;
1773
+ for (size_t i = 0, L = length(); i < L; ++i)
1774
+ { sum += (*this)[i]->specificity(); }
1775
+ return sum;
1776
+ }
1777
+ bool is_empty_reference()
1778
+ {
1779
+ return length() == 1 &&
1780
+ typeid(*(*this)[0]) == typeid(Selector_Reference) &&
1781
+ !static_cast<Selector_Reference*>((*this)[0])->selector();
1782
+ }
1783
+ vector<string> to_str_vec(); // sometimes need to convert to a flat "by-value" data structure
1784
+
1785
+ bool operator<(const Compound_Selector& rhs) const;
1786
+
1787
+ bool operator==(const Compound_Selector& rhs) const;
1788
+ inline bool operator!=(const Compound_Selector& rhs) const { return !(*this == rhs); }
1789
+
1790
+ SourcesSet& sources() { return sources_; }
1791
+ void clearSources() { sources_.clear(); }
1792
+ void mergeSources(SourcesSet& sources, Context& ctx);
1793
+
1794
+ Compound_Selector* clone(Context&) const; // does not clone the Simple_Selector*s
1795
+
1796
+ Compound_Selector* minus(Compound_Selector* rhs, Context& ctx);
1797
+ ATTACH_OPERATIONS();
1798
+ };
1799
+
1800
+ ////////////////////////////////////////////////////////////////////////////
1801
+ // General selectors -- i.e., simple sequences combined with one of the four
1802
+ // CSS selector combinators (">", "+", "~", and whitespace). Essentially a
1803
+ // linked list.
1804
+ ////////////////////////////////////////////////////////////////////////////
1805
+ struct Context;
1806
+ class Complex_Selector : public Selector {
1807
+ public:
1808
+ enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO };
1809
+ private:
1810
+ ADD_PROPERTY(Combinator, combinator);
1811
+ ADD_PROPERTY(Compound_Selector*, head);
1812
+ ADD_PROPERTY(Complex_Selector*, tail);
1813
+ public:
1814
+ Complex_Selector(string path, Position position,
1815
+ Combinator c,
1816
+ Compound_Selector* h,
1817
+ Complex_Selector* t)
1818
+ : Selector(path, position), combinator_(c), head_(h), tail_(t)
1819
+ {
1820
+ if ((h && h->has_reference()) || (t && t->has_reference())) has_reference(true);
1821
+ if ((h && h->has_placeholder()) || (t && t->has_placeholder())) has_placeholder(true);
1822
+ }
1823
+ Compound_Selector* base();
1824
+ Complex_Selector* context(Context&);
1825
+ Complex_Selector* innermost();
1826
+ size_t length();
1827
+ bool is_superselector_of(Compound_Selector*);
1828
+ bool is_superselector_of(Complex_Selector*);
1829
+ virtual Selector_Placeholder* find_placeholder();
1830
+ Combinator clear_innermost();
1831
+ void set_innermost(Complex_Selector*, Combinator);
1832
+ virtual int specificity() const
1833
+ {
1834
+ int sum = 0;
1835
+ if (head()) sum += head()->specificity();
1836
+ if (tail()) sum += tail()->specificity();
1837
+ return sum;
1838
+ }
1839
+ bool operator<(const Complex_Selector& rhs) const;
1840
+ bool operator==(const Complex_Selector& rhs) const;
1841
+ inline bool operator!=(const Complex_Selector& rhs) const { return !(*this == rhs); }
1842
+ SourcesSet sources()
1843
+ {
1844
+ //s = Set.new
1845
+ //seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)}
1846
+ //s
1847
+
1848
+ SourcesSet srcs;
1849
+
1850
+ Compound_Selector* pHead = head();
1851
+ Complex_Selector* pTail = tail();
1852
+
1853
+ if (pHead) {
1854
+ SourcesSet& headSources = pHead->sources();
1855
+ srcs.insert(headSources.begin(), headSources.end());
1856
+ }
1857
+
1858
+ if (pTail) {
1859
+ SourcesSet tailSources = pTail->sources();
1860
+ srcs.insert(tailSources.begin(), tailSources.end());
1861
+ }
1862
+
1863
+ return srcs;
1864
+ }
1865
+ void addSources(SourcesSet& sources, Context& ctx) {
1866
+ // members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m}
1867
+ Complex_Selector* pIter = this;
1868
+ while (pIter) {
1869
+ Compound_Selector* pHead = pIter->head();
1870
+
1871
+ if (pHead) {
1872
+ pHead->mergeSources(sources, ctx);
1873
+ }
1874
+
1875
+ pIter = pIter->tail();
1876
+ }
1877
+ }
1878
+ void clearSources() {
1879
+ Complex_Selector* pIter = this;
1880
+ while (pIter) {
1881
+ Compound_Selector* pHead = pIter->head();
1882
+
1883
+ if (pHead) {
1884
+ pHead->clearSources();
1885
+ }
1886
+
1887
+ pIter = pIter->tail();
1888
+ }
1889
+ }
1890
+ Complex_Selector* clone(Context&) const; // does not clone Compound_Selector*s
1891
+ Complex_Selector* cloneFully(Context&) const; // clones Compound_Selector*s
1892
+ vector<Compound_Selector*> to_vector();
1893
+ ATTACH_OPERATIONS();
1894
+ };
1895
+
1896
+ typedef deque<Complex_Selector*> ComplexSelectorDeque;
1897
+
1898
+ ///////////////////////////////////
1899
+ // Comma-separated selector groups.
1900
+ ///////////////////////////////////
1901
+ class Selector_List
1902
+ : public Selector, public Vectorized<Complex_Selector*> {
1903
+ #ifdef DEBUG
1904
+ ADD_PROPERTY(string, mCachedSelector);
1905
+ #endif
1906
+ protected:
1907
+ void adjust_after_pushing(Complex_Selector* c);
1908
+ public:
1909
+ Selector_List(string path, Position position, size_t s = 0)
1910
+ : Selector(path, position), Vectorized<Complex_Selector*>(s)
1911
+ { }
1912
+ virtual Selector_Placeholder* find_placeholder();
1913
+ virtual int specificity()
1914
+ {
1915
+ int sum = 0;
1916
+ for (size_t i = 0, L = length(); i < L; ++i)
1917
+ { sum += (*this)[i]->specificity(); }
1918
+ return sum;
1919
+ }
1920
+ // vector<Complex_Selector*> members() { return elements_; }
1921
+ ATTACH_OPERATIONS();
1922
+ };
1923
+
1924
+
1925
+ template<typename SelectorType>
1926
+ bool selectors_equal(const SelectorType& one, const SelectorType& two, bool simpleSelectorOrderDependent) {
1927
+ // Test for equality among selectors while differentiating between checks that demand the underlying Simple_Selector
1928
+ // ordering to be the same or not. This works because operator< (which doesn't make a whole lot of sense for selectors, but
1929
+ // is required for proper stl collection ordering) is implemented using string comparision. This gives stable sorting
1930
+ // behavior, and can be used to determine if the selectors would have exactly idential output. operator== matches the
1931
+ // ruby sass implementations for eql, which sometimes perform order independent comparisions (like set comparisons of the
1932
+ // members of a SimpleSequence (Compound_Selector)).
1933
+ //
1934
+ // Due to the reliance on operator== and operater< behavior, this templated method is currently only intended for
1935
+ // use with Compound_Selector and Complex_Selector objects.
1936
+ if (simpleSelectorOrderDependent) {
1937
+ return !(one < two) && !(two < one);
1938
+ } else {
1939
+ return one == two;
1940
+ }
1941
+ }
1942
+
1943
+ }
1944
+
1945
+ #ifdef __clang__
1946
+
1947
+ #pragma clang diagnostic pop
1948
+
1949
+ #endif