sassc 1.9.0 → 1.10.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -3
  3. data/ext/libsass/.gitignore +3 -0
  4. data/ext/libsass/.travis.yml +1 -1
  5. data/ext/libsass/GNUmakefile.am +7 -7
  6. data/ext/libsass/Makefile +7 -4
  7. data/ext/libsass/Makefile.conf +0 -1
  8. data/ext/libsass/appveyor.yml +6 -2
  9. data/ext/libsass/docs/api-context.md +4 -4
  10. data/ext/libsass/docs/api-doc.md +29 -11
  11. data/ext/libsass/docs/api-importer-example.md +5 -5
  12. data/ext/libsass/docs/build-on-windows.md +1 -1
  13. data/ext/libsass/include/sass/base.h +10 -0
  14. data/ext/libsass/include/sass/version.h +4 -0
  15. data/ext/libsass/include/sass/version.h.in +4 -0
  16. data/ext/libsass/include/sass2scss.h +1 -1
  17. data/ext/libsass/script/ci-build-libsass +15 -3
  18. data/ext/libsass/src/ast.cpp +161 -6
  19. data/ext/libsass/src/ast.hpp +71 -44
  20. data/ext/libsass/src/ast_factory.hpp +1 -1
  21. data/ext/libsass/src/ast_fwd_decl.hpp +2 -2
  22. data/ext/libsass/src/constants.cpp +2 -4
  23. data/ext/libsass/src/constants.hpp +3 -4
  24. data/ext/libsass/src/context.cpp +16 -17
  25. data/ext/libsass/src/context.hpp +2 -2
  26. data/ext/libsass/src/cssize.cpp +19 -8
  27. data/ext/libsass/src/cssize.hpp +5 -2
  28. data/ext/libsass/src/debugger.hpp +6 -3
  29. data/ext/libsass/src/emitter.cpp +1 -1
  30. data/ext/libsass/src/environment.cpp +1 -1
  31. data/ext/libsass/src/eval.cpp +42 -14
  32. data/ext/libsass/src/eval.hpp +1 -1
  33. data/ext/libsass/src/expand.cpp +24 -8
  34. data/ext/libsass/src/expand.hpp +2 -1
  35. data/ext/libsass/src/extend.cpp +55 -15
  36. data/ext/libsass/src/extend.hpp +5 -1
  37. data/ext/libsass/src/functions.cpp +10 -5
  38. data/ext/libsass/src/inspect.cpp +25 -19
  39. data/ext/libsass/src/inspect.hpp +2 -2
  40. data/ext/libsass/src/json.cpp +20 -9
  41. data/ext/libsass/src/json.hpp +5 -5
  42. data/ext/libsass/src/lexer.cpp +4 -1
  43. data/ext/libsass/src/lexer.hpp +21 -0
  44. data/ext/libsass/src/listize.cpp +2 -1
  45. data/ext/libsass/src/operation.hpp +4 -4
  46. data/ext/libsass/src/output.cpp +1 -1
  47. data/ext/libsass/src/output.hpp +1 -1
  48. data/ext/libsass/src/parser.cpp +189 -90
  49. data/ext/libsass/src/parser.hpp +42 -2
  50. data/ext/libsass/src/prelexer.cpp +474 -7
  51. data/ext/libsass/src/prelexer.hpp +15 -2
  52. data/ext/libsass/src/remove_placeholders.cpp +5 -5
  53. data/ext/libsass/src/remove_placeholders.hpp +3 -2
  54. data/ext/libsass/src/sass.cpp +33 -3
  55. data/ext/libsass/src/sass2scss.cpp +7 -0
  56. data/ext/libsass/src/sass_context.cpp +32 -62
  57. data/ext/libsass/src/sass_functions.cpp +3 -3
  58. data/ext/libsass/src/sass_values.cpp +5 -5
  59. data/ext/libsass/src/utf8/unchecked.h +16 -16
  60. data/ext/libsass/src/util.cpp +51 -30
  61. data/ext/libsass/src/util.hpp +6 -1
  62. data/ext/libsass/win/libsass.targets +0 -2
  63. data/ext/libsass/win/libsass.vcxproj.filters +0 -6
  64. data/lib/sassc/engine.rb +4 -1
  65. data/lib/sassc/error.rb +23 -1
  66. data/lib/sassc/version.rb +1 -1
  67. data/test/error_test.rb +27 -0
  68. data/test/native_test.rb +1 -1
  69. metadata +5 -5
  70. data/ext/libsass/include/sass/interface.h +0 -105
  71. data/ext/libsass/src/sass_interface.cpp +0 -215
@@ -24,6 +24,10 @@ namespace Sass {
24
24
  public:
25
25
  static Node subweave(Node& one, Node& two, Context& ctx);
26
26
  static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething);
27
+ static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace = false) {
28
+ bool extendedSomething = false;
29
+ return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething);
30
+ }
27
31
  Extend(Context&, ExtensionSubsetMap&);
28
32
  ~Extend() { }
