sassc 1.10.1 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -2
  3. data/ext/libsass/.github/CONTRIBUTING.md +65 -0
  4. data/ext/libsass/.github/ISSUE_TEMPLATE.md +29 -0
  5. data/ext/libsass/Makefile +8 -3
  6. data/ext/libsass/Makefile.conf +28 -22
  7. data/ext/libsass/Readme.md +14 -7
  8. data/ext/libsass/configure.ac +5 -8
  9. data/ext/libsass/docs/api-context-internal.md +3 -0
  10. data/ext/libsass/docs/api-context.md +7 -0
  11. data/ext/libsass/docs/api-doc.md +4 -0
  12. data/ext/libsass/docs/api-importer.md +2 -0
  13. data/ext/libsass/docs/api-value-example.md +55 -0
  14. data/ext/libsass/docs/api-value.md +49 -22
  15. data/ext/libsass/docs/implementations.md +4 -0
  16. data/ext/libsass/include/sass/base.h +5 -4
  17. data/ext/libsass/include/sass/context.h +3 -0
  18. data/ext/libsass/include/sass/values.h +28 -27
  19. data/ext/libsass/include/sass/version.h +1 -1
  20. data/ext/libsass/include/sass2scss.h +1 -1
  21. data/ext/libsass/script/ci-build-libsass +3 -3
  22. data/ext/libsass/script/ci-install-deps +12 -3
  23. data/ext/libsass/src/ast.cpp +321 -212
  24. data/ext/libsass/src/ast.hpp +273 -165
  25. data/ext/libsass/src/ast_factory.hpp +4 -5
  26. data/ext/libsass/src/ast_fwd_decl.hpp +8 -7
  27. data/ext/libsass/src/bind.cpp +2 -7
  28. data/ext/libsass/src/bind.hpp +0 -1
  29. data/ext/libsass/src/check_nesting.cpp +379 -0
  30. data/ext/libsass/src/check_nesting.hpp +60 -0
  31. data/ext/libsass/src/constants.cpp +7 -6
  32. data/ext/libsass/src/constants.hpp +2 -1
  33. data/ext/libsass/src/context.cpp +7 -1
  34. data/ext/libsass/src/context.hpp +1 -1
  35. data/ext/libsass/src/cssize.cpp +76 -32
  36. data/ext/libsass/src/cssize.hpp +7 -8
  37. data/ext/libsass/src/debugger.hpp +70 -40
  38. data/ext/libsass/src/error_handling.cpp +15 -2
  39. data/ext/libsass/src/error_handling.hpp +19 -0
  40. data/ext/libsass/src/eval.cpp +107 -161
  41. data/ext/libsass/src/eval.hpp +12 -8
  42. data/ext/libsass/src/expand.cpp +81 -74
  43. data/ext/libsass/src/expand.hpp +13 -12
  44. data/ext/libsass/src/extend.cpp +149 -142
  45. data/ext/libsass/src/extend.hpp +10 -3
  46. data/ext/libsass/src/file.cpp +2 -1
  47. data/ext/libsass/src/functions.cpp +96 -59
  48. data/ext/libsass/src/functions.hpp +2 -2
  49. data/ext/libsass/src/inspect.cpp +33 -45
  50. data/ext/libsass/src/inspect.hpp +7 -7
  51. data/ext/libsass/src/json.cpp +17 -5
  52. data/ext/libsass/src/lexer.cpp +3 -3
  53. data/ext/libsass/src/listize.cpp +10 -10
  54. data/ext/libsass/src/listize.hpp +3 -3
  55. data/ext/libsass/src/node.cpp +30 -30
  56. data/ext/libsass/src/node.hpp +13 -13
  57. data/ext/libsass/src/operation.hpp +21 -19
  58. data/ext/libsass/src/output.cpp +48 -103
  59. data/ext/libsass/src/output.hpp +0 -1
  60. data/ext/libsass/src/parser.cpp +161 -133
  61. data/ext/libsass/src/parser.hpp +10 -7
  62. data/ext/libsass/src/remove_placeholders.cpp +6 -6
  63. data/ext/libsass/src/remove_placeholders.hpp +1 -1
  64. data/ext/libsass/src/sass.cpp +21 -0
  65. data/ext/libsass/src/sass.hpp +8 -1
  66. data/ext/libsass/src/sass2scss.cpp +14 -3
  67. data/ext/libsass/src/sass_context.cpp +69 -24
  68. data/ext/libsass/src/sass_context.hpp +3 -0
  69. data/ext/libsass/src/source_map.cpp +22 -10
  70. data/ext/libsass/src/to_value.cpp +2 -2
  71. data/ext/libsass/src/to_value.hpp +1 -1
  72. data/ext/libsass/src/units.hpp +3 -1
  73. data/ext/libsass/src/util.cpp +20 -16
  74. data/ext/libsass/src/util.hpp +2 -1
  75. data/ext/libsass/win/libsass.targets +2 -0
  76. data/ext/libsass/win/libsass.vcxproj.filters +6 -0
  77. data/lib/sassc/engine.rb +5 -0
  78. data/lib/sassc/native/native_functions_api.rb +13 -1
  79. data/lib/sassc/script/value_conversion.rb +11 -1
  80. data/lib/sassc/script/value_conversion/list.rb +23 -0
  81. data/lib/sassc/version.rb +1 -1
  82. data/test/engine_test.rb +18 -2
  83. data/test/functions_test.rb +30 -0
  84. data/test/native_test.rb +1 -1
  85. metadata +8 -3
