1 /***********************************************************************
2 * $Id$
3 * Copyright 2009 Aplix Corporation. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 *
14 * Hand-crafted recursive descent parser for Web IDL grammar.
15 ***********************************************************************/
16 #include <assert.h>
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include "comment.h"
22 #include "lex.h"
23 #include "misc.h"
24 #include "node.h"
25 #include "parse.h"
26
27 /***********************************************************************
28 * tokerrorexit : error and exit with line number from token
29 */
30 static void
tokerrorexit(struct tok * tok,const char * format,...)31 tokerrorexit(struct tok *tok, const char *format, ...)
32 {
33 va_list ap;
34 char *m;
35 va_start(ap, format);
36 m = vmemprintf(format, ap);
37 if (tok->type == TOK_EOF)
38 locerrorexit(tok->filename, tok->linenum, "at end of input: %s", m);
39 else
40 locerrorexit(tok->filename, tok->linenum, "at '%.*s': %s", tok->len, tok->start, m);
41 va_end(ap);
42 }
43
44 /***********************************************************************
45 * lexnocomment : lex next token, discarding or storing comments
46 *
47 * A block comment starting with |** or |*! is a doxygen comment.
48 * If it starts with |**< or |*!< then it refers to the previous
49 * identifier, not the next one. (I am using | to represent / otherwise
50 * this comment would be illegal.)
51 *
52 * An inline comment starting with /// or //! is a doxygen comment.
53 * If it starts with ///< or //!< then it refers to the previous
54 * identifier, not the next one.
55 */
56 static struct tok *
lexnocomment(void)57 lexnocomment(void)
58 {
59 struct tok *tok;
60 for (;;) {
61 tok = lex();
62 if (tok->type != TOK_BLOCKCOMMENT && tok->type != TOK_INLINECOMMENT)
63 break;
64 addcomment(tok);
65 }
66 return tok;
67 }
68
69 /***********************************************************************
70 * eat : check token then read the following one
71 *
72 * Enter: tok struct
73 * type = type of token expected, error given if no match
74 *
75 * On return, tok is updated to the following token.
76 */
77 static void
eat(struct tok * tok,int type)78 eat(struct tok *tok, int type)
79 {
80 if (tok->type != type) {
81 const char *p;
82 if (type < TOK_DOMString)
83 tokerrorexit(tok, "expected '%c'", type);
84 p = keywords;
85 while (type != TOK_DOMString) {
86 p += strlen(p) + 1;
87 type--;
88 }
89 tokerrorexit(tok, "expected '%s'", p);
90 }
91 lexnocomment();
92 }
93
94 /***********************************************************************
95 * setid : flag that an id attribute is required on node
96 *
97 * Enter: node
98 *
99 * node->id is set to the value of the name attribute. This makes
100 * outputnode give it an id attribute whose value is the id attribute
101 * of the parent if any, then "::", then node->id.
102 */
103 static void
setid(struct node * node)104 setid(struct node *node)
105 {
106 node->id = getattr(node, "name");
107 }
108
109 /***********************************************************************
110 * setidentifier : allocate 0-terminated string for identifier token
111 *
112 * Enter: tok = token, error given if not identifier
113 *
114 * Return: allocated 0-terminated string
115 */
116 static char *
setidentifier(struct tok * tok)117 setidentifier(struct tok *tok)
118 {
119 char *s;
120 if (tok->type != TOK_IDENTIFIER)
121 tokerrorexit(tok, "expected identifier");
122 s = memprintf("%.*s", tok->len, tok->start);
123 return s;
124 }
125
126 /***********************************************************************
127 * setargumentname : allocate 0-terminated string for identifier token
128 *
129 * Enter: tok = token, error given if not identifier
130 *
131 * Return: allocated 0-terminated string
132 */
133 static char *
setargumentname(struct tok * tok)134 setargumentname(struct tok *tok)
135 {
136 char *s;
137 if (tok->type != TOK_IDENTIFIER && tok->type < TOK_attribute)
138 tokerrorexit(tok, "expected argument name");
139 s = memprintf("%.*s", tok->len, tok->start);
140 return s;
141 }
142
143
144 /* Prototypes for funcs that have a forward reference. */
145 static struct node *parsetype(struct tok *tok);
146 static struct node *parsedefaultvalue(struct tok *tok, struct node *parent);
147 static struct node *parseuniontype(struct tok *tok);
148 static struct node *parseargumentlist(struct tok *tok);
149 static void parsedefinitions(struct tok *tok, struct node *parent);
150 static struct node *parsetypesuffixstartingwitharray(struct tok *tok, struct node *node);
151
152 /***********************************************************************
153 * parsescopedname : parse [53] ScopedName
154 *
155 * Enter: tok = next token
156 * name = name of attribute to put scoped name in
157 * ref = whether to enable enclosing of the name in <ref> in
158 * outputwidl
159 *
160 * Return: node struct for new attribute
161 * tok updated
162 */
163 static struct node *
parsescopedname(struct tok * tok,const char * name,int ref)164 parsescopedname(struct tok *tok, const char *name, int ref)
165 {
166 const char *start = tok->start, *end;
167 struct node *node;
168 unsigned int len = 0;
169 char *s = memalloc(3);
170 if (tok->type != TOK_IDENTIFIER)
171 tokerrorexit(tok, "expected identifier");
172 s = memrealloc(s, len + tok->len + 1);
173 memcpy(s + len, tok->start, tok->len);
174 len += tok->len;
175 end = tok->start + tok->len;
176 lexnocomment();
177 s[len] = 0;
178 node = newattr(name, s);
179 if (ref) {
180 node->start = start;
181 node->end = end;
182 }
183 return node;
184 }
185
186 /***********************************************************************
187 * parsescopednamelist : parse [51] ScopedNameList
188 *
189 * Enter: tok = next token
190 * name = name of element for scoped name list
191 * name2 = name of element for entry in list
192 * comment = whether to attach documentation to each name
193 *
194 * Return: node for list of scoped names
195 * tok updated
196 */
197 static struct node *
parsescopednamelist(struct tok * tok,const char * name,const char * name2,int comment)198 parsescopednamelist(struct tok *tok, const char *name, const char *name2,
199 int comment)
200 {
201 struct node *node = newelement(name);
202 for (;;) {
203 struct node *attr = parsescopedname(tok, "name", 1);
204 struct node *n = newelement(name2);
205 if (comment)
206 setcommentnode(n);
207 addnode(n, attr);
208 addnode(node, n);
209 if (tok->type != ',')
210 break;
211 lexnocomment();
212 }
213 return node;
214 }
215
216 /***********************************************************************
217 * parsereturntype : parse [50] ReturnType
218 *
219 * Enter: tok = next token
220 *
221 * Return: node for type
222 * tok updated
223 */
224 static struct node *
parsereturntype(struct tok * tok)225 parsereturntype(struct tok *tok)
226 {
227 if (tok->type == TOK_void) {
228 struct node *node = newelement("Type");
229 addnode(node, newattr("type", "void"));
230 lexnocomment();
231 return node;
232 }
233 return parsetype(tok);
234 }
235
236 /***********************************************************************
237 * parseunsignedintegertype : parse [46] UnsignedIntegerType
238 *
239 * Enter: tok = next token (one of "unsigned", "short" or "long")
240 *
241 * Return: 0-terminated canonical string for the type
242 * tok updated to just past UnsignedIntegerType
243 */
244 static const char *
parseunsignedintegertype(struct tok * tok)245 parseunsignedintegertype(struct tok *tok)
246 {
247 static const char *names[] = {
248 "short", "long", "long long", 0,
249 "unsigned short", "unsigned long", "unsigned long long" };
250 enum { TYPE_SHORT, TYPE_LONG, TYPE_LONGLONG,
251 TYPE_UNSIGNED = 4 };
252 int type = 0;
253 if (tok->type == TOK_unsigned) {
254 type = TYPE_UNSIGNED;
255 lexnocomment();
256 }
257 if (tok->type == TOK_short) {
258 type |= TYPE_SHORT;
259 lexnocomment();
260 } else if (tok->type != TOK_long)
261 tokerrorexit(tok, "expected 'short' or 'long' after 'unsigned'");
262 else {
263 type |= TYPE_LONG;
264 lexnocomment();
265 if (tok->type == TOK_long) {
266 type += TYPE_LONGLONG - TYPE_LONG;
267 lexnocomment();
268 }
269 }
270 return names[type];
271 }
272 /***********************************************************************
273 * parsetypesuffix : parse [44] TypeSuffix
274 *
275 * Enter: tok = next token
276 *
277 * Return: node for type
278 * tok updated
279 */
280 static struct node *
parsetypesuffix(struct tok * tok,struct node * node)281 parsetypesuffix(struct tok *tok, struct node *node)
282 {
283 if (tok->type == TOK_DOUBLEBRACKET) {
284 struct node *typenode = node;
285 node = newelement("Type");
286 addnode(node, newattr("type", "array"));
287 addnode(node, typenode);
288 lexnocomment();
289 node = parsetypesuffix(tok, node);
290 } else if (tok->type == '?') {
291 addnode(node, newattr("nullable", "nullable"));
292 lexnocomment();
293 node = parsetypesuffixstartingwitharray(tok, node);
294 }
295 return node;
296 }
297
298 /***********************************************************************
299 * parsetypesuffixstartingwitharray : parse [44] TypeSuffixStartingWithArray
300 *
301 * Enter: tok = next token
302 *
303 * Return: node for type
304 * tok updated
305 */
306 static struct node *
parsetypesuffixstartingwitharray(struct tok * tok,struct node * node)307 parsetypesuffixstartingwitharray(struct tok *tok, struct node *node)
308 {
309 if (tok->type == TOK_DOUBLEBRACKET) {
310 struct node *typenode = node;
311 node = newelement("Type");
312 addnode(node, newattr("type", "array"));
313 addnode(node, typenode);
314 lexnocomment();
315 node = parsetypesuffix(tok, node);
316 }
317 return node;
318 }
319
320 /***********************************************************************
321 * parseprimitiveorstringtype : parse [45] PrimitiveOrString
322 *
323 * Enter: tok = next token
324 *
325 * Return: node for type
326 * tok updated
327 */
328 static struct node *
parseprimitiveorstringtype(struct tok * tok)329 parseprimitiveorstringtype(struct tok *tok)
330 {
331 struct node *node;
332 switch (tok->type) {
333 case TOK_unsigned:
334 case TOK_short:
335 case TOK_long:
336 node = newelement("Type");
337 addnode(node, newattr("type", parseunsignedintegertype(tok)));
338 break;
339 default:
340 node = newelement("Type");
341 switch (tok->type) {
342 default:
343 tokerrorexit(tok, "expected type");
344 break;
345 case TOK_unrestricted:
346 lexnocomment();
347 if (tok->type == TOK_float) {
348 addnode(node, newattr("type", "unrestricted float"));
349 } else if (tok->type == TOK_double) {
350 addnode(node, newattr("type", "unrestricted double"));
351 } else {
352 tokerrorexit(tok, "expected float or double after unrestricted");
353 }
354 break;
355 case TOK_boolean:
356 addnode(node, newattr("type", "boolean"));
357 break;
358 case TOK_byte:
359 addnode(node, newattr("type", "byte"));
360 break;
361 case TOK_octet:
362 addnode(node, newattr("type", "octet"));
363 break;
364 case TOK_float:
365 addnode(node, newattr("type", "float"));
366 break;
367 case TOK_double:
368 addnode(node, newattr("type", "double"));
369 break;
370 case TOK_DOMString:
371 addnode(node, newattr("type", "DOMString"));
372 break;
373 case TOK_ByteString:
374 addnode(node, newattr("type", "ByteString"));
375 break;
376 case TOK_Date:
377 addnode(node, newattr("type", "Date"));
378 break;
379 case TOK_RegExp:
380 addnode(node, newattr("type", "RegExp"));
381 break;
382
383 }
384 lexnocomment();
385 }
386 return node;
387 }
388
389 /***********************************************************************
390 * parsenonanytype : parse NonAnyType
391 *
392 * Enter: tok = next token
393 *
394 * Return: node for type
395 * tok updated
396 */
397 static struct node *
parsenonanytype(struct tok * tok)398 parsenonanytype(struct tok *tok)
399 {
400 struct node *node;
401 switch (tok->type) {
402 case TOK_IDENTIFIER:
403 node = newelement("Type");
404 addnode(node, parsescopedname(tok, "name", 1));
405 node = parsetypesuffix(tok, node);
406 break;
407 case TOK_sequence:
408 node = newelement("Type");
409 addnode(node, newattr("type", "sequence"));
410 lexnocomment();
411 eat(tok, '<');
412 addnode(node, parsetype(tok));
413 eat(tok, '>');
414 if (tok->type == '?') {
415 addnode(node, newattr("nullable", "nullable"));
416 lexnocomment();
417 }
418 break;
419 case TOK_object:
420 node = newelement("Type");
421 addnode(node, newattr("type", "object"));
422 lexnocomment();
423 node = parsetypesuffix(tok, node);
424 break;
425 default:
426 node = parseprimitiveorstringtype(tok);
427 node = parsetypesuffix(tok, node);
428 break;
429 }
430 return node;
431 }
432
433 /***********************************************************************
434 * parseunionmembertype: parse UnionMemberType
435 *
436 * Enter: tok = next token
437 *
438 * Return: node for type
439 * tok updated
440 */
441 static struct node *
parseunionmembertype(struct tok * tok)442 parseunionmembertype(struct tok *tok)
443 {
444 struct node *node;
445 if (tok->type == TOK_any) {
446 struct node *typenode = newelement("Type");
447 addnode(typenode, newattr("type", "any"));
448 lexnocomment();
449 eat(tok, TOK_DOUBLEBRACKET);
450 node = newelement("Type");
451 addnode(node, newattr("type", "array"));
452 addnode(node, typenode);
453 lexnocomment();
454 node = parsetypesuffix(tok, node);
455 } else if (tok->type == '(') {
456 node = parseuniontype(tok);
457 } else {
458 node = parsenonanytype(tok);
459 }
460 return node;
461 }
462
463
464 /***********************************************************************
465 * parseuniontype : parse UnionType
466 *
467 * Enter: tok = next token
468 *
469 * Return: node for type
470 * tok updated
471 */
472 static struct node *
parseuniontype(struct tok * tok)473 parseuniontype(struct tok *tok)
474 {
475 struct node *node;
476 eat(tok, '(');
477 node = newelement("Type");
478 addnode(node, newattr("type", "union"));
479 if (tok->type != ')') {
480 for (;;) {
481 addnode(node, parseunionmembertype(tok));
482 if (tok->type != TOK_or)
483 break;
484 lexnocomment();
485 }
486 }
487 eat(tok, ')');
488 node = parsetypesuffix(tok, node);
489 return node;
490 }
491
492 /***********************************************************************
493 * parsetype : parse [44] Type
494 *
495 * Enter: tok = next token
496 *
497 * Return: node for type
498 * tok updated
499 */
500 static struct node *
parsetype(struct tok * tok)501 parsetype(struct tok *tok)
502 {
503 struct node *node;
504 if (tok->type == '(') {
505 node = parseuniontype(tok);
506 } else if (tok->type == TOK_any) {
507 node = newelement("Type");
508 addnode(node, newattr("type", "any"));
509 lexnocomment();
510 node = parsetypesuffixstartingwitharray(tok, node);
511 } else {
512 node = parsenonanytype(tok);
513 }
514 return node;
515 }
516
517
518 /***********************************************************************
519 * parseextendedattribute : parse [39] ExtendedAttribute
520 *
521 * Enter: tok = next token
522 *
523 * Return: node for extended attribute
524 *
525 * This parses the various forms of extended attribute, as in
526 * rules [57] [58] [59] [60] [61].
527 *
528 * This does not spot the error that you cannot have a ScopedName
529 * and an ArgumentList.
530 */
531 static struct node *
parseextendedattribute(struct tok * tok)532 parseextendedattribute(struct tok *tok)
533 {
534 const char *start ;
535 struct node *node = newelement("ExtendedAttribute");
536 char *attrname = setidentifier(tok);
537 addnode(node, newattr("name", attrname));
538 start = tok->prestart;
539 node->wsstart = start;
540 node->end = tok->start + tok->len;
541 if(!strcmp(attrname, "Constructor") || !strcmp(attrname, "NamedConstructor")) {
542 setcommentnode(node);
543 }
544 lexnocomment();
545 if (tok->type == '=') {
546 lexnocomment();
547 addnode(node, parsescopedname(tok, "value", 0));
548 }
549 if (tok->type == '(') {
550 lexnocomment();
551 addnode(node, parseargumentlist(tok));
552 node->end = tok->start + tok->len;
553 eat(tok, ')');
554 }
555 return node;
556 }
557
558 /***********************************************************************
559 * parseextendedattributelist : parse [37] ExtendedAttributeList
560 *
561 * Enter: tok = next token
562 *
563 * Return: 0 else node for extended attribute list
564 * tok updated if anything parsed
565 */
566 static struct node *
parseextendedattributelist(struct tok * tok)567 parseextendedattributelist(struct tok *tok)
568 {
569 struct node *node;
570 if (tok->type != '[')
571 return 0;
572 node = newelement("ExtendedAttributeList");
573 for (;;) {
574 lexnocomment();
575 addnode(node, parseextendedattribute(tok));
576 if (tok->type != ',')
577 break;
578 }
579 if (tok->type != ']')
580 tokerrorexit(tok, "expected ',' or ']'");
581 lexnocomment();
582 return node;
583 }
584
585 /***********************************************************************
586 * parseexceptionfield : parse [36] ExceptionField
587 *
588 * Enter: tok = next token
589 * eal = 0 else extended attribute list node
590 *
591 * Return: new node for the exceptionfield
592 * tok updated
593 */
594 static struct node *
parseexceptionfield(struct tok * tok,struct node * eal)595 parseexceptionfield(struct tok *tok, struct node *eal)
596 {
597 struct node *node = newelement("ExceptionField");
598 if (eal) addnode(node, eal);
599 setcommentnode(node);
600 addnode(node, parsetype(tok));
601 addnode(node, newattr("name", setidentifier(tok)));
602 tok = lexnocomment();
603 return node;
604 }
605
606 /***********************************************************************
607 * parseargument : parse [31] Argument
608 *
609 * Enter: tok = next token
610 *
611 * Return: new node
612 *
613 * tok updated on return
614 */
615 static struct node *
parseargument(struct tok * tok)616 parseargument(struct tok *tok)
617 {
618 struct node *node = newelement("Argument");
619 struct node *eal = parseextendedattributelist(tok);
620 setcommentnode(node);
621 if (eal) addnode(node, eal);
622 if (tok->type == TOK_optional) {
623 addnode(node, newattr("optional", "optional"));
624 lexnocomment();
625 }
626 addnode(node, parsetype(tok));
627 if (tok->type == TOK_ELLIPSIS) {
628 addnode(node, newattr("ellipsis", "ellipsis"));
629 lexnocomment();
630 }
631 addnode(node, newattr("name", setargumentname(tok)));
632 lexnocomment();
633 // Optional default value
634 if (tok->type == '=') {
635 tok = lexnocomment();
636 node = parsedefaultvalue(tok, node);
637 }
638 return node;
639 }
640
641 /***********************************************************************
642 * parseargumentlist : parse [29] ArgumentList
643 *
644 * Enter: tok = next token
645 *
646 * Return: new node for the arglist
647 * tok updated
648 */
649 static struct node *
parseargumentlist(struct tok * tok)650 parseargumentlist(struct tok *tok)
651 {
652 struct node *node = newelement("ArgumentList");
653 /* We rely on the fact that ArgumentList is always followed by ')'. */
654 if (tok->type != ')') {
655 for (;;) {
656 addnode(node, parseargument(tok));
657 if (tok->type != ',')
658 break;
659 lexnocomment();
660 }
661 }
662 return node;
663 }
664
665
666 /***********************************************************************
667 * parseoperationrest : parse [25] OperationRest
668 *
669 * Enter: tok = next token
670 * node
671 *
672 * Return: node
673 * tok on terminating ';'
674 */
675 static struct node *
parseoperationrest(struct tok * tok,struct node * node)676 parseoperationrest(struct tok *tok, struct node *node)
677 {
678 if (tok->type == TOK_IDENTIFIER) {
679 addnode(node, newattr("name", setidentifier(tok)));
680 lexnocomment();
681 }
682 eat(tok, '(');
683 addnode(node, parseargumentlist(tok));
684 eat(tok, ')');
685 return node;
686 }
687
688 /***********************************************************************
689 * parsereturntypeandoperationrest: parse ReturnType OperationRest
690 * Enter: tok = next token
691 * eal
692 * attrs list of attributes
693 * Return: node
694 * tok on terminating ';'
695 */
696 static struct node *
parsereturntypeandoperationrest(struct tok * tok,struct node * eal,struct node * attrs)697 parsereturntypeandoperationrest(struct tok *tok, struct node *eal, struct node *attrs)
698 {
699 struct node *node = newelement("Operation");
700 struct node *nodeType = parsereturntype(tok);
701 if (eal) addnode(node, eal);
702 setcommentnode(node);
703 addnode(node, attrs);
704 addnode(node, nodeType);
705 return parseoperationrest(tok, node);
706 }
707
708 /***********************************************************************
709 * parseiteratorrest : parse OptionalIteratorInterface
710 *
711 * Enter: tok = next token
712 * node
713 *
714 * Return: node
715 * tok on terminating ';'
716 */
717 static struct node *
parseoptionaliteratorinterface(struct tok * tok,struct node * node)718 parseoptionaliteratorinterface(struct tok *tok, struct node *node)
719 {
720 if (tok->type == '=') {
721 lexnocomment();
722 addnode(node, newattr("interface", setidentifier(tok)));
723 lexnocomment();
724 }
725 return node;
726 }
727
728 /***********************************************************************
729 * parseoperationoriteratorrest : parse [25] OperationOrIteratorRest
730 *
731 * Enter: tok = next token
732 * eal = 0 else extended attribute list node
733 * attrs = list-of-attrs node containing attrs to add to new node
734 *
735 * Return: new node
736 * tok on terminating ';'
737 */
738 static struct node *
parseoperationoriteratorrest(struct tok * tok,struct node * eal,struct node * attrs)739 parseoperationoriteratorrest(struct tok *tok, struct node *eal, struct node *attrs)
740 {
741 struct node *node;
742 struct node *nodeType = parsereturntype(tok);
743 unsigned int isIterator = 0;
744 if (tok->type == TOK_iterator) {
745 lexnocomment();
746 if (tok->type == TOK_object) {
747 lexnocomment();
748 node = newelement("IteratorObject");
749 addnode(node, nodeType);
750 return node;
751 } else {
752 node = newelement("Iterator");
753 isIterator = 1;
754 }
755 } else {
756 node = newelement("Operation");
757 }
758 if (eal) addnode(node, eal);
759 setcommentnode(node);
760 addnode(node, attrs);
761 addnode(node, nodeType);
762 if (isIterator)
763 return parseoptionaliteratorinterface(tok, node);
764 else
765 return parseoperationrest(tok, node);
766 }
767
768
769 /***********************************************************************
770 * parseattribute : parse [17] Attribute
771 *
772 * Enter: tok = next token ("readonly" or "attribute")
773 * eal = 0 else extended attribute list node
774 * attrs = list-of-attrs node containing attrs to add to new node
775 *
776 * Return: node
777 * tok on terminating ';'
778 */
779 static struct node *
parseattribute(struct tok * tok,struct node * eal,struct node * attrs)780 parseattribute(struct tok *tok, struct node *eal, struct node *attrs)
781 {
782 struct node *node = newelement("Attribute");
783 if (eal) addnode(node, eal);
784 setcommentnode(node);
785 addnode(node, attrs);
786 if (tok->type == TOK_inherit) {
787 lexnocomment();
788 addnode(node, newattr("inherit", "inherit"));
789 }
790 if (tok->type == TOK_readonly) {
791 lexnocomment();
792 addnode(node, newattr("readonly", "readonly"));
793 }
794 eat(tok, TOK_attribute);
795 addnode(node, parsetype(tok));
796 addnode(node, newattr("name", setidentifier(tok)));
797 lexnocomment();
798 return node;
799 }
800
801 /***********************************************************************
802 * parseserializer : parse Serializer
803 *
804 * Enter: tok = next token
805 * eal
806 *
807 * Return: node updated with value
808 * tok updated
809 */
810 static struct node *
parseserializer(struct tok * tok,struct node * eal)811 parseserializer (struct tok *tok, struct node *eal) {
812 struct node *nodeAttribute;
813 struct node *node = newelement("Serializer");
814 if (tok->type == '=') {
815 if (eal) addnode(node, eal);
816 lexnocomment();
817 if (tok->type == TOK_IDENTIFIER) {
818 addnode(node, newattr("attribute", setidentifier(tok)));
819 lexnocomment();
820 } else if (tok->type == '{') {
821 unsigned int done = 0;
822 struct node *nodeMap = newelement("Map");
823 lexnocomment();
824 if (tok->type == TOK_getter) {
825 addnode(nodeMap, newattr("pattern", "getter"));
826 done = 1;
827 } else if (tok->type == TOK_attribute) {
828 addnode(nodeMap, newattr("pattern", "all"));
829 done = 1;
830 } else if (tok->type == TOK_inherit) {
831 addnode(nodeMap, newattr("inherit", "inherit"));
832 lexnocomment();
833 eat(tok, ',');
834 if (tok->type == TOK_attribute) {
835 addnode(nodeMap, newattr("pattern", "all"));
836 done = 1;
837 }
838 } else if (tok->type != TOK_IDENTIFIER) {
839 tokerrorexit(tok, "expected 'attribute', 'getter', 'inherit' or attribute identifiers in serializer map");
840 }
841 if (done) {
842 lexnocomment();
843 eat(tok, '}');
844 } else {
845 addnode(nodeMap, newattr("pattern", "selection"));
846 do {
847 if (tok->type != TOK_IDENTIFIER)
848 tokerrorexit(tok, "expected attribute identifiers in serializer map %s", tok->prestart);
849 nodeAttribute = newelement("PatternAttribute");
850 addnode(nodeAttribute, newattr("name", setidentifier(tok)));
851 addnode(nodeMap, nodeAttribute);
852 lexnocomment();
853 if (tok->type == ',')
854 lexnocomment();
855 } while (tok->type != '}');
856 eat(tok, '}');
857 }
858 addnode(node, nodeMap);
859 } else if (tok->type == '[') {
860 struct node *nodeList = newelement("List");
861 lexnocomment();
862 if (tok->type == TOK_getter) {
863 addnode(nodeList, newattr("pattern", "getter"));
864 lexnocomment();
865 eat(tok, ']');
866 } else {
867 addnode(nodeList, newattr("pattern", "selection"));
868 do {
869 if (tok->type != TOK_IDENTIFIER)
870 tokerrorexit(tok, "expected attribute identifiers in serializer list");
871 nodeAttribute = newelement("PatternAttribute");
872 addnode(nodeAttribute, newattr("name", setidentifier(tok)));
873 addnode(nodeList, nodeAttribute);
874 lexnocomment();
875 if (tok->type == ',')
876 lexnocomment();
877 } while (tok->type != ']');
878 eat(tok, ']');
879 }
880 addnode(node, nodeList);
881 } else {
882 tokerrorexit(tok, "Expected '{', '[' or an attribute identifier in the serializer declaration");
883 }
884 return node;
885 } else {
886 if (eal) addnode(node, eal);
887 return node;
888 }
889 }
890
891 /***********************************************************************
892 * parseattributeoroperationoriterator : parse [15] AttributeOrOperationOrIterator
893 *
894 * Enter: tok = next token
895 * eal = 0 else extended attribute list node
896 *
897 * Return: new node
898 * tok on terminating ';'
899 */
900 static struct node *
parseattributeoroperationoriterator(struct tok * tok,struct node * eal)901 parseattributeoroperationoriterator(struct tok *tok, struct node *eal)
902 {
903 int alreadyseen ;
904 struct node *attrs = newattrlist();
905 if (tok->type == TOK_serializer) {
906 lexnocomment();
907 if (tok->type == '=' || tok->type ==';') {
908 return parseserializer(tok, eal);
909 } else {
910 addnode(attrs, newattr("serializer", "serializer"));
911 return parsereturntypeandoperationrest(tok, eal, attrs);
912 }
913 }
914 if (tok->type == TOK_stringifier) {
915 addnode(attrs, newattr("stringifier", "stringifier"));
916 lexnocomment();
917 if (tok->type == ';') {
918 struct node *node = newelement("Stringifier");
919 if (eal) addnode(node, eal);
920 return node;
921 }
922 }
923 if (tok->type == TOK_static) {
924 lexnocomment();
925 addnode(attrs, newattr("static", "static"));
926 }
927 if (tok->type == TOK_inherit || tok->type == TOK_readonly || tok->type == TOK_attribute)
928 return parseattribute(tok, eal, attrs);
929 if (!nodeisempty(attrs))
930 return parsereturntypeandoperationrest(tok, eal, attrs);
931 alreadyseen = 0;
932 for (;;) {
933 static const int t[] = { TOK_getter,
934 TOK_setter, TOK_creator, TOK_deleter, TOK_legacycaller,
935 0 };
936 const int *tt = t;
937 char *s;
938 while (*tt && *tt != tok->type)
939 tt++;
940 if (!*tt)
941 break;
942 s = memprintf("%.*s", tok->len, tok->start);
943 if (alreadyseen & (1 << (tt - t)))
944 tokerrorexit(tok, "'%s' qualifier cannot be repeated", s);
945 alreadyseen |= 1 << (tt - t);
946 addnode(attrs, newattr(s, s));
947 lexnocomment();
948 }
949 if (!nodeisempty(attrs))
950 return parsereturntypeandoperationrest(tok, eal, attrs);
951 else
952 return parseoperationoriteratorrest(tok, eal, attrs);
953 }
954
955
956 /***********************************************************************
957 * parseconstexpr : parse ConstValue
958 *
959 * Enter: tok = next token
960 * node
961 *
962 * Return: node updated with value
963 * tok updated
964 */
965 static struct node *
parseconstexpr(struct tok * tok,struct node * node)966 parseconstexpr (struct tok *tok, struct node *node) {
967 char *s;
968 switch(tok->type) {
969 case TOK_true:
970 case TOK_false:
971 case TOK_minusinfinity:
972 case TOK_INTEGER:
973 case TOK_FLOAT:
974 case TOK_null:
975 case TOK_infinity:
976 case TOK_NaN:
977 break;
978 default:
979 tokerrorexit(tok, "expected constant value");
980 break;
981 }
982 s = memalloc(tok->len + 1);
983 memcpy(s, tok->start, tok->len);
984 s[tok->len] = 0;
985 if (tok->type != TOK_STRING) {
986 addnode(node, newattr("value", s));
987 } else {
988 addnode(node, newattr("stringvalue", s));
989 }
990 lexnocomment();
991 return node;
992 }
993
994 /***********************************************************************
995 * parsedefaultvalue : parse DefaultValue
996 *
997 * Enter: tok = next token
998 * node
999 *
1000 * Return: node updated with value
1001 * tok updated
1002 */
1003 static struct node *
parsedefaultvalue(struct tok * tok,struct node * node)1004 parsedefaultvalue (struct tok *tok, struct node *node) {
1005 char *s;
1006 if (tok->type == TOK_STRING) {
1007 s = memalloc(tok->len + 1);
1008 memcpy(s, tok->start, tok->len);
1009 s[tok->len] = 0;
1010 addnode(node, newattr("stringvalue", s));
1011 lexnocomment();
1012 return node;
1013 } else {
1014 return parseconstexpr(tok, node);
1015 }
1016 }
1017
1018
1019
1020 /***********************************************************************
1021 * parsedictionarymember : parse DictionaryMember
1022 *
1023 * Enter: tok = next token
1024 * eal = 0 else extended attribute list node
1025 *
1026 * Return: new node
1027 * tok on terminating ';'
1028 */
1029 static struct node *
parsedictionarymember(struct tok * tok,struct node * eal)1030 parsedictionarymember(struct tok *tok, struct node *eal)
1031 {
1032 struct node *node = newelement("DictionaryMember");
1033 if (eal) addnode(node, eal);
1034 setcommentnode(node);
1035 addnode(node, parsetype(tok));
1036 addnode(node, newattr("name", setidentifier(tok)));
1037 tok = lexnocomment();
1038 // Optional value
1039 if (tok->type == '=') {
1040 tok = lexnocomment();
1041 node = parsedefaultvalue(tok, node);
1042 }
1043 return node;
1044 }
1045
1046 /***********************************************************************
1047 * parseconst : parse [12] Const
1048 *
1049 * Enter: tok = next token, known to be TOK_const
1050 * eal = 0 else extended attribute list node
1051 *
1052 * Return: new node for the const
1053 * tok on terminating ';'
1054 */
1055 static struct node *
parseconst(struct tok * tok,struct node * eal)1056 parseconst(struct tok *tok, struct node *eal)
1057 {
1058 struct node *node = newelement("Const");
1059 setcommentnode(node);
1060 if (eal) addnode(node, eal);
1061 tok = lexnocomment();
1062 switch(tok->type) {
1063 case TOK_boolean:
1064 case TOK_byte:
1065 case TOK_octet:
1066 case TOK_float:
1067 case TOK_double:
1068 case TOK_unsigned:
1069 case TOK_unrestricted:
1070 case TOK_short:
1071 case TOK_long:
1072 addnode(node, parsetype(tok));
1073 break;
1074 default:
1075 tokerrorexit(tok, "expected acceptable constant type");
1076 break;
1077 }
1078 addnode(node, newattr("name", setidentifier(tok)));
1079 tok = lexnocomment();
1080 eat(tok, '=');
1081 node = parseconstexpr(tok, node);
1082 return node;
1083 }
1084
1085 /***********************************************************************
1086 * parseimplementsstatement : parse [11] ImplementsStatement
1087 *
1088 * Enter: tok = next token, known to be :: or TOK_IDENTIFIER
1089 * eal = 0 else extended attribute list node
1090 *
1091 * Return: new node for the typedef
1092 * tok updated to the terminating ';'
1093 */
1094 static struct node *
parseimplementsstatement(struct tok * tok,struct node * eal)1095 parseimplementsstatement(struct tok *tok, struct node *eal)
1096 {
1097 struct node *node = newelement("Implements");
1098 setcommentnode(node);
1099 if (eal) addnode(node, eal);
1100 addnode(node, parsescopedname(tok, "name1", 1));
1101 eat(tok, TOK_implements);
1102 addnode(node, parsescopedname(tok, "name2", 1));
1103 return node;
1104 }
1105
1106 /***********************************************************************
1107 * parsetypedef : parse [10] Typedef
1108 *
1109 * Enter: tok = next token, known to be TOK_typedef
1110 * eal = 0 else extended attribute list node
1111 *
1112 * Return: new node for the typedef
1113 * tok updated to the terminating ';'
1114 */
1115 static struct node *
parsetypedef(struct tok * tok,struct node * eal)1116 parsetypedef(struct tok *tok, struct node *eal)
1117 {
1118 struct node *ealtype;
1119 struct node *typenode;
1120 struct node *node = newelement("Typedef");
1121 setcommentnode(node);
1122 if (eal) addnode(node, eal);
1123 tok = lexnocomment();
1124 ealtype = parseextendedattributelist(tok);
1125 typenode = parsetype(tok);
1126 if (ealtype) addnode(typenode, ealtype);
1127 addnode(node, typenode);
1128 addnode(node, newattr("name", setidentifier(tok)));
1129 tok = lexnocomment();
1130 return node;
1131 }
1132
1133 /***********************************************************************
1134 * parseexception : parse [8] Exception
1135 *
1136 * Enter: tok = next token, known to be TOK_exception
1137 * eal = 0 else extended attribute list node
1138 *
1139 * Return: new node for the exception
1140 * tok updated to the terminating ';'
1141 */
1142 static struct node *
parseexception(struct tok * tok,struct node * eal)1143 parseexception(struct tok *tok, struct node *eal)
1144 {
1145 struct node *node = newelement("Exception");
1146 setcommentnode(node);
1147 if (eal) addnode(node, eal);
1148 tok = lexnocomment();
1149 addnode(node, newattr("name", setidentifier(tok)));
1150 lexnocomment();
1151 if (tok->type == ':') {
1152 lexnocomment();
1153 addnode(node, parsescopednamelist(tok, "ExceptionInheritance", "Name", 1));
1154 }
1155 eat(tok, '{');
1156 while (tok->type != '}') {
1157 const char *start = tok->prestart;
1158 struct node *node2;
1159 struct node *eal = parseextendedattributelist(tok);
1160 if (tok->type == TOK_const)
1161 node2 = parseconst(tok, eal);
1162 else
1163 node2 = parseexceptionfield(tok, eal);
1164 addnode(node, node2);
1165 node2->wsstart = start;
1166 node2->end = tok->start + tok->len;
1167 setid(node2);
1168 eat(tok, ';');
1169 }
1170 lexnocomment();
1171 return node;
1172 }
1173
1174 /***********************************************************************
1175 * parseinterface : parse [4] Interface
1176 *
1177 * Enter: tok = next token, known to be TOK_interface
1178 * eal = 0 else extended attribute list node
1179 *
1180 * Return: new node for the interface
1181 * tok updated to the terminating ';'
1182 */
1183 static struct node *
parseinterface(struct tok * tok,struct node * eal)1184 parseinterface(struct tok *tok, struct node *eal)
1185 {
1186 struct node *node = newelement("Interface");
1187 if (eal) addnode(node, eal);
1188 setcommentnode(node);
1189 tok = lexnocomment();
1190 addnode(node, newattr("name", setidentifier(tok)));
1191 tok = lexnocomment();
1192 if (tok->type == ':') {
1193 lexnocomment();
1194 addnode(node, parsescopednamelist(tok, "InterfaceInheritance", "Name", 1));
1195 }
1196 eat(tok, '{');
1197 while (tok->type != '}') {
1198 const char *start = tok->prestart;
1199 struct node *eal = parseextendedattributelist(tok);
1200 struct node *node2;
1201 if (tok->type == TOK_const)
1202 addnode(node, node2 = parseconst(tok, eal));
1203 else
1204 addnode(node, node2 = parseattributeoroperationoriterator(tok, eal));
1205 node2->wsstart = start;
1206 node2->end = tok->start + tok->len;
1207 setid(node2);
1208 eat(tok, ';');
1209 }
1210 lexnocomment();
1211 return node;
1212 }
1213
1214 /***********************************************************************
1215 * parsecallback : parse Callback
1216 *
1217 * Enter: tok = next token, known to be TOK_dictionary
1218 * eal = 0 else extended attribute list node
1219 *
1220 * Return: new node for the enum
1221 * tok updated to the terminating ';'
1222 */
1223 static struct node *
parsecallback(struct tok * tok,struct node * eal)1224 parsecallback(struct tok *tok, struct node *eal)
1225 {
1226 struct node *node;
1227 if (tok->type == TOK_interface) {
1228 node = parseinterface(tok, eal);
1229 addnode(node, newattr("callback", "callback"));
1230 } else {
1231 node = newelement("Callback");
1232 if (eal) addnode(node, eal);
1233 setcommentnode(node);
1234 addnode(node, newattr("name", setidentifier(tok)));
1235 tok = lexnocomment();
1236 eat(tok, '=');
1237 addnode(node, parsereturntype(tok));
1238 eat(tok, '(');
1239 addnode(node, parseargumentlist(tok));
1240 eat(tok, ')');
1241 }
1242 return node;
1243 }
1244
1245 /***********************************************************************
1246 * parsedictionary : parse Dictionary
1247 *
1248 * Enter: tok = next token, known to be TOK_dictionary
1249 * eal = 0 else extended attribute list node
1250 *
1251 * Return: new node for the dictionary
1252 * tok updated to the terminating ';'
1253 */
1254 static struct node *
parsedictionary(struct tok * tok,struct node * eal)1255 parsedictionary(struct tok *tok, struct node *eal)
1256 {
1257 struct node *node = newelement("Dictionary");
1258 if (eal) addnode(node, eal);
1259 setcommentnode(node);
1260 tok = lexnocomment();
1261 addnode(node, newattr("name", setidentifier(tok)));
1262 tok = lexnocomment();
1263 if (tok->type == ':') {
1264 lexnocomment();
1265 addnode(node, parsescopednamelist(tok, "DictionaryInheritance", "Name", 1));
1266 }
1267 eat(tok, '{');
1268 while (tok->type != '}') {
1269 const char *start = tok->prestart;
1270 struct node *eal = parseextendedattributelist(tok);
1271 struct node *node2;
1272 if (tok->type == TOK_const)
1273 addnode(node, node2 = parseconst(tok, eal));
1274 else
1275 addnode(node, node2 = parsedictionarymember(tok, eal));
1276 node2->wsstart = start;
1277 node2->end = tok->start + tok->len;
1278 setid(node2);
1279 eat(tok, ';');
1280 }
1281 lexnocomment();
1282 return node;
1283 }
1284
1285 /***********************************************************************
1286 * parseenum : parse Enum
1287 *
1288 * Enter: tok = next token, known to be TOK_dictionary
1289 * eal = 0 else extended attribute list node
1290 *
1291 * Return: new node for the enum
1292 * tok updated to the terminating ';'
1293 */
1294 static struct node *
parseenum(struct tok * tok,struct node * eal)1295 parseenum(struct tok *tok, struct node *eal)
1296 {
1297 char *s;
1298 struct node *node = newelement("Enum");
1299 if (eal) addnode(node, eal);
1300 setcommentnode(node);
1301 tok = lexnocomment();
1302 addnode(node, newattr("name", setidentifier(tok)));
1303 tok = lexnocomment();
1304 eat(tok, '{');
1305 while (tok->type != '}') {
1306 if (tok->type == TOK_STRING) {
1307 const char *start = tok->prestart;
1308 struct node *node2 = newelement("EnumValue");
1309 setcommentnode(node2);
1310
1311 s = memalloc(tok->len + 1);
1312 memcpy(s, tok->start, tok->len);
1313 s[tok->len] = 0;
1314 addnode(node2, newattr("stringvalue", s));
1315 node2->wsstart = start;
1316 node2->end = tok->start + tok->len;
1317 setid(node2);
1318 addnode(node, node2);
1319 } else {
1320 tokerrorexit(tok, "expected string in enum");
1321 }
1322 lexnocomment();
1323 if (tok->type == ',') {
1324 lexnocomment();
1325 }
1326 }
1327 eat(tok, '}');
1328 return node;
1329 }
1330
1331 /***********************************************************************
1332 * parsedefinitions : parse [1] Definitions
1333 *
1334 * Enter: tok = next token
1335 * parent = parent node to add definitions to
1336 *
1337 * On return, tok has been updated.
1338 */
1339 static void
parsedefinitions(struct tok * tok,struct node * parent)1340 parsedefinitions(struct tok *tok, struct node *parent)
1341 {
1342 parent->wsstart = tok->prestart;
1343 for (;;) {
1344 const char *wsstart = tok->prestart;
1345 struct node *eal = parseextendedattributelist(tok);
1346 struct node *node;
1347 switch (tok->type) {
1348 case TOK_partial:
1349 eat(tok, TOK_partial);
1350 if (tok->type == TOK_dictionary) {
1351 node = parsedictionary(tok, eal);
1352 } else {
1353 node = parseinterface(tok, eal);
1354 }
1355 addnode(node, newattr("partial", "partial"));
1356 break;
1357 case TOK_interface:
1358 node = parseinterface(tok, eal);
1359 break;
1360 case TOK_callback:
1361 eat(tok, TOK_callback);
1362 node = parsecallback(tok, eal);
1363 break;
1364 case TOK_dictionary:
1365 node = parsedictionary(tok, eal);
1366 break;
1367 case TOK_enum:
1368 node = parseenum(tok, eal);
1369 break;
1370 case TOK_exception:
1371 node = parseexception(tok, eal);
1372 break;
1373 case TOK_typedef:
1374 node = parsetypedef(tok, eal);
1375 break;
1376 case TOK_IDENTIFIER:
1377 node = parseimplementsstatement(tok, eal);
1378 break;
1379 default:
1380 if (eal)
1381 tokerrorexit(tok, "expected definition after extended attribute list");
1382 node = 0;
1383 break;
1384 }
1385 if (!node)
1386 break;
1387 node->wsstart = wsstart;
1388 node->end = tok->start + tok->len;
1389 eat(tok, ';');
1390 addnode(parent, node);
1391 setid(node);
1392 parent->end = node->end;
1393 }
1394 }
1395
1396 /***********************************************************************
1397 * parse
1398 *
1399 * Return: root element containing (possibly empty) list of definitions
1400 */
1401 struct node *
parse(void)1402 parse(void)
1403 {
1404 struct tok *tok;
1405 struct node *root = newelement("Definitions");
1406 setcommentnode(root);
1407 tok = lexnocomment();
1408 parsedefinitions(tok, root);
1409 if (tok->type != TOK_EOF)
1410 tokerrorexit(tok, "expected end of input");
1411 reversechildren(root);
1412 return root;
1413 }
1414
1415