sassc 1.8.3 → 1.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/ext/libsass/.editorconfig +1 -1
  4. data/ext/libsass/.gitignore +1 -0
  5. data/ext/libsass/LICENSE +1 -1
  6. data/ext/libsass/Makefile +20 -14
  7. data/ext/libsass/Makefile.conf +0 -1
  8. data/ext/libsass/Readme.md +3 -1
  9. data/ext/libsass/appveyor.yml +19 -11
  10. data/ext/libsass/docs/api-importer-example.md +2 -1235
  11. data/ext/libsass/docs/build-with-autotools.md +10 -0
  12. data/ext/libsass/docs/build-with-makefiles.md +18 -0
  13. data/ext/libsass/include/sass/base.h +4 -1
  14. data/ext/libsass/include/sass/values.h +2 -1
  15. data/ext/libsass/src/ast.cpp +279 -346
  16. data/ext/libsass/src/ast.hpp +234 -60
  17. data/ext/libsass/src/base64vlq.cpp +1 -0
  18. data/ext/libsass/src/bind.cpp +35 -45
  19. data/ext/libsass/src/bind.hpp +1 -0
  20. data/ext/libsass/src/color_maps.cpp +1 -0
  21. data/ext/libsass/src/constants.cpp +4 -1
  22. data/ext/libsass/src/constants.hpp +2 -1
  23. data/ext/libsass/src/context.cpp +41 -31
  24. data/ext/libsass/src/context.hpp +10 -10
  25. data/ext/libsass/src/cssize.cpp +7 -4
  26. data/ext/libsass/src/cssize.hpp +1 -3
  27. data/ext/libsass/src/debugger.hpp +73 -14
  28. data/ext/libsass/src/emitter.cpp +37 -25
  29. data/ext/libsass/src/emitter.hpp +10 -9
  30. data/ext/libsass/src/environment.cpp +16 -5
  31. data/ext/libsass/src/environment.hpp +5 -3
  32. data/ext/libsass/src/error_handling.cpp +91 -14
  33. data/ext/libsass/src/error_handling.hpp +105 -4
  34. data/ext/libsass/src/eval.cpp +519 -330
  35. data/ext/libsass/src/eval.hpp +12 -13
  36. data/ext/libsass/src/expand.cpp +92 -56
  37. data/ext/libsass/src/expand.hpp +5 -3
  38. data/ext/libsass/src/extend.cpp +60 -51
  39. data/ext/libsass/src/extend.hpp +1 -3
  40. data/ext/libsass/src/file.cpp +37 -27
  41. data/ext/libsass/src/functions.cpp +78 -62
  42. data/ext/libsass/src/functions.hpp +1 -0
  43. data/ext/libsass/src/inspect.cpp +293 -64
  44. data/ext/libsass/src/inspect.hpp +2 -0
  45. data/ext/libsass/src/lexer.cpp +1 -0
  46. data/ext/libsass/src/listize.cpp +14 -15
  47. data/ext/libsass/src/listize.hpp +3 -5
  48. data/ext/libsass/src/memory_manager.cpp +1 -0
  49. data/ext/libsass/src/node.cpp +2 -3
  50. data/ext/libsass/src/operation.hpp +70 -71
  51. data/ext/libsass/src/output.cpp +28 -32
  52. data/ext/libsass/src/output.hpp +1 -2
  53. data/ext/libsass/src/parser.cpp +402 -183
  54. data/ext/libsass/src/parser.hpp +19 -9
  55. data/ext/libsass/src/plugins.cpp +1 -0
  56. data/ext/libsass/src/position.cpp +1 -0
  57. data/ext/libsass/src/prelexer.cpp +134 -56
  58. data/ext/libsass/src/prelexer.hpp +51 -3
  59. data/ext/libsass/src/remove_placeholders.cpp +35 -9
  60. data/ext/libsass/src/remove_placeholders.hpp +4 -3
  61. data/ext/libsass/src/sass.cpp +1 -0
  62. data/ext/libsass/src/sass.hpp +129 -0
  63. data/ext/libsass/src/sass_context.cpp +31 -14
  64. data/ext/libsass/src/sass_context.hpp +2 -31
  65. data/ext/libsass/src/sass_functions.cpp +1 -0
  66. data/ext/libsass/src/sass_interface.cpp +5 -6
  67. data/ext/libsass/src/sass_util.cpp +1 -2
  68. data/ext/libsass/src/sass_util.hpp +5 -5
  69. data/ext/libsass/src/sass_values.cpp +13 -10
  70. data/ext/libsass/src/source_map.cpp +4 -3
  71. data/ext/libsass/src/source_map.hpp +2 -2
  72. data/ext/libsass/src/subset_map.hpp +0 -1
  73. data/ext/libsass/src/to_c.cpp +1 -0
  74. data/ext/libsass/src/to_c.hpp +1 -3
  75. data/ext/libsass/src/to_value.cpp +3 -5
  76. data/ext/libsass/src/to_value.hpp +1 -1
  77. data/ext/libsass/src/units.cpp +96 -59
  78. data/ext/libsass/src/units.hpp +10 -8
  79. data/ext/libsass/src/utf8_string.cpp +5 -0
  80. data/ext/libsass/src/util.cpp +23 -156
  81. data/ext/libsass/src/util.hpp +10 -14
  82. data/ext/libsass/src/values.cpp +1 -0
  83. data/ext/libsass/test/test_node.cpp +2 -6
  84. data/ext/libsass/test/test_selector_difference.cpp +1 -3
  85. data/ext/libsass/test/test_specificity.cpp +0 -2
  86. data/ext/libsass/test/test_superselector.cpp +0 -2
  87. data/ext/libsass/test/test_unification.cpp +1 -3
  88. data/ext/libsass/win/libsass.targets +18 -5
  89. data/ext/libsass/win/libsass.vcxproj +9 -7
  90. data/ext/libsass/win/libsass.vcxproj.filters +148 -106
  91. data/lib/sassc/version.rb +1 -1
  92. data/test/engine_test.rb +12 -0
  93. data/test/native_test.rb +1 -1
  94. metadata +3 -4
  95. data/ext/libsass/src/to_string.cpp +0 -48
  96. data/ext/libsass/src/to_string.hpp +0 -38
