sassc 1.9.0 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -3
  3. data/ext/libsass/.gitignore +3 -0
  4. data/ext/libsass/.travis.yml +1 -1
  5. data/ext/libsass/GNUmakefile.am +7 -7
  6. data/ext/libsass/Makefile +7 -4
  7. data/ext/libsass/Makefile.conf +0 -1
  8. data/ext/libsass/appveyor.yml +6 -2
  9. data/ext/libsass/docs/api-context.md +4 -4
  10. data/ext/libsass/docs/api-doc.md +29 -11
  11. data/ext/libsass/docs/api-importer-example.md +5 -5
  12. data/ext/libsass/docs/build-on-windows.md +1 -1
  13. data/ext/libsass/include/sass/base.h +10 -0
  14. data/ext/libsass/include/sass/version.h +4 -0
  15. data/ext/libsass/include/sass/version.h.in +4 -0
  16. data/ext/libsass/include/sass2scss.h +1 -1
  17. data/ext/libsass/script/ci-build-libsass +15 -3
  18. data/ext/libsass/src/ast.cpp +161 -6
  19. data/ext/libsass/src/ast.hpp +71 -44
  20. data/ext/libsass/src/ast_factory.hpp +1 -1
  21. data/ext/libsass/src/ast_fwd_decl.hpp +2 -2
  22. data/ext/libsass/src/constants.cpp +2 -4
  23. data/ext/libsass/src/constants.hpp +3 -4
  24. data/ext/libsass/src/context.cpp +16 -17
  25. data/ext/libsass/src/context.hpp +2 -2
  26. data/ext/libsass/src/cssize.cpp +19 -8
  27. data/ext/libsass/src/cssize.hpp +5 -2
  28. data/ext/libsass/src/debugger.hpp +6 -3
  29. data/ext/libsass/src/emitter.cpp +1 -1
  30. data/ext/libsass/src/environment.cpp +1 -1
  31. data/ext/libsass/src/eval.cpp +42 -14
  32. data/ext/libsass/src/eval.hpp +1 -1
  33. data/ext/libsass/src/expand.cpp +24 -8
  34. data/ext/libsass/src/expand.hpp +2 -1
  35. data/ext/libsass/src/extend.cpp +55 -15
  36. data/ext/libsass/src/extend.hpp +5 -1
  37. data/ext/libsass/src/functions.cpp +10 -5
  38. data/ext/libsass/src/inspect.cpp +25 -19
  39. data/ext/libsass/src/inspect.hpp +2 -2
  40. data/ext/libsass/src/json.cpp +20 -9
  41. data/ext/libsass/src/json.hpp +5 -5
  42. data/ext/libsass/src/lexer.cpp +4 -1
  43. data/ext/libsass/src/lexer.hpp +21 -0
  44. data/ext/libsass/src/listize.cpp +2 -1
  45. data/ext/libsass/src/operation.hpp +4 -4
  46. data/ext/libsass/src/output.cpp +1 -1
  47. data/ext/libsass/src/output.hpp +1 -1
  48. data/ext/libsass/src/parser.cpp +189 -90
  49. data/ext/libsass/src/parser.hpp +42 -2
  50. data/ext/libsass/src/prelexer.cpp +474 -7
  51. data/ext/libsass/src/prelexer.hpp +15 -2
  52. data/ext/libsass/src/remove_placeholders.cpp +5 -5
  53. data/ext/libsass/src/remove_placeholders.hpp +3 -2
  54. data/ext/libsass/src/sass.cpp +33 -3
  55. data/ext/libsass/src/sass2scss.cpp +7 -0
  56. data/ext/libsass/src/sass_context.cpp +32 -62
  57. data/ext/libsass/src/sass_functions.cpp +3 -3
  58. data/ext/libsass/src/sass_values.cpp +5 -5
  59. data/ext/libsass/src/utf8/unchecked.h +16 -16
  60. data/ext/libsass/src/util.cpp +51 -30
  61. data/ext/libsass/src/util.hpp +6 -1
  62. data/ext/libsass/win/libsass.targets +0 -2
  63. data/ext/libsass/win/libsass.vcxproj.filters +0 -6
  64. data/lib/sassc/engine.rb +4 -1
  65. data/lib/sassc/error.rb +23 -1
  66. data/lib/sassc/version.rb +1 -1
  67. data/test/error_test.rb +27 -0
  68. data/test/native_test.rb +1 -1
  69. metadata +5 -5
  70. data/ext/libsass/include/sass/interface.h +0 -105
  71. data/ext/libsass/src/sass_interface.cpp +0 -215
