]> mj.ucw.cz Git - leo.git/blob - css-parse.y
TODO
[leo.git] / css-parse.y
1 /*
2  *      Hic Est Leo -- MapCSS Parser
3  *
4  *      (c) 2014--2015 Martin Mares <mj@ucw.cz>
5  */
6
7 %{
8 #include <ucw/lib.h>
9 #include <ucw/mempool.h>
10
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "leo.h"
15 #include "css.h"
16 #include "expr.h"
17
18 static void *css_alloc(size_t n)
19 {
20   return mp_alloc_zero(css_this->pool, n);
21 }
22
23 static struct css_path *css_new_path(void)
24 {
25   struct css_path *p = css_alloc(sizeof(struct css_path));
26   clist_init(&p->conditions);
27   p->layer = STYLE_LAYER_DEFAULT;
28   return p;
29 }
30
31 static void css_add_to_val_list(struct style_prop *list, struct style_prop *elt)
32 {
33   struct style_val_list_entry *e = css_alloc(sizeof(*e));
34   clist_add_tail(list->val.list, &e->n);
35   e->val = *elt;
36 }
37
38 %}
39
40 %union {
41   char *s;
42   struct css_rule *rule;
43   struct css_selector *selector;
44   struct css_path *path;
45   struct css_condition *condition;
46   struct css_action *action;
47   struct style_prop prop;
48   enum css_cond_op cond_op;
49 }
50
51 %token LE GE NE CC
52 %token SINGLE_PROP
53 %token <s> NUMBER IDENT QUOTED RGB LUA
54
55 %type <s> ident_or_quoted
56 %type <rule> rule rule_start rule_selectors rule_start_actions rule_actions
57 %type <selector> selector selector_start
58 %type <path> path path_start path_conditions
59 %type <condition> condition
60 %type <action> action
61 %type <prop> prop_value prop_value_single prop_value_list
62 %type <cond_op> binary_op
63
64 %%
65
66 input:
67     input_css
68   | prop_single
69   ;
70
71 input_css:
72     /* empty */
73   | input_css rule { clist_add_tail(&css_this->rules, &$2->n); }
74   ;
75
76 rule_start:
77     /* empty */
78     {
79       $$ = css_alloc(sizeof(struct css_rule));
80       clist_init(&$$->selectors);
81       clist_init(&$$->actions);
82     }
83   ;
84
85 rule_selectors:
86     rule_start selector
87     {
88       clist_add_tail(&$1->selectors, &$2->n);
89       $$ = $1;
90     }
91   | rule_selectors ',' selector
92     {
93       clist_add_tail(&$1->selectors, &$3->n);
94       $$ = $1;
95     }
96   ;
97
98 rule_start_actions:
99     rule_start
100   | rule_selectors
101   ;
102
103 rule_actions:
104     rule_start_actions '{'
105     {
106       $$ = $1;
107     }
108   | rule_actions action ';'
109     {
110       $$ = $1;
111       clist_add_tail(&$$->actions, &$2->n);
112     }
113   ;
114
115 rule: rule_actions '}' ;
116
117 selector_start:
118     /* empty */
119     {
120       $$ = css_alloc(sizeof(struct css_selector));
121       clist_init(&$$->path);
122     }
123   ;
124
125 selector:
126     selector_start path
127     {
128       clist_add_tail(&$1->path, &$2->n);
129       $$ = $1;
130     }
131   | selector path
132     {
133       // FIXME: Descendant operator
134       clist_add_tail(&$1->path, &$2->n);
135       $$ = $1;
136     }
137   ;
138
139 path_start:
140     IDENT
141     {
142       $$ = css_new_path();
143       if (!strcmp($1, "node"))
144         $$->type = CSS_TYPE_NODE;
145       else if (!strcmp($1, "way"))
146         $$->type = CSS_TYPE_WAY;
147       else if (!strcmp($1, "relation"))
148         $$->type = CSS_TYPE_RELATION;
149       else if (!strcmp($1, "area"))
150         $$->type = CSS_TYPE_AREA;
151       else if (!strcmp($1, "meta"))
152         $$->type = CSS_TYPE_META;
153       else
154         die("Invalid selector %s", $1);
155     }
156   | '*'
157     {
158       $$ = css_new_path();
159       $$->type = CSS_TYPE_ANY;
160     }
161   ;
162
163 path_conditions:
164     path_start
165   | path_conditions '[' condition ']'
166     {
167       $$ = $1;
168       clist_add_tail(&$$->conditions, &$3->n);
169     }
170   ;
171
172 path:
173     path_conditions
174   | path ':' IDENT
175     {
176       // So far, no modifiers are supported, so a rule with modifiers never matches
177       $$ = $1;
178       $$->modifiers |= PATH_MOD_NEVER;
179     }
180   | path CC IDENT
181     {
182       // Layer
183       $$ = $1;
184       $$->layer = style_layer_encode($3);
185     }
186   | path CC '*'
187     {
188       // All layers
189       $$ = $1;
190       $$->layer = STYLE_LAYER_ALL;
191     }
192   ;
193
194 condition:
195     ident_or_quoted binary_op ident_or_quoted
196     {
197       $$ = css_alloc(sizeof(struct css_condition));
198       $$->op = $2;
199       $$->key = osm_key_encode($1);
200       $$->val = osm_val_encode($3);
201     }
202   | ident_or_quoted
203     {
204       $$ = css_alloc(sizeof(struct css_condition));
205       $$->op = COND_OP_IS_SET;
206       $$->key = osm_key_encode($1);
207     }
208   | '!' ident_or_quoted
209     {
210       $$ = css_alloc(sizeof(struct css_condition));
211       $$->op = COND_OP_IS_UNSET;
212       $$->key = osm_key_encode($2);
213     }
214   | ident_or_quoted '?'
215     {
216       $$ = css_alloc(sizeof(struct css_condition));
217       $$->op = COND_OP_IS_TRUE;
218       $$->key = osm_key_encode($1);
219     }
220   | ident_or_quoted '?' '!'
221     {
222       $$ = css_alloc(sizeof(struct css_condition));
223       $$->op = COND_OP_IS_FALSE;
224       $$->key = osm_key_encode($1);
225     }
226   ;
227
228 binary_op:
229     '=' { $$ = COND_OP_EQ; }
230   | '<' { $$ = COND_OP_LT; }
231   | '>' { $$ = COND_OP_GT; }
232   | LE  { $$ = COND_OP_LE; }
233   | GE  { $$ = COND_OP_GE; }
234   | NE  { $$ = COND_OP_NE; }
235   ;
236
237 action:
238     ident_or_quoted ':' prop_value
239       {
240         $$ = css_alloc(sizeof(struct css_action));
241         $$->type = CSS_ACTION_SET;
242         $$->prop = $3;
243         $$->prop.key = style_prop_encode($1);
244       }
245   | LUA
246       {
247         $$ = css_alloc(sizeof(struct css_action));
248         $$->type = CSS_ACTION_EXPR;
249         expr_compile($$, $1);
250       }
251   ;
252
253 prop_value:
254     prop_value_single
255   | prop_value_list
256   ;
257
258 prop_value_single:
259     IDENT
260       {
261         $$.type = PROP_TYPE_IDENT;
262         $$.val.id = osm_val_encode($1);
263       }
264   | QUOTED
265       {
266         $$.type = PROP_TYPE_STRING;
267         $$.val.id = osm_val_encode($1);
268       }
269   | NUMBER
270       {
271         $$.type = PROP_TYPE_NUMBER;
272         $$.val.number = atof($1);
273       }
274   | RGB
275       {
276         $$.type = PROP_TYPE_COLOR;
277         $$.val.color = css_rgb_to_color($1);
278       }
279   ;
280
281 prop_value_list:
282     prop_value_single ',' prop_value_single
283       {
284         $$.type = PROP_TYPE_LIST;
285         $$.val.list = css_alloc(sizeof(clist));
286         clist_init($$.val.list);
287         css_add_to_val_list(&$$, &$1);
288         css_add_to_val_list(&$$, &$3);
289       }
290   | prop_value_list ',' prop_value_single
291       {
292         $$ = $1;
293         css_add_to_val_list(&$$, &$3);
294       }
295   ;
296
297 prop_single:
298     SINGLE_PROP prop_value
299       {
300         struct style_prop *p = css_alloc(sizeof(*p));
301         css_this->parsed_prop = p;
302         *p = $2;
303       }
304   ;
305
306 ident_or_quoted: IDENT | QUOTED ;
307
308 %%
309
310 struct css_sheet *css_this;
311
312 struct css_sheet *css_load(char *filename)
313 {
314   struct mempool *mp = mp_new(4096);
315   struct css_sheet *ss = mp_alloc_zero(mp, sizeof(*ss));
316   ss->pool = mp;
317   clist_init(&ss->rules);
318   ss->filename = mp_strdup(mp, filename);
319
320   css_this = ss;
321   css_lex_open();
322   css_parse();
323
324   css_lex_close();
325   css_this = NULL;
326   return ss;
327 }
328
329 struct style_prop *css_parse_prop(struct mempool *mp, char *objname, const char *key_str, const char *value_str)
330 {
331   struct css_sheet ss = {
332     .pool = mp,
333     .filename = objname,
334     .pushed_token = SINGLE_PROP,
335   };
336   clist_init(&ss.rules);
337
338   css_this = &ss;
339   css_lex_string(value_str);
340   css_parse();
341
342   struct style_prop *p = ss.parsed_prop;
343   p->key = style_prop_encode(key_str);
344
345   css_this = NULL;
346   return p;
347 }