sassc 1.8.1 → 1.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/ext/libsass/Makefile +10 -6
  4. data/ext/libsass/Readme.md +4 -4
  5. data/ext/libsass/appveyor.yml +16 -1
  6. data/ext/libsass/docs/README.md +1 -1
  7. data/ext/libsass/docs/api-context-example.md +1 -1
  8. data/ext/libsass/docs/api-context.md +1 -1
  9. data/ext/libsass/docs/api-doc.md +1 -1
  10. data/ext/libsass/docs/api-function-example.md +12 -3
  11. data/ext/libsass/docs/api-function-internal.md +4 -4
  12. data/ext/libsass/docs/api-function.md +15 -13
  13. data/ext/libsass/docs/api-importer-internal.md +9 -4
  14. data/ext/libsass/docs/api-value.md +1 -1
  15. data/ext/libsass/docs/build-shared-library.md +3 -3
  16. data/ext/libsass/docs/custom-functions-internal.md +1 -1
  17. data/ext/libsass/docs/{plugins.go → plugins.md} +0 -0
  18. data/ext/libsass/script/ci-build-libsass +25 -36
  19. data/ext/libsass/script/ci-install-deps +3 -8
  20. data/ext/libsass/script/ci-report-coverage +17 -13
  21. data/ext/libsass/src/ast.cpp +102 -7
  22. data/ext/libsass/src/ast.hpp +53 -27
  23. data/ext/libsass/src/ast_def_macros.hpp +8 -0
  24. data/ext/libsass/src/ast_fwd_decl.hpp +3 -2
  25. data/ext/libsass/src/backtrace.hpp +1 -1
  26. data/ext/libsass/src/bind.cpp +28 -17
  27. data/ext/libsass/src/bind.hpp +1 -1
  28. data/ext/libsass/src/context.cpp +441 -184
  29. data/ext/libsass/src/context.hpp +79 -82
  30. data/ext/libsass/src/debugger.hpp +3 -1
  31. data/ext/libsass/src/emitter.cpp +18 -17
  32. data/ext/libsass/src/emitter.hpp +5 -2
  33. data/ext/libsass/src/error_handling.cpp +78 -7
  34. data/ext/libsass/src/error_handling.hpp +50 -9
  35. data/ext/libsass/src/eval.cpp +100 -36
  36. data/ext/libsass/src/eval.hpp +5 -5
  37. data/ext/libsass/src/expand.cpp +32 -3
  38. data/ext/libsass/src/extend.cpp +1 -1
  39. data/ext/libsass/src/file.cpp +39 -27
  40. data/ext/libsass/src/file.hpp +67 -13
  41. data/ext/libsass/src/functions.cpp +39 -32
  42. data/ext/libsass/src/inspect.cpp +21 -21
  43. data/ext/libsass/src/json.cpp +1 -1
  44. data/ext/libsass/src/lexer.hpp +33 -4
  45. data/ext/libsass/src/output.cpp +11 -11
  46. data/ext/libsass/src/parser.cpp +28 -130
  47. data/ext/libsass/src/parser.hpp +0 -4
  48. data/ext/libsass/src/prelexer.cpp +8 -5
  49. data/ext/libsass/src/prelexer.hpp +1 -3
  50. data/ext/libsass/src/sass_context.cpp +52 -241
  51. data/ext/libsass/src/sass_context.hpp +156 -0
  52. data/ext/libsass/src/sass_functions.cpp +1 -26
  53. data/ext/libsass/src/sass_functions.hpp +32 -0
  54. data/ext/libsass/src/sass_interface.cpp +14 -48
  55. data/ext/libsass/src/sass_values.cpp +3 -77
  56. data/ext/libsass/src/sass_values.hpp +81 -0
  57. data/ext/libsass/src/source_map.cpp +7 -7
  58. data/ext/libsass/src/source_map.hpp +1 -4
  59. data/ext/libsass/src/to_string.cpp +4 -3
  60. data/ext/libsass/src/to_string.hpp +2 -1
  61. data/ext/libsass/src/util.cpp +34 -16
  62. data/ext/libsass/src/util.hpp +10 -8
  63. data/lib/sassc/version.rb +1 -1
  64. data/lib/tasks/libsass.rb +1 -1
  65. data/test/custom_importer_test.rb +6 -4
  66. data/test/engine_test.rb +5 -3
  67. data/test/functions_test.rb +1 -0
  68. data/test/native_test.rb +1 -1
  69. metadata +6 -4
  70. data/ext/libsass/script/coveralls-debug +0 -32
