sassc 0.0.1
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 +7 -0
- data/.gitignore +15 -0
- data/.gitmodules +3 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +24 -0
- data/Rakefile +21 -0
- data/ext/libsass/.editorconfig +15 -0
- data/ext/libsass/.gitattributes +2 -0
- data/ext/libsass/.gitignore +61 -0
- data/ext/libsass/.travis.yml +38 -0
- data/ext/libsass/COPYING +25 -0
- data/ext/libsass/INSTALL +1 -0
- data/ext/libsass/LICENSE +25 -0
- data/ext/libsass/Makefile +223 -0
- data/ext/libsass/Makefile.am +145 -0
- data/ext/libsass/Readme.md +93 -0
- data/ext/libsass/appveyor.yml +76 -0
- data/ext/libsass/ast.cpp +581 -0
- data/ext/libsass/ast.hpp +1949 -0
- data/ext/libsass/ast_def_macros.hpp +16 -0
- data/ext/libsass/ast_factory.hpp +87 -0
- data/ext/libsass/ast_fwd_decl.hpp +72 -0
- data/ext/libsass/b64/cencode.h +32 -0
- data/ext/libsass/b64/encode.h +77 -0
- data/ext/libsass/backtrace.hpp +81 -0
- data/ext/libsass/base64vlq.cpp +43 -0
- data/ext/libsass/base64vlq.hpp +28 -0
- data/ext/libsass/bind.cpp +187 -0
- data/ext/libsass/bind.hpp +18 -0
- data/ext/libsass/cencode.c +102 -0
- data/ext/libsass/color_names.hpp +324 -0
- data/ext/libsass/configure.ac +130 -0
- data/ext/libsass/constants.cpp +144 -0
- data/ext/libsass/constants.hpp +145 -0
- data/ext/libsass/context.cpp +507 -0
- data/ext/libsass/context.hpp +150 -0
- data/ext/libsass/contextualize.cpp +157 -0
- data/ext/libsass/contextualize.hpp +65 -0
- data/ext/libsass/copy_c_str.cpp +13 -0
- data/ext/libsass/copy_c_str.hpp +5 -0
- data/ext/libsass/debug.hpp +39 -0
- data/ext/libsass/environment.hpp +75 -0
- data/ext/libsass/error_handling.cpp +28 -0
- data/ext/libsass/error_handling.hpp +28 -0
- data/ext/libsass/eval.cpp +1149 -0
- data/ext/libsass/eval.hpp +80 -0
- data/ext/libsass/expand.cpp +430 -0
- data/ext/libsass/expand.hpp +77 -0
- data/ext/libsass/extconf.rb +6 -0
- data/ext/libsass/extend.cpp +1962 -0
- data/ext/libsass/extend.hpp +50 -0
- data/ext/libsass/file.cpp +291 -0
- data/ext/libsass/file.hpp +18 -0
- data/ext/libsass/functions.cpp +1565 -0
- data/ext/libsass/functions.hpp +187 -0
- data/ext/libsass/inspect.cpp +727 -0
- data/ext/libsass/inspect.hpp +108 -0
- data/ext/libsass/json.cpp +1411 -0
- data/ext/libsass/json.hpp +117 -0
- data/ext/libsass/kwd_arg_macros.hpp +23 -0
- data/ext/libsass/m4/.gitkeep +0 -0
- data/ext/libsass/mapping.hpp +17 -0
- data/ext/libsass/memory_manager.hpp +54 -0
- data/ext/libsass/node.cpp +251 -0
- data/ext/libsass/node.hpp +122 -0
- data/ext/libsass/operation.hpp +153 -0
- data/ext/libsass/output_compressed.cpp +401 -0
- data/ext/libsass/output_compressed.hpp +95 -0
- data/ext/libsass/output_nested.cpp +364 -0
- data/ext/libsass/output_nested.hpp +108 -0
- data/ext/libsass/parser.cpp +2016 -0
- data/ext/libsass/parser.hpp +264 -0
- data/ext/libsass/paths.hpp +69 -0
- data/ext/libsass/position.hpp +22 -0
- data/ext/libsass/posix/getopt.c +562 -0
- data/ext/libsass/posix/getopt.h +95 -0
- data/ext/libsass/prelexer.cpp +688 -0
- data/ext/libsass/prelexer.hpp +513 -0
- data/ext/libsass/remove_placeholders.cpp +59 -0
- data/ext/libsass/remove_placeholders.hpp +43 -0
- data/ext/libsass/res/resource.rc +35 -0
- data/ext/libsass/sass.cpp +33 -0
- data/ext/libsass/sass.h +60 -0
- data/ext/libsass/sass2scss.cpp +834 -0
- data/ext/libsass/sass2scss.h +110 -0
- data/ext/libsass/sass_context.cpp +709 -0
- data/ext/libsass/sass_context.h +120 -0
- data/ext/libsass/sass_functions.cpp +137 -0
- data/ext/libsass/sass_functions.h +90 -0
- data/ext/libsass/sass_interface.cpp +277 -0
- data/ext/libsass/sass_interface.h +97 -0
- data/ext/libsass/sass_util.cpp +136 -0
- data/ext/libsass/sass_util.hpp +259 -0
- data/ext/libsass/sass_values.cpp +337 -0
- data/ext/libsass/sass_values.h +124 -0
- data/ext/libsass/script/bootstrap +10 -0
- data/ext/libsass/script/branding +10 -0
- data/ext/libsass/script/ci-build-libsass +72 -0
- data/ext/libsass/script/ci-install-compiler +4 -0
- data/ext/libsass/script/ci-install-deps +19 -0
- data/ext/libsass/script/ci-report-coverage +25 -0
- data/ext/libsass/script/coveralls-debug +32 -0
- data/ext/libsass/script/spec +5 -0
- data/ext/libsass/script/tap-driver +652 -0
- data/ext/libsass/script/tap-runner +1 -0
- data/ext/libsass/source_map.cpp +133 -0
- data/ext/libsass/source_map.hpp +46 -0
- data/ext/libsass/subset_map.hpp +145 -0
- data/ext/libsass/support/libsass.pc.in +11 -0
- data/ext/libsass/test-driver +127 -0
- data/ext/libsass/test/test_node.cpp +98 -0
- data/ext/libsass/test/test_paths.cpp +29 -0
- data/ext/libsass/test/test_selector_difference.cpp +28 -0
- data/ext/libsass/test/test_specificity.cpp +28 -0
- data/ext/libsass/test/test_subset_map.cpp +472 -0
- data/ext/libsass/test/test_superselector.cpp +71 -0
- data/ext/libsass/test/test_unification.cpp +33 -0
- data/ext/libsass/to_c.cpp +61 -0
- data/ext/libsass/to_c.hpp +44 -0
- data/ext/libsass/to_string.cpp +29 -0
- data/ext/libsass/to_string.hpp +32 -0
- data/ext/libsass/token.hpp +32 -0
- data/ext/libsass/units.cpp +54 -0
- data/ext/libsass/units.hpp +10 -0
- data/ext/libsass/utf8.h +34 -0
- data/ext/libsass/utf8/checked.h +327 -0
- data/ext/libsass/utf8/core.h +329 -0
- data/ext/libsass/utf8/unchecked.h +228 -0
- data/ext/libsass/utf8_string.cpp +102 -0
- data/ext/libsass/utf8_string.hpp +36 -0
- data/ext/libsass/util.cpp +189 -0
- data/ext/libsass/util.hpp +26 -0
- data/ext/libsass/win/libsass.filters +291 -0
- data/ext/libsass/win/libsass.sln +28 -0
- data/ext/libsass/win/libsass.vcxproj +255 -0
- data/lib/sassc.rb +6 -0
- data/lib/sassc/engine.rb +13 -0
- data/lib/sassc/native.rb +44 -0
- data/lib/sassc/native/native_context_api.rb +140 -0
- data/lib/sassc/native/native_functions_api.rb +41 -0
- data/lib/sassc/native/sass_input_style.rb +11 -0
- data/lib/sassc/native/sass_output_style.rb +10 -0
- data/lib/sassc/native/sass_value.rb +95 -0
- data/lib/sassc/native/string_list.rb +8 -0
- data/lib/sassc/version.rb +3 -0
- data/sassc.gemspec +43 -0
- data/test/smoke_test.rb +171 -0
- data/test/test_helper.rb +4 -0
- metadata +281 -0
data/ext/libsass/ast.hpp
ADDED
|
@@ -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
|