29
33
 
@@ -31,7 +35,7 @@ namespace Sass {
31
35
  void operator()(Ruleset*);
32
36
  void operator()(Supports_Block*);
33
37
  void operator()(Media_Block*);
34
- void operator()(At_Rule*);
38
+ void operator()(Directive*);
35
39
 
36
40
  template <typename U>
37
41
  void fallback(U x) { return fallback_impl(x); }
@@ -902,9 +902,16 @@ namespace Sass {
902
902
  BUILT_IN(sass_quote)
903
903
  {
904
904
  AST_Node* arg = env["$string"];
905
+ // only set quote mark to true if already a string
906
+ if (String_Quoted* qstr = dynamic_cast<String_Quoted*>(arg)) {
907
+ qstr->quote_mark('*');
908
+ return qstr;
909
+ }
910
+ // all other nodes must be converted to a string node
905
911
  std::string str(quote(arg->to_string(ctx.c_options), String_Constant::double_quote()));
906
912
  String_Quoted* result = SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, str);
907
913
  result->is_delayed(true);
914
+ result->quote_mark('*');
908
915
  return result;
909
916
  }
910
917
 
@@ -1815,7 +1822,7 @@ namespace Sass {
1815
1822
  }
1816
1823
 
1817
1824
  // Cannot be a Universal selector
1818
- Type_Selector* pType = dynamic_cast<Type_Selector*>(base->head()->first());
1825
+ Type_Selector* pType = dynamic_cast<Type_Selector*>(childSeq->head()->first());
1819
1826
  if(pType && pType->name() == "*") {
1820
1827
  std::string msg("Can't append `");
1821
1828
  msg += childSeq->to_string();
@@ -1882,8 +1889,7 @@ namespace Sass {
1882
1889
  ExtensionSubsetMap subset_map;
1883
1890
  extender->populate_extends(extendee, ctx, subset_map);
1884
1891
 
1885
- bool extendedSomething;
1886
- Selector_List* result = Extend::extendSelectorList(selector, ctx, subset_map, false, extendedSomething);
1892
+ Selector_List* result = Extend::extendSelectorList(selector, ctx, subset_map, false);
1887
1893
 
1888
1894
  Listize listize(ctx.mem);
1889
1895
  return result->perform(&listize);
@@ -1899,8 +1905,7 @@ namespace Sass {
1899
1905
  ExtensionSubsetMap subset_map;
1900
1906
  replacement->populate_extends(original, ctx, subset_map);
1901
1907
 
1902
- bool extendedSomething;
1903
- Selector_List* result = Extend::extendSelectorList(selector, ctx, subset_map, true, extendedSomething);
1908
+ Selector_List* result = Extend::extendSelectorList(selector, ctx, subset_map, true);
1904
1909
 
1905
1910
  Listize listize(ctx.mem);
1906
1911
  return result->perform(&listize);
@@ -96,7 +96,7 @@ namespace Sass {
96
96
  at_root_block->block()->perform(this);
97
97
  }
98
98
 
99
- void Inspect::operator()(At_Rule* at_rule)
99
+ void Inspect::operator()(Directive* at_rule)
100
100
  {
101
101
  append_indentation();
102
102
  append_token(at_rule->keyword(), at_rule);
@@ -385,9 +385,12 @@ namespace Sass {
385
385
  bool was_space_array = in_space_array;
386
386
  bool was_comma_array = in_comma_array;
387
387
  // probably ruby sass eqivalent of element_needs_parens
388
- if (output_style() == TO_SASS && list->length() == 1 &&
389
- (!dynamic_cast<List*>((*list)[0]) &&
390
- !dynamic_cast<Selector_List*>((*list)[0]))) {
388
+ if (output_style() == TO_SASS &&
389
+ list->length() == 1 &&
390
+ !list->from_selector() &&
391
+ !dynamic_cast<List*>((*list)[0]) &&
392
+ !dynamic_cast<List*>((*list)[0]) &&
393
+ !dynamic_cast<Selector_List*>((*list)[0])) {
391
394
  append_string("(");
392
395
  }
393
396
  else if (!in_declaration && (list->separator() == SASS_HASH ||
@@ -424,9 +427,12 @@ namespace Sass {
424
427
  in_comma_array = was_comma_array;
425
428
  in_space_array = was_space_array;
426
429
  // probably ruby sass eqivalent of element_needs_parens
427
- if (output_style() == TO_SASS && list->length() == 1 &&
428
- (!dynamic_cast<List*>((*list)[0]) &&
429
- !dynamic_cast<Selector_List*>((*list)[0]))) {
430
+ if (output_style() == TO_SASS &&
431
+ list->length() == 1 &&
432
+ !list->from_selector() &&
433
+ !dynamic_cast<List*>((*list)[0]) &&
434
+ !dynamic_cast<List*>((*list)[0]) &&
435
+ !dynamic_cast<Selector_List*>((*list)[0])) {
430
436
  append_string(",)");
431
437
  }
432
438
  else if (!in_declaration && (list->separator() == SASS_HASH ||
@@ -806,20 +812,15 @@ namespace Sass {
806
812
  }
807
813
  }
808
814
 
809
- void Inspect::operator()(At_Root_Expression* ae)
815
+ void Inspect::operator()(At_Root_Query* ae)
810
816
  {
811
- if (ae->is_interpolated()) {
812
- ae->feature()->perform(this);
813
- }
814
- else {
815
- append_string("(");
816
- ae->feature()->perform(this);
817
- if (ae->value()) {
818
- append_colon_separator();
819
- ae->value()->perform(this);
820
- }
821
- append_string(")");
817
+ append_string("(");
818
+ ae->feature()->perform(this);
819
+ if (ae->value()) {
820
+ append_colon_separator();
821
+ ae->value()->perform(this);
822
822
  }
823
+ append_string(")");
823
824
  }
824
825
 
825
826
  void Inspect::operator()(Null* n)
@@ -974,6 +975,11 @@ namespace Sass {
974
975
  Complex_Selector* tail = c->tail();
975
976
  Complex_Selector::Combinator comb = c->combinator();
976
977
 
978
+ if (comb == Complex_Selector::ANCESTOR_OF && (!head || head->empty())) {
979
+ if (tail) tail->perform(this);
980
+ return;
981
+ }
982
+
977
983
  if (c->has_line_feed()) {
978
984
  if (!(c->has_parent_ref())) {
979
985
  append_optional_linefeed();
@@ -28,7 +28,7 @@ namespace Sass {
28
28
  virtual void operator()(Supports_Block*);
29
29
  virtual void operator()(Media_Block*);
30
30
  virtual void operator()(At_Root_Block*);
31
- virtual void operator()(At_Rule*);
31
+ virtual void operator()(Directive*);
32
32
  virtual void operator()(Keyframe_Rule*);
33
33
  virtual void operator()(Declaration*);
34
34
  virtual void operator()(Assignment*);
@@ -72,7 +72,7 @@ namespace Sass {
72
72
  virtual void operator()(Supports_Interpolation*);
73
73
  virtual void operator()(Media_Query*);
74
74
  virtual void operator()(Media_Query_Expression*);
75
- virtual void operator()(At_Root_Expression*);
75
+ virtual void operator()(At_Root_Query*);
76
76
  virtual void operator()(Null*);
77
77
  virtual void operator()(Parent_Selector* p);
78
78
  // parameters and arguments
@@ -28,6 +28,10 @@
28
28
 
29
29
  #include "json.hpp"
30
30
 
31
+ // include utf8 library used by libsass
32
+ // ToDo: replace internal json utf8 code
33
+ #include "utf8.h"
34
+
31
35
  #include <assert.h>
32
36
  #include <stdint.h>
33
37
  #include <stdio.h>
@@ -548,7 +552,7 @@ static void append_node(JsonNode *parent, JsonNode *child)
548
552
  child->parent = parent;
549
553
  child->prev = parent->children.tail;
550
554
  child->next = NULL;
551
-
555
+
552
556
  if (parent->children.tail != NULL)
553
557
  parent->children.tail->next = child;
554
558
  else
@@ -563,7 +567,7 @@ static void prepend_node(JsonNode *parent, JsonNode *child)
563
567
  child->parent = parent;
564
568
  child->prev = NULL;
565
569
  child->next = parent->children.head;
566
-
570
+
567
571
  if (parent->children.head != NULL)
568
572
  parent->children.head->prev = child;
569
573
  else
@@ -585,7 +589,7 @@ void json_append_element(JsonNode *array, JsonNode *element)
585
589
  if (array != NULL && element !=NULL) {
586
590
  assert(array->tag == JSON_ARRAY);
587
591
  assert(element->parent == NULL);
588
-
592
+
589
593
  append_node(array, element);
590
594
  }
591
595
  }
@@ -603,7 +607,7 @@ void json_append_member(JsonNode *object, const char *key, JsonNode *value)
603
607
  if (object != NULL && key != NULL && value != NULL) {
604
608
  assert(object->tag == JSON_OBJECT);
605
609
  assert(value->parent == NULL);
606
-
610
+
607
611
  append_member(object, json_strdup(key), value);
608
612
  }
609
613
  }
@@ -613,7 +617,7 @@ void json_prepend_member(JsonNode *object, const char *key, JsonNode *value)
613
617
  if (object != NULL && key != NULL && value != NULL) {
614
618
  assert(object->tag == JSON_OBJECT);
615
619
  assert(value->parent == NULL);
616
-
620
+
617
621
  value->key = json_strdup(key);
618
622
  prepend_node(object, value);
619
623
  }
@@ -623,20 +627,20 @@ void json_remove_from_parent(JsonNode *node)
623
627
  {
624
628
  if (node != NULL) {
625
629
  JsonNode *parent = node->parent;
626
-
630
+
627
631
  if (parent != NULL) {
628
632
  if (node->prev != NULL)
629
633
  node->prev->next = node->next;
630
634
  else
631
635
  parent->children.head = node->next;
632
-
636
+
633
637
  if (node->next != NULL)
634
638
  node->next->prev = node->prev;
635
639
  else
636
640
  parent->children.tail = node->prev;
637
-
641
+
638
642
  free(node->key);
639
-
643
+
640
644
  node->parent = NULL;
641
645
  node->prev = node->next = NULL;
642
646
  node->key = NULL;
@@ -1141,6 +1145,13 @@ void emit_string(SB *out, const char *str)
1141
1145
  const char *s = str;
1142
1146
  char *b;
1143
1147
 
1148
+ // make assertion catchable
1149
+ #ifndef NDEBUG
1150
+ if (!utf8_validate(str)) {
1151
+ throw utf8::invalid_utf8(0);
1152
+ }
1153
+ #endif
1154
+
1144
1155
  assert(utf8_validate(str));
1145
1156
 
1146
1157
  /*
@@ -43,21 +43,21 @@ struct JsonNode
43
43
  /* only if parent is an object or array (NULL otherwise) */
44
44
  JsonNode *parent;
45
45
  JsonNode *prev, *next;
46
-
46
+
47
47
  /* only if parent is an object (NULL otherwise) */
48
48
  char *key; /* Must be valid UTF-8. */
49
-
49
+
50
50
  JsonTag tag;
51
51
  union {
52
52
  /* JSON_BOOL */
53
53
  bool bool_;
54
-
54
+
55
55
  /* JSON_STRING */
56
56
  char *string_; /* Must be valid UTF-8. */
57
-
57
+
58
58
  /* JSON_NUMBER */
59
59
  double number_;
60
-
60
+
61
61
  /* JSON_ARRAY */
62
62
  /* JSON_OBJECT */
63
63
  struct {
@@ -91,7 +91,8 @@ namespace Sass {
91
91
  // valid in a uri (copied from Ruby Sass)
92
92
  bool is_uri_character(const char& chr)
93
93
  {
94
- return unsigned(chr) > 41 && unsigned(chr) < 127;
94
+ return (unsigned(chr) > 41 && unsigned(chr) < 127) ||
95
+ unsigned(chr) == ':' || unsigned(chr) == '/';
95
96
  }
96
97
 
97
98
  // check if char is within a reduced ascii range
@@ -121,6 +122,7 @@ namespace Sass {
121
122
  const char* xdigit(const char* src) { return is_xdigit(*src) ? src + 1 : 0; }
122
123
  const char* alnum(const char* src) { return is_alnum(*src) ? src + 1 : 0; }
123
124
  const char* punct(const char* src) { return is_punct(*src) ? src + 1 : 0; }
125
+ const char* hyphen(const char* src) { return *src && *src == '-' ? src + 1 : 0; }
124
126
  const char* character(const char* src) { return is_character(*src) ? src + 1 : 0; }
125
127
  const char* uri_character(const char* src) { return is_uri_character(*src) ? src + 1 : 0; }
126
128
  const char* escapable_character(const char* src) { return is_escapable_character(*src) ? src + 1 : 0; }
@@ -128,6 +130,7 @@ namespace Sass {
128
130
  // Match multiple ctype characters.
129
131
  const char* spaces(const char* src) { return one_plus<space>(src); }
130
132
  const char* digits(const char* src) { return one_plus<digit>(src); }
133
+ const char* hyphens(const char* src) { return one_plus<hyphen>(src); }
131
134
 
132
135
  // Whitespace handling.
133
136
  const char* no_spaces(const char* src) { return negate< space >(src); }
@@ -44,6 +44,7 @@ namespace Sass {
44
44
  const char* xdigit(const char* src);
45
45
  const char* alnum(const char* src);
46
46
  const char* punct(const char* src);
47
+ const char* hyphen(const char* src);
47
48
  const char* unicode(const char* src);
48
49
  const char* nonascii(const char* src);
49
50
  const char* character(const char* src);
@@ -53,6 +54,7 @@ namespace Sass {
53
54
  // Match multiple ctype characters.
54
55
  const char* spaces(const char* src);
55
56
  const char* digits(const char* src);
57
+ const char* hyphens(const char* src);
56
58
 
57
59
  // Whitespace handling.
58
60
  const char* no_spaces(const char* src);
@@ -142,6 +144,25 @@ namespace Sass {
142
144
  return p == src ? 0 : p;
143
145
  }
144
146
 
147
+ // Match for members of char class.
148
+ // Regex equivalent: /[^axy]/
149
+ template <const char* neg_char_class>
150
+ const char* neg_class_char(const char* src) {
151
+ if (*src == 0) return 0;
152
+ const char* cc = neg_char_class;
153
+ while (*cc && *src != *cc) ++cc;
154
+ return *cc ? 0 : src + 1;
155
+ }
156
+
157
+ // Match for members of char class.
158
+ // Regex equivalent: /[^axy]+/
159
+ template <const char* neg_char_class>
160
+ const char* neg_class_chars(const char* src) {
161
+ const char* p = src;
162
+ while (neg_class_char<neg_char_class>(p)) ++p;
163
+ return p == src ? 0 : p;
164
+ }
165
+
145
166
  // Match all except the supplied one.
146
167
  // Regex equivalent: /[^x]/
147
168
  template <const char chr>
@@ -17,6 +17,7 @@ namespace Sass {
17
17
  Expression* Listize::operator()(Selector_List* sel)
18
18
  {
19
19
  List* l = SASS_MEMORY_NEW(mem, List, sel->pstate(), sel->length(), SASS_COMMA);
20
+ l->from_selector(true);
20
21
  for (size_t i = 0, L = sel->length(); i < L; ++i) {
21
22
  if (!(*sel)[i]) continue;
22
23
  *l << (*sel)[i]->perform(this);
@@ -38,7 +39,7 @@ namespace Sass {
38
39
  Expression* Listize::operator()(Complex_Selector* sel)
39
40
  {
40
41
  List* l = SASS_MEMORY_NEW(mem, List, sel->pstate(), 2);
41
-
42
+ l->from_selector(true);
42
43
  Compound_Selector* head = sel->head();
43
44
  if (head && !head->is_empty_reference())
44
45
  {
@@ -18,7 +18,7 @@ namespace Sass {
18
18
  virtual T operator()(Supports_Block* x) = 0;
19
19
  virtual T operator()(Media_Block* x) = 0;
20
20
  virtual T operator()(At_Root_Block* x) = 0;
21
- virtual T operator()(At_Rule* x) = 0;
21
+ virtual T operator()(Directive* x) = 0;
22
22
  virtual T operator()(Keyframe_Rule* x) = 0;
23
23
  virtual T operator()(Declaration* x) = 0;
24
24
  virtual T operator()(Assignment* x) = 0;
@@ -61,7 +61,7 @@ namespace Sass {
61
61
  virtual T operator()(Supports_Interpolation* x) = 0;
62
62
  virtual T operator()(Media_Query* x) = 0;
63
63
  virtual T operator()(Media_Query_Expression* x) = 0;
64
- virtual T operator()(At_Root_Expression* x) = 0;
64
+ virtual T operator()(At_Root_Query* x) = 0;
65
65
  virtual T operator()(Null* x) = 0;
66
66
  virtual T operator()(Parent_Selector* x) = 0;
67
67
  // parameters and arguments
@@ -99,7 +99,7 @@ namespace Sass {
99
99
  T operator()(Supports_Block* x) { return static_cast<D*>(this)->fallback(x); }
100
100
  T operator()(Media_Block* x) { return static_cast<D*>(this)->fallback(x); }
101
101
  T operator()(At_Root_Block* x) { return static_cast<D*>(this)->fallback(x); }
102
- T operator()(At_Rule* x) { return static_cast<D*>(this)->fallback(x); }
102
+ T operator()(Directive* x) { return static_cast<D*>(this)->fallback(x); }
103
103
  T operator()(Keyframe_Rule* x) { return static_cast<D*>(this)->fallback(x); }
104
104
  T operator()(Declaration* x) { return static_cast<D*>(this)->fallback(x); }
105
105
  T operator()(Assignment* x) { return static_cast<D*>(this)->fallback(x); }
@@ -142,7 +142,7 @@ namespace Sass {
142
142
  T operator()(Supports_Interpolation* x) { return static_cast<D*>(this)->fallback(x); }
143
143
  T operator()(Media_Query* x) { return static_cast<D*>(this)->fallback(x); }
144
144
  T operator()(Media_Query_Expression* x) { return static_cast<D*>(this)->fallback(x); }
145
- T operator()(At_Root_Expression* x) { return static_cast<D*>(this)->fallback(x); }
145
+ T operator()(At_Root_Query* x) { return static_cast<D*>(this)->fallback(x); }
146
146
  T operator()(Null* x) { return static_cast<D*>(this)->fallback(x); }
147
147
  T operator()(Parent_Selector* x) { return static_cast<D*>(this)->fallback(x); }
148
148
  // parameters and arguments
@@ -310,7 +310,7 @@ namespace Sass {
310
310
  append_scope_closer();
311
311
  }
312
312
 
313
- void Output::operator()(At_Rule* a)
313
+ void Output::operator()(Directive* a)
314
314
  {
315
315
  std::string kwd = a->keyword();
316
316
  Selector* s = a->selector();
@@ -38,7 +38,7 @@ namespace Sass {
38
38
  // virtual void operator()(Propset*);
39
39
  virtual void operator()(Supports_Block*);
40
40
  virtual void operator()(Media_Block*);
41
- virtual void operator()(At_Rule*);
41
+ virtual void operator()(Directive*);
42
42
  virtual void operator()(Keyframe_Rule*);
43
43
  virtual void operator()(Import*);
44
44
  virtual void operator()(Comment*);
@@ -250,7 +250,9 @@ namespace Sass {
250
250
  else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
251
251
 
252
252
  // generic at keyword (keep last)
253
- else if (lex< at_keyword >(true)) { (*block) << parse_at_rule(); }
253
+ else if (lex< re_special_directive >(true)) { (*block) << parse_special_directive(); }
254
+ else if (lex< re_prefixed_directive >(true)) { (*block) << parse_prefixed_directive(); }
255
+ else if (lex< at_keyword >(true)) { (*block) << parse_directive(); }
254
256
 
255
257
  else if (block->is_root()) {
256
258
  lex< css_whitespace >();
@@ -1325,10 +1327,7 @@ namespace Sass {
1325
1327
  else if (peek< ie_keyword_arg >()) {
1326
1328
  return parse_ie_keyword_arg();
1327
1329
  }
1328
- else if (peek< exactly< calc_kwd > >() ||
1329
- peek< exactly< moz_calc_kwd > >() ||
1330
- peek< exactly< ms_calc_kwd > >() ||
1331
- peek< exactly< webkit_calc_kwd > >()) {
1330
+ else if (peek< sequence < calc_fn_call, exactly <'('> > >()) {
1332
1331
  return parse_calc_function();
1333
1332
  }
1334
1333
  else if (lex < functional_schema >()) {
@@ -1773,6 +1772,7 @@ namespace Sass {
1773
1772
  prefix = std::string(lexed);
1774
1773
  }
1775
1774
 
1775
+ lex < optional_spaces >();
1776
1776
  String* url_string = parse_url_function_argument();
1777
1777
 
1778
1778
  std::string suffix("");
@@ -1809,7 +1809,7 @@ namespace Sass {
1809
1809
  if (peek< exactly< hash_lbrace > >()) {
1810
1810
  const char* pp = position;
1811
1811
  // TODO: error checking for unclosed interpolants
1812
- while (peek< exactly< hash_lbrace > >(pp)) {
1812
+ while (pp && peek< exactly< hash_lbrace > >(pp)) {
1813
1813
  pp = sequence< interpolant, real_uri_value >(pp);
1814
1814
  }
1815
1815
  position = pp;
@@ -2142,13 +2142,14 @@ namespace Sass {
2142
2142
  {
2143
2143
  ParserState at_source_position = pstate;
2144
2144
  Block* body = 0;
2145
- At_Root_Expression* expr = 0;
2145
+ At_Root_Query* expr = 0;
2146
2146
  Lookahead lookahead_result;
2147
2147
  LOCAL_FLAG(in_at_root, true);
2148
- if (lex< exactly<'('> >()) {
2149
- expr = parse_at_root_expression();
2148
+ if (lex_css< exactly<'('> >()) {
2149
+ expr = parse_at_root_query();
2150
2150
  }
2151
- if (peek < exactly<'{'> >()) {
2151
+ if (peek_css < exactly<'{'> >()) {
2152
+ lex <optional_spaces>();
2152
2153
  body = parse_block(true);
2153
2154
  }
2154
2155
  else if ((lookahead_result = lookahead_for_selector(position)).found) {
@@ -2161,7 +2162,7 @@ namespace Sass {
2161
2162
  return at_root;
2162
2163
  }
2163
2164
 
2164
- At_Root_Expression* Parser::parse_at_root_expression()
2165
+ At_Root_Query* Parser::parse_at_root_query()
2165
2166
  {
2166
2167
  if (peek< exactly<')'> >()) error("at-root feature required in at-root expression", pstate);
2167
2168
 
@@ -2169,29 +2170,60 @@ namespace Sass {
2169
2170
  css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
2170
2171
  }
2171
2172
 
2172
- Declaration* declaration = parse_declaration();
2173
- List* value = SASS_MEMORY_NEW(ctx.mem, List, declaration->value()->pstate(), 1);
2173
+ Expression* feature = parse_list();
2174
+ if (!lex_css< exactly<':'> >()) error("style declaration must contain a value", pstate);
2175
+ Expression* expression = parse_list();
2176
+ List* value = SASS_MEMORY_NEW(ctx.mem, List, feature->pstate(), 1);
2174
2177
 
2175
- if (declaration->value()->concrete_type() == Expression::LIST) {
2176
- value = static_cast<List*>(declaration->value());
2178
+ if (expression->concrete_type() == Expression::LIST) {
2179
+ value = static_cast<List*>(expression);
2177
2180
  }
2178
- else *value << declaration->value();
2181
+ else *value << expression;
2179
2182
 
2180
- At_Root_Expression* cond = SASS_MEMORY_NEW(ctx.mem, At_Root_Expression,
2181
- declaration->pstate(),
2182
- declaration->property(),
2183
- value);
2184
- if (!lex< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
2183
+ At_Root_Query* cond = SASS_MEMORY_NEW(ctx.mem, At_Root_Query,
2184
+ value->pstate(),
2185
+ feature,
2186
+ value);
2187
+ if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
2185
2188
  return cond;
2186
2189
  }
2187
2190
 
2188
- At_Rule* Parser::parse_at_rule()
2191
+ Directive* Parser::parse_special_directive()
2192
+ {
2193
+ std::string kwd(lexed);
2194
+
2195
+ if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
2196
+
2197
+ Directive* at_rule = SASS_MEMORY_NEW(ctx.mem, Directive, pstate, kwd);
2198
+ Lookahead lookahead = lookahead_for_include(position);
2199
+ if (lookahead.found && !lookahead.has_interpolants) {
2200
+ at_rule->selector(parse_selector_list(true));
2201
+ }
2202
+
2203
+ lex < css_comments >(false);
2204
+
2205
+ if (lex < static_property >()) {
2206
+ at_rule->value(parse_interpolated_chunk(Token(lexed)));
2207
+ } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
2208
+ at_rule->value(parse_list());
2209
+ }
2210
+
2211
+ lex < css_comments >(false);
2212
+
2213
+ if (peek< exactly<'{'> >()) {
2214
+ at_rule->block(parse_block());
2215
+ }
2216
+
2217
+ return at_rule;
2218
+ }
2219
+
2220
+ Directive* Parser::parse_prefixed_directive()
2189
2221
  {
2190
2222
  std::string kwd(lexed);
2191
2223
 
2192
2224
  if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
2193
2225
 
2194
- At_Rule* at_rule = SASS_MEMORY_NEW(ctx.mem, At_Rule, pstate, kwd);
2226
+ Directive* at_rule = SASS_MEMORY_NEW(ctx.mem, Directive, pstate, kwd);
2195
2227
  Lookahead lookahead = lookahead_for_include(position);
2196
2228
  if (lookahead.found && !lookahead.has_interpolants) {
2197
2229
  at_rule->selector(parse_selector_list(true));
@@ -2214,6 +2246,137 @@ namespace Sass {
2214
2246
  return at_rule;
2215
2247
  }
2216
2248
 
2249
+
2250
+ Directive* Parser::parse_directive()
2251
+ {
2252
+ Directive* directive = SASS_MEMORY_NEW(ctx.mem, Directive, pstate, lexed);
2253
+ Expression* val = parse_almost_any_value();
2254
+ // strip left and right if they are of type string
2255
+ // debug_ast(val);
2256
+ // std::cerr << "HAASDASD\n";
2257
+ directive->value(val);
2258
+ if (peek< exactly<'{'> >()) {
2259
+ directive->block(parse_block());
2260
+ } else if (!val) {
2261
+ css_error("most def");
2262
+ }
2263
+ return directive;
2264
+ }
2265
+
2266
+ Expression* Parser::lex_interpolation()
2267
+ {
2268
+ if (lex < interpolant >(true) != NULL) {
2269
+ return parse_interpolated_chunk(lexed, true);
2270
+ }
2271
+ return 0;
2272
+ }
2273
+
2274
+ Expression* Parser::lex_interp_uri()
2275
+ {
2276
+ // create a string schema by lexing optional interpolations
2277
+ return lex_interp< re_string_uri_open, re_string_uri_close >();
2278
+ }
2279
+
2280
+ Expression* Parser::lex_interp_string()
2281
+ {
2282
+ Expression* rv = 0;
2283
+ if ((rv = lex_interp< re_string_double_open, re_string_double_close >()) != NULL) return rv;
2284
+ if ((rv = lex_interp< re_string_single_open, re_string_single_close >()) != NULL) return rv;
2285
+ return rv;
2286
+ }
2287
+
2288
+ Expression* Parser::lex_almost_any_value_chars()
2289
+ {
2290
+ const char* match =
2291
+ lex <
2292
+ one_plus <
2293
+ alternatives <
2294
+ sequence <
2295
+ exactly <'\\'>,
2296
+ any_char
2297
+ >,
2298
+ sequence <
2299
+ negate <
2300
+ sequence <
2301
+ exactly < url_kwd >,
2302
+ exactly <'('>
2303
+ >
2304
+ >,
2305
+ neg_class_char <
2306
+ almost_any_value_class
2307
+ >
2308
+ >,
2309
+ sequence <
2310
+ exactly <'/'>,
2311
+ negate <
2312
+ alternatives <
2313
+ exactly <'/'>,
2314
+ exactly <'*'>
2315
+ >
2316
+ >
2317
+ >,
2318
+ sequence <
2319
+ exactly <'\\'>,
2320
+ exactly <'#'>,
2321
+ negate <
2322
+ exactly <'{'>
2323
+ >
2324
+ >,
2325
+ sequence <
2326
+ exactly <'!'>,
2327
+ negate <
2328
+ alpha
2329
+ >
2330
+ >
2331
+ >
2332
+ >
2333
+ >(false);
2334
+ if (match) {
2335
+ // std::cerr << "[[" << std::string(lexed) << "]\n";
2336
+ return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
2337
+ }
2338
+ return NULL;
2339
+ }
2340
+
2341
+ Expression* Parser::lex_almost_any_value_token()
2342
+ {
2343
+ Expression* rv = 0;
2344
+ if (*position == 0) return 0;
2345
+ if ((rv = lex_almost_any_value_chars()) != NULL) return rv;
2346
+ // if ((rv = lex_block_comment()) != NULL) return rv;
2347
+ // if ((rv = lex_single_line_comment()) != NULL) return rv;
2348
+ if ((rv = lex_interp_string()) != NULL) return rv;
2349
+ if ((rv = lex_interp_uri()) != NULL) return rv;
2350
+ if ((rv = lex_interpolation()) != NULL) return rv;
2351
+ return rv;
2352
+ }
2353
+
2354
+ String_Schema* Parser::parse_almost_any_value()
2355
+ {
2356
+
2357
+ String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
2358
+ if (*position == 0) return 0;
2359
+ lex < spaces >(false);
2360
+ Expression* token = lex_almost_any_value_token();
2361
+ if (!token) return 0;
2362
+ // std::cerr << "LEX [" << std::string(lexed) << "]\n";
2363
+ *schema << token;
2364
+ if (*position == 0) {
2365
+ schema->rtrim();
2366
+ return schema;
2367
+ }
2368
+
2369
+ while ((token = lex_almost_any_value_token())) {
2370
+ *schema << token;
2371
+ }
2372
+
2373
+ lex < css_whitespace >();
2374
+
2375
+ schema->rtrim();
2376
+
2377
+ return schema;
2378
+ }
2379
+
2217
2380
  Warning* Parser::parse_warning()
2218
2381
  {
2219
2382
  if (stack.back() != Scope::Root &&
@@ -2268,72 +2431,7 @@ namespace Sass {
2268
2431
  rv.error = p;
2269
2432
  if (const char* q =
2270
2433
  peek <
2271
- alternatives <
2272
- // partial BEM selector
2273
- sequence <
2274
- ampersand,
2275
- one_plus <
2276
- exactly < '-' >
2277
- >,
2278
- word_boundary
2279
- >,
2280
- // main selector matching
2281
- one_plus <
2282
- alternatives <
2283
- // consume whitespace and comments
2284
- spaces, block_comment, line_comment,
2285
- // match `/deep/` selector (pass-trough)
2286
- // there is no functionality for it yet
2287
- schema_reference_combinator,
2288
- // match selector ops /[*&%,()\[\]]/
2289
- class_char < selector_lookahead_ops >,
2290
- // match selector combinators /[>+~]/
2291
- class_char < selector_combinator_ops >,
2292
- // match attribute compare operators
2293
- alternatives <
2294
- exact_match, class_match, dash_match,
2295
- prefix_match, suffix_match, substring_match
2296
- >,
2297
- // main selector match
2298
- sequence <
2299
- // allow namespace prefix
2300
- optional < namespace_schema >,
2301
- // modifiers prefixes
2302
- alternatives <
2303
- sequence <
2304
- exactly <'#'>,
2305
- // not for interpolation
2306
- negate < exactly <'{'> >
2307
- >,
2308
- // class match
2309
- exactly <'.'>,
2310
- // single or double colon
2311
- optional < pseudo_prefix >
2312
- >,
2313
- // accept hyphens in token
2314
- one_plus < sequence <
2315
- // can start with hyphens
2316
- zero_plus < exactly<'-'> >,
2317
- // now the main token
2318
- alternatives <
2319
- kwd_optional,
2320
- exactly <'*'>,
2321
- quoted_string,
2322
- interpolant,
2323
- identifier,
2324
- variable,
2325
- percentage,
2326
- binomial,
2327
- dimension,
2328
- alnum
2329
- >
2330
- > >,
2331
- // can also end with hyphens
2332
- zero_plus < exactly<'-'> >
2333
- >
2334
- >
2335
- >
2336
- >
2434
+ re_selector_list
2337
2435
  >(p)
2338
2436
  ) {
2339
2437
  while (p < q) {
@@ -2353,6 +2451,7 @@ namespace Sass {
2353
2451
  // check expected opening bracket
2354
2452
  // only after successfull matching
2355
2453
  if (peek < exactly<'{'> >(q)) rv.found = q;
2454
+ else if (peek < exactly<'('> >(q)) rv.found = q;
2356
2455
  // else if (peek < exactly<';'> >(q)) rv.found = q;
2357
2456
  // else if (peek < exactly<'}'> >(q)) rv.found = q;
2358
2457
  if (rv.found || *p == 0) rv.error = 0;
@@ -2366,7 +2465,7 @@ namespace Sass {
2366
2465
  }
2367
2466
  // EO lookahead_for_selector
2368
2467
 
2369
- // used in parse_block_nodes and parse_at_rule
2468
+ // used in parse_block_nodes and parse_special_directive
2370
2469
  // ToDo: actual usage is still not really clear to me?
2371
2470
  Lookahead Parser::lookahead_for_include(const char* start)
2372
2471
  {