sassc 1.11.4 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +2 -2
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/README.md +4 -1
  5. data/ext/libsass/.editorconfig +1 -1
  6. data/ext/libsass/.github/CONTRIBUTING.md +7 -7
  7. data/ext/libsass/.github/ISSUE_TEMPLATE.md +31 -6
  8. data/ext/libsass/.gitignore +3 -0
  9. data/ext/libsass/.travis.yml +37 -18
  10. data/ext/libsass/GNUmakefile.am +23 -37
  11. data/ext/libsass/Makefile +10 -6
  12. data/ext/libsass/Makefile.conf +3 -0
  13. data/ext/libsass/Readme.md +68 -63
  14. data/ext/libsass/appveyor.yml +7 -3
  15. data/ext/libsass/configure.ac +10 -14
  16. data/ext/libsass/docs/api-context-internal.md +29 -21
  17. data/ext/libsass/docs/api-context.md +26 -6
  18. data/ext/libsass/docs/api-doc.md +49 -16
  19. data/ext/libsass/docs/api-function-example.md +1 -1
  20. data/ext/libsass/docs/api-function.md +31 -7
  21. data/ext/libsass/docs/api-importer.md +19 -19
  22. data/ext/libsass/docs/api-value.md +4 -2
  23. data/ext/libsass/docs/build-on-windows.md +4 -4
  24. data/ext/libsass/docs/build-with-mingw.md +3 -3
  25. data/ext/libsass/docs/build.md +9 -9
  26. data/ext/libsass/docs/custom-functions-internal.md +10 -8
  27. data/ext/libsass/docs/implementations.md +20 -8
  28. data/ext/libsass/docs/unicode.md +16 -10
  29. data/ext/libsass/include/sass/base.h +0 -3
  30. data/ext/libsass/include/sass/context.h +20 -2
  31. data/ext/libsass/include/sass/functions.h +31 -0
  32. data/ext/libsass/include/sass/values.h +3 -1
  33. data/ext/libsass/include/sass/version.h +1 -1
  34. data/ext/libsass/include/sass/version.h.in +1 -1
  35. data/ext/libsass/include/sass2scss.h +1 -1
  36. data/ext/libsass/res/resource.rc +6 -6
  37. data/ext/libsass/script/ci-build-libsass +10 -5
  38. data/ext/libsass/script/ci-build-plugin +62 -0
  39. data/ext/libsass/script/ci-install-compiler +1 -1
  40. data/ext/libsass/script/ci-install-deps +4 -7
  41. data/ext/libsass/script/ci-report-coverage +13 -3
  42. data/ext/libsass/script/tap-driver +1 -1
  43. data/ext/libsass/script/tap-runner +1 -1
  44. data/ext/libsass/src/GNUmakefile.am +1 -1
  45. data/ext/libsass/src/ast.cpp +537 -762
  46. data/ext/libsass/src/ast.hpp +377 -419
  47. data/ext/libsass/src/ast_def_macros.hpp +26 -1
  48. data/ext/libsass/src/ast_fwd_decl.cpp +29 -0
  49. data/ext/libsass/src/ast_fwd_decl.hpp +94 -21
  50. data/ext/libsass/src/b64/encode.h +3 -1
  51. data/ext/libsass/src/backtrace.cpp +46 -0
  52. data/ext/libsass/src/backtrace.hpp +7 -54
  53. data/ext/libsass/src/bind.cpp +72 -50
  54. data/ext/libsass/src/bind.hpp +0 -1
  55. data/ext/libsass/src/cencode.c +6 -0
  56. data/ext/libsass/src/check_nesting.cpp +157 -135
  57. data/ext/libsass/src/check_nesting.hpp +11 -10
  58. data/ext/libsass/src/color_maps.cpp +10 -6
  59. data/ext/libsass/src/color_maps.hpp +6 -8
  60. data/ext/libsass/src/constants.cpp +4 -3
  61. data/ext/libsass/src/constants.hpp +4 -3
  62. data/ext/libsass/src/context.cpp +110 -47
  63. data/ext/libsass/src/context.hpp +11 -1
  64. data/ext/libsass/src/cssize.cpp +105 -94
  65. data/ext/libsass/src/cssize.hpp +4 -5
  66. data/ext/libsass/src/debugger.hpp +247 -244
  67. data/ext/libsass/src/emitter.cpp +30 -6
  68. data/ext/libsass/src/emitter.hpp +7 -0
  69. data/ext/libsass/src/environment.cpp +67 -16
  70. data/ext/libsass/src/environment.hpp +28 -7
  71. data/ext/libsass/src/error_handling.cpp +92 -64
  72. data/ext/libsass/src/error_handling.hpp +64 -43
  73. data/ext/libsass/src/eval.cpp +494 -544
  74. data/ext/libsass/src/eval.hpp +17 -23
  75. data/ext/libsass/src/expand.cpp +182 -154
  76. data/ext/libsass/src/expand.hpp +4 -5
  77. data/ext/libsass/src/extend.cpp +299 -291
  78. data/ext/libsass/src/extend.hpp +46 -11
  79. data/ext/libsass/src/file.cpp +103 -36
  80. data/ext/libsass/src/file.hpp +21 -4
  81. data/ext/libsass/src/functions.cpp +561 -312
  82. data/ext/libsass/src/functions.hpp +8 -5
  83. data/ext/libsass/src/inspect.cpp +108 -53
  84. data/ext/libsass/src/inspect.hpp +5 -2
  85. data/ext/libsass/src/lexer.cpp +15 -7
  86. data/ext/libsass/src/lexer.hpp +13 -4
  87. data/ext/libsass/src/listize.cpp +3 -2
  88. data/ext/libsass/src/listize.hpp +0 -1
  89. data/ext/libsass/src/memory/SharedPtr.cpp +16 -18
  90. data/ext/libsass/src/memory/SharedPtr.hpp +47 -43
  91. data/ext/libsass/src/node.cpp +34 -38
  92. data/ext/libsass/src/node.hpp +6 -8
  93. data/ext/libsass/src/operation.hpp +2 -2
  94. data/ext/libsass/src/operators.cpp +240 -0
  95. data/ext/libsass/src/operators.hpp +30 -0
  96. data/ext/libsass/src/output.cpp +22 -20
  97. data/ext/libsass/src/parser.cpp +719 -358
  98. data/ext/libsass/src/parser.hpp +57 -22
  99. data/ext/libsass/src/plugins.cpp +28 -10
  100. data/ext/libsass/src/position.cpp +21 -3
  101. data/ext/libsass/src/position.hpp +2 -1
  102. data/ext/libsass/src/prelexer.cpp +104 -19
  103. data/ext/libsass/src/prelexer.hpp +10 -3
  104. data/ext/libsass/src/remove_placeholders.cpp +9 -10
  105. data/ext/libsass/src/remove_placeholders.hpp +1 -5
  106. data/ext/libsass/src/sass.cpp +62 -4
  107. data/ext/libsass/src/sass.hpp +5 -2
  108. data/ext/libsass/src/sass_context.cpp +96 -58
  109. data/ext/libsass/src/sass_context.hpp +7 -5
  110. data/ext/libsass/src/sass_functions.cpp +63 -1
  111. data/ext/libsass/src/sass_functions.hpp +19 -1
  112. data/ext/libsass/src/sass_util.cpp +3 -3
  113. data/ext/libsass/src/sass_util.hpp +4 -4
  114. data/ext/libsass/src/sass_values.cpp +42 -39
  115. data/ext/libsass/src/sass_values.hpp +2 -1
  116. data/ext/libsass/src/source_map.cpp +16 -18
  117. data/ext/libsass/src/subset_map.cpp +6 -8
  118. data/ext/libsass/src/subset_map.hpp +6 -6
  119. data/ext/libsass/src/to_c.cpp +2 -2
  120. data/ext/libsass/src/to_value.cpp +8 -3
  121. data/ext/libsass/src/to_value.hpp +1 -0
  122. data/ext/libsass/src/units.cpp +349 -45
  123. data/ext/libsass/src/units.hpp +39 -22
  124. data/ext/libsass/src/utf8/checked.h +7 -0
  125. data/ext/libsass/src/utf8/unchecked.h +7 -0
  126. data/ext/libsass/src/utf8_string.cpp +1 -1
  127. data/ext/libsass/src/util.cpp +139 -45
  128. data/ext/libsass/src/util.hpp +4 -7
  129. data/ext/libsass/src/values.cpp +15 -23
  130. data/ext/libsass/win/libsass.sln +13 -2
  131. data/ext/libsass/win/libsass.sln.DotSettings +9 -0
  132. data/ext/libsass/win/libsass.targets +3 -0
  133. data/ext/libsass/win/libsass.vcxproj.filters +9 -0
  134. data/lib/sassc/version.rb +1 -1
  135. data/sassc.gemspec +1 -1
  136. data/test/native_test.rb +1 -1
  137. metadata +11 -4
@@ -1,7 +1,4 @@
1
1
  #include "sass.hpp"
2
- #include <cstdlib>
3
- #include <iostream>
4
- #include <vector>
5
2
  #include "parser.hpp"
6
3
  #include "file.hpp"
7
4
  #include "inspect.hpp"
@@ -24,18 +21,20 @@
24
21
  // Another case with delayed values are colors. In compressed mode
25
22
  // only processed values get compressed (other are left as written).
26
23
 
24
+ #include <cstdlib>
25
+ #include <iostream>
26
+ #include <vector>
27
27
  #include <typeinfo>
28
- #include <tuple>
29
28
 
