sassc 1.1.2 → 1.2.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.
@@ -4,6 +4,13 @@
4
4
  #define PATH_SEP ':'
5
5
  #endif
6
6
 
7
+ #include <string>
8
+ #include <cstdlib>
9
+ #include <cstring>
10
+ #include <iomanip>
11
+ #include <sstream>
12
+ #include <iostream>
13
+
7
14
  #include "ast.hpp"
8
15
  #include "util.hpp"
9
16
  #include "sass.h"
@@ -29,13 +36,6 @@
29
36
  #include "prelexer.hpp"
30
37
  #include "emitter.hpp"
31
38
 
32
- #include <string>
33
- #include <cstdlib>
34
- #include <cstring>
35
- #include <iomanip>
36
- #include <sstream>
37
- #include <iostream>
38
-
39
39
  namespace Sass {
40
40
  using namespace Constants;
41
41
  using namespace File;
@@ -539,6 +539,8 @@ namespace Sass {
539
539
  // Misc Functions
540
540
  register_function(ctx, inspect_sig, inspect, env);
541
541
  register_function(ctx, unique_id_sig, unique_id, env);
542
+ // Selector functions
543
+ register_function(ctx, is_superselector_sig, is_superselector, env);
542
544
  }
543
545
 
544
546
  void register_c_functions(Context& ctx, Env* env, Sass_Function_List descrs)
@@ -32,12 +32,19 @@ namespace Sass {
32
32
  Selector_List* ss = 0;
33
33
  if (p) {
34
34
  ss = new (ctx.mem) Selector_List(s->pstate(), p->length() * s->length());
35
+ if (s->length() == 0) {
36
+ Complex_Selector* comb = static_cast<Complex_Selector*>(parent->perform(this));
37
+ if (parent->has_line_feed()) comb->has_line_feed(true);
38
+ if (comb) *ss << comb;
39
+ else cerr << "Warning: contextualize returned null" << endl;
40
+ }
35
41
  for (size_t i = 0, L = p->length(); i < L; ++i) {
36
42
  for (size_t j = 0, L = s->length(); j < L; ++j) {
37
43
  parent = (*p)[i];
38
44
  Complex_Selector* comb = static_cast<Complex_Selector*>((*s)[j]->perform(this));
39
45
  if (parent->has_line_feed()) comb->has_line_feed(true);
40
46
  if (comb) *ss << comb;
47
+ else cerr << "Warning: contextualize returned null" << endl;
41
48
  }
42
49
  }
43
50
  }
@@ -64,7 +64,7 @@ namespace Sass {
64
64
  // the value might be interpolated; evaluate it
65
65
  String* v = s->value();
66
66
  if (v && eval) {
67
- Eval* eval_with = eval->with(env, backtrace);
67
+ Eval* eval_with = eval->with(parent, env, backtrace);
68
68
  v = static_cast<String*>(v->perform(eval_with));
69
69
  }
70
70
  To_String toString;
@@ -264,6 +264,9 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
264
264
  cerr << ind << "If " << block;
265
265
  cerr << " (" << pstate_source_position(node) << ")";
266
266
  cerr << " " << block->tabs() << endl;
267
+ debug_ast(block->predicate(), ind + " = ");
268
+ debug_ast(block->consequent(), ind + " <>");
269
+ debug_ast(block->alternative(), ind + " ><");
267
270
  } else if (dynamic_cast<Return*>(node)) {
268
271
  Return* block = dynamic_cast<Return*>(node);
269
272
  cerr << ind << "Return " << block;
@@ -290,7 +293,7 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
290
293
  cerr << ind << "Import " << block;
291
294
  cerr << " (" << pstate_source_position(node) << ")";
292
295
  cerr << " " << block->tabs() << endl;
293
- debug_ast(block->media_queries(), ind + " @ ");
296
+ // debug_ast(block->media_queries(), ind + " @ ");
294
297
  // vector<string> files_;
295
298
  for (auto imp : block->urls()) debug_ast(imp, "@ ", env);
296
299
  } else if (dynamic_cast<Assignment*>(node)) {
@@ -353,7 +356,9 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
353
356
  if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
354
357
  } else if (dynamic_cast<Mixin_Call*>(node)) {
355
358
  Mixin_Call* block = dynamic_cast<Mixin_Call*>(node);
356
- cerr << ind << "Mixin_Call " << block << " " << block->tabs() << endl;
359
+ cerr << ind << "Mixin_Call " << block << " " << block->tabs();
360
+ cerr << " [" << block->name() << "]" << endl;
361
+ debug_ast(block->arguments(), ind + " args: ");
357
362
  if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
358
363
  } else if (dynamic_cast<Ruleset*>(node)) {
359
364
  Ruleset* ruleset = dynamic_cast<Ruleset*>(node);
@@ -380,9 +385,6 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
380
385
  cerr << endl;
381
386
  } else if (dynamic_cast<Variable*>(node)) {
382
387
  Variable* expression = dynamic_cast<Variable*>(node);
383
- cerr << ind << "Variable " << expression << " [" << expression->name() << "]";
384
- if (expression->is_delayed()) cerr << " [delayed]";
385
- cerr << endl;
386
388
  cerr << ind << "Variable " << expression;
387
389
  cerr << " (" << pstate_source_position(node) << ")";
388
390
  cerr << " [" << expression->name() << "]" << endl;
@@ -390,9 +392,6 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
390
392
  if (env && env->has(name)) debug_ast(static_cast<Expression*>((*env)[name]), ind + " -> ", env);
391
393
  } else if (dynamic_cast<Function_Call_Schema*>(node)) {
392
394
  Function_Call_Schema* expression = dynamic_cast<Function_Call_Schema*>(node);
393
- cerr << ind << "Function_Call_Schema " << expression << "]";
394
- if (expression->is_delayed()) cerr << " [delayed]";
395
- cerr << endl;
396
395
  cerr << ind << "Function_Call_Schema " << expression;
397
396
  cerr << " (" << pstate_source_position(node) << ")";
398
397
  cerr << "" << endl;
@@ -400,29 +399,19 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
400
399
  debug_ast(expression->arguments(), ind + " args: ", env);
401
400
  } else if (dynamic_cast<Function_Call*>(node)) {
402
401
  Function_Call* expression = dynamic_cast<Function_Call*>(node);
403
- cerr << ind << "Function_Call " << expression << " [" << expression->name() << "]";
404
- if (expression->is_delayed()) cerr << " [delayed]";
405
- cerr << endl;
406
402
  cerr << ind << "Function_Call " << expression;
407
403
  cerr << " (" << pstate_source_position(node) << ")";
408
404
  cerr << " [" << expression->name() << "]" << endl;
409
405
  debug_ast(expression->arguments(), ind + " args: ", env);
410
406
  } else if (dynamic_cast<Arguments*>(node)) {
411
407
  Arguments* expression = dynamic_cast<Arguments*>(node);
412
- cerr << ind << "Arguments " << expression << "]";
413
- if (expression->is_delayed()) cerr << " [delayed]";
414
- cerr << endl;
415
408
  cerr << ind << "Arguments " << expression;
409
+ if (expression->is_delayed()) cerr << " [delayed]";
416
410
  cerr << " (" << pstate_source_position(node) << ")";
417
411
  cerr << endl;
418
412
  for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
419
413
  } else if (dynamic_cast<Argument*>(node)) {
420
414
  Argument* expression = dynamic_cast<Argument*>(node);
421
- cerr << ind << "Argument " << expression << " [" << expression->value() << "]";
422
- if (expression->is_delayed()) cerr << " [delayed]";
423
- if (expression->is_rest_argument()) cerr << " [is_rest_argument]";
424
- if (expression->is_keyword_argument()) cerr << " [is_keyword_argument]";
425
- cerr << endl;
426
415
  cerr << ind << "Argument " << expression;
427
416
  cerr << " (" << pstate_source_position(node) << ")";
428
417
  cerr << " [" << expression->value() << "]";
@@ -447,21 +436,15 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
447
436
  cerr << " [rest: " << expression->is_rest_parameter() << "] " << endl;
448
437
  } else if (dynamic_cast<Unary_Expression*>(node)) {
449
438
  Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node);
450
- cerr << ind << "Unary_Expression " << expression << " [" << expression->type_name() << "]";
451
- if (expression->is_delayed()) cerr << " [delayed]";
452
- cerr << endl;
453
439
  cerr << ind << "Unary_Expression " << expression;
454
440
  cerr << " (" << pstate_source_position(node) << ")";
455
441
  cerr << " [" << expression->type() << "]" << endl;
456
442
  debug_ast(expression->operand(), ind + " operand: ", env);
457
443
  } else if (dynamic_cast<Binary_Expression*>(node)) {
458
444
  Binary_Expression* expression = dynamic_cast<Binary_Expression*>(node);
459
- cerr << ind << "Binary_Expression " << expression << " [" << expression->type_name() << "]";
460
- if (expression->is_delayed()) cerr << " [delayed]";
461
- cerr << endl;
462
445
  cerr << ind << "Binary_Expression " << expression;
463
446
  cerr << " (" << pstate_source_position(node) << ")";
464
- cerr << " [" << expression->type() << "]" << endl;
447
+ cerr << " [" << expression->type_name() << "]" << endl;
465
448
  debug_ast(expression->left(), ind + " left: ", env);
466
449
  debug_ast(expression->right(), ind + " right: ", env);
467
450
  } else if (dynamic_cast<Map*>(node)) {
@@ -469,6 +452,10 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
469
452
  cerr << ind << "Map " << expression;
470
453
  cerr << " (" << pstate_source_position(node) << ")";
471
454
  cerr << " [Hashed]" << endl;
455
+ // for (auto i : expression->elements()) {
456
+ // debug_ast(i.first, ind + " key: ");
457
+ // debug_ast(i.second, ind + " val: ");
458
+ // }
472
459
  } else if (dynamic_cast<List*>(node)) {
473
460
  List* expression = dynamic_cast<List*>(node);
474
461
  cerr << ind << "List " << expression;
@@ -476,9 +463,6 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
476
463
  cerr << " (" << expression->length() << ") " <<
477
464
  (expression->separator() == Sass::List::Separator::COMMA ? "Comma " : "Space ") <<
478
465
  " [delayed: " << expression->is_delayed() << "] " <<
479
- " [interpolant: " << expression->is_interpolant() << "]";
480
- if (expression->is_arglist()) cerr << " [is_arglist]";
481
- cerr << endl;
482
466
  " [interpolant: " << expression->is_interpolant() << "] " <<
483
467
  " [arglist: " << expression->is_arglist() << "] " <<
484
468
  endl;
@@ -490,79 +474,52 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
490
474
  cerr << " [Statement]" << endl;
491
475
  } else if (dynamic_cast<Boolean*>(node)) {
492
476
  Boolean* expression = dynamic_cast<Boolean*>(node);
493
- cerr << ind << "Boolean " << expression << " [" << expression->value() << "]";
494
- if (expression->is_delayed()) cerr << " [delayed]";
495
- cerr << endl;
496
477
  cerr << ind << "Boolean " << expression;
497
478
  cerr << " (" << pstate_source_position(node) << ")";
498
479
  cerr << " [" << expression->value() << "]" << endl;
499
480
  } else if (dynamic_cast<Color*>(node)) {
500
481
  Color* expression = dynamic_cast<Color*>(node);
501
- cerr << ind << "Color " << expression << " [" << expression->r() << ":" << expression->g() << ":" << expression->b() << "@" << expression->a() << "]";
502
- if (expression->is_delayed()) cerr << " [delayed]";
503
- cerr << endl;
504
482
  cerr << ind << "Color " << expression;
505
483
  cerr << " (" << pstate_source_position(node) << ")";
506
484
  cerr << " [" << expression->r() << ":" << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << endl;
507
485
  } else if (dynamic_cast<Number*>(node)) {
508
486
  Number* expression = dynamic_cast<Number*>(node);
509
- cerr << ind << "Number " << expression << " [" << expression->value() << expression->unit() << "]";
510
- if (expression->is_delayed()) cerr << " [delayed]";
511
- cerr << endl;
512
487
  cerr << ind << "Number " << expression;
513
488
  cerr << " (" << pstate_source_position(node) << ")";
514
489
  cerr << " [" << expression->value() << expression->unit() << "]" << endl;
515
490
  } else if (dynamic_cast<String_Quoted*>(node)) {
516
491
  String_Quoted* expression = dynamic_cast<String_Quoted*>(node);
517
- cerr << ind << "String_Quoted : " << expression << " [";
518
- cerr << prettyprint(expression->value()) << "]";
492
+ cerr << ind << "String_Quoted " << expression;
493
+ cerr << " (" << pstate_source_position(node) << ")";
494
+ cerr << " [" << prettyprint(expression->value()) << "]";
519
495
  if (expression->is_delayed()) cerr << " [delayed]";
520
496
  if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
521
- if (expression->quote_mark()) cerr << " [quote_mark]";
497
+ if (expression->quote_mark()) cerr << " [quote_mark: " << expression->quote_mark() << "]";
522
498
  cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
523
- cerr << ind << "String_Quoted : " << expression;
524
- cerr << " (" << pstate_source_position(node) << ")";
525
- cerr << " [" << prettyprint(expression->value()) << "]" <<
526
- (expression->is_delayed() ? " {delayed}" : "") <<
527
- (expression->sass_fix_1291() ? " {sass_fix_1291}" : "") <<
528
- (expression->quote_mark() != 0 ? " {qm:" + string(1, expression->quote_mark()) + "}" : "") <<
529
- " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
530
499
  } else if (dynamic_cast<String_Constant*>(node)) {
531
500
  String_Constant* expression = dynamic_cast<String_Constant*>(node);
532
- cerr << ind << "String_Constant : " << expression;
501
+ cerr << ind << "String_Constant " << expression;
502
+ cerr << " " << expression->concrete_type() <<
503
+ cerr << " (" << pstate_source_position(node) << ")";
533
504
  cerr << " [" << prettyprint(expression->value()) << "]";
534
505
  if (expression->is_delayed()) cerr << " [delayed]";
535
506
  if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
536
- cerr " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
537
- cerr << ind << "String_Constant : " << expression;
538
- cerr << " (" << pstate_source_position(node) << ")";
539
- cerr << " [" << prettyprint(expression->value()) << "]" <<
540
- (expression->is_delayed() ? " {delayed}" : "") <<
541
- (expression->sass_fix_1291() ? " {sass_fix_1291}" : "") <<
542
- (expression->quote_mark() != 0 ? " {qm:" + string(1, expression->quote_mark()) + "}" : "") <<
543
- " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
507
+ cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
544
508
  } else if (dynamic_cast<String_Schema*>(node)) {
545
509
  String_Schema* expression = dynamic_cast<String_Schema*>(node);
546
- cerr << ind << "String_Schema " << expression << " [" << expression->concrete_type() << "]";
510
+ cerr << ind << "String_Schema " << expression;
511
+ cerr << " " << expression->concrete_type();
547
512
  if (expression->is_delayed()) cerr << " [delayed]";
548
513
  if (expression->has_interpolants()) cerr << " [has_interpolants]";
549
- cerr " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
550
- cerr << ind << "String_Schema " << expression;
551
- cerr << " (" << pstate_source_position(node) << ")";
552
- cerr << " " << expression->concrete_type() <<
553
- (expression->has_interpolants() ? " {has_interpolants}" : "") <<
554
- endl;
514
+ cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
555
515
  for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
556
516
  } else if (dynamic_cast<String*>(node)) {
557
517
  String* expression = dynamic_cast<String*>(node);
558
- cerr << ind << "String " << expression << expression->concrete_type();
559
- if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
560
- cerr " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
561
518
  cerr << ind << "String " << expression;
519
+ cerr << " " << expression->concrete_type();
562
520
  cerr << " (" << pstate_source_position(node) << ")";
563
- cerr << expression->concrete_type() <<
564
- " " << (expression->sass_fix_1291() ? "{sass_fix_1291}" : "") <<
565
- endl;
521
+ if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
522
+ cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
566
523
  } else if (dynamic_cast<Expression*>(node)) {
567
524
  Expression* expression = dynamic_cast<Expression*>(node);
568
525
  cerr << ind << "Expression " << expression;
@@ -18,7 +18,8 @@ namespace Sass {
18
18
  in_wrapped(false),
19
19
  in_media_block(false),
20
20
  in_declaration(false),
21
- in_declaration_list(false)
21
+ in_space_array(false),
22
+ in_comma_array(false)
22
23
  { }
23
24
 
24
25
  // return buffer as string
@@ -191,7 +192,9 @@ namespace Sass {
191
192
  {
192
193
  if (output_style() != COMPRESSED && buffer().size()) {
193
194
  char lst = buffer().at(buffer().length() - 1);
194
- if (!isspace(lst)) append_mandatory_space();
195
+ if (!isspace(lst) || scheduled_delimiter) {
196
+ append_mandatory_space();
197
+ }
195
198
  }
196
199
  }
197
200
 
@@ -37,11 +37,17 @@ namespace Sass {
37
37
  bool scheduled_delimiter;
38
38
 
39
39
  public:
40
+ // output strings different in comments
40
41
  bool in_comment;
42
+ // selector list does not get linefeeds
41
43
  bool in_wrapped;
44
+ // lists always get a space after delimiter
42
45
  bool in_media_block;
46
+ // nested list must not have parentheses
43
47
  bool in_declaration;
44
- bool in_declaration_list;
48
+ // nested lists need parentheses
49
+ bool in_space_array;
50
+ bool in_comma_array;
45
51
 
46
52
  public:
47
53
  // return buffer as string
data/ext/libsass/eval.cpp CHANGED
@@ -1,3 +1,10 @@
1
+ #include <cstdlib>
2
+ #include <cmath>
3
+ #include <iostream>
4
+ #include <sstream>
5
+ #include <iomanip>
6
+ #include <typeinfo>
7
+
1
8
  #include "file.hpp"
2
9
  #include "eval.hpp"
3
10
  #include "ast.hpp"
@@ -11,12 +18,6 @@
11
18
  #include "prelexer.hpp"
12
19
  #include "parser.hpp"
13
20
 
14
- #include <cstdlib>
15
- #include <cmath>
16
- #include <iostream>
17
- #include <iomanip>
18
- #include <typeinfo>
19
-
20
21
  namespace Sass {
21
22
  using namespace std;
22
23
 
@@ -397,6 +398,13 @@ namespace Sass {
397
398
  for (auto key : m->keys()) {
398
399
  *mm << std::make_pair(key->perform(this), m->at(key)->perform(this));
399
400
  }
401
+
402
+ // check for duplicate keys
403
+ if (mm->has_duplicate_key()) {
404
+ To_String to_string(&ctx);
405
+ error("Duplicate key \"" + mm->get_duplicate_key()->perform(&to_string) + "\" in map " + m->perform(&to_string) + ".", m->pstate());
406
+ }
407
+
400
408
  mm->is_expanded(true);
401
409
  return mm;
402
410
  }
@@ -528,7 +536,9 @@ namespace Sass {
528
536
  Expression* Eval::operator()(Function_Call* c)
529
537
  {
530
538
  if (backtrace->parent != NULL && backtrace->depth() > Constants::MaxCallStack) {
531
- error("Stack depth exceeded max of " + to_string(Constants::MaxCallStack), c->pstate(), backtrace);
539
+ ostringstream stm;
540
+ stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
541
+ error(stm.str(), c->pstate(), backtrace);
532
542
  }
533
543
  string name(Util::normalize_underscores(c->name()));
534
544
  string full_name(name + "[f]");
@@ -876,6 +886,7 @@ namespace Sass {
876
886
  Expression* value = static_cast<Expression*>((*env)[name]);
877
887
  return evacuate_quotes(interpolation(value));
878
888
  } else if (Binary_Expression* var = dynamic_cast<Binary_Expression*>(s)) {
889
+ var->is_delayed(false);
879
890
  Expression* ex = var->perform(this);
880
891
  return evacuate_quotes(interpolation(ex));
881
892
  } else if (Function_Call* var = dynamic_cast<Function_Call*>(s)) {
@@ -901,9 +912,9 @@ namespace Sass {
901
912
  {
902
913
  string acc;
903
914
  for (size_t i = 0, L = s->length(); i < L; ++i) {
904
- if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>((*s)[i])) {
905
- if (!str_quoted->is_delayed()) str_quoted->value(string_eval_escapes(str_quoted->value()));
906
- }
915
+ // if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>((*s)[i])) {
916
+ // if (!str_quoted->is_delayed()) str_quoted->value(string_eval_escapes(str_quoted->value()));
917
+ // }
907
918
  acc += interpolation((*s)[i]);
908
919
  }
909
920
  String_Quoted* str = new (ctx.mem) String_Quoted(s->pstate(), acc);
@@ -1014,8 +1025,7 @@ namespace Sass {
1014
1025
  is_rest_argument = false;
1015
1026
  is_keyword_argument = true;
1016
1027
  }
1017
- else
1018
- if(val->concrete_type() != Expression::LIST) {
1028
+ else if(val->concrete_type() != Expression::LIST) {
1019
1029
  List* wrapper = new (ctx.mem) List(val->pstate(),
1020
1030
  0,
1021
1031
  List::COMMA,
@@ -1047,9 +1057,13 @@ namespace Sass {
1047
1057
 
1048
1058
  Expression* Eval::operator()(Parent_Selector* p)
1049
1059
  {
1060
+ // no idea why both calls are needed
1050
1061
  Selector* s = p->perform(contextualize);
1062
+ if (!s) s = p->selector()->perform(contextualize);
1051
1063
  // access to parent selector may return 0
1052
1064
  Selector_List* l = static_cast<Selector_List*>(s);
1065
+ // some spec tests cause this (might be a valid case!)
1066
+ // if (!s) { cerr << "Parent Selector eval error" << endl; }
1053
1067
  if (!s) { l = new (ctx.mem) Selector_List(p->pstate()); }
1054
1068
  return l->perform(listize);
1055
1069
  }
@@ -1186,7 +1200,7 @@ namespace Sass {
1186
1200
  } else {
1187
1201
  v->value(ops[op](lv, tmp.value()));
1188
1202
  }
1189
- // v->normalize();
1203
+ v->normalize();
1190
1204
  return v;
1191
1205
  }
1192
1206
 
@@ -54,8 +54,8 @@ namespace Sass {
54
54
  }
55
55
 
56
56
  Contextualize_Eval* contextual = contextualize_eval->with(selector_stack.back(), env, backtrace);
57
- if (old_in_at_root && !r->selector()->has_reference())
58
- contextual = contextualize_eval->with(at_root_selector_stack.back(), env, backtrace);
57
+ // if (old_in_at_root && !r->selector()->has_reference())
58
+ // contextual = contextualize_eval->with(selector_stack.back(), env, backtrace);
59
59
 
60
60
  Selector* sel_ctx = r->selector()->perform(contextual);
61
61
  if (sel_ctx == 0) throw "Cannot expand null selector";
@@ -1107,7 +1107,7 @@ namespace Sass {
1107
1107
 
1108
1108
  List* list = dynamic_cast<List*>(env["$list"]);
1109
1109
  return new (ctx.mem) Number(pstate,
1110
- list ? list->length() : 1);
1110
+ list ? list->size() : 1);
1111
1111
  }
1112
1112
 
1113
1113
  Signature nth_sig = "nth($list, $n)";
@@ -1217,7 +1217,18 @@ namespace Sass {
1217
1217
  else if (sep_str == "comma") result->separator(List::COMMA);
1218
1218
  else if (sep_str != "auto") error("argument `$separator` of `" + string(sig) + "` must be `space`, `comma`, or `auto`", pstate);
1219
1219
  *result += l;
1220
- *result << v;
1220
+ bool is_arglist = l->is_arglist();
1221
+ result->is_arglist(is_arglist);
1222
+ if (is_arglist) {
1223
+ *result << new (ctx.mem) Argument(v->pstate(),
1224
+ v,
1225
+ "",
1226
+ false,
1227
+ false);
1228
+
1229
+ } else {
1230
+ *result << v;
1231
+ }
1221
1232
  return result;
1222
1233
  }
1223
1234
 
@@ -1345,13 +1356,10 @@ namespace Sass {
1345
1356
  {
1346
1357
  List* arglist = new (ctx.mem) List(*ARG("$args", List));
1347
1358
  Map* result = new (ctx.mem) Map(pstate, 1);
1348
- // The parser ensures the ordering of arguments so we can assert this
1349
- // isn't keyword argument list the first argument isn't a keyword argument
1350
- if (!(arglist->empty() || ((Argument*)(*arglist)[0])->is_keyword_argument())) return result;
1351
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
1359
+ for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) {
1352
1360
  string name = string(((Argument*)(*arglist)[i])->name());
1353
- string sanitized_name = string(name, 1);
1354
- *result << make_pair(new (ctx.mem) String_Constant(pstate, sanitized_name),
1361
+ name = name.erase(0, 1); // sanitize name (remove dollar sign)
1362
+ *result << make_pair(new (ctx.mem) String_Constant(pstate, name),
1355
1363
  ((Argument*)(*arglist)[i])->value());
1356
1364
  }
1357
1365
  return result;
@@ -1540,11 +1548,14 @@ namespace Sass {
1540
1548
  } else if (v->concrete_type() == Expression::STRING) {
1541
1549
  return v;
1542
1550
  } else {
1551
+ bool parentheses = v->concrete_type() == Expression::MAP ||
1552
+ v->concrete_type() == Expression::LIST;
1543
1553
  Output_Style old_style;
1544
1554
  old_style = ctx.output_style;
1545
1555
  ctx.output_style = NESTED;
1546
- To_String to_string(&ctx);
1556
+ To_String to_string(&ctx, false);
1547
1557
  string inspect = v->perform(&to_string);
1558
+ if (inspect.empty() && parentheses) inspect = "()";
1548
1559
  ctx.output_style = old_style;
1549
1560
  return new (ctx.mem) String_Constant(pstate, inspect);
1550
1561
 
@@ -1553,6 +1564,20 @@ namespace Sass {
1553
1564
  // return v;
1554
1565
  }
1555
1566
 
1567
+ Signature is_superselector_sig = "is-superselector($super, $sub)";
1568
+ BUILT_IN(is_superselector)
1569
+ {
1570
+ To_String to_string(&ctx, false);
1571
+ Expression* ex_sup = ARG("$super", Expression);
1572
+ Expression* ex_sub = ARG("$sub", Expression);
1573
+ string sup_src = ex_sup->perform(&to_string) + "{";
1574
+ string sub_src = ex_sub->perform(&to_string) + "{";
1575
+ Selector_List* sel_sup = Parser::parse_selector(sup_src.c_str(), ctx);
1576
+ Selector_List* sel_sub = Parser::parse_selector(sub_src.c_str(), ctx);
1577
+ bool result = sel_sup->is_superselector_of(sel_sub);
1578
+ return new (ctx.mem) Boolean(pstate, result);
1579
+ }
1580
+
1556
1581
  Signature unique_id_sig = "unique-id()";
1557
1582
  BUILT_IN(unique_id)
1558
1583
  {