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