1// sass.hpp must go before all system headers to get the
2// __EXTENSIONS__ fix on Solaris.
3#include "sass.hpp"
4
5#include "parser.hpp"
6
7namespace Sass {
8
9 using namespace Prelexer;
10 using namespace Constants;
11
12 ComplexSelectorObj Parser::parseComplexSelector(bool chroot)
13 {
14
15 NESTING_GUARD(nestings);
16
17 lex < block_comment >();
18 advanceToNextToken();
19
20 ComplexSelectorObj sel = SASS_MEMORY_NEW(ComplexSelector, pstate);
21
22 if (peek < end_of_file >()) return sel;
23
24 while (true) {
25
26 lex < block_comment >();
27 advanceToNextToken();
28
29 // check for child (+) combinator
30 if (lex < exactly < selector_combinator_child > >()) {
31 sel->append(SASS_MEMORY_NEW(SelectorCombinator, pstate, SelectorCombinator::CHILD, peek_newline()));
32 }
33 // check for general sibling (~) combinator
34 else if (lex < exactly < selector_combinator_general > >()) {
35 sel->append(SASS_MEMORY_NEW(SelectorCombinator, pstate, SelectorCombinator::GENERAL, peek_newline()));
36 }
37 // check for adjecant sibling (+) combinator
38 else if (lex < exactly < selector_combinator_adjacent > >()) {
39 sel->append(SASS_MEMORY_NEW(SelectorCombinator, pstate, SelectorCombinator::ADJACENT, peek_newline()));
40 }
41 // check if we can parse a compound selector
42 else if (CompoundSelectorObj compound = parseCompoundSelector()) {
43 sel->append(element: compound);
44 }
45 else {
46 break;
47 }
48 }
49
50 if (sel->empty()) return {};
51
52 // check if we parsed any parent references
53 sel->chroots(chroots__: sel->has_real_parent_ref() || chroot);
54
55 sel->update_pstate(pstate);
56
57 return sel;
58
59 }
60
61 SelectorListObj Parser::parseSelectorList(bool chroot)
62 {
63
64 bool reloop;
65 bool had_linefeed = false;
66 NESTING_GUARD(nestings);
67 SelectorListObj list = SASS_MEMORY_NEW(SelectorList, pstate);
68
69 if (peek_css< alternatives < end_of_file, exactly <'{'>, exactly <','> > >()) {
70 css_error(msg: "Invalid CSS", prefix: " after ", middle: ": expected selector, was ");
71 }
72
73 do {
74 reloop = false;
75
76 had_linefeed = had_linefeed || peek_newline();
77
78 if (peek_css< alternatives < class_char < selector_list_delims > > >())
79 break; // in case there are superfluous commas at the end
80
81 // now parse the complex selector
82 ComplexSelectorObj complex = parseComplexSelector(chroot);
83 if (complex.isNull()) return list.detach();
84 complex->hasPreLineFeed(hasPreLineFeed__: had_linefeed);
85
86 had_linefeed = false;
87
88 while (peek_css< exactly<','> >())
89 {
90 lex< css_comments >(lazy: false);
91 // consume everything up and including the comma separator
92 reloop = lex< exactly<','> >() != 0;
93 // remember line break (also between some commas)
94 had_linefeed = had_linefeed || peek_newline();
95 // remember line break (also between some commas)
96 }
97 list->append(element: complex);
98
99 } while (reloop);
100
101 while (lex_css< kwd_optional >()) {
102 list->is_optional(is_optional__: true);
103 }
104
105 // update for end position
106 list->update_pstate(pstate);
107
108 return list.detach();
109 }
110
111 // parse one compound selector, which is basically
112 // a list of simple selectors (directly adjacent)
113 // lex them exactly (without skipping white-space)
114 CompoundSelectorObj Parser::parseCompoundSelector()
115 {
116 // init an empty compound selector wrapper
117 CompoundSelectorObj seq = SASS_MEMORY_NEW(CompoundSelector, pstate);
118
119 // skip initial white-space
120 lex < block_comment >();
121 advanceToNextToken();
122
123 if (lex< exactly<'&'> >(lazy: false))
124 {
125 // ToDo: check the conditions and try to simplify flag passing
126 if (!allow_parent) error(msg: "Parent selectors aren't allowed here.");
127 // Create and append a new parent selector object
128 seq->hasRealParent(hasRealParent__: true);
129 }
130
131 // parse list
132 while (true)
133 {
134 // remove all block comments
135 // leaves trailing white-space
136 lex < block_comment >();
137 // parse parent selector
138 if (lex< exactly<'&'> >(lazy: false))
139 {
140 // parent selector only allowed at start
141 // upcoming Sass may allow also trailing
142 SourceSpan state(pstate);
143 sass::string found("&");
144 if (lex < identifier >()) {
145 found += sass::string(lexed);
146 }
147 sass::string sel(seq->hasRealParent() ? "&" : "");
148 if (!seq->empty()) { sel = seq->last()->to_string(opt: { NESTED, 5 }); }
149 // ToDo: parser should throw parser exceptions
150 error(msg: "Invalid CSS after \"" + sel + "\": expected \"{\", was \"" + found + "\"\n\n"
151 "\"" + found + "\" may only be used at the beginning of a compound selector.");
152 }
153 // parse functional
154 else if (match < re_functional >())
155 {
156 seq->append(element: parse_simple_selector());
157 }
158
159 // parse type selector
160 else if (lex< re_type_selector >(lazy: false))
161 {
162 seq->append(SASS_MEMORY_NEW(TypeSelector, pstate, lexed));
163 }
164 // peek for abort conditions
165 else if (peek< spaces >()) break;
166 else if (peek< end_of_file >()) { break; }
167 else if (peek_css < class_char < selector_combinator_ops > >()) break;
168 else if (peek_css < class_char < complex_selector_delims > >()) break;
169 // otherwise parse another simple selector
170 else {
171 SimpleSelectorObj sel = parse_simple_selector();
172 if (!sel) return {};
173 seq->append(element: sel);
174 }
175 }
176 // EO while true
177
178 if (seq && !peek_css<alternatives<end_of_file,exactly<'{'>>>()) {
179 seq->hasPostLineBreak(hasPostLineBreak__: peek_newline());
180 }
181
182 // We may have set hasRealParent
183 if (seq && seq->empty() && !seq->hasRealParent()) return {};
184
185 return seq;
186 }
187
188
189}
190

source code of gtk/subprojects/libsass/src/parser_selectors.cpp