@@ -7,6 +7,16 @@ git clone https://github.com/sass/sassc.git libsass/sassc
7
7
  git clone https://github.com/sass/sass-spec.git libsass/sass-spec
8
8
  ```
9
9
 
10
+ ### Prerequisites
11
+
12
+ In order to run autotools you need a few tools installed on your system.
13
+ ```bash
14
+ yum install automake libtool # RedHat Linux
15
+ emerge -a automake libtool # Gentoo Linux
16
+ pkgin install automake libtool # SmartOS
17
+ ```
18
+
19
+
10
20
  ### Create configure script
11
21
  ```bash
12
22
  cd libsass
@@ -32,6 +32,24 @@ $ ls libsass/lib
32
32
  libsass.a libsass.so
33
33
  ```
34
34
 
35
+ ### Install onto the system
36
+
37
+ We recommend to use [autotools to install](build-with-autotools.md) libsass onto the
38
+ system, since that brings all the benefits of using libtools as the main install method.
39
+ If you still want to install libsass via the makefile, you need to make sure that gnu
40
+ `install` utility (or compatible) is installed on your system.
41
+ ```bash
42
+ yum install coreutils # RedHat Linux
43
+ emerge -a coreutils # Gentoo Linux
44
+ pkgin install coreutils # SmartOS
45
+ ```
46
+
47
+ You can set the install location by setting `PREFIX`
48
+ ```bash
49
+ PREFIX="/opt/local" make install
50
+ ```
51
+
52
+
35
53
  ### Compling sassc
36
54
 
37
55
  ```bash
@@ -56,7 +56,10 @@ enum Sass_Output_Style {
56
56
  SASS_STYLE_NESTED,
57
57
  SASS_STYLE_EXPANDED,
58
58
  SASS_STYLE_COMPACT,
59
- SASS_STYLE_COMPRESSED
59
+ SASS_STYLE_COMPRESSED,
60
+ // only used internaly
61
+ SASS_STYLE_INSPECT,
62
+ SASS_STYLE_TO_SASS
60
63
  };
61
64
 
62
65
  // Some convenient string helper function
