expression parsing has begun
[manmower/obtheme.git] / obtheme.y
1 %pure-parser
2 %name-prefix "obtheme"
3 %parse-param {struct parser_control *pc}
4 %{
5 #include <assert.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <limits.h>
12 #include <unistd.h>
13 #include "frame.h"
14 #include "misc.h"
15 #include "render.h"
16 #include "obtheme.h"
17 #include "obtheme.tab.h"
18
19 YY_DECL;
20
21 struct context_table_item {
22         char *name;
23         ObFrameContext val;
24 };
25
26 /* some of these contexts don't make any sense for a theme... */
27 static struct context_table_item contexts[OB_FRAME_NUM_CONTEXTS] = {
28         {"none", OB_FRAME_CONTEXT_NONE},
29         {"desktop", OB_FRAME_CONTEXT_DESKTOP},
30         {"root", OB_FRAME_CONTEXT_ROOT},
31         {"client", OB_FRAME_CONTEXT_CLIENT},
32         {"titlebar", OB_FRAME_CONTEXT_TITLEBAR},
33         {"frame", OB_FRAME_CONTEXT_FRAME},
34         {"blcorner", OB_FRAME_CONTEXT_BLCORNER},
35         {"brcorner", OB_FRAME_CONTEXT_BRCORNER},
36         {"tlcorner", OB_FRAME_CONTEXT_TLCORNER},
37         {"trcorner", OB_FRAME_CONTEXT_TRCORNER},
38         {"top", OB_FRAME_CONTEXT_TOP},
39         {"bottom", OB_FRAME_CONTEXT_BOTTOM},
40         {"left", OB_FRAME_CONTEXT_LEFT},
41         {"right", OB_FRAME_CONTEXT_RIGHT},
42         {"maximize", OB_FRAME_CONTEXT_MAXIMIZE},
43         {"alldesktops", OB_FRAME_CONTEXT_ALLDESKTOPS},
44         {"shade", OB_FRAME_CONTEXT_SHADE},
45         {"iconify", OB_FRAME_CONTEXT_ICONIFY},
46         {"icon", OB_FRAME_CONTEXT_ICON},
47         {"close", OB_FRAME_CONTEXT_CLOSE},
48         {"moveresize", OB_FRAME_CONTEXT_MOVE_RESIZE}
49 };
50
51 static ObFrameContext context_from_string(char *str)
52 {
53         int i;
54         for (i = 0; i < OB_FRAME_NUM_CONTEXTS; i++)
55                 if (strcmp(contexts[i].name, str) == 1)
56                         return contexts[i].val;
57         return -1;
58 }
59
60 struct gradient_table_item {
61         char *name;
62         RrSurfaceColorType val;
63 };
64
65 struct gradient_table_item gradients[RR_SURFACE_NUM_TYPES] = {
66         {"none", RR_SURFACE_NONE},
67         {"parentrel", RR_SURFACE_PARENTREL},
68         {"solid", RR_SURFACE_SOLID},
69         {"split", RR_SURFACE_SPLIT_VERTICAL},
70         {"horizontal", RR_SURFACE_HORIZONTAL},
71         {"vertical", RR_SURFACE_VERTICAL},
72         {"diagonal", RR_SURFACE_DIAGONAL},
73         {"cross_diagonal", RR_SURFACE_CROSS_DIAGONAL},
74         {"pyramid", RR_SURFACE_PYRAMID},
75         {"mirror_horizontal", RR_SURFACE_MIRROR_HORIZONTAL},
76 };
77
78 static RrSurfaceColorType gradient_from_string(char *str)
79 {
80         int i;
81
82         for (i = 0; i < RR_SURFACE_NUM_TYPES; i++)
83                 if (strcmp(gradients[i].name, str) == 1)
84                         return gradients[i].val;
85
86         return -1;
87 }
88
89 struct parser_control *parser_init(struct obthemedata *otd)
90 {
91         struct parser_control *out;
92         out = calloc(1, sizeof(struct parser_control));
93         out->include_stack_ptr = 0;
94         out->target = otd;
95         return out;
96 }
97
98 void parser_finish(struct parser_control *c)
99 {
100         free(c);
101 }
102
103 struct expression *exdup(struct expression in)
104 {
105         struct expression *out;
106         out = malloc(sizeof(struct expression));
107         *out = in;
108         return out;
109 }
110
111 %}
112 %start theme_objects
113
114 %union {
115         int integer;
116         float realnum;
117         char *string;
118         struct decor decor;
119         struct space space;
120         struct theme theme;
121         struct material material;
122         struct style style;
123         GSList *list;
124         GHashTable *hash;
125         struct vector vector;
126         ObCursor dir;
127         ObFrameContext context;
128         RrSurfaceColorType gradient;
129         struct expression expr;
130         struct variable var;
131 }
132
133 %token NORTH NORTHEAST EAST SOUTHEAST SOUTH SOUTHWEST
134 %token WEST NORTHWEST NONE UNCHANGED
135 %token LCB RCB LB RB
136 %token LEFT_ARROW RIGHT_ARROW DOUBLE_ARROW
137 %token SEMICOLON AT COLON DEFAULT NOT
138 %token PLUS MINUS STAR SLASH COMMA
139 %token <string> STRING ID
140 %token <integer> NUMBER SUBST BULK BIG LITTLE
141 %token THEME FRAME SPACE GEOMETRY MATERIAL GRADIENT
142 %token CONTEXT CURSOR UP ANCHOR STYLE TEXTURE OPACITY
143 %token SHAPEOF DECOR DOT
144 %type <decor> decor
145 %type <decor> decoritems styleitem
146 %type <space> space
147 %type <style> style styleitems
148 %type <hash> styles
149 %type <material> material_props
150 %type <realnum> opacity
151 %type <space> spaceconstraints
152 %type <vector> up anchor
153 %type <dir> cursor
154 %type <context> context
155 %type <gradient> gradient
156 %type <expr> expression
157 %type <var> variable
158
159 %left PLUS MINUS
160 %left STAR SLASH
161 %left LB
162 %%
163
164 theme_object    : material_decl
165                 | theme
166                 ;
167
168 theme_objects   : /* empty */
169                 | theme_objects theme_object
170                 ;
171
172 theme           : THEME ID LCB styles RCB {
173                         struct theme *out;
174                         out = malloc(sizeof(struct theme));
175                         out->name = $2;
176                         out->styles = $4;
177                         g_hash_table_insert(pc->target->themes, $2, out);
178                 }
179                 ;
180
181 opacity         : OPACITY LB NUMBER RB { $$ = $3; }
182                 ;
183
184 material_props  : /* empty */ { memset(&$$, 0, sizeof($$)); }
185                 | material_props opacity { $$ = $1; $$.opacity = $2;}
186                 | material_props gradient
187                 ;
188
189 material_decl   : MATERIAL ID LCB material_props RCB {
190                         struct material *out;
191                         out = malloc(sizeof(struct material));
192                         *out = $4;
193                         g_hash_table_insert(pc->target->materials, $2, out);
194                 }
195                 ;
196
197 anchor          : ANCHOR LB expression COMMA expression COMMA expression RB {
198                         $$.x = $3;
199                         $$.y = $5;
200                         $$.z = $7;
201                 }
202                 ;
203
204 up              : UP LB expression COMMA expression COMMA expression RB {
205                         $$.x = $3;
206                         $$.y = $5;
207                         $$.z = $7;
208                 }
209                 ;
210
211 spaceconstraints: /* empty */ { memset(&$$, 0, sizeof($$));
212                         $$.anchor.x.op = OB_THEME_EQL;
213                         $$.anchor.x.v.number = 1;
214                         $$.anchor.y.op = OB_THEME_EQL;
215                         $$.anchor.y.v.number = 1;
216                         $$.anchor.z.op = OB_THEME_EQL;
217                         $$.anchor.z.v.number = 1;
218                         $$.up.x.op = OB_THEME_EQL;
219                         $$.up.x.v.number = 1;
220                         $$.up.y.op = OB_THEME_EQL;
221                         $$.up.y.v.number = 1;
222                         $$.up.z.op = OB_THEME_EQL;
223                         $$.up.z.v.number = 1;
224                 }
225                 | spaceconstraints anchor { $1.anchor = $2; $$ = $1; }
226                 | spaceconstraints up     { $1.up = $2; $$ = $1; }
227                 ;
228
229 space           : SPACE LCB spaceconstraints RCB {
230                         $$ = $3;
231                 }
232                 ;
233
234 shape           : SHAPEOF LB ID RB
235                 ;
236
237 geometry_item   : /* empty */
238                 | shape
239                 ;
240
241 geometry        : GEOMETRY LCB geometry_item RCB
242                 ;
243
244 material_use    : MATERIAL LB ID RB {
245                         if (g_hash_table_lookup(pc->target->materials, $3) == NULL) {
246                                 snprintf(pc->error_buf, 4000, "No definition for material '%s'\n", $3);
247                                 obthemeerror(pc, pc->error_buf);
248                                 return 1;
249                         }
250                 }
251                 ;
252
253 styleitem       : decor
254                 ;
255
256 styleitems      : /* empty */ { $$.tree = NULL; $$.name = NULL; }
257                 | styleitems styleitem {
258                         struct decor *out = malloc(sizeof(struct decor));
259                         *out = $2;
260                         $1.tree = g_slist_prepend($1.tree, out);
261                         $$ = $1;
262                 }
263                 ;
264
265 styles          : /* empty */ { $$ = g_hash_table_new(g_str_hash, g_str_equal); }
266                 | styles style {
267                         struct style *out = malloc(sizeof(struct style));
268                         *out = $2;
269                         $$ = $1;
270                         g_hash_table_insert($1, out->name, out);
271                 }
272                 ;
273
274 style           : STYLE ID LCB styleitems RCB {
275                         $$ = $4;
276                         $$.name = $2;
277                 }
278                 ;
279
280 decoritems      : /* empty */ {
281                         memset(&$$, 0, sizeof($$));
282 //                      $$.space.up.y = -1;  XXX need a sane default!
283                         $$.cursor = OB_CURSOR_NONE;
284                         $$.space.anchor.x.op = OB_THEME_EQL;
285                         $$.space.anchor.x.v.number = 1;
286                         $$.space.anchor.y.op = OB_THEME_EQL;
287                         $$.space.anchor.y.v.number = 1;
288                         $$.space.anchor.z.op = OB_THEME_EQL;
289                         $$.space.anchor.z.v.number = 1;
290                         $$.space.up.x.op = OB_THEME_EQL;
291                         $$.space.up.x.v.number = 1;
292                         $$.space.up.y.op = OB_THEME_EQL;
293                         $$.space.up.y.v.number = 1;
294                         $$.space.up.z.op = OB_THEME_EQL;
295                         $$.space.up.z.v.number = 1;
296                 }
297                 | decoritems decor {
298                         struct decor *out = malloc(sizeof(struct decor));
299                         *out = $2;
300                         $$ = $1;
301                         $$.children = g_slist_append($1.children, out);
302                 }
303                 | decoritems space { $1.space = $2; $$ = $1; }
304                 | decoritems material_use
305                 | decoritems geometry
306                 | decoritems texture
307                 | decoritems context { $1.context = $2; }
308                 | decoritems cursor { $1.cursor = $2; }
309                 ;
310
311                 ;
312
313 decor           : DECOR ID LCB decoritems RCB {
314                         $$ = $4;
315                         $$.name = $2;
316                 }
317                 ;
318
319 texture         : TEXTURE LCB RCB
320                 ;
321
322 context         : CONTEXT LB ID RB {
323                         ObFrameContext frc;
324                         frc = context_from_string($3);
325                         if (frc == -1) {
326                                 snprintf(pc->error_buf, 4000, "Illegal context '%s'\n", $3);
327                                 obthemeerror(pc, pc->error_buf);
328                                 return 1;
329                         }
330                 }
331                 ;
332
333 cursor          : CURSOR LB NORTH RB { $$ = OB_CURSOR_NORTH; }
334                 | CURSOR LB NORTHEAST RB { $$ = OB_CURSOR_NORTHEAST; }
335                 | CURSOR LB EAST RB { $$ = OB_CURSOR_EAST; }
336                 | CURSOR LB SOUTHEAST RB { $$ = OB_CURSOR_SOUTHEAST; }
337                 | CURSOR LB SOUTH RB { $$ = OB_CURSOR_SOUTH; }
338                 | CURSOR LB SOUTHWEST RB { $$ = OB_CURSOR_SOUTHWEST; }
339                 | CURSOR LB WEST RB { $$ = OB_CURSOR_WEST; }
340                 | CURSOR LB NORTHWEST RB { $$ = OB_CURSOR_NORTHWEST; }
341 //              | CURSOR LB NONE RB { $$ = OB_CURSOR_NORTHEAST; }
342                 | CURSOR LB UNCHANGED RB { $$ = OB_CURSOR_NONE; }
343                 ;
344 gradient        : GRADIENT LB ID RB {
345                         $$ = gradient_from_string($3);
346                         if ($$ == -1) {
347                                 snprintf(pc->error_buf, 4000, "No gradient named '%s'\n", $3);
348                                 obthemeerror(pc, pc->error_buf);
349                                 return 1;
350                         }
351                 }
352                 ;
353
354 variable        : ID DOT ID { $$.base = $1; $$.member = $3; }
355                 | ID        { $$.base = $1; $$.member = NULL; }
356                 | NUMBER    { $$.base = NULL; $$.number = $1; }
357                 ;
358
359 expression      : expression STAR expression {
360                         $$.op = OB_THEME_MUL;
361                         $$.a = exdup($1);
362                         $$.b = exdup($3);
363                 }
364                 | expression SLASH expression {
365                         $$.op = OB_THEME_DIV;
366                         $$.a = exdup($1);
367                         $$.b = exdup($3);
368                 }
369                 | expression PLUS expression {
370                         $$.op = OB_THEME_ADD;
371                         $$.a = exdup($1);
372                         $$.b = exdup($3);
373                 }
374                 | expression MINUS expression {
375                         $$.op = OB_THEME_SUB;
376                         $$.a = exdup($1);
377                         $$.b = exdup($3);
378                 }
379                 | variable {
380                         $$.op = OB_THEME_EQL;
381                         $$.v = $1;
382                 }
383                 | LB expression RB { $$ = $2; }
384                 ;
385
386 %%