sassc 0.0.9 → 0.0.10

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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/ext/libsass/.gitignore +13 -6
  4. data/ext/libsass/Makefile +42 -26
  5. data/ext/libsass/Makefile.am +43 -30
  6. data/ext/libsass/Readme.md +4 -2
  7. data/ext/libsass/appveyor.yml +10 -14
  8. data/ext/libsass/ast.cpp +54 -44
  9. data/ext/libsass/ast.hpp +404 -236
  10. data/ext/libsass/ast_def_macros.hpp +5 -0
  11. data/ext/libsass/ast_factory.hpp +6 -3
  12. data/ext/libsass/ast_fwd_decl.hpp +12 -0
  13. data/ext/libsass/b64/encode.h +2 -2
  14. data/ext/libsass/backtrace.hpp +13 -17
  15. data/ext/libsass/base64vlq.hpp +4 -1
  16. data/ext/libsass/bind.cpp +12 -15
  17. data/ext/libsass/bind.hpp +6 -6
  18. data/ext/libsass/color_names.hpp +4 -1
  19. data/ext/libsass/configure.ac +7 -21
  20. data/ext/libsass/constants.cpp +6 -4
  21. data/ext/libsass/constants.hpp +10 -4
  22. data/ext/libsass/context.cpp +89 -58
  23. data/ext/libsass/context.hpp +28 -35
  24. data/ext/libsass/contextualize.cpp +20 -10
  25. data/ext/libsass/contextualize.hpp +8 -23
  26. data/ext/libsass/contrib/libsass.spec +66 -0
  27. data/ext/libsass/cssize.cpp +547 -0
  28. data/ext/libsass/cssize.hpp +82 -0
  29. data/ext/libsass/debug.hpp +3 -3
  30. data/ext/libsass/debugger.hpp +358 -0
  31. data/ext/libsass/emitter.cpp +255 -0
  32. data/ext/libsass/emitter.hpp +83 -0
  33. data/ext/libsass/environment.hpp +7 -3
  34. data/ext/libsass/error_handling.cpp +11 -14
  35. data/ext/libsass/error_handling.hpp +9 -7
  36. data/ext/libsass/eval.cpp +253 -161
  37. data/ext/libsass/eval.hpp +13 -13
  38. data/ext/libsass/expand.cpp +135 -64
  39. data/ext/libsass/expand.hpp +11 -13
  40. data/ext/libsass/extend.cpp +66 -20
  41. data/ext/libsass/extend.hpp +6 -11
  42. data/ext/libsass/file.cpp +31 -26
  43. data/ext/libsass/file.hpp +6 -1
  44. data/ext/libsass/functions.cpp +270 -287
  45. data/ext/libsass/functions.hpp +8 -11
  46. data/ext/libsass/inspect.cpp +385 -255
  47. data/ext/libsass/inspect.hpp +15 -26
  48. data/ext/libsass/kwd_arg_macros.hpp +5 -0
  49. data/ext/libsass/mapping.hpp +4 -3
  50. data/ext/libsass/memory_manager.hpp +5 -2
  51. data/ext/libsass/node.cpp +50 -50
  52. data/ext/libsass/node.hpp +26 -27
  53. data/ext/libsass/operation.hpp +15 -4
  54. data/ext/libsass/output.cpp +401 -0
  55. data/ext/libsass/output.hpp +56 -0
  56. data/ext/libsass/parser.cpp +573 -399
  57. data/ext/libsass/parser.hpp +122 -88
  58. data/ext/libsass/paths.hpp +7 -2
  59. data/ext/libsass/plugins.cpp +155 -0
  60. data/ext/libsass/plugins.hpp +56 -0
  61. data/ext/libsass/position.cpp +128 -0
  62. data/ext/libsass/position.hpp +108 -11
  63. data/ext/libsass/prelexer.cpp +184 -110
  64. data/ext/libsass/prelexer.hpp +131 -24
  65. data/ext/libsass/remove_placeholders.cpp +1 -1
  66. data/ext/libsass/remove_placeholders.hpp +6 -6
  67. data/ext/libsass/sass.cpp +3 -3
  68. data/ext/libsass/sass.h +12 -4
  69. data/ext/libsass/sass2scss.cpp +3 -2
  70. data/ext/libsass/sass2scss.h +5 -0
  71. data/ext/libsass/sass_context.cpp +136 -37
  72. data/ext/libsass/sass_context.h +19 -10
  73. data/ext/libsass/sass_functions.cpp +29 -2
  74. data/ext/libsass/sass_functions.h +8 -2
  75. data/ext/libsass/sass_interface.cpp +32 -23
  76. data/ext/libsass/sass_interface.h +9 -4
  77. data/ext/libsass/sass_util.cpp +19 -23
  78. data/ext/libsass/sass_util.hpp +28 -27
  79. data/ext/libsass/sass_values.cpp +6 -4
  80. data/ext/libsass/sass_values.h +3 -3
  81. data/ext/libsass/script/ci-build-libsass +13 -1
  82. data/ext/libsass/script/ci-report-coverage +2 -1
  83. data/ext/libsass/source_map.cpp +79 -28
  84. data/ext/libsass/source_map.hpp +35 -16
  85. data/ext/libsass/subset_map.hpp +6 -4
  86. data/ext/libsass/to_c.hpp +4 -4
  87. data/ext/libsass/to_string.cpp +13 -8
  88. data/ext/libsass/to_string.hpp +6 -4
  89. data/ext/libsass/units.cpp +2 -1
  90. data/ext/libsass/units.hpp +6 -1
  91. data/ext/libsass/utf8_string.cpp +0 -5
  92. data/ext/libsass/utf8_string.hpp +3 -2
  93. data/ext/libsass/util.cpp +461 -49
  94. data/ext/libsass/util.hpp +34 -13
  95. data/ext/libsass/version.sh +10 -0
  96. data/ext/libsass/win/libsass.filters +20 -11
  97. data/ext/libsass/win/libsass.vcxproj +11 -8
  98. data/lib/sassc/importer.rb +1 -8
  99. data/lib/sassc/native.rb +7 -0
  100. data/lib/sassc/native/native_context_api.rb +5 -5
  101. data/lib/sassc/version.rb +1 -1
  102. data/test/native_test.rb +1 -1
  103. metadata +14 -10
  104. data/ext/libsass/copy_c_str.cpp +0 -13
  105. data/ext/libsass/copy_c_str.hpp +0 -5
  106. data/ext/libsass/output_compressed.cpp +0 -401
  107. data/ext/libsass/output_compressed.hpp +0 -95
  108. data/ext/libsass/output_nested.cpp +0 -364
  109. data/ext/libsass/output_nested.hpp +0 -108
  110. data/ext/libsass/test-driver +0 -127
  111. data/ext/libsass/token.hpp +0 -32
@@ -0,0 +1,56 @@
1
+ #ifndef SASS_OUTPUT_H
2
+ #define SASS_OUTPUT_H
3
+
4
+ #include <string>
5
+ #include <vector>
6
+
7
+ #include "util.hpp"
8
+ #include "inspect.hpp"
9
+ #include "operation.hpp"
10
+
11
+ namespace Sass {
12
+ class Context;
13
+ using namespace std;
14
+
15
+ // Refactor to make it generic to find linefeed (look behind)
16
+ inline bool ends_with(std::string const & value, std::string const & ending)
17
+ {
18
+ if (ending.size() > value.size()) return false;
19
+ return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
20
+ }
21
+
22
+ class Output : public Inspect {
23
+ protected:
24
+ using Inspect::operator();
25
+
26
+ public:
27
+ // change to Emitter
28
+ Output(Context* ctx);
29
+ virtual ~Output();
30
+
31
+ protected:
32
+ string charset;
33
+ vector<Import*> top_imports;
34
+ vector<Comment*> top_comments;
35
+
36
+ public:
37
+ OutputBuffer get_buffer(void);
38
+
39
+ virtual void operator()(Ruleset*);
40
+ // virtual void operator()(Propset*);
41
+ virtual void operator()(Feature_Block*);
42
+ virtual void operator()(Media_Block*);
43
+ virtual void operator()(At_Rule*);
44
+ virtual void operator()(Keyframe_Rule*);
45
+ virtual void operator()(Import*);
46
+ virtual void operator()(Comment*);
47
+ virtual void operator()(String_Quoted*);
48
+ virtual void operator()(String_Constant*);
49
+
50
+ void fallback_impl(AST_Node* n);
51
+
52
+ };
53
+
54
+ }
55
+
56
+ #endif
@@ -7,11 +7,7 @@
7
7
  #include "to_string.hpp"
8
8
  #include "constants.hpp"
9
9
  #include "util.hpp"
10
-
11
- #ifndef SASS_PRELEXER
12
10
  #include "prelexer.hpp"
13
- #endif
14
-
15
11
  #include "sass_functions.h"
16
12
 
17
13
  #include <typeinfo>
@@ -20,36 +16,60 @@ namespace Sass {
20
16
  using namespace std;
21
17
  using namespace Constants;
22
18
 
23
- Parser Parser::from_c_str(const char* str, Context& ctx, string path, Position source_position)
19
+ Parser Parser::from_c_str(const char* str, Context& ctx, ParserState pstate)
24
20
  {
25
- Parser p(ctx, path, source_position);
21
+ Parser p(ctx, pstate);
26
22
  p.source = str;
27
23
  p.position = p.source;
28
24
  p.end = str + strlen(str);
25
+ Block* root = new (ctx.mem) Block(pstate);
26
+ p.block_stack.push_back(root);
27
+ root->is_root(true);
28
+ return p;
29
+ }
30
+
31
+ Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate)
32
+ {
33
+ Parser p(ctx, pstate);
34
+ p.source = beg;
35
+ p.position = p.source;
36
+ p.end = end;
37
+ Block* root = new (ctx.mem) Block(pstate);
38
+ p.block_stack.push_back(root);
39
+ root->is_root(true);
29
40
  return p;
30
41
  }
31
42
 
32
- Parser Parser::from_token(Token t, Context& ctx, string path, Position source_position)
43
+ bool Parser::peek_newline(const char* start)
44
+ {
45
+ return peek_linefeed(start ? start : position);
46
+ }
47
+
48
+ Parser Parser::from_token(Token t, Context& ctx, ParserState pstate)
33
49
  {
34
- Parser p(ctx, path, source_position);
50
+ Parser p(ctx, pstate);
35
51
  p.source = t.begin;
36
52
  p.position = p.source;
37
53
  p.end = t.end;
38
- p.dequote = true;
54
+ Block* root = new (ctx.mem) Block(pstate);
55
+ p.block_stack.push_back(root);
56
+ root->is_root(true);
39
57
  return p;
40
58
  }
41
59
 
42
60
  Block* Parser::parse()
