@@ -22,6 +22,9 @@ namespace Sass {
22
22
else if (peek< mixin >() || peek< exactly<' =' > >()) {
23
23
root << parse_mixin_definition ();
24
24
}
25
+ else if (peek< function >()) {
26
+ root << parse_function_definition ();
27
+ }
25
28
else if (peek< variable >()) {
26
29
root << parse_assignment ();
27
30
if (!lex< exactly<' ;' > >()) throw_syntax_error (" top-level variable binding must be terminated by ';'" );
@@ -37,16 +40,16 @@ namespace Sass {
37
40
if (!lex< exactly<' ;' > >()) throw_syntax_error (" top-level @include directive must be terminated by ';'" );
38
41
}
39
42
else if (peek< if_directive >()) {
40
- root << parse_if_directive (Node ());
43
+ root << parse_if_directive (Node (), Node::none );
41
44
}
42
45
else if (peek< for_directive >()) {
43
- root << parse_for_directive (Node ());
46
+ root << parse_for_directive (Node (), Node::none );
44
47
}
45
48
else if (peek< each_directive >()) {
46
- root << parse_each_directive (Node ());
49
+ root << parse_each_directive (Node (), Node::none );
47
50
}
48
51
else if (peek< while_directive >()) {
49
- root << parse_while_directive (Node ());
52
+ root << parse_while_directive (Node (), Node::none );
50
53
}
51
54
else {
52
55
lex< spaces_and_comments >();
@@ -103,15 +106,30 @@ namespace Sass {
103
106
lex< mixin >() || lex< exactly<' =' > >();
104
107
if (!lex< identifier >()) throw_syntax_error (" invalid name in @mixin directive" );
105
108
Node name (context.new_Node (Node::identifier, path, line, lexed));
106
- Node params (parse_mixin_parameters ());
109
+ Node params (parse_parameters ());
107
110
if (!peek< exactly<' {' > >()) throw_syntax_error (" body for mixin " + name.token ().to_string () + " must begin with a '{'" );
108
- Node body (parse_block (Node (), true ));
111
+ Node body (parse_block (Node (), Node::mixin ));
109
112
Node the_mixin (context.new_Node (Node::mixin, path, line, 3 ));
110
113
the_mixin << name << params << body;
111
114
return the_mixin;
112
115
}
113
116
114
- Node Document::parse_mixin_parameters ()
117
+ Node Document::parse_function_definition ()
118
+ {
119
+
120
+ lex< function >();
121
+ size_t func_line = line;
122
+ if (!lex< identifier >()) throw_syntax_error (" name required for function definition" );
123
+ Node name (context.new_Node (Node::identifier, path, line, lexed));
124
+ Node params (parse_parameters ());
125
+ if (!peek< exactly<' {' > >()) throw_syntax_error (" body for function " + name.to_string () + " must begin with a '{'" );
126
+ Node body (parse_block (Node (), Node::function));
127
+ Node func (context.new_Node (Node::function, path, func_line, 3 ));
128
+ func << name << params << body;
129
+ return func;
130
+ }
131
+
132
+ Node Document::parse_parameters ()
115
133
{
116
134
Node params (context.new_Node (Node::parameters, path, line, 0 ));
117
135
Token name (lexed);
@@ -226,7 +244,7 @@ namespace Sass {
226
244
return propset;
227
245
}
228
246
229
- Node Document::parse_ruleset (Selector_Lookahead lookahead, bool in_definition )
247
+ Node Document::parse_ruleset (Selector_Lookahead lookahead, Node::Type inside_of )
230
248
{
231
249
Node ruleset (context.new_Node (Node::ruleset, path, line, 2 ));
232
250
if (lookahead.has_interpolants ) {
@@ -236,7 +254,7 @@ namespace Sass {
236
254
ruleset << parse_selector_group ();
237
255
}
238
256
if (!peek< exactly<' {' > >()) throw_syntax_error (" expected a '{' after the selector" );
239
- ruleset << parse_block (ruleset, in_definition );
257
+ ruleset << parse_block (ruleset, inside_of );
240
258
return ruleset;
241
259
}
242
260
@@ -436,7 +454,7 @@ namespace Sass {
436
454
return attr_sel;
437
455
}
438
456
439
- Node Document::parse_block (Node surrounding_ruleset, bool in_definition )
457
+ Node Document::parse_block (Node surrounding_ruleset, Node::Type inside_of )
440
458
{
441
459
lex< exactly<' {' > >();
442
460
bool semicolon = false ;
@@ -455,9 +473,9 @@ namespace Sass {
455
473
block << context.new_Node (Node::comment, path, line, lexed);
456
474
}
457
475
else if (peek< import >(position)) {
458
- if (in_definition ) {
476
+ if (inside_of == Node::mixin || inside_of == Node::function ) {
459
477
lex< import >(); // to adjust the line number
460
- throw_syntax_error (" @import directive not allowed inside mixin definition " );
478
+ throw_syntax_error (" @import directive not allowed inside definition of mixin or function " );
461
479
}
462
480
Node imported_tree (parse_import ());
463
481
if (imported_tree.type () == Node::css_import) {
@@ -470,19 +488,34 @@ namespace Sass {
470
488
semicolon = true ;
471
489
}
472
490
}
473
- else if (peek< include >(position)) {
474
- block << parse_mixin_call ();
475
- semicolon = true ;
476
- }
477
491
else if (lex< variable >()) {
478
492
block << parse_assignment ();
479
493
semicolon = true ;
480
494
}
495
+ else if (peek< if_directive >()) {
496
+ block << parse_if_directive (surrounding_ruleset, inside_of);
497
+ }
498
+ else if (peek< for_directive >()) {
499
+ block << parse_for_directive (surrounding_ruleset, inside_of);
500
+ }
501
+ else if (peek< each_directive >()) {
502
+ block << parse_each_directive (surrounding_ruleset, inside_of);
503
+ }
504
+ else if (peek < while_directive >()) {
505
+ block << parse_while_directive (surrounding_ruleset, inside_of);
506
+ }
507
+ else if (inside_of == Node::function) {
508
+ throw_syntax_error (" only variable declarations and control directives are allowed inside functions" );
509
+ }
510
+ else if (peek< include >(position)) {
511
+ block << parse_mixin_call ();
512
+ semicolon = true ;
513
+ }
481
514
else if (peek< sequence< identifier, optional_spaces, exactly<' :' >, optional_spaces, exactly<' {' > > >(position)) {
482
515
block << parse_propset ();
483
516
}
484
517
else if ((lookahead_result = lookahead_for_selector (position)).found ) {
485
- block << parse_ruleset (lookahead_result, in_definition );
518
+ block << parse_ruleset (lookahead_result, inside_of );
486
519
}
487
520
else if (peek< exactly<' +' > >()) {
488
521
block << parse_mixin_call ();
@@ -492,22 +525,9 @@ namespace Sass {
492
525
if (surrounding_ruleset.is_null_ptr ()) throw_syntax_error (" @extend directive may only be used within rules" );
493
526
Node extendee (parse_simple_selector_sequence ());
494
527
context.extensions .insert (pair<Node, Node>(extendee, surrounding_ruleset));
495
- cerr << " PARSED EXTENSION REQUEST: " << surrounding_ruleset[0 ].to_string () << " EXTENDS " << extendee.to_string () << endl;
496
528
context.has_extensions = true ;
497
529
semicolon = true ;
498
530
}
499
- else if (peek< if_directive >()) {
500
- block << parse_if_directive (surrounding_ruleset);
501
- }
502
- else if (peek< for_directive >()) {
503
- block << parse_for_directive (surrounding_ruleset);
504
- }
505
- else if (peek< each_directive >()) {
506
- block << parse_each_directive (surrounding_ruleset);
507
- }
508
- else if (peek < while_directive >()) {
509
- block << parse_while_directive (surrounding_ruleset);
510
- }
511
531
else if (!peek< exactly<' ;' > >()) {
512
532
Node rule (parse_rule ());
513
533
// check for lbrace; if it's there, we have a namespace property with a value
@@ -896,28 +916,28 @@ namespace Sass {
896
916
return call;
897
917
}
898
918
899
- Node Document::parse_if_directive (Node surrounding_ruleset)
919
+ Node Document::parse_if_directive (Node surrounding_ruleset, Node::Type inside_of )
900
920
{
901
921
lex< if_directive >();
902
922
Node conditional (context.new_Node (Node::if_directive, path, line, 2 ));
903
923
conditional << parse_list (); // the predicate
904
924
if (!lex< exactly<' {' > >()) throw_syntax_error (" expected '{' after the predicate for @if" );
905
- conditional << parse_block (surrounding_ruleset); // the consequent
925
+ conditional << parse_block (surrounding_ruleset, inside_of ); // the consequent
906
926
// collect all "@else if"s
907
927
while (lex< elseif_directive >()) {
908
928
conditional << parse_list (); // the next predicate
909
929
if (!lex< exactly<' {' > >()) throw_syntax_error (" expected '{' after the predicate for @else if" );
910
- conditional << parse_block (surrounding_ruleset); // the next consequent
930
+ conditional << parse_block (surrounding_ruleset, inside_of ); // the next consequent
911
931
}
912
932
// parse the "@else" if present
913
933
if (lex< else_directive >()) {
914
934
if (!lex< exactly<' {' > >()) throw_syntax_error (" expected '{' after @else" );
915
- conditional << parse_block (surrounding_ruleset); // the alternative
935
+ conditional << parse_block (surrounding_ruleset, inside_of ); // the alternative
916
936
}
917
937
return conditional;
918
938
}
919
939
920
- Node Document::parse_for_directive (Node surrounding_ruleset)
940
+ Node Document::parse_for_directive (Node surrounding_ruleset, Node::Type inside_of )
921
941
{
922
942
lex< for_directive >();
923
943
size_t for_line = line;
@@ -931,13 +951,13 @@ namespace Sass {
931
951
else throw_syntax_error (" expected 'through' or 'to' keywod in @for directive" );
932
952
Node upper_bound (parse_expression ());
933
953
if (!peek< exactly<' {' > >()) throw_syntax_error (" expected '{' after the upper bound in @for directive" );
934
- Node body (parse_block (surrounding_ruleset));
954
+ Node body (parse_block (surrounding_ruleset, inside_of ));
935
955
Node loop (context.new_Node (for_type, path, for_line, 4 ));
936
956
loop << var << lower_bound << upper_bound << body;
937
957
return loop;
938
958
}
939
959
940
- Node Document::parse_each_directive (Node surrounding_ruleset)
960
+ Node Document::parse_each_directive (Node surrounding_ruleset, Node::Type inside_of )
941
961
{
942
962
lex < each_directive >();
943
963
size_t each_line = line;
@@ -946,18 +966,18 @@ namespace Sass {
946
966
if (!lex< in >()) throw_syntax_error (" expected 'in' keyword in @each directive" );
947
967
Node list (parse_list ());
948
968
if (!peek< exactly<' {' > >()) throw_syntax_error (" expected '{' after the upper bound in @each directive" );
949
- Node body (parse_block (surrounding_ruleset));
969
+ Node body (parse_block (surrounding_ruleset, inside_of ));
950
970
Node each (context.new_Node (Node::each_directive, path, each_line, 3 ));
951
971
each << var << list << body;
952
972
return each;
953
973
}
954
974
955
- Node Document::parse_while_directive (Node surrounding_ruleset)
975
+ Node Document::parse_while_directive (Node surrounding_ruleset, Node::Type inside_of )
956
976
{
957
977
lex< while_directive >();
958
978
size_t while_line = line;
959
979
Node predicate (parse_list ());
960
- Node body (parse_block (surrounding_ruleset));
980
+ Node body (parse_block (surrounding_ruleset, inside_of ));
961
981
Node loop (context.new_Node (Node::while_directive, path, while_line, 2 ));
962
982
loop << predicate << body;
963
983
return loop;
0 commit comments