sassc 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
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
  }