43
61
  {
44
- Block* root = new (ctx.mem) Block(path, source_position);
62
+ Block* root = new (ctx.mem) Block(pstate);
63
+ block_stack.push_back(root);
45
64
  root->is_root(true);
46
65
  read_bom();
47
66
  lex< optional_spaces >();
48
67
  Selector_Lookahead lookahead_result;
49
68
  while (position < end) {
50
69
  if (lex< block_comment >()) {
70
+ bool is_important = lexed.begin[2] == '!';
51
71
  String* contents = parse_interpolated_chunk(lexed);
52
- Comment* comment = new (ctx.mem) Comment(path, source_position, contents);
72
+ Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
53
73
  (*root) << comment;
54
74
  }
55
75
  else if (peek< import >()) {
@@ -57,25 +77,25 @@ namespace Sass {
57
77
  if (!imp->urls().empty()) (*root) << imp;
58
78
  if (!imp->files().empty()) {
59
79
  for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
60
- (*root) << new (ctx.mem) Import_Stub(path, source_position, imp->files()[i]);
80
+ (*root) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
61
81
  }
62
82
  }
63
- if (!lex< one_plus< exactly<';'> > >()) error("top-level @import directive must be terminated by ';'");
83
+ if (!lex< one_plus< exactly<';'> > >()) error("top-level @import directive must be terminated by ';'", pstate);
64
84
  }
65
85
  else if (peek< mixin >() || peek< function >()) {
66
86
  (*root) << parse_definition();
67
87
  }
68
88
  else if (peek< variable >()) {
69
89
  (*root) << parse_assignment();
70
- if (!lex< one_plus< exactly<';'> > >()) error("top-level variable binding must be terminated by ';'");
90
+ if (!lex< one_plus< exactly<';'> > >()) error("top-level variable binding must be terminated by ';'", pstate);
71
91
  }
72
- else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
92
+ /*else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
73
93
  (*root) << parse_propset();
74
- }
94
+ }*/
75
95
  else if (peek< include >() /* || peek< exactly<'+'> >() */) {
76
96
  Mixin_Call* mixin_call = parse_mixin_call();
77
97
  (*root) << mixin_call;
78
- if (!mixin_call->block() && !lex< one_plus< exactly<';'> > >()) error("top-level @include directive must be terminated by ';'");
98
+ if (!mixin_call->block() && !lex< one_plus< exactly<';'> > >()) error("top-level @include directive must be terminated by ';'", pstate);
79
99
  }
80
100
  else if (peek< if_directive >()) {
81
101
  (*root) << parse_if_directive();
@@ -92,30 +112,33 @@ namespace Sass {
92
112
  else if (peek< media >()) {
93
113
  (*root) << parse_media_block();
94
114
  }
115
+ else if (peek< at_root >()) {
116
+ (*root) << parse_at_root_block();
117
+ }
95
118
  else if (peek< supports >()) {
96
119
  (*root) << parse_feature_block();
97
120
  }
98
121
  else if (peek< warn >()) {
99
122
  (*root) << parse_warning();
100
- if (!lex< one_plus< exactly<';'> > >()) error("top-level @warn directive must be terminated by ';'");
123
+ if (!lex< one_plus< exactly<';'> > >()) error("top-level @warn directive must be terminated by ';'", pstate);
101
124
  }
102
125
  else if (peek< err >()) {
103
126
  (*root) << parse_error();
104
- if (!lex< one_plus< exactly<';'> > >()) error("top-level @error directive must be terminated by ';'");
127
+ if (!lex< one_plus< exactly<';'> > >()) error("top-level @error directive must be terminated by ';'", pstate);
105
128
  }
106
129
  else if (peek< dbg >()) {
107
130
  (*root) << parse_debug();
108
- if (!lex< one_plus< exactly<';'> > >()) error("top-level @debug directive must be terminated by ';'");
131
+ if (!lex< one_plus< exactly<';'> > >()) error("top-level @debug directive must be terminated by ';'", pstate);
109
132
  }
110
133
  // ignore the @charset directive for now
111
134
  else if (lex< exactly< charset_kwd > >()) {
112
- lex< string_constant >();
135
+ lex< quoted_string >();
113
136
  lex< one_plus< exactly<';'> > >();
114
137
  }
115
138
  else if (peek< at_keyword >()) {
116
139
  At_Rule* at_rule = parse_at_rule();
117
140
  (*root) << at_rule;
118
- if (!at_rule->block() && !lex< one_plus< exactly<';'> > >()) error("top-level directive must be terminated by ';'");
141
+ if (!at_rule->block() && !lex< one_plus< exactly<';'> > >()) error("top-level directive must be terminated by ';'", pstate);
119
142
  }
120
143
  else if ((lookahead_result = lookahead_for_selector(position)).found) {
121
144
  (*root) << parse_ruleset(lookahead_result);
@@ -124,12 +147,13 @@ namespace Sass {
124
147
  lex< one_plus< exactly<';'> > >();
125
148
  }
126
149
  else {
127
- lex< spaces_and_comments >();
150
+ lex< optional_spaces_and_comments >();
128
151
  if (position >= end) break;
129
- error("invalid top-level expression");
152
+ error("invalid top-level expression", pstate);
130
153
  }
131
154
  lex< optional_spaces >();
132
155
  }
156
+ block_stack.pop_back();
133
157
  return root;
134
158
  }
135
159
 
@@ -143,17 +167,17 @@ namespace Sass {
143
167
  }
144
168
 
145
169
  if (extension == ".css") {
146
- String_Constant* loc = new (ctx.mem) String_Constant(path, source_position, import_path, true);
147
- Argument* loc_arg = new (ctx.mem) Argument(path, source_position, loc);
148
- Arguments* loc_args = new (ctx.mem) Arguments(path, source_position);
170
+ String_Constant* loc = new (ctx.mem) String_Constant(pstate, unquote(import_path));
171
+ Argument* loc_arg = new (ctx.mem) Argument(pstate, loc);
172
+ Arguments* loc_args = new (ctx.mem) Arguments(pstate);
149
173
  (*loc_args) << loc_arg;
150
- Function_Call* new_url = new (ctx.mem) Function_Call(path, source_position, "url", loc_args);
174
+ Function_Call* new_url = new (ctx.mem) Function_Call(pstate, "url", loc_args);
151
175
  imp->urls().push_back(new_url);
152
176
  }
153
177
  else {
154
178
  string current_dir = File::dir_name(path);
155
179
  string resolved(ctx.add_file(current_dir, unquoted));
156
- if (resolved.empty()) error("file to import not found or unreadable: " + unquoted + "\nCurrent dir: " + current_dir);
180
+ if (resolved.empty()) error("file to import not found or unreadable: " + unquoted + "\nCurrent dir: " + current_dir, pstate);
157
181
  imp->files().push_back(resolved);
158
182
  }
159
183
 
@@ -162,10 +186,11 @@ namespace Sass {
162
186
  Import* Parser::parse_import()
163
187
  {
164
188
  lex< import >();
165
- Import* imp = new (ctx.mem) Import(path, source_position);
189
+ Import* imp = new (ctx.mem) Import(pstate);
166
190
  bool first = true;
167
191
  do {
168
- if (lex< string_constant >()) {
192
+ while (lex< block_comment >());
193
+ if (lex< quoted_string >()) {
169
194
  string import_path(lexed);
170
195
 
171
196
  // struct Sass_Options opt = sass_context_get_options(ctx)
@@ -186,9 +211,15 @@ namespace Sass {
186
211
  while (*includes) {
187
212
  struct Sass_Import* include = *includes;
188
213
  const char *file = sass_import_get_path(include);
189
- char *source = sass_import_take_source(include);
214
+ char* source = sass_import_take_source(include);
215
+ size_t line = sass_import_get_error_line(include);
216
+ size_t column = sass_import_get_error_column(include);
217
+ const char* message = sass_import_get_error_message(include);
190
218
  // char *srcmap = sass_import_take_srcmap(include);
191
- if (source) {
219
+ if (message) {
220
+ if (line == string::npos && column == string::npos) error(message, pstate);
221
+ else error(message, ParserState(message, Position(line, column)));
222
+ } else if (source) {
192
223
  if (file) {
193
224
  ctx.add_source(file, inc_path, source);
194
225
  imp->files().push_back(file);
@@ -208,15 +239,23 @@ namespace Sass {
208
239
  }
209
240
  }
210
241
 
211
- add_single_file(imp, import_path);
242
+ if (!unquote(import_path).substr(0, 7).compare("http://") ||
243
+ !unquote(import_path).substr(0, 8).compare("https://") ||
244
+ !unquote(import_path).substr(0, 2).compare("//"))
245
+ {
246
+ imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
247
+ }
248
+ else {
249
+ add_single_file(imp, import_path);
250
+ }
212
251
 
213
252
  }
214
253
  else if (peek< uri_prefix >()) {
215
254
  imp->urls().push_back(parse_value());
216
255
  }
217
256
  else {
218
- if (first) error("@import directive requires a url or quoted path");
219
- else error("expecting another url or quoted path in @import list");
257
+ if (first) error("@import directive requires a url or quoted path", pstate);
258
+ else error("expecting another url or quoted path in @import list", pstate);
220
259
  }
221
260
  first = false;
222
261
  } while (lex< exactly<','> >());
@@ -229,81 +268,86 @@ namespace Sass {
229
268
  if (lex< mixin >()) which_type = Definition::MIXIN;
230
269
  else if (lex< function >()) which_type = Definition::FUNCTION;
231
270
  string which_str(lexed);
232
- if (!lex< identifier >()) error("invalid name in " + which_str + " definition");
271
+ if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate);
233
272
  string name(Util::normalize_underscores(lexed));
234
273
  if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not"))
235
- { error("Invalid function name \"" + name + "\"."); }
236
- Position source_position_of_def = source_position;
274
+ { error("Invalid function name \"" + name + "\".", pstate); }
275
+ ParserState source_position_of_def = pstate;
237
276
  Parameters* params = parse_parameters();
238
- if (!peek< exactly<'{'> >()) error("body for " + which_str + " " + name + " must begin with a '{'");
277
+ if (!peek< exactly<'{'> >()) error("body for " + which_str + " " + name + " must begin with a '{'", pstate);
239
278
  if (which_type == Definition::MIXIN) stack.push_back(mixin_def);
240
279
  else stack.push_back(function_def);
241
280
  Block* body = parse_block();
242
281
  stack.pop_back();
243
- Definition* def = new (ctx.mem) Definition(path, source_position_of_def, name, params, body, which_type);
282
+ Definition* def = new (ctx.mem) Definition(source_position_of_def, name, params, body, which_type);
244
283
  return def;
245
284
  }
246
285
 
247
286
  Parameters* Parser::parse_parameters()
248
287
  {
249
288
  string name(lexed); // for the error message
250
- Parameters* params = new (ctx.mem) Parameters(path, source_position);
289
+ Parameters* params = new (ctx.mem) Parameters(pstate);
251
290
  if (lex< exactly<'('> >()) {
252
291
  // if there's anything there at all
253
292
  if (!peek< exactly<')'> >()) {
254
293
  do (*params) << parse_parameter();
255
- while (lex< exactly<','> >());
294
+ while (lex< alternatives < spaces,block_comment, exactly<','> > >());
256
295
  }
257
- if (!lex< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name);
296
+ while (lex< alternatives < spaces, block_comment > >()) {};
297
+ if (!lex< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, pstate);
258
298
  }
259
299
  return params;
260
300
  }
261
301
 
262
302
  Parameter* Parser::parse_parameter()
263
303
  {
304
+ while (lex< alternatives < spaces, block_comment > >());
264
305
  lex< variable >();
265
306
  string name(Util::normalize_underscores(lexed));
266
- Position pos = source_position;
307
+ ParserState pos = pstate;
267
308
  Expression* val = 0;
268
309
  bool is_rest = false;
310
+ while (lex< alternatives < spaces, block_comment > >());
269
311
  if (lex< exactly<':'> >()) { // there's a default value
312
+ while (lex< block_comment >());
270
313
  val = parse_space_list();
271
314
  val->is_delayed(false);
272
315
  }
273
316
  else if (lex< exactly< ellipsis > >()) {
274
317
  is_rest = true;
275
318
  }
276
- Parameter* p = new (ctx.mem) Parameter(path, pos, name, val, is_rest);
319
+ Parameter* p = new (ctx.mem) Parameter(pos, name, val, is_rest);
277
320
  return p;
278
321
  }
279
322
 
280
323
  Mixin_Call* Parser::parse_mixin_call()
281
324
  {
282
325
  lex< include >() /* || lex< exactly<'+'> >() */;
283
- if (!lex< identifier >()) error("invalid name in @include directive");
284
- Position source_position_of_call = source_position;
326
+ if (!lex< identifier >()) error("invalid name in @include directive", pstate);
327
+ ParserState source_position_of_call = pstate;
285
328
  string name(Util::normalize_underscores(lexed));
286
329
  Arguments* args = parse_arguments();
287
330
  Block* content = 0;
288
331
  if (peek< exactly<'{'> >()) {
289
332
  content = parse_block();
290
333
  }
291
- Mixin_Call* the_call = new (ctx.mem) Mixin_Call(path, source_position_of_call, name, args, content);
334
+ Mixin_Call* the_call = new (ctx.mem) Mixin_Call(source_position_of_call, name, args, content);
292
335
  return the_call;
293
336
  }
294
337
 
295
338
  Arguments* Parser::parse_arguments()
296
339
  {
297
340
  string name(lexed);
298
- Arguments* args = new (ctx.mem) Arguments(path, source_position);
341
+ Arguments* args = new (ctx.mem) Arguments(pstate);
299
342
 
300
343
  if (lex< exactly<'('> >()) {
301
344
  // if there's anything there at all
302
345
  if (!peek< exactly<')'> >()) {
303
346
  do (*args) << parse_argument();
304
- while (lex< exactly<','> >());
347
+ while (lex< alternatives < block_comment, exactly<','> > >());
305
348
  }
306
- if (!lex< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name);
349
+ while (lex< block_comment >());
350
+ if (!lex< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, pstate);
307
351
  }
308
352
 
309
353
  return args;
@@ -312,14 +356,16 @@ namespace Sass {
312
356
  Argument* Parser::parse_argument()
313
357
  {
314
358
  Argument* arg;
315
- if (peek< sequence < variable, spaces_and_comments, exactly<':'> > >()) {
359
+ while (lex< alternatives < spaces, block_comment > >());
360
+ if (peek< sequence < variable, zero_plus < alternatives < spaces, line_comment, block_comment > >, exactly<':'> > >()) {
316
361
  lex< variable >();
317
362
  string name(Util::normalize_underscores(lexed));
318
- Position p = source_position;
363
+ ParserState p = pstate;
364
+ while (lex< alternatives < spaces, block_comment > >()) {};
319
365
  lex< exactly<':'> >();
320
366
  Expression* val = parse_space_list();
321
367
  val->is_delayed(false);
322
- arg = new (ctx.mem) Argument(path, p, val, name);
368
+ arg = new (ctx.mem) Argument(p, val, name);
323
369
  }
324
370
  else {
325
371
  bool is_arglist = false;
@@ -330,7 +376,7 @@ namespace Sass {
330
376
  if (val->concrete_type() == Expression::MAP) is_keyword = true;
331
377
  else is_arglist = true;
332
378
  }
333
- arg = new (ctx.mem) Argument(path, source_position, val, "", is_arglist, is_keyword);
379
+ arg = new (ctx.mem) Argument(pstate, val, "", is_arglist, is_keyword);
334
380
  }
335
381
  return arg;
336
382
  }
@@ -339,8 +385,8 @@ namespace Sass {
339
385
  {
340
386
  lex< variable >();
341
387
  string name(Util::normalize_underscores(lexed));
342
- Position var_source_position = source_position;
343
- if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement");
388
+ ParserState var_source_position = pstate;
389
+ if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
344
390
  Expression* val = parse_list();
345
391
  val->is_delayed(false);
346
392
  bool is_guarded = false;
@@ -349,10 +395,11 @@ namespace Sass {
349
395
  is_guarded = lex< default_flag >() || is_guarded;
350
396
  is_global = lex< global_flag >() || is_global;
351
397
  }
352
- Assignment* var = new (ctx.mem) Assignment(path, var_source_position, name, val, is_guarded, is_global);
398
+ Assignment* var = new (ctx.mem) Assignment(var_source_position, name, val, is_guarded, is_global);
353
399
  return var;
354
400
  }
355
401
 
402
+ /* not used anymore - remove?
356
403
  Propset* Parser::parse_propset()
357
404
  {
358
405
  String* property_segment;
@@ -361,17 +408,19 @@ namespace Sass {
361
408
  }
362
409
  else {
363
410
  lex< sequence< optional< exactly<'*'> >, identifier > >();
364
- property_segment = new (ctx.mem) String_Constant(path, source_position, lexed);
411
+ property_segment = new (ctx.mem) String_Quoted(pstate, lexed);
365
412
  }
366
- Propset* propset = new (ctx.mem) Propset(path, source_position, property_segment);
413
+ Propset* propset = new (ctx.mem) Propset(pstate, property_segment);
367
414
  lex< exactly<':'> >();
368
415
 
369
- if (!peek< exactly<'{'> >()) error("expected a '{' after namespaced property");
416
+ if (!peek< exactly<'{'> >()) error("expected a '{' after namespaced property", pstate);
370
417
 
371
418
  propset->block(parse_block());
372
419
 
420
+ propset->tabs(indentation);
421
+
373
422
  return propset;
374
- }
423
+ } */
375
424
 
376
425
  Ruleset* Parser::parse_ruleset(Selector_Lookahead lookahead)
377
426
  {
@@ -382,10 +431,14 @@ namespace Sass {
382
431
  else {
383
432
  sel = parse_selector_group();
384
433
  }
385
- Position r_source_position = source_position;
386
- if (!peek< exactly<'{'> >()) error("expected a '{' after the selector");
434
+ bool old_in_at_root = in_at_root;
435
+ in_at_root = false;
436
+ ParserState r_source_position = pstate;
437
+ if (!peek< exactly<'{'> >()) error("expected a '{' after the selector", pstate);
387
438
  Block* block = parse_block();
388
- Ruleset* ruleset = new (ctx.mem) Ruleset(path, r_source_position, sel, block);
439
+ in_at_root = old_in_at_root;
440
+ old_in_at_root = false;
441
+ Ruleset* ruleset = new (ctx.mem) Ruleset(r_source_position, sel, block);
389
442
  return ruleset;
390
443
  }
391
444
 
@@ -393,66 +446,91 @@ namespace Sass {
393
446
  {
394
447
  lex< optional_spaces >();
395
448
  const char* i = position;
396
- const char* p;
397
- String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
398
-
449
+ String_Schema* schema = new (ctx.mem) String_Schema(pstate);
399
450
  while (i < end_of_selector) {
400
- p = find_first_in_interval< exactly<hash_lbrace> >(i, end_of_selector);
401
- if (p) {
402
- // accumulate the preceding segment if there is one
403
- if (i < p) (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, p));
404
- // find the end of the interpolant and parse it
405
- const char* j = find_first_in_interval< exactly<rbrace> >(p, end_of_selector);
406
- Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, path, source_position).parse_list();
407
- interp_node->is_interpolant(true);
408
- (*schema) << interp_node;
409
- i = j + 1;
410
- }
411
- else { // no interpolants left; add the last segment if there is one
412
- if (i < end_of_selector) (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, end_of_selector));
451
+ // try to parse mutliple interpolants
452
+ if (const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, end_of_selector)) {
453
+ // accumulate the preceding segment if the position has advanced
454
+ if (i < p) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
455
+ // skip to the delimiter by skipping occurences in quoted strings
456
+ const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
457
+ Expression* interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
458
+ interpolant->is_interpolant(true);
459
+ (*schema) << interpolant;
460
+ i = j;
461
+ }
462
+ // no more interpolants have been found
463
+ // add the last segment if there is one
464
+ else {
465
+ if (i < end_of_selector) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, end_of_selector));
413
466
  break;
414
467
  }
415
468
  }
416
469
  position = end_of_selector;
417
- return new (ctx.mem) Selector_Schema(path, source_position, schema);
470
+ Selector_Schema* selector_schema = new (ctx.mem) Selector_Schema(pstate, schema);
471
+ selector_schema->media_block(last_media_block);
472
+ selector_schema->last_block(block_stack.back());
473
+ return selector_schema;
418
474
  }
419
475
 
420
476
  Selector_List* Parser::parse_selector_group()
421
477
  {
422
- To_String to_string;
423
- lex< spaces_and_comments >();
424
- Selector_List* group = new (ctx.mem) Selector_List(path, source_position);
478
+ bool reloop = true;
479
+ To_String to_string(&ctx);
480
+ lex< optional_spaces_and_comments >();
481
+ Selector_List* group = new (ctx.mem) Selector_List(pstate);
482
+ group->media_block(last_media_block);
483
+ group->last_block(block_stack.back());
425
484
  do {
485
+ reloop = false;
426
486
  if (peek< exactly<'{'> >() ||
427
487
  peek< exactly<'}'> >() ||
428
488
  peek< exactly<')'> >() ||
429
489
  peek< exactly<';'> >())
430
490
  break; // in case there are superfluous commas at the end
431
491
  Complex_Selector* comb = parse_selector_combination();
432
- if (!comb->has_reference()) {
433
- Position sel_source_position = source_position;
434
- Selector_Reference* ref = new (ctx.mem) Selector_Reference(path, sel_source_position);
435
- Compound_Selector* ref_wrap = new (ctx.mem) Compound_Selector(path, sel_source_position);
492
+ if (!comb->has_reference() && !in_at_root) {
493
+ ParserState sel_source_position = pstate;
494
+ Selector_Reference* ref = new (ctx.mem) Selector_Reference(sel_source_position);
495
+ Compound_Selector* ref_wrap = new (ctx.mem) Compound_Selector(sel_source_position);
496
+ ref_wrap->media_block(last_media_block);
497
+ ref_wrap->last_block(block_stack.back());
436
498
  (*ref_wrap) << ref;
437
499
  if (!comb->head()) {
438
500
  comb->head(ref_wrap);
439
501
  comb->has_reference(true);
440
502
  }
441
503
  else {
442
- comb = new (ctx.mem) Complex_Selector(path, sel_source_position, Complex_Selector::ANCESTOR_OF, ref_wrap, comb);
504
+ comb = new (ctx.mem) Complex_Selector(sel_source_position, Complex_Selector::ANCESTOR_OF, ref_wrap, comb);
505
+ comb->media_block(last_media_block);
506
+ comb->last_block(block_stack.back());
443
507
  comb->has_reference(true);
444
508
  }
509
+ if (peek_newline()) ref_wrap->has_line_break(true);
510
+ }
511
+ while (peek< sequence< optional_spaces_and_comments, exactly<','> > >())
512
+ {
513
+ // consume everything up and including the comma speparator
514
+ reloop = lex< sequence< optional_spaces_and_comments, exactly<','> > >() != 0;
515
+ // remember line break (also between some commas)
516
+ if (peek_newline()) comb->has_line_feed(true);
517
+ if (comb->tail() && peek_newline()) comb->tail()->has_line_feed(true);
518
+ if (comb->tail() && comb->tail()->head() && peek_newline()) comb->tail()->head()->has_line_feed(true);
519
+ // remember line break (also between some commas)
445
520
  }
446
521
  (*group) << comb;
447
522
  }
448
- while (lex< one_plus< sequence< spaces_and_comments, exactly<','> > > >());
449
- while (lex< optional >()); // JMA - ignore optional flag if it follows the selector group
523
+ while (reloop);
524
+ while (lex< optional >()) {
525
+ group->is_optional(true);
526
+ }
450
527
  return group;
451
528
  }
452
529
 
453
530
  Complex_Selector* Parser::parse_selector_combination()
454
531
  {
455
- Position sel_source_position = Position();
532
+ // lex< optional_spaces_and_comments >();
533
+ Position sel_source_position(-1);
456
534
  Compound_Selector* lhs;
457
535
  if (peek< exactly<'+'> >() ||
458
536
  peek< exactly<'~'> >() ||
@@ -462,7 +540,8 @@ namespace Sass {
462
540
  }
463
541
  else {
464
542
  lhs = parse_simple_selector_sequence();
465
- sel_source_position = source_position;
543
+ sel_source_position = before_token;
544
+ lhs->has_line_break(peek_newline());
466
545
  }
467
546
 
468
547
  Complex_Selector::Combinator cmb;
@@ -470,6 +549,7 @@ namespace Sass {
470
549
  else if (lex< exactly<'~'> >()) cmb = Complex_Selector::PRECEDES;
471
550
  else if (lex< exactly<'>'> >()) cmb = Complex_Selector::PARENT_OF;
472
551
  else cmb = Complex_Selector::ANCESTOR_OF;
552
+ bool cpx_lf = peek_newline();
473
553
 
474
554
  Complex_Selector* rhs;
475
555
  if (peek< exactly<','> >() ||
@@ -483,31 +563,40 @@ namespace Sass {
483
563
  }
484
564
  else {
485
565
  rhs = parse_selector_combination();
486
- sel_source_position = source_position;
566
+ sel_source_position = before_token;
487
567
  }
488
- if (!sel_source_position.line) sel_source_position = source_position;
489
- return new (ctx.mem) Complex_Selector(path, sel_source_position, cmb, lhs, rhs);
568
+ if (!sel_source_position.line) sel_source_position = before_token;
569
+ Complex_Selector* cpx = new (ctx.mem) Complex_Selector(ParserState(path, sel_source_position), cmb, lhs, rhs);
570
+ cpx->media_block(last_media_block);
571
+ cpx->last_block(block_stack.back());
572
+ if (cpx_lf) cpx->has_line_break(cpx_lf);
573
+ return cpx;
490
574
  }
491
575
 
492
576
  Compound_Selector* Parser::parse_simple_selector_sequence()
493
577
  {
494
- Compound_Selector* seq = new (ctx.mem) Compound_Selector(path, source_position);
578
+ Compound_Selector* seq = new (ctx.mem) Compound_Selector(pstate);
579
+ seq->media_block(last_media_block);
580
+ seq->last_block(block_stack.back());
495
581
  bool sawsomething = false;
496
582
  if (lex< exactly<'&'> >()) {
497
- // if you see a &
498
- (*seq) << new (ctx.mem) Selector_Reference(path, source_position);
583
+ // check if we have a parent selector on the root level block
584
+ if (block_stack.back() && block_stack.back()->is_root()) {
585
+ error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate);
586
+ }
587
+ (*seq) << new (ctx.mem) Selector_Reference(pstate);
499
588
  sawsomething = true;
500
589
  // if you see a space after a &, then you're done
501
- if(lex< spaces >()) {
590
+ if(peek< spaces >()) {
502
591
  return seq;
503
592
  }
504
593
  }
505
- if (sawsomething && lex< sequence< negate< functional >, alternatives< identifier_fragment, universal, string_constant, dimension, percentage, number > > >()) {
594
+ if (sawsomething && lex< sequence< negate< functional >, alternatives< identifier_fragment, universal, quoted_string, dimension, percentage, number > > >()) {
506
595
  // saw an ampersand, then allow type selectors with arbitrary number of hyphens at the beginning
507
- (*seq) << new (ctx.mem) Type_Selector(path, source_position, lexed);
508
- } else if (lex< sequence< negate< functional >, alternatives< type_selector, universal, string_constant, dimension, percentage, number > > >()) {
596
+ (*seq) << new (ctx.mem) Type_Selector(pstate, unquote(lexed));
597
+ } else if (lex< sequence< negate< functional >, alternatives< type_selector, universal, quoted_string, dimension, percentage, number > > >()) {
509
598
  // if you see a type selector
510
- (*seq) << new (ctx.mem) Type_Selector(path, source_position, lexed);
599
+ (*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
511
600
  sawsomething = true;
512
601
  }
513
602
  if (!sawsomething) {
@@ -532,10 +621,10 @@ namespace Sass {
532
621
  Simple_Selector* Parser::parse_simple_selector()
533
622
  {
534
623
  if (lex< id_name >() || lex< class_name >()) {
535
- return new (ctx.mem) Selector_Qualifier(path, source_position, lexed);
624
+ return new (ctx.mem) Selector_Qualifier(pstate, unquote(lexed));
536
625
  }
537
- else if (lex< string_constant >() || lex< number >()) {
538
- return new (ctx.mem) Type_Selector(path, source_position, lexed);
626
+ else if (lex< quoted_string >() || lex< number >()) {
627
+ return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
539
628
  }
540
629
  else if (peek< pseudo_not >()) {
541
630
  return parse_negated_selector();
@@ -547,10 +636,13 @@ namespace Sass {
547
636
  return parse_attribute_selector();
548
637
  }
549
638
  else if (lex< placeholder >()) {
550
- return new (ctx.mem) Selector_Placeholder(path, source_position, lexed);
639
+ Selector_Placeholder* sel = new (ctx.mem) Selector_Placeholder(pstate, unquote(lexed));
640
+ sel->media_block(last_media_block);
641
+ sel->last_block(block_stack.back());
642
+ return sel;
551
643
  }
552
644
  else {
553
- error("invalid selector after " + lexed.to_string());
645
+ error("invalid selector after " + lexed.to_string(), pstate);
554
646
  }
555
647
  // unreachable statement
556
648
  return 0;
@@ -560,73 +652,73 @@ namespace Sass {
560
652
  {
561
653
  lex< pseudo_not >();
562
654
  string name(lexed);
563
- Position nsource_position = source_position;
655
+ ParserState nsource_position = pstate;
564
656
  Selector* negated = parse_selector_group();
565
657
  if (!lex< exactly<')'> >()) {
566
- error("negated selector is missing ')'");
658
+ error("negated selector is missing ')'", pstate);
567
659
  }
568
- return new (ctx.mem) Wrapped_Selector(path, nsource_position, name, negated);
660
+ return new (ctx.mem) Wrapped_Selector(nsource_position, name, negated);
569
661
  }
570
662
 
571
663
  Simple_Selector* Parser::parse_pseudo_selector() {
572
664
  if (lex< sequence< pseudo_prefix, functional > >() || lex< functional >()) {
573
665
  string name(lexed);
574
666
  String* expr = 0;
575
- Position p = source_position;
667
+ ParserState p = pstate;
576
668
  Selector* wrapped = 0;
577
669
  if (lex< alternatives< even, odd > >()) {
578
- expr = new (ctx.mem) String_Constant(path, p, lexed);
670
+ expr = new (ctx.mem) String_Quoted(p, lexed);
579
671
  }
580
672
  else if (peek< binomial >(position)) {
581
673
  lex< sequence< optional< coefficient >, exactly<'n'> > >();
582
- String_Constant* var_coef = new (ctx.mem) String_Constant(path, p, lexed);
674
+ String_Constant* var_coef = new (ctx.mem) String_Quoted(p, lexed);
583
675
  lex< sign >();
584
- String_Constant* op = new (ctx.mem) String_Constant(path, p, lexed);
676
+ String_Constant* op = new (ctx.mem) String_Quoted(p, lexed);
585
677
  // Binary_Expression::Type op = (lexed == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
586
678
  lex< digits >();
587
- String_Constant* constant = new (ctx.mem) String_Constant(path, p, lexed);
588
- // expr = new (ctx.mem) Binary_Expression(path, p, op, var_coef, constant);
589
- String_Schema* schema = new (ctx.mem) String_Schema(path, p, 3);
679
+ String_Constant* constant = new (ctx.mem) String_Quoted(p, lexed);
680
+ // expr = new (ctx.mem) Binary_Expression(p, op, var_coef, constant);
681
+ String_Schema* schema = new (ctx.mem) String_Schema(p, 3);
590
682
  *schema << var_coef << op << constant;
591
683
  expr = schema;
592
684
  }
593
685
  else if (peek< sequence< optional<sign>,
594
686
  optional<digits>,
595
687
  exactly<'n'>,
596
- spaces_and_comments,
688
+ optional_spaces_and_comments,
597
689
  exactly<')'> > >()) {
598
690
  lex< sequence< optional<sign>,
599
691
  optional<digits>,
600
692
  exactly<'n'> > >();
601
- expr = new (ctx.mem) String_Constant(path, p, lexed);
693
+ expr = new (ctx.mem) String_Quoted(p, lexed);
602
694
  }
603
695
  else if (lex< sequence< optional<sign>, digits > >()) {
604
- expr = new (ctx.mem) String_Constant(path, p, lexed);
696
+ expr = new (ctx.mem) String_Quoted(p, lexed);
605
697
  }
606
- else if (peek< sequence< identifier, spaces_and_comments, exactly<')'> > >()) {
698
+ else if (peek< sequence< identifier, optional_spaces_and_comments, exactly<')'> > >()) {
607
699
  lex< identifier >();
608
- expr = new (ctx.mem) String_Constant(path, p, lexed);
700
+ expr = new (ctx.mem) String_Quoted(p, lexed);
609
701
  }
610
- else if (lex< string_constant >()) {
611
- expr = new (ctx.mem) String_Constant(path, p, lexed);
702
+ else if (lex< quoted_string >()) {
703
+ expr = new (ctx.mem) String_Quoted(p, lexed);
612
704
  }
613
705
  else if (peek< exactly<')'> >()) {
614
- expr = new (ctx.mem) String_Constant(path, p, "");
706
+ expr = new (ctx.mem) String_Constant(p, "");
615
707
  }
616
708
  else {
617
709
  wrapped = parse_selector_group();
618
710
  }
619
- if (!lex< exactly<')'> >()) error("unterminated argument to " + name + "...)");
711
+ if (!lex< exactly<')'> >()) error("unterminated argument to " + name + "...)", pstate);
620
712
  if (wrapped) {
621
- return new (ctx.mem) Wrapped_Selector(path, p, name, wrapped);
713
+ return new (ctx.mem) Wrapped_Selector(p, name, wrapped);
622
714
  }
623
- return new (ctx.mem) Pseudo_Selector(path, p, name, expr);
715
+ return new (ctx.mem) Pseudo_Selector(p, name, expr);
624
716
  }
625
717
  else if (lex < sequence< pseudo_prefix, identifier > >()) {
626
- return new (ctx.mem) Pseudo_Selector(path, source_position, lexed);
718
+ return new (ctx.mem) Pseudo_Selector(pstate, unquote(lexed));
627
719
  }
628
720
  else {
629
- error("unrecognized pseudo-class or pseudo-element");
721
+ error("unrecognized pseudo-class or pseudo-element", pstate);
630
722
  }
631
723
  // unreachable statement
632
724
  return 0;
@@ -635,29 +727,29 @@ namespace Sass {
635
727
  Attribute_Selector* Parser::parse_attribute_selector()
636
728
  {
637
729
  lex< exactly<'['> >();
638
- Position p = source_position;
639
- if (!lex< attribute_name >()) error("invalid attribute name in attribute selector");
730
+ ParserState p = pstate;
731
+ if (!lex< attribute_name >()) error("invalid attribute name in attribute selector", pstate);
640
732
  string name(lexed);
641
- if (lex< exactly<']'> >()) return new (ctx.mem) Attribute_Selector(path, p, name, "", 0);
733
+ if (lex< exactly<']'> >()) return new (ctx.mem) Attribute_Selector(p, name, "", 0);
642
734
  if (!lex< alternatives< exact_match, class_match, dash_match,
643
735
  prefix_match, suffix_match, substring_match > >()) {
644
- error("invalid operator in attribute selector for " + name);
736
+ error("invalid operator in attribute selector for " + name, pstate);
645
737
  }
646
738
  string matcher(lexed);
647
739
 
648
740
  String* value = 0;
649
741
  if (lex< identifier >()) {
650
- value = new (ctx.mem) String_Constant(path, p, lexed, true);
742
+ value = new (ctx.mem) String_Constant(p, lexed);
651
743
  }
652
- else if (lex< string_constant >()) {
653
- value = parse_interpolated_chunk(lexed);
744
+ else if (lex< quoted_string >()) {
745
+ value = parse_interpolated_chunk(lexed, true); // needed!
654
746
  }
655
747
  else {
656
- error("expected a string constant or identifier in attribute selector for " + name);
748
+ error("expected a string constant or identifier in attribute selector for " + name, pstate);
657
749
  }
658
750
 
659
- if (!lex< exactly<']'> >()) error("unterminated attribute selector for " + name);
660
- return new (ctx.mem) Attribute_Selector(path, p, name, matcher, value);
751
+ if (!lex< exactly<']'> >()) error("unterminated attribute selector for " + name, pstate);
752
+ return new (ctx.mem) Attribute_Selector(p, name, matcher, value);
661
753
  }
662
754
 
663
755
  Block* Parser::parse_block()
@@ -665,43 +757,47 @@ namespace Sass {
665
757
  lex< exactly<'{'> >();
666
758
  bool semicolon = false;
667
759
  Selector_Lookahead lookahead_result;
668
- Block* block = new (ctx.mem) Block(path, source_position);
669
-
760
+ Block* block = new (ctx.mem) Block(pstate);
761
+ block_stack.push_back(block);
762
+ lex< zero_plus < alternatives < space, line_comment > > >();
670
763
  // JMA - ensure that a block containing only block_comments is parsed
671
764
  while (lex< block_comment >()) {
765
+ bool is_important = lexed.begin[2] == '!';
672
766
  String* contents = parse_interpolated_chunk(lexed);
673
- Comment* comment = new (ctx.mem) Comment(path, source_position, contents);
767
+ Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
674
768
  (*block) << comment;
675
769
  }
676
770
 
677
771
  while (!lex< exactly<'}'> >()) {
678
772
  if (semicolon) {
679
773
  if (!lex< one_plus< exactly<';'> > >()) {
680
- error("non-terminal statement or declaration must end with ';'");
774
+ error("non-terminal statement or declaration must end with ';'", pstate);
681
775
  }
682
776
  semicolon = false;
683
777
  while (lex< block_comment >()) {
778
+ bool is_important = lexed.begin[2] == '!';
684
779
  String* contents = parse_interpolated_chunk(lexed);
685
- Comment* comment = new (ctx.mem) Comment(path, source_position, contents);
780
+ Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
686
781
  (*block) << comment;
687
782
  }
688
783
  if (lex< sequence< exactly<'}'>, zero_plus< exactly<';'> > > >()) break;
689
784
  }
690
785
  if (lex< block_comment >()) {
786
+ bool is_important = lexed.begin[2] == '!';
691
787
  String* contents = parse_interpolated_chunk(lexed);
692
- Comment* comment = new (ctx.mem) Comment(path, source_position, contents);
788
+ Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
693
789
  (*block) << comment;
694
790
  }
695
791
  else if (peek< import >(position)) {
696
792
  if (stack.back() == mixin_def || stack.back() == function_def) {
697
- lex< import >(); // to adjust the source_position number
698
- error("@import directives are not allowed inside mixins and functions");
793
+ lex< import >(); // to adjust the before_token number
794
+ error("@import directives are not allowed inside mixins and functions", pstate);
699
795
  }
700
796
  Import* imp = parse_import();
701
797
  if (!imp->urls().empty()) (*block) << imp;
702
798
  if (!imp->files().empty()) {
703
799
  for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
704
- (*block) << new (ctx.mem) Import_Stub(path, source_position, imp->files()[i]);
800
+ (*block) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
705
801
  }
706
802
  }
707
803
  semicolon = true;
@@ -710,6 +806,9 @@ namespace Sass {
710
806
  (*block) << parse_assignment();
711
807
  semicolon = true;
712
808
  }
809
+ else if (lex< line_comment >()) {
810
+ // throw line comments away
811
+ }
713
812
  else if (peek< if_directive >()) {
714
813
  (*block) << parse_if_directive();
715
814
  }
@@ -723,7 +822,7 @@ namespace Sass {
723
822
  (*block) << parse_while_directive();
724
823
  }
725
824
  else if (lex < return_directive >()) {
726
- (*block) << new (ctx.mem) Return(path, source_position, parse_list());
825
+ (*block) << new (ctx.mem) Return(pstate, parse_list());
727
826
  semicolon = true;
728
827
  }
729
828
  else if (peek< warn >()) {
@@ -739,7 +838,7 @@ namespace Sass {
739
838
  semicolon = true;
740
839
  }
741
840
  else if (stack.back() == function_def) {
742
- error("only variable declarations and control directives are allowed inside functions");
841
+ error("only variable declarations and control directives are allowed inside functions", pstate);
743
842
  }
744
843
  else if (peek< mixin >() || peek< function >()) {
745
844
  (*block) << parse_definition();
@@ -752,9 +851,9 @@ namespace Sass {
752
851
  }
753
852
  else if (lex< content >()) {
754
853
  if (stack.back() != mixin_def) {
755
- error("@content may only be used within a mixin");
854
+ error("@content may only be used within a mixin", pstate);
756
855
  }
757
- (*block) << new (ctx.mem) Content(path, source_position);
856
+ (*block) << new (ctx.mem) Content(pstate);
758
857
  semicolon = true;
759
858
  }
760
859
  /*
@@ -765,11 +864,11 @@ namespace Sass {
765
864
  */
766
865
  else if (lex< extend >()) {
767
866
  Selector_Lookahead lookahead = lookahead_for_extension_target(position);
768
- if (!lookahead.found) error("invalid selector for @extend");
867
+ if (!lookahead.found) error("invalid selector for @extend", pstate);
769
868
  Selector* target;
770
869
  if (lookahead.has_interpolants) target = parse_selector_schema(lookahead.found);
771
870
  else target = parse_selector_group();
772
- (*block) << new (ctx.mem) Extension(path, source_position, target);
871
+ (*block) << new (ctx.mem) Extension(pstate, target);
773
872
  semicolon = true;
774
873
  }
775
874
  else if (peek< media >()) {
@@ -778,9 +877,12 @@ namespace Sass {
778
877
  else if (peek< supports >()) {
779
878
  (*block) << parse_feature_block();
780
879
  }
880
+ else if (peek< at_root >()) {
881
+ (*block) << parse_at_root_block();
882
+ }
781
883
  // ignore the @charset directive for now
782
884
  else if (lex< exactly< charset_kwd > >()) {
783
- lex< string_constant >();
885
+ lex< quoted_string >();
784
886
  lex< one_plus< exactly<';'> > >();
785
887
  }
786
888
  else if (peek< at_keyword >()) {
@@ -790,23 +892,28 @@ namespace Sass {
790
892
  }
791
893
  else if ((lookahead_result = lookahead_for_selector(position)).found) {
792
894
  (*block) << parse_ruleset(lookahead_result);
793
- }
895
+ }/* not used anymore - remove?
794
896
  else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
795
897
  (*block) << parse_propset();
796
- }
898
+ }*/
797
899
  else if (!peek< exactly<';'> >()) {
900
+ bool indent = ! peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position);
901
+ /* not used anymore - remove?
798
902
  if (peek< sequence< optional< exactly<'*'> >, identifier_schema, exactly<':'>, exactly<'{'> > >()) {
799
903
  (*block) << parse_propset();
800
904
  }
801
905
  else if (peek< sequence< optional< exactly<'*'> >, identifier, exactly<':'>, exactly<'{'> > >()) {
802
906
  (*block) << parse_propset();
803
907
  }
804
- else {
908
+ else */ {
805
909
  Declaration* decl = parse_declaration();
910
+ decl->tabs(indentation);
806
911
  (*block) << decl;
807
912
  if (peek< exactly<'{'> >()) {
808
913
  // parse a propset that rides on the declaration's property
809
- Propset* ps = new (ctx.mem) Propset(path, source_position, decl->property(), parse_block());
914
+ if (indent) indentation++;
915
+ Propset* ps = new (ctx.mem) Propset(pstate, decl->property(), parse_block());
916
+ if (indent) indentation--;
810
917
  (*block) << ps;
811
918
  }
812
919
  else {
@@ -817,11 +924,13 @@ namespace Sass {
817
924
  }
818
925
  else lex< one_plus< exactly<';'> > >();
819
926
  while (lex< block_comment >()) {
927
+ bool is_important = lexed.begin[2] == '!';
820
928
  String* contents = parse_interpolated_chunk(lexed);
821
- Comment* comment = new (ctx.mem) Comment(path, source_position, contents);
929
+ Comment* comment = new (ctx.mem) Comment(pstate, contents, is_important);
822
930
  (*block) << comment;
823
931
  }
824
932
  }
933
+ block_stack.pop_back();
825
934
  return block;
826
935
  }
827
936
 
@@ -831,27 +940,43 @@ namespace Sass {
831
940
  prop = parse_identifier_schema();
832
941
  }
833
942
  else if (lex< sequence< optional< exactly<'*'> >, identifier > >()) {
834
- prop = new (ctx.mem) String_Constant(path, source_position, lexed);
943
+ prop = new (ctx.mem) String_Quoted(pstate, lexed);
835
944
  }
836
945
  else if (lex< custom_property_name >()) {
837
- prop = new (ctx.mem) String_Constant(path, source_position, lexed);
946
+ prop = new (ctx.mem) String_Quoted(pstate, lexed);
838
947
  }
839
948
  else {
840
- error("invalid property name");
949
+ error("invalid property name", pstate);
841
950
  }
842
- if (!lex< one_plus< exactly<':'> > >()) error("property \"" + string(lexed) + "\" must be followed by a ':'");
843
- if (peek< exactly<';'> >()) error("style declaration must contain a value");
951
+ if (!lex< one_plus< exactly<':'> > >()) error("property \"" + string(lexed) + "\" must be followed by a ':'", pstate);
952
+ if (peek< exactly<';'> >()) error("style declaration must contain a value", pstate);
844
953
  if (peek< static_value >()) {
845
- return new (ctx.mem) Declaration(path, prop->position(), prop, parse_static_value()/*, lex<important>()*/);
954
+ return new (ctx.mem) Declaration(prop->pstate(), prop, parse_static_value()/*, lex<important>()*/);
846
955
  }
847
956
  else {
848
- return new (ctx.mem) Declaration(path, prop->position(), prop, parse_list()/*, lex<important>()*/);
957
+ return new (ctx.mem) Declaration(prop->pstate(), prop, parse_list()/*, lex<important>()*/);
958
+ }
959
+ }
960
+
961
+ // parse +/- and return false if negative
962
+ bool Parser::parse_number_prefix()
963
+ {
964
+ bool positive = true;
965
+ while(true) {
966
+ if (lex < block_comment >()) continue;
967
+ if (lex < number_prefix >()) continue;
968
+ if (lex < exactly < '-' > >()) {
969
+ positive = !positive;
970
+ continue;
971
+ }
972
+ break;
849
973
  }
974
+ return positive;
850
975
  }
851
976
 
852
977
  Expression* Parser::parse_map()
853
978
  {
854
- To_String to_string;
979
+ To_String to_string(&ctx);
855
980
  Expression* key = parse_list();
856
981
 
857
982
  // it's not a map so return the lexed value as a list value
@@ -862,7 +987,7 @@ namespace Sass {
862
987
 
863
988
  Expression* value = parse_space_list();
864
989
 
865
- Map* map = new (ctx.mem) Map(path, source_position, 1);
990
+ Map* map = new (ctx.mem) Map(pstate, 1);
866
991
  (*map) << make_pair(key, value);
867
992
 
868
993
  while (lex< exactly<','> >())
@@ -874,7 +999,7 @@ namespace Sass {
874
999
  Expression* key = parse_list();
875
1000
 
876
1001
  if (!(lex< exactly<':'> >()))
877
- { error("invalid syntax"); }
1002
+ { error("invalid syntax", pstate); }
878
1003
 
879
1004
  Expression* value = parse_space_list();
880
1005
 
@@ -882,7 +1007,7 @@ namespace Sass {
882
1007
  }
883
1008
 
884
1009
  if (map->has_duplicate_key())
885
- { error("Duplicate key \"" + map->get_duplicate_key()->perform(&to_string) + "\" in map " + map->perform(&to_string) + "."); }
1010
+ { error("Duplicate key \"" + map->get_duplicate_key()->perform(&to_string) + "\" in map " + map->perform(&to_string) + ".", pstate); }
886
1011
 
887
1012
  return map;
888
1013
  }
@@ -901,12 +1026,12 @@ namespace Sass {
901
1026
  peek< exactly<')'> >(position) ||
902
1027
  //peek< exactly<':'> >(position) ||
903
1028
  peek< exactly<ellipsis> >(position))
904
- { return new (ctx.mem) List(path, source_position, 0); }
1029
+ { return new (ctx.mem) List(pstate, 0); }
905
1030
  Expression* list1 = parse_space_list();
906
1031
  // if it's a singleton, return it directly; don't wrap it
907
1032
  if (!peek< exactly<','> >(position)) return list1;
908
1033
 
909
- List* comma_list = new (ctx.mem) List(path, source_position, 2, List::COMMA);
1034
+ List* comma_list = new (ctx.mem) List(pstate, 2, List::COMMA);
910
1035
  (*comma_list) << list1;
911
1036
 
912
1037
  while (lex< exactly<','> >())
@@ -943,7 +1068,7 @@ namespace Sass {
943
1068
  peek< global_flag >(position))
944
1069
  { return disj1; }
945
1070
 
946
- List* space_list = new (ctx.mem) List(path, source_position, 2, List::SPACE);
1071
+ List* space_list = new (ctx.mem) List(pstate, 2, List::SPACE);
947
1072
  (*space_list) << disj1;
948
1073
 
949
1074
  while (!(//peek< exactly<'!'> >(position) ||
@@ -1012,7 +1137,7 @@ namespace Sass {
1012
1137
 
1013
1138
  Expression* expr2 = parse_expression();
1014
1139
 
1015
- return new (ctx.mem) Binary_Expression(path, expr1->position(), op, expr1, expr2);
1140
+ return new (ctx.mem) Binary_Expression(expr1->pstate(), op, expr1, expr2);
1016
1141
  }
1017
1142
 
1018
1143
  Expression* Parser::parse_expression()
@@ -1020,14 +1145,15 @@ namespace Sass {
1020
1145
  Expression* term1 = parse_term();
1021
1146
  // if it's a singleton, return it directly; don't wrap it
1022
1147
  if (!(peek< exactly<'+'> >(position) ||
1023
- peek< sequence< negate< number >, exactly<'-'> > >(position)) ||
1148
+ (peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
1149
+ (peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
1024
1150
  peek< identifier >(position))
1025
1151
  { return term1; }
1026
1152
 
1027
1153
  vector<Expression*> operands;
1028
1154
  vector<Binary_Expression::Type> operators;
1029
- while (lex< exactly<'+'> >() || lex< sequence< negate< number >, exactly<'-'> > >()) {
1030
- operators.push_back(lexed == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
1155
+ while (lex< exactly<'+'> >() || lex< sequence< negate< digits >, exactly<'-'> > >()) {
1156
+ operators.push_back(lexed.to_string() == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
1031
1157
  operands.push_back(parse_term());
1032
1158
  }
1033
1159
 
@@ -1040,12 +1166,8 @@ namespace Sass {
1040
1166
 
1041
1167
  // Special case: Ruby sass never tries to modulo if the lhs contains an interpolant
1042
1168
  if (peek< exactly<'%'> >(position) && fact1->concrete_type() == Expression::STRING) {
1043
- try {
1044
- String_Schema* ss = dynamic_cast<String_Schema*>(fact1);
1045
- if (ss->has_interpolants()) return fact1;
1046
- }
1047
- catch (bad_cast&) {}
1048
- catch (...) { throw; }
1169
+ String_Schema* ss = dynamic_cast<String_Schema*>(fact1);
1170
+ if (ss && ss->has_interpolants()) return fact1;
1049
1171
  }
1050
1172
 
1051
1173
  // if it's a singleton, return it directly; don't wrap it
@@ -1054,11 +1176,12 @@ namespace Sass {
1054
1176
  peek< exactly<'%'> >(position)))
1055
1177
  { return fact1; }
1056
1178
 
1179
+ while (lex< block_comment >());
1057
1180
  vector<Expression*> operands;
1058
1181
  vector<Binary_Expression::Type> operators;
1059
1182
  while (lex< exactly<'*'> >() || lex< exactly<'/'> >() || lex< exactly<'%'> >()) {
1060
- if (lexed == "*") operators.push_back(Binary_Expression::MUL);
1061
- else if (lexed == "/") operators.push_back(Binary_Expression::DIV);
1183
+ if (lexed.to_string() == "*") operators.push_back(Binary_Expression::MUL);
1184
+ else if (lexed.to_string() == "/") operators.push_back(Binary_Expression::DIV);
1062
1185
  else operators.push_back(Binary_Expression::MOD);
1063
1186
  operands.push_back(parse_factor());
1064
1187
  }
@@ -1070,7 +1193,7 @@ namespace Sass {
1070
1193
  {
1071
1194
  if (lex< exactly<'('> >()) {
1072
1195
  Expression* value = parse_map();
1073
- if (!lex< exactly<')'> >()) error("unclosed parenthesis");
1196
+ if (!lex< exactly<')'> >()) error("unclosed parenthesis", pstate);
1074
1197
  value->is_delayed(false);
1075
1198
  // make sure wrapped lists and division expressions are non-delayed within parentheses
1076
1199
  if (value->concrete_type() == Expression::LIST) {
@@ -1091,6 +1214,7 @@ namespace Sass {
1091
1214
  }
1092
1215
  else if (peek< exactly< calc_kwd > >() ||
1093
1216
  peek< exactly< moz_calc_kwd > >() ||
1217
+ peek< exactly< ms_calc_kwd > >() ||
1094
1218
  peek< exactly< webkit_calc_kwd > >()) {
1095
1219
  return parse_calc_function();
1096
1220
  }
@@ -1103,14 +1227,18 @@ namespace Sass {
1103
1227
  else if (peek< functional >() && !peek< uri_prefix >()) {
1104
1228
  return parse_function_call();
1105
1229
  }
1106
- else if (lex< sequence< exactly<'+'>, spaces_and_comments, negate< number > > >()) {
1107
- return new (ctx.mem) Unary_Expression(path, source_position, Unary_Expression::PLUS, parse_factor());
1230
+ else if (lex< sequence< exactly<'+'>, optional_spaces_and_comments, negate< number > > >()) {
1231
+ return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::PLUS, parse_factor());
1108
1232
  }
1109
- else if (lex< sequence< exactly<'-'>, spaces_and_comments, negate< number> > >()) {
1110
- return new (ctx.mem) Unary_Expression(path, source_position, Unary_Expression::MINUS, parse_factor());
1233
+ else if (lex< sequence< exactly<'-'>, optional_spaces_and_comments, negate< number> > >()) {
1234
+ return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_factor());
1111
1235
  }
1112
1236
  else if (lex< sequence< not_op, spaces_and_comments > >()) {
1113
- return new (ctx.mem) Unary_Expression(path, source_position, Unary_Expression::NOT, parse_factor());
1237
+ return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::NOT, parse_factor());
1238
+ }
1239
+ else if (peek < sequence < one_plus < alternatives < spaces_and_comments, exactly<'-'>, exactly<'+'> > >, number > >()) {
1240
+ if (parse_number_prefix()) return parse_value(); // prefix is positive
1241
+ return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_value());
1114
1242
  }
1115
1243
  else {
1116
1244
  return parse_value();
@@ -1119,11 +1247,12 @@ namespace Sass {
1119
1247
 
1120
1248
  Expression* Parser::parse_value()
1121
1249
  {
1250
+ while (lex< block_comment >());
1122
1251
  if (lex< uri_prefix >()) {
1123
- Arguments* args = new (ctx.mem) Arguments(path, source_position);
1124
- Function_Call* result = new (ctx.mem) Function_Call(path, source_position, "url", args);
1252
+ Arguments* args = new (ctx.mem) Arguments(pstate);
1253
+ Function_Call* result = new (ctx.mem) Function_Call(pstate, "url", args);
1125
1254
  const char* here = position;
1126
- Position here_p = source_position;
1255
+ Position here_p = before_token;
1127
1256
  // Try to parse a SassScript expression. If it succeeds and we can munch
1128
1257
  // a matching rparen, then that's our url. If we can't munch a matching
1129
1258
  // rparen, or if the attempt to parse an expression fails, then try to
@@ -1131,118 +1260,128 @@ namespace Sass {
1131
1260
  try {
1132
1261
  // special case -- if there's a comment, treat it as part of a URL
1133
1262
  lex<spaces>();
1134
- if (peek<line_comment_prefix>() || peek<block_comment_prefix>()) error("comment in URL"); // doesn't really matter what we throw
1263
+ if (peek<line_comment_prefix>() || peek<block_comment_prefix>()) error("comment in URL", pstate); // doesn't really matter what we throw
1135
1264
  Expression* expr = parse_list();
1136
- if (!lex< exactly<')'> >()) error("dangling expression in URL"); // doesn't really matter what we throw
1137
- Argument* arg = new (ctx.mem) Argument(path, expr->position(), expr);
1265
+ if (!lex< exactly<')'> >()) error("dangling expression in URL", pstate); // doesn't really matter what we throw
1266
+ Argument* arg = new (ctx.mem) Argument(expr->pstate(), expr);
1138
1267
  *args << arg;
1139
1268
  return result;
1140
1269
  }
1141
1270
  catch (Sass_Error&) {
1142
1271
  // back up so we can try again
1143
1272
  position = here;
1144
- source_position = here_p;
1273
+ before_token = here_p;
1145
1274
  }
1146
1275
  catch (...) { throw; }
1147
1276
  lex< spaces >();
1148
1277
  if (lex< url >()) {
1149
1278
  String* the_url = parse_interpolated_chunk(lexed);
1150
- Argument* arg = new (ctx.mem) Argument(path, the_url->position(), the_url);
1279
+ Argument* arg = new (ctx.mem) Argument(the_url->pstate(), the_url);
1151
1280
  *args << arg;
1152
1281
  }
1153
1282
  else {
1154
- error("malformed URL");
1283
+ error("malformed URL", pstate);
1155
1284
  }
1156
- if (!lex< exactly<')'> >()) error("URI is missing ')'");
1285
+ if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
1157
1286
  return result;
1158
1287
  }
1159
1288
 
1160
1289
  if (lex< important >())
1161
- { return new (ctx.mem) String_Constant(path, source_position, "!important"); }
1290
+ { return new (ctx.mem) String_Constant(pstate, "!important"); }
1162
1291
 
1163
- if (lex< value_schema >())
1164
- { return Parser::from_token(lexed, ctx, path, source_position).parse_value_schema(); }
1292
+ const char* stop;
1293
+ if ((stop = peek< value_schema >()))
1294
+ { return parse_value_schema(stop); }
1165
1295
 
1166
1296
  if (lex< sequence< true_val, negate< identifier > > >())
1167
- { return new (ctx.mem) Boolean(path, source_position, true); }
1297
+ { return new (ctx.mem) Boolean(pstate, true); }
1168
1298
 
1169
1299
  if (lex< sequence< false_val, negate< identifier > > >())
1170
- { return new (ctx.mem) Boolean(path, source_position, false); }
1300
+ { return new (ctx.mem) Boolean(pstate, false); }
1171
1301
 
1172
1302
  if (lex< sequence< null, negate< identifier > > >())
1173
- { return new (ctx.mem) Null(path, source_position); }
1303
+ { return new (ctx.mem) Null(pstate); }
1174
1304
 
1175
1305
  if (lex< identifier >()) {
1176
- String_Constant* str = new (ctx.mem) String_Constant(path, source_position, lexed);
1306
+ String_Constant* str = new (ctx.mem) String_Quoted(pstate, lexed);
1177
1307
  // Dont' delay this string if it is a name color. Fixes #652.
1178
- str->is_delayed(ctx.names_to_colors.count(lexed) == 0);
1308
+ str->is_delayed(ctx.names_to_colors.count(unquote(lexed)) == 0);
1179
1309
  return str;
1180
1310
  }
1181
1311
 
1182
1312
  if (lex< percentage >())
1183
- { return new (ctx.mem) Textual(path, source_position, Textual::PERCENTAGE, lexed); }
1313
+ { return new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed); }
1184
1314
 
1185
- if (lex< dimension >())
1186
- { return new (ctx.mem) Textual(path, source_position, Textual::DIMENSION, lexed); }
1315
+ // match hex number first because 0x000 looks like a number followed by an indentifier
1316
+ if (lex< alternatives< hex, hex0 > >())
1317
+ { return new (ctx.mem) Textual(pstate, Textual::HEX, lexed); }
1187
1318
 
1188
- if (lex< number >())
1189
- { return new (ctx.mem) Textual(path, source_position, Textual::NUMBER, lexed); }
1319
+ // also handle the 10em- foo special case
1320
+ if (lex< sequence< dimension, optional< sequence< exactly<'-'>, negate< digit > > > > >())
1321
+ { return new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed); }
1190
1322
 
1191
- if (lex< hex >())
1192
- { return new (ctx.mem) Textual(path, source_position, Textual::HEX, lexed); }
1323
+ if (lex< number >())
1324
+ { return new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed); }
1193
1325
 
1194
- if (peek< string_constant >())
1326
+ if (peek< quoted_string >())
1195
1327
  { return parse_string(); }
1196
1328
 
1197
1329
  if (lex< variable >())
1198
- { return new (ctx.mem) Variable(path, source_position, Util::normalize_underscores(lexed)); }
1330
+ { return new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed)); }
1199
1331
 
1200
1332
  // Special case handling for `%` proceeding an interpolant.
1201
1333
  if (lex< sequence< exactly<'%'>, optional< percentage > > >())
1202
- { return new (ctx.mem) String_Constant(path, source_position, lexed); }
1334
+ { return new (ctx.mem) String_Quoted(pstate, lexed); }
1203
1335
 
1204
- error("error reading values after " + lexed.to_string());
1336
+ error("error reading values after " + lexed.to_string(), pstate);
1205
1337
 
1206
1338
  // unreachable statement
1207
1339
  return 0;
1208
1340
  }
1209
1341
 
1210
- String* Parser::parse_interpolated_chunk(Token chunk)
1342
+ // this parses interpolation inside other strings
1343
+ // means the result should later be quoted again
1344
+ String* Parser::parse_interpolated_chunk(Token chunk, bool constant)
1211
1345
  {
1212
1346
  const char* i = chunk.begin;
1213
1347
  // see if there any interpolants
1214
- const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(chunk.begin, chunk.end);
1348
+ const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
1215
1349
  if (!p) {
1216
- String_Constant* str_node = new (ctx.mem) String_Constant(path, source_position, chunk, dequote);
1217
- str_node->is_delayed(true);
1218
- return str_node;
1350
+ String_Quoted* str_quoted = new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
1351
+ if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
1352
+ str_quoted->is_delayed(true);
1353
+ return str_quoted;
1219
1354
  }
1220
1355
 
1221
- String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
1222
- schema->quote_mark(*chunk.begin);
1356
+ String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1223
1357
  while (i < chunk.end) {
1224
- p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, chunk.end);
1358
+ p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
1225
1359
  if (p) {
1226
1360
  if (i < p) {
1227
- (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, p)); // accumulate the preceding segment if it's nonempty
1361
+ // accumulate the preceding segment if it's nonempty
1362
+ (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
1228
1363
  }
1229
- const char* j = find_first_in_interval< exactly<rbrace> >(p, chunk.end); // find the closing brace
1230
- if (j) {
1364
+ // we need to skip anything inside strings
1365
+ // create a new target in parser/prelexer
1366
+ const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
1367
+ if (j) { --j;
1231
1368
  // parse the interpolant and accumulate it
1232
- Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, path, source_position).parse_list();
1369
+ Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
1233
1370
  interp_node->is_interpolant(true);
1234
1371
  (*schema) << interp_node;
1235
- i = j+1;
1372
+ i = j;
1236
1373
  }
1237
1374
  else {
1238
1375
  // throw an error if the interpolant is unterminated
1239
- error("unterminated interpolant inside string constant " + chunk.to_string());
1376
+ error("unterminated interpolant inside string constant " + chunk.to_string(), pstate);
1240
1377
  }
1241
1378
  }
1242
1379
  else { // no interpolants left; add the last segment if nonempty
1243
- if (i < chunk.end) (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, chunk.end));
1380
+ // check if we need quotes here (was not sure after merge)
1381
+ if (i < chunk.end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
1244
1382
  break;
1245
1383
  }
1384
+ ++ i;
1246
1385
  }
1247
1386
  return schema;
1248
1387
  }
@@ -1253,52 +1392,16 @@ namespace Sass {
1253
1392
  Token str(lexed);
1254
1393
  --str.end;
1255
1394
  --position;
1256
- String_Constant* str_node = new (ctx.mem) String_Constant(path, source_position, str);
1257
- str_node->is_delayed(true);
1395
+ String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str);
1396
+ // str_node->is_delayed(true);
1258
1397
  return str_node;
1259
1398
  }
1260
1399
 
1261
1400
  String* Parser::parse_string()
1262
1401
  {
1263
- lex< string_constant >();
1264
- Token str(lexed);
1265
- return parse_interpolated_chunk(str);
1266
- // const char* i = str.begin;
1267
- // // see if there any interpolants
1268
- // const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(str.begin, str.end);
1269
- // if (!p) {
1270
- // String_Constant* str_node = new (ctx.mem) String_Constant(path, source_position, str);
1271
- // str_node->is_delayed(true);
1272
- // return str_node;
1273
- // }
1274
-
1275
- // String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
1276
- // schema->quote_mark(*str.begin);
1277
- // while (i < str.end) {
1278
- // p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, str.end);
1279
- // if (p) {
1280
- // if (i < p) {
1281
- // (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, p)); // accumulate the preceding segment if it's nonempty
1282
- // }
1283
- // const char* j = find_first_in_interval< exactly<rbrace> >(p, str.end); // find the closing brace
1284
- // if (j) {
1285
- // // parse the interpolant and accumulate it
1286
- // Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, path, source_position).parse_list();
1287
- // interp_node->is_interpolant(true);
1288
- // (*schema) << interp_node;
1289
- // i = j+1;
1290
- // }
1291
- // else {
1292
- // // throw an error if the interpolant is unterminated
1293
- // error("unterminated interpolant inside string constant " + str.to_string());
1294
- // }
1295
- // }
1296
- // else { // no interpolants left; add the last segment if nonempty
1297
- // if (i < str.end) (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, str.end));
1298
- // break;
1299
- // }
1300
- // }
1301
- // return schema;
1402
+ lex< quoted_string >();
1403
+ Token token(lexed);
1404
+ return parse_interpolated_chunk(token);
1302
1405
  }
1303
1406
 
1304
1407
  String* Parser::parse_ie_property()
@@ -1307,35 +1410,35 @@ namespace Sass {
1307
1410
  Token str(lexed);
1308
1411
  const char* i = str.begin;
1309
1412
  // see if there any interpolants
1310
- const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(str.begin, str.end);
1413
+ const char* p = find_first_in_interval< exactly<hash_lbrace> >(str.begin, str.end);
1311
1414
  if (!p) {
1312
- String_Constant* str_node = new (ctx.mem) String_Constant(path, source_position, str);
1415
+ String_Constant* str_node = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(str.begin, str.end)));
1313
1416
  str_node->is_delayed(true);
1314
1417
  return str_node;
1315
1418
  }
1316
1419
 
1317
- String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
1420
+ String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1318
1421
  while (i < str.end) {
1319
- p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, str.end);
1422
+ p = find_first_in_interval< exactly<hash_lbrace> >(i, str.end);
1320
1423
  if (p) {
1321
1424
  if (i < p) {
1322
- (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, p)); // accumulate the preceding segment if it's nonempty
1425
+ (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
1323
1426
  }
1324
- const char* j = find_first_in_interval< exactly<rbrace> >(p, str.end); // find the closing brace
1427
+ const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
1325
1428
  if (j) {
1326
1429
  // parse the interpolant and accumulate it
1327
- Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, path, source_position).parse_list();
1430
+ Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
1328
1431
  interp_node->is_interpolant(true);
1329
1432
  (*schema) << interp_node;
1330
- i = j+1;
1433
+ i = j;
1331
1434
  }
1332
1435
  else {
1333
1436
  // throw an error if the interpolant is unterminated
1334
- error("unterminated interpolant inside IE function " + str.to_string());
1437
+ error("unterminated interpolant inside IE function " + str.to_string(), pstate);
1335
1438
  }
1336
1439
  }
1337
1440
  else { // no interpolants left; add the last segment if nonempty
1338
- if (i < str.end) (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, str.end));
1441
+ if (i < str.end) (*schema) << new (ctx.mem) String_Constant(pstate, string(i, str.end));
1339
1442
  break;
1340
1443
  }
1341
1444
  }
@@ -1344,130 +1447,136 @@ namespace Sass {
1344
1447
 
1345
1448
  String* Parser::parse_ie_keyword_arg()
1346
1449
  {
1347
- String_Schema* kwd_arg = new (ctx.mem) String_Schema(path, source_position, 3);
1348
- if (lex< variable >()) *kwd_arg << new (ctx.mem) Variable(path, source_position, Util::normalize_underscores(lexed));
1349
- else {
1450
+ String_Schema* kwd_arg = new (ctx.mem) String_Schema(pstate, 3);
1451
+ if (lex< variable >()) {
1452
+ *kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
1453
+ } else {
1350
1454
  lex< alternatives< identifier_schema, identifier > >();
1351
- *kwd_arg << new (ctx.mem) String_Constant(path, source_position, lexed);
1455
+ *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
1352
1456
  }
1353
1457
  lex< exactly<'='> >();
1354
- *kwd_arg << new (ctx.mem) String_Constant(path, source_position, lexed);
1458
+ *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
1355
1459
  if (peek< variable >()) *kwd_arg << parse_list();
1356
- else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(path, source_position, Textual::NUMBER, Util::normalize_decimals(lexed));
1357
- else {
1358
- lex< alternatives< identifier_schema, identifier, number, hex > >();
1359
- *kwd_arg << new (ctx.mem) String_Constant(path, source_position, lexed);
1460
+ else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
1461
+ else if (lex< alternatives< identifier_schema, identifier, number, hexa, hex > >()) {
1462
+ *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
1360
1463
  }
1361
1464
  return kwd_arg;
1362
1465
  }
1363
1466
 
1364
- String_Schema* Parser::parse_value_schema()
1467
+ String_Schema* Parser::parse_value_schema(const char* stop)
1365
1468
  {
1366
- String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
1469
+ String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1367
1470
  size_t num_items = 0;
1368
- while (position < end) {
1471
+ while (position < stop) {
1369
1472
  if (lex< interpolant >()) {
1370
- Token insides(Token(lexed.begin + 2, lexed.end - 1));
1371
- Expression* interp_node = Parser::from_token(insides, ctx, path, source_position).parse_list();
1473
+ Token insides(Token(lexed.begin + 2, lexed.end - 1, before_token));
1474
+ Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
1372
1475
  interp_node->is_interpolant(true);
1373
1476
  (*schema) << interp_node;
1374
1477
  }
1375
1478
  else if (lex< exactly<'%'> >()) {
1376
- (*schema) << new (ctx.mem) String_Constant(path, source_position, lexed);
1479
+ (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
1377
1480
  }
1378
1481
  else if (lex< identifier >()) {
1379
- (*schema) << new (ctx.mem) String_Constant(path, source_position, lexed);
1482
+ (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1380
1483
  }
1381
1484
  else if (lex< percentage >()) {
1382
- (*schema) << new (ctx.mem) Textual(path, source_position, Textual::PERCENTAGE, lexed);
1485
+ (*schema) << new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed);
1383
1486
  }
1384
1487
  else if (lex< dimension >()) {
1385
- (*schema) << new (ctx.mem) Textual(path, source_position, Textual::DIMENSION, lexed);
1488
+ (*schema) << new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed);
1386
1489
  }
1387
1490
  else if (lex< number >()) {
1388
- (*schema) << new (ctx.mem) Textual(path, source_position, Textual::NUMBER, lexed);
1491
+ (*schema) << new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
1389
1492
  }
1390
1493
  else if (lex< hex >()) {
1391
- (*schema) << new (ctx.mem) Textual(path, source_position, Textual::HEX, lexed);
1494
+ (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
1392
1495
  }
1393
- else if (lex< string_constant >()) {
1394
- (*schema) << new (ctx.mem) String_Constant(path, source_position, lexed);
1395
- if (!num_items) schema->quote_mark(*lexed.begin);
1496
+ else if (lex< quoted_string >()) {
1497
+ (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
1396
1498
  }
1397
1499
  else if (lex< variable >()) {
1398
- (*schema) << new (ctx.mem) Variable(path, source_position, Util::normalize_underscores(lexed));
1500
+ (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
1399
1501
  }
1400
1502
  else {
1401
- error("error parsing interpolated value");
1503
+ error("error parsing interpolated value", pstate);
1402
1504
  }
1403
1505
  ++num_items;
1404
1506
  }
1405
1507
  return schema;
1406
1508
  }
1407
1509
 
1510
+ /* not used anymore - remove?
1408
1511
  String_Schema* Parser::parse_url_schema()
1409
1512
  {
1410
- String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
1513
+ String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1411
1514
 
1412
1515
  while (position < end) {
1413
1516
  if (position[0] == '/') {
1414
- lexed = Token(position, position+1);
1415
- (*schema) << new (ctx.mem) String_Constant(path, source_position, lexed);
1517
+ lexed = Token(position, position+1, before_token);
1518
+ (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1416
1519
  ++position;
1417
1520
  }
1418
1521
  else if (lex< interpolant >()) {
1419
- Token insides(Token(lexed.begin + 2, lexed.end - 1));
1420
- Expression* interp_node = Parser::from_token(insides, ctx, path, source_position).parse_list();
1522
+ Token insides(Token(lexed.begin + 2, lexed.end - 1, before_token));
1523
+ Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
1421
1524
  interp_node->is_interpolant(true);
1422
1525
  (*schema) << interp_node;
1423
1526
  }
1424
1527
  else if (lex< sequence< identifier, exactly<':'> > >()) {
1425
- (*schema) << new (ctx.mem) String_Constant(path, source_position, lexed);
1528
+ (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1426
1529
  }
1427
1530
  else if (lex< filename >()) {
1428
- (*schema) << new (ctx.mem) String_Constant(path, source_position, lexed);
1531
+ (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1429
1532
  }
1430
1533
  else {
1431
- error("error parsing interpolated url");
1534
+ error("error parsing interpolated url", pstate);
1432
1535
  }
1433
1536
  }
1434
1537
  return schema;
1435
- }
1538
+ } */
1436
1539
 
1540
+ // this parses interpolation outside other strings
1541
+ // means the result must not be quoted again later
1437
1542
  String* Parser::parse_identifier_schema()
1438
1543
  {
1544
+ // first lex away whatever we have found
1439
1545
  lex< sequence< optional< exactly<'*'> >, identifier_schema > >();
1440
1546
  Token id(lexed);
1441
1547
  const char* i = id.begin;
1442
1548
  // see if there any interpolants
1443
- const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(id.begin, id.end);
1549
+ const char* p = find_first_in_interval< exactly<hash_lbrace> >(id.begin, id.end);
1444
1550
  if (!p) {
1445
- return new (ctx.mem) String_Constant(path, source_position, id);
1551
+ return new (ctx.mem) String_Quoted(pstate, string(id.begin, id.end));
1446
1552
  }
1447
1553
 
1448
- String_Schema* schema = new (ctx.mem) String_Schema(path, source_position);
1554
+ String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1449
1555
  while (i < id.end) {
1450
- p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, id.end);
1556
+ p = find_first_in_interval< exactly<hash_lbrace> >(i, id.end);
1451
1557
  if (p) {
1452
1558
  if (i < p) {
1453
- (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, p)); // accumulate the preceding segment if it's nonempty
1559
+ // accumulate the preceding segment if it's nonempty
1560
+ (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p));
1454
1561
  }
1455
- const char* j = find_first_in_interval< exactly<rbrace> >(p, id.end); // find the closing brace
1562
+ // we need to skip anything inside strings
1563
+ // create a new target in parser/prelexer
1564
+ const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
1456
1565
  if (j) {
1457
1566
  // parse the interpolant and accumulate it
1458
- Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, path, source_position).parse_list();
1567
+ Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
1459
1568
  interp_node->is_interpolant(true);
1460
1569
  (*schema) << interp_node;
1461
1570
  schema->has_interpolants(true);
1462
- i = j+1;
1571
+ i = j;
1463
1572
  }
1464
1573
  else {
1465
1574
  // throw an error if the interpolant is unterminated
1466
- error("unterminated interpolant inside interpolated identifier " + id.to_string());
1575
+ error("unterminated interpolant inside interpolated identifier " + id.to_string(), pstate);
1467
1576
  }
1468
1577
  }
1469
1578
  else { // no interpolants left; add the last segment if nonempty
1470
- if (i < id.end) (*schema) << new (ctx.mem) String_Constant(path, source_position, Token(i, id.end));
1579
+ if (i < end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, id.end));
1471
1580
  break;
1472
1581
  }
1473
1582
  }
@@ -1478,95 +1587,95 @@ namespace Sass {
1478
1587
  {
1479
1588
  lex< identifier >();
1480
1589
  string name(lexed);
1481
- Position call_pos = source_position;
1590
+ ParserState call_pos = pstate;
1482
1591
  lex< exactly<'('> >();
1483
- Position arg_pos = source_position;
1592
+ ParserState arg_pos = pstate;
1484
1593
  const char* arg_beg = position;
1485
1594
  parse_list();
1486
1595
  const char* arg_end = position;
1487
1596
  lex< exactly<')'> >();
1488
1597
 
1489
- Argument* arg = new (ctx.mem) Argument(path, arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end)));
1490
- Arguments* args = new (ctx.mem) Arguments(path, arg_pos);
1598
+ Argument* arg = new (ctx.mem) Argument(arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end, before_token)));
1599
+ Arguments* args = new (ctx.mem) Arguments(arg_pos);
1491
1600
  *args << arg;
1492
- return new (ctx.mem) Function_Call(path, call_pos, name, args);
1601
+ return new (ctx.mem) Function_Call(call_pos, name, args);
1493
1602
  }
1494
1603
 
1495
1604
  Function_Call* Parser::parse_function_call()
1496
1605
  {
1497
1606
  lex< identifier >();
1498
1607
  string name(Util::normalize_underscores(lexed));
1499
- Position source_position_of_call = source_position;
1608
+ ParserState source_position_of_call = pstate;
1500
1609
 
1501
- Function_Call* the_call = new (ctx.mem) Function_Call(path, source_position_of_call, name, parse_arguments());
1610
+ Function_Call* the_call = new (ctx.mem) Function_Call(source_position_of_call, name, parse_arguments());
1502
1611
  return the_call;
1503
1612
  }
1504
1613
 
1505
1614
  Function_Call_Schema* Parser::parse_function_call_schema()
1506
1615
  {
1507
1616
  String* name = parse_identifier_schema();
1508
- Position source_position_of_call = source_position;
1617
+ ParserState source_position_of_call = pstate;
1509
1618
 
1510
- Function_Call_Schema* the_call = new (ctx.mem) Function_Call_Schema(path, source_position_of_call, name, parse_arguments());
1619
+ Function_Call_Schema* the_call = new (ctx.mem) Function_Call_Schema(source_position_of_call, name, parse_arguments());
1511
1620
  return the_call;
1512
1621
  }
1513
1622
 
1514
1623
  If* Parser::parse_if_directive(bool else_if)
1515
1624
  {
1516
1625
  lex< if_directive >() || (else_if && lex< exactly<if_after_else_kwd> >());
1517
- Position if_source_position = source_position;
1626
+ ParserState if_source_position = pstate;
1518
1627
  Expression* predicate = parse_list();
1519
1628
  predicate->is_delayed(false);
1520
- if (!peek< exactly<'{'> >()) error("expected '{' after the predicate for @if");
1629
+ if (!peek< exactly<'{'> >()) error("expected '{' after the predicate for @if", pstate);
1521
1630
  Block* consequent = parse_block();
1522
1631
  Block* alternative = 0;
1523
1632
  if (lex< else_directive >()) {
1524
1633
  if (peek< exactly<if_after_else_kwd> >()) {
1525
- alternative = new (ctx.mem) Block(path, source_position);
1634
+ alternative = new (ctx.mem) Block(pstate);
1526
1635
  (*alternative) << parse_if_directive(true);
1527
1636
  }
1528
1637
  else if (!peek< exactly<'{'> >()) {
1529
- error("expected '{' after @else");
1638
+ error("expected '{' after @else", pstate);
1530
1639
  }
1531
1640
  else {
1532
1641
  alternative = parse_block();
1533
1642
  }
1534
1643
  }
1535
- return new (ctx.mem) If(path, if_source_position, predicate, consequent, alternative);
1644
+ return new (ctx.mem) If(if_source_position, predicate, consequent, alternative);
1536
1645
  }
1537
1646
 
1538
1647
  For* Parser::parse_for_directive()
1539
1648
  {
1540
1649
  lex< for_directive >();
1541
- Position for_source_position = source_position;
1542
- if (!lex< variable >()) error("@for directive requires an iteration variable");
1650
+ ParserState for_source_position = pstate;
1651
+ if (!lex< variable >()) error("@for directive requires an iteration variable", pstate);
1543
1652
  string var(Util::normalize_underscores(lexed));
1544
- if (!lex< from >()) error("expected 'from' keyword in @for directive");
1653
+ if (!lex< from >()) error("expected 'from' keyword in @for directive", pstate);
1545
1654
  Expression* lower_bound = parse_expression();
1546
1655
  lower_bound->is_delayed(false);
1547
1656
  bool inclusive = false;
1548
1657
  if (lex< through >()) inclusive = true;
1549
1658
  else if (lex< to >()) inclusive = false;
1550
- else error("expected 'through' or 'to' keyword in @for directive");
1659
+ else error("expected 'through' or 'to' keyword in @for directive", pstate);
1551
1660
  Expression* upper_bound = parse_expression();
1552
1661
  upper_bound->is_delayed(false);
1553
- if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @for directive");
1662
+ if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @for directive", pstate);
1554
1663
  Block* body = parse_block();
1555
- return new (ctx.mem) For(path, for_source_position, var, lower_bound, upper_bound, body, inclusive);
1664
+ return new (ctx.mem) For(for_source_position, var, lower_bound, upper_bound, body, inclusive);
1556
1665
  }
1557
1666
 
1558
1667
  Each* Parser::parse_each_directive()
1559
1668
  {
1560
1669
  lex < each_directive >();
1561
- Position each_source_position = source_position;
1562
- if (!lex< variable >()) error("@each directive requires an iteration variable");
1670
+ ParserState each_source_position = pstate;
1671
+ if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
1563
1672
  vector<string> vars;
1564
1673
  vars.push_back(Util::normalize_underscores(lexed));
1565
1674
  while (peek< exactly<','> >() && lex< exactly<','> >()) {
1566
- if (!lex< variable >()) error("@each directive requires an iteration variable");
1675
+ if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
1567
1676
  vars.push_back(Util::normalize_underscores(lexed));
1568
1677
  }
1569
- if (!lex< in >()) error("expected 'in' keyword in @each directive");
1678
+ if (!lex< in >()) error("expected 'in' keyword in @each directive", pstate);
1570
1679
  Expression* list = parse_list();
1571
1680
  list->is_delayed(false);
1572
1681
  if (list->concrete_type() == Expression::LIST) {
@@ -1575,39 +1684,43 @@ namespace Sass {
1575
1684
  (*l)[i]->is_delayed(false);
1576
1685
  }
1577
1686
  }
1578
- if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @each directive");
1687
+ if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @each directive", pstate);
1579
1688
  Block* body = parse_block();
1580
- return new (ctx.mem) Each(path, each_source_position, vars, list, body);
1689
+ return new (ctx.mem) Each(each_source_position, vars, list, body);
1581
1690
  }
1582
1691
 
1583
1692
  While* Parser::parse_while_directive()
1584
1693
  {
1585
1694
  lex< while_directive >();
1586
- Position while_source_position = source_position;
1695
+ ParserState while_source_position = pstate;
1587
1696
  Expression* predicate = parse_list();
1588
1697
  predicate->is_delayed(false);
1589
1698
  Block* body = parse_block();
1590
- return new (ctx.mem) While(path, while_source_position, predicate, body);
1699
+ return new (ctx.mem) While(while_source_position, predicate, body);
1591
1700
  }
1592
1701
 
1593
1702
  Media_Block* Parser::parse_media_block()
1594
1703
  {
1595
1704
  lex< media >();
1596
- Position media_source_position = source_position;
1705
+ ParserState media_source_position = pstate;
1597
1706
 
1598
1707
  List* media_queries = parse_media_queries();
1599
1708
 
1600
1709
  if (!peek< exactly<'{'> >()) {
1601
- error("expected '{' in media query");
1710
+ error("expected '{' in media query", pstate);
1602
1711
  }
1603
- Block* block = parse_block();
1712
+ Media_Block* media_block = new (ctx.mem) Media_Block(media_source_position, media_queries, 0);
1713
+ Media_Block* prev_media_block = last_media_block;
1714
+ last_media_block = media_block;
1715
+ media_block->block(parse_block());
1716
+ last_media_block = prev_media_block;
1604
1717
 
1605
- return new (ctx.mem) Media_Block(path, media_source_position, media_queries, block);
1718
+ return media_block;
1606
1719
  }
1607
1720
 
1608
1721
  List* Parser::parse_media_queries()
1609
1722
  {
1610
- List* media_queries = new (ctx.mem) List(path, source_position, 0, List::COMMA);
1723
+ List* media_queries = new (ctx.mem) List(pstate, 0, List::COMMA);
1611
1724
  if (!peek< exactly<'{'> >()) (*media_queries) << parse_media_query();
1612
1725
  while (lex< exactly<','> >()) (*media_queries) << parse_media_query();
1613
1726
  return media_queries;
@@ -1616,17 +1729,24 @@ namespace Sass {
1616
1729
  // Expression* Parser::parse_media_query()
1617
1730
  Media_Query* Parser::parse_media_query()
1618
1731
  {
1619
- Media_Query* media_query = new (ctx.mem) Media_Query(path, source_position);
1732
+ Media_Query* media_query = new (ctx.mem) Media_Query(pstate);
1620
1733
 
1621
1734
  if (lex< exactly< not_kwd > >()) media_query->is_negated(true);
1622
1735
  else if (lex< exactly< only_kwd > >()) media_query->is_restricted(true);
1623
1736
 
1624
1737
  if (peek< identifier_schema >()) media_query->media_type(parse_identifier_schema());
1625
- else if (lex< identifier >()) media_query->media_type(new (ctx.mem) String_Constant(path, source_position, lexed));
1738
+ else if (lex< identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
1626
1739
  else (*media_query) << parse_media_expression();
1627
1740
 
1628
1741
  while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
1629
-
1742
+ if (peek< identifier_schema >()) {
1743
+ String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1744
+ *schema << media_query->media_type();
1745
+ *schema << new (ctx.mem) String_Constant(pstate, " ");
1746
+ *schema << parse_identifier_schema();
1747
+ media_query->media_type(schema);
1748
+ }
1749
+ while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
1630
1750
  return media_query;
1631
1751
  }
1632
1752
 
@@ -1634,14 +1754,14 @@ namespace Sass {
1634
1754
  {
1635
1755
  if (peek< identifier_schema >()) {
1636
1756
  String* ss = parse_identifier_schema();
1637
- return new (ctx.mem) Media_Query_Expression(path, source_position, ss, 0, true);
1757
+ return new (ctx.mem) Media_Query_Expression(pstate, ss, 0, true);
1638
1758
  }
1639
1759
  if (!lex< exactly<'('> >()) {
1640
- error("media query expression must begin with '('");
1760
+ error("media query expression must begin with '('", pstate);
1641
1761
  }
1642
1762
  Expression* feature = 0;
1643
1763
  if (peek< exactly<')'> >()) {
1644
- error("media feature required in media query expression");
1764
+ error("media feature required in media query expression", pstate);
1645
1765
  }
1646
1766
  feature = parse_expression();
1647
1767
  Expression* expression = 0;
@@ -1649,36 +1769,36 @@ namespace Sass {
1649
1769
  expression = parse_list();
1650
1770
  }
1651
1771
  if (!lex< exactly<')'> >()) {
1652
- error("unclosed parenthesis in media query expression");
1772
+ error("unclosed parenthesis in media query expression", pstate);
1653
1773
  }
1654
- return new (ctx.mem) Media_Query_Expression(path, feature->position(), feature, expression);
1774
+ return new (ctx.mem) Media_Query_Expression(feature->pstate(), feature, expression);
1655
1775
  }
1656
1776
 
1657
1777
  Feature_Block* Parser::parse_feature_block()
1658
1778
  {
1659
1779
  lex< supports >();
1660
- Position supports_source_position = source_position;
1780
+ ParserState supports_source_position = pstate;
1661
1781
 
1662
1782
  Feature_Query* feature_queries = parse_feature_queries();
1663
1783
 
1664
1784
  if (!peek< exactly<'{'> >()) {
1665
- error("expected '{' in feature query");
1785
+ error("expected '{' in feature query", pstate);
1666
1786
  }
1667
1787
  Block* block = parse_block();
1668
1788
 
1669
- return new (ctx.mem) Feature_Block(path, supports_source_position, feature_queries, block);
1789
+ return new (ctx.mem) Feature_Block(supports_source_position, feature_queries, block);
1670
1790
  }
1671
1791
 
1672
1792
  Feature_Query* Parser::parse_feature_queries()
1673
1793
  {
1674
- Feature_Query* fq = new (ctx.mem) Feature_Query(path, source_position);
1675
- Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(path, source_position);
1794
+ Feature_Query* fq = new (ctx.mem) Feature_Query(pstate);
1795
+ Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(pstate);
1676
1796
  cond->is_root(true);
1677
1797
  while (!peek< exactly<')'> >(position) && !peek< exactly<'{'> >(position))
1678
1798
  (*cond) << parse_feature_query();
1679
1799
  (*fq) << cond;
1680
1800
 
1681
- if (fq->empty()) error("expected @supports condition (e.g. (display: flexbox))");
1801
+ if (fq->empty()) error("expected @supports condition (e.g. (display: flexbox))", pstate);
1682
1802
 
1683
1803
  return fq;
1684
1804
  }
@@ -1694,12 +1814,12 @@ namespace Sass {
1694
1814
 
1695
1815
  Feature_Query_Condition* Parser::parse_feature_query_in_parens()
1696
1816
  {
1697
- Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(path, source_position);
1817
+ Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(pstate);
1698
1818
 
1699
- if (!lex< exactly<'('> >()) error("@supports declaration expected '('");
1819
+ if (!lex< exactly<'('> >()) error("@supports declaration expected '('", pstate);
1700
1820
  while (!peek< exactly<')'> >(position) && !peek< exactly<'{'> >(position))
1701
1821
  (*cond) << parse_feature_query();
1702
- if (!lex< exactly<')'> >()) error("unclosed parenthesis in @supports declaration");
1822
+ if (!lex< exactly<')'> >()) error("unclosed parenthesis in @supports declaration", pstate);
1703
1823
 
1704
1824
  return (cond->length() == 1) ? (*cond)[0] : cond;
1705
1825
  }
@@ -1737,19 +1857,71 @@ namespace Sass {
1737
1857
  Feature_Query_Condition* Parser::parse_supports_declaration()
1738
1858
  {
1739
1859
  Declaration* declaration = parse_declaration();
1740
- Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(declaration->path(),
1741
- declaration->position(),
1860
+ Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(declaration->pstate(),
1742
1861
  1,
1743
1862
  declaration->property(),
1744
1863
  declaration->value());
1745
1864
  return cond;
1746
1865
  }
1747
1866
 
1867
+ At_Root_Block* Parser::parse_at_root_block()
1868
+ {
1869
+ lex<at_root>();
1870
+ ParserState at_source_position = pstate;
1871
+ Block* body = 0;
1872
+ At_Root_Expression* expr = 0;
1873
+ Selector_Lookahead lookahead_result;
1874
+ in_at_root = true;
1875
+ if (peek< exactly<'('> >()) {
1876
+ expr = parse_at_root_expression();
1877
+ body = parse_block();
1878
+ }
1879
+ else if (peek< exactly<'{'> >()) {
1880
+ body = parse_block();
1881
+ }
1882
+ else if ((lookahead_result = lookahead_for_selector(position)).found) {
1883
+ Ruleset* r = parse_ruleset(lookahead_result);
1884
+ body = new (ctx.mem) Block(r->pstate(), 1);
1885
+ *body << r;
1886
+ }
1887
+ in_at_root = false;
1888
+ At_Root_Block* at_root = new (ctx.mem) At_Root_Block(at_source_position, body);
1889
+ if (expr) at_root->expression(expr);
1890
+ return at_root;
1891
+ }
1892
+
1893
+ At_Root_Expression* Parser::parse_at_root_expression()
1894
+ {
1895
+ lex< exactly<'('> >();
1896
+ if (peek< exactly<')'> >()) error("at-root feature required in at-root expression", pstate);
1897
+
1898
+ if (!peek< alternatives< with_directive, without_directive > >()) {
1899
+ const char* i = position;
1900
+ const char* p = peek< until<')'> >(i);
1901
+ Token* t = new Token(i, p, Position(0, 0));
1902
+ error("Invalid CSS after \"(\": expected \"with\" or \"without\", was \""+t->to_string()+"\"", pstate);
1903
+ }
1904
+
1905
+ Declaration* declaration = parse_declaration();
1906
+ List* value = new (ctx.mem) List(declaration->value()->pstate(), 1);
1907
+
1908
+ if (declaration->value()->concrete_type() == Expression::LIST) {
1909
+ value = static_cast<List*>(declaration->value());
1910
+ }
1911
+ else *value << declaration->value();
1912
+
1913
+ At_Root_Expression* cond = new (ctx.mem) At_Root_Expression(declaration->pstate(),
1914
+ declaration->property(),
1915
+ value);
1916
+ if (!lex< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
1917
+ return cond;
1918
+ }
1919
+
1748
1920
  At_Rule* Parser::parse_at_rule()
1749
1921
  {
1750
1922
  lex<at_keyword>();
1751
1923
  string kwd(lexed);
1752
- Position at_source_position = source_position;
1924
+ ParserState at_source_position = pstate;
1753
1925
  Selector* sel = 0;
1754
1926
  Expression* val = 0;
1755
1927
  Selector_Lookahead lookahead = lookahead_for_extension_target(position);
@@ -1766,7 +1938,7 @@ namespace Sass {
1766
1938
  }
1767
1939
  Block* body = 0;
1768
1940
  if (peek< exactly<'{'> >()) body = parse_block();
1769
- At_Rule* rule = new (ctx.mem) At_Rule(path, at_source_position, kwd, sel, body);
1941
+ At_Rule* rule = new (ctx.mem) At_Rule(at_source_position, kwd, sel, body);
1770
1942
  if (!sel) rule->value(val);
1771
1943
  return rule;
1772
1944
  }
@@ -1774,19 +1946,19 @@ namespace Sass {
1774
1946
  Warning* Parser::parse_warning()
1775
1947
  {
1776
1948
  lex< warn >();
1777
- return new (ctx.mem) Warning(path, source_position, parse_list());
1949
+ return new (ctx.mem) Warning(pstate, parse_list());
1778
1950
  }
1779
1951
 
1780
1952
  Error* Parser::parse_error()
1781
1953
  {
1782
1954
  lex< err >();
1783
- return new (ctx.mem) Error(path, source_position, parse_list());
1955
+ return new (ctx.mem) Error(pstate, parse_list());
1784
1956
  }
1785
1957
 
1786
1958
  Debug* Parser::parse_debug()
1787
1959
  {
1788
1960
  lex< dbg >();
1789
- return new (ctx.mem) Debug(path, source_position, parse_list());
1961
+ return new (ctx.mem) Debug(pstate, parse_list());
1790
1962
  }
1791
1963
 
1792
1964
  Selector_Lookahead Parser::lookahead_for_selector(const char* start)
@@ -1805,7 +1977,7 @@ namespace Sass {
1805
1977
  (q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
1806
1978
  (q = peek< percentage >(p)) ||
1807
1979
  (q = peek< dimension >(p)) ||
1808
- (q = peek< string_constant >(p)) ||
1980
+ (q = peek< quoted_string >(p)) ||
1809
1981
  (q = peek< exactly<'*'> >(p)) ||
1810
1982
  (q = peek< exactly<'('> >(p)) ||
1811
1983
  (q = peek< exactly<')'> >(p)) ||
@@ -1815,6 +1987,7 @@ namespace Sass {
1815
1987
  (q = peek< exactly<'~'> >(p)) ||
1816
1988
  (q = peek< exactly<'>'> >(p)) ||
1817
1989
  (q = peek< exactly<','> >(p)) ||
1990
+ (saw_stuff && (q = peek< exactly<'-'> >(p))) ||
1818
1991
  (q = peek< binomial >(p)) ||
1819
1992
  (q = peek< sequence< optional<sign>,
1820
1993
  optional<digits>,
@@ -1863,7 +2036,7 @@ namespace Sass {
1863
2036
  (q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
1864
2037
  (q = peek< percentage >(p)) ||
1865
2038
  (q = peek< dimension >(p)) ||
1866
- (q = peek< string_constant >(p)) ||
2039
+ (q = peek< quoted_string >(p)) ||
1867
2040
  (q = peek< exactly<'*'> >(p)) ||
1868
2041
  (q = peek< exactly<'('> >(p)) ||
1869
2042
  (q = peek< exactly<')'> >(p)) ||
@@ -1873,6 +2046,7 @@ namespace Sass {
1873
2046
  (q = peek< exactly<'~'> >(p)) ||
1874
2047
  (q = peek< exactly<'>'> >(p)) ||
1875
2048
  (q = peek< exactly<','> >(p)) ||
2049
+ (saw_stuff && (q = peek< exactly<'-'> >(p))) ||
1876
2050
  (q = peek< binomial >(p)) ||
1877
2051
  (q = peek< sequence< optional<sign>,
1878
2052
  optional<digits>,
@@ -1961,7 +2135,7 @@ namespace Sass {
1961
2135
  encoding = "GB-18030";
1962
2136
  break;
1963
2137
  }
1964
- if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding);
2138
+ if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding, pstate);
1965
2139
  position += skip;
1966
2140
  }
1967
2141
 
@@ -1979,7 +2153,7 @@ namespace Sass {
1979
2153
  Expression* Parser::fold_operands(Expression* base, vector<Expression*>& operands, Binary_Expression::Type op)
1980
2154
  {
1981
2155
  for (size_t i = 0, S = operands.size(); i < S; ++i) {
1982
- base = new (ctx.mem) Binary_Expression(path, source_position, op, base, operands[i]);
2156
+ base = new (ctx.mem) Binary_Expression(pstate, op, base, operands[i]);
1983
2157
  Binary_Expression* b = static_cast<Binary_Expression*>(base);
1984
2158
  if (op == Binary_Expression::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
1985
2159
  base->is_delayed(true);
@@ -1995,7 +2169,7 @@ namespace Sass {
1995
2169
  Expression* Parser::fold_operands(Expression* base, vector<Expression*>& operands, vector<Binary_Expression::Type>& ops)
1996
2170
  {
1997
2171
  for (size_t i = 0, S = operands.size(); i < S; ++i) {
1998
- base = new (ctx.mem) Binary_Expression(path, base->position(), ops[i], base, operands[i]);
2172
+ base = new (ctx.mem) Binary_Expression(base->pstate(), ops[i], base, operands[i]);
1999
2173
  Binary_Expression* b = static_cast<Binary_Expression*>(base);
2000
2174
  if (ops[i] == Binary_Expression::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
2001
2175
  base->is_delayed(true);
@@ -2010,7 +2184,7 @@ namespace Sass {
2010
2184
 
2011
2185
  void Parser::error(string msg, Position pos)
2012
2186
  {
2013
- throw Sass_Error(Sass_Error::syntax, path, pos.line ? pos : source_position, msg);
2187
+ throw Sass_Error(Sass_Error::syntax, ParserState(path, pos.line ? pos : before_token, Offset(0, 0)), msg);
2014
2188
  }
2015
2189
 
2016
2190
  }