1 /*
2  Copyright (C) 2016-2017 Alexander Borisov
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 
18  Author: lex.borisov@gmail.com (Alexander Borisov)
19 */
20 
21 #include "mycss/selectors/parser.h"
22 #include "mycss/selectors/value_resource.h"
23 
24 /////////////////////////////////////////////////////////
25 //// Selectors Begin
26 ////
27 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_begin(mycss_entry_t * entry,mycss_token_t * token)28 void mycss_selectors_parser_selector_begin(mycss_entry_t* entry, mycss_token_t* token)
29 {
30     mycss_selectors_entry_t *selector = mycss_selectors_entry_create(entry->selectors);
31     mycss_selectors_entry_append_to_current(entry->selectors, selector);
32 }
33 
34 /////////////////////////////////////////////////////////
35 //// Selector type
36 ////
37 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_ident_type(mycss_entry_t * entry,mycss_token_t * token)38 void mycss_selectors_parser_selector_ident_type(mycss_entry_t* entry, mycss_token_t* token)
39 {
40     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
41 
42     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
43     mycss_token_data_to_string(entry, token, str, true, false);
44 
45     /* set default namespace */
46     if(entry->stylesheet)
47         selector->ns_entry = entry->stylesheet->ns_stylesheet.entry_default;
48 
49     selector->type = MyCSS_SELECTORS_TYPE_ELEMENT;
50     selector->key  = str;
51 
52     if(entry->selectors->specificity)
53         if(str->length != 1 || *str->data != '*')
54             entry->selectors->specificity->c++;
55 }
56 
mycss_selectors_parser_selector_ident_attr(mycss_entry_t * entry,mycss_token_t * token)57 void mycss_selectors_parser_selector_ident_attr(mycss_entry_t* entry, mycss_token_t* token)
58 {
59     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
60 
61     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
62     mycss_token_data_to_string(entry, token, str, true, false);
63 
64     /* set default namespace */
65     if(entry->stylesheet)
66         selector->ns_entry = entry->stylesheet->ns_stylesheet.entry_default;
67 
68     selector->type = MyCSS_SELECTORS_TYPE_ATTRIBUTE;
69     selector->key  = str;
70 
71     if(entry->selectors->specificity)
72         if(str->length != 1 || *str->data != '*')
73             entry->selectors->specificity->b++;
74 }
75 
mycss_selectors_parser_selector_id(mycss_entry_t * entry,mycss_token_t * token)76 void mycss_selectors_parser_selector_id(mycss_entry_t* entry, mycss_token_t* token)
77 {
78     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
79 
80     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
81     mycss_token_data_to_string(entry, token, str, true, false);
82 
83     /* set default namespace */
84     if(entry->stylesheet)
85         selector->ns_entry = entry->stylesheet->ns_stylesheet.entry_default;
86 
87     selector->type = MyCSS_SELECTORS_TYPE_ID;
88     selector->key  = str;
89 
90     if(entry->selectors->specificity)
91         entry->selectors->specificity->a++;
92 
93     mycss_selectors_parser_selector_end(entry, token);
94 }
95 
mycss_selectors_parser_selector_class(mycss_entry_t * entry,mycss_token_t * token)96 void mycss_selectors_parser_selector_class(mycss_entry_t* entry, mycss_token_t* token)
97 {
98     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
99 
100     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
101     mycss_token_data_to_string(entry, token, str, true, false);
102 
103     /* set default namespace */
104     if(entry->stylesheet)
105         selector->ns_entry = entry->stylesheet->ns_stylesheet.entry_default;
106 
107     selector->type = MyCSS_SELECTORS_TYPE_CLASS;
108     selector->key  = str;
109 
110     if(entry->selectors->specificity)
111         entry->selectors->specificity->b++;
112 
113     mycss_selectors_parser_selector_end(entry, token);
114 }
115 
116 /////////////////////////////////////////////////////////
117 //// Namespace
118 ////
119 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_namespace(mycss_entry_t * entry,mycss_token_t * token)120 void mycss_selectors_parser_selector_namespace(mycss_entry_t* entry, mycss_token_t* token)
121 {
122     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
123     mycore_string_t *str = selector->key;
124 
125     if(str == NULL || str->length == 0) {
126         mycore_string_destroy(str, 0);
127 
128         selector->key = NULL;
129 
130         if(entry->stylesheet)
131             selector->ns_entry = &entry->stylesheet->ns_stylesheet.entry_undef;
132 
133         return;
134     }
135 
136     if(str->length == 1 && *str->data == '*') {
137         mycore_string_destroy(str, 0);
138 
139         selector->key = NULL;
140 
141         if(entry->stylesheet)
142             selector->ns_entry = &entry->stylesheet->ns_stylesheet.entry_any;
143 
144         return;
145     }
146 
147     if(entry->stylesheet)
148         selector->ns_entry = mycss_namespace_entry_by_name(entry->ns, entry->stylesheet->ns_stylesheet.name_tree, str->data, str->length, false);
149 
150     if(selector->ns_entry == NULL)
151         mycss_selectors_parser_expectations_error(entry, token);
152 
153     mycore_string_destroy(str, 0);
154     selector->key = NULL;
155 }
156 
mycss_selectors_parser_selector_namespace_ident(mycss_entry_t * entry,mycss_token_t * token)157 void mycss_selectors_parser_selector_namespace_ident(mycss_entry_t* entry, mycss_token_t* token)
158 {
159     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
160 
161     mycss_selectors_parser_selector_namespace(entry, token);
162 
163     if(selector->type == MyCSS_SELECTORS_TYPE_UNDEF)
164         selector->type = MyCSS_SELECTORS_TYPE_ELEMENT;
165 }
166 
mycss_selectors_parser_selector_namespace_attr(mycss_entry_t * entry,mycss_token_t * token)167 void mycss_selectors_parser_selector_namespace_attr(mycss_entry_t* entry, mycss_token_t* token)
168 {
169     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
170 
171     mycss_selectors_parser_selector_namespace(entry, token);
172 
173     if(selector->type == MyCSS_SELECTORS_TYPE_UNDEF)
174         selector->type = MyCSS_SELECTORS_TYPE_ATTRIBUTE;
175 }
176 
mycss_selectors_parser_selector_after_namespace(mycss_entry_t * entry,mycss_token_t * token)177 void mycss_selectors_parser_selector_after_namespace(mycss_entry_t* entry, mycss_token_t* token)
178 {
179     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
180 
181     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
182     mycss_token_data_to_string(entry, token, str, true, true);
183 
184     selector->key = str;
185 
186     if(entry->selectors->specificity) {
187         if(selector->ns_entry == &entry->stylesheet->ns_stylesheet.entry_any) {
188             if(selector->type == MyCSS_SELECTORS_TYPE_ATTRIBUTE)
189                 entry->selectors->specificity->b--;
190             else
191                 entry->selectors->specificity->c--;
192         }
193 
194         if(str->length != 1 || *str->data != '*') {
195             if(selector->type == MyCSS_SELECTORS_TYPE_ATTRIBUTE)
196                 entry->selectors->specificity->b++;
197             else
198                 entry->selectors->specificity->c++;
199         }
200     }
201 }
202 
203 /////////////////////////////////////////////////////////
204 //// Value and Modifier
205 ////
206 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_value(mycss_entry_t * entry,mycss_token_t * token)207 void mycss_selectors_parser_selector_value(mycss_entry_t* entry, mycss_token_t* token)
208 {
209     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
210     mycss_selectors_object_attribute_t *attr = selector->value;
211 
212     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
213     mycss_token_data_to_string(entry, token, str, true, false);
214 
215     attr->value = str;
216 }
217 
mycss_selectors_parser_selector_modifier(mycss_entry_t * entry,mycss_token_t * token)218 void mycss_selectors_parser_selector_modifier(mycss_entry_t* entry, mycss_token_t* token)
219 {
220     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
221     mycss_selector_value_attribute(selector->value)->mod = MyCSS_SELECTORS_MOD_I;
222 }
223 
224 /////////////////////////////////////////////////////////
225 //// Pseudo Class
226 ////
227 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_pseudo_class(mycss_entry_t * entry,mycss_token_t * token)228 void mycss_selectors_parser_selector_pseudo_class(mycss_entry_t* entry, mycss_token_t* token)
229 {
230     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
231 
232     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
233     mycss_token_data_to_string(entry, token, str, true, true);
234 
235     selector->sub_type = mycss_pseudo_class_by_name(str->data, str->length);
236     selector->key      = str;
237     selector->type     = MyCSS_SELECTORS_TYPE_PSEUDO_CLASS;
238 
239     /* hack for elements */
240     if(selector->sub_type == MyCSS_SELECTORS_SUB_TYPE_PSEUDO_CLASS_UNKNOWN) {
241         selector->sub_type = mycss_pseudo_element_by_name(str->data, str->length);
242 
243         if(selector->sub_type == MyCSS_SELECTORS_SUB_TYPE_PSEUDO_ELEMENT_UNKNOWN) {
244             selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
245         }
246         else {
247             selector->type = MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT;
248         }
249     }
250 
251     if(selector->type == MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT) {
252         if(entry->selectors->specificity)
253             entry->selectors->specificity->c++;
254     } else {
255         if(entry->selectors->specificity)
256             entry->selectors->specificity->b++;
257     }
258 
259     mycss_selectors_parser_check_and_set_bad_parent_selector(entry, entry->selectors->list_last);
260     mycss_selectors_parser_selector_end(entry, token);
261 }
262 
mycss_selectors_parser_selector_pseudo_class_function(mycss_entry_t * entry,mycss_token_t * token)263 void mycss_selectors_parser_selector_pseudo_class_function(mycss_entry_t* entry, mycss_token_t* token)
264 {
265     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
266 
267     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
268     mycss_token_data_to_string(entry, token, str, true, true);
269 
270     selector->key   = str;
271     selector->type  = MyCSS_SELECTORS_TYPE_PSEUDO_CLASS_FUNCTION;
272 
273     entry->parser_ending_token = MyCSS_TOKEN_TYPE_RIGHT_PARENTHESIS;
274     mycss_entry_parser_list_push(entry, mycss_selectors_state_simple_selector_colon_function, entry->parser_switch, entry->selectors->ending_token, false);
275 
276     if(entry->selectors->specificity)
277         entry->selectors->specificity->b++;
278 
279     mycss_selectors_function_begin_f to_func = mycss_function_begin_by_name(str->data, str->length);
280 
281     if(to_func) {
282         to_func(entry, selector);
283     }
284     else {
285         /* skip and set bad type for current selector */
286         selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
287 
288         if(entry->selectors->list_last)
289             entry->selectors->list_last->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
290 
291         mycss_selectors_begin_unknown(entry, selector);
292     }
293 }
294 
mycss_selectors_parser_selector_pseudo_class_function_end(mycss_entry_t * entry,mycss_token_t * token)295 void mycss_selectors_parser_selector_pseudo_class_function_end(mycss_entry_t* entry, mycss_token_t* token)
296 {
297     entry->selectors->ending_token = entry->parser_ending_token;
298 
299     mycss_selectors_parser_check_and_set_bad_parent_selector(entry, entry->selectors->list_last);
300     mycss_selectors_parser_selector_end(entry, token);
301 }
302 
303 /////////////////////////////////////////////////////////
304 //// Pseudo Element
305 ////
306 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_pseudo_element(mycss_entry_t * entry,mycss_token_t * token)307 void mycss_selectors_parser_selector_pseudo_element(mycss_entry_t* entry, mycss_token_t* token)
308 {
309     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
310 
311     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
312     mycss_token_data_to_string(entry, token, str, true, true);
313 
314     selector->key  = str;
315     selector->type = MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT;
316 
317     selector->sub_type = mycss_pseudo_element_by_name(str->data, str->length);
318 
319     if(selector->sub_type == MyCSS_SELECTORS_SUB_TYPE_PSEUDO_ELEMENT_UNKNOWN)
320         selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
321 
322     if(entry->selectors->specificity)
323         entry->selectors->specificity->c++;
324 
325     mycss_selectors_parser_check_and_set_bad_parent_selector(entry, entry->selectors->list_last);
326     mycss_selectors_parser_selector_end(entry, token);
327 }
328 
mycss_selectors_parser_selector_pseudo_element_function(mycss_entry_t * entry,mycss_token_t * token)329 void mycss_selectors_parser_selector_pseudo_element_function(mycss_entry_t* entry, mycss_token_t* token)
330 {
331     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
332 
333     mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
334     mycss_token_data_to_string(entry, token, str, true, true);
335 
336     selector->key   = str;
337     selector->type  = MyCSS_SELECTORS_TYPE_PSEUDO_ELEMENT_FUNCTION;
338 
339     selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
340     mycss_selectors_begin_unknown(entry, selector);
341 
342     if(entry->selectors->specificity)
343         entry->selectors->specificity->c++;
344 }
345 
mycss_selectors_parser_selector_pseudo_element_function_end(mycss_entry_t * entry,mycss_token_t * token)346 void mycss_selectors_parser_selector_pseudo_element_function_end(mycss_entry_t* entry, mycss_token_t* token)
347 {
348     mycss_selectors_parser_check_and_set_bad_parent_selector(entry, entry->selectors->list_last);
349     mycss_selectors_parser_selector_end(entry, token);
350 }
351 
352 /////////////////////////////////////////////////////////
353 //// End and bad selectors
354 ////
355 /////////////////////////////////////////////////////////
mycss_selectors_parser_selector_end(mycss_entry_t * entry,mycss_token_t * token)356 void mycss_selectors_parser_selector_end(mycss_entry_t* entry, mycss_token_t* token)
357 {
358     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
359 
360     if(entry->callback_selector_done)
361         entry->callback_selector_done(entry->selectors, selector);
362 }
363 
mycss_selectors_parser_expectations_error(mycss_entry_t * entry,mycss_token_t * token)364 void mycss_selectors_parser_expectations_error(mycss_entry_t* entry, mycss_token_t* token)
365 {
366     mycss_selectors_t *selectors = entry->selectors;
367 
368     selectors->entry_last->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
369 
370     if(entry->selectors->list_last)
371         entry->selectors->list_last->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
372 }
373 
mycss_selectors_parser_bad_token(mycss_entry_t * entry,mycss_token_t * token)374 void mycss_selectors_parser_bad_token(mycss_entry_t* entry, mycss_token_t* token)
375 {
376     mycss_selectors_entry_t *selector = entry->selectors->entry_last;
377 
378     if((selector->flags & MyCSS_SELECTORS_FLAGS_SELECTOR_BAD) == 0) {
379         selector->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
380 
381         mycore_string_t *str = mcobject_malloc(entry->mcobject_string_entries, NULL);
382         selector->key = str;
383 
384         mycss_token_data_to_string(entry, token, selector->key, true, false);
385         return;
386     }
387 
388     mycss_token_data_to_string(entry, token, selector->key, false, false);
389 }
390 
391 /////////////////////////////////////////////////////////
392 //// Set bad
393 ////
394 /////////////////////////////////////////////////////////
mycss_selectors_parser_check_and_set_bad_parent_selector(mycss_entry_t * entry,mycss_selectors_list_t * selectors_list)395 void mycss_selectors_parser_check_and_set_bad_parent_selector(mycss_entry_t* entry, mycss_selectors_list_t* selectors_list)
396 {
397     mycss_selectors_list_t *list = entry->selectors->list_last;
398 
399     if(list && entry->selectors->entry_last->flags & MyCSS_SELECTORS_FLAGS_SELECTOR_BAD)
400     {
401         if((list->flags & MyCSS_SELECTORS_FLAGS_SELECTOR_BAD) == 0)
402             list->flags |= MyCSS_SELECTORS_FLAGS_SELECTOR_BAD;
403     }
404 }
405 
406 
407