sassc 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Rakefile +1 -3
  5. data/ext/extconf.rb +13 -5
  6. data/ext/libsass/VERSION +1 -1
  7. data/ext/libsass/include/sass/base.h +2 -1
  8. data/ext/libsass/include/sass/context.h +1 -0
  9. data/ext/libsass/src/ast.cpp +49 -59
  10. data/ext/libsass/src/ast.hpp +263 -102
  11. data/ext/libsass/src/ast_def_macros.hpp +8 -0
  12. data/ext/libsass/src/ast_fwd_decl.cpp +2 -1
  13. data/ext/libsass/src/ast_fwd_decl.hpp +40 -116
  14. data/ext/libsass/src/ast_helpers.hpp +292 -0
  15. data/ext/libsass/src/ast_sel_cmp.cpp +209 -722
  16. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  17. data/ext/libsass/src/ast_sel_unify.cpp +207 -212
  18. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  19. data/ext/libsass/src/ast_selectors.cpp +559 -1001
  20. data/ext/libsass/src/ast_selectors.hpp +311 -367
  21. data/ext/libsass/src/ast_supports.cpp +1 -17
  22. data/ext/libsass/src/ast_values.cpp +216 -29
  23. data/ext/libsass/src/ast_values.hpp +42 -33
  24. data/ext/libsass/src/bind.cpp +1 -1
  25. data/ext/libsass/src/cencode.c +4 -6
  26. data/ext/libsass/src/check_nesting.cpp +5 -6
  27. data/ext/libsass/src/check_nesting.hpp +4 -0
  28. data/ext/libsass/src/color_maps.cpp +11 -10
  29. data/ext/libsass/src/color_maps.hpp +0 -8
  30. data/ext/libsass/src/constants.cpp +5 -0
  31. data/ext/libsass/src/constants.hpp +6 -0
  32. data/ext/libsass/src/context.cpp +30 -60
  33. data/ext/libsass/src/context.hpp +8 -20
  34. data/ext/libsass/src/cssize.cpp +36 -120
  35. data/ext/libsass/src/cssize.hpp +4 -10
  36. data/ext/libsass/src/dart_helpers.hpp +199 -0
  37. data/ext/libsass/src/debugger.hpp +364 -207
  38. data/ext/libsass/src/emitter.cpp +3 -4
  39. data/ext/libsass/src/emitter.hpp +0 -2
  40. data/ext/libsass/src/environment.hpp +5 -0
  41. data/ext/libsass/src/error_handling.cpp +21 -0
  42. data/ext/libsass/src/error_handling.hpp +25 -3
  43. data/ext/libsass/src/eval.cpp +33 -153
  44. data/ext/libsass/src/eval.hpp +11 -13
  45. data/ext/libsass/src/eval_selectors.cpp +75 -0
  46. data/ext/libsass/src/expand.cpp +214 -167
  47. data/ext/libsass/src/expand.hpp +26 -6
  48. data/ext/libsass/src/extender.cpp +1186 -0
  49. data/ext/libsass/src/extender.hpp +399 -0
  50. data/ext/libsass/src/extension.cpp +43 -0
  51. data/ext/libsass/src/extension.hpp +89 -0
  52. data/ext/libsass/src/file.cpp +15 -14
  53. data/ext/libsass/src/file.hpp +5 -12
  54. data/ext/libsass/src/fn_colors.cpp +12 -10
  55. data/ext/libsass/src/fn_lists.cpp +12 -11
  56. data/ext/libsass/src/fn_miscs.cpp +22 -34
  57. data/ext/libsass/src/fn_numbers.cpp +13 -6
  58. data/ext/libsass/src/fn_selectors.cpp +94 -124
  59. data/ext/libsass/src/fn_strings.cpp +16 -14
  60. data/ext/libsass/src/fn_utils.cpp +5 -6
  61. data/ext/libsass/src/fn_utils.hpp +9 -3
  62. data/ext/libsass/src/inspect.cpp +154 -117
  63. data/ext/libsass/src/inspect.hpp +10 -8
  64. data/ext/libsass/src/lexer.cpp +17 -81
  65. data/ext/libsass/src/lexer.hpp +5 -16
  66. data/ext/libsass/src/listize.cpp +22 -36
  67. data/ext/libsass/src/listize.hpp +8 -9
  68. data/ext/libsass/src/memory/SharedPtr.hpp +39 -5
  69. data/ext/libsass/src/operation.hpp +27 -17
  70. data/ext/libsass/src/operators.cpp +1 -0
  71. data/ext/libsass/src/ordered_map.hpp +112 -0
  72. data/ext/libsass/src/output.cpp +30 -49
  73. data/ext/libsass/src/output.hpp +1 -1
  74. data/ext/libsass/src/parser.cpp +211 -381
  75. data/ext/libsass/src/parser.hpp +17 -15
  76. data/ext/libsass/src/parser_selectors.cpp +189 -0
  77. data/ext/libsass/src/permutate.hpp +140 -0
  78. data/ext/libsass/src/position.hpp +1 -1
  79. data/ext/libsass/src/prelexer.cpp +6 -6
  80. data/ext/libsass/src/remove_placeholders.cpp +55 -56
  81. data/ext/libsass/src/remove_placeholders.hpp +21 -18
  82. data/ext/libsass/src/sass.hpp +1 -0
  83. data/ext/libsass/src/sass2scss.cpp +4 -4
  84. data/ext/libsass/src/sass_context.cpp +42 -91
  85. data/ext/libsass/src/sass_context.hpp +2 -2
  86. data/ext/libsass/src/sass_functions.cpp +1 -1
  87. data/ext/libsass/src/sass_values.cpp +0 -1
  88. data/ext/libsass/src/stylesheet.cpp +22 -0
  89. data/ext/libsass/src/stylesheet.hpp +57 -0
  90. data/ext/libsass/src/to_value.cpp +2 -2
  91. data/ext/libsass/src/to_value.hpp +1 -1
  92. data/ext/libsass/src/units.cpp +5 -3
  93. data/ext/libsass/src/util.cpp +10 -12
  94. data/ext/libsass/src/util.hpp +2 -3
  95. data/ext/libsass/src/util_string.cpp +111 -61
  96. data/ext/libsass/src/util_string.hpp +61 -8
  97. data/lib/sassc/engine.rb +5 -3
  98. data/lib/sassc/functions_handler.rb +8 -8
  99. data/lib/sassc/native.rb +1 -1
  100. data/lib/sassc/script.rb +4 -4
  101. data/lib/sassc/version.rb +1 -1
  102. data/test/functions_test.rb +18 -1
  103. data/test/native_test.rb +1 -1
  104. metadata +17 -12
  105. data/ext/libsass/src/extend.cpp +0 -2132
  106. data/ext/libsass/src/extend.hpp +0 -86
  107. data/ext/libsass/src/node.cpp +0 -322
  108. data/ext/libsass/src/node.hpp +0 -118
  109. data/ext/libsass/src/paths.hpp +0 -71
  110. data/ext/libsass/src/sass_util.cpp +0 -152
  111. data/ext/libsass/src/sass_util.hpp +0 -256
  112. data/ext/libsass/src/subset_map.cpp +0 -58
  113. data/ext/libsass/src/subset_map.hpp +0 -76