@@ -133,6 +133,8 @@ namespace Sass {
133
133
  const char* lex(bool lazy = true, bool force = false)
134
134
  {
135
135
 
136
+ if (*position == 0) return 0;
137
+
136
138
  // position considered before lexed token
137
139
  // we can skip whitespace or comments for
138
140
  // lazy developers (but we need control)
@@ -298,12 +300,22 @@ namespace Sass {
298
300
  Supports_Condition* parse_supports_declaration();
299
301
  Supports_Condition* parse_supports_condition_in_parens();
300
302
  At_Root_Block* parse_at_root_block();
301
- At_Root_Expression* parse_at_root_expression();
302
- At_Rule* parse_at_rule();
303
+ At_Root_Query* parse_at_root_query();
304
+ String_Schema* parse_almost_any_value();
305
+ Directive* parse_special_directive();
306
+ Directive* parse_prefixed_directive();
307
+ Directive* parse_directive();
303
308
  Warning* parse_warning();
304
309
  Error* parse_error();
305
310
  Debug* parse_debug();
306
311
 
312
+ // be more like ruby sass
313
+ Expression* lex_almost_any_value_token();
314
+ Expression* lex_almost_any_value_chars();
315
+ Expression* lex_interp_string();
316
+ Expression* lex_interp_uri();
317
+ Expression* lex_interpolation();
318
+
307
319
  // these will throw errors
308
320
  Token lex_variable();
309
321
  Token lex_identifier();
@@ -319,6 +331,34 @@ namespace Sass {
319
331
 
320
332
  void throw_syntax_error(std::string message, size_t ln = 0);
321
333
  void throw_read_error(std::string message, size_t ln = 0);
334
+
335
+
336
+ template <Prelexer::prelexer open, Prelexer::prelexer close>
337
+ Expression* lex_interp()
338
+ {
339
+ if (lex < open >(false)) {
340
+ String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
341
+ // std::cerr << "LEX [[" << std::string(lexed) << "]]\n";
342
+ *schema << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
343
+ if (position[0] == '#' && position[1] == '{') {
344
+ Expression* itpl = lex_interpolation();
345
+ if (itpl) *schema << itpl;
346
+ while (lex < close >(false)) {
347
+ // std::cerr << "LEX [[" << std::string(lexed) << "]]\n";
348
+ *schema << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
349
+ if (position[0] == '#' && position[1] == '{') {
350
+ Expression* itpl = lex_interpolation();
351
+ if (itpl) *schema << itpl;
352
+ } else {
353
+ return schema;
354
+ }
355
+ }
356
+ } else {
357
+ return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
358
+ }
359
+ }
360
+ return 0;
361
+ }
322
362
  };
323
363
 
324
364
  size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len);
@@ -16,6 +16,248 @@ namespace Sass {
16
16
  namespace Prelexer {
17
17
 
18
18
 
19
+ /*
20
+
21
+ def string_re(open, close)
22
+ /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
23
+ end
24
+ end
25
+
26
+ # A hash of regular expressions that are used for tokenizing strings.
27
+ #
28
+ # The key is a `[Symbol, Boolean]` pair.
29
+ # The symbol represents which style of quotation to use,
30
+ # while the boolean represents whether or not the string
31
+ # is following an interpolated segment.
32
+ STRING_REGULAR_EXPRESSIONS = {
33
+ :double => {
34
+ /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
35
+ false => string_re('"', '"'),
36
+ true => string_re('', '"')
37
+ },
38
+ :single => {
39
+ false => string_re("'", "'"),
40
+ true => string_re('', "'")
41
+ },
42
+ :uri => {
43
+ false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
44
+ true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
45
+ },
46
+ # Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
47
+ # non-standard version of http://www.w3.org/TR/css3-conditional/
48
+ :url_prefix => {
49
+ false => /url-prefix\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
50
+ true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
51
+ },
52
+ :domain => {
53
+ false => /domain\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
54
+ true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
55
+ }
56
+ }
57
+ */
58
+
59
+ /*
60
+ /#{open}
61
+ (
62
+ \\.
63
+ |
64
+ \# (?!\{)
65
+ |
66
+ [^#{close}\\#]
67
+ )*
68
+ (#{close}|#\{)
69
+ /m
70
+ false => string_re('"', '"'),
71
+ true => string_re('', '"')
72
+ */
73
+ extern const char string_double_negates[] = "\"\\#";
74
+ const char* re_string_double_close(const char* src)
75
+ {
76
+ return sequence <
77
+ // valid chars
78
+ zero_plus <
79
+ alternatives <
80
+ // escaped char
81
+ sequence <
82
+ exactly <'\\'>,
83
+ any_char
84
+ >,
85
+ // non interpolate hash
86
+ sequence <
87
+ exactly <'#'>,
88
+ negate <
89
+ exactly <'{'>
90
+ >
91
+ >,
92
+ // other valid chars
93
+ neg_class_char <
94
+ string_double_negates
95
+ >
96
+ >
97
+ >,
98
+ // quoted string closer
99
+ // or interpolate opening
100
+ alternatives <
101
+ exactly <'"'>,
102
+ lookahead < exactly< hash_lbrace > >
103
+ >
104
+ >(src);
105
+ }
106
+
107
+ const char* re_string_double_open(const char* src)
108
+ {
109
+ return sequence <
110
+ // quoted string opener
111
+ exactly <'"'>,
112
+ // valid chars
113
+ zero_plus <
114
+ alternatives <
115
+ // escaped char
116
+ sequence <
117
+ exactly <'\\'>,
118
+ any_char
119
+ >,
120
+ // non interpolate hash
121
+ sequence <
122
+ exactly <'#'>,
123
+ negate <
124
+ exactly <'{'>
125
+ >
126
+ >,
127
+ // other valid chars
128
+ neg_class_char <
129
+ string_double_negates
130
+ >
131
+ >
132
+ >,
133
+ // quoted string closer
134
+ // or interpolate opening
135
+ alternatives <
136
+ exactly <'"'>,
137
+ lookahead < exactly< hash_lbrace > >
138
+ >
139
+ >(src);
140
+ }
141
+
142
+ extern const char string_single_negates[] = "'\\#";
143
+ const char* re_string_single_close(const char* src)
144
+ {
145
+ return sequence <
146
+ // valid chars
147
+ zero_plus <
148
+ alternatives <
149
+ // escaped char
150
+ sequence <
151
+ exactly <'\\'>,
152
+ any_char
153
+ >,
154
+ // non interpolate hash
155
+ sequence <
156
+ exactly <'#'>,
157
+ negate <
158
+ exactly <'{'>
159
+ >
160
+ >,
161
+ // other valid chars
162
+ neg_class_char <
163
+ string_single_negates
164
+ >
165
+ >
166
+ >,
167
+ // quoted string closer
168
+ // or interpolate opening
169
+ alternatives <
170
+ exactly <'\''>,
171
+ lookahead < exactly< hash_lbrace > >
172
+ >
173
+ >(src);
174
+ }
175
+
176
+ const char* re_string_single_open(const char* src)
177
+ {
178
+ return sequence <
179
+ // quoted string opener
180
+ exactly <'\''>,
181
+ // valid chars
182
+ zero_plus <
183
+ alternatives <
184
+ // escaped char
185
+ sequence <
186
+ exactly <'\\'>,
187
+ any_char
188
+ >,
189
+ // non interpolate hash
190
+ sequence <
191
+ exactly <'#'>,
192
+ negate <
193
+ exactly <'{'>
194
+ >
195
+ >,
196
+ // other valid chars
197
+ neg_class_char <
198
+ string_single_negates
199
+ >
200
+ >
201
+ >,
202
+ // quoted string closer
203
+ // or interpolate opening
204
+ alternatives <
205
+ exactly <'\''>,
206
+ lookahead < exactly< hash_lbrace > >
207
+ >
208
+ >(src);
209
+ }
210
+
211
+ /*
212
+ :uri => {
213
+ false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
214
+ true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
215
+ },
216
+ */
217
+ const char* re_string_uri_close(const char* src)
218
+ {
219
+ return sequence <
220
+ non_greedy<
221
+ alternatives<
222
+ class_char< real_uri_chars >,
223
+ uri_character,
224
+ NONASCII,
225
+ ESCAPE
226
+ >,
227
+ alternatives<
228
+ sequence < optional < W >, exactly <')'> >,
229
+ lookahead < exactly< hash_lbrace > >
230
+ >
231
+ >,
232
+ optional <
233
+ sequence < optional < W >, exactly <')'> >
234
+ >
235
+ >(src);
236
+ }
237
+
238
+ const char* re_string_uri_open(const char* src)
239
+ {
240
+ return sequence <
241
+ exactly <'u'>,
242
+ exactly <'r'>,
243
+ exactly <'l'>,
244
+ exactly <'('>,
245
+ W,
246
+ non_greedy<
247
+ alternatives<
248
+ class_char< real_uri_chars >,
249
+ uri_character,
250
+ NONASCII,
251
+ ESCAPE
252
+ >,
253
+ alternatives<
254
+ sequence < W, exactly <')'> >,
255
+ exactly< hash_lbrace >
256
+ >
257
+ >
258
+ >(src);
259
+ }
260
+
19
261
  // Match a line comment (/.*?(?=\n|\r\n?|\Z)/.
20
262
  const char* line_comment(const char* src)
21
263
  {
@@ -370,6 +612,133 @@ namespace Sass {
370
612
  return sequence<exactly<'@'>, identifier>(src);
371
613
  }
372
614
 
615
+ /*
616
+ tok(%r{
617
+ (
618
+ \\.
619
+ |
620
+ (?!url\()
621
+ [^"'/\#!;\{\}] # "
622
+ |
623
+ /(?![\*\/])
624
+ |
625
+ \#(?!\{)
626
+ |
627
+ !(?![a-z]) # TODO: never consume "!" when issue 1126 is fixed.
628
+ )+
629
+ }xi) || tok(COMMENT) || tok(SINGLE_LINE_COMMENT) || interp_string || interp_uri ||
630
+ interpolation(:warn_for_color)
631
+ */
632
+ const char* re_almost_any_value_token(const char* src) {
633
+
634
+ return alternatives <
635
+ one_plus <
636
+ alternatives <
637
+ sequence <
638
+ exactly <'\\'>,
639
+ any_char
640
+ >,
641
+ sequence <
642
+ negate <
643
+ sequence <
644
+ exactly < url_kwd >,
645
+ exactly <'('>
646
+ >
647
+ >,
648
+ neg_class_char <
649
+ almost_any_value_class
650
+ >
651
+ >,
652
+ sequence <
653
+ exactly <'/'>,
654
+ negate <
655
+ alternatives <
656
+ exactly <'/'>,
657
+ exactly <'*'>
658
+ >
659
+ >
660
+ >,
661
+ sequence <
662
+ exactly <'\\'>,
663
+ exactly <'#'>,
664
+ negate <
665
+ exactly <'{'>
666
+ >
667
+ >,
668
+ sequence <
669
+ exactly <'!'>,
670
+ negate <
671
+ alpha
672
+ >
673
+ >
674
+ >
675
+ >,
676
+ block_comment,
677
+ line_comment,
678
+ interpolant,
679
+ space,
680
+ sequence <
681
+ exactly<'u'>,
682
+ exactly<'r'>,
683
+ exactly<'l'>,
684
+ exactly<'('>,
685
+ zero_plus <
686
+ alternatives <
687
+ class_char< real_uri_chars >,
688
+ uri_character,
689
+ NONASCII,
690
+ ESCAPE
691
+ >
692
+ >,
693
+ // false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
694
+ // true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
695
+ exactly<')'>
696
+ >
697
+ >(src);
698
+ }
699
+
700
+ /*
701
+ DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
702
+ :each, :while, :if, :else, :extend, :import, :media, :charset, :content,
703
+ :_moz_document, :at_root, :error]
704
+ */
705
+ const char* re_special_directive(const char* src) {
706
+ return alternatives <
707
+ word < mixin_kwd >,
708
+ word < include_kwd >,
709
+ word < function_kwd >,
710
+ word < return_kwd >,
711
+ word < debug_kwd >,
712
+ word < warn_kwd >,
713
+ word < for_kwd >,
714
+ word < each_kwd >,
715
+ word < while_kwd >,
716
+ word < if_kwd >,
717
+ word < else_kwd >,
718
+ word < extend_kwd >,
719
+ word < import_kwd >,
720
+ word < media_kwd >,
721
+ word < charset_kwd >,
722
+ word < content_kwd >,
723
+ // exactly < moz_document_kwd >,
724
+ word < at_root_kwd >,
725
+ word < error_kwd >
726
+ >(src);
727
+ }
728
+
729
+ const char* re_prefixed_directive(const char* src) {
730
+ return sequence <
731
+ optional <
732
+ sequence <
733
+ exactly <'-'>,
734
+ one_plus < alnum >,
735
+ exactly <'-'>
736
+ >
737
+ >,
738
+ exactly < supports_kwd >
739
+ >(src);
740
+ }
741
+
373
742
  const char* re_reference_combinator(const char* src) {
374
743
  return sequence <
375
744
  optional <
@@ -508,7 +877,7 @@ namespace Sass {
508
877
  return one_plus< alternatives< alnum,
509
878
  exactly<'-'>,
510
879
  exactly<'_'>,
511
- exactly<'\\'> > >(src);
880
+ escape_seq > >(src);
512
881
  }
513
882
 
514
883
  const char* kwd_warn(const char* src) {
@@ -586,7 +955,7 @@ namespace Sass {
586
955
  }
587
956
 
588
957
  const char* hyphens_and_identifier(const char* src) {
589
- return sequence< zero_plus< exactly< '-' > >, identifier >(src);
958
+ return sequence< zero_plus< exactly< '-' > >, identifier_alnums >(src);
590
959
  }
591
960
  const char* hyphens_and_name(const char* src) {
592
961
  return sequence< zero_plus< exactly< '-' > >, name >(src);
@@ -596,11 +965,11 @@ namespace Sass {
596
965
  }
597
966
  // Match CSS id names.
598
967
  const char* id_name(const char* src) {
599
- return sequence<exactly<'#'>, name>(src);
968
+ return sequence<exactly<'#'>, identifier_alnums >(src);
600
969
  }
601
970
  // Match CSS class names.
602
971
  const char* class_name(const char* src) {
603
- return sequence<exactly<'.'>, identifier>(src);
972
+ return sequence<exactly<'.'>, identifier >(src);
604
973
  }
605
974
  // Attribute name in an attribute selector.
606
975
  const char* attribute_name(const char* src) {
@@ -609,7 +978,7 @@ namespace Sass {
609
978
  }
610
979
  // match placeholder selectors
611
980
  const char* placeholder(const char* src) {
612
- return sequence<exactly<'%'>, identifier>(src);
981
+ return sequence<exactly<'%'>, identifier_alnums >(src);
613
982
  }
614
983
  // Match CSS numeric constants.
615
984
 
@@ -825,6 +1194,22 @@ namespace Sass {
825
1194
  return sequence<exactly<'$'>, identifier>(src);
826
1195
  }
827
1196
 
1197
+ // parse `calc`, `-a-calc` and `--b-c-calc`
1198
+ // but do not parse `foocalc` or `foo-calc`
1199
+ const char* calc_fn_call(const char* src) {
1200
+ return sequence <
1201
+ optional < sequence <
1202
+ hyphens,
1203
+ one_plus < sequence <
1204
+ strict_identifier,
1205
+ hyphens
1206
+ > >
1207
+ > >,
1208
+ exactly < calc_fn_kwd >,
1209
+ word_boundary
1210
+ >(src);
1211
+ }
1212
+
828
1213
  // Match Sass boolean keywords.
829
1214
  const char* kwd_true(const char* src) {
830
1215
  return word<true_kwd>(src);
@@ -1167,6 +1552,83 @@ namespace Sass {
1167
1552
  >(src);
1168
1553
  }
1169
1554
 
1555
+ const char* re_selector_list(const char* src) {
1556
+ return alternatives <
1557
+ // partial bem selector
1558
+ sequence <
1559
+ ampersand,
1560
+ one_plus <
1561
+ exactly < '-' >
1562
+ >,
1563
+ word_boundary,
1564
+ optional_spaces
1565
+ >,
1566
+ // main selector matching
1567
+ one_plus <
1568
+ alternatives <
1569
+ // consume whitespace and comments
1570
+ spaces, block_comment, line_comment,
1571
+ // match `/deep/` selector (pass-trough)
1572
+ // there is no functionality for it yet
1573
+ schema_reference_combinator,
1574
+ // match selector ops /[*&%,\[\]]/
1575
+ class_char < selector_lookahead_ops >,
1576
+ // match selector combinators /[>+~]/
1577
+ class_char < selector_combinator_ops >,
1578
+ // match attribute compare operators
1579
+ sequence <
1580
+ exactly <'('>,
1581
+ optional_spaces,
1582
+ optional <re_selector_list>,
1583
+ optional_spaces,
1584
+ exactly <')'>
1585
+ >,
1586
+ alternatives <
1587
+ exact_match, class_match, dash_match,
1588
+ prefix_match, suffix_match, substring_match
1589
+ >,
1590
+ // main selector match
1591
+ sequence <
1592
+ // allow namespace prefix
1593
+ optional < namespace_schema >,
1594
+ // modifiers prefixes
1595
+ alternatives <
1596
+ sequence <
1597
+ exactly <'#'>,
1598
+ // not for interpolation
1599
+ negate < exactly <'{'> >
1600
+ >,
1601
+ // class match
1602
+ exactly <'.'>,
1603
+ // single or double colon
1604
+ optional < pseudo_prefix >
1605
+ >,
1606
+ // accept hypens in token
1607
+ one_plus < sequence <
1608
+ // can start with hyphens
1609
+ zero_plus < exactly<'-'> >,
1610
+ // now the main token
1611
+ alternatives <
1612
+ kwd_optional,
1613
+ exactly <'*'>,
1614
+ quoted_string,
1615
+ interpolant,
1616
+ identifier,
1617
+ variable,
1618
+ percentage,
1619
+ binomial,
1620
+ dimension,
1621
+ alnum
1622
+ >
1623
+ > >,
1624
+ // can also end with hyphens
1625
+ zero_plus < exactly<'-'> >
1626
+ >
1627
+ >
1628
+ >
1629
+ >(src);
1630
+ }
1631
+
1170
1632
  const char* type_selector(const char* src) {
1171
1633
  return sequence< optional<namespace_schema>, identifier>(src);
1172
1634
  }
@@ -1183,6 +1645,12 @@ namespace Sass {
1183
1645
  // lexer special_fn: these functions cannot be overloaded
1184
1646
  // (/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
1185
1647
  const char* re_special_fun(const char* src) {
1648
+
1649
+ // match this first as we test prefix hyphens
1650
+ if (const char* calc = calc_fn_call(src)) {
1651
+ return calc;
1652
+ }
1653
+
1186
1654
  return sequence <
1187
1655
  optional <
1188
1656
  sequence <
@@ -1197,8 +1665,7 @@ namespace Sass {
1197
1665
  >
1198
1666
  >,
1199
1667
  alternatives <
1200
- exactly < calc_fn_kwd >,
1201
- exactly < expression_kwd >,
1668
+ word < expression_kwd >,
1202
1669
  sequence <
1203
1670
  sequence <
1204
1671
  exactly < progid_kwd >,