@@ -35,11 +35,19 @@ namespace Sass {
35
35
  : Base(pstate), fn(fn), arg(arg), type(type), value(value)
36
36
  {
37
37
  msg = arg + ": \"";
38
- msg += value->to_string(Sass_Inspect_Options());
38
+ if (value) msg += value->to_string(Sass_Inspect_Options());
39
39
  msg += "\" is not a " + type;
40
40
  msg += " for `" + fn + "'";
41
41
  }
42
42
 
43
+ MissingArgument::MissingArgument(ParserState pstate, std::string fn, std::string arg, std::string fntype)
44
+ : Base(pstate), fn(fn), arg(arg), fntype(fntype)
45
+ {
46
+ msg = fntype + " " + fn;
47
+ msg += " is missing argument ";
48
+ msg += arg + ".";
49
+ }
50
+
43
51
  InvalidSyntax::InvalidSyntax(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack)
44
52
  : Base(pstate, msg, import_stack)
45
53
  { }
@@ -74,7 +82,6 @@ namespace Sass {
74
82
  : Base(org.pstate()), dup(dup), org(org)
75
83
  {
76
84
  msg = "Duplicate key ";
77
- dup.get_duplicate_key()->is_delayed(false);
78
85
  msg += dup.get_duplicate_key()->inspect();
79
86
  msg += " in map (";
80
87
  msg += org.inspect();
@@ -97,6 +104,12 @@ namespace Sass {
97
104
  msg += " isn't a valid CSS value.";
98
105
  }
99
106
 
107
+ StackError::StackError(const AST_Node& node)
108
+ : Base(node.pstate()), node(node)
109
+ {
110
+ msg = "stack level too deep";
111
+ }
112
+
100
113
  IncompatibleUnits::IncompatibleUnits(const Number& lhs, const Number& rhs)
101
114
  : lhs(lhs), rhs(rhs)
102
115
  {
@@ -45,6 +45,16 @@ namespace Sass {
45
45
  virtual ~InvalidParent() throw() {};
46
46
  };
47
47
 
48
+ class MissingArgument : public Base {
49
+ protected:
50
+ std::string fn;
51
+ std::string arg;
52
+ std::string fntype;
53
+ public:
54
+ MissingArgument(ParserState pstate, std::string fn, std::string arg, std::string fntype);
55
+ virtual ~MissingArgument() throw() {};
56
+ };
57
+
48
58
  class InvalidArgumentType : public Base {
49
59
  protected:
50
60
  std::string fn;
@@ -115,6 +125,15 @@ namespace Sass {
115
125
  virtual ~InvalidValue() throw() {};
116
126
  };
117
127
 
128
+ class StackError : public Base {
129
+ protected:
130
+ const AST_Node& node;
131
+ public:
132
+ StackError(const AST_Node& node);
133
+ virtual const char* errtype() const { return "SystemStackError"; }
134
+ virtual ~StackError() throw() {};
135
+ };
136
+
118
137
  class IncompatibleUnits : public OperationError {
119
138
  protected:
120
139
  const Number& lhs;
@@ -31,7 +31,14 @@ namespace Sass {
31
31
  inline double sub(double x, double y) { return x - y; }
32
32
  inline double mul(double x, double y) { return x * y; }
33
33
  inline double div(double x, double y) { return x / y; } // x/0 checked by caller
34
- inline double mod(double x, double y) { return std::abs(std::fmod(x, y)); } // x/0 checked by caller
34
+ inline double mod(double x, double y) { // x/0 checked by caller
35
+ if ((x > 0 && y < 0) || (x < 0 && y > 0)) {
36
+ double ret = std::fmod(x, y);
37
+ return ret ? ret + y : ret;
38
+ } else {
39
+ return std::fmod(x, y);
40
+ }
41
+ }
35
42
  typedef double (*bop)(double, double);
36
43
  bop ops[Sass_OP::NUM_OPS] = {
37
44
  0, 0, // and, or
@@ -41,7 +48,9 @@ namespace Sass {
41
48
 
42
49
  Eval::Eval(Expand& exp)
43
50
  : exp(exp),
44
- ctx(exp.ctx)
51
+ ctx(exp.ctx),
52
+ force(false),
53
+ is_in_comment(false)
45
54
  { }
46
55
  Eval::~Eval() { }
47
56
 
@@ -55,7 +64,7 @@ namespace Sass {
55
64
  return exp.environment();
56
65
  }
57
66
 
58
- Selector_List* Eval::selector()
67
+ CommaSequence_Selector* Eval::selector()
59
68
  {
60
69
  return exp.selector();
61
70
  }
@@ -221,7 +230,7 @@ namespace Sass {
221
230
  if (expr->concrete_type() == Expression::MAP) {
222
231
  map = static_cast<Map*>(expr);
223
232
  }
224
- else if (Selector_List* ls = dynamic_cast<Selector_List*>(expr)) {
233
+ else if (CommaSequence_Selector* ls = dynamic_cast<CommaSequence_Selector*>(expr)) {
225
234
  Listize listize(ctx.mem);
226
235
  list = dynamic_cast<List*>(ls->perform(&listize));
227
236
  }
@@ -255,7 +264,7 @@ namespace Sass {
255
264
  }
256
265
  }
257
266
  else {
258
- if (list->length() == 1 && dynamic_cast<Selector_List*>(list)) {
267
+ if (list->length() == 1 && dynamic_cast<CommaSequence_Selector*>(list)) {
259
268
  list = dynamic_cast<Vectorized<Expression*>*>(list);
260
269
  }
261
270
  for (size_t i = 0, L = list->length(); i < L; ++i) {
@@ -436,7 +445,7 @@ namespace Sass {
436
445
  Expression* key = (*l)[i+0]->perform(this);
437
446
  Expression* val = (*l)[i+1]->perform(this);
438
447
  // make sure the color key never displays its real name
439
- key->is_delayed(true);
448
+ key->is_delayed(true); // verified
440
449
  *lm << std::make_pair(key, val);
441
450
  }
442
451
  if (lm->has_duplicate_key()) {
@@ -497,21 +506,13 @@ namespace Sass {
497
506
  String_Schema* ret_schema = 0;
498
507
  enum Sass_OP op_type = b->type();
499
508
 
500
- // don't eval delayed expressions (the '/' when used as a separator)
501
- if (op_type == Sass_OP::DIV && b->is_delayed()) {
502
- b->right(b->right()->perform(this));
503
- b->left(b->left()->perform(this));
504
- return b;
505
- }
506
-
507
509
  // only the last item will be used to eval the binary expression
508
510
  if (String_Schema* s_l = dynamic_cast<String_Schema*>(b->left())) {
509
511
  if (!s_l->has_interpolant() && (!s_l->is_right_interpolant())) {
510
- ret_schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, s_l->pstate());
512
+ ret_schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, b->pstate());
511
513
  Binary_Expression* bin_ex = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, b->pstate(),
512
514
  b->op(), s_l->last(), b->right());
513
- bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed());
514
- // bin_ex->is_interpolant(b->left()->is_interpolant());
515
+ bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // unverified
515
516
  for (size_t i = 0; i < s_l->length() - 1; ++i) {
516
517
  *ret_schema << s_l->at(i)->perform(this);
517
518
  }
@@ -521,11 +522,10 @@ namespace Sass {
521
522
  }
522
523
  if (String_Schema* s_r = dynamic_cast<String_Schema*>(b->right())) {
523
524
  if (!s_r->has_interpolant() && (!s_r->is_left_interpolant() || op_type == Sass_OP::DIV)) {
524
- ret_schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, s_r->pstate());
525
+ ret_schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, b->pstate());
525
526
  Binary_Expression* bin_ex = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, b->pstate(),
526
527
  b->op(), b->left(), s_r->first());
527
- bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed());
528
- // if (op_type == Sass_OP::SUB && b->is_right_interpolant()) bin_ex->is_interpolant(true);
528
+ bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // verified
529
529
  *ret_schema << bin_ex->perform(this);
530
530
  for (size_t i = 1; i < s_r->length(); ++i) {
531
531
  *ret_schema << s_r->at(i)->perform(this);
@@ -535,34 +535,18 @@ namespace Sass {
535
535
  }
536
536
 
537
537
 
538
+ b = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, *b);
538
539
  // don't eval delayed expressions (the '/' when used as a separator)
539
- if (op_type == Sass_OP::DIV && b->is_delayed()) {
540
+ if (!force && op_type == Sass_OP::DIV && b->is_delayed()) {
540
541
  b->right(b->right()->perform(this));
541
542
  b->left(b->left()->perform(this));
542
543
  return b;
543
544
  }
544
545
 
545
- // b->is_delayed(false);
546
546
  Expression* lhs = b->left();
547
547
  Expression* rhs = b->right();
548
548
 
549
- // bool delay_lhs = false;
550
- // bool delay_rhs = false;
551
-
552
- if (String_Schema* schema = dynamic_cast<String_Schema*>(lhs)) {
553
- if (schema->is_right_interpolant()) {
554
- b->is_delayed(true);
555
- // delay_lhs = true;
556
- }
557
- }
558
- if (String_Schema* schema = dynamic_cast<String_Schema*>(rhs)) {
559
- if (schema->is_left_interpolant()) {
560
- b->is_delayed(true);
561
- // delay_rhs = true;
562
- }
563
- }
564
-
565
- // maybe fully evaluate structure
549
+ // fully evaluate their values
566
550
  if (op_type == Sass_OP::EQ ||
567
551
  op_type == Sass_OP::NEQ ||
568
552
  op_type == Sass_OP::GT ||
@@ -570,43 +554,16 @@ namespace Sass {
570
554
  op_type == Sass_OP::LT ||
571
555
  op_type == Sass_OP::LTE)
572
556
  {
573
-
574
- if (String_Schema* schema = dynamic_cast<String_Schema*>(lhs)) {
575
- if (schema->has_interpolants()) {
576
- b->is_delayed(true);
577
- }
578
- }
579
- if (String_Schema* schema = dynamic_cast<String_Schema*>(rhs)) {
580
- if (schema->has_interpolants()) {
581
- b->is_delayed(true);
582
- }
583
- }
584
- lhs->is_expanded(false);
585
- lhs->set_delayed(false);
586
- lhs = lhs->perform(this);
557
+ LOCAL_FLAG(force, true);
587
558
  lhs->is_expanded(false);
588
559
  lhs->set_delayed(false);
589
560
  lhs = lhs->perform(this);
590
561
  rhs->is_expanded(false);
591
562
  rhs->set_delayed(false);
592
563
  rhs = rhs->perform(this);
593
- rhs->is_expanded(false);
594
- rhs->set_delayed(false);
595
- rhs = rhs->perform(this);
596
- }
597
- else
598
- {
599
- // rhs->set_delayed(false);
600
- // rhs = rhs->perform(this);
601
564
  }
602
-
603
- // if one of the operands is a '/' then make sure it's evaluated
604
- lhs = lhs->perform(this);
605
- lhs->is_delayed(false);
606
- while (typeid(*lhs) == typeid(Binary_Expression)) {
607
- Binary_Expression* lhs_ex = static_cast<Binary_Expression*>(lhs);
608
- if (lhs_ex->type() == Sass_OP::DIV && lhs_ex->is_delayed()) break;
609
- lhs = Eval::operator()(lhs_ex);
565
+ else {
566
+ lhs = lhs->perform(this);
610
567
  }
611
568
 
612
569
  switch (op_type) {
@@ -624,19 +581,6 @@ namespace Sass {
624
581
  // not a logical connective, so go ahead and eval the rhs
625
582
  rhs = rhs->perform(this);
626
583
 
627
- // upgrade string to number if possible (issue #948)
628
- if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL) {
629
- if (String_Constant* str = dynamic_cast<String_Constant*>(rhs)) {
630
- std::string value(str->value());
631
- const char* start = value.c_str();
632
- if (Prelexer::sequence < Prelexer::number >(start) != 0) {
633
- rhs = SASS_MEMORY_NEW(ctx.mem, Textual, rhs->pstate(), Textual::DIMENSION, str->value());
634
- rhs->is_delayed(false); rhs = rhs->perform(this);
635
- }
636
- }
637
- }
638
-
639
-
640
584
  Expression::Concrete_Type l_type = lhs->concrete_type();
641
585
  Expression::Concrete_Type r_type = rhs->concrete_type();
642
586
 
@@ -662,16 +606,16 @@ namespace Sass {
662
606
  std::string value(str->value());
663
607
  const char* start = value.c_str();
664
608
  if (Prelexer::sequence < Prelexer::dimension, Prelexer::end_of_file >(start) != 0) {
665
- lhs = SASS_MEMORY_NEW(ctx.mem, Textual, lhs->pstate(), Textual::DIMENSION, str->value());
666
- lhs->is_delayed(false); lhs = lhs->perform(this);
609
+ lhs = SASS_MEMORY_NEW(ctx.mem, Textual, b->pstate(), Textual::DIMENSION, str->value());
610
+ lhs = lhs->perform(this);
667
611
  }
668
612
  }
669
613
  if (String_Constant* str = dynamic_cast<String_Constant*>(rhs)) {
670
614
  std::string value(str->value());
671
615
  const char* start = value.c_str();
672
616
  if (Prelexer::sequence < Prelexer::number >(start) != 0) {
673
- rhs = SASS_MEMORY_NEW(ctx.mem, Textual, rhs->pstate(), Textual::DIMENSION, str->value());
674
- rhs->is_delayed(false); rhs = rhs->perform(this);
617
+ rhs = SASS_MEMORY_NEW(ctx.mem, Textual, b->pstate(), Textual::DIMENSION, str->value());
618
+ rhs = rhs->perform(this);
675
619
  }
676
620
  }
677
621
  }
@@ -699,7 +643,7 @@ namespace Sass {
699
643
  str += b->separator();
700
644
  if (b->op().ws_after) str += " ";
701
645
  str += v_r->to_string(ctx.c_options);
702
- String_Constant* val = SASS_MEMORY_NEW(ctx.mem, String_Constant, lhs->pstate(), str);
646
+ String_Constant* val = SASS_MEMORY_NEW(ctx.mem, String_Constant, b->pstate(), str);
703
647
  val->is_interpolant(b->left()->has_interpolant());
704
648
  return val;
705
649
  }
@@ -760,6 +704,13 @@ namespace Sass {
760
704
  b->is_interpolant();
761
705
  if (op_type == Sass_OP::SUB) interpolant = false;
762
706
  // if (op_type == Sass_OP::DIV) interpolant = true;
707
+ // check for type violations
708
+ if (l_type == Expression::MAP) {
709
+ throw Exception::InvalidValue(*v_l);
710
+ }
711
+ if (r_type == Expression::MAP) {
712
+ throw Exception::InvalidValue(*v_r);
713
+ }
763
714
  Value* ex = op_strings(ctx.mem, b->op(), *v_l, *v_r, ctx.c_options, &pstate, !interpolant); // pass true to compress
764
715
  if (String_Constant* str = dynamic_cast<String_Constant*>(ex))
765
716
  {
@@ -815,7 +766,20 @@ namespace Sass {
815
766
  if (operand->concrete_type() == Expression::NULL_VAL && dynamic_cast<Variable*>(u->operand())) {
816
767
  u->operand(SASS_MEMORY_NEW(ctx.mem, String_Quoted, u->pstate(), ""));
817
768
  }
818
- else u->operand(operand);
769
+ // Never apply unary opertions on colors @see #2140
770
+ else if (operand->concrete_type() == Expression::COLOR) {
771
+ Color* c = dynamic_cast<Color*>(operand);
772
+
773
+ // Use the color name if this was eval with one
774
+ if (c->disp().length() > 0) {
775
+ operand = SASS_MEMORY_NEW(ctx.mem, String_Constant, operand->pstate(), c->disp());
776
+ u->operand(operand);
777
+ }
778
+ }
779
+ else {
780
+ u->operand(operand);
781
+ }
782
+
819
783
  String_Constant* result = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
820
784
  u->pstate(),
821
785
  u->inspect());
@@ -837,26 +801,12 @@ namespace Sass {
837
801
  std::string full_name(name + "[f]");
838
802
  Arguments* args = SASS_MEMORY_NEW(ctx.mem, Arguments, *c->arguments());
839
803
 
840
- // handle call here if valid arg
841
- // otherwise we eval arguments to early
842
- if (name == "call" && args->length() > 0) {
843
- Expression* redirect = args->at(0)->perform(this);
844
- args->erase(args->begin());
845
- Function_Call* lit = SASS_MEMORY_NEW(ctx.mem, Function_Call,
846
- c->pstate(),
847
- unquote(redirect->to_string()),
848
- args);
849
- return operator()(lit);
850
- }
851
-
852
804
  Env* env = environment();
853
805
  if (!env->has(full_name)) {
854
806
  if (!env->has("*[f]")) {
855
- // just pass it through as a literal
856
- for (Argument* arg : *args) {
857
- if (Binary_Expression* b = dynamic_cast<Binary_Expression*>(arg->value())) {
858
- b->reset_whitespace();
859
- arg->is_delayed(b->can_delay()); // delay
807
+ for (Argument* arg : args->elements()) {
808
+ if (List* ls = dynamic_cast<List*>(arg->value())) {
809
+ if (ls->size() == 0) error("() isn't a valid CSS value.", c->pstate());
860
810
  }
861
811
  }
862
812
  args = static_cast<Arguments*>(args->perform(this));
@@ -878,16 +828,26 @@ namespace Sass {
878
828
  }
879
829
  }
880
830
 
831
+ // further delay for calls
832
+ if (full_name != "call[f]") {
833
+ args->set_delayed(false); // verified
834
+ }
881
835
  if (full_name != "if[f]") {
882
836
  args = static_cast<Arguments*>(args->perform(this));
883
837
  }
884
-
885
838
  Definition* def = static_cast<Definition*>((*env)[full_name]);
886
839
 
887
840
  if (def->is_overload_stub()) {
888
841
  std::stringstream ss;
889
- ss << full_name
890
- << args->length();
842
+ size_t L = args->length();
843
+ // account for rest arguments
844
+ if (args->has_rest_argument() && args->length() > 0) {
845
+ // get the rest arguments list
846
+ List* rest = dynamic_cast<List*>(args->last()->value());
847
+ // arguments before rest argument plus rest
848
+ if (rest) L += rest->length() - 1;
849
+ }
850
+ ss << full_name << L;
891
851
  full_name = ss.str();
892
852
  std::string resolved_name(full_name);
893
853
  if (!env->has(resolved_name)) error("overloaded function `" + std::string(c->name()) + "` given wrong number of arguments", c->pstate());
@@ -908,8 +868,8 @@ namespace Sass {
908
868
  Backtrace here(backtrace(), c->pstate(), ", in function `" + c->name() + "`");
909
869
  exp.backtrace_stack.push_back(&here);
910
870
  // eval the body if user-defined or special, invoke underlying CPP function if native
911
- if (body && !Prelexer::re_special_fun(c->name().c_str())) { result = body->perform(this); }
912
- else if (func) { result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace()); }
871
+ if (body && !Prelexer::re_special_fun(name.c_str())) { result = body->perform(this); }
872
+ else if (func) { result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace(), exp.selector_stack); }
913
873
  if (!result) error(std::string("Function ") + c->name() + " did not return a value", c->pstate());
914
874
  exp.backtrace_stack.pop_back();
915
875
  }
@@ -960,8 +920,7 @@ namespace Sass {
960
920
  if (result->pstate().file == std::string::npos)
961
921
  result->pstate(c->pstate());
962
922
 
963
- result->is_delayed(result->concrete_type() == Expression::STRING);
964
- if (!result->is_delayed()) result = result->perform(this);
923
+ result = result->perform(this);
965
924
  result->is_interpolant(c->is_interpolant());
966
925
  exp.env_stack.pop_back();
967
926
  return result;
@@ -990,35 +949,13 @@ namespace Sass {
990
949
  value = SASS_MEMORY_NEW(ctx.mem, Number, *static_cast<Number*>(value));
991
950
  static_cast<Number*>(value)->zero(true);
992
951
  }
993
- else if (value->concrete_type() == Expression::STRING) {
994
- if (auto str = dynamic_cast<String_Quoted*>(value)) {
995
- value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, *str);
996
- } else if (auto str = dynamic_cast<String_Constant*>(value)) {
997
- value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, str->pstate(), str->value());
998
- }
999
- }
1000
- else if (value->concrete_type() == Expression::LIST) {
1001
- value = SASS_MEMORY_NEW(ctx.mem, List, *static_cast<List*>(value));
1002
- }
1003
- else if (value->concrete_type() == Expression::MAP) {
1004
- value = SASS_MEMORY_NEW(ctx.mem, Map, *static_cast<Map*>(value));
1005
- }
1006
- else if (value->concrete_type() == Expression::BOOLEAN) {
1007
- value = SASS_MEMORY_NEW(ctx.mem, Boolean, *static_cast<Boolean*>(value));
1008
- }
1009
- else if (value->concrete_type() == Expression::COLOR) {
1010
- value = SASS_MEMORY_NEW(ctx.mem, Color, *static_cast<Color*>(value));
1011
- }
1012
- else if (value->concrete_type() == Expression::NULL_VAL) {
1013
- value = SASS_MEMORY_NEW(ctx.mem, Null, value->pstate());
1014
- }
1015
- else if (value->concrete_type() == Expression::SELECTOR) {
1016
- value = value->perform(this); // ->perform(&listize);
1017
- }
1018
952
 
1019
953
  value->is_interpolant(v->is_interpolant());
1020
- value->is_expanded(false);
1021
- return value->perform(this);
954
+ if (force) value->is_expanded(false);
955
+ value->set_delayed(false); // verified
956
+ value = value->perform(this);
957
+ if(!force) (*env)[name] = value;
958
+ return value;
1022
959
  }
1023
960
 
1024
961
  Expression* Eval::operator()(Textual* t)
@@ -1095,6 +1032,11 @@ namespace Sass {
1095
1032
  return result;
1096
1033
  }
1097
1034
 
1035
+ Expression* Eval::operator()(Color* c)
1036
+ {
1037
+ return c;
1038
+ }
1039
+
1098
1040
  Expression* Eval::operator()(Number* n)
1099
1041
  {
1100
1042
  return n;
@@ -1153,14 +1095,23 @@ namespace Sass {
1153
1095
  bool is_null = dynamic_cast<Null*>(item) != 0; // rl != ""
1154
1096
  if (!is_null) *ll << SASS_MEMORY_NEW(ctx.mem, String_Quoted, item->pstate(), rl);
1155
1097
  }
1156
- res += (ll->to_string(ctx.c_options));
1098
+ // Check indicates that we probably should not get a list
1099
+ // here. Normally single list items are already unwrapped.
1100
+ if (l->size() > 1) {
1101
+ // string_to_output would fail "#{'_\a' '_\a'}";
1102
+ std::string str(ll->to_string(ctx.c_options));
1103
+ newline_to_space(str); // replace directly
1104
+ res += str; // append to result string
1105
+ } else {
1106
+ res += (ll->to_string(ctx.c_options));
1107
+ }
1157
1108
  ll->is_interpolant(l->is_interpolant());
1158
1109
  }
1159
1110
 
1160
1111
  // Value
1161
1112
  // Textual
1162
1113
  // Function_Call
1163
- // Selector_List
1114
+ // CommaSequence_Selector
1164
1115
  // String_Quoted
1165
1116
  // String_Constant
1166
1117
  // Parent_Selector
@@ -1201,7 +1152,7 @@ namespace Sass {
1201
1152
  bool is_quoted = dynamic_cast<String_Quoted*>((*s)[i]) != NULL;
1202
1153
  if (was_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; }
1203
1154
  else if (i > 0 && is_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; }
1204
- Expression* ex = (*s)[i]->is_delayed() ? (*s)[i] : (*s)[i]->perform(this);
1155
+ Expression* ex = (*s)[i]->perform(this);
1205
1156
  interpolation(ctx, res, ex, into_quotes, ex->is_interpolant());
1206
1157
  was_quoted = dynamic_cast<String_Quoted*>((*s)[i]) != NULL;
1207
1158
  was_interpolant = (*s)[i]->is_interpolant();
@@ -1211,7 +1162,8 @@ namespace Sass {
1211
1162
  if (s->length() > 1 && res == "") return SASS_MEMORY_NEW(ctx.mem, Null, s->pstate());
1212
1163
  return SASS_MEMORY_NEW(ctx.mem, String_Constant, s->pstate(), res);
1213
1164
  }
1214
- String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), res);
1165
+ // string schema seems to have a special unquoting behavior (also handles "nested" quotes)
1166
+ String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), res, 0, false, false, false);
1215
1167
  // if (s->is_interpolant()) str->quote_mark(0);
1216
1168
  // String_Constant* str = SASS_MEMORY_NEW(ctx.mem, String_Constant, s->pstate(), res);
1217
1169
  if (str->quote_mark()) str->quote_mark('*');
@@ -1227,6 +1179,7 @@ namespace Sass {
1227
1179
  Color* c = SASS_MEMORY_NEW(ctx.mem, Color, *name_to_color(s->value()));
1228
1180
  c->pstate(s->pstate());
1229
1181
  c->disp(s->value());
1182
+ c->is_delayed(true);
1230
1183
  return c;
1231
1184
  }
1232
1185
  return s;
@@ -1343,10 +1296,7 @@ namespace Sass {
1343
1296
  Expression* Eval::operator()(Argument* a)
1344
1297
  {
1345
1298
  Expression* val = a->value();
1346
- // delay missin function arguments?
1347
- val->is_delayed(a->is_delayed());
1348
1299
  val = val->perform(this);
1349
- val->is_delayed(false);
1350
1300
 
1351
1301
  bool is_rest_argument = a->is_rest_argument();
1352
1302
  bool is_keyword_argument = a->is_keyword_argument();
@@ -1606,12 +1556,8 @@ namespace Sass {
1606
1556
  if ( (sep == "") /* &&
1607
1557
  (sep != "/" || !rqstr || !rqstr->quote_mark()) */
1608
1558
  ) {
1609
- char quote_mark = 0;
1610
- std::string unq(unquote(lstr + sep + rstr, &quote_mark, true));
1611
- if (quote_mark && quote_mark != '*') {
1612
- return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), quote_mark + unq + quote_mark);
1613
- }
1614
- return SASS_MEMORY_NEW(mem, String_Quoted, lhs.pstate(), lstr + sep + rstr);
1559
+ // create a new string that might be quoted on output (but do not unquote what we pass)
1560
+ return SASS_MEMORY_NEW(mem, String_Quoted, pstate ? *pstate : lhs.pstate(), lstr + rstr, 0, false, true);
1615
1561
  }
1616
1562
 
1617
1563
  if (sep != "" && !delayed) {
@@ -1622,10 +1568,9 @@ namespace Sass {
1622
1568
  if (op == Sass_OP::SUB || op == Sass_OP::DIV) {
1623
1569
  if (lqstr && lqstr->quote_mark()) lstr = quote(lstr);
1624
1570
  if (rqstr && rqstr->quote_mark()) rstr = quote(rstr);
1625
- return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), lstr + sep + rstr);
1626
1571
  }
1627
1572
 
1628
- return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), (lstr) + sep + (rstr));
1573
+ return SASS_MEMORY_NEW(mem, String_Constant, pstate ? *pstate : lhs.pstate(), lstr + sep + rstr);
1629
1574
  }
1630
1575
 
1631
1576
  Expression* cval_to_astnode(Memory_Manager& mem, union Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
@@ -1679,10 +1624,10 @@ namespace Sass {
1679
1624
  return e;
1680
1625
  }
1681
1626
 
1682
- Selector_List* Eval::operator()(Selector_List* s)
1627
+ CommaSequence_Selector* Eval::operator()(CommaSequence_Selector* s)
1683
1628
  {
1684
- std::vector<Selector_List*> rv;
1685
- Selector_List* sl = SASS_MEMORY_NEW(ctx.mem, Selector_List, s->pstate());
1629
+ std::vector<CommaSequence_Selector*> rv;
1630
+ CommaSequence_Selector* sl = SASS_MEMORY_NEW(ctx.mem, CommaSequence_Selector, s->pstate());
1686
1631
  sl->is_optional(s->is_optional());
1687
1632
  sl->media_block(s->media_block());
1688
1633
  sl->is_optional(s->is_optional());
@@ -1712,9 +1657,10 @@ namespace Sass {
1712
1657
  }
1713
1658
 
1714
1659
 
1715
- Selector_List* Eval::operator()(Complex_Selector* s)
1660
+ CommaSequence_Selector* Eval::operator()(Sequence_Selector* s)
1716
1661
  {
1717
- return s->parentize(selector(), ctx);
1662
+ bool implicit_parent = !exp.old_at_root_without_rule;
1663
+ return s->resolve_parent_refs(ctx, selector(), implicit_parent);
1718
1664
 
1719
1665
  }
1720
1666
 
@@ -1728,21 +1674,21 @@ namespace Sass {
1728
1674
  return ss;
1729
1675
  }
1730
1676
 
1731
- Selector_List* Eval::operator()(Selector_Schema* s)
1677
+ CommaSequence_Selector* Eval::operator()(Selector_Schema* s)
1732
1678
  {
1733
1679
  // the parser will look for a brace to end the selector
1734
1680
  std::string result_str(s->contents()->perform(this)->to_string(ctx.c_options));
1735
1681
  result_str = unquote(Util::rtrim(result_str)) + "\n{";
1736
1682
  Parser p = Parser::from_c_str(result_str.c_str(), ctx, s->pstate());
1737
1683
  p.last_media_block = s->media_block();
1738
- Selector_List* sl = p.parse_selector_list(exp.block_stack.back()->is_root());
1684
+ CommaSequence_Selector* sl = p.parse_selector_list(exp.block_stack.back()->is_root());
1739
1685
  if (s->has_parent_ref()) sl->remove_parent_selectors();
1740
1686
  return operator()(sl);
1741
1687
  }
1742
1688
 
1743
1689
  Expression* Eval::operator()(Parent_Selector* p)
1744
1690
  {
1745
- Selector_List* pr = selector();
1691
+ CommaSequence_Selector* pr = selector();
1746
1692
  if (pr) {
1747
1693
  exp.selector_stack.pop_back();
1748
1694
  pr = operator()(pr);