sassc 1.8.1 → 1.8.2

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