sassc 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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