@@ -13,7 +13,6 @@
13
13
  #else
14
14
  # include <unistd.h>
15
15
  #endif
16
- #include <cctype>
17
16
  #include <cstdio>
18
17
  #include <vector>
19
18
  #include <algorithm>
@@ -25,6 +24,7 @@
25
24
  #include "sass_functions.hpp"
26
25
  #include "error_handling.hpp"
27
26
  #include "util.hpp"
27
+ #include "util_string.hpp"
28
28
  #include "sass2scss.h"
29
29
 
30
30
  #ifdef _WIN32
@@ -106,19 +106,19 @@ namespace Sass {
106
106
  bool is_absolute_path(const std::string& path)
107
107
  {
108
108
  #ifdef _WIN32
109
- if (path.length() >= 2 && isalpha(path[0]) && path[1] == ':') return true;
109
+ if (path.length() >= 2 && Util::ascii_isalpha(path[0]) && path[1] == ':') return true;
110
110
  #endif
111
111
  size_t i = 0;
112
112
  // check if we have a protocol
113
- if (path[i] && Prelexer::is_alpha(path[i])) {
113
+ if (path[i] && Util::ascii_isalpha(static_cast<unsigned char>(path[i]))) {
114
114
  // skip over all alphanumeric characters
115
- while (path[i] && Prelexer::is_alnum(path[i])) ++i;
115
+ while (path[i] && Util::ascii_isalnum(static_cast<unsigned char>(path[i]))) ++i;
116
116
  i = i && path[i] == ':' ? i + 1 : 0;
117
117
  }
118
118
  return path[i] == '/';
119
119
  }
120
120
 
121
- // helper function to find the last directory seperator
121
+ // helper function to find the last directory separator
122
122
  inline size_t find_last_folder_separator(const std::string& path, size_t limit = std::string::npos)
123
123
  {
124
124
  size_t pos;
@@ -173,15 +173,15 @@ namespace Sass {
173
173
  while((pos = path.find("/./", pos)) != std::string::npos) path.erase(pos, 2);
174
174
 
175
175
  // remove all leading and trailing self references
176
- while(path.length() > 1 && path.substr(0, 2) == "./") path.erase(0, 2);
177
- while((pos = path.length()) > 1 && path.substr(pos - 2) == "/.") path.erase(pos - 2);
176
+ while(path.size() >= 2 && path[0] == '.' && path[1] == '/') path.erase(0, 2);
177
+ while((pos = path.length()) > 1 && path[pos - 2] == '/' && path[pos - 1] == '.') path.erase(pos - 2);
178
178
 
179
179
 
180
180
  size_t proto = 0;
181
181
  // check if we have a protocol
182
- if (path[proto] && Prelexer::is_alpha(path[proto])) {
182
+ if (path[proto] && Util::ascii_isalpha(static_cast<unsigned char>(path[proto]))) {
183
183
  // skip over all alphanumeric characters
184
- while (path[proto] && Prelexer::is_alnum(path[proto++])) {}
184
+ while (path[proto] && Util::ascii_isalnum(static_cast<unsigned char>(path[proto++]))) {}
185
185
  // then skip over the mandatory colon
186
186
  if (proto && path[proto] == ':') ++ proto;
187
187
  }
@@ -260,9 +260,9 @@ namespace Sass {
260
260
 
261
261
  size_t proto = 0;
262
262
  // check if we have a protocol
263
- if (path[proto] && Prelexer::is_alpha(path[proto])) {
263
+ if (path[proto] && Util::ascii_isalpha(static_cast<unsigned char>(path[proto]))) {
264
264
  // skip over all alphanumeric characters
265
- while (path[proto] && Prelexer::is_alnum(path[proto++])) {}
265
+ while (path[proto] && Util::ascii_isalnum(static_cast<unsigned char>(path[proto++]))) {}
266
266
  // then skip over the mandatory colon
267
267
  if (proto && path[proto] == ':') ++ proto;
268
268
  }
@@ -288,7 +288,8 @@ namespace Sass {
288
288
  #else
289
289
  // compare the charactes in a case insensitive manner
290
290
  // windows fs is only case insensitive in ascii ranges
291
- if (tolower(abs_path[i]) != tolower(abs_base[i])) break;
291
+ if (Util::ascii_tolower(static_cast<unsigned char>(abs_path[i])) !=
292
+ Util::ascii_tolower(static_cast<unsigned char>(abs_base[i]))) break;
292
293
  #endif
293
294
  if (abs_path[i] == '/') index = i + 1;
294
295
  }
@@ -474,6 +475,7 @@ namespace Sass {
474
475
  char* contents = static_cast<char*>(malloc(st.st_size + 2 * sizeof(char)));
475
476
  if (std::fread(static_cast<void*>(contents), 1, size, fd) != size) {
476
477
  free(contents);
478
+ std::fclose(fd);
477
479
  return nullptr;
478
480
  }
479
481
  if (std::fclose(fd) != 0) {
@@ -487,8 +489,7 @@ namespace Sass {
487
489
  if (path.length() > 5) {
488
490
  extension = path.substr(path.length() - 5, 5);
489
491
  }
490
- for(size_t i=0; i<extension.size();++i)
491
- extension[i] = tolower(extension[i]);
492
+ Util::ascii_str_tolower(&extension);
492
493
  if (extension == ".sass" && contents != 0) {
493
494
  char * converted = sass2scss(contents, SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
494
495
  free(contents); // free the indented contents
@@ -1,6 +1,10 @@
1
1
  #ifndef SASS_FILE_H
2
2
  #define SASS_FILE_H
3
3
 
4
+ // sass.hpp must go before all system headers to get the
5
+ // __EXTENSIONS__ fix on Solaris.
6
+ #include "sass.hpp"
7
+
4
8
  #include <string>
5
9
  #include <vector>
6
10
 
@@ -100,7 +104,7 @@ namespace Sass {
100
104
  public:
101
105
  // the file contents
102
106
  char* contents;
103
- // conected sourcemap
107
+ // connected sourcemap
104
108
  char* srcmap;
105
109
  public:
106
110
  Resource(char* contents, char* srcmap)
@@ -108,17 +112,6 @@ namespace Sass {
108
112
  { }
109
113
  };
110
114
 
111
- // parsed stylesheet from loaded resource
112
- class StyleSheet : public Resource {
113
- public:
114
- // parsed root block
115
- Block_Obj root;
116
- public:
117
- StyleSheet(const Resource& res, Block_Obj root)
118
- : Resource(res), root(root)
119
- { }
120
- };
121
-
122
115
  namespace File {
123
116
 
124
117
  static std::vector<std::string> defaultExtensions = { ".scss", ".sass", ".css" };
@@ -2,12 +2,12 @@
2
2
  // __EXTENSIONS__ fix on Solaris.
3
3
  #include "sass.hpp"
4
4
 
5
- #include <cctype>
6
5
  #include <iomanip>
7
6
  #include "ast.hpp"
8
7
  #include "fn_utils.hpp"
9
8
  #include "fn_colors.hpp"
10
9
  #include "util.hpp"
10
+ #include "util_string.hpp"
11
11
 
12
12
  namespace Sass {
13
13
 
@@ -163,11 +163,11 @@ namespace Sass {
163
163
  c1->a()*p + c2->a()*(1-p));
164
164
  }
165
165
 
166
- Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)";
166
+ Signature mix_sig = "mix($color1, $color2, $weight: 50%)";
167
167
  BUILT_IN(mix)
168
168
  {
169
- Color_Obj color1 = ARG("$color-1", Color);
170
- Color_Obj color2 = ARG("$color-2", Color);
169
+ Color_Obj color1 = ARG("$color1", Color);
170
+ Color_Obj color2 = ARG("$color2", Color);
171
171
  double weight = DARG_U_PRCT("$weight");
172
172
  return colormix(ctx, pstate, color1, color2, weight);
173
173
 
@@ -361,12 +361,16 @@ namespace Sass {
361
361
  {
362
362
  // CSS3 filter function overload: pass literal through directly
363
363
  Number* amount = Cast<Number>(env["$color"]);
364
+ double weight = DARG_U_PRCT("$weight");
364
365
  if (amount) {
366
+ // TODO: does not throw on 100% manually passed as value
367
+ if (weight < 100.0) {
368
+ error("Only one argument may be passed to the plain-CSS invert() function.", pstate, traces);
369
+ }
365
370
  return SASS_MEMORY_NEW(String_Quoted, pstate, "invert(" + amount->to_string(ctx.c_options) + ")");
366
371
  }
367
372
 
368
373
  Color* col = ARG("$color", Color);
369
- double weight = DARG_U_PRCT("$weight");
370
374
  Color_RGBA_Obj inv = col->copyAsRGBA();
371
375
  inv->r(clip(255.0 - inv->r(), 0.0, 255.0));
372
376
  inv->g(clip(255.0 - inv->g(), 0.0, 255.0));
@@ -504,7 +508,7 @@ namespace Sass {
504
508
  double lscale = (l ? DARG_R_PRCT("$lightness") : 0.0) / 100.0;
505
509
  double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0;
506
510
  if (hscale) c->h(c->h() + hscale * (hscale > 0.0 ? 360.0 - c->h() : c->h()));
507
- if (sscale) c->s(c->s() + sscale * (sscale > 0.0 ? 100.0 - c->l() : c->s()));
511
+ if (sscale) c->s(c->s() + sscale * (sscale > 0.0 ? 100.0 - c->s() : c->s()));
508
512
  if (lscale) c->l(c->l() + lscale * (lscale > 0.0 ? 100.0 - c->l() : c->l()));
509
513
  if (ascale) c->a(c->a() + ascale * (ascale > 0.0 ? 1.0 - c->a() : c->a()));
510
514
  return c.detach();
@@ -582,10 +586,8 @@ namespace Sass {
582
586
  ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(g, ctx.c_options.precision));
583
587
  ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(b, ctx.c_options.precision));
584
588
 
585
- std::string result(ss.str());
586
- for (size_t i = 0, L = result.length(); i < L; ++i) {
587
- result[i] = std::toupper(result[i]);
588
- }
589
+ std::string result = ss.str();
590
+ Util::ascii_str_toupper(&result);
589
591
  return SASS_MEMORY_NEW(String_Quoted, pstate, result);
590
592
  }
591
593
 
@@ -1,3 +1,7 @@
1
+ // sass.hpp must go before all system headers to get the
2
+ // __EXTENSIONS__ fix on Solaris.
3
+ #include "sass.hpp"
4
+
1
5
  #include "listize.hpp"
2
6
  #include "operators.hpp"
3
7
  #include "fn_utils.hpp"
@@ -31,8 +35,8 @@ namespace Sass {
31
35
  Signature length_sig = "length($list)";
32
36
  BUILT_IN(length)
33
37
  {
34
- if (Selector_List* sl = Cast<Selector_List>(env["$list"])) {
35
- return SASS_MEMORY_NEW(Number, pstate, (double)sl->length());
38
+ if (SelectorList * sl = Cast<SelectorList>(env["$list"])) {
39
+ return SASS_MEMORY_NEW(Number, pstate, (double) sl->length());
36
40
  }
37
41
  Expression* v = ARG("$list", Expression);
38
42
  if (v->concrete_type() == Expression::MAP) {
@@ -40,9 +44,9 @@ namespace Sass {
40
44
  return SASS_MEMORY_NEW(Number, pstate, (double)(map ? map->length() : 1));
41
45
  }
42
46
  if (v->concrete_type() == Expression::SELECTOR) {
43
- if (Compound_Selector* h = Cast<Compound_Selector>(v)) {
47
+ if (CompoundSelector * h = Cast<CompoundSelector>(v)) {
44
48
  return SASS_MEMORY_NEW(Number, pstate, (double)h->length());
45
- } else if (Selector_List* ls = Cast<Selector_List>(v)) {
49
+ } else if (SelectorList * ls = Cast<SelectorList>(v)) {
46
50
  return SASS_MEMORY_NEW(Number, pstate, (double)ls->length());
47
51
  } else {
48
52
  return SASS_MEMORY_NEW(Number, pstate, 1);
@@ -60,15 +64,13 @@ namespace Sass {
60
64
  {
61
65
  double nr = ARGVAL("$n");
62
66
  Map* m = Cast<Map>(env["$list"]);
63
- if (Selector_List* sl = Cast<Selector_List>(env["$list"])) {
67
+ if (SelectorList * sl = Cast<SelectorList>(env["$list"])) {
64
68
  size_t len = m ? m->length() : sl->length();
65
69
  bool empty = m ? m->empty() : sl->empty();
66
70
  if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces);
67
71
  double index = std::floor(nr < 0 ? len + nr : nr - 1);
68
72
  if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces);
69
- // return (*sl)[static_cast<int>(index)];
70
- Listize listize;
71
- return Cast<Value>((*sl)[static_cast<int>(index)]->perform(&listize));
73
+ return Cast<Value>(Listize::perform(sl->get(static_cast<int>(index))));
72
74
  }
73
75
  List_Obj l = Cast<List>(env["$list"]);
74
76
  if (nr == 0) error("argument `$n` of `" + std::string(sig) + "` must be non-zero", pstate, traces);
@@ -189,9 +191,8 @@ namespace Sass {
189
191
  Map_Obj m = Cast<Map>(env["$list"]);
190
192
  List_Obj l = Cast<List>(env["$list"]);
191
193
  Expression_Obj v = ARG("$val", Expression);
192
- if (Selector_List* sl = Cast<Selector_List>(env["$list"])) {
193
- Listize listize;
194
- l = Cast<List>(sl->perform(&listize));
194
+ if (SelectorList * sl = Cast<SelectorList>(env["$list"])) {
195
+ l = Cast<List>(Listize::perform(sl));
195
196
  }
196
197
  String_Constant_Obj sep = ARG("$separator", String_Constant);
197
198
  if (!l) {
@@ -8,15 +8,6 @@ namespace Sass {
8
8
 
9
9
  namespace Functions {
10
10
 
11
- // features
12
- static std::set<std::string> features {
13
- "global-variable-shadowing",
14
- "extend-selector-pseudoclass",
15
- "at-error",
16
- "units-level-3",
17
- "custom-property"
18
- };
19
-
20
11
  //////////////////////////
21
12
  // INTROSPECTION FUNCTIONS
22
13
  //////////////////////////
@@ -85,34 +76,36 @@ namespace Sass {
85
76
  }
86
77
  }
87
78
 
88
- Signature feature_exists_sig = "feature-exists($name)";
79
+ Signature feature_exists_sig = "feature-exists($feature)";
89
80
  BUILT_IN(feature_exists)
90
81
  {
91
- std::string s = unquote(ARG("$name", String_Constant)->value());
92
-
93
- if(features.find(s) == features.end()) {
94
- return SASS_MEMORY_NEW(Boolean, pstate, false);
95
- }
96
- else {
97
- return SASS_MEMORY_NEW(Boolean, pstate, true);
98
- }
82
+ std::string s = unquote(ARG("$feature", String_Constant)->value());
83
+
84
+ static const auto *const features = new std::unordered_set<std::string> {
85
+ "global-variable-shadowing",
86
+ "extend-selector-pseudoclass",
87
+ "at-error",
88
+ "units-level-3",
89
+ "custom-property"
90
+ };
91
+ return SASS_MEMORY_NEW(Boolean, pstate, features->find(s) != features->end());
99
92
  }
100
93
 
101
- Signature call_sig = "call($name, $args...)";
94
+ Signature call_sig = "call($function, $args...)";
102
95
  BUILT_IN(call)
103
96
  {
104
- std::string name;
105
- Function* ff = Cast<Function>(env["$name"]);
106
- String_Constant* ss = Cast<String_Constant>(env["$name"]);
97
+ std::string function;
98
+ Function* ff = Cast<Function>(env["$function"]);
99
+ String_Constant* ss = Cast<String_Constant>(env["$function"]);
107
100
 
108
101
  if (ss) {
109
- name = Util::normalize_underscores(unquote(ss->value()));
102
+ function = Util::normalize_underscores(unquote(ss->value()));
110
103
  std::cerr << "DEPRECATION WARNING: ";
111
104
  std::cerr << "Passing a string to call() is deprecated and will be illegal" << std::endl;
112
- std::cerr << "in Sass 4.0. Use call(get-function(" + quote(name) + ")) instead." << std::endl;
105
+ std::cerr << "in Sass 4.0. Use call(get-function(" + quote(function) + ")) instead." << std::endl;
113
106
  std::cerr << std::endl;
114
107
  } else if (ff) {
115
- name = ff->name();
108
+ function = ff->name();
116
109
  }
117
110
 
118
111
  List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List));
@@ -142,8 +135,9 @@ namespace Sass {
142
135
  args->append(SASS_MEMORY_NEW(Argument, pstate, expr));
143
136
  }
144
137
  }
145
- Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, args);
146
- Expand expand(ctx, &d_env, &selector_stack);
138
+ Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, function, args);
139
+
140
+ Expand expand(ctx, &d_env, &selector_stack, &original_stack);
147
141
  func->via_call(true); // calc invoke is allowed
148
142
  if (ff) func->func(ff);
149
143
  return Cast<PreValue>(func->perform(&expand.eval));
@@ -160,11 +154,9 @@ namespace Sass {
160
154
  }
161
155
 
162
156
  Signature if_sig = "if($condition, $if-true, $if-false)";
163
- // BUILT_IN(sass_if)
164
- // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); }
165
157
  BUILT_IN(sass_if)
166
158
  {
167
- Expand expand(ctx, &d_env, &selector_stack);
159
+ Expand expand(ctx, &d_env, &selector_stack, &original_stack);
168
160
  Expression_Obj cond = ARG("$condition", Expression)->perform(&expand.eval);
169
161
  bool is_true = !cond->is_false();
170
162
  Expression_Obj res = ARG(is_true ? "$if-true" : "$if-false", Expression);
@@ -178,9 +170,6 @@ namespace Sass {
178
170
  // MISCELLANEOUS FUNCTIONS
179
171
  //////////////////////////
180
172
 
181
- // value.check_deprecated_interp if value.is_a?(Sass::Script::Value::String)
182
- // unquoted_string(value.to_sass)
183
-
184
173
  Signature inspect_sig = "inspect($value)";
185
174
  BUILT_IN(inspect)
186
175
  {
@@ -208,7 +197,6 @@ namespace Sass {
208
197
  ctx.c_options.output_style = old_style;
209
198
  return SASS_MEMORY_NEW(String_Quoted, pstate, i.get_buffer());
210
199
  }
211
- // return v;
212
200
  }
213
201
 
214
202
  Signature content_exists_sig = "content-exists()";
@@ -5,7 +5,6 @@
5
5
  #include <cstdint>
6
6
  #include <cstdlib>
7
7
  #include <cmath>
8
- #include <cctype>
9
8
  #include <random>
10
9
  #include <sstream>
11
10
  #include <iomanip>
@@ -106,7 +105,11 @@ namespace Sass {
106
105
  {
107
106
  List* arglist = ARG("$numbers", List);
108
107
  Number_Obj least;
109
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
108
+ size_t L = arglist->length();
109
+ if (L == 0) {
110
+ error("At least one argument must be passed.", pstate, traces);
111
+ }
112
+ for (size_t i = 0; i < L; ++i) {
110
113
  Expression_Obj val = arglist->value_at_index(i);
111
114
  Number_Obj xi = Cast<Number>(val);
112
115
  if (!xi) {
@@ -124,7 +127,11 @@ namespace Sass {
124
127
  {
125
128
  List* arglist = ARG("$numbers", List);
126
129
  Number_Obj greatest;
127
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
130
+ size_t L = arglist->length();
131
+ if (L == 0) {
132
+ error("At least one argument must be passed.", pstate, traces);
133
+ }
134
+ for (size_t i = 0; i < L; ++i) {
128
135
  Expression_Obj val = arglist->value_at_index(i);
129
136
  Number_Obj xi = Cast<Number>(val);
130
137
  if (!xi) {
@@ -200,11 +207,11 @@ namespace Sass {
200
207
  return SASS_MEMORY_NEW(Boolean, pstate, unitless);
201
208
  }
202
209
 
203
- Signature comparable_sig = "comparable($number-1, $number-2)";
210
+ Signature comparable_sig = "comparable($number1, $number2)";
204
211
  BUILT_IN(comparable)
205
212
  {
206
- Number_Obj n1 = ARGN("$number-1");
207
- Number_Obj n2 = ARGN("$number-2");
213
+ Number_Obj n1 = ARGN("$number1");
214
+ Number_Obj n2 = ARGN("$number2");
208
215
  if (n1->is_unitless() || n2->is_unitless()) {
209
216
  return SASS_MEMORY_NEW(Boolean, pstate, true);
210
217
  }
@@ -1,5 +1,8 @@
1
+ #include <numeric>
2
+
1
3
  #include "parser.hpp"
2
- #include "extend.hpp"
4
+ #include "extender.hpp"
5
+ #include "listize.hpp"
3
6
  #include "fn_utils.hpp"
4
7
  #include "fn_selectors.hpp"
5
8
 
@@ -13,24 +16,27 @@ namespace Sass {
13
16
  List* arglist = ARG("$selectors", List);
14
17
 
15
18
  // Not enough parameters
16
- if( arglist->length() == 0 )
17
- error("$selectors: At least one selector must be passed for `selector-nest'", pstate, traces);
19
+ if (arglist->length() == 0) {
20
+ error(
21
+ "$selectors: At least one selector must be passed for `selector-nest'",
22
+ pstate, traces);
23
+ }
18
24
 
19
25
  // Parse args into vector of selectors
20
26
  SelectorStack parsedSelectors;
21
27
  for (size_t i = 0, L = arglist->length(); i < L; ++i) {
22
28
  Expression_Obj exp = Cast<Expression>(arglist->value_at_index(i));
23
29
  if (exp->concrete_type() == Expression::NULL_VAL) {
24
- std::stringstream msg;
25
- msg << "$selectors: null is not a valid selector: it must be a string,\n";
26
- msg << "a list of strings, or a list of lists of strings for 'selector-nest'";
27
- error(msg.str(), pstate, traces);
30
+ error(
31
+ "$selectors: null is not a valid selector: it must be a string,\n"
32
+ "a list of strings, or a list of lists of strings for 'selector-nest'",
33
+ pstate, traces);
28
34
  }
29
35
  if (String_Constant_Obj str = Cast<String_Constant>(exp)) {
30
36
  str->quote_mark(0);
31
37
  }
32
38
  std::string exp_src = exp->to_string(ctx.c_options);
33
- Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces);
39
+ SelectorListObj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces);
34
40
  parsedSelectors.push_back(sel);
35
41
  }
36
42
 
@@ -39,25 +45,21 @@ namespace Sass {
39
45
  return SASS_MEMORY_NEW(Null, pstate);
40
46
  }
41
47
 
42
- // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector.
48
+ // Set the first element as the `result`, keep
49
+ // appending to as we go down the parsedSelector vector.
43
50
  SelectorStack::iterator itr = parsedSelectors.begin();
44
- Selector_List_Obj result = *itr;
51
+ SelectorListObj& result = *itr;
45
52
  ++itr;
46
53
 
47
54
  for(;itr != parsedSelectors.end(); ++itr) {
48
- Selector_List_Obj child = *itr;
49
- std::vector<Complex_Selector_Obj> exploded;
50
- selector_stack.push_back(result);
51
- Selector_List_Obj rv = child->resolve_parent_refs(selector_stack, traces);
52
- selector_stack.pop_back();
53
- for (size_t m = 0, mLen = rv->length(); m < mLen; ++m) {
54
- exploded.push_back((*rv)[m]);
55
- }
56
- result->elements(exploded);
55
+ SelectorListObj& child = *itr;
56
+ original_stack.push_back(result);
57
+ SelectorListObj rv = child->resolve_parent_refs(original_stack, traces);
58
+ result->elements(rv->elements());
59
+ original_stack.pop_back();
57
60
  }
58
61
 
59
- Listize listize;
60
- return Cast<Value>(result->perform(&listize));
62
+ return Cast<Value>(Listize::perform(result));
61
63
  }
62
64
 
63
65
  Signature selector_append_sig = "selector-append($selectors...)";
@@ -66,113 +68,96 @@ namespace Sass {
66
68
  List* arglist = ARG("$selectors", List);
67
69
 
68
70
  // Not enough parameters
69
- if( arglist->length() == 0 )
70
- error("$selectors: At least one selector must be passed for `selector-append'", pstate, traces);
71
+ if (arglist->empty()) {
72
+ error(
73
+ "$selectors: At least one selector must be "
74
+ "passed for `selector-append'",
75
+ pstate, traces);
76
+ }
71
77
 
72
78
  // Parse args into vector of selectors
73
79
  SelectorStack parsedSelectors;
80
+ parsedSelectors.push_back({});
74
81
  for (size_t i = 0, L = arglist->length(); i < L; ++i) {
75
- Expression_Obj exp = Cast<Expression>(arglist->value_at_index(i));
82
+ Expression* exp = Cast<Expression>(arglist->value_at_index(i));
76
83
  if (exp->concrete_type() == Expression::NULL_VAL) {
77
- std::stringstream msg;
78
- msg << "$selectors: null is not a valid selector: it must be a string,\n";
79
- msg << "a list of strings, or a list of lists of strings for 'selector-append'";
80
- error(msg.str(), pstate, traces);
84
+ error(
85
+ "$selectors: null is not a valid selector: it must be a string,\n"
86
+ "a list of strings, or a list of lists of strings for 'selector-append'",
87
+ pstate, traces);
81
88
  }
82
89
  if (String_Constant* str = Cast<String_Constant>(exp)) {
83
90
  str->quote_mark(0);
84
91
  }
85
92
  std::string exp_src = exp->to_string();
86
- Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces,
87
- exp->pstate(), pstate.src,
88
- /*allow_parent=*/false);
89
-
90
- parsedSelectors.push_back(sel);
91
- }
92
-
93
- // Nothing to do
94
- if( parsedSelectors.empty() ) {
95
- return SASS_MEMORY_NEW(Null, pstate);
96
- }
97
-
98
- // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector.
99
- SelectorStack::iterator itr = parsedSelectors.begin();
100
- Selector_List_Obj result = *itr;
101
- ++itr;
102
-
103
- for(;itr != parsedSelectors.end(); ++itr) {
104
- Selector_List_Obj child = *itr;
105
- std::vector<Complex_Selector_Obj> newElements;
106
-
107
- // For every COMPLEX_SELECTOR in `result`
108
- // For every COMPLEX_SELECTOR in `child`
109
- // let parentSeqClone equal a copy of result->elements[i]
110
- // let childSeq equal child->elements[j]
111
- // Append all of childSeq head elements into parentSeqClone
112
- // Set the innermost tail of parentSeqClone, to childSeq's tail
113
- // Replace result->elements with newElements
114
- for (size_t i = 0, resultLen = result->length(); i < resultLen; ++i) {
115
- for (size_t j = 0, childLen = child->length(); j < childLen; ++j) {
116
- Complex_Selector_Obj parentSeqClone = SASS_MEMORY_CLONE((*result)[i]);
117
- Complex_Selector_Obj childSeq = (*child)[j];
118
- Complex_Selector_Obj base = childSeq->tail();
119
-
120
- // Must be a simple sequence
121
- if( childSeq->combinator() != Complex_Selector::Combinator::ANCESTOR_OF ) {
122
- error("Can't append \"" + childSeq->to_string() + "\" to \"" +
123
- parentSeqClone->to_string() + "\" for `selector-append'", pstate, traces);
124
- }
93
+ SelectorListObj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces,
94
+ exp->pstate(), pstate.src,
95
+ /*allow_parent=*/true);
125
96
 
126
- // Cannot be a Universal selector
127
- Type_Selector_Obj pType = Cast<Type_Selector>(childSeq->head()->first());
128
- if(pType && pType->name() == "*") {
129
- error("Can't append \"" + childSeq->to_string() + "\" to \"" +
130
- parentSeqClone->to_string() + "\" for `selector-append'", pstate, traces);
131
- }
97
+ for (auto& complex : sel->elements()) {
98
+ if (complex->empty()) {
99
+ complex->append(SASS_MEMORY_NEW(CompoundSelector, "[phony]"));
100
+ }
101
+ if (CompoundSelector* comp = Cast<CompoundSelector>(complex->first())) {
102
+ comp->hasRealParent(true);
103
+ complex->chroots(true);
104
+ }
105
+ }
132
106
 
133
- // TODO: Add check for namespace stuff
107
+ if (parsedSelectors.size() > 1) {
134
108
 
135
- Complex_Selector* lastComponent = parentSeqClone->mutable_last();
136
- if (lastComponent->head() == nullptr) {
137
- std::string msg = "Parent \"" + parentSeqClone->to_string() + "\" is incompatible with \"" + base->to_string() + "\"";
138
- error(msg, pstate, traces);
109
+ if (!sel->has_real_parent_ref()) {
110
+ auto parent = parsedSelectors.back();
111
+ for (auto& complex : parent->elements()) {
112
+ if (CompoundSelector* comp = Cast<CompoundSelector>(complex->first())) {
113
+ comp->hasRealParent(false);
114
+ }
139
115
  }
140
- lastComponent->head()->concat(base->head());
141
- lastComponent->tail(base->tail());
142
-
143
- newElements.push_back(parentSeqClone);
116
+ error("Can't append \"" + sel->to_string() + "\" to \"" +
117
+ parent->to_string() + "\" for `selector-append'",
118
+ pstate, traces);
144
119
  }
120
+
121
+ // Build the resolved stack from the left. It's cheaper to directly
122
+ // calculate and update each resolved selcted from the left, than to
123
+ // recursively calculate them from the right side, as we would need
124
+ // to go through the whole stack depth to build the final results.
125
+ // E.g. 'a', 'b', 'x, y' => 'a' => 'a b' => 'a b x, a b y'
126
+ // vs 'a', 'b', 'x, y' => 'x' => 'b x' => 'a b x', 'y' ...
127
+ parsedSelectors.push_back(sel->resolve_parent_refs(parsedSelectors, traces, true));
128
+ }
129
+ else {
130
+ parsedSelectors.push_back(sel);
145
131
  }
132
+ }
146
133
 
147
- result->elements(newElements);
134
+ // Nothing to do
135
+ if( parsedSelectors.empty() ) {
136
+ return SASS_MEMORY_NEW(Null, pstate);
148
137
  }
149
138
 
150
- Listize listize;
151
- return Cast<Value>(result->perform(&listize));
139
+ return Cast<Value>(Listize::perform(parsedSelectors.back()));
152
140
  }
153
141
 
154
142
  Signature selector_unify_sig = "selector-unify($selector1, $selector2)";
155
143
  BUILT_IN(selector_unify)
156
144
  {
157
- Selector_List_Obj selector1 = ARGSELS("$selector1");
158
- Selector_List_Obj selector2 = ARGSELS("$selector2");
159
-
160
- Selector_List_Obj result = selector1->unify_with(selector2);
161
- Listize listize;
162
- return Cast<Value>(result->perform(&listize));
145
+ SelectorListObj selector1 = ARGSELS("$selector1");
146
+ SelectorListObj selector2 = ARGSELS("$selector2");
147
+ SelectorListObj result = selector1->unifyWith(selector2);
148
+ return Cast<Value>(Listize::perform(result));
163
149
  }
164
150
 
165
151
  Signature simple_selectors_sig = "simple-selectors($selector)";
166
152
  BUILT_IN(simple_selectors)
167
153
  {
168
- Compound_Selector_Obj sel = ARGSEL("$selector");
154
+ CompoundSelectorObj sel = ARGSEL("$selector");
169
155
 
170
156
  List* l = SASS_MEMORY_NEW(List, sel->pstate(), sel->length(), SASS_COMMA);
171
157
 
172
158
  for (size_t i = 0, L = sel->length(); i < L; ++i) {
173
- Simple_Selector_Obj ss = (*sel)[i];
159
+ const SimpleSelectorObj& ss = sel->get(i);
174
160
  std::string ss_string = ss->to_string() ;
175
-
176
161
  l->append(SASS_MEMORY_NEW(String_Quoted, ss->pstate(), ss_string));
177
162
  }
178
163
 
@@ -182,51 +167,36 @@ namespace Sass {
182
167
  Signature selector_extend_sig = "selector-extend($selector, $extendee, $extender)";
183
168
  BUILT_IN(selector_extend)
184
169
  {
185
- Selector_List_Obj selector = ARGSELS("$selector");
186
- Selector_List_Obj extendee = ARGSELS("$extendee");
187
- Selector_List_Obj extender = ARGSELS("$extender");
188
-
189
- Subset_Map subset_map;
190
- extender->populate_extends(extendee, subset_map);
191
- Extend extend(subset_map);
192
-
193
- Selector_List_Obj result = extend.extendSelectorList(selector, false);
194
-
195
- Listize listize;
196
- return Cast<Value>(result->perform(&listize));
170
+ SelectorListObj selector = ARGSELS("$selector");
171
+ SelectorListObj target = ARGSELS("$extendee");
172
+ SelectorListObj source = ARGSELS("$extender");
173
+ SelectorListObj result = Extender::extend(selector, source, target, traces);
174
+ return Cast<Value>(Listize::perform(result));
197
175
  }
198
176
 
199
177
  Signature selector_replace_sig = "selector-replace($selector, $original, $replacement)";
200
178
  BUILT_IN(selector_replace)
201
179
  {
202
- Selector_List_Obj selector = ARGSELS("$selector");
203
- Selector_List_Obj original = ARGSELS("$original");
204
- Selector_List_Obj replacement = ARGSELS("$replacement");
205
- Subset_Map subset_map;
206
- replacement->populate_extends(original, subset_map);
207
- Extend extend(subset_map);
208
-
209
- Selector_List_Obj result = extend.extendSelectorList(selector, true);
210
-
211
- Listize listize;
212
- return Cast<Value>(result->perform(&listize));
180
+ SelectorListObj selector = ARGSELS("$selector");
181
+ SelectorListObj target = ARGSELS("$original");
182
+ SelectorListObj source = ARGSELS("$replacement");
183
+ SelectorListObj result = Extender::replace(selector, source, target, traces);
184
+ return Cast<Value>(Listize::perform(result));
213
185
  }
214
186
 
215
187
  Signature selector_parse_sig = "selector-parse($selector)";
216
188
  BUILT_IN(selector_parse)
217
189
  {
218
- Selector_List_Obj sel = ARGSELS("$selector");
219
-
220
- Listize listize;
221
- return Cast<Value>(sel->perform(&listize));
190
+ SelectorListObj selector = ARGSELS("$selector");
191
+ return Cast<Value>(Listize::perform(selector));
222
192
  }
223
193
 
224
194
  Signature is_superselector_sig = "is-superselector($super, $sub)";
225
195
  BUILT_IN(is_superselector)
226
196
  {
227
- Selector_List_Obj sel_sup = ARGSELS("$super");
228
- Selector_List_Obj sel_sub = ARGSELS("$sub");
229
- bool result = sel_sup->is_superselector_of(sel_sub);
197
+ SelectorListObj sel_sup = ARGSELS("$super");
198
+ SelectorListObj sel_sub = ARGSELS("$sub");
199
+ bool result = sel_sup->isSuperselectorOf(sel_sub);
230
200
  return SASS_MEMORY_NEW(Boolean, pstate, result);
231
201
  }
232
202