30
29
  namespace Sass {
31
30
  using namespace Constants;
32
31
  using namespace Prelexer;
33
32
 
34
- Parser Parser::from_c_str(const char* beg, Context& ctx, ParserState pstate, const char* source)
33
+ Parser Parser::from_c_str(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
35
34
  {
36
35
  pstate.offset.column = 0;
37
36
  pstate.offset.line = 0;
38
- Parser p(ctx, pstate);
37
+ Parser p(ctx, pstate, traces);
39
38
  p.source = source ? source : beg;
40
39
  p.position = beg ? beg : p.source;
41
40
  p.end = p.position + strlen(p.position);
@@ -45,11 +44,11 @@ namespace Sass {
45
44
  return p;
46
45
  }
47
46
 
48
- Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate, const char* source)
47
+ Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
49
48
  {
50
49
  pstate.offset.column = 0;
51
50
  pstate.offset.line = 0;
52
- Parser p(ctx, pstate);
51
+ Parser p(ctx, pstate, traces);
53
52
  p.source = source ? source : beg;
54
53
  p.position = beg ? beg : p.source;
55
54
  p.end = end ? end : p.position + strlen(p.position);
@@ -67,9 +66,9 @@ namespace Sass {
67
66
  pstate.offset.line = 0;
68
67
  }
69
68
 
70
- Selector_List_Obj Parser::parse_selector(const char* beg, Context& ctx, ParserState pstate, const char* source)
69
+ Selector_List_Obj Parser::parse_selector(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
71
70
  {
72
- Parser p = Parser::from_c_str(beg, ctx, pstate, source);
71
+ Parser p = Parser::from_c_str(beg, ctx, traces, pstate, source);
73
72
  // ToDo: ruby sass errors on parent references
74
73
  // ToDo: remap the source-map entries somehow
75
74
  return p.parse_selector_list(false);
@@ -81,9 +80,9 @@ namespace Sass {
81
80
  && ! peek_css<exactly<'{'>>(start);
82
81
  }
83
82
 
84
- Parser Parser::from_token(Token t, Context& ctx, ParserState pstate, const char* source)
83
+ Parser Parser::from_token(Token t, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
85
84
  {
86
- Parser p(ctx, pstate);
85
+ Parser p(ctx, pstate, traces);
87
86
  p.source = source ? source : t.begin;
88
87
  p.position = t.begin ? t.begin : p.source;
89
88
  p.end = t.end ? t.end : p.position + strlen(p.position);
@@ -96,21 +95,35 @@ namespace Sass {
96
95
  /* main entry point to parse root block */
97
96
  Block_Obj Parser::parse()
98
97
  {
99
- bool is_root = false;
100
- Block_Obj root = SASS_MEMORY_NEW(Block, pstate, 0, true);
98
+
99
+ // consume unicode BOM
101
100
  read_bom();
102
101
 
103
- // custom headers
102
+ // scan the input to find invalid utf8 sequences
103
+ const char* it = utf8::find_invalid(position, end);
104
+
105
+ // report invalid utf8
106
+ if (it != end) {
107
+ pstate += Offset::init(position, it);
108
+ traces.push_back(Backtrace(pstate));
109
+ throw Exception::InvalidSass(pstate, traces, "Invalid UTF-8 sequence");
110
+ }
111
+
112
+ // create a block AST node to hold children
113
+ Block_Obj root = SASS_MEMORY_NEW(Block, pstate, 0, true);
114
+
115
+ // check seems a bit esoteric but works
104
116
  if (ctx.resources.size() == 1) {
105
- is_root = true;
106
- ctx.apply_custom_headers(&root, path, pstate);
117
+ // apply headers only on very first include
118
+ ctx.apply_custom_headers(root, path, pstate);
107
119
  }
108
120
 
121
+ // parse children nodes
109
122
  block_stack.push_back(root);
110
- /* bool rv = */ parse_block_nodes(is_root);
123
+ parse_block_nodes(true);
111
124
  block_stack.pop_back();
112
125
 
113
- // update for end position
126
+ // update final position
114
127
  root->update_pstate(pstate);
115
128
 
116
129
  if (position != end) {
@@ -138,7 +151,7 @@ namespace Sass {
138
151
  Block_Obj block = SASS_MEMORY_NEW(Block, pstate, 0, is_root);
139
152
  block_stack.push_back(block);
140
153
 
141
- if (!parse_block_nodes()) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
154
+ if (!parse_block_nodes(is_root)) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
142
155
 
143
156
  if (!lex_css < exactly<'}'> >()) {
144
157
  css_error("Invalid CSS", " after ", ": expected \"}\", was ");
@@ -154,7 +167,7 @@ namespace Sass {
154
167
 
155
168
  block_stack.pop_back();
156
169
 
157
- return &block;
170
+ return block;
158
171
  }
159
172
 
160
173
  // convenience function for block parsing
@@ -162,7 +175,6 @@ namespace Sass {
162
175
  // also updates the `in_at_root` flag
163
176
  Block_Obj Parser::parse_block(bool is_root)
164
177
  {
165
- LOCAL_FLAG(in_at_root, is_root);
166
178
  return parse_css_block(is_root);
167
179
  }
168
180
 
@@ -214,27 +226,29 @@ namespace Sass {
214
226
  // also parse block comments
215
227
 
216
228
  // first parse everything that is allowed in functions
217
- if (lex < variable >(true)) { block->append(&parse_assignment()); }
218
- else if (lex < kwd_err >(true)) { block->append(&parse_error()); }
219
- else if (lex < kwd_dbg >(true)) { block->append(&parse_debug()); }
220
- else if (lex < kwd_warn >(true)) { block->append(&parse_warning()); }
221
- else if (lex < kwd_if_directive >(true)) { block->append(&parse_if_directive()); }
222
- else if (lex < kwd_for_directive >(true)) { block->append(&parse_for_directive()); }
223
- else if (lex < kwd_each_directive >(true)) { block->append(&parse_each_directive()); }
224
- else if (lex < kwd_while_directive >(true)) { block->append(&parse_while_directive()); }
225
- else if (lex < kwd_return_directive >(true)) { block->append(&parse_return_directive()); }
229
+ if (lex < variable >(true)) { block->append(parse_assignment()); }
230
+ else if (lex < kwd_err >(true)) { block->append(parse_error()); }
231
+ else if (lex < kwd_dbg >(true)) { block->append(parse_debug()); }
232
+ else if (lex < kwd_warn >(true)) { block->append(parse_warning()); }
233
+ else if (lex < kwd_if_directive >(true)) { block->append(parse_if_directive()); }
234
+ else if (lex < kwd_for_directive >(true)) { block->append(parse_for_directive()); }
235
+ else if (lex < kwd_each_directive >(true)) { block->append(parse_each_directive()); }
236
+ else if (lex < kwd_while_directive >(true)) { block->append(parse_while_directive()); }
237
+ else if (lex < kwd_return_directive >(true)) { block->append(parse_return_directive()); }
226
238
 
227
239
  // parse imports to process later
228
240
  else if (lex < kwd_import >(true)) {
229
241
  Scope parent = stack.empty() ? Scope::Rules : stack.back();
230
242
  if (parent != Scope::Function && parent != Scope::Root && parent != Scope::Rules && parent != Scope::Media) {
231
243
  if (! peek_css< uri_prefix >(position)) { // this seems to go in ruby sass 3.4.20
232
- error("Import directives may not be used within control directives or mixins.", pstate);
244
+ error("Import directives may not be used within control directives or mixins.");
233
245
  }
234
246
  }
247
+ // this puts the parsed doc into sheets
248
+ // import stub will fetch this in expand
235
249
  Import_Obj imp = parse_import();
236
250
  // if it is a url, we only add the statement
237
- if (!imp->urls().empty()) block->append(&imp);
251
+ if (!imp->urls().empty()) block->append(imp);
238
252
  // process all resources now (add Import_Stub nodes)
239
253
  for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
240
254
  block->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i]));
@@ -244,34 +258,45 @@ namespace Sass {
244
258
  else if (lex < kwd_extend >(true)) {
245
259
  Lookahead lookahead = lookahead_for_include(position);
246
260
  if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was ");
247
- Selector_Obj target;
248
- if (lookahead.has_interpolants) target = &parse_selector_schema(lookahead.found);
249
- else target = &parse_selector_list(true);
250
- block->append(SASS_MEMORY_NEW(Extension, pstate, &target));
261
+ Selector_List_Obj target;
262
+ if (!lookahead.has_interpolants) {
263
+ target = parse_selector_list(true);
264
+ }
265
+ else {
266
+ target = SASS_MEMORY_NEW(Selector_List, pstate);
267
+ target->schema(parse_selector_schema(lookahead.found, true));
268
+ }
269
+
270
+ block->append(SASS_MEMORY_NEW(Extension, pstate, target));
251
271
  }
252
272
 
253
273
  // selector may contain interpolations which need delayed evaluation
254
- else if (!(lookahead_result = lookahead_for_selector(position)).error)
255
- { block->append(&parse_ruleset(lookahead_result, is_root)); }
274
+ else if (
275
+ !(lookahead_result = lookahead_for_selector(position)).error &&
276
+ !lookahead_result.is_custom_property
277
+ )
278
+ {
279
+ block->append(parse_ruleset(lookahead_result));
280
+ }
256
281
 
257
282
  // parse multiple specific keyword directives
258
- else if (lex < kwd_media >(true)) { block->append(&parse_media_block()); }
259
- else if (lex < kwd_at_root >(true)) { block->append(&parse_at_root_block()); }
260
- else if (lex < kwd_include_directive >(true)) { block->append(&parse_include_directive()); }
261
- else if (lex < kwd_content_directive >(true)) { block->append(&parse_content_directive()); }
262
- else if (lex < kwd_supports_directive >(true)) { block->append(&parse_supports_directive()); }
263
- else if (lex < kwd_mixin >(true)) { block->append(&parse_definition(Definition::MIXIN)); }
264
- else if (lex < kwd_function >(true)) { block->append(&parse_definition(Definition::FUNCTION)); }
283
+ else if (lex < kwd_media >(true)) { block->append(parse_media_block()); }
284
+ else if (lex < kwd_at_root >(true)) { block->append(parse_at_root_block()); }
285
+ else if (lex < kwd_include_directive >(true)) { block->append(parse_include_directive()); }
286
+ else if (lex < kwd_content_directive >(true)) { block->append(parse_content_directive()); }
287
+ else if (lex < kwd_supports_directive >(true)) { block->append(parse_supports_directive()); }
288
+ else if (lex < kwd_mixin >(true)) { block->append(parse_definition(Definition::MIXIN)); }
289
+ else if (lex < kwd_function >(true)) { block->append(parse_definition(Definition::FUNCTION)); }
265
290
 
266
291
  // ignore the @charset directive for now
267
292
  else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
268
293
 
269
294
  // generic at keyword (keep last)
270
- else if (lex< re_special_directive >(true)) { block->append(&parse_special_directive()); }
271
- else if (lex< re_prefixed_directive >(true)) { block->append(&parse_prefixed_directive()); }
272
- else if (lex< at_keyword >(true)) { block->append(&parse_directive()); }
295
+ else if (lex< re_special_directive >(true)) { block->append(parse_special_directive()); }
296
+ else if (lex< re_prefixed_directive >(true)) { block->append(parse_prefixed_directive()); }
297
+ else if (lex< at_keyword >(true)) { block->append(parse_directive()); }
273
298
 
274
- else if (is_root /* && block->is_root() */) {
299
+ else if (is_root && stack.back() != Scope::AtRoot /* && block->is_root() */) {
275
300
  lex< css_whitespace >();
276
301
  if (position >= end) return true;
277
302
  css_error("Invalid CSS", " after ", ": expected 1 selector or at-rule, was ");
@@ -283,7 +308,7 @@ namespace Sass {
283
308
  // maybe we are expected to parse something?
284
309
  Declaration_Obj decl = parse_declaration();
285
310
  decl->tabs(indentation);
286
- block->append(&decl);
311
+ block->append(decl);
287
312
  // maybe we have a "sub-block"
288
313
  if (peek< exactly<'{'> >()) {
289
314
  if (decl->is_indented()) ++ indentation;
@@ -312,28 +337,28 @@ namespace Sass {
312
337
  }
313
338
  else if (lex< uri_prefix >()) {
314
339
  Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
315
- Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url", &args);
340
+ Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url", args);
316
341
 
317
342
  if (lex< quoted_string >()) {
318
- Expression_Obj the_url = &parse_string();
319
- args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url));
343
+ Expression_Obj quoted_url = parse_string();
344
+ args->append(SASS_MEMORY_NEW(Argument, quoted_url->pstate(), quoted_url));
320
345
  }
321
- else if (String_Obj the_url = parse_url_function_argument()) {
322
- args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url));
346
+ else if (String_Obj string_url = parse_url_function_argument()) {
347
+ args->append(SASS_MEMORY_NEW(Argument, string_url->pstate(), string_url));
323
348
  }
324
349
  else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
325
- Expression_Obj the_url = parse_list(); // parse_interpolated_chunk(lexed);
326
- args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url));
350
+ Expression_Obj braced_url = parse_list(); // parse_interpolated_chunk(lexed);
351
+ args->append(SASS_MEMORY_NEW(Argument, braced_url->pstate(), braced_url));
327
352
  }
328
353
  else {
329
- error("malformed URL", pstate);
354
+ error("malformed URL");
330
355
  }
331
- if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
332
- to_import.push_back(std::pair<std::string, Function_Call_Obj>("", &result));
356
+ if (!lex< exactly<')'> >()) error("URI is missing ')'");
357
+ to_import.push_back(std::pair<std::string, Function_Call_Obj>("", result));
333
358
  }
334
359
  else {
335
- if (first) error("@import directive requires a url or quoted path", pstate);
336
- else error("expecting another url or quoted path in @import list", pstate);
360
+ if (first) error("@import directive requires a url or quoted path");
361
+ else error("expecting another url or quoted path in @import list");
337
362
  }
338
363
  first = false;
339
364
  } while (lex_css< exactly<','> >());
@@ -345,9 +370,12 @@ namespace Sass {
345
370
 
346
371
  for(auto location : to_import) {
347
372
  if (location.second) {
348
- imp->urls().push_back(&location.second);
349
- } else if (!ctx.call_importers(unquote(location.first), path, pstate, &imp)) {
350
- ctx.import_url(&imp, location.first, path);
373
+ imp->urls().push_back(location.second);
374
+ }
375
+ // check if custom importers want to take over the handling
376
+ else if (!ctx.call_importers(unquote(location.first), path, pstate, imp)) {
377
+ // nobody wants it, so we do our import
378
+ ctx.import_url(imp, location.first, path);
351
379
  }
352
380
  }
353
381
 
@@ -357,37 +385,42 @@ namespace Sass {
357
385
  Definition_Obj Parser::parse_definition(Definition::Type which_type)
358
386
  {
359
387
  std::string which_str(lexed);
360
- if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate);
388
+ if (!lex< identifier >()) error("invalid name in " + which_str + " definition");
361
389
  std::string name(Util::normalize_underscores(lexed));
362
390
  if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not"))
363
- { error("Invalid function name \"" + name + "\".", pstate); }
391
+ { error("Invalid function name \"" + name + "\"."); }
364
392
  ParserState source_position_of_def = pstate;
365
393
  Parameters_Obj params = parse_parameters();
366
394
  if (which_type == Definition::MIXIN) stack.push_back(Scope::Mixin);
367
395
  else stack.push_back(Scope::Function);
368
396
  Block_Obj body = parse_block();
369
397
  stack.pop_back();
370
- return SASS_MEMORY_NEW(Definition, source_position_of_def, name, &params, &body, which_type);
398
+ return SASS_MEMORY_NEW(Definition, source_position_of_def, name, params, body, which_type);
371
399
  }
372
400
 
373
401
  Parameters_Obj Parser::parse_parameters()
374
402
  {
375
- std::string name(lexed);
376
- Position position = after_token;
377
403
  Parameters_Obj params = SASS_MEMORY_NEW(Parameters, pstate);
378
404
  if (lex_css< exactly<'('> >()) {
379
405
  // if there's anything there at all
380
406
  if (!peek_css< exactly<')'> >()) {
381
- do params->append(&parse_parameter());
382
- while (lex_css< exactly<','> >());
407
+ do {
408
+ if (peek< exactly<')'> >()) break;
409
+ params->append(parse_parameter());
410
+ } while (lex_css< exactly<','> >());
411
+ }
412
+ if (!lex_css< exactly<')'> >()) {
413
+ css_error("Invalid CSS", " after ", ": expected \")\", was ");
383
414
  }
384
- if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
385
415
  }
386
416
  return params;
387
417
  }
388
418
 
389
419
  Parameter_Obj Parser::parse_parameter()
390
420
  {
421
+ if (peek< alternatives< exactly<','>, exactly< '{' >, exactly<';'> > >()) {
422
+ css_error("Invalid CSS", " after ", ": expected variable (e.g. $foo), was ");
423
+ }
391
424
  while (lex< alternatives < spaces, block_comment > >());
392
425
  lex < variable >();
393
426
  std::string name(Util::normalize_underscores(lexed));
@@ -402,27 +435,32 @@ namespace Sass {
402
435
  else if (lex< exactly< ellipsis > >()) {
403
436
  is_rest = true;
404
437
  }
405
- return SASS_MEMORY_NEW(Parameter, pos, name, &val, is_rest);
438
+ return SASS_MEMORY_NEW(Parameter, pos, name, val, is_rest);
406
439
  }
407
440
 
408
441
  Arguments_Obj Parser::parse_arguments()
409
442
  {
410
- std::string name(lexed);
411
- Position position = after_token;
412
443
  Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
413
444
  if (lex_css< exactly<'('> >()) {
414
445
  // if there's anything there at all
415
446
  if (!peek_css< exactly<')'> >()) {
416
- do args->append(&parse_argument());
417
- while (lex_css< exactly<','> >());
447
+ do {
448
+ if (peek< exactly<')'> >()) break;
449
+ args->append(parse_argument());
450
+ } while (lex_css< exactly<','> >());
451
+ }
452
+ if (!lex_css< exactly<')'> >()) {
453
+ css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
418
454
  }
419
- if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
420
455
  }
421
456
  return args;
422
457
  }
423
458
 
424
459
  Argument_Obj Parser::parse_argument()
425
460
  {
461
+ if (peek< alternatives< exactly<','>, exactly< '{' >, exactly<';'> > >()) {
462
+ css_error("Invalid CSS", " after ", ": expected \")\", was ");
463
+ }
426
464
  if (peek_css< sequence < exactly< hash_lbrace >, exactly< rbrace > > >()) {
427
465
  position += 2;
428
466
  css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
@@ -441,7 +479,7 @@ namespace Sass {
441
479
  bool is_arglist = false;
442
480
  bool is_keyword = false;
443
481
  Expression_Obj val = parse_space_list();
444
- List_Ptr l = SASS_MEMORY_CAST(List, val);
482
+ List_Ptr l = Cast<List>(val);
445
483
  if (lex_css< exactly< ellipsis > >()) {
446
484
  if (val->concrete_type() == Expression::MAP || (
447
485
  (l != NULL && l->separator() == SASS_HASH)
@@ -457,14 +495,14 @@ namespace Sass {
457
495
  {
458
496
  std::string name(Util::normalize_underscores(lexed));
459
497
  ParserState var_source_position = pstate;
460
- if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
498
+ if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement");
461
499
  if (peek_css< alternatives < exactly<';'>, end_of_file > >()) {
462
500
  css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
463
501
  }
464
502
  Expression_Obj val;
465
503
  Lookahead lookahead = lookahead_for_value(position);
466
504
  if (lookahead.has_interpolants && lookahead.found) {
467
- val = &parse_value_schema(lookahead.found);
505
+ val = parse_value_schema(lookahead.found);
468
506
  } else {
469
507
  val = parse_list();
470
508
  }
@@ -478,15 +516,23 @@ namespace Sass {
478
516
  }
479
517
 
480
518
  // a ruleset connects a selector and a block
481
- Ruleset_Obj Parser::parse_ruleset(Lookahead lookahead, bool is_root)
519
+ Ruleset_Obj Parser::parse_ruleset(Lookahead lookahead)
482
520
  {
521
+ NESTING_GUARD(nestings);
522
+ // inherit is_root from parent block
523
+ Block_Obj parent = block_stack.back();
524
+ bool is_root = parent && parent->is_root();
483
525
  // make sure to move up the the last position
484
526
  lex < optional_css_whitespace >(false, true);
485
527
  // create the connector object (add parts later)
486
528
  Ruleset_Obj ruleset = SASS_MEMORY_NEW(Ruleset, pstate);
487
529
  // parse selector static or as schema to be evaluated later
488
- if (lookahead.parsable) ruleset->selector(&parse_selector_list(is_root));
489
- else ruleset->selector(&parse_selector_schema(lookahead.found));
530
+ if (lookahead.parsable) ruleset->selector(parse_selector_list(false));
531
+ else {
532
+ Selector_List_Obj list = SASS_MEMORY_NEW(Selector_List, pstate);
533
+ list->schema(parse_selector_schema(lookahead.position, false));
534
+ ruleset->selector(list);
535
+ }
490
536
  // then parse the inner block
491
537
  stack.push_back(Scope::Rules);
492
538
  ruleset->block(parse_block());
@@ -494,7 +540,6 @@ namespace Sass {
494
540
  // update for end position
495
541
  ruleset->update_pstate(pstate);
496
542
  ruleset->block()->update_pstate(pstate);
497
- // inherit is_root from parent block
498
543
  // need this info for sanity checks
499
544
  ruleset->is_root(is_root);
500
545
  // return AST Node
@@ -504,15 +549,17 @@ namespace Sass {
504
549
  // parse a selector schema that will be evaluated in the eval stage
505
550
  // uses a string schema internally to do the actual schema handling
506
551
  // in the eval stage we will be re-parse it into an actual selector
507
- Selector_Schema_Obj Parser::parse_selector_schema(const char* end_of_selector)
552
+ Selector_Schema_Obj Parser::parse_selector_schema(const char* end_of_selector, bool chroot)
508
553
  {
554
+ NESTING_GUARD(nestings);
509
555
  // move up to the start
510
556
  lex< optional_spaces >();
511
557
  const char* i = position;
512
558
  // selector schema re-uses string schema implementation
513
559
  String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
514
560
  // the selector schema is pretty much just a wrapper for the string schema
515
- Selector_Schema_Ptr selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema);
561
+ Selector_Schema_Obj selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema);
562
+ selector_schema->connect_parent(chroot == false);
516
563
  selector_schema->media_block(last_media_block);
517
564
 
518
565
  // process until end
@@ -525,23 +572,24 @@ namespace Sass {
525
572
  String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
526
573
  pstate += Offset(parsed);
527
574
  str->update_pstate(pstate);
528
- schema->append(&str);
575
+ schema->append(str);
529
576
  }
530
577
 
531
- // check if the interpolation only contains white-space (error out)
532
- if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
533
- css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
534
- }
535
578
  // skip over all nested inner interpolations up to our own delimiter
536
579
  const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
580
+ // check if the interpolation never ends of only contains white-space (error out)
581
+ if (!j || peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) {
582
+ position = p+2;
583
+ css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
584
+ }
537
585
  // pass inner expression to the parser to resolve nested interpolations
538
586
  pstate.add(p, p+2);
539
- Expression_Obj interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
587
+ Expression_Obj interpolant = Parser::from_c_str(p+2, j, ctx, traces, pstate).parse_list();
540
588
  // set status on the list expression
541
589
  interpolant->is_interpolant(true);
542
590
  // schema->has_interpolants(true);
543
591
  // add to the string schema
544
- schema->append(&interpolant);
592
+ schema->append(interpolant);
545
593
  // advance parser state
546
594
  pstate.add(p+2, j);
547
595
  // advance position
@@ -557,7 +605,7 @@ namespace Sass {
557
605
  pstate += Offset(parsed);
558
606
  str->update_pstate(pstate);
559
607
  i = end_of_selector;
560
- schema->append(&str);
608
+ schema->append(str);
561
609
  }
562
610
  // exit loop
563
611
  }
@@ -574,7 +622,7 @@ namespace Sass {
574
622
  after_token = before_token = pstate;
575
623
 
576
624
  // return parsed result
577
- return selector_schema;
625
+ return selector_schema.detach();
578
626
  }
579
627
  // EO parse_selector_schema
580
628
 
@@ -611,24 +659,29 @@ namespace Sass {
611
659
 
612
660
  // parse a list of complex selectors
613
661
  // this is the main entry point for most
614
- Selector_List_Obj Parser::parse_selector_list(bool in_root)
662
+ Selector_List_Obj Parser::parse_selector_list(bool chroot)
615
663
  {
616
- bool reloop = true;
664
+ bool reloop;
617
665
  bool had_linefeed = false;
666
+ NESTING_GUARD(nestings);
618
667
  Complex_Selector_Obj sel;
619
668
  Selector_List_Obj group = SASS_MEMORY_NEW(Selector_List, pstate);
620
669
  group->media_block(last_media_block);
670
+
671
+ if (peek_css< alternatives < end_of_file, exactly <'{'>, exactly <','> > >()) {
672
+ css_error("Invalid CSS", " after ", ": expected selector, was ");
673
+ }
674
+
621
675
  do {
622
676
  reloop = false;
623
677
 
624
678
  had_linefeed = had_linefeed || peek_newline();
625
679
 
626
- if (peek_css< class_char < selector_list_delims > >())
680
+ if (peek_css< alternatives < class_char < selector_list_delims > > >())
627
681
  break; // in case there are superfluous commas at the end
628
682
 
629
-
630
683
  // now parse the complex selector
631
- sel = parse_complex_selector(in_root);
684
+ sel = parse_complex_selector(chroot);
632
685
 
633
686
  if (!sel) return group.detach();
634
687
 
@@ -662,14 +715,17 @@ namespace Sass {
662
715
  // complex selector, with one of four combinator operations.
663
716
  // the compound selector (head) is optional, since the combinator
664
717
  // can come first in the whole selector sequence (like `> DIV').
665
- Complex_Selector_Obj Parser::parse_complex_selector(bool in_root)
718
+ Complex_Selector_Obj Parser::parse_complex_selector(bool chroot)
666
719
  {
667
720
 
668
- String_Ptr reference = 0;
721
+ NESTING_GUARD(nestings);
722
+ String_Obj reference = 0;
669
723
  lex < block_comment >();
670
724
  advanceToNextToken();
671
725
  Complex_Selector_Obj sel = SASS_MEMORY_NEW(Complex_Selector, pstate);
672
726
 
727
+ if (peek < end_of_file >()) return 0;
728
+
673
729
  // parse the left hand side
674
730
  Compound_Selector_Obj lhs;
675
731
  // special case if it starts with combinator ([+~>])
@@ -678,11 +734,9 @@ namespace Sass {
678
734
  lhs = parse_compound_selector();
679
735
  }
680
736
 
681
- // check for end of file condition
682
- if (peek < end_of_file >()) return 0;
683
737
 
684
738
  // parse combinator between lhs and rhs
685
- Complex_Selector::Combinator combinator;
739
+ Complex_Selector::Combinator combinator = Complex_Selector::ANCESTOR_OF;
686
740
  if (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO;
687
741
  else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES;
688
742
  else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF;
@@ -693,7 +747,6 @@ namespace Sass {
693
747
  reference = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
694
748
  if (!lex < exactly < '/' > >()) return 0; // ToDo: error msg?
695
749
  }
696
- else /* if (lex< zero >()) */ combinator = Complex_Selector::ANCESTOR_OF;
697
750
 
698
751
  if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return 0;
699
752
 
@@ -715,7 +768,7 @@ namespace Sass {
715
768
 
716
769
  // add a parent selector if we are not in a root
717
770
  // also skip adding parent ref if we only have refs
718
- if (!sel->has_parent_ref() && !in_at_root && !in_root) {
771
+ if (!sel->has_parent_ref() && !chroot) {
719
772
  // create the objects to wrap parent selector reference
720
773
  Compound_Selector_Obj head = SASS_MEMORY_NEW(Compound_Selector, pstate);
721
774
  Parent_Selector_Ptr parent = SASS_MEMORY_NEW(Parent_Selector, pstate, false);
@@ -760,7 +813,7 @@ namespace Sass {
760
813
  // parse functional
761
814
  if (match < re_pseudo_selector >())
762
815
  {
763
- seq->append(&parse_simple_selector());
816
+ seq->append(parse_simple_selector());
764
817
  }
765
818
  // parse parent selector
766
819
  else if (lex< exactly<'&'> >(false))
@@ -795,11 +848,11 @@ namespace Sass {
795
848
  else {
796
849
  Simple_Selector_Obj sel = parse_simple_selector();
797
850
  if (!sel) return 0;
798
- seq->append(&sel);
851
+ seq->append(sel);
799
852
  }
800
853
  }
801
854
 
802
- if (seq && !peek_css<exactly<'{'>>()) {
855
+ if (seq && !peek_css<alternatives<end_of_file,exactly<'{'>>>()) {
803
856
  seq->has_line_break(peek_newline());
804
857
  }
805
858
 
@@ -818,29 +871,29 @@ namespace Sass {
818
871
  else if (lex< id_name >()) {
819
872
  return SASS_MEMORY_NEW(Id_Selector, pstate, lexed);
820
873
  }
821
- else if (lex< quoted_string >()) {
822
- return SASS_MEMORY_NEW(Element_Selector, pstate, unquote(lexed));
823
- }
824
874
  else if (lex< alternatives < variable, number, static_reference_combinator > >()) {
825
875
  return SASS_MEMORY_NEW(Element_Selector, pstate, lexed);
826
876
  }
827
877
  else if (peek< pseudo_not >()) {
828
- return &parse_negated_selector();
878
+ return parse_negated_selector();
829
879
  }
830
880
  else if (peek< re_pseudo_selector >()) {
831
- return &parse_pseudo_selector();
881
+ return parse_pseudo_selector();
832
882
  }
833
883
  else if (peek< exactly<':'> >()) {
834
- return &parse_pseudo_selector();
884
+ return parse_pseudo_selector();
835
885
  }
836
886
  else if (lex < exactly<'['> >()) {
837
- return &parse_attribute_selector();
887
+ return parse_attribute_selector();
838
888
  }
839
889
  else if (lex< placeholder >()) {
840
890
  Placeholder_Selector_Ptr sel = SASS_MEMORY_NEW(Placeholder_Selector, pstate, lexed);
841
891
  sel->media_block(last_media_block);
842
892
  return sel;
843
893
  }
894
+ else {
895
+ css_error("Invalid CSS", " after ", ": expected selector, was ");
896
+ }
844
897
  // failed
845
898
  return 0;
846
899
  }
@@ -852,10 +905,10 @@ namespace Sass {
852
905
  ParserState nsource_position = pstate;
853
906
  Selector_List_Obj negated = parse_selector_list(true);
854
907
  if (!lex< exactly<')'> >()) {
855
- error("negated selector is missing ')'", pstate);
908
+ error("negated selector is missing ')'");
856
909
  }
857
910
  name.erase(name.size() - 1);
858
- return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name, &negated);
911
+ return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name, negated);
859
912
  }
860
913
 
861
914
  // a pseudo selector often starts with one or two colons
@@ -888,15 +941,15 @@ namespace Sass {
888
941
  >()
889
942
  ) {
890
943
  lex_css< alternatives < static_value, binomial > >();
891
- String_Constant_Ptr expr = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
892
- if (expr && lex_css< exactly<')'> >()) {
944
+ String_Constant_Obj expr = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
945
+ if (lex_css< exactly<')'> >()) {
893
946
  expr->can_compress_whitespace(true);
894
947
  return SASS_MEMORY_NEW(Pseudo_Selector, p, name, expr);
895
948
  }
896
949
  }
897
950
  else if (Selector_List_Obj wrapped = parse_selector_list(true)) {
898
951
  if (wrapped && lex_css< exactly<')'> >()) {
899
- return SASS_MEMORY_NEW(Wrapped_Selector, p, name, &wrapped);
952
+ return SASS_MEMORY_NEW(Wrapped_Selector, p, name, wrapped);
900
953
  }
901
954
  }
902
955
 
@@ -916,15 +969,31 @@ namespace Sass {
916
969
  return 0;
917
970
  }
918
971
 
972
+ const char* Parser::re_attr_sensitive_close(const char* src)
973
+ {
974
+ return alternatives < exactly<']'>, exactly<'/'> >(src);
975
+ }
976
+
977
+ const char* Parser::re_attr_insensitive_close(const char* src)
978
+ {
979
+ return sequence < insensitive<'i'>, re_attr_sensitive_close >(src);
980
+ }
981
+
919
982
  Attribute_Selector_Obj Parser::parse_attribute_selector()
920
983
  {
921
984
  ParserState p = pstate;
922
- if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector", pstate);
985
+ if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector");
923
986
  std::string name(lexed);
924
- if (lex_css< alternatives < exactly<']'>, exactly<'/'> > >()) return SASS_MEMORY_NEW(Attribute_Selector, p, name, "", 0);
987
+ if (lex_css< re_attr_sensitive_close >()) {
988
+ return SASS_MEMORY_NEW(Attribute_Selector, p, name, "", 0, 0);
989
+ }
990
+ else if (lex_css< re_attr_insensitive_close >()) {
991
+ char modifier = lexed.begin[0];
992
+ return SASS_MEMORY_NEW(Attribute_Selector, p, name, "", 0, modifier);
993
+ }
925
994
  if (!lex_css< alternatives< exact_match, class_match, dash_match,
926
995
  prefix_match, suffix_match, substring_match > >()) {
927
- error("invalid operator in attribute selector for " + name, pstate);
996
+ error("invalid operator in attribute selector for " + name);
928
997
  }
929
998
  std::string matcher(lexed);
930
999
 
@@ -933,14 +1002,21 @@ namespace Sass {
933
1002
  value = SASS_MEMORY_NEW(String_Constant, p, lexed);
934
1003
  }
935
1004
  else if (lex_css< quoted_string >()) {
936
- value = &parse_interpolated_chunk(lexed, true); // needed!
1005
+ value = parse_interpolated_chunk(lexed, true); // needed!
937
1006
  }
938
1007
  else {
939
- error("expected a string constant or identifier in attribute selector for " + name, pstate);
1008
+ error("expected a string constant or identifier in attribute selector for " + name);
940
1009
  }
941
1010
 
942
- if (!lex_css< alternatives < exactly<']'>, exactly<'/'> > >()) error("unterminated attribute selector for " + name, pstate);
943
- return SASS_MEMORY_NEW(Attribute_Selector, p, name, matcher, value);
1011
+ if (lex_css< re_attr_sensitive_close >()) {
1012
+ return SASS_MEMORY_NEW(Attribute_Selector, p, name, matcher, value, 0);
1013
+ }
1014
+ else if (lex_css< re_attr_insensitive_close >()) {
1015
+ char modifier = lexed.begin[0];
1016
+ return SASS_MEMORY_NEW(Attribute_Selector, p, name, matcher, value, modifier);
1017
+ }
1018
+ error("unterminated attribute selector for " + name);
1019
+ return NULL; // to satisfy compilers (error must not return)
944
1020
  }
945
1021
 
946
1022
  /* parse block comment and add to block */
@@ -951,17 +1027,22 @@ namespace Sass {
951
1027
  while (lex< block_comment >()) {
952
1028
  bool is_important = lexed.begin[2] == '!';
953
1029
  // flag on second param is to skip loosely over comments
954
- String_Obj contents = parse_interpolated_chunk(lexed, true);
1030
+ String_Obj contents = parse_interpolated_chunk(lexed, true, false);
955
1031
  block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
956
1032
  }
957
1033
  }
958
1034
 
959
1035
  Declaration_Obj Parser::parse_declaration() {
960
1036
  String_Obj prop;
1037
+ bool is_custom_property = false;
961
1038
  if (lex< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
1039
+ const std::string property(lexed);
1040
+ is_custom_property = property.compare(0, 2, "--") == 0;
962
1041
  prop = parse_identifier_schema();
963
1042
  }
964
1043
  else if (lex< sequence< optional< exactly<'*'> >, identifier, zero_plus< block_comment > > >()) {
1044
+ const std::string property(lexed);
1045
+ is_custom_property = property.compare(0, 2, "--") == 0;
965
1046
  prop = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
966
1047
  }
967
1048
  else {
@@ -969,27 +1050,30 @@ namespace Sass {
969
1050
  }
970
1051
  bool is_indented = true;
971
1052
  const std::string property(lexed);
972
- if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + property + "\" must be followed by a ':'", pstate);
1053
+ if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + escape_string(property) + "\" must be followed by a ':'");
1054
+ if (!is_custom_property && match< sequence< optional_css_comments, exactly<';'> > >()) error("style declaration must contain a value");
1055
+ if (match< sequence< optional_css_comments, exactly<'{'> > >()) is_indented = false; // don't indent if value is empty
1056
+ if (is_custom_property) {
1057
+ return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, parse_css_variable_value(), false, true);
1058
+ }
973
1059
  lex < css_comments >(false);
974
- if (peek_css< exactly<';'> >()) error("style declaration must contain a value", pstate);
975
- if (peek_css< exactly<'{'> >()) is_indented = false; // don't indent if value is empty
976
1060
  if (peek_css< static_value >()) {
977
- return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, &parse_static_value()/*, lex<kwd_important>()*/);
1061
+ return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, parse_static_value()/*, lex<kwd_important>()*/);
978
1062
  }
979
1063
  else {
980
1064
  Expression_Obj value;
981
1065
  Lookahead lookahead = lookahead_for_value(position);
982
1066
  if (lookahead.found) {
983
1067
  if (lookahead.has_interpolants) {
984
- value = &parse_value_schema(lookahead.found);
1068
+ value = parse_value_schema(lookahead.found);
985
1069
  } else {
986
- value = &parse_list(DELAYED);
1070
+ value = parse_list(DELAYED);
987
1071
  }
988
1072
  }
989
1073
  else {
990
- value = &parse_list(DELAYED);
991
- if (List_Ptr list = SASS_MEMORY_CAST(List, value)) {
992
- if (list->length() == 0 && !peek< exactly <'{'> >()) {
1074
+ value = parse_list(DELAYED);
1075
+ if (List_Ptr list = Cast<List>(value)) {
1076
+ if (!list->is_bracketed() && list->length() == 0 && !peek< exactly <'{'> >()) {
993
1077
  css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
994
1078
  }
995
1079
  }
@@ -1003,6 +1087,7 @@ namespace Sass {
1003
1087
  }
1004
1088
 
1005
1089
  // parse +/- and return false if negative
1090
+ // this is never hit via spec tests
1006
1091
  bool Parser::parse_number_prefix()
1007
1092
  {
1008
1093
  bool positive = true;
@@ -1020,6 +1105,7 @@ namespace Sass {
1020
1105
 
1021
1106
  Expression_Obj Parser::parse_map()
1022
1107
  {
1108
+ NESTING_GUARD(nestings);
1023
1109
  Expression_Obj key = parse_list();
1024
1110
  List_Obj map = SASS_MEMORY_NEW(List, pstate, 0, SASS_HASH);
1025
1111
 
@@ -1027,6 +1113,11 @@ namespace Sass {
1027
1113
  if (!lex_css< exactly<':'> >())
1028
1114
  { return key; }
1029
1115
 
1116
+ List_Obj l = Cast<List>(key);
1117
+ if (l && l->separator() == SASS_COMMA) {
1118
+ css_error("Invalid CSS", " after ", ": expected \")\", was ");
1119
+ }
1120
+
1030
1121
  Expression_Obj value = parse_space_list();
1031
1122
 
1032
1123
  map->append(key);
@@ -1038,12 +1129,12 @@ namespace Sass {
1038
1129
  if (peek_css< exactly<')'> >(position))
1039
1130
  { break; }
1040
1131
 
1041
- Expression_Obj key = parse_space_list();
1132
+ key = parse_space_list();
1042
1133
 
1043
1134
  if (!(lex< exactly<':'> >()))
1044
1135
  { css_error("Invalid CSS", " after ", ": expected \":\", was "); }
1045
1136
 
1046
- Expression_Obj value = parse_space_list();
1137
+ value = parse_space_list();
1047
1138
 
1048
1139
  map->append(key);
1049
1140
  map->append(value);
@@ -1053,7 +1144,51 @@ namespace Sass {
1053
1144
  ps.offset = pstate - ps + pstate.offset;
1054
1145
  map->pstate(ps);
1055
1146
 
1056
- return &map;
1147
+ return map;
1148
+ }
1149
+
1150
+ Expression_Obj Parser::parse_bracket_list()
1151
+ {
1152
+ NESTING_GUARD(nestings);
1153
+ // check if we have an empty list
1154
+ // return the empty list as such
1155
+ if (peek_css< list_terminator >(position))
1156
+ {
1157
+ // return an empty list (nothing to delay)
1158
+ return SASS_MEMORY_NEW(List, pstate, 0, SASS_SPACE, false, true);
1159
+ }
1160
+
1161
+ bool has_paren = peek_css< exactly<'('> >() != NULL;
1162
+
1163
+ // now try to parse a space list
1164
+ Expression_Obj list = parse_space_list();
1165
+ // if it's a singleton, return it (don't wrap it)
1166
+ if (!peek_css< exactly<','> >(position)) {
1167
+ List_Obj l = Cast<List>(list);
1168
+ if (!l || l->is_bracketed() || has_paren) {
1169
+ List_Obj bracketed_list = SASS_MEMORY_NEW(List, pstate, 1, SASS_SPACE, false, true);
1170
+ bracketed_list->append(list);
1171
+ return bracketed_list;
1172
+ }
1173
+ l->is_bracketed(true);
1174
+ return l;
1175
+ }
1176
+
1177
+ // if we got so far, we actually do have a comma list
1178
+ List_Obj bracketed_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_COMMA, false, true);
1179
+ // wrap the first expression
1180
+ bracketed_list->append(list);
1181
+
1182
+ while (lex_css< exactly<','> >())
1183
+ {
1184
+ // check for abort condition
1185
+ if (peek_css< list_terminator >(position)
1186
+ ) { break; }
1187
+ // otherwise add another expression
1188
+ bracketed_list->append(parse_space_list());
1189
+ }
1190
+ // return the list
1191
+ return bracketed_list;
1057
1192
  }
1058
1193
 
1059
1194
  // parse list returns either a space separated list,
@@ -1061,26 +1196,17 @@ namespace Sass {
1061
1196
  // so to speak: we unwrap items from lists if possible here!
1062
1197
  Expression_Obj Parser::parse_list(bool delayed)
1063
1198
  {
1199
+ NESTING_GUARD(nestings);
1064
1200
  return parse_comma_list(delayed);
1065
1201
  }
1066
1202
 
1067
1203
  // will return singletons unwrapped
1068
1204
  Expression_Obj Parser::parse_comma_list(bool delayed)
1069
1205
  {
1206
+ NESTING_GUARD(nestings);
1070
1207
  // check if we have an empty list
1071
1208
  // return the empty list as such
1072
- if (peek_css< alternatives <
1073
- // exactly<'!'>,
1074
- exactly<';'>,
1075
- exactly<'}'>,
1076
- exactly<'{'>,
1077
- exactly<')'>,
1078
- exactly<':'>,
1079
- end_of_file,
1080
- exactly<ellipsis>,
1081
- default_flag,
1082
- global_flag
1083
- > >(position))
1209
+ if (peek_css< list_terminator >(position))
1084
1210
  {
1085
1211
  // return an empty list (nothing to delay)
1086
1212
  return SASS_MEMORY_NEW(List, pstate, 0);
@@ -1104,74 +1230,45 @@ namespace Sass {
1104
1230
  while (lex_css< exactly<','> >())
1105
1231
  {
1106
1232
  // check for abort condition
1107
- if (peek_css< alternatives <
1108
- exactly<';'>,
1109
- exactly<'}'>,
1110
- exactly<'{'>,
1111
- exactly<')'>,
1112
- exactly<':'>,
1113
- end_of_file,
1114
- exactly<ellipsis>,
1115
- default_flag,
1116
- global_flag
1117
- > >(position)
1233
+ if (peek_css< list_terminator >(position)
1118
1234
  ) { break; }
1119
1235
  // otherwise add another expression
1120
1236
  comma_list->append(parse_space_list());
1121
1237
  }
1122
1238
  // return the list
1123
- return &comma_list;
1239
+ return comma_list;
1124
1240
  }
1125
1241
  // EO parse_comma_list
1126
1242
 
1127
1243
  // will return singletons unwrapped
1128
1244
  Expression_Obj Parser::parse_space_list()
1129
1245
  {
1246
+ NESTING_GUARD(nestings);
1130
1247
  Expression_Obj disj1 = parse_disjunction();
1131
1248
  // if it's a singleton, return it (don't wrap it)
1132
- if (peek_css< alternatives <
1133
- // exactly<'!'>,
1134
- exactly<';'>,
1135
- exactly<'}'>,
1136
- exactly<'{'>,
1137
- exactly<')'>,
1138
- exactly<','>,
1139
- exactly<':'>,
1140
- end_of_file,
1141
- exactly<ellipsis>,
1142
- default_flag,
1143
- global_flag
1144
- > >(position)
1145
- ) { return disj1; }
1249
+ if (peek_css< space_list_terminator >(position)
1250
+ ) {
1251
+ return disj1; }
1146
1252
 
1147
1253
  List_Obj space_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_SPACE);
1148
1254
  space_list->append(disj1);
1149
1255
 
1150
- while (!(peek_css< alternatives <
1151
- // exactly<'!'>,
1152
- exactly<';'>,
1153
- exactly<'}'>,
1154
- exactly<'{'>,
1155
- exactly<')'>,
1156
- exactly<','>,
1157
- exactly<':'>,
1158
- end_of_file,
1159
- exactly<ellipsis>,
1160
- default_flag,
1161
- global_flag
1162
- > >(position)) && peek_css< optional_css_whitespace >() != end
1256
+ while (
1257
+ !(peek_css< space_list_terminator >(position)) &&
1258
+ peek_css< optional_css_whitespace >() != end
1163
1259
  ) {
1164
1260
  // the space is parsed implicitly?
1165
1261
  space_list->append(parse_disjunction());
1166
1262
  }
1167
1263
  // return the list
1168
- return &space_list;
1264
+ return space_list;
1169
1265
  }
1170
1266
  // EO parse_space_list
1171
1267
 
1172
1268
  // parse logical OR operation
1173
1269
  Expression_Obj Parser::parse_disjunction()
1174
1270
  {
1271
+ NESTING_GUARD(nestings);
1175
1272
  advanceToNextToken();
1176
1273
  ParserState state(pstate);
1177
1274
  // parse the left hand side conjunction
@@ -1193,6 +1290,7 @@ namespace Sass {
1193
1290
  // parse logical AND operation
1194
1291
  Expression_Obj Parser::parse_conjunction()
1195
1292
  {
1293
+ NESTING_GUARD(nestings);
1196
1294
  advanceToNextToken();
1197
1295
  ParserState state(pstate);
1198
1296
  // parse the left hand side relation
@@ -1200,7 +1298,7 @@ namespace Sass {
1200
1298
  // parse multiple right hand sides
1201
1299
  std::vector<Expression_Obj> operands;
1202
1300
  while (lex_css< kwd_and >()) {
1203
- operands.push_back(&parse_relation());
1301
+ operands.push_back(parse_relation());
1204
1302
  }
1205
1303
  // if it's a singleton, return it directly
1206
1304
  if (operands.size() == 0) return rel;
@@ -1215,6 +1313,7 @@ namespace Sass {
1215
1313
  // parse comparison operations
1216
1314
  Expression_Obj Parser::parse_relation()
1217
1315
  {
1316
+ NESTING_GUARD(nestings);
1218
1317
  advanceToNextToken();
1219
1318
  ParserState state(pstate);
1220
1319
  // parse the left hand side expression
@@ -1246,8 +1345,7 @@ namespace Sass {
1246
1345
  // is directly adjacent to expression?
1247
1346
  bool right_ws = peek < css_comments >() != NULL;
1248
1347
  operators.push_back({ op, left_ws, right_ws });
1249
- operands.push_back(&parse_expression());
1250
- left_ws = peek < css_comments >() != NULL;
1348
+ operands.push_back(parse_expression());
1251
1349
  }
1252
1350
  // we are called recursively for list, so we first
1253
1351
  // fold inner binary expression which has delayed
@@ -1268,6 +1366,7 @@ namespace Sass {
1268
1366
  // parse addition and subtraction operations
1269
1367
  Expression_Obj Parser::parse_expression()
1270
1368
  {
1369
+ NESTING_GUARD(nestings);
1271
1370
  advanceToNextToken();
1272
1371
  ParserState state(pstate);
1273
1372
  // parses multiple add and subtract operations
@@ -1297,7 +1396,7 @@ namespace Sass {
1297
1396
 
1298
1397
  bool right_ws = peek < css_comments >() != NULL;
1299
1398
  operators.push_back({ lexed.to_string() == "+" ? Sass_OP::ADD : Sass_OP::SUB, left_ws, right_ws });
1300
- operands.push_back(&parse_operators());
1399
+ operands.push_back(parse_operators());
1301
1400
  left_ws = peek < css_comments >() != NULL;
1302
1401
  }
1303
1402
 
@@ -1311,6 +1410,7 @@ namespace Sass {
1311
1410
  // parse addition and subtraction operations
1312
1411
  Expression_Obj Parser::parse_operators()
1313
1412
  {
1413
+ NESTING_GUARD(nestings);
1314
1414
  advanceToNextToken();
1315
1415
  ParserState state(pstate);
1316
1416
  Expression_Obj factor = parse_factor();
@@ -1325,7 +1425,7 @@ namespace Sass {
1325
1425
  case '*': operators.push_back({ Sass_OP::MUL, left_ws != 0, right_ws != 0 }); break;
1326
1426
  case '/': operators.push_back({ Sass_OP::DIV, left_ws != 0, right_ws != 0 }); break;
1327
1427
  case '%': operators.push_back({ Sass_OP::MOD, left_ws != 0, right_ws != 0 }); break;
1328
- default: throw std::runtime_error("unknown static op parsed"); break;
1428
+ default: throw std::runtime_error("unknown static op parsed");
1329
1429
  }
1330
1430
  operands.push_back(parse_factor());
1331
1431
  left_ws = peek < css_comments >();
@@ -1343,65 +1443,79 @@ namespace Sass {
1343
1443
  // called from parse_value_schema
1344
1444
  Expression_Obj Parser::parse_factor()
1345
1445
  {
1446
+ NESTING_GUARD(nestings);
1346
1447
  lex < css_comments >(false);
1347
1448
  if (lex_css< exactly<'('> >()) {
1348
1449
  // parse_map may return a list
1349
1450
  Expression_Obj value = parse_map();
1350
1451
  // lex the expected closing parenthesis
1351
- if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
1452
+ if (!lex_css< exactly<')'> >()) error("unclosed parenthesis");
1352
1453
  // expression can be evaluated
1353
- return &value;
1454
+ return value;
1455
+ }
1456
+ else if (lex_css< exactly<'['> >()) {
1457
+ // explicit bracketed
1458
+ Expression_Obj value = parse_bracket_list();
1459
+ // lex the expected closing square bracket
1460
+ if (!lex_css< exactly<']'> >()) error("unclosed squared bracket");
1461
+ return value;
1354
1462
  }
1355
1463
  // string may be interpolated
1356
1464
  // if (lex< quoted_string >()) {
1357
1465
  // return &parse_string();
1358
1466
  // }
1359
1467
  else if (peek< ie_property >()) {
1360
- return &parse_ie_property();
1468
+ return parse_ie_property();
1361
1469
  }
1362
1470
  else if (peek< ie_keyword_arg >()) {
1363
- return &parse_ie_keyword_arg();
1471
+ return parse_ie_keyword_arg();
1364
1472
  }
1365
1473
  else if (peek< sequence < calc_fn_call, exactly <'('> > >()) {
1366
- return &parse_calc_function();
1474
+ return parse_calc_function();
1367
1475
  }
1368
1476
  else if (lex < functional_schema >()) {
1369
- return &parse_function_call_schema();
1477
+ return parse_function_call_schema();
1370
1478
  }
1371
1479
  else if (lex< identifier_schema >()) {
1372
1480
  String_Obj string = parse_identifier_schema();
1373
- if (String_Schema_Ptr schema = SASS_MEMORY_CAST(String_Schema, string)) {
1481
+ if (String_Schema_Ptr schema = Cast<String_Schema>(string)) {
1374
1482
  if (lex < exactly < '(' > >()) {
1375
- schema->append(&parse_list());
1483
+ schema->append(parse_list());
1376
1484
  lex < exactly < ')' > >();
1377
1485
  }
1378
1486
  }
1379
- return &string;
1487
+ return string;
1380
1488
  }
1381
1489
  else if (peek< sequence< uri_prefix, W, real_uri_value > >()) {
1382
- return &parse_url_function_string();
1490
+ return parse_url_function_string();
1383
1491
  }
1384
1492
  else if (peek< re_functional >()) {
1385
- return &parse_function_call();
1493
+ return parse_function_call();
1386
1494
  }
1387
1495
  else if (lex< exactly<'+'> >()) {
1388
- Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS, &parse_factor());
1496
+ Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS, parse_factor());
1389
1497
  if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
1390
1498
  return ex;
1391
1499
  }
1392
1500
  else if (lex< exactly<'-'> >()) {
1393
- Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, &parse_factor());
1501
+ Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_factor());
1502
+ if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
1503
+ return ex;
1504
+ }
1505
+ else if (lex< exactly<'/'> >()) {
1506
+ Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::SLASH, parse_factor());
1394
1507
  if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
1395
1508
  return ex;
1396
1509
  }
1397
1510
  else if (lex< sequence< kwd_not > >()) {
1398
- Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT, &parse_factor());
1511
+ Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT, parse_factor());
1399
1512
  if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
1400
1513
  return ex;
1401
1514
  }
1515
+ // this whole branch is never hit via spec tests
1402
1516
  else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
1403
- if (parse_number_prefix()) return &parse_value(); // prefix is positive
1404
- Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, &parse_value());
1517
+ if (parse_number_prefix()) return parse_value(); // prefix is positive
1518
+ Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_value());
1405
1519
  if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
1406
1520
  return ex;
1407
1521
  }
@@ -1410,12 +1524,132 @@ namespace Sass {
1410
1524
  }
1411
1525
  }
1412
1526
 
1527
+ bool number_has_zero(const std::string& parsed)
1528
+ {
1529
+ size_t L = parsed.length();
1530
+ return !( (L > 0 && parsed.substr(0, 1) == ".") ||
1531
+ (L > 1 && parsed.substr(0, 2) == "0.") ||
1532
+ (L > 1 && parsed.substr(0, 2) == "-.") ||
1533
+ (L > 2 && parsed.substr(0, 3) == "-0.") );
1534
+ }
1535
+
1536
+ Number_Ptr Parser::lexed_number(const ParserState& pstate, const std::string& parsed)
1537
+ {
1538
+ Number_Ptr nr = SASS_MEMORY_NEW(Number,
1539
+ pstate,
1540
+ sass_strtod(parsed.c_str()),
1541
+ "",
1542
+ number_has_zero(parsed));
1543
+ nr->is_interpolant(false);
1544
+ nr->is_delayed(true);
1545
+ return nr;
1546
+ }
1547
+
1548
+ Number_Ptr Parser::lexed_percentage(const ParserState& pstate, const std::string& parsed)
1549
+ {
1550
+ Number_Ptr nr = SASS_MEMORY_NEW(Number,
1551
+ pstate,
1552
+ sass_strtod(parsed.c_str()),
1553
+ "%",
1554
+ true);
1555
+ nr->is_interpolant(false);
1556
+ nr->is_delayed(true);
1557
+ return nr;
1558
+ }
1559
+
1560
+ Number_Ptr Parser::lexed_dimension(const ParserState& pstate, const std::string& parsed)
1561
+ {
1562
+ size_t L = parsed.length();
1563
+ size_t num_pos = parsed.find_first_not_of(" \n\r\t");
1564
+ if (num_pos == std::string::npos) num_pos = L;
1565
+ size_t unit_pos = parsed.find_first_not_of("-+0123456789.", num_pos);
1566
+ if (parsed[unit_pos] == 'e' && is_number(parsed[unit_pos+1]) ) {
1567
+ unit_pos = parsed.find_first_not_of("-+0123456789.", ++ unit_pos);
1568
+ }
1569
+ if (unit_pos == std::string::npos) unit_pos = L;
1570
+ const std::string& num = parsed.substr(num_pos, unit_pos - num_pos);
1571
+ Number_Ptr nr = SASS_MEMORY_NEW(Number,
1572
+ pstate,
1573
+ sass_strtod(num.c_str()),
1574
+ Token(number(parsed.c_str())),
1575
+ number_has_zero(parsed));
1576
+ nr->is_interpolant(false);
1577
+ nr->is_delayed(true);
1578
+ return nr;
1579
+ }
1580
+
1581
+ Value_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed)
1582
+ {
1583
+ Color_Ptr color = NULL;
1584
+ if (parsed[0] != '#') {
1585
+ return SASS_MEMORY_NEW(String_Quoted, pstate, parsed);
1586
+ }
1587
+ // chop off the '#'
1588
+ std::string hext(parsed.substr(1));
1589
+ if (parsed.length() == 4) {
1590
+ std::string r(2, parsed[1]);
1591
+ std::string g(2, parsed[2]);
1592
+ std::string b(2, parsed[3]);
1593
+ color = SASS_MEMORY_NEW(Color,
1594
+ pstate,
1595
+ static_cast<double>(strtol(r.c_str(), NULL, 16)),
1596
+ static_cast<double>(strtol(g.c_str(), NULL, 16)),
1597
+ static_cast<double>(strtol(b.c_str(), NULL, 16)),
1598
+ 1, // alpha channel
1599
+ parsed);
1600
+ }
1601
+ else if (parsed.length() == 7) {
1602
+ std::string r(parsed.substr(1,2));
1603
+ std::string g(parsed.substr(3,2));
1604
+ std::string b(parsed.substr(5,2));
1605
+ color = SASS_MEMORY_NEW(Color,
1606
+ pstate,
1607
+ static_cast<double>(strtol(r.c_str(), NULL, 16)),
1608
+ static_cast<double>(strtol(g.c_str(), NULL, 16)),
1609
+ static_cast<double>(strtol(b.c_str(), NULL, 16)),
1610
+ 1, // alpha channel
1611
+ parsed);
1612
+ }
1613
+ else if (parsed.length() == 9) {
1614
+ std::string r(parsed.substr(1,2));
1615
+ std::string g(parsed.substr(3,2));
1616
+ std::string b(parsed.substr(5,2));
1617
+ std::string a(parsed.substr(7,2));
1618
+ color = SASS_MEMORY_NEW(Color,
1619
+ pstate,
1620
+ static_cast<double>(strtol(r.c_str(), NULL, 16)),
1621
+ static_cast<double>(strtol(g.c_str(), NULL, 16)),
1622
+ static_cast<double>(strtol(b.c_str(), NULL, 16)),
1623
+ static_cast<double>(strtol(a.c_str(), NULL, 16)) / 255,
1624
+ parsed);
1625
+ }
1626
+ color->is_interpolant(false);
1627
+ color->is_delayed(false);
1628
+ return color;
1629
+ }
1630
+
1631
+ Value_Ptr Parser::color_or_string(const std::string& lexed) const
1632
+ {
1633
+ if (auto color = name_to_color(lexed)) {
1634
+ auto c = SASS_MEMORY_NEW(Color, color);
1635
+ c->is_delayed(true);
1636
+ c->pstate(pstate);
1637
+ c->disp(lexed);
1638
+ return c;
1639
+ } else {
1640
+ return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
1641
+ }
1642
+ }
1643
+
1413
1644
  // parse one value for a list
1414
1645
  Expression_Obj Parser::parse_value()
1415
1646
  {
1416
1647
  lex< css_comments >(false);
1417
1648
  if (lex< ampersand >())
1418
1649
  {
1650
+ if (match< ampersand >()) {
1651
+ warning("In Sass, \"&&\" means two copies of the parent selector. You probably want to use \"and\" instead.", pstate);
1652
+ }
1419
1653
  return SASS_MEMORY_NEW(Parent_Selector, pstate); }
1420
1654
 
1421
1655
  if (lex< kwd_important >())
@@ -1423,21 +1657,21 @@ namespace Sass {
1423
1657
 
1424
1658
  // parse `10%4px` into separated items and not a schema
1425
1659
  if (lex< sequence < percentage, lookahead < number > > >())
1426
- { return SASS_MEMORY_NEW(Textual, pstate, Textual::PERCENTAGE, lexed); }
1660
+ { return lexed_percentage(lexed); }
1427
1661
 
1428
1662
  if (lex< sequence < number, lookahead< sequence < op, number > > > >())
1429
- { return SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, lexed); }
1663
+ { return lexed_number(lexed); }
1430
1664
 
1431
1665
  // string may be interpolated
1432
1666
  if (lex< sequence < quoted_string, lookahead < exactly <'-'> > > >())
1433
- { return &parse_string(); }
1667
+ { return parse_string(); }
1434
1668
 
1435
1669
  if (const char* stop = peek< value_schema >())
1436
- { return &parse_value_schema(stop); }
1670
+ { return parse_value_schema(stop); }
1437
1671
 
1438
1672
  // string may be interpolated
1439
1673
  if (lex< quoted_string >())
1440
- { return &parse_string(); }
1674
+ { return parse_string(); }
1441
1675
 
1442
1676
  if (lex< kwd_true >())
1443
1677
  { return SASS_MEMORY_NEW(Boolean, pstate, true); }
@@ -1449,15 +1683,28 @@ namespace Sass {
1449
1683
  { return SASS_MEMORY_NEW(Null, pstate); }
1450
1684
 
1451
1685
  if (lex< identifier >()) {
1452
- return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
1686
+ return color_or_string(lexed);
1453
1687
  }
1454
1688
 
1455
1689
  if (lex< percentage >())
1456
- { return SASS_MEMORY_NEW(Textual, pstate, Textual::PERCENTAGE, lexed); }
1690
+ { return lexed_percentage(lexed); }
1457
1691
 
1458
1692
  // match hex number first because 0x000 looks like a number followed by an identifier
1459
1693
  if (lex< sequence < alternatives< hex, hex0 >, negate < exactly<'-'> > > >())
1460
- { return SASS_MEMORY_NEW(Textual, pstate, Textual::HEX, lexed); }
1694
+ { return lexed_hex_color(lexed); }
1695
+
1696
+ if (lex< hexa >())
1697
+ {
1698
+ std::string s = lexed.to_string();
1699
+
1700
+ deprecated(
1701
+ "The value \""+s+"\" is currently parsed as a string, but it will be parsed as a color in",
1702
+ "future versions of Sass. Use \"unquote('"+s+"')\" to continue parsing it as a string.",
1703
+ true, pstate
1704
+ );
1705
+
1706
+ return SASS_MEMORY_NEW(String_Quoted, pstate, lexed);
1707
+ }
1461
1708
 
1462
1709
  if (lex< sequence < exactly <'#'>, identifier > >())
1463
1710
  { return SASS_MEMORY_NEW(String_Quoted, pstate, lexed); }
@@ -1465,13 +1712,13 @@ namespace Sass {
1465
1712
  // also handle the 10em- foo special case
1466
1713
  // alternatives < exactly < '.' >, .. > -- `1.5em-.75em` is split into a list, not a binary expression
1467
1714
  if (lex< sequence< dimension, optional< sequence< exactly<'-'>, lookahead< alternatives < space > > > > > >())
1468
- { return SASS_MEMORY_NEW(Textual, pstate, Textual::DIMENSION, lexed); }
1715
+ { return lexed_dimension(lexed); }
1469
1716
 
1470
1717
  if (lex< sequence< static_component, one_plus< strict_identifier > > >())
1471
1718
  { return SASS_MEMORY_NEW(String_Constant, pstate, lexed); }
1472
1719
 
1473
1720
  if (lex< number >())
1474
- { return SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, lexed); }
1721
+ { return lexed_number(lexed); }
1475
1722
 
1476
1723
  if (lex< variable >())
1477
1724
  { return SASS_MEMORY_NEW(Variable, pstate, Util::normalize_underscores(lexed)); }
@@ -1488,7 +1735,7 @@ namespace Sass {
1488
1735
 
1489
1736
  // this parses interpolation inside other strings
1490
1737
  // means the result should later be quoted again
1491
- String_Obj Parser::parse_interpolated_chunk(Token chunk, bool constant)
1738
+ String_Obj Parser::parse_interpolated_chunk(Token chunk, bool constant, bool css)
1492
1739
  {
1493
1740
  const char* i = chunk.begin;
1494
1741
  // see if there any interpolants
@@ -1496,12 +1743,12 @@ namespace Sass {
1496
1743
  find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
1497
1744
 
1498
1745
  if (!p) {
1499
- String_Quoted_Ptr str_quoted = SASS_MEMORY_NEW(String_Quoted, pstate, std::string(i, chunk.end));
1746
+ String_Quoted_Ptr str_quoted = SASS_MEMORY_NEW(String_Quoted, pstate, std::string(i, chunk.end), 0, false, false, true, css);
1500
1747
  if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
1501
1748
  return str_quoted;
1502
1749
  }
1503
1750
 
1504
- String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
1751
+ String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate, 0, css);
1505
1752
  schema->is_interpolant(true);
1506
1753
  while (i < chunk.end) {
1507
1754
  p = constant ? find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end) :
@@ -1509,7 +1756,7 @@ namespace Sass {
1509
1756
  if (p) {
1510
1757
  if (i < p) {
1511
1758
  // accumulate the preceding segment if it's nonempty
1512
- schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, p)));
1759
+ schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, p), css));
1513
1760
  }
1514
1761
  // we need to skip anything inside strings
1515
1762
  // create a new target in parser/prelexer
@@ -1519,39 +1766,106 @@ namespace Sass {
1519
1766
  const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
1520
1767
  if (j) { --j;
1521
1768
  // parse the interpolant and accumulate it
1522
- Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
1769
+ Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list();
1523
1770
  interp_node->is_interpolant(true);
1524
- schema->append(&interp_node);
1771
+ schema->append(interp_node);
1525
1772
  i = j;
1526
1773
  }
1527
1774
  else {
1528
1775
  // throw an error if the interpolant is unterminated
1529
- error("unterminated interpolant inside string constant " + chunk.to_string(), pstate);
1776
+ error("unterminated interpolant inside string constant " + chunk.to_string());
1530
1777
  }
1531
1778
  }
1532
1779
  else { // no interpolants left; add the last segment if nonempty
1533
1780
  // check if we need quotes here (was not sure after merge)
1534
- if (i < chunk.end) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, chunk.end)));
1781
+ if (i < chunk.end) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, chunk.end), css));
1535
1782
  break;
1536
1783
  }
1537
1784
  ++ i;
1538
1785
  }
1539
1786
 
1540
- return schema;
1787
+ return schema.detach();
1541
1788
  }
1542
1789
 
1543
- String_Constant_Obj Parser::parse_static_value()
1790
+ String_Schema_Obj Parser::parse_css_variable_value(bool top_level)
1791
+ {
1792
+ String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
1793
+ String_Schema_Obj tok;
1794
+ if (!(tok = parse_css_variable_value_token(top_level))) {
1795
+ return NULL;
1796
+ }
1797
+
1798
+ schema->concat(tok);
1799
+ while ((tok = parse_css_variable_value_token(top_level))) {
1800
+ schema->concat(tok);
1801
+ }
1802
+
1803
+ return schema.detach();
1804
+ }
1805
+
1806
+ String_Schema_Obj Parser::parse_css_variable_value_token(bool top_level)
1807
+ {
1808
+ String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
1809
+ if (
1810
+ (top_level && lex< css_variable_top_level_value >(false)) ||
1811
+ (!top_level && lex< css_variable_value >(false))
1812
+ ) {
1813
+ Token str(lexed);
1814
+ schema->append(SASS_MEMORY_NEW(String_Constant, pstate, str));
1815
+ }
1816
+ else if (Expression_Obj tok = lex_interpolation()) {
1817
+ if (String_Schema_Ptr s = Cast<String_Schema>(tok)) {
1818
+ schema->concat(s);
1819
+ } else {
1820
+ schema->append(tok);
1821
+ }
1822
+ }
1823
+ else if (lex< quoted_string >()) {
1824
+ Expression_Obj tok = parse_string();
1825
+ if (String_Schema_Ptr s = Cast<String_Schema>(tok)) {
1826
+ schema->concat(s);
1827
+ } else {
1828
+ schema->append(tok);
1829
+ }
1830
+ }
1831
+ else {
1832
+ if (peek< alternatives< exactly<'('>, exactly<'['>, exactly<'{'> > >()) {
1833
+ if (lex< exactly<'('> >()) {
1834
+ schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("(")));
1835
+ if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
1836
+ if (!lex< exactly<')'> >()) css_error("Invalid CSS", " after ", ": expected \")\", was ");
1837
+ schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(")")));
1838
+ }
1839
+ else if (lex< exactly<'['> >()) {
1840
+ schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("[")));
1841
+ if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
1842
+ if (!lex< exactly<']'> >()) css_error("Invalid CSS", " after ", ": expected \"]\", was ");
1843
+ schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("]")));
1844
+ }
1845
+ else if (lex< exactly<'{'> >()) {
1846
+ schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("{")));
1847
+ if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
1848
+ if (!lex< exactly<'}'> >()) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
1849
+ schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("}")));
1850
+ }
1851
+ }
1852
+ }
1853
+
1854
+ return schema->length() > 0 ? schema.detach() : NULL;
1855
+ }
1856
+
1857
+ Value_Obj Parser::parse_static_value()
1544
1858
  {
1545
1859
  lex< static_value >();
1546
1860
  Token str(lexed);
1547
1861
  // static values always have trailing white-
1548
1862
  // space and end delimiter (\s*[;]$) included
1549
- -- pstate.offset.column;
1863
+ --pstate.offset.column;
1864
+ --after_token.column;
1550
1865
  --str.end;
1551
1866
  --position;
1552
1867
 
1553
- String_Constant_Ptr str_node = SASS_MEMORY_NEW(String_Constant, pstate, str.time_wspace());
1554
- return str_node;
1868
+ return color_or_string(str.time_wspace());;
1555
1869
  }
1556
1870
 
1557
1871
  String_Obj Parser::parse_string()
@@ -1583,14 +1897,14 @@ namespace Sass {
1583
1897
  const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
1584
1898
  if (j) {
1585
1899
  // parse the interpolant and accumulate it
1586
- Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
1900
+ Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list();
1587
1901
  interp_node->is_interpolant(true);
1588
- schema->append(&interp_node);
1902
+ schema->append(interp_node);
1589
1903
  i = j;
1590
1904
  }
1591
1905
  else {
1592
1906
  // throw an error if the interpolant is unterminated
1593
- error("unterminated interpolant inside IE function " + str.to_string(), pstate);
1907
+ error("unterminated interpolant inside IE function " + str.to_string());
1594
1908
  }
1595
1909
  }
1596
1910
  else { // no interpolants left; add the last segment if nonempty
@@ -1614,9 +1928,13 @@ namespace Sass {
1614
1928
  }
1615
1929
  lex< exactly<'='> >();
1616
1930
  kwd_arg->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
1617
- if (peek< variable >()) kwd_arg->append(&parse_list());
1618
- else if (lex< number >()) kwd_arg->append(SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, Util::normalize_decimals(lexed)));
1619
- else if (peek < ie_keyword_arg_value >()) { kwd_arg->append(&parse_list()); }
1931
+ if (peek< variable >()) kwd_arg->append(parse_list());
1932
+ else if (lex< number >()) {
1933
+ std::string parsed(lexed);
1934
+ Util::normalize_decimals(parsed);
1935
+ kwd_arg->append(lexed_number(parsed));
1936
+ }
1937
+ else if (peek < ie_keyword_arg_value >()) { kwd_arg->append(parse_list()); }
1620
1938
  return kwd_arg;
1621
1939
  }
1622
1940
 
@@ -1629,7 +1947,7 @@ namespace Sass {
1629
1947
  css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
1630
1948
  }
1631
1949
 
1632
- const char* e = 0;
1950
+ const char* e;
1633
1951
  const char* ee = end;
1634
1952
  end = stop;
1635
1953
  size_t num_items = 0;
@@ -1644,7 +1962,7 @@ namespace Sass {
1644
1962
  // schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
1645
1963
  }
1646
1964
  if ((e = peek< re_functional >()) && e < stop) {
1647
- schema->append(&parse_function_call());
1965
+ schema->append(parse_function_call());
1648
1966
  }
1649
1967
  // lex an interpolant /#{...}/
1650
1968
  else if (lex< exactly < hash_lbrace > >()) {
@@ -1652,11 +1970,11 @@ namespace Sass {
1652
1970
  if (peek< exactly< rbrace > >()) {
1653
1971
  css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
1654
1972
  }
1655
- Expression_Obj ex = 0;
1973
+ Expression_Obj ex;
1656
1974
  if (lex< re_static_expression >()) {
1657
1975
  ex = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
1658
1976
  } else {
1659
- ex = parse_list();
1977
+ ex = parse_list(true);
1660
1978
  }
1661
1979
  ex->is_interpolant(true);
1662
1980
  schema->append(ex);
@@ -1674,13 +1992,13 @@ namespace Sass {
1674
1992
  // need_space = true;
1675
1993
  // if (schema->length()) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
1676
1994
  // else need_space = true;
1677
- schema->append(&parse_string());
1995
+ schema->append(parse_string());
1678
1996
  if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
1679
1997
  // need_space = true;
1680
1998
  }
1681
1999
  if (peek < exactly < '-' > >()) break;
1682
2000
  }
1683
- else if (lex< sequence < identifier > >()) {
2001
+ else if (lex< identifier >()) {
1684
2002
  schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
1685
2003
  if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
1686
2004
  // need_space = true;
@@ -1693,26 +2011,26 @@ namespace Sass {
1693
2011
  }
1694
2012
  // lex percentage value
1695
2013
  else if (lex< percentage >()) {
1696
- schema->append(SASS_MEMORY_NEW(Textual, pstate, Textual::PERCENTAGE, lexed));
2014
+ schema->append(lexed_percentage(lexed));
1697
2015
  }
1698
2016
  // lex dimension value
1699
2017
  else if (lex< dimension >()) {
1700
- schema->append(SASS_MEMORY_NEW(Textual, pstate, Textual::DIMENSION, lexed));
2018
+ schema->append(lexed_dimension(lexed));
1701
2019
  }
1702
2020
  // lex number value
1703
2021
  else if (lex< number >()) {
1704
- schema->append( SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, lexed));
2022
+ schema->append(lexed_number(lexed));
1705
2023
  }
1706
2024
  // lex hex color value
1707
2025
  else if (lex< sequence < hex, negate < exactly < '-' > > > >()) {
1708
- schema->append(SASS_MEMORY_NEW(Textual, pstate, Textual::HEX, lexed));
2026
+ schema->append(lexed_hex_color(lexed));
1709
2027
  }
1710
2028
  else if (lex< sequence < exactly <'#'>, identifier > >()) {
1711
2029
  schema->append(SASS_MEMORY_NEW(String_Quoted, pstate, lexed));
1712
2030
  }
1713
2031
  // lex a value in parentheses
1714
2032
  else if (peek< parenthese_scope >()) {
1715
- schema->append(&parse_factor());
2033
+ schema->append(parse_factor());
1716
2034
  }
1717
2035
  else {
1718
2036
  break;
@@ -1746,7 +2064,7 @@ namespace Sass {
1746
2064
  if (i < p) {
1747
2065
  // accumulate the preceding segment if it's nonempty
1748
2066
  const char* o = position; position = i;
1749
- schema->append(&parse_value_schema(p));
2067
+ schema->append(parse_value_schema(p));
1750
2068
  position = o;
1751
2069
  }
1752
2070
  // we need to skip anything inside strings
@@ -1757,7 +2075,7 @@ namespace Sass {
1757
2075
  const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
1758
2076
  if (j) {
1759
2077
  // parse the interpolant and accumulate it
1760
- Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list(DELAYED);
2078
+ Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list(DELAYED);
1761
2079
  interp_node->is_interpolant(true);
1762
2080
  schema->append(interp_node);
1763
2081
  // schema->has_interpolants(true);
@@ -1765,13 +2083,13 @@ namespace Sass {
1765
2083
  }
1766
2084
  else {
1767
2085
  // throw an error if the interpolant is unterminated
1768
- error("unterminated interpolant inside interpolated identifier " + id.to_string(), pstate);
2086
+ error("unterminated interpolant inside interpolated identifier " + id.to_string());
1769
2087
  }
1770
2088
  }
1771
2089
  else { // no interpolants left; add the last segment if nonempty
1772
2090
  if (i < end) {
1773
2091
  const char* o = position; position = i;
1774
- schema->append(&parse_value_schema(id.end));
2092
+ schema->append(parse_value_schema(id.end));
1775
2093
  position = o;
1776
2094
  }
1777
2095
  break;
@@ -1796,9 +2114,9 @@ namespace Sass {
1796
2114
  exactly < ')' >
1797
2115
  > >();
1798
2116
 
1799
- Argument_Obj arg = SASS_MEMORY_NEW(Argument, arg_pos, &parse_interpolated_chunk(Token(arg_beg, arg_end)));
2117
+ Argument_Obj arg = SASS_MEMORY_NEW(Argument, arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end)));
1800
2118
  Arguments_Obj args = SASS_MEMORY_NEW(Arguments, arg_pos);
1801
- args->append(&arg);
2119
+ args->append(arg);
1802
2120
  return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
1803
2121
  }
1804
2122
 
@@ -1818,16 +2136,16 @@ namespace Sass {
1818
2136
  }
1819
2137
 
1820
2138
  std::string uri("");
1821
- if (&url_string) {
2139
+ if (url_string) {
1822
2140
  uri = url_string->to_string({ NESTED, 5 });
1823
2141
  }
1824
2142
 
1825
- if (String_Schema_Ptr schema = dynamic_cast<String_Schema_Ptr>(&url_string)) {
2143
+ if (String_Schema_Ptr schema = Cast<String_Schema>(url_string)) {
1826
2144
  String_Schema_Obj res = SASS_MEMORY_NEW(String_Schema, pstate);
1827
2145
  res->append(SASS_MEMORY_NEW(String_Constant, pstate, prefix));
1828
2146
  res->append(schema);
1829
2147
  res->append(SASS_MEMORY_NEW(String_Constant, pstate, suffix));
1830
- return &res;
2148
+ return res;
1831
2149
  } else {
1832
2150
  std::string res = prefix + uri + suffix;
1833
2151
  return SASS_MEMORY_NEW(String_Constant, pstate, res);
@@ -1850,7 +2168,7 @@ namespace Sass {
1850
2168
  pp = sequence< interpolant, real_uri_value >(pp);
1851
2169
  }
1852
2170
  position = pp;
1853
- return &parse_interpolated_chunk(Token(p, position));
2171
+ return parse_interpolated_chunk(Token(p, position));
1854
2172
  }
1855
2173
  else if (uri != "") {
1856
2174
  std::string res = Util::rtrim(uri);
@@ -1865,6 +2183,9 @@ namespace Sass {
1865
2183
  lex< identifier >();
1866
2184
  std::string name(lexed);
1867
2185
 
2186
+ if (Util::normalize_underscores(name) == "content-exists" && stack.back() != Scope::Mixin)
2187
+ { error("Cannot call content-exists() except within a mixin."); }
2188
+
1868
2189
  ParserState call_pos = pstate;
1869
2190
  Arguments_Obj args = parse_arguments();
1870
2191
  return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
@@ -1897,10 +2218,10 @@ namespace Sass {
1897
2218
  // we want all other comments to be parsed
1898
2219
  if (lex_css< elseif_directive >()) {
1899
2220
  alternative = SASS_MEMORY_NEW(Block, pstate);
1900
- alternative->append(&parse_if_directive(true));
2221
+ alternative->append(parse_if_directive(true));
1901
2222
  }
1902
2223
  else if (lex_css< kwd_else_directive >()) {
1903
- alternative = &parse_block(root);
2224
+ alternative = parse_block(root);
1904
2225
  }
1905
2226
  stack.pop_back();
1906
2227
  return SASS_MEMORY_NEW(If, if_source_position, predicate, block, alternative);
@@ -1913,12 +2234,12 @@ namespace Sass {
1913
2234
  bool root = block_stack.back()->is_root();
1914
2235
  lex_variable();
1915
2236
  std::string var(Util::normalize_underscores(lexed));
1916
- if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive", pstate);
2237
+ if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive");
1917
2238
  Expression_Obj lower_bound = parse_expression();
1918
2239
  bool inclusive = false;
1919
2240
  if (lex< kwd_through >()) inclusive = true;
1920
2241
  else if (lex< kwd_to >()) inclusive = false;
1921
- else error("expected 'through' or 'to' keyword in @for directive", pstate);
2242
+ else error("expected 'through' or 'to' keyword in @for directive");
1922
2243
  Expression_Obj upper_bound = parse_expression();
1923
2244
  Block_Obj body = parse_block(root);
1924
2245
  stack.pop_back();
@@ -1960,10 +2281,10 @@ namespace Sass {
1960
2281
  lex_variable();
1961
2282
  vars.push_back(Util::normalize_underscores(lexed));
1962
2283
  while (lex< exactly<','> >()) {
1963
- if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
2284
+ if (!lex< variable >()) error("@each directive requires an iteration variable");
1964
2285
  vars.push_back(Util::normalize_underscores(lexed));
1965
2286
  }
1966
- if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive", pstate);
2287
+ if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive");
1967
2288
  Expression_Obj list = parse_list();
1968
2289
  Block_Obj body = parse_block(root);
1969
2290
  stack.pop_back();
@@ -1979,6 +2300,10 @@ namespace Sass {
1979
2300
  While_Obj call = SASS_MEMORY_NEW(While, pstate, 0, 0);
1980
2301
  // parse mandatory predicate
1981
2302
  Expression_Obj predicate = parse_list();
2303
+ List_Obj l = Cast<List>(predicate);
2304
+ if (!predicate || (l && !l->length())) {
2305
+ css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ", false);
2306
+ }
1982
2307
  call->predicate(predicate);
1983
2308
  // parse mandatory block
1984
2309
  call->block(parse_block(root));
@@ -1997,9 +2322,9 @@ namespace Sass {
1997
2322
  media_block->media_queries(parse_media_queries());
1998
2323
 
1999
2324
  Media_Block_Obj prev_media_block = last_media_block;
2000
- last_media_block = &media_block;
2325
+ last_media_block = media_block;
2001
2326
  media_block->block(parse_css_block());
2002
- last_media_block = &prev_media_block;
2327
+ last_media_block = prev_media_block;
2003
2328
  stack.pop_back();
2004
2329
  return media_block.detach();
2005
2330
  }
@@ -2008,8 +2333,8 @@ namespace Sass {
2008
2333
  {
2009
2334
  advanceToNextToken();
2010
2335
  List_Obj queries = SASS_MEMORY_NEW(List, pstate, 0, SASS_COMMA);
2011
- if (!peek_css < exactly <'{'> >()) queries->append(&parse_media_query());
2012
- while (lex_css < exactly <','> >()) queries->append(&parse_media_query());
2336
+ if (!peek_css < exactly <'{'> >()) queries->append(parse_media_query());
2337
+ while (lex_css < exactly <','> >()) queries->append(parse_media_query());
2013
2338
  queries->update_pstate(pstate);
2014
2339
  return queries.detach();
2015
2340
  }
@@ -2022,19 +2347,19 @@ namespace Sass {
2022
2347
  if (lex < kwd_not >()) { media_query->is_negated(true); lex < css_comments >(false); }
2023
2348
  else if (lex < kwd_only >()) { media_query->is_restricted(true); lex < css_comments >(false); }
2024
2349
 
2025
- if (lex < identifier_schema >()) media_query->media_type(&parse_identifier_schema());
2026
- else if (lex < identifier >()) media_query->media_type(&parse_interpolated_chunk(lexed));
2027
- else media_query->append(&parse_media_expression());
2350
+ if (lex < identifier_schema >()) media_query->media_type(parse_identifier_schema());
2351
+ else if (lex < identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
2352
+ else media_query->append(parse_media_expression());
2028
2353
 
2029
- while (lex_css < kwd_and >()) media_query->append(&parse_media_expression());
2354
+ while (lex_css < kwd_and >()) media_query->append(parse_media_expression());
2030
2355
  if (lex < identifier_schema >()) {
2031
2356
  String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
2032
- schema->append(&media_query->media_type());
2357
+ schema->append(media_query->media_type());
2033
2358
  schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
2034
- schema->append(&parse_identifier_schema());
2359
+ schema->append(parse_identifier_schema());
2035
2360
  media_query->media_type(schema);
2036
2361
  }
2037
- while (lex_css < kwd_and >()) media_query->append(&parse_media_expression());
2362
+ while (lex_css < kwd_and >()) media_query->append(parse_media_expression());
2038
2363
 
2039
2364
  media_query->update_pstate(pstate);
2040
2365
 
@@ -2045,22 +2370,22 @@ namespace Sass {
2045
2370
  {
2046
2371
  if (lex < identifier_schema >()) {
2047
2372
  String_Obj ss = parse_identifier_schema();
2048
- return SASS_MEMORY_NEW(Media_Query_Expression, pstate, &ss, 0, true);
2373
+ return SASS_MEMORY_NEW(Media_Query_Expression, pstate, ss, 0, true);
2049
2374
  }
2050
2375
  if (!lex_css< exactly<'('> >()) {
2051
- error("media query expression must begin with '('", pstate);
2376
+ error("media query expression must begin with '('");
2052
2377
  }
2053
- Expression_Obj feature = 0;
2378
+ Expression_Obj feature;
2054
2379
  if (peek_css< exactly<')'> >()) {
2055
- error("media feature required in media query expression", pstate);
2380
+ error("media feature required in media query expression");
2056
2381
  }
2057
- feature = &parse_expression();
2382
+ feature = parse_expression();
2058
2383
  Expression_Obj expression = 0;
2059
2384
  if (lex_css< exactly<':'> >()) {
2060
- expression = &parse_list(DELAYED);
2385
+ expression = parse_list(DELAYED);
2061
2386
  }
2062
2387
  if (!lex_css< exactly<')'> >()) {
2063
- error("unclosed parenthesis in media query expression", pstate);
2388
+ error("unclosed parenthesis in media query expression");
2064
2389
  }
2065
2390
  return SASS_MEMORY_NEW(Media_Query_Expression, feature->pstate(), feature, expression);
2066
2391
  }
@@ -2070,6 +2395,9 @@ namespace Sass {
2070
2395
  Supports_Block_Obj Parser::parse_supports_directive()
2071
2396
  {
2072
2397
  Supports_Condition_Obj cond = parse_supports_condition();
2398
+ if (!cond) {
2399
+ css_error("Invalid CSS", " after ", ": expected @supports condition (e.g. (display: flexbox)), was ", false);
2400
+ }
2073
2401
  // create the ast node object for the support queries
2074
2402
  Supports_Block_Obj query = SASS_MEMORY_NEW(Supports_Block, pstate, cond);
2075
2403
  // additional block is mandatory
@@ -2084,7 +2412,7 @@ namespace Sass {
2084
2412
  Supports_Condition_Obj Parser::parse_supports_condition()
2085
2413
  {
2086
2414
  lex < css_whitespace >();
2087
- Supports_Condition_Obj cond = 0;
2415
+ Supports_Condition_Obj cond;
2088
2416
  if ((cond = parse_supports_negation())) return cond;
2089
2417
  if ((cond = parse_supports_operator())) return cond;
2090
2418
  if ((cond = parse_supports_interpolation())) return cond;
@@ -2095,13 +2423,13 @@ namespace Sass {
2095
2423
  {
2096
2424
  if (!lex < kwd_not >()) return 0;
2097
2425
  Supports_Condition_Obj cond = parse_supports_condition_in_parens();
2098
- return SASS_MEMORY_NEW(Supports_Negation, pstate, &cond);
2426
+ return SASS_MEMORY_NEW(Supports_Negation, pstate, cond);
2099
2427
  }
2100
2428
 
2101
2429
  Supports_Condition_Obj Parser::parse_supports_operator()
2102
2430
  {
2103
2431
  Supports_Condition_Obj cond = parse_supports_condition_in_parens();
2104
- if (!&cond) return 0;
2432
+ if (cond.isNull()) return 0;
2105
2433
 
2106
2434
  while (true) {
2107
2435
  Supports_Operator::Operand op = Supports_Operator::OR;
@@ -2112,7 +2440,7 @@ namespace Sass {
2112
2440
  Supports_Condition_Obj right = parse_supports_condition_in_parens();
2113
2441
 
2114
2442
  // Supports_Condition_Ptr cc = SASS_MEMORY_NEW(Supports_Condition, *static_cast<Supports_Condition_Ptr>(cond));
2115
- cond = SASS_MEMORY_NEW(Supports_Operator, pstate, &cond, &right, op);
2443
+ cond = SASS_MEMORY_NEW(Supports_Operator, pstate, cond, right, op);
2116
2444
  }
2117
2445
  return cond;
2118
2446
  }
@@ -2124,21 +2452,25 @@ namespace Sass {
2124
2452
  String_Obj interp = parse_interpolated_chunk(lexed);
2125
2453
  if (!interp) return 0;
2126
2454
 
2127
- return SASS_MEMORY_NEW(Supports_Interpolation, pstate, &interp);
2455
+ return SASS_MEMORY_NEW(Supports_Interpolation, pstate, interp);
2128
2456
  }
2129
2457
 
2130
2458
  // TODO: This needs some major work. Although feature conditions
2131
2459
  // look like declarations their semantics differ significantly
2132
2460
  Supports_Condition_Obj Parser::parse_supports_declaration()
2133
2461
  {
2134
- Supports_Condition_Ptr cond = 0;
2462
+ Supports_Condition_Ptr cond;
2135
2463
  // parse something declaration like
2136
- Declaration_Obj declaration = parse_declaration();
2137
- if (!declaration) error("@supports condition expected declaration", pstate);
2464
+ Expression_Obj feature = parse_expression();
2465
+ Expression_Obj expression = 0;
2466
+ if (lex_css< exactly<':'> >()) {
2467
+ expression = parse_list(DELAYED);
2468
+ }
2469
+ if (!feature || !expression) error("@supports condition expected declaration");
2138
2470
  cond = SASS_MEMORY_NEW(Supports_Declaration,
2139
- declaration->pstate(),
2140
- &declaration->property(),
2141
- declaration->value());
2471
+ feature->pstate(),
2472
+ feature,
2473
+ expression);
2142
2474
  // ToDo: maybe we need an additional error condition?
2143
2475
  return cond;
2144
2476
  }
@@ -2146,17 +2478,17 @@ namespace Sass {
2146
2478
  Supports_Condition_Obj Parser::parse_supports_condition_in_parens()
2147
2479
  {
2148
2480
  Supports_Condition_Obj interp = parse_supports_interpolation();
2149
- if (&interp != 0) return interp;
2481
+ if (interp != 0) return interp;
2150
2482
 
2151
2483
  if (!lex < exactly <'('> >()) return 0;
2152
2484
  lex < css_whitespace >();
2153
2485
 
2154
2486
  Supports_Condition_Obj cond = parse_supports_condition();
2155
- if (&cond != 0) {
2156
- if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration", pstate);
2487
+ if (cond != 0) {
2488
+ if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration");
2157
2489
  } else {
2158
2490
  cond = parse_supports_declaration();
2159
- if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration", pstate);
2491
+ if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration");
2160
2492
  }
2161
2493
  lex < css_whitespace >();
2162
2494
  return cond;
@@ -2164,51 +2496,52 @@ namespace Sass {
2164
2496
 
2165
2497
  At_Root_Block_Obj Parser::parse_at_root_block()
2166
2498
  {
2499
+ stack.push_back(Scope::AtRoot);
2167
2500
  ParserState at_source_position = pstate;
2168
2501
  Block_Obj body = 0;
2169
2502
  At_Root_Query_Obj expr;
2170
2503
  Lookahead lookahead_result;
2171
- LOCAL_FLAG(in_at_root, true);
2172
2504
  if (lex_css< exactly<'('> >()) {
2173
2505
  expr = parse_at_root_query();
2174
2506
  }
2175
2507
  if (peek_css < exactly<'{'> >()) {
2176
2508
  lex <optional_spaces>();
2177
- body = &parse_block(true);
2509
+ body = parse_block(true);
2178
2510
  }
2179
2511
  else if ((lookahead_result = lookahead_for_selector(position)).found) {
2180
- Ruleset_Obj r = parse_ruleset(lookahead_result, false);
2512
+ Ruleset_Obj r = parse_ruleset(lookahead_result);
2181
2513
  body = SASS_MEMORY_NEW(Block, r->pstate(), 1, true);
2182
- body->append(&r);
2514
+ body->append(r);
2183
2515
  }
2184
2516
  At_Root_Block_Obj at_root = SASS_MEMORY_NEW(At_Root_Block, at_source_position, body);
2185
- if (&expr) at_root->expression(&expr);
2517
+ if (!expr.isNull()) at_root->expression(expr);
2518
+ stack.pop_back();
2186
2519
  return at_root;
2187
2520
  }
2188
2521
 
2189
2522
  At_Root_Query_Obj Parser::parse_at_root_query()
2190
2523
  {
2191
- if (peek< exactly<')'> >()) error("at-root feature required in at-root expression", pstate);
2524
+ if (peek< exactly<')'> >()) error("at-root feature required in at-root expression");
2192
2525
 
2193
2526
  if (!peek< alternatives< kwd_with_directive, kwd_without_directive > >()) {
2194
2527
  css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
2195
2528
  }
2196
2529
 
2197
2530
  Expression_Obj feature = parse_list();
2198
- if (!lex_css< exactly<':'> >()) error("style declaration must contain a value", pstate);
2531
+ if (!lex_css< exactly<':'> >()) error("style declaration must contain a value");
2199
2532
  Expression_Obj expression = parse_list();
2200
2533
  List_Obj value = SASS_MEMORY_NEW(List, feature->pstate(), 1);
2201
2534
 
2202
2535
  if (expression->concrete_type() == Expression::LIST) {
2203
- value = SASS_MEMORY_CAST(List, expression);
2536
+ value = Cast<List>(expression);
2204
2537
  }
2205
2538
  else value->append(expression);
2206
2539
 
2207
2540
  At_Root_Query_Obj cond = SASS_MEMORY_NEW(At_Root_Query,
2208
2541
  value->pstate(),
2209
2542
  feature,
2210
- &value);
2211
- if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
2543
+ value);
2544
+ if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression");
2212
2545
  return cond;
2213
2546
  }
2214
2547
 
@@ -2216,18 +2549,20 @@ namespace Sass {
2216
2549
  {
2217
2550
  std::string kwd(lexed);
2218
2551
 
2219
- if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
2552
+ if (lexed == "@else") error("Invalid CSS: @else must come after @if");
2553
+
2554
+ // this whole branch is never hit via spec tests
2220
2555
 
2221
2556
  Directive_Ptr at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
2222
2557
  Lookahead lookahead = lookahead_for_include(position);
2223
2558
  if (lookahead.found && !lookahead.has_interpolants) {
2224
- at_rule->selector(&parse_selector_list(true));
2559
+ at_rule->selector(parse_selector_list(false));
2225
2560
  }
2226
2561
 
2227
2562
  lex < css_comments >(false);
2228
2563
 
2229
2564
  if (lex < static_property >()) {
2230
- at_rule->value(&parse_interpolated_chunk(Token(lexed)));
2565
+ at_rule->value(parse_interpolated_chunk(Token(lexed)));
2231
2566
  } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
2232
2567
  at_rule->value(parse_list());
2233
2568
  }
@@ -2241,24 +2576,25 @@ namespace Sass {
2241
2576
  return at_rule;
2242
2577
  }
2243
2578
 
2579
+ // this whole branch is never hit via spec tests
2244
2580
  Directive_Obj Parser::parse_prefixed_directive()
2245
2581
  {
2246
2582
  std::string kwd(lexed);
2247
2583
 
2248
- if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
2584
+ if (lexed == "@else") error("Invalid CSS: @else must come after @if");
2249
2585
 
2250
2586
  Directive_Obj at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
2251
2587
  Lookahead lookahead = lookahead_for_include(position);
2252
2588
  if (lookahead.found && !lookahead.has_interpolants) {
2253
- at_rule->selector(&parse_selector_list(true));
2589
+ at_rule->selector(parse_selector_list(false));
2254
2590
  }
2255
2591
 
2256
2592
  lex < css_comments >(false);
2257
2593
 
2258
2594
  if (lex < static_property >()) {
2259
- at_rule->value(&parse_interpolated_chunk(Token(lexed)));
2595
+ at_rule->value(parse_interpolated_chunk(Token(lexed)));
2260
2596
  } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
2261
- at_rule->value(&parse_list());
2597
+ at_rule->value(parse_list());
2262
2598
  }
2263
2599
 
2264
2600
  lex < css_comments >(false);
@@ -2276,7 +2612,7 @@ namespace Sass {
2276
2612
  Directive_Obj directive = SASS_MEMORY_NEW(Directive, pstate, lexed);
2277
2613
  String_Schema_Obj val = parse_almost_any_value();
2278
2614
  // strip left and right if they are of type string
2279
- directive->value(&val);
2615
+ directive->value(val);
2280
2616
  if (peek< exactly<'{'> >()) {
2281
2617
  directive->block(parse_block());
2282
2618
  }
@@ -2286,7 +2622,7 @@ namespace Sass {
2286
2622
  Expression_Obj Parser::lex_interpolation()
2287
2623
  {
2288
2624
  if (lex < interpolant >(true) != NULL) {
2289
- return &parse_interpolated_chunk(lexed, true);
2625
+ return parse_interpolated_chunk(lexed, true);
2290
2626
  }
2291
2627
  return 0;
2292
2628
  }
@@ -2299,7 +2635,7 @@ namespace Sass {
2299
2635
 
2300
2636
  Expression_Obj Parser::lex_interp_string()
2301
2637
  {
2302
- Expression_Obj rv = 0;
2638
+ Expression_Obj rv;
2303
2639
  if ((rv = lex_interp< re_string_double_open, re_string_double_close >())) return rv;
2304
2640
  if ((rv = lex_interp< re_string_single_open, re_string_single_close >())) return rv;
2305
2641
  return rv;
@@ -2359,15 +2695,17 @@ namespace Sass {
2359
2695
 
2360
2696
  Expression_Obj Parser::lex_almost_any_value_token()
2361
2697
  {
2362
- Expression_Obj rv = 0;
2698
+ Expression_Obj rv;
2363
2699
  if (*position == 0) return 0;
2364
- if ((rv = &lex_almost_any_value_chars())) return rv;
2700
+ if ((rv = lex_almost_any_value_chars())) return rv;
2365
2701
  // if ((rv = lex_block_comment())) return rv;
2366
2702
  // if ((rv = lex_single_line_comment())) return rv;
2367
- if ((rv = &lex_interp_string())) return rv;
2368
- if ((rv = &lex_interp_uri())) return rv;
2369
- if ((rv = &lex_interpolation())) return rv;
2370
- return rv;
2703
+ if ((rv = lex_interp_string())) return rv;
2704
+ if ((rv = lex_interp_uri())) return rv;
2705
+ if ((rv = lex_interpolation())) return rv;
2706
+ if (lex< alternatives< hex, hex0 > >())
2707
+ { return lexed_hex_color(lexed); }
2708
+ return rv;
2371
2709
  }
2372
2710
 
2373
2711
  String_Schema_Obj Parser::parse_almost_any_value()
@@ -2384,7 +2722,7 @@ namespace Sass {
2384
2722
  return schema.detach();
2385
2723
  }
2386
2724
 
2387
- while ((token = &lex_almost_any_value_token())) {
2725
+ while ((token = lex_almost_any_value_token())) {
2388
2726
  schema->append(token);
2389
2727
  }
2390
2728
 
@@ -2402,7 +2740,7 @@ namespace Sass {
2402
2740
  stack.back() != Scope::Mixin &&
2403
2741
  stack.back() != Scope::Control &&
2404
2742
  stack.back() != Scope::Rules) {
2405
- error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
2743
+ error("Illegal nesting: Only properties may be nested beneath properties.");
2406
2744
  }
2407
2745
  return SASS_MEMORY_NEW(Warning, pstate, parse_list(DELAYED));
2408
2746
  }
@@ -2414,7 +2752,7 @@ namespace Sass {
2414
2752
  stack.back() != Scope::Mixin &&
2415
2753
  stack.back() != Scope::Control &&
2416
2754
  stack.back() != Scope::Rules) {
2417
- error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
2755
+ error("Illegal nesting: Only properties may be nested beneath properties.");
2418
2756
  }
2419
2757
  return SASS_MEMORY_NEW(Error, pstate, parse_list(DELAYED));
2420
2758
  }
@@ -2426,7 +2764,7 @@ namespace Sass {
2426
2764
  stack.back() != Scope::Mixin &&
2427
2765
  stack.back() != Scope::Control &&
2428
2766
  stack.back() != Scope::Rules) {
2429
- error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
2767
+ error("Illegal nesting: Only properties may be nested beneath properties.");
2430
2768
  }
2431
2769
  return SASS_MEMORY_NEW(Debug, pstate, parse_list(DELAYED));
2432
2770
  }
@@ -2436,7 +2774,7 @@ namespace Sass {
2436
2774
  // check that we do not have an empty list (ToDo: check if we got all cases)
2437
2775
  if (peek_css < alternatives < exactly < ';' >, exactly < '}' >, end_of_file > >())
2438
2776
  { css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was "); }
2439
- return SASS_MEMORY_NEW(Return, pstate, &parse_list());
2777
+ return SASS_MEMORY_NEW(Return, pstate, parse_list());
2440
2778
  }
2441
2779
 
2442
2780
  Lookahead Parser::lookahead_for_selector(const char* start)
@@ -2452,12 +2790,20 @@ namespace Sass {
2452
2790
  re_selector_list
2453
2791
  >(p)
2454
2792
  ) {
2793
+ bool could_be_property = peek< sequence< exactly<'-'>, exactly<'-'> > >(p) != 0;
2794
+ bool could_be_escaped = false;
2455
2795
  while (p < q) {
2456
2796
  // did we have interpolations?
2457
2797
  if (*p == '#' && *(p+1) == '{') {
2458
2798
  rv.has_interpolants = true;
2459
2799
  p = q; break;
2460
2800
  }
2801
+ // A property that's ambiguous with a nested selector is interpreted as a
2802
+ // custom property.
2803
+ if (*p == ':' && !could_be_escaped) {
2804
+ rv.is_custom_property = could_be_property || p+1 == q || peek< space >(p+1);
2805
+ }
2806
+ could_be_escaped = *p == '\\';
2461
2807
  ++ p;
2462
2808
  }
2463
2809
  // store anyway }
@@ -2469,6 +2815,7 @@ namespace Sass {
2469
2815
  // check expected opening bracket
2470
2816
  // only after successfull matching
2471
2817
  if (peek < exactly<'{'> >(q)) rv.found = q;
2818
+ // else if (peek < end_of_file >(q)) rv.found = q;
2472
2819
  else if (peek < exactly<'('> >(q)) rv.found = q;
2473
2820
  // else if (peek < exactly<';'> >(q)) rv.found = q;
2474
2821
  // else if (peek < exactly<'}'> >(q)) rv.found = q;
@@ -2538,6 +2885,7 @@ namespace Sass {
2538
2885
  sequence <
2539
2886
  // optional_spaces,
2540
2887
  alternatives <
2888
+ // end_of_file,
2541
2889
  exactly<'{'>,
2542
2890
  exactly<'}'>,
2543
2891
  exactly<';'>
@@ -2622,8 +2970,9 @@ namespace Sass {
2622
2970
  skip = check_bom_chars(source, end, gb_18030_bom, 4);
2623
2971
  encoding = "GB-18030";
2624
2972
  break;
2973
+ default: break;
2625
2974
  }
2626
- if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding, pstate);
2975
+ if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding);
2627
2976
  position += skip;
2628
2977
  }
2629
2978
 
@@ -2641,14 +2990,14 @@ namespace Sass {
2641
2990
  Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, Operand op)
2642
2991
  {
2643
2992
  for (size_t i = 0, S = operands.size(); i < S; ++i) {
2644
- base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op, &base, operands[i]);
2993
+ base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op, base, operands[i]);
2645
2994
  }
2646
2995
  return base;
2647
2996
  }
2648
2997
 
2649
2998
  Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, std::vector<Operand>& ops, size_t i)
2650
2999
  {
2651
- if (String_Schema_Ptr schema = dynamic_cast<String_Schema_Ptr>(&base)) {
3000
+ if (String_Schema_Ptr schema = Cast<String_Schema>(base)) {
2652
3001
  // return schema;
2653
3002
  if (schema->has_interpolants()) {
2654
3003
  if (i + 1 < operands.size() && (
@@ -2663,7 +3012,7 @@ namespace Sass {
2663
3012
  || (ops[0].operand == Sass_OP::GTE)
2664
3013
  )) {
2665
3014
  Expression_Obj rhs = fold_operands(operands[i], operands, ops, i + 1);
2666
- rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema, &rhs);
3015
+ rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema, rhs);
2667
3016
  return rhs;
2668
3017
  }
2669
3018
  // return schema;
@@ -2671,54 +3020,64 @@ namespace Sass {
2671
3020
  }
2672
3021
 
2673
3022
  for (size_t S = operands.size(); i < S; ++i) {
2674
- if (String_Schema_Ptr schema = dynamic_cast<String_Schema_Ptr>(&operands[i])) {
3023
+ if (String_Schema_Ptr schema = Cast<String_Schema>(operands[i])) {
2675
3024
  if (schema->has_interpolants()) {
2676
3025
  if (i + 1 < S) {
3026
+ // this whole branch is never hit via spec tests
2677
3027
  Expression_Obj rhs = fold_operands(operands[i+1], operands, ops, i + 2);
2678
- rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema, &rhs);
2679
- base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, &rhs);
3028
+ rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema, rhs);
3029
+ base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, rhs);
2680
3030
  return base;
2681
3031
  }
2682
- base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]);
3032
+ base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
2683
3033
  return base;
2684
3034
  } else {
2685
- base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]);
3035
+ base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
2686
3036
  }
2687
3037
  } else {
2688
- base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]);
3038
+ base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
2689
3039
  }
2690
- Binary_Expression_Ptr b = static_cast<Binary_Expression_Ptr>(&base);
3040
+ Binary_Expression_Ptr b = Cast<Binary_Expression>(base.ptr());
2691
3041
  if (b && ops[i].operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
2692
3042
  base->is_delayed(true);
2693
3043
  }
2694
3044
  }
2695
3045
  // nested binary expression are never to be delayed
2696
- if (Binary_Expression_Ptr b = dynamic_cast<Binary_Expression_Ptr>(&base)) {
2697
- if (SASS_MEMORY_CAST(Binary_Expression, b->left())) base->set_delayed(false);
2698
- if (SASS_MEMORY_CAST(Binary_Expression, b->right())) base->set_delayed(false);
3046
+ if (Binary_Expression_Ptr b = Cast<Binary_Expression>(base)) {
3047
+ if (Cast<Binary_Expression>(b->left())) base->set_delayed(false);
3048
+ if (Cast<Binary_Expression>(b->right())) base->set_delayed(false);
2699
3049
  }
2700
3050
  return base;
2701
3051
  }
2702
3052
 
2703
3053
  void Parser::error(std::string msg, Position pos)
2704
3054
  {
2705
- throw Exception::InvalidSass(ParserState(path, source, pos.line ? pos : before_token, Offset(0, 0)), msg);
3055
+ Position p(pos.line ? pos : before_token);
3056
+ ParserState pstate(path, source, p, Offset(0, 0));
3057
+ traces.push_back(Backtrace(pstate));
3058
+ throw Exception::InvalidSass(pstate, traces, msg);
3059
+ }
3060
+
3061
+ void Parser::error(std::string msg)
3062
+ {
3063
+ error(msg, pstate);
2706
3064
  }
2707
3065
 
2708
3066
  // print a css parsing error with actual context information from parsed source
2709
- void Parser::css_error(const std::string& msg, const std::string& prefix, const std::string& middle)
3067
+ void Parser::css_error(const std::string& msg, const std::string& prefix, const std::string& middle, const bool trim)
2710
3068
  {
2711
3069
  int max_len = 18;
2712
3070
  const char* end = this->end;
2713
3071
  while (*end != 0) ++ end;
2714
3072
  const char* pos = peek < optional_spaces >();
3073
+ if (!pos) pos = position;
2715
3074
 
2716
3075
  const char* last_pos(pos);
2717
3076
  if (last_pos > source) {
2718
3077
  utf8::prior(last_pos, source);
2719
3078
  }
2720
3079
  // backup position to last significant char
2721
- while (last_pos > source && last_pos < end) {
3080
+ while (trim && last_pos > source && last_pos < end) {
2722
3081
  if (!Prelexer::is_space(*last_pos)) break;
2723
3082
  utf8::prior(last_pos, source);
2724
3083
  }
@@ -2727,8 +3086,8 @@ namespace Sass {
2727
3086
  const char* pos_left(last_pos);
2728
3087
  const char* end_left(last_pos);
2729
3088
 
2730
- utf8::next(pos_left, end);
2731
- utf8::next(end_left, end);
3089
+ if (*pos_left) utf8::next(pos_left, end);
3090
+ if (*end_left) utf8::next(end_left, end);
2732
3091
  while (pos_left > source) {
2733
3092
  if (utf8::distance(pos_left, end_left) >= max_len) {
2734
3093
  utf8::prior(pos_left, source);
@@ -2769,8 +3128,10 @@ namespace Sass {
2769
3128
  size_t right_subpos = right.size() > 15 ? right.size() - 15 : 0;
2770
3129
  if (left_subpos && ellipsis_left) left = ellipsis + left.substr(left_subpos);
2771
3130
  if (right_subpos && ellipsis_right) right = right.substr(right_subpos) + ellipsis;
3131
+ // Hotfix when source is null, probably due to interpolation parsing!?
3132
+ if (source == NULL || *source == 0) source = pstate.src;
2772
3133
  // now pass new message to the more generic error function
2773
- error(msg + prefix + quote(left) + middle + quote(right), pstate);
3134
+ error(msg + prefix + quote(left) + middle + quote(right));
2774
3135
  }
2775
3136
 
2776
3137
  }