@@ -29,7 +29,8 @@ enum Sass_Tag {
29
29
  // Tags for denoting Sass list separators
30
30
  enum Sass_Separator {
31
31
  SASS_COMMA,
32
- SASS_SPACE
32
+ SASS_SPACE,
33
+ SASS_HASH
33
34
  };
34
35
 
35
36
  // Value Operators
@@ -1,8 +1,9 @@
1
+ #include "sass.hpp"
1
2
  #include "ast.hpp"
2
3
  #include "context.hpp"
3
4
  #include "node.hpp"
4
5
  #include "extend.hpp"
5
- #include "to_string.hpp"
6
+ #include "emitter.hpp"
6
7
  #include "color_maps.hpp"
7
8
  #include <set>
8
9
  #include <iomanip>
@@ -58,7 +59,10 @@ namespace Sass {
58
59
 
59
60
  bool Compound_Selector::has_parent_ref()
60
61
  {
61
- return has_parent_reference();
62
+ for (Simple_Selector* s : *this) {
63
+ if (s->has_parent_ref()) return true;
64
+ }
65
+ return false;
62
66
  }
63
67
 
64
68
  bool Complex_Selector::has_parent_ref()
@@ -205,10 +209,8 @@ namespace Sass {
205
209
 
206
210
  bool Simple_Selector::operator== (const Simple_Selector& rhs) const
207
211
  {
208
- const Attribute_Selector* ll = dynamic_cast<const Attribute_Selector*>(this);
209
- const Attribute_Selector* rr = dynamic_cast<const Attribute_Selector*>(&rhs);
210
- if (ll && rr) return *ll == *rr;
211
-
212
+ if (const Wrapped_Selector* lw = dynamic_cast<const Wrapped_Selector*>(this)) return *lw == rhs;
213
+ if (const Attribute_Selector* la = dynamic_cast<const Attribute_Selector*>(this)) return *la == rhs;
212
214
  if (is_ns_eq(ns(), rhs.ns()))
213
215
  { return name() == rhs.name(); }
214
216
  return ns() == rhs.ns();
@@ -216,10 +218,8 @@ namespace Sass {
216
218
 
217
219
  bool Simple_Selector::operator< (const Simple_Selector& rhs) const
218
220
  {
219
- const Attribute_Selector* ll = dynamic_cast<const Attribute_Selector*>(this);
220
- const Attribute_Selector* rr = dynamic_cast<const Attribute_Selector*>(&rhs);
221
- if (ll && rr) return *ll < *rr;
222
-
221
+ if (const Wrapped_Selector* lw = dynamic_cast<const Wrapped_Selector*>(this)) return *lw < rhs;
222
+ if (const Attribute_Selector* la = dynamic_cast<const Attribute_Selector*>(this)) return *la < rhs;
223
223
  if (is_ns_eq(ns(), rhs.ns()))
224
224
  { return name() < rhs.name(); }
225
225
  return ns() < rhs.ns();
@@ -280,9 +280,8 @@ namespace Sass {
280
280
 
281
281
  Compound_Selector* Simple_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
282
282
  {
283
- To_String to_string(&ctx);
284
283
  for (size_t i = 0, L = rhs->length(); i < L; ++i)
285
- { if (perform(&to_string) == (*rhs)[i]->perform(&to_string)) return rhs; }
284
+ { if (to_string(ctx.c_options) == (*rhs)[i]->to_string(ctx.c_options)) return rhs; }
286
285
 
287
286
  // check for pseudo elements because they are always last
288
287
  size_t i, L;
@@ -291,7 +290,7 @@ namespace Sass {
291
290
  {
292
291
  for (i = 0, L = rhs->length(); i < L; ++i)
293
292
  {
294
- if ((typeid(*(*rhs)[i]) == typeid(Pseudo_Selector) || typeid(*(*rhs)[i]) == typeid(Wrapped_Selector)) && (*rhs)[L-1]->is_pseudo_element())
293
+ if ((dynamic_cast<Pseudo_Selector*>((*rhs)[i]) || dynamic_cast<Wrapped_Selector*>((*rhs)[i])) && (*rhs)[L-1]->is_pseudo_element())
295
294
  { found = true; break; }
296
295
  }
297
296
  }
@@ -299,7 +298,7 @@ namespace Sass {
299
298
  {
300
299
  for (i = 0, L = rhs->length(); i < L; ++i)
301
300
  {
302
- if (typeid(*(*rhs)[i]) == typeid(Pseudo_Selector) || typeid(*(*rhs)[i]) == typeid(Wrapped_Selector))
301
+ if (dynamic_cast<Pseudo_Selector*>((*rhs)[i]) || dynamic_cast<Wrapped_Selector*>((*rhs)[i]))
303
302
  { found = true; break; }
304
303
  }
305
304
  }
@@ -500,6 +499,26 @@ namespace Sass {
500
499
  return ns() == rhs.ns();
501
500
  }
502
501
 
502
+ bool Wrapped_Selector::operator< (const Wrapped_Selector& rhs) const
503
+ {
504
+ if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
505
+ { return *(selector()) < *(rhs.selector()); }
506
+ if (is_ns_eq(ns(), rhs.ns()))
507
+ { return name() < rhs.name(); }
508
+ return ns() < rhs.ns();
509
+ }
510
+
511
+ bool Wrapped_Selector::operator< (const Simple_Selector& rhs) const
512
+ {
513
+ if (const Wrapped_Selector* w = dynamic_cast<const Wrapped_Selector*>(&rhs))
514
+ {
515
+ return *this < *w;
516
+ }
517
+ if (is_ns_eq(ns(), rhs.ns()))
518
+ { return name() < rhs.name(); }
519
+ return ns() < rhs.ns();
520
+ }
521
+
503
522
  bool Wrapped_Selector::is_superselector_of(Wrapped_Selector* sub)
504
523
  {
505
524
  if (this->name() != sub->name()) return false;
@@ -531,8 +550,6 @@ namespace Sass {
531
550
 
532
551
  bool Compound_Selector::is_superselector_of(Compound_Selector* rhs, std::string wrapping)
533
552
  {
534
- To_String to_string;
535
-
536
553
  Compound_Selector* lhs = this;
537
554
  Simple_Selector* lbase = lhs->base();
538
555
  Simple_Selector* rbase = rhs->base();
@@ -543,7 +560,7 @@ namespace Sass {
543
560
  for (size_t i = 0, L = length(); i < L; ++i)
544
561
  {
545
562
  if ((*this)[i]->is_pseudo_element()) {
546
- std::string pseudo((*this)[i]->perform(&to_string));
563
+ std::string pseudo((*this)[i]->to_string());
547
564
  pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
548
565
  lpsuedoset.insert(pseudo);
549
566
  }
@@ -551,7 +568,7 @@ namespace Sass {
551
568
  for (size_t i = 0, L = rhs->length(); i < L; ++i)
552
569
  {
553
570
  if ((*rhs)[i]->is_pseudo_element()) {
554
- std::string pseudo((*rhs)[i]->perform(&to_string));
571
+ std::string pseudo((*rhs)[i]->to_string());
555
572
  pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
556
573
  rpsuedoset.insert(pseudo);
557
574
  }
@@ -564,11 +581,11 @@ namespace Sass {
564
581
 
565
582
  if (lbase && rbase)
566
583
  {
567
- if (lbase->perform(&to_string) == rbase->perform(&to_string)) {
584
+ if (lbase->to_string() == rbase->to_string()) {
568
585
  for (size_t i = 1, L = length(); i < L; ++i)
569
- { lset.insert((*this)[i]->perform(&to_string)); }
586
+ { lset.insert((*this)[i]->to_string()); }
570
587
  for (size_t i = 1, L = rhs->length(); i < L; ++i)
571
- { rset.insert((*rhs)[i]->perform(&to_string)); }
588
+ { rset.insert((*rhs)[i]->to_string()); }
572
589
  return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
573
590
  }
574
591
  return false;
@@ -602,13 +619,13 @@ namespace Sass {
602
619
  if (wrapped->name() == wrapped_r->name()) {
603
620
  if (wrapped->is_superselector_of(wrapped_r)) {
604
621
  continue;
605
- rset.insert(lhs->perform(&to_string));
622
+ rset.insert(lhs->to_string());
606
623
 
607
624
  }}
608
625
  }
609
626
  }
610
627
  // match from here on as strings
611
- lset.insert(lhs->perform(&to_string));
628
+ lset.insert(lhs->to_string());
612
629
  }
613
630
 
614
631
  for (size_t n = 0, nL = rhs->length(); n < nL; ++n)
@@ -631,7 +648,7 @@ namespace Sass {
631
648
  }
632
649
  }
633
650
  }
634
- rset.insert(r->perform(&to_string));
651
+ rset.insert(r->to_string());
635
652
  }
636
653
 
637
654
  //for (auto l : lset) { cerr << "l: " << l << endl; }
@@ -767,7 +784,6 @@ namespace Sass {
767
784
  bool Complex_Selector::is_superselector_of(Complex_Selector* rhs, std::string wrapping)
768
785
  {
769
786
  Complex_Selector* lhs = this;
770
- To_String to_string;
771
787
  // check for selectors with leading or trailing combinators
772
788
  if (!lhs->head() || !rhs->head())
773
789
  { return false; }
@@ -793,7 +809,7 @@ namespace Sass {
793
809
  if (lhs_tail->combinator() != rhs_tail->combinator()) return false;
794
810
  if (lhs_tail->head() && !rhs_tail->head()) return false;
795
811
  if (!lhs_tail->head() && rhs_tail->head()) return false;
796
- if (lhs_tail->head() && lhs_tail->head()) {
812
+ if (lhs_tail->head() && rhs_tail->head()) {
797
813
  if (!lhs_tail->head()->is_superselector_of(rhs_tail->head())) return false;
798
814
  }
799
815
  }
@@ -955,11 +971,12 @@ namespace Sass {
955
971
 
956
972
  if (head && head->length() > 0) {
957
973
 
974
+ Selector_List* retval = 0;
958
975
  // we have a parent selector in a simple compound list
959
976
  // mix parent complex selector into the compound list
960
977
  if (dynamic_cast<Parent_Selector*>((*head)[0])) {
978
+ retval = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
961
979
  if (parents && parents->length()) {
962
- Selector_List* retval = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
963
980
  if (tails && tails->length() > 0) {
964
981
  for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
965
982
  for (size_t i = 0, iL = parents->length(); i < iL; ++i) {
@@ -998,11 +1015,9 @@ namespace Sass {
998
1015
  *retval << s;
999
1016
  }
1000
1017
  }
1001
- return retval;
1002
1018
  }
1003
1019
  // have no parent but some tails
1004
1020
  else {
1005
- Selector_List* retval = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
1006
1021
  if (tails && tails->length() > 0) {
1007
1022
  for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
1008
1023
  Complex_Selector* cpy = this->clone(ctx);
@@ -1023,14 +1038,23 @@ namespace Sass {
1023
1038
  if (!cpy->head()->length()) cpy->head(0);
1024
1039
  *retval << cpy->skip_empty_reference();
1025
1040
  }
1026
- return retval;
1027
1041
  }
1028
1042
  }
1029
1043
  // no parent selector in head
1030
1044
  else {
1031
- return this->tails(ctx, tails);
1045
+ retval = this->tails(ctx, tails);
1032
1046
  }
1033
1047
 
1048
+ for (Simple_Selector* ss : *head) {
1049
+ if (Wrapped_Selector* ws = dynamic_cast<Wrapped_Selector*>(ss)) {
1050
+ if (Selector_List* sl = dynamic_cast<Selector_List*>(ws->selector())) {
1051
+ if (parents) ws->selector(sl->parentize(parents, ctx));
1052
+ }
1053
+ }
1054
+ }
1055
+
1056
+ return retval;
1057
+
1034
1058
  }
1035
1059
  // has no head
1036
1060
  else {
@@ -1141,6 +1165,7 @@ namespace Sass {
1141
1165
  Complex_Selector* Complex_Selector::clone(Context& ctx) const
1142
1166
  {
1143
1167
  Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this);
1168
+ cpy->is_optional(this->is_optional());
1144
1169
  cpy->media_block(this->media_block());
1145
1170
  if (tail()) cpy->tail(tail()->clone(ctx));
1146
1171
  return cpy;
@@ -1149,7 +1174,8 @@ namespace Sass {
1149
1174
  Complex_Selector* Complex_Selector::cloneFully(Context& ctx) const
1150
1175
  {
1151
1176
  Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this);
1152
-
1177
+ cpy->is_optional(this->is_optional());
1178
+ cpy->media_block(this->media_block());
1153
1179
  if (head()) {
1154
1180
  cpy->head(head()->clone(ctx));
1155
1181
  }
@@ -1164,13 +1190,16 @@ namespace Sass {
1164
1190
  Compound_Selector* Compound_Selector::clone(Context& ctx) const
1165
1191
  {
1166
1192
  Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *this);
1193
+ cpy->is_optional(this->is_optional());
1167
1194
  cpy->media_block(this->media_block());
1195
+ cpy->extended(this->extended());
1168
1196
  return cpy;
1169
1197
  }
1170
1198
 
1171
1199
  Selector_List* Selector_List::clone(Context& ctx) const
1172
1200
  {
1173
1201
  Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, *this);
1202
+ cpy->is_optional(this->is_optional());
1174
1203
  cpy->media_block(this->media_block());
1175
1204
  return cpy;
1176
1205
  }
@@ -1178,6 +1207,8 @@ namespace Sass {
1178
1207
  Selector_List* Selector_List::cloneFully(Context& ctx) const
1179
1208
  {
1180
1209
  Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
1210
+ cpy->is_optional(this->is_optional());
1211
+ cpy->media_block(this->media_block());
1181
1212
  for (size_t i = 0, L = length(); i < L; ++i) {
1182
1213
  *cpy << (*this)[i]->cloneFully(ctx);
1183
1214
  }
@@ -1213,9 +1244,17 @@ namespace Sass {
1213
1244
  }
1214
1245
  }
1215
1246
 
1247
+ bool Selector_List::has_parent_ref()
1248
+ {
1249
+ for (Complex_Selector* s : *this) {
1250
+ if (s->has_parent_ref()) return true;
1251
+ }
1252
+ return false;
1253
+ }
1254
+
1216
1255
  void Selector_List::adjust_after_pushing(Complex_Selector* c)
1217
1256
  {
1218
- if (c->has_reference()) has_reference(true);
1257
+ // if (c->has_reference()) has_reference(true);
1219
1258
  }
1220
1259
 
1221
1260
  // it's a superselector if every selector of the right side
@@ -1287,8 +1326,8 @@ namespace Sass {
1287
1326
  return final_result;
1288
1327
  }
1289
1328
 
1290
- void Selector_List::populate_extends(Selector_List* extendee, Context& ctx, ExtensionSubsetMap& extends) {
1291
- To_String to_string;
1329
+ void Selector_List::populate_extends(Selector_List* extendee, Context& ctx, ExtensionSubsetMap& extends)
1330
+ {
1292
1331
 
1293
1332
  Selector_List* extender = this;
1294
1333
  for (auto complex_sel : extendee->elements()) {
@@ -1322,17 +1361,15 @@ namespace Sass {
1322
1361
 
1323
1362
  std::vector<std::string> Compound_Selector::to_str_vec()
1324
1363
  {
1325
- To_String to_string;
1326
1364
  std::vector<std::string> result;
1327
1365
  result.reserve(length());
1328
1366
  for (size_t i = 0, L = length(); i < L; ++i)
1329
- { result.push_back((*this)[i]->perform(&to_string)); }
1367
+ { result.push_back((*this)[i]->to_string()); }
1330
1368
  return result;
1331
1369
  }
1332
1370
 
1333
1371
  Compound_Selector* Compound_Selector::minus(Compound_Selector* rhs, Context& ctx)
1334
1372
  {
1335
- To_String to_string(&ctx);
1336
1373
  Compound_Selector* result = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pstate());
1337
1374
  // result->has_parent_reference(has_parent_reference());
1338
1375
 
@@ -1340,10 +1377,10 @@ namespace Sass {
1340
1377
  for (size_t i = 0, L = length(); i < L; ++i)
1341
1378
  {
1342
1379
  bool found = false;
1343
- std::string thisSelector((*this)[i]->perform(&to_string));
1380
+ std::string thisSelector((*this)[i]->to_string(ctx.c_options));
1344
1381
  for (size_t j = 0, M = rhs->length(); j < M; ++j)
1345
1382
  {
1346
- if (thisSelector == (*rhs)[j]->perform(&to_string))
1383
+ if (thisSelector == (*rhs)[j]->to_string(ctx.c_options))
1347
1384
  {
1348
1385
  found = true;
1349
1386
  break;
@@ -1362,6 +1399,36 @@ namespace Sass {
1362
1399
  }
1363
1400
  }
1364
1401
 
1402
+ Argument* Arguments::get_rest_argument()
1403
+ {
1404
+ Argument* arg = 0;
1405
+ if (this->has_rest_argument()) {
1406
+ for (auto a : this->elements()) {
1407
+ if (a->is_rest_argument()) {
1408
+ arg = a;
1409
+ break;
1410
+ }
1411
+ }
1412
+ }
1413
+
1414
+ return arg;
1415
+ }
1416
+
1417
+ Argument* Arguments::get_keyword_argument()
1418
+ {
1419
+ Argument* arg = 0;
1420
+ if (this->has_keyword_argument()) {
1421
+ for (auto a : this->elements()) {
1422
+ if (a->is_keyword_argument()) {
1423
+ arg = a;
1424
+ break;
1425
+ }
1426
+ }
1427
+ }
1428
+
1429
+ return arg;
1430
+ }
1431
+
1365
1432
  void Arguments::adjust_after_pushing(Argument* a)
1366
1433
  {
1367
1434
  if (!a->name().empty()) {
@@ -1453,7 +1520,13 @@ namespace Sass {
1453
1520
  return u;
1454
1521
  }
1455
1522
 
1456
- bool Number::is_unitless()
1523
+ bool Number::is_valid_css_unit() const
1524
+ {
1525
+ return numerator_units().size() <= 1 &&
1526
+ denominator_units().size() == 0;
1527
+ }
1528
+
1529
+ bool Number::is_unitless() const
1457
1530
  { return numerator_units_.empty() && denominator_units_.empty(); }
1458
1531
 
1459
1532
  void Number::normalize(const std::string& prefered, bool strict)
@@ -1541,10 +1614,128 @@ namespace Sass {
1541
1614
 
1542
1615
  }
1543
1616
 
1544
- void Number::convert(const std::string& prefered, bool strict)
1617
+ // this does not cover all cases (multiple prefered units)
1618
+ double Number::convert_factor(const Number& n) const
1619
+ {
1620
+
1621
+ // first make sure same units cancel each other out
1622
+ // it seems that a map table will fit nicely to do this
1623
+ // we basically construct exponents for each unit class
1624
+ // std::map<std::string, int> exponents;
1625
+ // initialize by summing up occurences in unit vectors
1626
+ // for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[unit_to_class(numerator_units_[i])];
1627
+ // for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[unit_to_class(denominator_units_[i])];
1628
+
1629
+ std::vector<std::string> l_miss_nums(0);
1630
+ std::vector<std::string> l_miss_dens(0);
1631
+ // create copy since we need these for state keeping
1632
+ std::vector<std::string> r_nums(n.numerator_units_);
1633
+ std::vector<std::string> r_dens(n.denominator_units_);
1634
+
1635
+ std::vector<std::string>::const_iterator l_num_it = numerator_units_.begin();
1636
+ std::vector<std::string>::const_iterator l_num_end = numerator_units_.end();
1637
+
1638
+ bool l_unitless = is_unitless();
1639
+ bool r_unitless = n.is_unitless();
1640
+
1641
+ // overall conversion
1642
+ double factor = 1;
1643
+
1644
+ // process all left numerators
1645
+ while (l_num_it != l_num_end)
1646
+ {
1647
+ // get and increment afterwards
1648
+ const std::string l_num = *(l_num_it ++);
1649
+
1650
+ std::vector<std::string>::iterator r_num_it = r_nums.begin();
1651
+ std::vector<std::string>::iterator r_num_end = r_nums.end();
1652
+
1653
+ bool found = false;
1654
+ // search for compatible numerator
1655
+ while (r_num_it != r_num_end)
1656
+ {
1657
+ // get and increment afterwards
1658
+ const std::string r_num = *(r_num_it);
1659
+ // get possible converstion factor for units
1660
+ double conversion = conversion_factor(l_num, r_num, false);
1661
+ // skip incompatible numerator
1662
+ if (conversion == 0) {
1663
+ ++ r_num_it;
1664
+ continue;
1665
+ }
1666
+ // apply to global factor
1667
+ factor *= conversion;
1668
+ // remove item from vector
1669
+ r_nums.erase(r_num_it);
1670
+ // found numerator
1671
+ found = true;
1672
+ break;
1673
+ }
1674
+ // maybe we did not find any
1675
+ // left numerator is leftover
1676
+ if (!found) l_miss_nums.push_back(l_num);
1677
+ }
1678
+
1679
+ std::vector<std::string>::const_iterator l_den_it = denominator_units_.begin();
1680
+ std::vector<std::string>::const_iterator l_den_end = denominator_units_.end();
1681
+
1682
+ // process all left denominators
1683
+ while (l_den_it != l_den_end)
1684
+ {
1685
+ // get and increment afterwards
1686
+ const std::string l_den = *(l_den_it ++);
1687
+
1688
+ std::vector<std::string>::iterator r_den_it = r_dens.begin();
1689
+ std::vector<std::string>::iterator r_den_end = r_dens.end();
1690
+
1691
+ bool found = false;
1692
+ // search for compatible denominator
1693
+ while (r_den_it != r_den_end)
1694
+ {
1695
+ // get and increment afterwards
1696
+ const std::string r_den = *(r_den_it);
1697
+ // get possible converstion factor for units
1698
+ double conversion = conversion_factor(l_den, r_den, false);
1699
+ // skip incompatible denominator
1700
+ if (conversion == 0) {
1701
+ ++ r_den_it;
1702
+ continue;
1703
+ }
1704
+ // apply to global factor
1705
+ factor *= conversion;
1706
+ // remove item from vector
1707
+ r_dens.erase(r_den_it);
1708
+ // found denominator
1709
+ found = true;
1710
+ break;
1711
+ }
1712
+ // maybe we did not find any
1713
+ // left denominator is leftover
1714
+ if (!found) l_miss_dens.push_back(l_den);
1715
+ }
1716
+
1717
+ // check left-overs (ToDo: might cancel out)
1718
+ if (l_miss_nums.size() > 0 && !r_unitless) {
1719
+ throw Exception::IncompatibleUnits(n, *this);
1720
+ }
1721
+ if (l_miss_dens.size() > 0 && !r_unitless) {
1722
+ throw Exception::IncompatibleUnits(n, *this);
1723
+ }
1724
+ if (r_nums.size() > 0 && !l_unitless) {
1725
+ throw Exception::IncompatibleUnits(n, *this);
1726
+ }
1727
+ if (r_dens.size() > 0 && !l_unitless) {
1728
+ throw Exception::IncompatibleUnits(n, *this);
1729
+ }
1730
+
1731
+ return factor;
1732
+ }
1733
+
1734
+ // this does not cover all cases (multiple prefered units)
1735
+ bool Number::convert(const std::string& prefered, bool strict)
1545
1736
  {
1546
- // abort if unit is empty
1547
- if (prefered.empty()) return;
1737
+ // no conversion if unit is empty
1738
+ if (prefered.empty()) return true;
1548
1739
 
1549
1740
  // first make sure same units cancel each other out
1550
1741
  // it seems that a map table will fit nicely to do this
@@ -1626,6 +1817,9 @@ namespace Sass {
1626
1817
  // best precision this way
1627
1818
  value_ *= factor;
1628
1819
 
1820
+ // success?
1821
+ return true;
1822
+
1629
1823
  }
1630
1824
 
1631
1825
  // useful for making one number compatible with another
@@ -1661,6 +1855,12 @@ namespace Sass {
1661
1855
  bool Number::operator== (const Expression& rhs) const
1662
1856
  {
1663
1857
  if (const Number* r = dynamic_cast<const Number*>(&rhs)) {
1858
+ size_t lhs_units = numerator_units_.size() + denominator_units_.size();
1859
+ size_t rhs_units = r->numerator_units_.size() + r->denominator_units_.size();
1860
+ // unitless and only having one unit seems equivalent (will change in future)
1861
+ if (!lhs_units || !rhs_units) {
1862
+ return std::fabs(value() - r->value()) < NUMBER_EPSILON;
1863
+ }
1664
1864
  return (numerator_units_ == r->numerator_units_) &&
1665
1865
  (denominator_units_ == r->denominator_units_) &&
1666
1866
  std::fabs(value() - r->value()) < NUMBER_EPSILON;
@@ -1670,11 +1870,18 @@ namespace Sass {
1670
1870
 
1671
1871
  bool Number::operator< (const Number& rhs) const
1672
1872
  {
1873
+ size_t lhs_units = numerator_units_.size() + denominator_units_.size();
1874
+ size_t rhs_units = rhs.numerator_units_.size() + rhs.denominator_units_.size();
1875
+ // unitless and only having one unit seems equivalent (will change in future)
1876
+ if (!lhs_units || !rhs_units) {
1877
+ return value() < rhs.value();
1878
+ }
1879
+
1673
1880
  Number tmp_r(rhs);
1674
1881
  tmp_r.normalize(find_convertible_unit());
1675
1882
  std::string l_unit(unit());
1676
1883
  std::string r_unit(tmp_r.unit());
1677
- if (!l_unit.empty() && !r_unit.empty() && unit() != tmp_r.unit()) {
1884
+ if (unit() != tmp_r.unit()) {
1678
1885
  error("cannot compare numbers with incompatible units", pstate());
1679
1886
  }
1680
1887
  return value() < tmp_r.value();
@@ -1700,6 +1907,15 @@ namespace Sass {
1700
1907
  return false;
1701
1908
  }
1702
1909
 
1910
+ bool String_Schema::is_left_interpolant(void) const
1911
+ {
1912
+ return length() && first()->is_left_interpolant();
1913
+ }
1914
+ bool String_Schema::is_right_interpolant(void) const
1915
+ {
1916
+ return length() && last()->is_right_interpolant();
1917
+ }
1918
+
1703
1919
  bool String_Schema::operator== (const Expression& rhs) const
1704
1920
  {
1705
1921
  if (const String_Schema* r = dynamic_cast<const String_Schema*>(&rhs)) {
@@ -1789,65 +2005,29 @@ namespace Sass {
1789
2005
  else { return &sass_null; }
1790
2006
  }
1791
2007
 
1792
- std::string Map::to_string(bool compressed, int precision) const
2008
+ bool Binary_Expression::is_left_interpolant(void) const
1793
2009
  {
1794
- std::string res("");
1795
- if (empty()) return res;
1796
- if (is_invisible()) return res;
1797
- bool items_output = false;
1798
- for (auto key : keys()) {
1799
- if (key->is_invisible()) continue;
1800
- if (at(key)->is_invisible()) continue;
1801
- if (items_output) res += compressed ? "," : ", ";
1802
- Value* v_key = dynamic_cast<Value*>(key);
1803
- Value* v_val = dynamic_cast<Value*>(at(key));
1804
- if (v_key) res += v_key->to_string(compressed, precision);
1805
- res += compressed ? ":" : ": ";
1806
- if (v_val) res += v_val->to_string(compressed, precision);
1807
- items_output = true;
1808
- }
1809
- return res;
2010
+ return is_interpolant() || (left() && left()->is_left_interpolant());
1810
2011
  }
1811
-
1812
- std::string List::to_string(bool compressed, int precision) const
2012
+ bool Binary_Expression::is_right_interpolant(void) const
1813
2013
  {
1814
- std::string res("");
1815
- if (empty()) return res;
1816
- if (is_invisible()) return res;
1817
- bool items_output = false;
1818
- std::string sep = separator() == SASS_COMMA ? "," : " ";
1819
- if (!compressed && sep == ",") sep += " ";
1820
- for (size_t i = 0, L = size(); i < L; ++i) {
1821
- Expression* item = (*this)[i];
1822
- if (item->is_invisible()) continue;
1823
- if (items_output) res += sep;
1824
- if (Value* v_val = dynamic_cast<Value*>(item))
1825
- { res += v_val->to_string(compressed, precision); }
1826
- items_output = true;
1827
- }
1828
- return res;
1829
- }
1830
-
1831
- std::string String_Schema::to_string(bool compressed, int precision) const
1832
- {
1833
- std::string res("");
1834
- for (size_t i = 0, L = length(); i < L; ++i) {
1835
- if ((*this)[i]->is_interpolant()) res += "#{";
1836
- if (Value* val = dynamic_cast<Value*>((*this)[i]))
1837
- { res += val->to_string(compressed, precision); }
1838
- if ((*this)[i]->is_interpolant()) res += "}";
1839
- }
1840
- return res;
2014
+ return is_interpolant() || (right() && right()->is_right_interpolant());
1841
2015
  }
1842
2016
 
1843
- std::string Null::to_string(bool compressed, int precision) const
2017
+ std::string AST_Node::to_string(Sass_Inspect_Options opt) const
1844
2018
  {
1845
- return "null";
2019
+ Sass_Output_Options out(opt);
2020
+ Emitter emitter(out);
2021
+ Inspect i(emitter);
2022
+ i.in_declaration = true;
2023
+ // ToDo: inspect should be const
2024
+ const_cast<AST_Node*>(this)->perform(&i);
2025
+ return i.get_buffer();
1846
2026
  }
1847
2027
 
1848
- std::string Boolean::to_string(bool compressed, int precision) const
2028
+ std::string AST_Node::to_string() const
1849
2029
  {
1850
- return value_ ? "true" : "false";
2030
+ return to_string({ NESTED, 5 });
1851
2031
  }
1852
2032
 
1853
2033
  // helper function for serializing colors
@@ -1858,261 +2038,14 @@ namespace Sass {
1858
2038
  else return c;
1859
2039
  }
1860
2040
 
1861
- std::string Color::to_string(bool compressed, int precision) const
1862
- {
1863
- std::stringstream ss;
1864
-
1865
- // original color name
1866
- // maybe an unknown token
1867
- std::string name = disp();
1868
-
1869
- // resolved color
1870
- std::string res_name = name;
1871
-
1872
- double r = Sass::round(cap_channel<0xff>(r_));
1873
- double g = Sass::round(cap_channel<0xff>(g_));
1874
- double b = Sass::round(cap_channel<0xff>(b_));
1875
- double a = cap_channel<1> (a_);
1876
-
1877
- // get color from given name (if one was given at all)
1878
- if (name != "" && name_to_color(name)) {
1879
- const Color* n = name_to_color(name);
1880
- r = Sass::round(cap_channel<0xff>(n->r()));
1881
- g = Sass::round(cap_channel<0xff>(n->g()));
1882
- b = Sass::round(cap_channel<0xff>(n->b()));
1883
- a = cap_channel<1> (n->a());
1884
- }
1885
- // otherwise get the possible resolved color name
1886
- else {
1887
- double numval = r * 0x10000 + g * 0x100 + b;
1888
- if (color_to_name(numval))
1889
- res_name = color_to_name(numval);
1890
- }
1891
-
1892
- std::stringstream hexlet;
1893
- hexlet << '#' << std::setw(1) << std::setfill('0');
1894
- // create a short color hexlet if there is any need for it
1895
- if (compressed && is_color_doublet(r, g, b) && a == 1) {
1896
- hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(r) >> 4);
1897
- hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(g) >> 4);
1898
- hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(b) >> 4);
1899
- } else {
1900
- hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(r);
1901
- hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(g);
1902
- hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(b);
1903
- }
1904
-
1905
- if (compressed && !this->is_delayed()) name = "";
1906
-
1907
- // retain the originally specified color definition if unchanged
1908
- if (name != "") {
1909
- ss << name;
1910
- }
1911
- else if (r == 0 && g == 0 && b == 0 && a == 0) {
1912
- ss << "transparent";
1913
- }
1914
- else if (a >= 1) {
1915
- if (res_name != "") {
1916
- if (compressed && hexlet.str().size() < res_name.size()) {
1917
- ss << hexlet.str();
1918
- } else {
1919
- ss << res_name;
1920
- }
1921
- }
1922
- else {
1923
- ss << hexlet.str();
1924
- }
1925
- }
1926
- else {
1927
- ss << "rgba(";
1928
- ss << static_cast<unsigned long>(r) << ",";
1929
- if (!compressed) ss << " ";
1930
- ss << static_cast<unsigned long>(g) << ",";
1931
- if (!compressed) ss << " ";
1932
- ss << static_cast<unsigned long>(b) << ",";
1933
- if (!compressed) ss << " ";
1934
- ss << a << ')';
1935
- }
1936
-
1937
- return ss.str();
1938
-
1939
- }
1940
-
1941
- std::string Number::to_string(bool compressed, int precision) const
1942
- {
1943
-
1944
- std::string res;
1945
-
1946
- // check if the fractional part of the value equals to zero
1947
- // neat trick from http://stackoverflow.com/a/1521682/1550314
1948
- // double int_part; bool is_int = modf(value, &int_part) == 0.0;
1949
-
1950
- // this all cannot be done with one run only, since fixed
1951
- // output differs from normal output and regular output
1952
- // can contain scientific notation which we do not want!
1953
-
1954
- // first sample
1955
- std::stringstream ss;
1956
- ss.precision(12);
1957
- ss << value_;
1958
-
1959
- // check if we got scientific notation in result
1960
- if (ss.str().find_first_of("e") != std::string::npos) {
1961
- ss.clear(); ss.str(std::string());
1962
- ss.precision(std::max(12, precision));
1963
- ss << std::fixed << value_;
1964
- }
1965
-
1966
- std::string tmp = ss.str();
1967
- size_t pos_point = tmp.find_first_of(".,");
1968
- size_t pos_fract = tmp.find_last_not_of("0");
1969
- bool is_int = pos_point == pos_fract ||
1970
- pos_point == std::string::npos;
1971
-
1972
- // reset stream for another run
1973
- ss.clear(); ss.str(std::string());
1974
-
1975
- // take a shortcut for integers
1976
- if (is_int)
1977
- {
1978
- ss.precision(0);
1979
- ss << std::fixed << value_;
1980
- res = std::string(ss.str());
1981
- }
1982
- // process floats
1983
- else
1984
- {
1985
- // do we have have too much precision?
1986
- if (pos_fract < precision + pos_point)
1987
- { precision = (int)(pos_fract - pos_point); }
1988
- // round value again
1989
- ss.precision(precision);
1990
- ss << std::fixed << value_;
1991
- res = std::string(ss.str());
1992
- // maybe we truncated up to decimal point
1993
- size_t pos = res.find_last_not_of("0");
1994
- bool at_dec_point = res[pos] == '.' ||
1995
- res[pos] == ',';
1996
- // don't leave a blank point
1997
- if (at_dec_point) ++ pos;
1998
- res.resize (pos + 1);
1999
- }
2000
-
2001
- // some final cosmetics
2002
- if (res == "-0.0") res.erase(0, 1);
2003
- else if (res == "-0") res.erase(0, 1);
2004
- else if (res == "") res = "0";
2005
-
2006
- // add unit now
2007
- res += unit();
2008
-
2009
- // and return
2010
- return res;
2011
-
2012
- }
2013
-
2014
- std::string String_Quoted::to_string(bool compressed, int precision) const
2015
- {
2016
- return quote_mark_ ? quote(value_, quote_mark_, true) : value_;
2017
- }
2018
-
2019
- std::string String_Constant::to_string(bool compressed, int precision) const
2020
- {
2021
- return quote_mark_ ? quote(value_, quote_mark_, true) : value_;
2022
- }
2023
-
2024
- std::string Custom_Error::to_string(bool compressed, int precision) const
2025
- {
2026
- return message();
2027
- }
2028
- std::string Custom_Warning::to_string(bool compressed, int precision) const
2029
- {
2030
- return message();
2031
- }
2032
-
2033
- std::string Selector_List::to_string(bool compressed, int precision) const
2034
- {
2035
- std::string str("");
2036
- auto end = this->end();
2037
- auto start = this->begin();
2038
- while (start < end && *start) {
2039
- Complex_Selector* sel = *start;
2040
- if (!str.empty()) str += ", ";
2041
- str += sel->to_string(compressed, precision);
2042
- ++ start;
2043
- }
2044
- return str;
2045
- }
2046
-
2047
- std::string Compound_Selector::to_string(bool compressed, int precision) const
2048
- {
2049
- std::string str("");
2050
- auto end = this->end();
2051
- auto start = this->begin();
2052
- while (start < end && *start) {
2053
- Simple_Selector* sel = *start;
2054
- str += sel->to_string(compressed, precision);
2055
- ++ start;
2056
- }
2057
- return str;
2058
- }
2059
-
2060
- std::string Complex_Selector::to_string(bool compressed, int precision) const
2061
- {
2062
- // first render head and tail if they are available
2063
- std::string str_head(head() ? head()->to_string(compressed, precision) : "");
2064
- std::string str_tail(tail() ? tail()->to_string(compressed, precision) : "");
2065
- std::string str_ref(reference() ? reference()->to_string(compressed, precision) : "");
2066
- // combinator in between
2067
- std::string str_op("");
2068
- // use a switch statement
2069
- switch (combinator()) {
2070
- case ANCESTOR_OF: str_op = " "; break;
2071
- case PARENT_OF: str_op = ">"; break;
2072
- case PRECEDES: str_op = "~"; break;
2073
- case ADJACENT_TO: str_op = "+"; break;
2074
- case REFERENCE: str_op = "/" + str_ref + "/"; break;
2075
- }
2076
- // prettify for non ancestors
2077
- if (combinator() != ANCESTOR_OF) {
2078
- // no spaces needed for compressed
2079
- if (compressed == false) {
2080
- // make sure we add some spaces where needed
2081
- if (str_tail != "") str_op += " ";
2082
- if (str_head != "") str_head += " ";
2083
- }
2084
- }
2085
- // is ancestor with no tail
2086
- else if (str_tail == "") {
2087
- str_op = ""; // superflous
2088
- }
2089
- // now build the final result
2090
- return str_head + str_op + str_tail;
2091
- }
2092
-
2093
- std::string Selector_Schema::to_string(bool compressed, int precision) const
2094
- {
2095
- return contents()->to_string(compressed, precision);
2096
- }
2097
-
2098
- std::string Parent_Selector::to_string(bool compressed, int precision) const
2099
- {
2100
- return "&";
2101
- }
2102
-
2103
- std::string Attribute_Selector::to_string(bool compressed, int precision) const
2041
+ std::string String_Quoted::inspect() const
2104
2042
  {
2105
- std::string val(value() ? value()->to_string(compressed, precision) : "");
2106
- return "[" + this->ns_name() + this->matcher() + val + "]";
2043
+ return quote(value_, '*');
2107
2044
  }
2108
2045
 
2109
- std::string Wrapped_Selector::to_string(bool compressed, int precision) const
2046
+ std::string String_Constant::inspect() const
2110
2047
  {
2111
- // first render the
2112
- std::string main(this->Simple_Selector::to_string(compressed, precision));
2113
- std::string wrapped(selector() ? selector()->to_string(compressed, precision) : "");
2114
- // now build the final result
2115
- return main + "(" + wrapped + ")";
2048
+ return quote(value_, '*');
2116
2049
  }
2117
2050
 
2118
2051
  //////////////////////////////////////////////////////////////////////////////////////////