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