Initial commit
[yaffs-website] / node_modules / node-sass / src / libsass / src / parser.hpp
1 #ifndef SASS_PARSER_H
2 #define SASS_PARSER_H
3
4 #include <string>
5 #include <vector>
6
7 #include "ast.hpp"
8 #include "position.hpp"
9 #include "context.hpp"
10 #include "position.hpp"
11 #include "prelexer.hpp"
12
13 struct Lookahead {
14   const char* found;
15   const char* error;
16   const char* position;
17   bool parsable;
18   bool has_interpolants;
19 };
20
21 namespace Sass {
22
23   class Parser : public ParserState {
24   public:
25
26     enum Scope { Root, Mixin, Function, Media, Control, Properties, Rules };
27
28     Context& ctx;
29     std::vector<Block_Obj> block_stack;
30     std::vector<Scope> stack;
31     Media_Block_Ptr last_media_block;
32     const char* source;
33     const char* position;
34     const char* end;
35     Position before_token;
36     Position after_token;
37     ParserState pstate;
38     int indentation;
39
40
41     Token lexed;
42
43     Parser(Context& ctx, const ParserState& pstate)
44     : ParserState(pstate), ctx(ctx), block_stack(), stack(0), last_media_block(),
45       source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate(pstate), indentation(0)
46     { stack.push_back(Scope::Root); }
47
48     // static Parser from_string(const std::string& src, Context& ctx, ParserState pstate = ParserState("[STRING]"));
49     static Parser from_c_str(const char* src, Context& ctx, ParserState pstate = ParserState("[CSTRING]"), const char* source = 0);
50     static Parser from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate = ParserState("[CSTRING]"), const char* source = 0);
51     static Parser from_token(Token t, Context& ctx, ParserState pstate = ParserState("[TOKEN]"), const char* source = 0);
52     // special static parsers to convert strings into certain selectors
53     static Selector_List_Obj parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"), const char* source = 0);
54
55 #ifdef __clang__
56
57     // lex and peak uses the template parameter to branch on the action, which
58     // triggers clangs tautological comparison on the single-comparison
59     // branches. This is not a bug, just a merging of behaviour into
60     // one function
61
62 #pragma clang diagnostic push
63 #pragma clang diagnostic ignored "-Wtautological-compare"
64
65 #endif
66
67
68     // skip current token and next whitespace
69     // moves ParserState right before next token
70     void advanceToNextToken();
71
72     bool peek_newline(const char* start = 0);
73
74     // skip over spaces, tabs and line comments
75     template <Prelexer::prelexer mx>
76     const char* sneak(const char* start = 0)
77     {
78       using namespace Prelexer;
79
80       // maybe use optional start position from arguments?
81       const char* it_position = start ? start : position;
82
83       // skip white-space?
84       if (mx == spaces ||
85           mx == no_spaces ||
86           mx == css_comments ||
87           mx == css_whitespace ||
88           mx == optional_spaces ||
89           mx == optional_css_comments ||
90           mx == optional_css_whitespace
91       ) {
92         return it_position;
93       }
94
95       // skip over spaces, tabs and sass line comments
96       const char* pos = optional_css_whitespace(it_position);
97       // always return a valid position
98       return pos ? pos : it_position;
99
100     }
101
102     // peek will only skip over space, tabs and line comment
103     // return the position where the lexer match will occur
104     template <Prelexer::prelexer mx>
105     const char* match(const char* start = 0)
106     {
107       // match the given prelexer
108       return mx(position);
109     }
110
111     // peek will only skip over space, tabs and line comment
112     // return the position where the lexer match will occur
113     template <Prelexer::prelexer mx>
114     const char* peek(const char* start = 0)
115     {
116
117       // sneak up to the actual token we want to lex
118       // this should skip over white-space if desired
119       const char* it_before_token = sneak < mx >(start);
120
121       // match the given prelexer
122       const char* match = mx(it_before_token);
123
124       // check if match is in valid range
125       return match <= end ? match : 0;
126
127     }
128
129     // white-space handling is built into the lexer
130     // this way you do not need to parse it yourself
131     // some matchers don't accept certain white-space
132     // we do not support start arg, since we manipulate
133     // sourcemap offset and we modify the position pointer!
134     // lex will only skip over space, tabs and line comment
135     template <Prelexer::prelexer mx>
136     const char* lex(bool lazy = true, bool force = false)
137     {
138
139       if (*position == 0) return 0;
140
141       // position considered before lexed token
142       // we can skip whitespace or comments for
143       // lazy developers (but we need control)
144       const char* it_before_token = position;
145
146       // sneak up to the actual token we want to lex
147       // this should skip over white-space if desired
148       if (lazy) it_before_token = sneak < mx >(position);
149
150       // now call matcher to get position after token
151       const char* it_after_token = mx(it_before_token);
152
153       // check if match is in valid range
154       if (it_after_token > end) return 0;
155
156       // maybe we want to update the parser state anyway?
157       if (force == false) {
158         // assertion that we got a valid match
159         if (it_after_token == 0) return 0;
160         // assertion that we actually lexed something
161         if (it_after_token == it_before_token) return 0;
162       }
163
164       // create new lexed token object (holds the parse results)
165       lexed = Token(position, it_before_token, it_after_token);
166
167       // advance position (add whitespace before current token)
168       before_token = after_token.add(position, it_before_token);
169
170       // update after_token position for current token
171       after_token.add(it_before_token, it_after_token);
172
173       // ToDo: could probably do this incremetal on original object (API wants offset?)
174       pstate = ParserState(path, source, lexed, before_token, after_token - before_token);
175
176       // advance internal char iterator
177       return position = it_after_token;
178
179     }
180
181     // lex_css skips over space, tabs, line and block comment
182     // all block comments will be consumed and thrown away
183     // source-map position will point to token after the comment
184     template <Prelexer::prelexer mx>
185     const char* lex_css()
186     {
187       // copy old token
188       Token prev = lexed;
189       // store previous pointer
190       const char* oldpos = position;
191       Position bt = before_token;
192       Position at = after_token;
193       ParserState op = pstate;
194       // throw away comments
195       // update srcmap position
196       lex < Prelexer::css_comments >();
197       // now lex a new token
198       const char* pos = lex< mx >();
199       // maybe restore prev state
200       if (pos == 0) {
201         pstate = op;
202         lexed = prev;
203         position = oldpos;
204         after_token = at;
205         before_token = bt;
206       }
207       // return match
208       return pos;
209     }
210
211     // all block comments will be skipped and thrown away
212     template <Prelexer::prelexer mx>
213     const char* peek_css(const char* start = 0)
214     {
215       // now peek a token (skip comments first)
216       return peek< mx >(peek < Prelexer::css_comments >(start));
217     }
218
219 #ifdef __clang__
220
221 #pragma clang diagnostic pop
222
223 #endif
224
225     void error(std::string msg, Position pos);
226     // generate message with given and expected sample
227     // text before and in the middle are configurable
228     void css_error(const std::string& msg,
229                    const std::string& prefix = " after ",
230                    const std::string& middle = ", was: ");
231     void read_bom();
232
233     Block_Obj parse();
234     Import_Obj parse_import();
235     Definition_Obj parse_definition(Definition::Type which_type);
236     Parameters_Obj parse_parameters();
237     Parameter_Obj parse_parameter();
238     Mixin_Call_Obj parse_include_directive();
239     Arguments_Obj parse_arguments();
240     Argument_Obj parse_argument();
241     Assignment_Obj parse_assignment();
242     Ruleset_Obj parse_ruleset(Lookahead lookahead);
243     Selector_List_Obj parse_selector_list(bool chroot);
244     Complex_Selector_Obj parse_complex_selector(bool chroot);
245     Selector_Schema_Obj parse_selector_schema(const char* end_of_selector, bool chroot);
246     Compound_Selector_Obj parse_compound_selector();
247     Simple_Selector_Obj parse_simple_selector();
248     Wrapped_Selector_Obj parse_negated_selector();
249     Simple_Selector_Obj parse_pseudo_selector();
250     Attribute_Selector_Obj parse_attribute_selector();
251     Block_Obj parse_block(bool is_root = false);
252     Block_Obj parse_css_block(bool is_root = false);
253     bool parse_block_nodes(bool is_root = false);
254     bool parse_block_node(bool is_root = false);
255
256     bool parse_number_prefix();
257     Declaration_Obj parse_declaration();
258     Expression_Obj parse_map();
259     Expression_Obj parse_bracket_list();
260     Expression_Obj parse_list(bool delayed = false);
261     Expression_Obj parse_comma_list(bool delayed = false);
262     Expression_Obj parse_space_list();
263     Expression_Obj parse_disjunction();
264     Expression_Obj parse_conjunction();
265     Expression_Obj parse_relation();
266     Expression_Obj parse_expression();
267     Expression_Obj parse_operators();
268     Expression_Obj parse_factor();
269     Expression_Obj parse_value();
270     Function_Call_Obj parse_calc_function();
271     Function_Call_Obj parse_function_call();
272     Function_Call_Schema_Obj parse_function_call_schema();
273     String_Obj parse_url_function_string();
274     String_Obj parse_url_function_argument();
275     String_Obj parse_interpolated_chunk(Token, bool constant = false);
276     String_Obj parse_string();
277     String_Constant_Obj parse_static_value();
278     String_Obj parse_ie_property();
279     String_Obj parse_ie_keyword_arg();
280     String_Schema_Obj parse_value_schema(const char* stop);
281     String_Obj parse_identifier_schema();
282     If_Obj parse_if_directive(bool else_if = false);
283     For_Obj parse_for_directive();
284     Each_Obj parse_each_directive();
285     While_Obj parse_while_directive();
286     Return_Obj parse_return_directive();
287     Content_Obj parse_content_directive();
288     void parse_charset_directive();
289     Media_Block_Obj parse_media_block();
290     List_Obj parse_media_queries();
291     Media_Query_Obj parse_media_query();
292     Media_Query_Expression_Obj parse_media_expression();
293     Supports_Block_Obj parse_supports_directive();
294     Supports_Condition_Obj parse_supports_condition();
295     Supports_Condition_Obj parse_supports_negation();
296     Supports_Condition_Obj parse_supports_operator();
297     Supports_Condition_Obj parse_supports_interpolation();
298     Supports_Condition_Obj parse_supports_declaration();
299     Supports_Condition_Obj parse_supports_condition_in_parens();
300     At_Root_Block_Obj parse_at_root_block();
301     At_Root_Query_Obj parse_at_root_query();
302     String_Schema_Obj parse_almost_any_value();
303     Directive_Obj parse_special_directive();
304     Directive_Obj parse_prefixed_directive();
305     Directive_Obj parse_directive();
306     Warning_Obj parse_warning();
307     Error_Obj parse_error();
308     Debug_Obj parse_debug();
309
310     // be more like ruby sass
311     Expression_Obj lex_almost_any_value_token();
312     Expression_Obj lex_almost_any_value_chars();
313     Expression_Obj lex_interp_string();
314     Expression_Obj lex_interp_uri();
315     Expression_Obj lex_interpolation();
316
317     // these will throw errors
318     Token lex_variable();
319     Token lex_identifier();
320
321     void parse_block_comments();
322
323     Lookahead lookahead_for_value(const char* start = 0);
324     Lookahead lookahead_for_selector(const char* start = 0);
325     Lookahead lookahead_for_include(const char* start = 0);
326
327     Expression_Obj fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, Operand op);
328     Expression_Obj fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, std::vector<Operand>& ops, size_t i = 0);
329
330     void throw_syntax_error(std::string message, size_t ln = 0);
331     void throw_read_error(std::string message, size_t ln = 0);
332
333
334     template <Prelexer::prelexer open, Prelexer::prelexer close>
335     Expression_Obj lex_interp()
336     {
337       if (lex < open >(false)) {
338         String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
339         // std::cerr << "LEX [[" << std::string(lexed) << "]]\n";
340         schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
341         if (position[0] == '#' && position[1] == '{') {
342           Expression_Obj itpl = lex_interpolation();
343           if (!itpl.isNull()) schema->append(itpl);
344           while (lex < close >(false)) {
345             // std::cerr << "LEX [[" << std::string(lexed) << "]]\n";
346             schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
347             if (position[0] == '#' && position[1] == '{') {
348               Expression_Obj itpl = lex_interpolation();
349               if (!itpl.isNull()) schema->append(itpl);
350             } else {
351               return schema;
352             }
353           }
354         } else {
355           return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
356         }
357       }
358       return 0;
359     }
360   };
361
362   size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len);
363 }
364
365 #endif