wbemprox: Add query tests.
[wine/multimedia.git] / dlls / wbemprox / wql.y
blob8e347c22e5b6b64be1ceae6c2050a5d527c0b6e1
1 %{
3 /*
4 * Copyright 2012 Hans Leidekker for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wbemcli.h"
27 #include "wbemprox_private.h"
29 #include "wine/list.h"
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
33 #define YYLEX_PARAM ctx
34 #define YYPARSE_PARAM ctx
35 #define YYERROR_DEBUG 1
36 #define YYERROR_VERBOSE 1
38 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
40 struct parser
42 const WCHAR *cmd;
43 UINT idx;
44 UINT len;
45 HRESULT error;
46 struct view **view;
47 struct list *mem;
50 struct string
52 const WCHAR *data;
53 int len;
56 static void *alloc_mem( struct parser *parser, UINT size )
58 struct list *mem = heap_alloc( sizeof(struct list) + size );
59 list_add_tail( parser->mem, mem );
60 return &mem[1];
63 static struct property *alloc_property( struct parser *parser, const WCHAR *class, const WCHAR *name )
65 struct property *prop = alloc_mem( parser, sizeof(*prop) );
66 if (prop)
68 prop->name = name;
69 prop->class = class;
70 prop->next = NULL;
72 return prop;
75 static WCHAR *get_string( struct parser *parser, const struct string *str )
77 const WCHAR *p = str->data;
78 int len = str->len;
79 WCHAR *ret;
81 if ((p[0] == '\"' && p[len - 1] != '\"') ||
82 (p[0] == '\'' && p[len - 1] != '\'')) return NULL;
83 if ((p[0] == '\"' && p[len - 1] == '\"') ||
84 (p[0] == '\'' && p[len - 1] == '\''))
86 p++;
87 len -= 2;
89 if (!(ret = alloc_mem( parser, (len + 1) * sizeof(WCHAR) ))) return NULL;
90 memcpy( ret, p, len * sizeof(WCHAR) );
91 ret[len] = 0;
92 return ret;
95 static int get_int( struct parser *parser )
97 const WCHAR *p = &parser->cmd[parser->idx];
98 int i, ret = 0;
100 for (i = 0; i < parser->len; i++)
102 if (p[i] < '0' || p[i] > '9')
104 ERR("should only be numbers here!\n");
105 break;
107 ret = (p[i] - '0') + ret * 10;
109 return ret;
112 static struct expr *expr_complex( struct parser *parser, struct expr *l, UINT op, struct expr *r )
114 struct expr *e = alloc_mem( parser, sizeof(*e) );
115 if (e)
117 e->type = EXPR_COMPLEX;
118 e->u.expr.left = l;
119 e->u.expr.op = op;
120 e->u.expr.right = r;
122 return e;
125 static struct expr *expr_unary( struct parser *parser, struct expr *l, UINT op )
127 struct expr *e = alloc_mem( parser, sizeof(*e) );
128 if (e)
130 e->type = EXPR_UNARY;
131 e->u.expr.left = l;
132 e->u.expr.op = op;
133 e->u.expr.right = NULL;
135 return e;
138 static struct expr *expr_ival( struct parser *parser, int val )
140 struct expr *e = alloc_mem( parser, sizeof *e );
141 if (e)
143 e->type = EXPR_IVAL;
144 e->u.ival = val;
146 return e;
149 static struct expr *expr_sval( struct parser *parser, const struct string *str )
151 struct expr *e = alloc_mem( parser, sizeof *e );
152 if (e)
154 e->type = EXPR_SVAL;
155 e->u.sval = get_string( parser, str );
156 if (!e->u.sval)
157 return NULL; /* e will be freed by query destructor */
159 return e;
162 static struct expr *expr_bval( struct parser *parser, int val )
164 struct expr *e = alloc_mem( parser, sizeof *e );
165 if (e)
167 e->type = EXPR_BVAL;
168 e->u.ival = val;
170 return e;
173 static struct expr *expr_propval( struct parser *parser, const struct property *prop )
175 struct expr *e = alloc_mem( parser, sizeof *e );
176 if (e)
178 e->type = EXPR_PROPVAL;
179 e->u.propval = prop;
181 return e;
184 static int wql_error( const char *str );
185 static int wql_lex( void *val, struct parser *parser );
187 #define PARSER_BUBBLE_UP_VIEW( parser, result, current_view ) \
188 *parser->view = current_view; \
189 result = current_view
193 %pure-parser
195 %union
197 struct string str;
198 WCHAR *string;
199 struct property *proplist;
200 struct view *view;
201 struct expr *expr;
202 int integer;
205 %token TK_SELECT TK_FROM TK_STAR TK_COMMA TK_DOT TK_IS TK_LP TK_RP TK_NULL TK_FALSE TK_TRUE
206 %token TK_INTEGER TK_WHERE TK_SPACE TK_MINUS TK_ILLEGAL TK_BY
207 %token <str> TK_STRING TK_ID
209 %type <string> id
210 %type <proplist> prop proplist
211 %type <view> select
212 %type <expr> expr prop_val const_val string_val
213 %type <integer> number
215 %left TK_OR
216 %left TK_AND
217 %left TK_NOT
218 %left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
222 select:
223 TK_SELECT TK_FROM id
225 HRESULT hr;
226 struct parser *parser = ctx;
227 struct view *view;
229 hr = create_view( NULL, $3, NULL, &view );
230 if (hr != S_OK)
231 YYABORT;
233 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
235 | TK_SELECT proplist TK_FROM id
237 HRESULT hr;
238 struct parser *parser = ctx;
239 struct view *view;
241 hr = create_view( $2, $4, NULL, &view );
242 if (hr != S_OK)
243 YYABORT;
245 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
247 | TK_SELECT proplist TK_FROM id TK_WHERE expr
249 HRESULT hr;
250 struct parser *parser = ctx;
251 struct view *view;
253 hr = create_view( $2, $4, $6, &view );
254 if (hr != S_OK)
255 YYABORT;
257 PARSER_BUBBLE_UP_VIEW( parser, $$, view );
261 proplist:
262 prop
263 | prop TK_COMMA proplist
265 $1->next = $3;
267 | TK_STAR
269 $$ = NULL;
273 prop:
274 id TK_DOT id
276 $$ = alloc_property( ctx, $1, $3 );
277 if (!$$)
278 YYABORT;
280 | id
282 $$ = alloc_property( ctx, NULL, $1 );
283 if (!$$)
284 YYABORT;
289 TK_ID
291 $$ = get_string( ctx, &$1 );
292 if (!$$)
293 YYABORT;
297 number:
298 TK_INTEGER
300 $$ = get_int( ctx );
304 expr:
305 TK_LP expr TK_RP
307 $$ = $2;
308 if (!$$)
309 YYABORT;
311 | expr TK_AND expr
313 $$ = expr_complex( ctx, $1, OP_AND, $3 );
314 if (!$$)
315 YYABORT;
317 | expr TK_OR expr
319 $$ = expr_complex( ctx, $1, OP_OR, $3 );
320 if (!$$)
321 YYABORT;
323 | prop_val TK_EQ const_val
325 $$ = expr_complex( ctx, $1, OP_EQ, $3 );
326 if (!$$)
327 YYABORT;
329 | prop_val TK_GT const_val
331 $$ = expr_complex( ctx, $1, OP_GT, $3 );
332 if (!$$)
333 YYABORT;
335 | prop_val TK_LT const_val
337 $$ = expr_complex( ctx, $1, OP_LT, $3 );
338 if (!$$)
339 YYABORT;
341 | prop_val TK_LE const_val
343 $$ = expr_complex( ctx, $1, OP_LE, $3 );
344 if (!$$)
345 YYABORT;
347 | prop_val TK_GE const_val
349 $$ = expr_complex( ctx, $1, OP_GE, $3 );
350 if (!$$)
351 YYABORT;
353 | prop_val TK_NE const_val
355 $$ = expr_complex( ctx, $1, OP_NE, $3 );
356 if (!$$)
357 YYABORT;
359 | const_val TK_EQ prop_val
361 $$ = expr_complex( ctx, $1, OP_EQ, $3 );
362 if (!$$)
363 YYABORT;
365 | const_val TK_GT prop_val
367 $$ = expr_complex( ctx, $1, OP_GT, $3 );
368 if (!$$)
369 YYABORT;
371 | const_val TK_LT prop_val
373 $$ = expr_complex( ctx, $1, OP_LT, $3 );
374 if (!$$)
375 YYABORT;
377 | const_val TK_LE prop_val
379 $$ = expr_complex( ctx, $1, OP_LE, $3 );
380 if (!$$)
381 YYABORT;
383 | const_val TK_GE prop_val
385 $$ = expr_complex( ctx, $1, OP_GE, $3 );
386 if (!$$)
387 YYABORT;
389 | const_val TK_NE prop_val
391 $$ = expr_complex( ctx, $1, OP_NE, $3 );
392 if (!$$)
393 YYABORT;
395 | prop_val TK_LIKE string_val
397 $$ = expr_complex( ctx, $1, OP_LIKE, $3 );
398 if (!$$)
399 YYABORT;
401 | prop_val TK_IS TK_NULL
403 $$ = expr_unary( ctx, $1, OP_ISNULL );
404 if (!$$)
405 YYABORT;
407 | prop_val TK_IS TK_NOT TK_NULL
409 $$ = expr_unary( ctx, $1, OP_NOTNULL );
410 if (!$$)
411 YYABORT;
415 string_val:
416 TK_STRING
418 $$ = expr_sval( ctx, &$1 );
419 if (!$$)
420 YYABORT;
424 prop_val:
425 prop
427 $$ = expr_propval( ctx, $1 );
428 if (!$$)
429 YYABORT;
433 const_val:
434 number
436 $$ = expr_ival( ctx, $1 );
437 if (!$$)
438 YYABORT;
440 | TK_STRING
442 $$ = expr_sval( ctx, &$1 );
443 if (!$$)
444 YYABORT;
446 | TK_TRUE
448 $$ = expr_bval( ctx, -1 );
449 if (!$$)
450 YYABORT;
452 | TK_FALSE
454 $$ = expr_bval( ctx, 0 );
455 if (!$$)
456 YYABORT;
462 HRESULT parse_query( const WCHAR *str, struct view **view, struct list *mem )
464 struct parser parser;
465 int ret;
467 *view = NULL;
469 parser.cmd = str;
470 parser.idx = 0;
471 parser.len = 0;
472 parser.error = WBEM_E_INVALID_QUERY;
473 parser.view = view;
474 parser.mem = mem;
476 ret = wql_parse( &parser );
477 TRACE("wql_parse returned %d\n", ret);
478 if (ret)
480 if (*parser.view)
482 destroy_view( *parser.view );
483 *parser.view = NULL;
485 return parser.error;
487 return S_OK;
490 static const char id_char[] =
492 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
493 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
494 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
495 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
496 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
497 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
498 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
499 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
500 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
501 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
502 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
503 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
504 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
505 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
506 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
507 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
510 struct keyword
512 const WCHAR *name;
513 unsigned int len;
514 int type;
517 #define MAX_TOKEN_LEN 6
519 static const WCHAR andW[] = {'A','N','D'};
520 static const WCHAR byW[] = {'B','Y'};
521 static const WCHAR falseW[] = {'F','A','L','S','E'};
522 static const WCHAR fromW[] = {'F','R','O','M'};
523 static const WCHAR isW[] = {'I','S'};
524 static const WCHAR likeW[] = {'L','I','K','E'};
525 static const WCHAR notW[] = {'N','O','T'};
526 static const WCHAR nullW[] = {'N','U','L','L'};
527 static const WCHAR orW[] = {'O','R'};
528 static const WCHAR selectW[] = {'S','E','L','E','C','T'};
529 static const WCHAR trueW[] = {'T','R','U','E'};
530 static const WCHAR whereW[] = {'W','H','E','R','E'};
532 static const struct keyword keyword_table[] =
534 { andW, SIZEOF(andW), TK_AND },
535 { byW, SIZEOF(byW), TK_BY },
536 { falseW, SIZEOF(falseW), TK_FALSE },
537 { fromW, SIZEOF(fromW), TK_FROM },
538 { isW, SIZEOF(isW), TK_IS },
539 { likeW, SIZEOF(likeW), TK_LIKE },
540 { notW, SIZEOF(notW), TK_NOT },
541 { nullW, SIZEOF(nullW), TK_NULL },
542 { orW, SIZEOF(orW), TK_OR },
543 { selectW, SIZEOF(selectW), TK_SELECT },
544 { trueW, SIZEOF(trueW), TK_TRUE },
545 { whereW, SIZEOF(whereW), TK_WHERE }
548 static int cmp_keyword( const void *arg1, const void *arg2 )
550 const struct keyword *key1 = arg1, *key2 = arg2;
551 int len = min( key1->len, key2->len );
552 int ret;
554 if ((ret = memicmpW( key1->name, key2->name, len ))) return ret;
555 if (key1->len < key2->len) return -1;
556 else if (key1->len > key2->len) return 1;
557 return 0;
560 static int keyword_type( const WCHAR *str, unsigned int len )
562 struct keyword key, *ret;
564 if (len > MAX_TOKEN_LEN) return TK_ID;
566 key.name = str;
567 key.len = len;
568 key.type = 0;
569 ret = bsearch( &key, keyword_table, SIZEOF(keyword_table), sizeof(struct keyword), cmp_keyword );
570 if (ret) return ret->type;
571 return TK_ID;
574 static int get_token( const WCHAR *s, int *token )
576 int i;
578 switch (*s)
580 case ' ':
581 case '\t':
582 case '\n':
583 for (i = 1; isspaceW( s[i] ); i++) {}
584 *token = TK_SPACE;
585 return i;
586 case '-':
587 if (!s[1]) return -1;
588 *token = TK_MINUS;
589 return 1;
590 case '(':
591 *token = TK_LP;
592 return 1;
593 case ')':
594 *token = TK_RP;
595 return 1;
596 case '*':
597 *token = TK_STAR;
598 return 1;
599 case '=':
600 *token = TK_EQ;
601 return 1;
602 case '<':
603 if (s[1] == '=' )
605 *token = TK_LE;
606 return 2;
608 else if (s[1] == '>')
610 *token = TK_NE;
611 return 2;
613 else
615 *token = TK_LT;
616 return 1;
618 case '>':
619 if (s[1] == '=')
621 *token = TK_GE;
622 return 2;
624 else
626 *token = TK_GT;
627 return 1;
629 case '!':
630 if (s[1] != '=')
632 *token = TK_ILLEGAL;
633 return 2;
635 else
637 *token = TK_NE;
638 return 2;
640 case ',':
641 *token = TK_COMMA;
642 return 1;
643 case '\"':
644 case '\'':
646 for (i = 1; s[i]; i++)
648 if (s[i] == s[0]) break;
650 if (s[i]) i++;
651 *token = TK_STRING;
652 return i;
654 case '.':
655 if (!isdigitW( s[1] ))
657 *token = TK_DOT;
658 return 1;
660 /* fall through */
661 case '0': case '1': case '2': case '3': case '4':
662 case '5': case '6': case '7': case '8': case '9':
663 *token = TK_INTEGER;
664 for (i = 1; isdigitW( s[i] ); i++) {}
665 return i;
666 default:
667 if (!id_char[*s]) break;
669 for (i = 1; id_char[s[i]]; i++) {}
670 *token = keyword_type( s, i );
671 return i;
673 *token = TK_ILLEGAL;
674 return 1;
677 static int wql_lex( void *p, struct parser *parser )
679 struct string *str = p;
680 int token = -1;
683 parser->idx += parser->len;
684 if (!parser->cmd[parser->idx]) return 0;
685 parser->len = get_token( &parser->cmd[parser->idx], &token );
686 if (!parser->len) break;
688 str->data = &parser->cmd[parser->idx];
689 str->len = parser->len;
690 } while (token == TK_SPACE);
691 return token;
694 static int wql_error( const char *str )
696 ERR("%s\n", str);
697 return 0;