sassc 1.11.4 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
  }