1// sass.hpp must go before all system headers to get the
2// __EXTENSIONS__ fix on Solaris.
3#include "sass.hpp"
4#include "ast.hpp"
5
6namespace Sass {
7
8 void str_rtrim(sass::string& str, const sass::string& delimiters = " \f\n\r\t\v")
9 {
10 str.erase( pos: str.find_last_not_of( str: delimiters ) + 1 );
11 }
12
13 /////////////////////////////////////////////////////////////////////////
14 /////////////////////////////////////////////////////////////////////////
15
16 PreValue::PreValue(SourceSpan pstate, bool d, bool e, bool i, Type ct)
17 : Expression(pstate, d, e, i, ct)
18 { }
19 PreValue::PreValue(const PreValue* ptr)
20 : Expression(ptr)
21 { }
22
23 /////////////////////////////////////////////////////////////////////////
24 /////////////////////////////////////////////////////////////////////////
25
26 Value::Value(SourceSpan pstate, bool d, bool e, bool i, Type ct)
27 : PreValue(pstate, d, e, i, ct)
28 { }
29 Value::Value(const Value* ptr)
30 : PreValue(ptr)
31 { }
32
33 /////////////////////////////////////////////////////////////////////////
34 /////////////////////////////////////////////////////////////////////////
35
36 List::List(SourceSpan pstate, size_t size, enum Sass_Separator sep, bool argl, bool bracket)
37 : Value(pstate),
38 Vectorized<ExpressionObj>(size),
39 separator_(sep),
40 is_arglist_(argl),
41 is_bracketed_(bracket),
42 from_selector_(false)
43 { concrete_type(concrete_type__: LIST); }
44
45 List::List(const List* ptr)
46 : Value(ptr),
47 Vectorized<ExpressionObj>(*ptr),
48 separator_(ptr->separator_),
49 is_arglist_(ptr->is_arglist_),
50 is_bracketed_(ptr->is_bracketed_),
51 from_selector_(ptr->from_selector_)
52 { concrete_type(concrete_type__: LIST); }
53
54 size_t List::hash() const
55 {
56 if (hash_ == 0) {
57 hash_ = std::hash<sass::string>()(sep_string());
58 hash_combine(seed&: hash_, val: std::hash<bool>()(is_bracketed()));
59 for (size_t i = 0, L = length(); i < L; ++i)
60 hash_combine(seed&: hash_, val: (elements()[i])->hash());
61 }
62 return hash_;
63 }
64
65 void List::set_delayed(bool delayed)
66 {
67 is_delayed(is_delayed__: delayed);
68 // don't set children
69 }
70
71 bool List::operator< (const Expression& rhs) const
72 {
73 if (auto r = Cast<List>(ptr: &rhs)) {
74 if (length() < r->length()) return true;
75 if (length() > r->length()) return false;
76 const auto& left = elements();
77 const auto& right = r->elements();
78 for (size_t i = 0; i < left.size(); i += 1) {
79 if (*left[i] < *right[i]) return true;
80 if (*left[i] == *right[i]) continue;
81 return false;
82 }
83 return false;
84 }
85 // compare/sort by type
86 return type() < rhs.type();
87 }
88
89 bool List::operator== (const Expression& rhs) const
90 {
91 if (auto r = Cast<List>(ptr: &rhs)) {
92 if (length() != r->length()) return false;
93 if (separator() != r->separator()) return false;
94 if (is_bracketed() != r->is_bracketed()) return false;
95 for (size_t i = 0, L = length(); i < L; ++i) {
96 auto rv = r->at(i);
97 auto lv = this->at(i);
98 if (!lv && rv) return false;
99 else if (!rv && lv) return false;
100 else if (*lv != *rv) return false;
101 }
102 return true;
103 }
104 return false;
105 }
106
107 size_t List::size() const {
108 if (!is_arglist_) return length();
109 // arglist expects a list of arguments
110 // so we need to break before keywords
111 for (size_t i = 0, L = length(); i < L; ++i) {
112 ExpressionObj obj = this->at(i);
113 if (Argument* arg = Cast<Argument>(ptr: obj)) {
114 if (!arg->name().empty()) return i;
115 }
116 }
117 return length();
118 }
119
120
121 ExpressionObj List::value_at_index(size_t i) {
122 ExpressionObj obj = this->at(i);
123 if (is_arglist_) {
124 if (Argument* arg = Cast<Argument>(ptr: obj)) {
125 return arg->value();
126 } else {
127 return obj;
128 }
129 } else {
130 return obj;
131 }
132 }
133
134 /////////////////////////////////////////////////////////////////////////
135 /////////////////////////////////////////////////////////////////////////
136
137 Map::Map(SourceSpan pstate, size_t size)
138 : Value(pstate),
139 Hashed(size)
140 { concrete_type(concrete_type__: MAP); }
141
142 Map::Map(const Map* ptr)
143 : Value(ptr),
144 Hashed(*ptr)
145 { concrete_type(concrete_type__: MAP); }
146
147 bool Map::operator< (const Expression& rhs) const
148 {
149 if (auto r = Cast<Map>(ptr: &rhs)) {
150 if (length() < r->length()) return true;
151 if (length() > r->length()) return false;
152 const auto& lkeys = keys();
153 const auto& rkeys = r->keys();
154 for (size_t i = 0; i < lkeys.size(); i += 1) {
155 if (*lkeys[i] < *rkeys[i]) return true;
156 if (*lkeys[i] == *rkeys[i]) continue;
157 return false;
158 }
159 const auto& lvals = values();
160 const auto& rvals = r->values();
161 for (size_t i = 0; i < lvals.size(); i += 1) {
162 if (*lvals[i] < *rvals[i]) return true;
163 if (*lvals[i] == *rvals[i]) continue;
164 return false;
165 }
166 return false;
167 }
168 // compare/sort by type
169 return type() < rhs.type();
170 }
171
172 bool Map::operator== (const Expression& rhs) const
173 {
174 if (auto r = Cast<Map>(ptr: &rhs)) {
175 if (length() != r->length()) return false;
176 for (auto key : keys()) {
177 auto rv = r->at(k: key);
178 auto lv = this->at(k: key);
179 if (!lv && rv) return false;
180 else if (!rv && lv) return false;
181 else if (*lv != *rv) return false;
182 }
183 return true;
184 }
185 return false;
186 }
187
188 List_Obj Map::to_list(SourceSpan& pstate) {
189 List_Obj ret = SASS_MEMORY_NEW(List, pstate, length(), SASS_COMMA);
190
191 for (auto key : keys()) {
192 List_Obj l = SASS_MEMORY_NEW(List, pstate, 2);
193 l->append(element: key);
194 l->append(element: at(k: key));
195 ret->append(element: l);
196 }
197
198 return ret;
199 }
200
201 size_t Map::hash() const
202 {
203 if (hash_ == 0) {
204 for (auto key : keys()) {
205 hash_combine(seed&: hash_, val: key->hash());
206 hash_combine(seed&: hash_, val: at(k: key)->hash());
207 }
208 }
209
210 return hash_;
211 }
212
213 /////////////////////////////////////////////////////////////////////////
214 /////////////////////////////////////////////////////////////////////////
215
216 Binary_Expression::Binary_Expression(SourceSpan pstate,
217 Operand op, ExpressionObj lhs, ExpressionObj rhs)
218 : PreValue(pstate), op_(op), left_(lhs), right_(rhs), hash_(0)
219 { }
220
221 Binary_Expression::Binary_Expression(const Binary_Expression* ptr)
222 : PreValue(ptr),
223 op_(ptr->op_),
224 left_(ptr->left_),
225 right_(ptr->right_),
226 hash_(ptr->hash_)
227 { }
228
229 bool Binary_Expression::is_left_interpolant(void) const
230 {
231 return is_interpolant() || (left() && left()->is_left_interpolant());
232 }
233 bool Binary_Expression::is_right_interpolant(void) const
234 {
235 return is_interpolant() || (right() && right()->is_right_interpolant());
236 }
237
238 const sass::string Binary_Expression::type_name()
239 {
240 return sass_op_to_name(op: optype());
241 }
242
243 const sass::string Binary_Expression::separator()
244 {
245 return sass_op_separator(op: optype());
246 }
247
248 bool Binary_Expression::has_interpolant() const
249 {
250 return is_left_interpolant() ||
251 is_right_interpolant();
252 }
253
254 void Binary_Expression::set_delayed(bool delayed)
255 {
256 right()->set_delayed(delayed);
257 left()->set_delayed(delayed);
258 is_delayed(is_delayed__: delayed);
259 }
260
261 bool Binary_Expression::operator<(const Expression& rhs) const
262 {
263 if (auto m = Cast<Binary_Expression>(ptr: &rhs)) {
264 return type() < m->type() ||
265 *left() < *m->left() ||
266 *right() < *m->right();
267 }
268 // compare/sort by type
269 return type() < rhs.type();
270 }
271
272 bool Binary_Expression::operator==(const Expression& rhs) const
273 {
274 if (auto m = Cast<Binary_Expression>(ptr: &rhs)) {
275 return type() == m->type() &&
276 *left() == *m->left() &&
277 *right() == *m->right();
278 }
279 return false;
280 }
281
282 size_t Binary_Expression::hash() const
283 {
284 if (hash_ == 0) {
285 hash_ = std::hash<size_t>()(optype());
286 hash_combine(seed&: hash_, val: left()->hash());
287 hash_combine(seed&: hash_, val: right()->hash());
288 }
289 return hash_;
290 }
291
292 /////////////////////////////////////////////////////////////////////////
293 /////////////////////////////////////////////////////////////////////////
294
295 Function::Function(SourceSpan pstate, Definition_Obj def, bool css)
296 : Value(pstate), definition_(def), is_css_(css)
297 { concrete_type(concrete_type__: FUNCTION_VAL); }
298
299 Function::Function(const Function* ptr)
300 : Value(ptr), definition_(ptr->definition_), is_css_(ptr->is_css_)
301 { concrete_type(concrete_type__: FUNCTION_VAL); }
302
303 bool Function::operator< (const Expression& rhs) const
304 {
305 if (auto r = Cast<Function>(ptr: &rhs)) {
306 auto d1 = Cast<Definition>(ptr: definition());
307 auto d2 = Cast<Definition>(ptr: r->definition());
308 if (d1 == nullptr) return d2 != nullptr;
309 else if (d2 == nullptr) return false;
310 if (is_css() == r->is_css()) {
311 return d1 < d2;
312 }
313 return r->is_css();
314 }
315 // compare/sort by type
316 return type() < rhs.type();
317 }
318
319 bool Function::operator== (const Expression& rhs) const
320 {
321 if (auto r = Cast<Function>(ptr: &rhs)) {
322 auto d1 = Cast<Definition>(ptr: definition());
323 auto d2 = Cast<Definition>(ptr: r->definition());
324 return d1 && d2 && d1 == d2 && is_css() == r->is_css();
325 }
326 return false;
327 }
328
329 sass::string Function::name() {
330 if (definition_) {
331 return definition_->name();
332 }
333 return "";
334 }
335
336 /////////////////////////////////////////////////////////////////////////
337 /////////////////////////////////////////////////////////////////////////
338
339 Function_Call::Function_Call(SourceSpan pstate, String_Obj n, Arguments_Obj args, void* cookie)
340 : PreValue(pstate), sname_(n), arguments_(args), func_(), via_call_(false), cookie_(cookie), hash_(0)
341 { concrete_type(concrete_type__: FUNCTION); }
342 Function_Call::Function_Call(SourceSpan pstate, String_Obj n, Arguments_Obj args, Function_Obj func)
343 : PreValue(pstate), sname_(n), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0)
344 { concrete_type(concrete_type__: FUNCTION); }
345 Function_Call::Function_Call(SourceSpan pstate, String_Obj n, Arguments_Obj args)
346 : PreValue(pstate), sname_(n), arguments_(args), via_call_(false), cookie_(0), hash_(0)
347 { concrete_type(concrete_type__: FUNCTION); }
348
349 Function_Call::Function_Call(SourceSpan pstate, sass::string n, Arguments_Obj args, void* cookie)
350 : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), func_(), via_call_(false), cookie_(cookie), hash_(0)
351 { concrete_type(concrete_type__: FUNCTION); }
352 Function_Call::Function_Call(SourceSpan pstate, sass::string n, Arguments_Obj args, Function_Obj func)
353 : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0)
354 { concrete_type(concrete_type__: FUNCTION); }
355 Function_Call::Function_Call(SourceSpan pstate, sass::string n, Arguments_Obj args)
356 : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), via_call_(false), cookie_(0), hash_(0)
357 { concrete_type(concrete_type__: FUNCTION); }
358
359 Function_Call::Function_Call(const Function_Call* ptr)
360 : PreValue(ptr),
361 sname_(ptr->sname_),
362 arguments_(ptr->arguments_),
363 func_(ptr->func_),
364 via_call_(ptr->via_call_),
365 cookie_(ptr->cookie_),
366 hash_(ptr->hash_)
367 { concrete_type(concrete_type__: FUNCTION); }
368
369 bool Function_Call::operator==(const Expression& rhs) const
370 {
371 if (auto m = Cast<Function_Call>(ptr: &rhs)) {
372 if (*sname() != *m->sname()) return false;
373 if (arguments()->length() != m->arguments()->length()) return false;
374 for (size_t i = 0, L = arguments()->length(); i < L; ++i)
375 if (*arguments()->get(i) != *m->arguments()->get(i)) return false;
376 return true;
377 }
378 return false;
379 }
380
381 size_t Function_Call::hash() const
382 {
383 if (hash_ == 0) {
384 hash_ = std::hash<sass::string>()(name());
385 for (auto argument : arguments()->elements())
386 hash_combine(seed&: hash_, val: argument->hash());
387 }
388 return hash_;
389 }
390
391 sass::string Function_Call::name() const
392 {
393 return sname();
394 }
395
396 bool Function_Call::is_css() {
397 if (func_) return func_->is_css();
398 return false;
399 }
400
401 /////////////////////////////////////////////////////////////////////////
402 /////////////////////////////////////////////////////////////////////////
403
404 Variable::Variable(SourceSpan pstate, sass::string n)
405 : PreValue(pstate), name_(n)
406 { concrete_type(concrete_type__: VARIABLE); }
407
408 Variable::Variable(const Variable* ptr)
409 : PreValue(ptr), name_(ptr->name_)
410 { concrete_type(concrete_type__: VARIABLE); }
411
412 bool Variable::operator==(const Expression& rhs) const
413 {
414 if (auto e = Cast<Variable>(ptr: &rhs)) {
415 return name() == e->name();
416 }
417 return false;
418 }
419
420 size_t Variable::hash() const
421 {
422 return std::hash<sass::string>()(name());
423 }
424
425 /////////////////////////////////////////////////////////////////////////
426 /////////////////////////////////////////////////////////////////////////
427
428 Number::Number(SourceSpan pstate, double val, sass::string u, bool zero)
429 : Value(pstate),
430 Units(),
431 value_(val),
432 zero_(zero),
433 hash_(0)
434 {
435 size_t l = 0;
436 size_t r;
437 if (!u.empty()) {
438 bool nominator = true;
439 while (true) {
440 r = u.find_first_of(s: "*/", pos: l);
441 sass::string unit(u.substr(pos: l, n: r == sass::string::npos ? r : r - l));
442 if (!unit.empty()) {
443 if (nominator) numerators.push_back(x: unit);
444 else denominators.push_back(x: unit);
445 }
446 if (r == sass::string::npos) break;
447 // ToDo: should error for multiple slashes
448 // if (!nominator && u[r] == '/') error(...)
449 if (u[r] == '/')
450 nominator = false;
451 // strange math parsing?
452 // else if (u[r] == '*')
453 // nominator = true;
454 l = r + 1;
455 }
456 }
457 concrete_type(concrete_type__: NUMBER);
458 }
459
460 Number::Number(const Number* ptr)
461 : Value(ptr),
462 Units(ptr),
463 value_(ptr->value_), zero_(ptr->zero_),
464 hash_(ptr->hash_)
465 { concrete_type(concrete_type__: NUMBER); }
466
467 // cancel out unnecessary units
468 void Number::reduce()
469 {
470 // apply conversion factor
471 value_ *= this->Units::reduce();
472 }
473
474 void Number::normalize()
475 {
476 // apply conversion factor
477 value_ *= this->Units::normalize();
478 }
479
480 size_t Number::hash() const
481 {
482 if (hash_ == 0) {
483 hash_ = std::hash<double>()(value_);
484 for (const auto numerator : numerators)
485 hash_combine(seed&: hash_, val: std::hash<sass::string>()(numerator));
486 for (const auto denominator : denominators)
487 hash_combine(seed&: hash_, val: std::hash<sass::string>()(denominator));
488 }
489 return hash_;
490 }
491
492 bool Number::operator< (const Expression& rhs) const
493 {
494 if (auto n = Cast<Number>(ptr: &rhs)) {
495 return *this < *n;
496 }
497 return false;
498 }
499
500 bool Number::operator== (const Expression& rhs) const
501 {
502 if (auto n = Cast<Number>(ptr: &rhs)) {
503 return *this == *n;
504 }
505 return false;
506 }
507
508 bool Number::operator== (const Number& rhs) const
509 {
510 // unitless or only having one unit are equivalent (3.4)
511 // therefore we need to reduce the units beforehand
512 Number l(*this), r(rhs); l.reduce(); r.reduce();
513 size_t lhs_units = l.numerators.size() + l.denominators.size();
514 size_t rhs_units = r.numerators.size() + r.denominators.size();
515 if (!lhs_units || !rhs_units) {
516 return NEAR_EQUAL(l.value(), r.value());
517 }
518 // ensure both have same units
519 l.normalize(); r.normalize();
520 Units &lhs_unit = l, &rhs_unit = r;
521 return lhs_unit == rhs_unit &&
522 NEAR_EQUAL(l.value(), r.value());
523 }
524
525 bool Number::operator< (const Number& rhs) const
526 {
527 // unitless or only having one unit are equivalent (3.4)
528 // therefore we need to reduce the units beforehand
529 Number l(*this), r(rhs); l.reduce(); r.reduce();
530 size_t lhs_units = l.numerators.size() + l.denominators.size();
531 size_t rhs_units = r.numerators.size() + r.denominators.size();
532 if (!lhs_units || !rhs_units) {
533 return l.value() < r.value();
534 }
535 // ensure both have same units
536 l.normalize(); r.normalize();
537 Units &lhs_unit = l, &rhs_unit = r;
538 if (!(lhs_unit == rhs_unit)) {
539 /* ToDo: do we always get useful backtraces? */
540 throw Exception::IncompatibleUnits(rhs, *this);
541 }
542 if (lhs_unit == rhs_unit) {
543 return l.value() < r.value();
544 } else {
545 return lhs_unit < rhs_unit;
546 }
547 }
548
549 /////////////////////////////////////////////////////////////////////////
550 /////////////////////////////////////////////////////////////////////////
551
552 Color::Color(SourceSpan pstate, double a, const sass::string disp)
553 : Value(pstate),
554 disp_(disp), a_(a),
555 hash_(0)
556 { concrete_type(concrete_type__: COLOR); }
557
558 Color::Color(const Color* ptr)
559 : Value(ptr->pstate()),
560 // reset on copy
561 disp_(""),
562 a_(ptr->a_),
563 hash_(ptr->hash_)
564 { concrete_type(concrete_type__: COLOR); }
565
566 bool Color::operator< (const Expression& rhs) const
567 {
568 if (auto r = Cast<Color_RGBA>(ptr: &rhs)) {
569 return *this < *r;
570 }
571 else if (auto r = Cast<Color_HSLA>(ptr: &rhs)) {
572 return *this < *r;
573 }
574 else if (auto r = Cast<Color>(ptr: &rhs)) {
575 return a_ < r->a();
576 }
577 // compare/sort by type
578 return type() < rhs.type();
579 }
580
581 bool Color::operator== (const Expression& rhs) const
582 {
583 if (auto r = Cast<Color_RGBA>(ptr: &rhs)) {
584 return *this == *r;
585 }
586 else if (auto r = Cast<Color_HSLA>(ptr: &rhs)) {
587 return *this == *r;
588 }
589 else if (auto r = Cast<Color>(ptr: &rhs)) {
590 return a_ == r->a();
591 }
592 return false;
593 }
594
595 /////////////////////////////////////////////////////////////////////////
596 /////////////////////////////////////////////////////////////////////////
597
598 Color_RGBA::Color_RGBA(SourceSpan pstate, double r, double g, double b, double a, const sass::string disp)
599 : Color(pstate, a, disp),
600 r_(r), g_(g), b_(b)
601 { concrete_type(concrete_type__: COLOR); }
602
603 Color_RGBA::Color_RGBA(const Color_RGBA* ptr)
604 : Color(ptr),
605 r_(ptr->r_),
606 g_(ptr->g_),
607 b_(ptr->b_)
608 { concrete_type(concrete_type__: COLOR); }
609
610 bool Color_RGBA::operator< (const Expression& rhs) const
611 {
612 if (auto r = Cast<Color_RGBA>(ptr: &rhs)) {
613 if (r_ < r->r()) return true;
614 if (r_ > r->r()) return false;
615 if (g_ < r->g()) return true;
616 if (g_ > r->g()) return false;
617 if (b_ < r->b()) return true;
618 if (b_ > r->b()) return false;
619 if (a_ < r->a()) return true;
620 if (a_ > r->a()) return false;
621 return false; // is equal
622 }
623 // compare/sort by type
624 return type() < rhs.type();
625 }
626
627 bool Color_RGBA::operator== (const Expression& rhs) const
628 {
629 if (auto r = Cast<Color_RGBA>(ptr: &rhs)) {
630 return r_ == r->r() &&
631 g_ == r->g() &&
632 b_ == r->b() &&
633 a_ == r->a();
634 }
635 return false;
636 }
637
638 size_t Color_RGBA::hash() const
639 {
640 if (hash_ == 0) {
641 hash_ = std::hash<sass::string>()("RGBA");
642 hash_combine(seed&: hash_, val: std::hash<double>()(a_));
643 hash_combine(seed&: hash_, val: std::hash<double>()(r_));
644 hash_combine(seed&: hash_, val: std::hash<double>()(g_));
645 hash_combine(seed&: hash_, val: std::hash<double>()(b_));
646 }
647 return hash_;
648 }
649
650 Color_HSLA* Color_RGBA::copyAsHSLA() const
651 {
652
653 // Algorithm from http://en.wikipedia.org/wiki/wHSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
654 double r = r_ / 255.0;
655 double g = g_ / 255.0;
656 double b = b_ / 255.0;
657
658 double max = std::max(a: r, b: std::max(a: g, b: b));
659 double min = std::min(a: r, b: std::min(a: g, b: b));
660 double delta = max - min;
661
662 double h = 0;
663 double s;
664 double l = (max + min) / 2.0;
665
666 if (NEAR_EQUAL(max, min)) {
667 h = s = 0; // achromatic
668 }
669 else {
670 if (l < 0.5) s = delta / (max + min);
671 else s = delta / (2.0 - max - min);
672
673 if (r == max) h = (g - b) / delta + (g < b ? 6 : 0);
674 else if (g == max) h = (b - r) / delta + 2;
675 else if (b == max) h = (r - g) / delta + 4;
676 }
677
678 // HSL hsl_struct;
679 h = h * 60;
680 s = s * 100;
681 l = l * 100;
682
683 return SASS_MEMORY_NEW(Color_HSLA,
684 pstate(), h, s, l, a(), ""
685 );
686 }
687
688 Color_RGBA* Color_RGBA::copyAsRGBA() const
689 {
690 return SASS_MEMORY_COPY(this);
691 }
692
693 /////////////////////////////////////////////////////////////////////////
694 /////////////////////////////////////////////////////////////////////////
695
696 Color_HSLA::Color_HSLA(SourceSpan pstate, double h, double s, double l, double a, const sass::string disp)
697 : Color(pstate, a, disp),
698 h_(absmod(n: h, r: 360.0)),
699 s_(clip(n: s, lower: 0.0, upper: 100.0)),
700 l_(clip(n: l, lower: 0.0, upper: 100.0))
701 // hash_(0)
702 { concrete_type(concrete_type__: COLOR); }
703
704 Color_HSLA::Color_HSLA(const Color_HSLA* ptr)
705 : Color(ptr),
706 h_(ptr->h_),
707 s_(ptr->s_),
708 l_(ptr->l_)
709 // hash_(ptr->hash_)
710 { concrete_type(concrete_type__: COLOR); }
711
712 bool Color_HSLA::operator< (const Expression& rhs) const
713 {
714 if (auto r = Cast<Color_HSLA>(ptr: &rhs)) {
715 if (h_ < r->h()) return true;
716 if (h_ > r->h()) return false;
717 if (s_ < r->s()) return true;
718 if (s_ > r->s()) return false;
719 if (l_ < r->l()) return true;
720 if (l_ > r->l()) return false;
721 if (a_ < r->a()) return true;
722 if (a_ > r->a()) return false;
723 return false; // is equal
724 }
725 // compare/sort by type
726 return type() < rhs.type();
727 }
728
729 bool Color_HSLA::operator== (const Expression& rhs) const
730 {
731 if (auto r = Cast<Color_HSLA>(ptr: &rhs)) {
732 return h_ == r->h() &&
733 s_ == r->s() &&
734 l_ == r->l() &&
735 a_ == r->a();
736 }
737 return false;
738 }
739
740 size_t Color_HSLA::hash() const
741 {
742 if (hash_ == 0) {
743 hash_ = std::hash<sass::string>()("HSLA");
744 hash_combine(seed&: hash_, val: std::hash<double>()(a_));
745 hash_combine(seed&: hash_, val: std::hash<double>()(h_));
746 hash_combine(seed&: hash_, val: std::hash<double>()(s_));
747 hash_combine(seed&: hash_, val: std::hash<double>()(l_));
748 }
749 return hash_;
750 }
751
752 // hue to RGB helper function
753 double h_to_rgb(double m1, double m2, double h)
754 {
755 h = absmod(n: h, r: 1.0);
756 if (h*6.0 < 1) return m1 + (m2 - m1)*h*6;
757 if (h*2.0 < 1) return m2;
758 if (h*3.0 < 2) return m1 + (m2 - m1) * (2.0/3.0 - h)*6;
759 return m1;
760 }
761
762 Color_RGBA* Color_HSLA::copyAsRGBA() const
763 {
764
765 double h = absmod(n: h_ / 360.0, r: 1.0);
766 double s = clip(n: s_ / 100.0, lower: 0.0, upper: 1.0);
767 double l = clip(n: l_ / 100.0, lower: 0.0, upper: 1.0);
768
769 // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
770 double m2;
771 if (l <= 0.5) m2 = l*(s+1.0);
772 else m2 = (l+s)-(l*s);
773 double m1 = (l*2.0)-m2;
774 // round the results -- consider moving this into the Color constructor
775 double r = (h_to_rgb(m1, m2, h: h + 1.0/3.0) * 255.0);
776 double g = (h_to_rgb(m1, m2, h) * 255.0);
777 double b = (h_to_rgb(m1, m2, h: h - 1.0/3.0) * 255.0);
778
779 return SASS_MEMORY_NEW(Color_RGBA,
780 pstate(), r, g, b, a(), ""
781 );
782 }
783
784 Color_HSLA* Color_HSLA::copyAsHSLA() const
785 {
786 return SASS_MEMORY_COPY(this);
787 }
788
789 /////////////////////////////////////////////////////////////////////////
790 /////////////////////////////////////////////////////////////////////////
791
792 Custom_Error::Custom_Error(SourceSpan pstate, sass::string msg)
793 : Value(pstate), message_(msg)
794 { concrete_type(concrete_type__: C_ERROR); }
795
796 Custom_Error::Custom_Error(const Custom_Error* ptr)
797 : Value(ptr), message_(ptr->message_)
798 { concrete_type(concrete_type__: C_ERROR); }
799
800 bool Custom_Error::operator< (const Expression& rhs) const
801 {
802 if (auto r = Cast<Custom_Error>(ptr: &rhs)) {
803 return message() < r->message();
804 }
805 // compare/sort by type
806 return type() < rhs.type();
807 }
808
809 bool Custom_Error::operator== (const Expression& rhs) const
810 {
811 if (auto r = Cast<Custom_Error>(ptr: &rhs)) {
812 return message() == r->message();
813 }
814 return false;
815 }
816
817 /////////////////////////////////////////////////////////////////////////
818 /////////////////////////////////////////////////////////////////////////
819
820 Custom_Warning::Custom_Warning(SourceSpan pstate, sass::string msg)
821 : Value(pstate), message_(msg)
822 { concrete_type(concrete_type__: C_WARNING); }
823
824 Custom_Warning::Custom_Warning(const Custom_Warning* ptr)
825 : Value(ptr), message_(ptr->message_)
826 { concrete_type(concrete_type__: C_WARNING); }
827
828 bool Custom_Warning::operator< (const Expression& rhs) const
829 {
830 if (auto r = Cast<Custom_Warning>(ptr: &rhs)) {
831 return message() < r->message();
832 }
833 // compare/sort by type
834 return type() < rhs.type();
835 }
836
837 bool Custom_Warning::operator== (const Expression& rhs) const
838 {
839 if (auto r = Cast<Custom_Warning>(ptr: &rhs)) {
840 return message() == r->message();
841 }
842 return false;
843 }
844
845 /////////////////////////////////////////////////////////////////////////
846 /////////////////////////////////////////////////////////////////////////
847
848 Boolean::Boolean(SourceSpan pstate, bool val)
849 : Value(pstate), value_(val),
850 hash_(0)
851 { concrete_type(concrete_type__: BOOLEAN); }
852
853 Boolean::Boolean(const Boolean* ptr)
854 : Value(ptr),
855 value_(ptr->value_),
856 hash_(ptr->hash_)
857 { concrete_type(concrete_type__: BOOLEAN); }
858
859 bool Boolean::operator< (const Expression& rhs) const
860 {
861 if (auto r = Cast<Boolean>(ptr: &rhs)) {
862 return (value() < r->value());
863 }
864 return false;
865 }
866
867 bool Boolean::operator== (const Expression& rhs) const
868 {
869 if (auto r = Cast<Boolean>(ptr: &rhs)) {
870 return (value() == r->value());
871 }
872 return false;
873 }
874
875 size_t Boolean::hash() const
876 {
877 if (hash_ == 0) {
878 hash_ = std::hash<bool>()(value_);
879 }
880 return hash_;
881 }
882
883 /////////////////////////////////////////////////////////////////////////
884 /////////////////////////////////////////////////////////////////////////
885
886 String::String(SourceSpan pstate, bool delayed)
887 : Value(pstate, delayed)
888 { concrete_type(concrete_type__: STRING); }
889 String::String(const String* ptr)
890 : Value(ptr)
891 { concrete_type(concrete_type__: STRING); }
892
893 /////////////////////////////////////////////////////////////////////////
894 /////////////////////////////////////////////////////////////////////////
895
896 String_Schema::String_Schema(SourceSpan pstate, size_t size, bool css)
897 : String(pstate), Vectorized<PreValueObj>(size), css_(css), hash_(0)
898 { concrete_type(concrete_type__: STRING); }
899
900 String_Schema::String_Schema(const String_Schema* ptr)
901 : String(ptr),
902 Vectorized<PreValueObj>(*ptr),
903 css_(ptr->css_),
904 hash_(ptr->hash_)
905 { concrete_type(concrete_type__: STRING); }
906
907 void String_Schema::rtrim()
908 {
909 if (!empty()) {
910 if (String* str = Cast<String>(ptr: last())) str->rtrim();
911 }
912 }
913
914 bool String_Schema::is_left_interpolant(void) const
915 {
916 return length() && first()->is_left_interpolant();
917 }
918 bool String_Schema::is_right_interpolant(void) const
919 {
920 return length() && last()->is_right_interpolant();
921 }
922
923 bool String_Schema::operator< (const Expression& rhs) const
924 {
925 if (auto r = Cast<String_Schema>(ptr: &rhs)) {
926 if (length() < r->length()) return true;
927 if (length() > r->length()) return false;
928 for (size_t i = 0, L = length(); i < L; ++i) {
929 if (*get(i) < *r->get(i)) return true;
930 if (*get(i) == *r->get(i)) continue;
931 return false;
932 }
933 // Is equal
934 return false;
935 }
936 // compare/sort by type
937 return type() < rhs.type();
938 }
939
940 bool String_Schema::operator== (const Expression& rhs) const
941 {
942 if (auto r = Cast<String_Schema>(ptr: &rhs)) {
943 if (length() != r->length()) return false;
944 for (size_t i = 0, L = length(); i < L; ++i) {
945 auto rv = (*r)[i];
946 auto lv = (*this)[i];
947 if (*lv != *rv) return false;
948 }
949 return true;
950 }
951 return false;
952 }
953
954 bool String_Schema::has_interpolants()
955 {
956 for (auto el : elements()) {
957 if (el->is_interpolant()) return true;
958 }
959 return false;
960 }
961
962 size_t String_Schema::hash() const
963 {
964 if (hash_ == 0) {
965 for (auto string : elements())
966 hash_combine(seed&: hash_, val: string->hash());
967 }
968 return hash_;
969 }
970
971 void String_Schema::set_delayed(bool delayed)
972 {
973 is_delayed(is_delayed__: delayed);
974 }
975
976 /////////////////////////////////////////////////////////////////////////
977 /////////////////////////////////////////////////////////////////////////
978
979 String_Constant::String_Constant(SourceSpan pstate, sass::string val, bool css)
980 : String(pstate), quote_mark_(0), value_(read_css_string(str: val, css)), hash_(0)
981 { }
982 String_Constant::String_Constant(SourceSpan pstate, const char* beg, bool css)
983 : String(pstate), quote_mark_(0), value_(read_css_string(str: sass::string(beg), css)), hash_(0)
984 { }
985 String_Constant::String_Constant(SourceSpan pstate, const char* beg, const char* end, bool css)
986 : String(pstate), quote_mark_(0), value_(read_css_string(str: sass::string(beg, end-beg), css)), hash_(0)
987 { }
988 String_Constant::String_Constant(SourceSpan pstate, const Token& tok, bool css)
989 : String(pstate), quote_mark_(0), value_(read_css_string(str: sass::string(tok.begin, tok.end), css)), hash_(0)
990 { }
991
992 String_Constant::String_Constant(const String_Constant* ptr)
993 : String(ptr),
994 quote_mark_(ptr->quote_mark_),
995 value_(ptr->value_),
996 hash_(ptr->hash_)
997 { }
998
999 bool String_Constant::is_invisible() const {
1000 return value_.empty() && quote_mark_ == 0;
1001 }
1002
1003 bool String_Constant::operator< (const Expression& rhs) const
1004 {
1005 if (auto qstr = Cast<String_Quoted>(ptr: &rhs)) {
1006 return value() < qstr->value();
1007 }
1008 else if (auto cstr = Cast<String_Constant>(ptr: &rhs)) {
1009 return value() < cstr->value();
1010 }
1011 // compare/sort by type
1012 return type() < rhs.type();
1013 }
1014
1015 bool String_Constant::operator== (const Expression& rhs) const
1016 {
1017 if (auto qstr = Cast<String_Quoted>(ptr: &rhs)) {
1018 return value() == qstr->value();
1019 }
1020 else if (auto cstr = Cast<String_Constant>(ptr: &rhs)) {
1021 return value() == cstr->value();
1022 }
1023 return false;
1024 }
1025
1026 sass::string String_Constant::inspect() const
1027 {
1028 return quote(value_, q: '*');
1029 }
1030
1031 void String_Constant::rtrim()
1032 {
1033 str_rtrim(str&: value_);
1034 }
1035
1036 size_t String_Constant::hash() const
1037 {
1038 if (hash_ == 0) {
1039 hash_ = std::hash<sass::string>()(value_);
1040 }
1041 return hash_;
1042 }
1043
1044 /////////////////////////////////////////////////////////////////////////
1045 /////////////////////////////////////////////////////////////////////////
1046
1047 String_Quoted::String_Quoted(SourceSpan pstate, sass::string val, char q,
1048 bool keep_utf8_escapes, bool skip_unquoting,
1049 bool strict_unquoting, bool css)
1050 : String_Constant(pstate, val, css)
1051 {
1052 if (skip_unquoting == false) {
1053 value_ = unquote(value_, q: &quote_mark_, keep_utf8_sequences: keep_utf8_escapes, strict: strict_unquoting);
1054 }
1055 if (q && quote_mark_) quote_mark_ = q;
1056 }
1057
1058 String_Quoted::String_Quoted(const String_Quoted* ptr)
1059 : String_Constant(ptr)
1060 { }
1061
1062 bool String_Quoted::operator< (const Expression& rhs) const
1063 {
1064 if (auto qstr = Cast<String_Quoted>(ptr: &rhs)) {
1065 return value() < qstr->value();
1066 }
1067 else if (auto cstr = Cast<String_Constant>(ptr: &rhs)) {
1068 return value() < cstr->value();
1069 }
1070 // compare/sort by type
1071 return type() < rhs.type();
1072 }
1073
1074 bool String_Quoted::operator== (const Expression& rhs) const
1075 {
1076 if (auto qstr = Cast<String_Quoted>(ptr: &rhs)) {
1077 return value() == qstr->value();
1078 }
1079 else if (auto cstr = Cast<String_Constant>(ptr: &rhs)) {
1080 return value() == cstr->value();
1081 }
1082 return false;
1083 }
1084
1085 sass::string String_Quoted::inspect() const
1086 {
1087 return quote(value_, q: '*');
1088 }
1089
1090 /////////////////////////////////////////////////////////////////////////
1091 /////////////////////////////////////////////////////////////////////////
1092
1093 Null::Null(SourceSpan pstate)
1094 : Value(pstate)
1095 { concrete_type(concrete_type__: NULL_VAL); }
1096
1097 Null::Null(const Null* ptr) : Value(ptr)
1098 { concrete_type(concrete_type__: NULL_VAL); }
1099
1100 bool Null::operator< (const Expression& rhs) const
1101 {
1102 if (Cast<Null>(ptr: &rhs)) {
1103 return false;
1104 }
1105 // compare/sort by type
1106 return type() < rhs.type();
1107 }
1108
1109 bool Null::operator== (const Expression& rhs) const
1110 {
1111 return Cast<Null>(ptr: &rhs) != nullptr;
1112 }
1113
1114 size_t Null::hash() const
1115 {
1116 return -1;
1117 }
1118
1119 /////////////////////////////////////////////////////////////////////////
1120 /////////////////////////////////////////////////////////////////////////
1121
1122 Parent_Reference::Parent_Reference(SourceSpan pstate)
1123 : Value(pstate)
1124 { concrete_type(concrete_type__: PARENT); }
1125
1126 Parent_Reference::Parent_Reference(const Parent_Reference* ptr)
1127 : Value(ptr)
1128 { concrete_type(concrete_type__: PARENT); }
1129
1130 /////////////////////////////////////////////////////////////////////////
1131 /////////////////////////////////////////////////////////////////////////
1132
1133 IMPLEMENT_AST_OPERATORS(List);
1134 IMPLEMENT_AST_OPERATORS(Map);
1135 IMPLEMENT_AST_OPERATORS(Binary_Expression);
1136 IMPLEMENT_AST_OPERATORS(Function);
1137 IMPLEMENT_AST_OPERATORS(Function_Call);
1138 IMPLEMENT_AST_OPERATORS(Variable);
1139 IMPLEMENT_AST_OPERATORS(Number);
1140 IMPLEMENT_AST_OPERATORS(Color_RGBA);
1141 IMPLEMENT_AST_OPERATORS(Color_HSLA);
1142 IMPLEMENT_AST_OPERATORS(Custom_Error);
1143 IMPLEMENT_AST_OPERATORS(Custom_Warning);
1144 IMPLEMENT_AST_OPERATORS(Boolean);
1145 IMPLEMENT_AST_OPERATORS(String_Schema);
1146 IMPLEMENT_AST_OPERATORS(String_Constant);
1147 IMPLEMENT_AST_OPERATORS(String_Quoted);
1148 IMPLEMENT_AST_OPERATORS(Null);
1149 IMPLEMENT_AST_OPERATORS(Parent_Reference);
1150
1151 /////////////////////////////////////////////////////////////////////////
1152 /////////////////////////////////////////////////////////////////////////
1153
1154}
1155

source code of gtk/subprojects/libsass/src/ast_values.cpp