@@ -802,7 +802,7 @@ failure:
802
802
  bool parse_string(const char **sp, char **out)
803
803
  {
804
804
  const char *s = *sp;
805
- SB sb = { 0, 0, 0};
805
+ SB sb = { 0, 0, 0 };
806
806
  char throwaway_buffer[4];
807
807
  /* enough space for a UTF-8 character */
808
808
  char *b;
@@ -84,14 +84,14 @@ namespace Sass {
84
84
  //####################################
85
85
 
86
86
  // Match a single character literal.
87
- // Regex equivalent: /(?:literal)/
87
+ // Regex equivalent: /(?:x)/
88
88
  template <char chr>
89
89
  const char* exactly(const char* src) {
90
90
  return *src == chr ? src + 1 : 0;
91
91
  }
92
92
 
93
- // Match a string constant.
94
- // Regex equivalent: /[axy]/
93
+ // Match the full string literal.
94
+ // Regex equivalent: /(?:literal)/
95
95
  template <const char* str>
96
96
  const char* exactly(const char* src) {
97
97
  if (str == 0) return 0;
@@ -102,7 +102,26 @@ namespace Sass {
102
102
  while (*pre && *src == *pre) {
103
103
  ++src, ++pre;
104
104
  }
105
- return *pre ? 0 : src;
105
+ // did the matcher finish?
106
+ return *pre == 0 ? src : 0;
107
+ }
108
+
109
+
110
+ // Match the full string literal.
111
+ // Regex equivalent: /(?:literal)/i
112
+ // only define lower case alpha chars
113
+ template <const char* str>
114
+ const char* insensitive(const char* src) {
115
+ if (str == 0) return 0;
116
+ const char* pre = str;
117
+ if (src == 0) return 0;
118
+ // there is a small chance that the search string
119
+ // is longer than the rest of the string to look at
120
+ while (*pre && (*src == *pre || *src+32 == *pre)) {
121
+ ++src, ++pre;
122
+ }
123
+ // did the matcher finish?
124
+ return *pre == 0 ? src : 0;
106
125
  }
107
126
 
108
127
  // Match for members of char class.
@@ -225,6 +244,16 @@ namespace Sass {
225
244
  // ADVANCED "REGEX" CONSTRUCTORS
226
245
  //####################################
227
246
 
247
+ // Match with word boundary rule.
248
+ // Regex equivalent: /(?:$mx)\b/i
249
+ template <const char* str>
250
+ const char* keyword(const char* src) {
251
+ return sequence <
252
+ insensitive < str >,
253
+ word_boundary
254
+ >(src);
255
+ }
256
+
228
257
  // Match with word boundary rule.
229
258
  // Regex equivalent: /(?:$mx)\b/
230
259
  template <const char* str>
@@ -74,7 +74,7 @@ namespace Sass {
74
74
  // skip all ascii chars
75
75
  if (chr >= 0) continue;
76
76
  // declare the charset
77
- if (output_style() != COMPRESSED)
77
+ if (output_style() != SASS_STYLE_COMPRESSED)
78
78
  charset = "@charset \"UTF-8\";"
79
79
  + ctx->linefeed;
80
80
  else charset = "\xEF\xBB\xBF";
@@ -95,7 +95,7 @@ namespace Sass {
95
95
  std::string txt = c->text()->perform(&to_string);
96
96
  // if (indentation && txt == "/**/") return;
97
97
  bool important = c->is_important();
98
- if (output_style() != COMPRESSED || important) {
98
+ if (output_style() != SASS_STYLE_COMPRESSED || important) {
99
99
  if (buffer().size() == 0) {
100
100
  top_nodes.push_back(c);
101
101
  } else {
@@ -131,11 +131,11 @@ namespace Sass {
131
131
 
132
132
  if (b->has_non_hoistable()) {
133
133
  decls = true;
134
- if (output_style() == NESTED) indentation += r->tabs();
135
- if (ctx && ctx->source_comments) {
134
+ if (output_style() == SASS_STYLE_NESTED) indentation += r->tabs();
135
+ if (ctx && ctx->c_options->source_comments) {
136
136
  std::stringstream ss;
137
137
  append_indentation();
138
- ss << "/* line " << r->pstate().line+1 << ", " << r->pstate().path << " */";
138
+ ss << "/* line " << r->pstate().line + 1 << ", " << r->pstate().path << " */";
139
139
  append_string(ss.str());
140
140
  append_optional_linefeed();
141
141
  }
@@ -171,7 +171,7 @@ namespace Sass {
171
171
  stm->perform(this);
172
172
  }
173
173
  }
174
- if (output_style() == NESTED) indentation -= r->tabs();
174
+ if (output_style() == SASS_STYLE_NESTED) indentation -= r->tabs();
175
175
  append_scope_closer(b);
176
176
  }
177
177
 
@@ -238,7 +238,7 @@ namespace Sass {
238
238
  return;
239
239
  }
240
240
 
241
- if (output_style() == NESTED) indentation += f->tabs();
241
+ if (output_style() == SASS_STYLE_NESTED) indentation += f->tabs();
242
242
  append_indentation();
243
243
  append_token("@supports", f);
244
244
  append_mandatory_space();
@@ -274,7 +274,7 @@ namespace Sass {
274
274
  }
275
275
  }
276
276
 
277
- if (output_style() == NESTED) indentation -= f->tabs();
277
+ if (output_style() == SASS_STYLE_NESTED) indentation -= f->tabs();
278
278
 
279
279
  append_scope_closer();
280
280
 
@@ -297,7 +297,7 @@ namespace Sass {
297
297
  }
298
298
  return;
299
299
  }
300
- if (output_style() == NESTED) indentation += m->tabs();
300
+ if (output_style() == SASS_STYLE_NESTED) indentation += m->tabs();
301
301
  append_indentation();
302
302
  append_token("@media", m);
303
303
  append_mandatory_space();
@@ -311,7 +311,7 @@ namespace Sass {
311
311
  if (i < L - 1) append_special_linefeed();
312
312
  }
313
313
 
314
- if (output_style() == NESTED) indentation -= m->tabs();
314
+ if (output_style() == SASS_STYLE_NESTED) indentation -= m->tabs();
315
315
  append_scope_closer();
316
316
  }
317
317
 
@@ -380,7 +380,7 @@ namespace Sass {
380
380
  void Output::operator()(String_Constant* s)
381
381
  {
382
382
  std::string value(s->value());
383
- if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
383
+ if (s->can_compress_whitespace() && output_style() == SASS_STYLE_COMPRESSED) {
384
384
  value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
385
385
  }
386
386
  if (!in_comment) {
@@ -76,18 +76,10 @@ namespace Sass {
76
76
  Block* root = SASS_MEMORY_NEW(ctx.mem, Block, pstate, 0, true);
77
77
  read_bom();
78
78
 
79
- if (ctx.queue.size() == 1) {
80
- is_root = true;
81
- Import* pre = SASS_MEMORY_NEW(ctx.mem, Import, pstate);
82
- std::string load_path(ctx.queue[0].load_path);
83
- do_import(load_path, pre, ctx.c_headers, false);
84
- ctx.head_imports = ctx.queue.size() - 1;
85
- if (!pre->urls().empty()) (*root) << pre;
86
- if (!pre->files().empty()) {
87
- for (size_t i = 0, S = pre->files().size(); i < S; ++i) {
88
- (*root) << SASS_MEMORY_NEW(ctx.mem, Import_Stub, pstate, pre->files()[i]);
89
- }
90
- }
79
+ // custom headers
80
+ if (ctx.resources.size() == 1) {
81
+ is_root = true;
82
+ ctx.apply_custom_headers(root, path, pstate);
91
83
  }
92
84
 
93
85
  block_stack.push_back(root);
@@ -113,6 +105,7 @@ namespace Sass {
113
105
 
114
106
  // parse comments before block
115
107
  // lex < optional_css_comments >();
108
+
116
109
  // lex mandatory opener or error out
117
110
  if (!lex_css < exactly<'{'> >()) {
118
111
  css_error("Invalid CSS", " after ", ": expected \"{\", was ");
@@ -130,7 +123,7 @@ namespace Sass {
130
123
  // update for end position
131
124
  block->update_pstate(pstate);
132
125
 
133
- // parse comments before block
126
+ // parse comments after block
134
127
  // lex < optional_css_comments >();
135
128
 
136
129
  block_stack.pop_back();
@@ -222,11 +215,9 @@ namespace Sass {
222
215
  Import* imp = parse_import();
223
216
  // if it is a url, we only add the statement
224
217
  if (!imp->urls().empty()) (*block) << imp;
225
- // if it is a file(s), we should process them
226
- if (!imp->files().empty()) {
227
- for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
228
- (*block) << SASS_MEMORY_NEW(ctx.mem, Import_Stub, pstate, imp->files()[i]);
229
- }
218
+ // process all resources now (add Import_Stub nodes)
219
+ for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
220
+ (*block) << SASS_MEMORY_NEW(ctx.mem, Import_Stub, pstate, imp->incs()[i]);
230
221
  }
231
222
  }
232
223
 
@@ -288,105 +279,7 @@ namespace Sass {
288
279
  }
289
280
  // EO parse_block_nodes
290
281
 
291
- void Parser::add_single_file (Import* imp, std::string import_path) {
292
-
293
- std::string extension;
294
- std::string unquoted(unquote(import_path));
295
- if (unquoted.length() > 4) { // 2 quote marks + the 4 chars in .css
296
- // a string constant is guaranteed to end with a quote mark, so make sure to skip it when indexing from the end
297
- extension = unquoted.substr(unquoted.length() - 4, 4);
298
- }
299
-
300
- if (extension == ".css") {
301
- String_Constant* loc = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, unquote(import_path));
302
- Argument* loc_arg = SASS_MEMORY_NEW(ctx.mem, Argument, pstate, loc);
303
- Arguments* loc_args = SASS_MEMORY_NEW(ctx.mem, Arguments, pstate);
304
- (*loc_args) << loc_arg;
305
- Function_Call* new_url = SASS_MEMORY_NEW(ctx.mem, Function_Call, pstate, "url", loc_args);
306
- imp->urls().push_back(new_url);
307
- }
308
- else {
309
- std::string current_dir = File::dir_name(path);
310
- std::string resolved(ctx.add_file(current_dir, unquoted, *this));
311
- if (resolved.empty()) error("file to import not found or unreadable: " + unquoted + "\nCurrent dir: " + current_dir, pstate);
312
- imp->files().push_back(resolved);
313
- }
314
-
315
- }
316
-
317
- void Parser::import_single_file (Import* imp, std::string import_path) {
318
-
319
- if (imp->media_queries() ||
320
- !unquote(import_path).substr(0, 7).compare("http://") ||
321
- !unquote(import_path).substr(0, 8).compare("https://") ||
322
- !unquote(import_path).substr(0, 2).compare("//"))
323
- {
324
- imp->urls().push_back(SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, import_path));
325
- }
326
- else {
327
- add_single_file(imp, import_path);
328
- }
329
-
330
- }
331
-
332
- bool Parser::do_import(const std::string& import_path, Import* imp, std::vector<Sass_Importer_Entry> importers, bool only_one)
333
- {
334
- size_t i = 0;
335
- bool has_import = false;
336
- std::string load_path = unquote(import_path);
337
- // std::cerr << "-- " << load_path << "\n";
338
- for (Sass_Importer_Entry& importer : importers) {
339
- // int priority = sass_importer_get_priority(importer);
340
- Sass_Importer_Fn fn = sass_importer_get_function(importer);
341
- if (Sass_Import_List includes =
342
- fn(load_path.c_str(), importer, ctx.c_compiler)
343
- ) {
344
- Sass_Import_List list = includes;
345
- while (*includes) { ++i;
346
- std::string uniq_path = load_path;
347
- if (!only_one && i) {
348
- std::stringstream pathstrm;
349
- pathstrm << uniq_path << ":" << i;
350
- uniq_path = pathstrm.str();
351
- }
352
- Sass_Import_Entry include = *includes;
353
- const char *abs_path = sass_import_get_abs_path(include);
354
- char* source = sass_import_take_source(include);
355
- size_t line = sass_import_get_error_line(include);
356
- size_t column = sass_import_get_error_column(include);
357
- const char* message = sass_import_get_error_message(include);
358
- if (message) {
359
- if (line == std::string::npos && column == std::string::npos) error(message, pstate);
360
- else error(message, ParserState(message, source, Position(line, column)));
361
- } else if (source) {
362
- if (abs_path) {
363
- ctx.add_source(uniq_path, abs_path, source);
364
- imp->files().push_back(uniq_path);
365
- size_t i = ctx.queue.size() - 1;
366
- ctx.process_queue_entry(ctx.queue[i], i);
367
- } else {
368
- ctx.add_source(uniq_path, uniq_path, source);
369
- imp->files().push_back(uniq_path);
370
- size_t i = ctx.queue.size() - 1;
371
- ctx.process_queue_entry(ctx.queue[i], i);
372
- }
373
- } else if(abs_path) {
374
- import_single_file(imp, abs_path);
375
- }
376
- ++includes;
377
- }
378
- // deallocate returned memory
379
- sass_delete_import_list(list);
380
- // set success flag
381
- has_import = true;
382
- // break import chain
383
- if (only_one) return true;
384
- }
385
- }
386
- // return result
387
- return has_import;
388
- }
389
-
282
+ // parse imports inside the
390
283
  Import* Parser::parse_import()
391
284
  {
392
285
  Import* imp = SASS_MEMORY_NEW(ctx.mem, Import, pstate);
@@ -395,7 +288,7 @@ namespace Sass {
395
288
  do {
396
289
  while (lex< block_comment >());
397
290
  if (lex< quoted_string >()) {
398
- if (!do_import(lexed, imp, ctx.c_importers, true))
291
+ if (!ctx.call_importers(unquote(std::string(lexed)), path, pstate, imp))
399
292
  {
400
293
  // push single file import
401
294
  // import_single_file(imp, lexed);
@@ -421,8 +314,7 @@ namespace Sass {
421
314
  error("malformed URL", pstate);
422
315
  }
423
316
  if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
424
- // imp->urls().push_back(result);
425
- to_import.push_back(std::pair<std::string,Function_Call*>("", result));
317
+ to_import.push_back(std::pair<std::string, Function_Call*>("", result));
426
318
  }
427
319
  else {
428
320
  if (first) error("@import directive requires a url or quoted path", pstate);
@@ -440,7 +332,7 @@ namespace Sass {
440
332
  if (location.second) {
441
333
  imp->urls().push_back(location.second);
442
334
  } else {
443
- import_single_file(imp, location.first);
335
+ ctx.import_url(imp, location.first, path);
444
336
  }
445
337
  }
446
338
 
@@ -1849,11 +1741,13 @@ namespace Sass {
1849
1741
  Block* block = parse_block();
1850
1742
  Block* alternative = 0;
1851
1743
 
1852
- if (lex< elseif_directive >()) {
1744
+ // only throw away comment if we parse a case
1745
+ // we want all other comments to be parsed
1746
+ if (lex_css< elseif_directive >()) {
1853
1747
  alternative = SASS_MEMORY_NEW(ctx.mem, Block, pstate);
1854
1748
  (*alternative) << parse_if_directive(true);
1855
1749
  }
1856
- else if (lex< kwd_else_directive >()) {
1750
+ else if (lex_css< kwd_else_directive >()) {
1857
1751
  alternative = parse_block();
1858
1752
  }
1859
1753
  return SASS_MEMORY_NEW(ctx.mem, If, if_source_position, predicate, block, alternative);
@@ -1969,15 +1863,15 @@ namespace Sass {
1969
1863
  Media_Query* media_query = SASS_MEMORY_NEW(ctx.mem, Media_Query, pstate);
1970
1864
 
1971
1865
  lex < css_comments >(false);
1972
- if (lex < word < not_kwd > >()) media_query->is_negated(true);
1973
- else if (lex < word < only_kwd > >()) media_query->is_restricted(true);
1866
+ if (lex < kwd_not >()) media_query->is_negated(true);
1867
+ else if (lex < kwd_only >()) media_query->is_restricted(true);
1974
1868
 
1975
1869
  lex < css_comments >(false);
1976
1870
  if (lex < identifier_schema >()) media_query->media_type(parse_identifier_schema());
1977
1871
  else if (lex < identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
1978
1872
  else (*media_query) << parse_media_expression();
1979
1873
 
1980
- while (lex_css < word < and_kwd > >()) (*media_query) << parse_media_expression();
1874
+ while (lex_css < kwd_and >()) (*media_query) << parse_media_expression();
1981
1875
  if (lex < identifier_schema >()) {
1982
1876
  String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
1983
1877
  *schema << media_query->media_type();
@@ -1985,7 +1879,7 @@ namespace Sass {
1985
1879
  *schema << parse_identifier_schema();
1986
1880
  media_query->media_type(schema);
1987
1881
  }
1988
- while (lex_css < word < and_kwd > >()) (*media_query) << parse_media_expression();
1882
+ while (lex_css < kwd_and >()) (*media_query) << parse_media_expression();
1989
1883
  return media_query;
1990
1884
  }
1991
1885
 
@@ -2051,9 +1945,10 @@ namespace Sass {
2051
1945
  Supports_Condition* cond = parse_supports_condition_in_parens();
2052
1946
  if (!cond) return 0;
2053
1947
 
2054
- while (lex < kwd_and >() || lex < kwd_or >()) {
1948
+ while (true) {
2055
1949
  Supports_Operator::Operand op = Supports_Operator::OR;
2056
- if (lexed.to_string() == "and") op = Supports_Operator::AND;
1950
+ if (lex < kwd_and >()) { op = Supports_Operator::AND; }
1951
+ else if(!lex < kwd_or >()) { break; }
2057
1952
 
2058
1953
  lex < css_whitespace >();
2059
1954
  Supports_Condition* right = parse_supports_condition_in_parens();
@@ -2159,6 +2054,9 @@ namespace Sass {
2159
2054
  At_Rule* Parser::parse_at_rule()
2160
2055
  {
2161
2056
  std::string kwd(lexed);
2057
+
2058
+ if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
2059
+
2162
2060
  At_Rule* at_rule = SASS_MEMORY_NEW(ctx.mem, At_Rule, pstate, kwd);
2163
2061
  Lookahead lookahead = lookahead_for_include(position);
2164
2062
  if (lookahead.found && !lookahead.has_interpolants) {
@@ -2482,7 +2380,7 @@ namespace Sass {
2482
2380
 
2483
2381
  void Parser::error(std::string msg, Position pos)
2484
2382
  {
2485
- throw Error_Invalid(Error_Invalid::syntax, ParserState(path, source, pos.line ? pos : before_token, Offset(0, 0)), msg);
2383
+ throw Exception::InvalidSass(ParserState(path, source, pos.line ? pos : before_token, Offset(0, 0)), msg);
2486
2384
  }
2487
2385
 
2488
2386
  // print a css parsing error with actual context information from parsed source
@@ -21,13 +21,9 @@ struct Lookahead {
21
21
  namespace Sass {
22
22
 
23
23
  class Parser : public ParserState {
24
- private:
25
- void add_single_file (Import* imp, std::string import_path);
26
- void import_single_file (Import* imp, std::string import_path);
27
24
  public:
28
25
 
29
26
  enum Syntactic_Context { nothing, mixin_def, function_def };
30
- bool do_import(const std::string& import_path, Import* imp, std::vector<Sass_Importer_Entry> importers, bool only_one = true);
31
27
 
32
28
  Context& ctx;
33
29
  std::vector<Block*> block_stack;
@@ -398,7 +398,7 @@ namespace Sass {
398
398
  }
399
399
  const char* elseif_directive(const char* src) {
400
400
  return sequence< exactly< else_kwd >,
401
- optional_css_whitespace,
401
+ optional_css_comments,
402
402
  word< if_after_else_kwd > >(src);
403
403
  }
404
404
 
@@ -759,14 +759,17 @@ namespace Sass {
759
759
  const char* kwd_false(const char* src) {
760
760
  return word<false_kwd>(src);
761
761
  }
762
+ const char* kwd_only(const char* src) {
763
+ return keyword < only_kwd >(src);
764
+ }
762
765
  const char* kwd_and(const char* src) {
763
- return word<and_kwd>(src);
766
+ return keyword < and_kwd >(src);
764
767
  }
765
768
  const char* kwd_or(const char* src) {
766
- return word<or_kwd>(src);
769
+ return keyword < or_kwd >(src);
767
770
  }
768
771
  const char* kwd_not(const char* src) {
769
- return word<not_kwd>(src);
772
+ return keyword < not_kwd >(src);
770
773
  }
771
774
  const char* kwd_eq(const char* src) {
772
775
  return exactly<eq>(src);
@@ -1016,7 +1019,7 @@ namespace Sass {
1016
1019
  hex,
1017
1020
  exactly<'|'>,
1018
1021
  // exactly<'+'>,
1019
- sequence < number, identifier >,
1022
+ sequence < number, unit_identifier >,
1020
1023
  number,
1021
1024
  sequence< exactly<'!'>, word<important_kwd> >
1022
1025
  >(src);