sassc 1.10.1 → 1.11.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 (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);