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 6 namespace Sass { 7 str_rtrim(sass::string & str,const sass::string & delimiters=" \\f\\n\\r\\t\\v")8 void str_rtrim(sass::string& str, const sass::string& delimiters = " \f\n\r\t\v") 9 { 10 str.erase( str.find_last_not_of( delimiters ) + 1 ); 11 } 12 13 ///////////////////////////////////////////////////////////////////////// 14 ///////////////////////////////////////////////////////////////////////// 15 PreValue(SourceSpan pstate,bool d,bool e,bool i,Type ct)16 PreValue::PreValue(SourceSpan pstate, bool d, bool e, bool i, Type ct) 17 : Expression(pstate, d, e, i, ct) 18 { } PreValue(const PreValue * ptr)19 PreValue::PreValue(const PreValue* ptr) 20 : Expression(ptr) 21 { } 22 23 ///////////////////////////////////////////////////////////////////////// 24 ///////////////////////////////////////////////////////////////////////// 25 Value(SourceSpan pstate,bool d,bool e,bool i,Type ct)26 Value::Value(SourceSpan pstate, bool d, bool e, bool i, Type ct) 27 : PreValue(pstate, d, e, i, ct) 28 { } Value(const Value * ptr)29 Value::Value(const Value* ptr) 30 : PreValue(ptr) 31 { } 32 33 ///////////////////////////////////////////////////////////////////////// 34 ///////////////////////////////////////////////////////////////////////// 35 List(SourceSpan pstate,size_t size,enum Sass_Separator sep,bool argl,bool bracket)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(LIST); } 44 List(const List * ptr)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(LIST); } 53 hash() const54 size_t List::hash() const 55 { 56 if (hash_ == 0) { 57 hash_ = std::hash<sass::string>()(sep_string()); 58 hash_combine(hash_, std::hash<bool>()(is_bracketed())); 59 for (size_t i = 0, L = length(); i < L; ++i) 60 hash_combine(hash_, (elements()[i])->hash()); 61 } 62 return hash_; 63 } 64 set_delayed(bool delayed)65 void List::set_delayed(bool delayed) 66 { 67 is_delayed(delayed); 68 // don't set children 69 } 70 operator <(const Expression & rhs) const71 bool List::operator< (const Expression& rhs) const 72 { 73 if (auto r = Cast<List>(&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 operator ==(const Expression & rhs) const89 bool List::operator== (const Expression& rhs) const 90 { 91 if (auto r = Cast<List>(&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 size() const107 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>(obj)) { 114 if (!arg->name().empty()) return i; 115 } 116 } 117 return length(); 118 } 119 120 value_at_index(size_t i)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>(obj)) { 125 return arg->value(); 126 } else { 127 return obj; 128 } 129 } else { 130 return obj; 131 } 132 } 133 134 ///////////////////////////////////////////////////////////////////////// 135 ///////////////////////////////////////////////////////////////////////// 136 Map(SourceSpan pstate,size_t size)137 Map::Map(SourceSpan pstate, size_t size) 138 : Value(pstate), 139 Hashed(size) 140 { concrete_type(MAP); } 141 Map(const Map * ptr)142 Map::Map(const Map* ptr) 143 : Value(ptr), 144 Hashed(*ptr) 145 { concrete_type(MAP); } 146 operator <(const Expression & rhs) const147 bool Map::operator< (const Expression& rhs) const 148 { 149 if (auto r = Cast<Map>(&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 operator ==(const Expression & rhs) const172 bool Map::operator== (const Expression& rhs) const 173 { 174 if (auto r = Cast<Map>(&rhs)) { 175 if (length() != r->length()) return false; 176 for (auto key : keys()) { 177 auto rv = r->at(key); 178 auto lv = this->at(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 to_list(SourceSpan & pstate)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(key); 194 l->append(at(key)); 195 ret->append(l); 196 } 197 198 return ret; 199 } 200 hash() const201 size_t Map::hash() const 202 { 203 if (hash_ == 0) { 204 for (auto key : keys()) { 205 hash_combine(hash_, key->hash()); 206 hash_combine(hash_, at(key)->hash()); 207 } 208 } 209 210 return hash_; 211 } 212 213 ///////////////////////////////////////////////////////////////////////// 214 ///////////////////////////////////////////////////////////////////////// 215 Binary_Expression(SourceSpan pstate,Operand op,ExpressionObj lhs,ExpressionObj rhs)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 Binary_Expression(const Binary_Expression * ptr)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 is_left_interpolant(void) const229 bool Binary_Expression::is_left_interpolant(void) const 230 { 231 return is_interpolant() || (left() && left()->is_left_interpolant()); 232 } is_right_interpolant(void) const233 bool Binary_Expression::is_right_interpolant(void) const 234 { 235 return is_interpolant() || (right() && right()->is_right_interpolant()); 236 } 237 type_name()238 const sass::string Binary_Expression::type_name() 239 { 240 return sass_op_to_name(optype()); 241 } 242 separator()243 const sass::string Binary_Expression::separator() 244 { 245 return sass_op_separator(optype()); 246 } 247 has_interpolant() const248 bool Binary_Expression::has_interpolant() const 249 { 250 return is_left_interpolant() || 251 is_right_interpolant(); 252 } 253 set_delayed(bool delayed)254 void Binary_Expression::set_delayed(bool delayed) 255 { 256 right()->set_delayed(delayed); 257 left()->set_delayed(delayed); 258 is_delayed(delayed); 259 } 260 operator <(const Expression & rhs) const261 bool Binary_Expression::operator<(const Expression& rhs) const 262 { 263 if (auto m = Cast<Binary_Expression>(&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 operator ==(const Expression & rhs) const272 bool Binary_Expression::operator==(const Expression& rhs) const 273 { 274 if (auto m = Cast<Binary_Expression>(&rhs)) { 275 return type() == m->type() && 276 *left() == *m->left() && 277 *right() == *m->right(); 278 } 279 return false; 280 } 281 hash() const282 size_t Binary_Expression::hash() const 283 { 284 if (hash_ == 0) { 285 hash_ = std::hash<size_t>()(optype()); 286 hash_combine(hash_, left()->hash()); 287 hash_combine(hash_, right()->hash()); 288 } 289 return hash_; 290 } 291 292 ///////////////////////////////////////////////////////////////////////// 293 ///////////////////////////////////////////////////////////////////////// 294 Function(SourceSpan pstate,Definition_Obj def,bool css)295 Function::Function(SourceSpan pstate, Definition_Obj def, bool css) 296 : Value(pstate), definition_(def), is_css_(css) 297 { concrete_type(FUNCTION_VAL); } 298 Function(const Function * ptr)299 Function::Function(const Function* ptr) 300 : Value(ptr), definition_(ptr->definition_), is_css_(ptr->is_css_) 301 { concrete_type(FUNCTION_VAL); } 302 operator <(const Expression & rhs) const303 bool Function::operator< (const Expression& rhs) const 304 { 305 if (auto r = Cast<Function>(&rhs)) { 306 auto d1 = Cast<Definition>(definition()); 307 auto d2 = Cast<Definition>(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 operator ==(const Expression & rhs) const319 bool Function::operator== (const Expression& rhs) const 320 { 321 if (auto r = Cast<Function>(&rhs)) { 322 auto d1 = Cast<Definition>(definition()); 323 auto d2 = Cast<Definition>(r->definition()); 324 return d1 && d2 && d1 == d2 && is_css() == r->is_css(); 325 } 326 return false; 327 } 328 name()329 sass::string Function::name() { 330 if (definition_) { 331 return definition_->name(); 332 } 333 return ""; 334 } 335 336 ///////////////////////////////////////////////////////////////////////// 337 ///////////////////////////////////////////////////////////////////////// 338 Function_Call(SourceSpan pstate,String_Obj n,Arguments_Obj args,void * cookie)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(FUNCTION); } Function_Call(SourceSpan pstate,String_Obj n,Arguments_Obj args,Function_Obj func)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(FUNCTION); } Function_Call(SourceSpan pstate,String_Obj n,Arguments_Obj args)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(FUNCTION); } 348 Function_Call(SourceSpan pstate,sass::string n,Arguments_Obj args,void * cookie)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(FUNCTION); } Function_Call(SourceSpan pstate,sass::string n,Arguments_Obj args,Function_Obj func)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(FUNCTION); } Function_Call(SourceSpan pstate,sass::string n,Arguments_Obj args)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(FUNCTION); } 358 Function_Call(const Function_Call * ptr)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(FUNCTION); } 368 operator ==(const Expression & rhs) const369 bool Function_Call::operator==(const Expression& rhs) const 370 { 371 if (auto m = Cast<Function_Call>(&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 hash() const381 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(hash_, argument->hash()); 387 } 388 return hash_; 389 } 390 name() const391 sass::string Function_Call::name() const 392 { 393 return sname(); 394 } 395 is_css()396 bool Function_Call::is_css() { 397 if (func_) return func_->is_css(); 398 return false; 399 } 400 401 ///////////////////////////////////////////////////////////////////////// 402 ///////////////////////////////////////////////////////////////////////// 403 Variable(SourceSpan pstate,sass::string n)404 Variable::Variable(SourceSpan pstate, sass::string n) 405 : PreValue(pstate), name_(n) 406 { concrete_type(VARIABLE); } 407 Variable(const Variable * ptr)408 Variable::Variable(const Variable* ptr) 409 : PreValue(ptr), name_(ptr->name_) 410 { concrete_type(VARIABLE); } 411 operator ==(const Expression & rhs) const412 bool Variable::operator==(const Expression& rhs) const 413 { 414 if (auto e = Cast<Variable>(&rhs)) { 415 return name() == e->name(); 416 } 417 return false; 418 } 419 hash() const420 size_t Variable::hash() const 421 { 422 return std::hash<sass::string>()(name()); 423 } 424 425 ///////////////////////////////////////////////////////////////////////// 426 ///////////////////////////////////////////////////////////////////////// 427 Number(SourceSpan pstate,double val,sass::string u,bool zero)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("*/", l); 441 sass::string unit(u.substr(l, r == sass::string::npos ? r : r - l)); 442 if (!unit.empty()) { 443 if (nominator) numerators.push_back(unit); 444 else denominators.push_back(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(NUMBER); 458 } 459 Number(const Number * ptr)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(NUMBER); } 466 467 // cancel out unnecessary units reduce()468 void Number::reduce() 469 { 470 // apply conversion factor 471 value_ *= this->Units::reduce(); 472 } 473 normalize()474 void Number::normalize() 475 { 476 // apply conversion factor 477 value_ *= this->Units::normalize(); 478 } 479 hash() const480 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(hash_, std::hash<sass::string>()(numerator)); 486 for (const auto& denominator : denominators) 487 hash_combine(hash_, std::hash<sass::string>()(denominator)); 488 } 489 return hash_; 490 } 491 operator <(const Expression & rhs) const492 bool Number::operator< (const Expression& rhs) const 493 { 494 if (auto n = Cast<Number>(&rhs)) { 495 return *this < *n; 496 } 497 return false; 498 } 499 operator ==(const Expression & rhs) const500 bool Number::operator== (const Expression& rhs) const 501 { 502 if (auto n = Cast<Number>(&rhs)) { 503 return *this == *n; 504 } 505 return false; 506 } 507 operator ==(const Number & rhs) const508 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 operator <(const Number & rhs) const525 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 Color(SourceSpan pstate,double a,const sass::string disp)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(COLOR); } 557 Color(const Color * ptr)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(COLOR); } 565 operator <(const Expression & rhs) const566 bool Color::operator< (const Expression& rhs) const 567 { 568 if (auto r = Cast<Color_RGBA>(&rhs)) { 569 return *this < *r; 570 } 571 else if (auto r = Cast<Color_HSLA>(&rhs)) { 572 return *this < *r; 573 } 574 else if (auto r = Cast<Color>(&rhs)) { 575 return a_ < r->a(); 576 } 577 // compare/sort by type 578 return type() < rhs.type(); 579 } 580 operator ==(const Expression & rhs) const581 bool Color::operator== (const Expression& rhs) const 582 { 583 if (auto r = Cast<Color_RGBA>(&rhs)) { 584 return *this == *r; 585 } 586 else if (auto r = Cast<Color_HSLA>(&rhs)) { 587 return *this == *r; 588 } 589 else if (auto r = Cast<Color>(&rhs)) { 590 return a_ == r->a(); 591 } 592 return false; 593 } 594 595 ///////////////////////////////////////////////////////////////////////// 596 ///////////////////////////////////////////////////////////////////////// 597 Color_RGBA(SourceSpan pstate,double r,double g,double b,double a,const sass::string disp)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(COLOR); } 602 Color_RGBA(const Color_RGBA * ptr)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(COLOR); } 609 operator <(const Expression & rhs) const610 bool Color_RGBA::operator< (const Expression& rhs) const 611 { 612 if (auto r = Cast<Color_RGBA>(&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 operator ==(const Expression & rhs) const627 bool Color_RGBA::operator== (const Expression& rhs) const 628 { 629 if (auto r = Cast<Color_RGBA>(&rhs)) { 630 return r_ == r->r() && 631 g_ == r->g() && 632 b_ == r->b() && 633 a_ == r->a(); 634 } 635 return false; 636 } 637 hash() const638 size_t Color_RGBA::hash() const 639 { 640 if (hash_ == 0) { 641 hash_ = std::hash<sass::string>()("RGBA"); 642 hash_combine(hash_, std::hash<double>()(a_)); 643 hash_combine(hash_, std::hash<double>()(r_)); 644 hash_combine(hash_, std::hash<double>()(g_)); 645 hash_combine(hash_, std::hash<double>()(b_)); 646 } 647 return hash_; 648 } 649 copyAsHSLA() const650 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(r, std::max(g, b)); 659 double min = std::min(r, std::min(g, 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 copyAsRGBA() const688 Color_RGBA* Color_RGBA::copyAsRGBA() const 689 { 690 return SASS_MEMORY_COPY(this); 691 } 692 693 ///////////////////////////////////////////////////////////////////////// 694 ///////////////////////////////////////////////////////////////////////// 695 Color_HSLA(SourceSpan pstate,double h,double s,double l,double a,const sass::string disp)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(h, 360.0)), 699 s_(clip(s, 0.0, 100.0)), 700 l_(clip(l, 0.0, 100.0)) 701 // hash_(0) 702 { concrete_type(COLOR); } 703 Color_HSLA(const Color_HSLA * ptr)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(COLOR); } 711 operator <(const Expression & rhs) const712 bool Color_HSLA::operator< (const Expression& rhs) const 713 { 714 if (auto r = Cast<Color_HSLA>(&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 operator ==(const Expression & rhs) const729 bool Color_HSLA::operator== (const Expression& rhs) const 730 { 731 if (auto r = Cast<Color_HSLA>(&rhs)) { 732 return h_ == r->h() && 733 s_ == r->s() && 734 l_ == r->l() && 735 a_ == r->a(); 736 } 737 return false; 738 } 739 hash() const740 size_t Color_HSLA::hash() const 741 { 742 if (hash_ == 0) { 743 hash_ = std::hash<sass::string>()("HSLA"); 744 hash_combine(hash_, std::hash<double>()(a_)); 745 hash_combine(hash_, std::hash<double>()(h_)); 746 hash_combine(hash_, std::hash<double>()(s_)); 747 hash_combine(hash_, std::hash<double>()(l_)); 748 } 749 return hash_; 750 } 751 752 // hue to RGB helper function h_to_rgb(double m1,double m2,double h)753 double h_to_rgb(double m1, double m2, double h) 754 { 755 h = absmod(h, 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 copyAsRGBA() const762 Color_RGBA* Color_HSLA::copyAsRGBA() const 763 { 764 765 double h = absmod(h_ / 360.0, 1.0); 766 double s = clip(s_ / 100.0, 0.0, 1.0); 767 double l = clip(l_ / 100.0, 0.0, 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 + 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 - 1.0/3.0) * 255.0); 778 779 return SASS_MEMORY_NEW(Color_RGBA, 780 pstate(), r, g, b, a(), "" 781 ); 782 } 783 copyAsHSLA() const784 Color_HSLA* Color_HSLA::copyAsHSLA() const 785 { 786 return SASS_MEMORY_COPY(this); 787 } 788 789 ///////////////////////////////////////////////////////////////////////// 790 ///////////////////////////////////////////////////////////////////////// 791 Custom_Error(SourceSpan pstate,sass::string msg)792 Custom_Error::Custom_Error(SourceSpan pstate, sass::string msg) 793 : Value(pstate), message_(msg) 794 { concrete_type(C_ERROR); } 795 Custom_Error(const Custom_Error * ptr)796 Custom_Error::Custom_Error(const Custom_Error* ptr) 797 : Value(ptr), message_(ptr->message_) 798 { concrete_type(C_ERROR); } 799 operator <(const Expression & rhs) const800 bool Custom_Error::operator< (const Expression& rhs) const 801 { 802 if (auto r = Cast<Custom_Error>(&rhs)) { 803 return message() < r->message(); 804 } 805 // compare/sort by type 806 return type() < rhs.type(); 807 } 808 operator ==(const Expression & rhs) const809 bool Custom_Error::operator== (const Expression& rhs) const 810 { 811 if (auto r = Cast<Custom_Error>(&rhs)) { 812 return message() == r->message(); 813 } 814 return false; 815 } 816 817 ///////////////////////////////////////////////////////////////////////// 818 ///////////////////////////////////////////////////////////////////////// 819 Custom_Warning(SourceSpan pstate,sass::string msg)820 Custom_Warning::Custom_Warning(SourceSpan pstate, sass::string msg) 821 : Value(pstate), message_(msg) 822 { concrete_type(C_WARNING); } 823 Custom_Warning(const Custom_Warning * ptr)824 Custom_Warning::Custom_Warning(const Custom_Warning* ptr) 825 : Value(ptr), message_(ptr->message_) 826 { concrete_type(C_WARNING); } 827 operator <(const Expression & rhs) const828 bool Custom_Warning::operator< (const Expression& rhs) const 829 { 830 if (auto r = Cast<Custom_Warning>(&rhs)) { 831 return message() < r->message(); 832 } 833 // compare/sort by type 834 return type() < rhs.type(); 835 } 836 operator ==(const Expression & rhs) const837 bool Custom_Warning::operator== (const Expression& rhs) const 838 { 839 if (auto r = Cast<Custom_Warning>(&rhs)) { 840 return message() == r->message(); 841 } 842 return false; 843 } 844 845 ///////////////////////////////////////////////////////////////////////// 846 ///////////////////////////////////////////////////////////////////////// 847 Boolean(SourceSpan pstate,bool val)848 Boolean::Boolean(SourceSpan pstate, bool val) 849 : Value(pstate), value_(val), 850 hash_(0) 851 { concrete_type(BOOLEAN); } 852 Boolean(const Boolean * ptr)853 Boolean::Boolean(const Boolean* ptr) 854 : Value(ptr), 855 value_(ptr->value_), 856 hash_(ptr->hash_) 857 { concrete_type(BOOLEAN); } 858 operator <(const Expression & rhs) const859 bool Boolean::operator< (const Expression& rhs) const 860 { 861 if (auto r = Cast<Boolean>(&rhs)) { 862 return (value() < r->value()); 863 } 864 return false; 865 } 866 operator ==(const Expression & rhs) const867 bool Boolean::operator== (const Expression& rhs) const 868 { 869 if (auto r = Cast<Boolean>(&rhs)) { 870 return (value() == r->value()); 871 } 872 return false; 873 } 874 hash() const875 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 String(SourceSpan pstate,bool delayed)886 String::String(SourceSpan pstate, bool delayed) 887 : Value(pstate, delayed) 888 { concrete_type(STRING); } String(const String * ptr)889 String::String(const String* ptr) 890 : Value(ptr) 891 { concrete_type(STRING); } 892 893 ///////////////////////////////////////////////////////////////////////// 894 ///////////////////////////////////////////////////////////////////////// 895 String_Schema(SourceSpan pstate,size_t size,bool css)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(STRING); } 899 String_Schema(const String_Schema * ptr)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(STRING); } 906 rtrim()907 void String_Schema::rtrim() 908 { 909 if (!empty()) { 910 if (String* str = Cast<String>(last())) str->rtrim(); 911 } 912 } 913 is_left_interpolant(void) const914 bool String_Schema::is_left_interpolant(void) const 915 { 916 return length() && first()->is_left_interpolant(); 917 } is_right_interpolant(void) const918 bool String_Schema::is_right_interpolant(void) const 919 { 920 return length() && last()->is_right_interpolant(); 921 } 922 operator <(const Expression & rhs) const923 bool String_Schema::operator< (const Expression& rhs) const 924 { 925 if (auto r = Cast<String_Schema>(&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 operator ==(const Expression & rhs) const940 bool String_Schema::operator== (const Expression& rhs) const 941 { 942 if (auto r = Cast<String_Schema>(&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 has_interpolants()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 hash() const962 size_t String_Schema::hash() const 963 { 964 if (hash_ == 0) { 965 for (auto string : elements()) 966 hash_combine(hash_, string->hash()); 967 } 968 return hash_; 969 } 970 set_delayed(bool delayed)971 void String_Schema::set_delayed(bool delayed) 972 { 973 is_delayed(delayed); 974 } 975 976 ///////////////////////////////////////////////////////////////////////// 977 ///////////////////////////////////////////////////////////////////////// 978 String_Constant(SourceSpan pstate,sass::string val,bool css)979 String_Constant::String_Constant(SourceSpan pstate, sass::string val, bool css) 980 : String(pstate), quote_mark_(0), value_(read_css_string(val, css)), hash_(0) 981 { } String_Constant(SourceSpan pstate,const char * beg,bool css)982 String_Constant::String_Constant(SourceSpan pstate, const char* beg, bool css) 983 : String(pstate), quote_mark_(0), value_(read_css_string(sass::string(beg), css)), hash_(0) 984 { } String_Constant(SourceSpan pstate,const char * beg,const char * end,bool css)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(sass::string(beg, end-beg), css)), hash_(0) 987 { } String_Constant(SourceSpan pstate,const Token & tok,bool css)988 String_Constant::String_Constant(SourceSpan pstate, const Token& tok, bool css) 989 : String(pstate), quote_mark_(0), value_(read_css_string(sass::string(tok.begin, tok.end), css)), hash_(0) 990 { } 991 String_Constant(const String_Constant * ptr)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 is_invisible() const999 bool String_Constant::is_invisible() const { 1000 return value_.empty() && quote_mark_ == 0; 1001 } 1002 operator <(const Expression & rhs) const1003 bool String_Constant::operator< (const Expression& rhs) const 1004 { 1005 if (auto qstr = Cast<String_Quoted>(&rhs)) { 1006 return value() < qstr->value(); 1007 } 1008 else if (auto cstr = Cast<String_Constant>(&rhs)) { 1009 return value() < cstr->value(); 1010 } 1011 // compare/sort by type 1012 return type() < rhs.type(); 1013 } 1014 operator ==(const Expression & rhs) const1015 bool String_Constant::operator== (const Expression& rhs) const 1016 { 1017 if (auto qstr = Cast<String_Quoted>(&rhs)) { 1018 return value() == qstr->value(); 1019 } 1020 else if (auto cstr = Cast<String_Constant>(&rhs)) { 1021 return value() == cstr->value(); 1022 } 1023 return false; 1024 } 1025 inspect() const1026 sass::string String_Constant::inspect() const 1027 { 1028 return quote(value_, '*'); 1029 } 1030 rtrim()1031 void String_Constant::rtrim() 1032 { 1033 str_rtrim(value_); 1034 } 1035 hash() const1036 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 String_Quoted(SourceSpan pstate,sass::string val,char q,bool keep_utf8_escapes,bool skip_unquoting,bool strict_unquoting,bool css)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_, "e_mark_, keep_utf8_escapes, strict_unquoting); 1054 } 1055 if (q && quote_mark_) quote_mark_ = q; 1056 } 1057 String_Quoted(const String_Quoted * ptr)1058 String_Quoted::String_Quoted(const String_Quoted* ptr) 1059 : String_Constant(ptr) 1060 { } 1061 operator <(const Expression & rhs) const1062 bool String_Quoted::operator< (const Expression& rhs) const 1063 { 1064 if (auto qstr = Cast<String_Quoted>(&rhs)) { 1065 return value() < qstr->value(); 1066 } 1067 else if (auto cstr = Cast<String_Constant>(&rhs)) { 1068 return value() < cstr->value(); 1069 } 1070 // compare/sort by type 1071 return type() < rhs.type(); 1072 } 1073 operator ==(const Expression & rhs) const1074 bool String_Quoted::operator== (const Expression& rhs) const 1075 { 1076 if (auto qstr = Cast<String_Quoted>(&rhs)) { 1077 return value() == qstr->value(); 1078 } 1079 else if (auto cstr = Cast<String_Constant>(&rhs)) { 1080 return value() == cstr->value(); 1081 } 1082 return false; 1083 } 1084 inspect() const1085 sass::string String_Quoted::inspect() const 1086 { 1087 return quote(value_, '*'); 1088 } 1089 1090 ///////////////////////////////////////////////////////////////////////// 1091 ///////////////////////////////////////////////////////////////////////// 1092 Null(SourceSpan pstate)1093 Null::Null(SourceSpan pstate) 1094 : Value(pstate) 1095 { concrete_type(NULL_VAL); } 1096 Null(const Null * ptr)1097 Null::Null(const Null* ptr) : Value(ptr) 1098 { concrete_type(NULL_VAL); } 1099 operator <(const Expression & rhs) const1100 bool Null::operator< (const Expression& rhs) const 1101 { 1102 if (Cast<Null>(&rhs)) { 1103 return false; 1104 } 1105 // compare/sort by type 1106 return type() < rhs.type(); 1107 } 1108 operator ==(const Expression & rhs) const1109 bool Null::operator== (const Expression& rhs) const 1110 { 1111 return Cast<Null>(&rhs) != nullptr; 1112 } 1113 hash() const1114 size_t Null::hash() const 1115 { 1116 return -1; 1117 } 1118 1119 ///////////////////////////////////////////////////////////////////////// 1120 ///////////////////////////////////////////////////////////////////////// 1121 Parent_Reference(SourceSpan pstate)1122 Parent_Reference::Parent_Reference(SourceSpan pstate) 1123 : Value(pstate) 1124 { concrete_type(PARENT); } 1125 Parent_Reference(const Parent_Reference * ptr)1126 Parent_Reference::Parent_Reference(const Parent_Reference* ptr) 1127 : Value(ptr) 1128 { 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