summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/resources/webidl2/test/widlproc/src
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /testing/web-platform/tests/resources/webidl2/test/widlproc/src
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'testing/web-platform/tests/resources/webidl2/test/widlproc/src')
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c1827
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.h25
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/entities.h271
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/lex.c560
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/lex.h141
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/main.c63
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/misc.c119
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/misc.h31
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/node.c331
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/node.h65
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/os.h31
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/parse.c1414
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/parse.h19
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/process.c319
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/process.h27
-rw-r--r--testing/web-platform/tests/resources/webidl2/test/widlproc/src/widlprocxmltohtml.xsl828
16 files changed, 6071 insertions, 0 deletions
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c
new file mode 100644
index 000000000..622a7bea7
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.c
@@ -0,0 +1,1827 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "comment.h"
+#include "entities.h"
+#include "lex.h"
+#include "misc.h"
+#include "node.h"
+#include "os.h"
+#include "process.h"
+
+/* struct cnode : a node in the comment parse tree */
+struct cnode {
+ struct cnode *next;
+ struct cnode *children;
+ struct cnode *parent;
+ const struct cnodefuncs *funcs;
+ const char *attrtext;
+ const char *filename;
+ unsigned int linenum;
+};
+
+struct cnodefuncs {
+ int indesc; /* non-zero if it outputs its own xml element that does
+ not want to be inside <description> */
+ int needpara; /* non-zero if text must be in a para node that is a child
+ of this one */
+ int (*askend)(struct cnode *cnode, const struct cnodefuncs *type);
+ void (*end)(struct cnode *cnode);
+ void (*output)(struct cnode *cnode, unsigned int indent);
+};
+
+struct paramcnode {
+ struct cnode cn;
+ int inout;
+ char name[1];
+};
+
+/* struct comment : a doxygen comment */
+struct comment {
+ struct comment *next;
+ struct node *node;
+ unsigned int type;
+ const char *filename;
+ unsigned int linenum;
+ struct cnode root;
+ int back; /* Whether the comment refers back rather than forward. */
+ char *text;
+};
+
+
+static struct node *lastidentifier;
+static struct comment *comments;
+static int incode, inhtmlblock;
+static struct comment *curcomment;
+
+/***********************************************************************
+ * htmleldescs : table of recnogized HTML elements
+ */
+#define HTMLEL_EMPTY 1
+#define HTMLEL_INLINE 2
+#define HTMLEL_BLOCK 4
+#define HTMLEL_AUTOCLOSE 8
+#define HTMLEL_LI 0x10
+#define HTMLEL_DLCONTENTS 0x20
+#define HTMLEL_TABLECONTENTS 0x40
+#define HTMLEL_TRCONTENTS 0x80
+
+#define HTMLEL_FLOW (HTMLEL_BLOCK | HTMLEL_INLINE)
+
+struct htmleldesc {
+ unsigned int namelen;
+ const char *name;
+ unsigned int flags;
+ unsigned int content;
+};
+
+static const struct htmleldesc htmleldescs[] = {
+ { 1, "a", HTMLEL_INLINE, 0 },
+ { 1, "b", HTMLEL_INLINE, 0 },
+ { 2, "br", HTMLEL_INLINE, HTMLEL_EMPTY },
+ { 3, "img", HTMLEL_INLINE, HTMLEL_EMPTY },
+ { 2, "dd", HTMLEL_DLCONTENTS, HTMLEL_FLOW },
+ { 2, "dl", HTMLEL_BLOCK, HTMLEL_DLCONTENTS },
+ { 2, "dt", HTMLEL_DLCONTENTS, HTMLEL_INLINE },
+ { 2, "em", HTMLEL_INLINE, 0 },
+ { 2, "li", HTMLEL_LI, HTMLEL_FLOW },
+ { 2, "ol", HTMLEL_BLOCK, HTMLEL_LI },
+ { 1, "p", HTMLEL_BLOCK, HTMLEL_INLINE },
+ { 2, "td", HTMLEL_TRCONTENTS | HTMLEL_AUTOCLOSE, HTMLEL_FLOW },
+ { 2, "th", HTMLEL_TRCONTENTS | HTMLEL_AUTOCLOSE, HTMLEL_FLOW },
+ { 2, "tr", HTMLEL_TABLECONTENTS | HTMLEL_AUTOCLOSE, HTMLEL_TRCONTENTS },
+ { 5, "table", HTMLEL_BLOCK, HTMLEL_TABLECONTENTS },
+ { 2, "ul", HTMLEL_BLOCK, HTMLEL_LI },
+ { 0, 0, 0, 0 }
+};
+#define HTMLELDESC_B (htmleldescs + 1)
+#define HTMLELDESC_BR (htmleldescs + 2)
+
+/***********************************************************************
+ * addcomment : add a comment to the list of comments if it has doxygen syntax
+ *
+ * Enter: tok struct
+ */
+void
+addcomment(struct tok *tok)
+{
+ if (tok->len >= 1 && (tok->start[0] == '!'
+ || (tok->type == TOK_BLOCKCOMMENT && tok->start[0] == '*')
+ || (tok->type == TOK_INLINECOMMENT && tok->start[0] == '/')))
+ {
+ struct comment *comment;
+ comment = memalloc(sizeof(struct comment));
+ comment->text = memalloc(tok->len + 1);
+ memcpy(comment->text, tok->start, tok->len);
+ comment->text[tok->len] = 0;
+ comment->type = tok->type;
+ comment->filename = tok->filename;
+ comment->linenum = tok->linenum;
+ comment->node = 0;
+ comment->back = 0;
+ if (comment->text[1] == '<') {
+ comment->back = 1;
+ if (!lastidentifier) {
+ locerrorexit(comment->filename, comment->linenum,
+ "no identifier to attach doxygen comment to");
+ }
+ comment->node = lastidentifier;
+ }
+ comment->next = comments;
+ comments = comment;
+ }
+}
+
+/***********************************************************************
+ * setcommentnode : set parse node to attach comments to
+ *
+ * Enter: node2 = parse node for identifier
+ */
+void
+setcommentnode(struct node *node2)
+{
+ struct comment *comment = comments;
+ while (comment && !comment->node) {
+ comment->node = node2;
+ comment = comment->next;
+ }
+ lastidentifier = node2;
+}
+
+/***********************************************************************
+ * joininlinecomments : join adjacent inline comments
+ *
+ * Enter: comment = list of comment structs
+ *
+ * Return: new list of comment structs
+ *
+ * This function also discards any single inline comment that does not
+ * refer back.
+ */
+static struct comment *
+joininlinecomments(struct comment *comments)
+{
+ struct comment **pcomment;
+ pcomment = &comments;
+ for (;;) {
+ struct comment *comment;
+ comment = *pcomment;
+ if (!comment)
+ break;
+ if (comment->type != TOK_INLINECOMMENT) {
+ /* Keep block comment as is. */
+ pcomment = &comment->next;
+ } else if (!comment->back && (!comment->next
+ || comment->next->type != TOK_INLINECOMMENT
+ || comment->next->filename != comment->filename
+ || comment->next->linenum != comment->linenum + 1))
+ {
+ /* Discard single // comment that does not refer back. */
+ *pcomment = comment->next;
+
+ } else {
+ /* Find sequence of adjacent // comments (adjacent lines,
+ * referring to same node) and join them. We do this in two
+ * passes, one to count the length of the comment and one
+ * to join. Note that the list is still in reverse order,
+ * so we expect the line number to decrease by 1 each time. */
+ struct comment *newcomment = 0, *comment2;
+ const char *filename = comment->filename;
+ unsigned int linenum = comment->linenum;
+ for (;;) {
+ char *wp = newcomment->text;
+ comment2 = comment;
+ do {
+ unsigned int len = strlen(comment2->text);
+ if (newcomment)
+ memcpy(wp, comment2->text, len);
+ wp += len;
+ linenum--;
+ comment2 = comment2->next;
+ } while (comment2 && comment2->filename == filename
+ && comment2->linenum == linenum
+ && comment2->node == comment->node);
+ /* Finished a pass. */
+ if (newcomment) {
+ *wp = 0;
+ break;
+ }
+ newcomment = memalloc(sizeof(struct comment)
+ + wp - newcomment->text);
+ newcomment->node = comment->node;
+ newcomment->type = comment->type;
+ newcomment->filename = filename;
+ newcomment->linenum = linenum + 1;
+ }
+ /* Replace the scanned comment struct with newcomment in the
+ * list. */
+ newcomment->next = comment2;
+ *pcomment = newcomment;
+ pcomment = &newcomment->next;
+ }
+ }
+ return comments;
+}
+
+/***********************************************************************
+ * outputchildren : call output recursively on children of cnode
+ *
+ * Enter: cnode
+ * indent = indent (nesting) level of parent
+ * indesc = whether already in <description> or other top-level
+ * descriptive element
+ */
+static void
+outputchildren(struct cnode *cnode, unsigned int indent, int indesc)
+{
+ int curindesc = indesc;
+ cnode = cnode->children;
+ while (cnode) {
+ if (curindesc != cnode->funcs->indesc) {
+ assert(!indesc);
+ printf("%*s<%sdescription>\n", indent + 1, "", curindesc ? "/" : "");
+ curindesc = !curindesc;
+ }
+ (*cnode->funcs->output)(cnode, indent + 2);
+ cnode = cnode->next;
+ }
+ if (curindesc != indesc)
+ printf("%*s<%sdescription>\n", indent + 1, "", curindesc ? "/" : "");
+}
+
+/***********************************************************************
+ * default_askend : ask node if it wants to end at a para start (default
+ * implementation)
+ *
+ * Enter: cnode
+ * type = 0 else cnodefuncs for newly starting para
+ *
+ * Return: non-zero if this node wants to end
+ */
+static int
+default_askend(struct cnode *cnode, const struct cnodefuncs *type)
+{
+ return 1;
+}
+
+/***********************************************************************
+ * root_askend : ask root node if it wants to end at a para start
+ *
+ * Enter: cnode for root
+ * type = 0 else cnodefuncs for newly starting para
+ *
+ * Return: non-zero if this node wants to end
+ */
+static int
+root_askend(struct cnode *cnode, const struct cnodefuncs *type)
+{
+ return 0;
+}
+
+/***********************************************************************
+ * root_output : output root cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+root_output(struct cnode *cnode, unsigned int indent)
+{
+ outputchildren(cnode, indent, 0);
+}
+
+/***********************************************************************
+ * cnode type root
+ */
+static const struct cnodefuncs root_funcs = {
+ 0, /* !indesc */
+ 1, /* needpara */
+ &root_askend,
+ 0, /* end */
+ &root_output,
+};
+
+/***********************************************************************
+ * endcnode : end current cnode
+ *
+ * Enter: cnode = current cnode
+ *
+ * Return: cnode = new current code (parent of old one)
+ */
+static struct cnode *
+endcnode(struct cnode *cnode)
+{
+ if (cnode->funcs->end)
+ (*cnode->funcs->end)(cnode);
+ /* Reverse the children list. */
+ {
+ struct cnode *child = cnode->children;
+ cnode->children = 0;
+ while (child) {
+ struct cnode *next = child->next;
+ child->next = cnode->children;
+ cnode->children = child;
+ child = next;
+ }
+ }
+ return cnode->parent;
+}
+
+/***********************************************************************
+ * endspecificcnode : end a specific type of cnode
+ *
+ * Enter: cnode = current cnode
+ * type = type of node to end
+ * filename, linenum = filename and line number (for error reporting)
+ *
+ * Return: new current cnode
+ */
+static struct cnode *
+endspecificcnode(struct cnode *cnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum)
+{
+ while (cnode->funcs != type) {
+ if (cnode->funcs == &root_funcs)
+ locerrorexit(filename, linenum, "unmatched \\endcode");
+ cnode = endcnode(cnode);
+ }
+ return cnode;
+}
+
+/***********************************************************************
+ * startcnode : start a newly created cnode
+ *
+ * Enter: cnode = current cnode
+ * newcnode = new cnode to start
+ *
+ * Return: new current cnode (which is the same as newcnode)
+ */
+static struct cnode *
+startcnode(struct cnode *cnode, struct cnode *newcnode)
+{
+ newcnode->parent = cnode;
+ newcnode->next = cnode->children;
+ cnode->children = newcnode;
+ return newcnode;
+}
+
+/***********************************************************************
+ * para_output : output para cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+para_output(struct cnode *cnode, unsigned int indent)
+{
+ printf("%*s<p>\n", indent, "");
+ outputchildren(cnode, indent, 1);
+ printf("%*s</p>\n", indent, "");
+}
+
+/***********************************************************************
+ * para_end : end a para cnode
+ *
+ * Enter: cnode struct
+ */
+static void
+para_end(struct cnode *cnode)
+{
+ /* If the para cnode is empty, remove it. */
+ if (!cnode->children)
+ cnode->parent->children = cnode->next;
+}
+
+/***********************************************************************
+ * cnode type para
+ */
+static const struct cnodefuncs para_funcs = {
+ 1, /* indesc */
+ 0, /* !needpara */
+ &default_askend,
+ &para_end, /* end */
+ &para_output,
+};
+
+/***********************************************************************
+ * brief_output : output brief cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+brief_output(struct cnode *cnode, unsigned int indent)
+{
+ printf("%*s<brief>\n", indent, "");
+ outputchildren(cnode, indent, 1);
+ printf("%*s</brief>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type brief
+ */
+static const struct cnodefuncs brief_funcs = {
+ 0, /* !indesc */
+ 0, /* !needpara */
+ &default_askend,
+ 0, /* end */
+ &brief_output,
+};
+
+/***********************************************************************
+ * return_output : output return cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+return_output(struct cnode *cnode, unsigned int indent)
+{
+ printf("%*s<description><p>\n", indent, "");
+ outputchildren(cnode, indent, 1);
+ printf("%*s</p></description>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type return
+ */
+static const struct cnodefuncs return_funcs = {
+ 0, /* !indesc */
+ 0, /* !needpara */
+ &default_askend,
+ 0, /* end */
+ &return_output,
+};
+
+/***********************************************************************
+ * author_output : output name cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+name_output(struct cnode *cnode, unsigned int indent)
+{
+ printf("%*s<name>\n", indent, "");
+ outputchildren(cnode, indent, 1);
+ printf("%*s</name>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type name
+ */
+static const struct cnodefuncs name_funcs = {
+ 0, /* !indesc */
+ 0, /* !needpara */
+ &default_askend,
+ 0, /* end */
+ &name_output,
+};
+
+/***********************************************************************
+ * author_output : output author cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+author_output(struct cnode *cnode, unsigned int indent)
+{
+ printf("%*s<author>\n", indent, "");
+ outputchildren(cnode, indent, 1);
+ printf("%*s</author>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type author
+ */
+static const struct cnodefuncs author_funcs = {
+ 0, /* !indesc */
+ 0, /* !needpara */
+ &default_askend,
+ 0, /* end */
+ &author_output,
+};
+
+/***********************************************************************
+ * version_output : output version cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+version_output(struct cnode *cnode, unsigned int indent)
+{
+ printf("%*s<version>\n", indent, "");
+ outputchildren(cnode, indent, 1);
+ printf("%*s</version>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type version
+ */
+static const struct cnodefuncs version_funcs = {
+ 0, /* !indesc */
+ 0, /* !needpara */
+ &default_askend,
+ 0, /* end */
+ &version_output,
+};
+
+/***********************************************************************
+ * cnode type code
+ */
+/***********************************************************************
+ * code_end : end a code cnode
+ *
+ * Enter: cnode struct
+ */
+static void
+code_end(struct cnode *cnode)
+{
+ if (incode) {
+ /* The incode flag has not been cleared, so this code cnode is
+ * being ended implicitly. We complain about that. */
+ locerrorexit(cnode->filename, cnode->linenum, "mismatched \\code");
+ }
+}
+
+/***********************************************************************
+ * code_output : output code cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+code_output(struct cnode *cnode, unsigned int indent)
+{
+ /* Note capitalization to differentiate it from HTML code element. */
+ if(cnode->attrtext)
+ printf("%*s<Code %s>", indent, "", cnode->attrtext);
+ else
+ printf("%*s<Code>", indent, "");
+ outputchildren(cnode, indent, 1);
+ printf("</Code>\n");
+}
+
+static const struct cnodefuncs code_funcs = {
+ 0, /* indesc */
+ 0, /* !needpara */
+ &default_askend,
+ &code_end, /* end */
+ &code_output,
+};
+
+/***********************************************************************
+ * startpara : start a new para cnode in the parse tree
+ *
+ * Enter: cnode = current cnode
+ * type = vtable for particular type of cnode
+ *
+ * Return: new current cnode
+ */
+static struct cnode *
+startpara(struct cnode *cnode, const struct cnodefuncs *type)
+{
+ struct cnode *newcnode;
+ while ((*cnode->funcs->askend)(cnode, type))
+ cnode = endcnode(cnode);
+ newcnode = memalloc(sizeof(struct cnode));
+ newcnode->funcs = type;
+ return startcnode(cnode, newcnode);
+}
+
+/***********************************************************************
+ * cnode type text
+ */
+struct textcnode {
+ struct cnode cn;
+ unsigned char *data;
+ unsigned int len;
+ unsigned int max;
+};
+
+/***********************************************************************
+ * text_end : end a text cnode
+ *
+ * Enter: cnode struct
+ */
+static void
+text_end(struct cnode *cnode)
+{
+ struct textcnode *textcnode = (void *)cnode;
+ textcnode->data[textcnode->len] = 0;
+ textcnode->max = textcnode->len + 1;
+ textcnode->data = memrealloc(textcnode->data, textcnode->max);
+}
+
+/***********************************************************************
+ * text_output : output text cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+text_output(struct cnode *cnode, unsigned int indent)
+{
+ /* We do not indent, in case this is inside a code cnode. */
+ struct textcnode *textcnode = (void *)cnode;
+ unsigned int len = textcnode->len;
+ unsigned const char *p = textcnode->data;
+ while (len) {
+ unsigned int thislen;
+ const char *thisptr;
+ thislen = p[0];
+ /* (void *) cast is to avoid a warning from the MS compiler.
+ * I think the warning is wrong, but I could be wrong. */
+ memcpy((void *)&thisptr, p + 1, sizeof(void *));
+ p += 1 + sizeof(void *);
+ len -= 1 + sizeof(void *);
+ printtext(thisptr, thislen, 0);
+ }
+}
+
+static const struct cnodefuncs text_funcs = {
+ 1, /* !indesc */
+ 0, /* !needpara */
+ &default_askend,
+ &text_end, /* end */
+ &text_output,
+};
+
+/***********************************************************************
+ * cnode type html (HTML element)
+ */
+struct htmlcnode {
+ struct cnode cn;
+ const struct htmleldesc *desc;
+ char attrs[1];
+};
+
+/***********************************************************************
+ * html_end : end an html cnode
+ *
+ * Enter: cnode struct
+ */
+static void
+html_end(struct cnode *cnode)
+{
+ if (((struct htmlcnode *)cnode)->desc->flags & HTMLEL_BLOCK)
+ inhtmlblock--;
+}
+
+/***********************************************************************
+ * html_output : output html cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+html_output(struct cnode *cnode, unsigned int indent)
+{
+ struct htmlcnode *htmlcnode = (void *)cnode;
+ if (!(htmlcnode->desc->flags & HTMLEL_INLINE))
+ printf("%*s", indent, "");
+ if (htmlcnode->cn.children) {
+ printf("<%s%s>", htmlcnode->desc->name, htmlcnode->attrs);
+ if (!(htmlcnode->desc->flags & HTMLEL_INLINE))
+ putchar('\n');
+ outputchildren(&htmlcnode->cn, indent, 1);
+ if (!(htmlcnode->desc->flags & HTMLEL_INLINE))
+ printf("%*s", indent, "");
+ printf("</%s>", htmlcnode->desc->name);
+ } else
+ printf("<%s%s/>", htmlcnode->desc->name, htmlcnode->attrs);
+ if (!(htmlcnode->desc->flags & HTMLEL_INLINE))
+ putchar('\n');
+}
+
+static const struct cnodefuncs html_funcs = {
+ 1, /* indesc */
+ 0, /* !needpara */
+ &default_askend,
+ &html_end, /* end */
+ &html_output,
+};
+
+/***********************************************************************
+ * starthtmlcnode : start a new html cnode
+ *
+ * Enter: cnode = current cnode
+ * htmleldesc = html element descriptor
+ * attrs = attributes text
+ * attrslen = length of attributes text
+ * filename
+ * linenum = line number
+ *
+ * Return: new current cnode
+ */
+static struct cnode *
+starthtmlcnode(struct cnode *cnode, const struct htmleldesc *htmleldesc,
+ const char *attrs, unsigned int attrslen,
+ const char *filename, unsigned int linenum)
+{
+ struct htmlcnode *htmlcnode;
+ /* First close enough elements to get to a content
+ * model that will accept this new element. */
+ for (;;) {
+ if (cnode->funcs != &html_funcs) {
+ /* Not in any html element. We can accept any block element
+ * (in which case we need to close the current paragraph
+ * first) or any inline element (in which case we need to
+ * close the current text cnode first). */
+ if (!(htmleldesc->flags & HTMLEL_INLINE)) {
+ if (!(htmleldesc->flags & HTMLEL_BLOCK))
+ locerrorexit(filename, linenum, "<%s> not valid here", htmleldesc->name);
+ while ((*cnode->funcs->askend)(cnode, 0))
+ cnode = endcnode(cnode);
+ } else {
+ while (cnode->funcs == &text_funcs)
+ cnode = endcnode(cnode);
+ }
+ break;
+ }
+ htmlcnode = (struct htmlcnode *)cnode;
+ if (!(htmleldesc->flags & htmlcnode->desc->content))
+ locerrorexit(filename, linenum, "<%s> not valid here", htmleldesc->name);
+ break;
+ }
+ if (htmleldesc->flags & HTMLEL_BLOCK)
+ inhtmlblock++;
+ /* Create the new html cnode. */
+ htmlcnode = memalloc(sizeof(struct htmlcnode) + attrslen);
+ htmlcnode->desc = htmleldesc;
+ htmlcnode->cn.funcs = &html_funcs;
+ htmlcnode->cn.filename = filename;
+ htmlcnode->cn.linenum = linenum;
+ memcpy(htmlcnode->attrs, attrs, attrslen);
+ htmlcnode->attrs[attrslen] = 0;
+ /* Start the html cnode. */
+ cnode = startcnode(cnode, &htmlcnode->cn);
+ return cnode;
+}
+
+/***********************************************************************
+ * param_output : output param cnode
+ *
+ * Enter: cnode for param
+ * indent = indent (nesting) level
+ *
+ * This is only used for a \param inside a \def-device-cap. A normal
+ * \param that gets attached to a function argument gets changed to
+ * a \return so it does not use this output function.
+ */
+static void
+param_output(struct cnode *cnode, unsigned int indent)
+{
+ struct paramcnode *paramcnode = (void *)cnode;
+ printf("%*s<param identifier=\"%s\">\n", indent, "", paramcnode->name);
+ outputchildren(&paramcnode->cn, indent, 1);
+ printf("%*s</param>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type param
+ */
+static const struct cnodefuncs param_funcs = {
+ 0, /* !indesc */
+ 0, /* !needpara */
+ &default_askend,
+ 0, /* end */
+ &param_output,
+};
+
+/***********************************************************************
+ * cnode type throw
+ */
+static const struct cnodefuncs throw_funcs = {
+ 0, /* !indesc */
+ 0, /* !needpara */
+ &default_askend,
+ 0, /* end */
+ &return_output,
+};
+
+/***********************************************************************
+ * startparamcnode : start param (or throw) cnode
+ *
+ * Enter: cnode = current cnode
+ * word = name of param
+ * wordlen = length of name
+ * inout = bit 0 = in, bit 1 = out
+ * type = &param_funcs or &throw_funcs
+ *
+ * Return: new current cnode
+ */
+static struct cnode *
+startparamcnode(struct cnode *cnode, const char *word, unsigned int wordlen,
+ int inout, const struct cnodefuncs *funcs)
+{
+ struct paramcnode *paramcnode;
+ paramcnode = memalloc(sizeof(struct paramcnode) + wordlen);
+ paramcnode->cn.funcs = funcs;
+ memcpy(paramcnode->name, word, wordlen);
+ paramcnode->name[wordlen] = 0;
+ paramcnode->inout = inout;
+ return startcnode(cnode, &paramcnode->cn);
+}
+
+/***********************************************************************
+ * api_feature_output : output api-feature cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+api_feature_output(struct cnode *cnode, unsigned int indent)
+{
+ struct paramcnode *paramcnode = (void *)cnode;
+ printf("%*s<api-feature identifier=\"%s\">\n", indent, "", paramcnode->name);
+ outputchildren(cnode, indent, 1);
+ printf("%*s</api-feature>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type api_feature
+ */
+static const struct cnodefuncs api_feature_funcs = {
+ 0, /* !indesc */
+ 0, /* needpara */
+ &default_askend,
+ 0, /* end */
+ &api_feature_output,
+};
+
+/***********************************************************************
+ * device_cap_output : output device-cap cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+device_cap_output(struct cnode *cnode, unsigned int indent)
+{
+ struct paramcnode *paramcnode = (void *)cnode;
+ printf("%*s<device-cap identifier=\"%s\">\n", indent, "", paramcnode->name);
+ outputchildren(cnode, indent, 1);
+ printf("%*s</device-cap>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type device_cap
+ */
+static const struct cnodefuncs device_cap_funcs = {
+ 0, /* !indesc */
+ 0, /* needpara */
+ &default_askend,
+ 0, /* end */
+ &device_cap_output,
+};
+
+/***********************************************************************
+ * def_api_feature_askend : ask if def-api-feature cnode wants to end at new para
+ *
+ * Enter: cnode for def-api-feature
+ * type = cnodefuncs for new para (0 if html block element)
+ *
+ * Return: non-zero to end the def-api-feature
+ */
+static int
+def_api_feature_askend(struct cnode *cnode, const struct cnodefuncs *type)
+{
+ /* A def-api-feature does not end at a plain para, an html block element,
+ * a brief para, or a device-cap. */
+ if (!type || type == &para_funcs || type == &device_cap_funcs || type == &brief_funcs)
+ return 0;
+ return 1;
+}
+
+/***********************************************************************
+ * def_api_feature_output : output def-api-feature cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+def_api_feature_output(struct cnode *cnode, unsigned int indent)
+{
+ struct paramcnode *paramcnode = (void *)cnode;
+ printf("%*s<def-api-feature identifier=\"%s\">\n", indent, "", paramcnode->name);
+ printf("%*s<descriptive>\n", indent + 2, "");
+ outputchildren(cnode, indent + 2, 0);
+ printf("%*s</descriptive>\n", indent + 2, "");
+ printf("%*s</def-api-feature>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type def_api_feature
+ */
+static const struct cnodefuncs def_api_feature_funcs = {
+ 0, /* !indesc */
+ 1, /* needpara */
+ &def_api_feature_askend,
+ 0, /* end */
+ &def_api_feature_output,
+};
+
+/***********************************************************************
+ * def_api_feature_set_askend : ask if def-api-feature-set cnode wants to end at new para
+ *
+ * Enter: cnode for def-api-feature-set
+ * type = cnodefuncs for new para (0 if html block element)
+ *
+ * Return: non-zero to end the def-api-feature-set
+ */
+static int
+def_api_feature_set_askend(struct cnode *cnode, const struct cnodefuncs *type)
+{
+ /* A def-api-feature-set does not end at a plain para, an html block element,
+ * a brief para, or an api-feature. */
+ if (!type || type == &para_funcs || type == &api_feature_funcs || type == &brief_funcs)
+ return 0;
+ return 1;
+}
+
+/***********************************************************************
+ * def_api_feature_set_output : output def-api-feature-set cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+def_api_feature_set_output(struct cnode *cnode, unsigned int indent)
+{
+ struct paramcnode *paramcnode = (void *)cnode;
+ printf("%*s<def-api-feature-set identifier=\"%s\">\n", indent, "", paramcnode->name);
+ printf("%*s<descriptive>\n", indent + 2, "");
+ outputchildren(cnode, indent + 2, 0);
+ printf("%*s</descriptive>\n", indent + 2, "");
+ printf("%*s</def-api-feature-set>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type def_api_feature_set
+ */
+static const struct cnodefuncs def_api_feature_set_funcs = {
+ 0, /* !indesc */
+ 1, /* needpara */
+ &def_api_feature_set_askend,
+ 0, /* end */
+ &def_api_feature_set_output,
+};
+
+/***********************************************************************
+ * def_instantiated_askend : ask if def-instantiated cnode wants to end at new para
+ *
+ * Enter: cnode for def-instantiated
+ * type = cnodefuncs for new para (0 if html block element)
+ *
+ * Return: non-zero to end the def-instantiated
+ */
+static int
+def_instantiated_askend(struct cnode *cnode, const struct cnodefuncs *type)
+{
+ /* A def-instantiated does not end at a plain para, an html block element,
+ * a brief para, or an api-feature. */
+ if (!type || type == &para_funcs || type == &api_feature_funcs || type == &brief_funcs)
+ return 0;
+ return 1;
+}
+
+/***********************************************************************
+ * def_instantiated_output : output def-instantiated cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+def_instantiated_output(struct cnode *cnode, unsigned int indent)
+{
+ printf("%*s<def-instantiated>\n", indent, "");
+ printf("%*s<descriptive>\n", indent + 2, "");
+ outputchildren(cnode, indent + 2, 0);
+ printf("%*s</descriptive>\n", indent + 2, "");
+ printf("%*s</def-instantiated>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type def_instantiated
+ */
+static const struct cnodefuncs def_instantiated_funcs = {
+ 0, /* !indesc */
+ 1, /* needpara */
+ &def_instantiated_askend,
+ 0, /* end */
+ &def_instantiated_output,
+};
+
+/***********************************************************************
+ * def_device_cap_askend : ask if def-device-cap cnode wants to end at new para
+ *
+ * Enter: cnode for def-device-cap
+ * type = cnodefuncs for new para (0 if html block element)
+ *
+ * Return: non-zero to end the def-device-cap
+ */
+static int
+def_device_cap_askend(struct cnode *cnode, const struct cnodefuncs *type)
+{
+ /* A def-device-cap does not end at a plain para, an html block element,
+ * a \brief para, or a param. */
+ if (!type || type == &para_funcs || type == &param_funcs || type == &brief_funcs)
+ return 0;
+ return 1;
+}
+
+/***********************************************************************
+ * def_device_cap_output : output def_device-cap cnode
+ *
+ * Enter: cnode for root
+ * indent = indent (nesting) level
+ */
+static void
+def_device_cap_output(struct cnode *cnode, unsigned int indent)
+{
+ struct paramcnode *paramcnode = (void *)cnode;
+ printf("%*s<def-device-cap identifier=\"%s\">\n", indent, "", paramcnode->name);
+ printf("%*s<descriptive>\n", indent + 2, "");
+ outputchildren(cnode, indent + 2, 0);
+ printf("%*s</descriptive>\n", indent + 2, "");
+ printf("%*s</def-device-cap>\n", indent, "");
+}
+
+/***********************************************************************
+ * cnode type def_device_cap
+ */
+static const struct cnodefuncs def_device_cap_funcs = {
+ 0, /* !indesc */
+ 1, /* needpara */
+ &def_device_cap_askend,
+ 0, /* end */
+ &def_device_cap_output,
+};
+
+/***********************************************************************
+ * addtext : add text to current text node, starting one if necessary
+ *
+ * Enter: cnode = current cnode
+ * text
+ * len = length of text
+ *
+ * Return: new current cnode
+ */
+static struct cnode *
+addtext(struct cnode *cnode, const char *text, unsigned int len)
+{
+ struct textcnode *textcnode;
+ if (!len)
+ return cnode;
+ if (cnode->funcs != &text_funcs) {
+ /* Start new text cnode. */
+ textcnode = memalloc(sizeof(struct textcnode));
+ textcnode->cn.funcs = &text_funcs;
+ cnode = startcnode(cnode, &textcnode->cn);
+ }
+ textcnode = (void *)cnode;
+ do {
+ unsigned char buf[1 + sizeof(void *)];
+ unsigned int thislen = len;
+ if (thislen > 255)
+ thislen = 255;
+ /* Encode a record as a single byte length followed by a pointer. */
+ buf[0] = thislen;
+ memcpy(buf + 1, &text, sizeof(void *));
+ /* Add to the text cnode's data. */
+ if (textcnode->len + sizeof(buf) >= textcnode->max) {
+ /* Need to reallocate (or allocate) data buffer. */
+ textcnode->max = textcnode->max ? 2 * textcnode->max : 1024;
+ textcnode->data = memrealloc(textcnode->data, textcnode->max);
+ }
+ memcpy(textcnode->data + textcnode->len, buf, sizeof(buf));
+ textcnode->len += sizeof(buf);
+ text += thislen;
+ len -= thislen;
+ } while (len);
+ return &textcnode->cn;
+}
+
+/***********************************************************************
+ * iswhitespace : determine if character is whitespace
+ *
+ * Enter: ch = character
+ *
+ * Return: 1 if whitespace
+ */
+static inline int
+iswhitespace(int ch)
+{
+ unsigned int i = ch - 1;
+ if (i >= 32)
+ return 0;
+ return 0x80001100 >> i & 1;
+}
+
+/***********************************************************************
+ * parseword : parse the next word, ignoring leading whitespace
+ *
+ * Enter: *pp = text pointer
+ *
+ * Return: 0 else start of word (*pp updated to just beyond end)
+ */
+static const char *
+parseword(const char **pp)
+{
+ const char *p = *pp, *word = 0;
+ int ch = *p;
+ while (iswhitespace(ch))
+ ch = *++p;
+ word = p;
+ while ((unsigned)((ch & ~0x20) - 'A') <= 'Z' - 'A'
+ || (unsigned)(ch - '0') < 10 || ch == '_' || ch == '.'
+ || ch == ':' || ch == '/' || ch == '-')
+ {
+ ch = *++p;
+ }
+ if (p == word)
+ return 0;
+ *pp = p;
+ return word;
+}
+
+/***********************************************************************
+ * Doxygen command handlers
+ *
+ * Enter: p = text just after command
+ * *pcnode = pointer to current cnode struct
+ * type = 0 else cnodefuncs pointer for type of node to start
+ * filename, linenum = current filename and line number (for error reporting)
+ *
+ * Return: p = updated if extra text was eaten
+ *
+ * On return, *pnode is updated if any node was closed or opened.
+ */
+
+/***********************************************************************
+ * Doxygen command handler : \b
+ */
+static const char *
+dox_b(const char *p, struct cnode **pcnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum, const char *cmdname)
+{
+ struct cnode *cnode = *pcnode;
+ const char *word = parseword(&p);
+ /* Silently ignore \b with no following word. */
+ if (word) {
+ struct cnode *mycnode;
+ mycnode = cnode = starthtmlcnode(cnode, HTMLELDESC_B, 0, 0, filename, linenum);
+ cnode = addtext(cnode, word, p - word);
+ while (cnode != mycnode)
+ cnode = endcnode(cnode);
+ cnode = endcnode(cnode);
+ }
+ *pcnode = cnode;
+ return p;
+}
+
+/***********************************************************************
+ * Doxygen command handler : \n
+ */
+static const char *
+dox_n(const char *p, struct cnode **pcnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum, const char *cmdname)
+{
+ struct cnode *cnode = *pcnode;
+ cnode = starthtmlcnode(cnode, HTMLELDESC_BR, 0, 0, filename, linenum);
+ cnode = endcnode(cnode);
+ *pcnode = cnode;
+ return p;
+}
+
+/***********************************************************************
+ * Doxygen command handler : \code
+ */
+static const char *
+dox_code(const char *p, struct cnode **pcnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum, const char *cmdname)
+{
+ *pcnode = startpara(*pcnode, &code_funcs);
+ (*pcnode)->filename = filename;
+ (*pcnode)->linenum = linenum; /* for reporting mismatched \code error */
+ incode = 1;
+ return p;
+}
+
+/***********************************************************************
+ * Doxygen command handler : \endcode
+ */
+static const char *
+dox_endcode(const char *p, struct cnode **pcnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum, const char *cmdname)
+{
+ incode = 0;
+ *pcnode = endspecificcnode(*pcnode, &code_funcs, filename, linenum);
+ return p;
+}
+
+/***********************************************************************
+ * Doxygen command handler : \param
+ */
+static const char *
+dox_param(const char *p, struct cnode **pcnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum, const char *cmdname)
+{
+ struct cnode *cnode = *pcnode;
+ unsigned int inout = 0;
+ const char *word;
+ /* Check for "in", "out" or both as attributes. */
+ if (*p == '[') {
+ for (;;) {
+ p++;
+ if (!memcmp(p, "in", 2)) {
+ inout |= 1;
+ p += 2;
+ } else if (!memcmp(p, "out", 3)) {
+ inout |= 2;
+ p += 3;
+ } else
+ break;
+ if (*p != ',')
+ break;
+ }
+ if (*p != ']')
+ locerrorexit(filename, linenum, "bad attributes on \\param");
+ p++;
+ }
+ /* Get the next word as the parameter name. */
+ word = parseword(&p);
+ if (!word)
+ locerrorexit(filename, linenum, "expected word after \\param");
+ /* Close any open nodes. */
+ while ((*cnode->funcs->askend)(cnode, type))
+ cnode = endcnode(cnode);
+ /* Create a new param cnode. */
+ cnode = startparamcnode(cnode, word, p - word, inout, type);
+ cnode->filename = filename;
+ cnode->linenum = linenum;
+ *pcnode = cnode;
+ return p;
+}
+
+/***********************************************************************
+ * Doxygen command handler : \brief, \return
+ */
+static const char *
+dox_para(const char *p, struct cnode **pcnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum, const char *cmdname)
+{
+ *pcnode = startpara(*pcnode, type);
+ return p;
+}
+
+/***********************************************************************
+ * Doxygen command handler : \throw
+ */
+static const char *
+dox_throw(const char *p, struct cnode **pcnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum, const char *cmdname)
+{
+ struct cnode *cnode = *pcnode;
+ const char *word;
+ /* Get the next word as the exception name. */
+ word = parseword(&p);
+ if (!word)
+ locerrorexit(filename, linenum, "expected word after \\throw");
+ /* Close any open nodes. */
+ while ((*cnode->funcs->askend)(cnode, type))
+ cnode = endcnode(cnode);
+ /* Create a new throw cnode. */
+ cnode = startparamcnode(cnode, word, p - word, 0, type);
+ cnode->filename = filename;
+ cnode->linenum = linenum;
+ *pcnode = cnode;
+ return p;
+}
+
+/***********************************************************************
+ * Doxygen command handler : \lang
+ */
+static const char *
+dox_attr(const char *p, struct cnode **pcnode, const struct cnodefuncs *type,
+ const char *filename, unsigned int linenum, const char *cmdname)
+{
+ struct cnode *cnode = *pcnode;
+ const char *word;
+ int len, wordlen, offset = 0;
+ char *attrtext;
+ /* Get the next word as the attribute value. */
+ word = parseword(&p);
+ if (!word)
+ locerrorexit(filename, linenum, "expected word after \\%s", cmdname);
+
+ len = strlen(cmdname) + (wordlen = p-word) + 4; /* p="word"\0 */
+ if(cnode->attrtext)
+ len += (offset = strlen(cnode->attrtext)) + 1; /* add space for space */
+ attrtext = memalloc(len);
+ if(offset) {
+ memcpy(attrtext, cnode->attrtext, offset);
+ attrtext[offset++] = ' ';
+ memfree(((void*)cnode->attrtext));
+ }
+ offset += sprintf(&attrtext[offset], "%s=\"", cmdname);
+ memcpy(&attrtext[offset], word, wordlen);
+ strcpy(&attrtext[offset + wordlen], "\"");
+ cnode->attrtext = attrtext;
+ /* skip delimiter because it won't be done otherwise */
+ if(incode && iswhitespace(*p)) ++p;
+ return p;
+}
+
+/***********************************************************************
+ * commands : table of Doxygen commands
+ */
+struct command {
+ const char *(*func)(const char *p, struct cnode **pcnode, const struct cnodefuncs *type, const char *filename, unsigned int linenum, const char *cmdname);
+ const struct cnodefuncs *type;
+ unsigned int namelen;
+ const char *name;
+};
+static const struct command commands[] = {
+ { &dox_throw, &def_api_feature_funcs, 15, "def-api-feature" },
+ { &dox_throw, &def_api_feature_set_funcs, 19, "def-api-feature-set" },
+ { &dox_para, &def_instantiated_funcs, 16, "def-instantiated" },
+ { &dox_para, &name_funcs, 4, "name" },
+ { &dox_para, &author_funcs, 6, "author" },
+ { &dox_b, 0, 1, "b" },
+ { &dox_para, &brief_funcs, 5, "brief" },
+ { &dox_code, 0, 4, "code" },
+ { &dox_throw, &def_device_cap_funcs, 14, "def-device-cap" },
+ { &dox_attr, 0, 4, "lang" },
+ { &dox_endcode, 0, 7, "endcode" },
+ { &dox_n, 0, 1, "n" },
+ { &dox_param, &param_funcs, 5, "param" },
+ { &dox_para, &return_funcs, 6, "return" },
+ { &dox_throw, &throw_funcs, 5, "throw" },
+ { &dox_throw, &api_feature_funcs, 11, "api-feature" },
+ { &dox_throw, &device_cap_funcs, 10, "device-cap" },
+ { &dox_para, &version_funcs, 7, "version" },
+ { 0, 0, 0 }
+};
+
+/***********************************************************************
+ * parsehtmltag : parse html tag
+ *
+ * Enter: start = start of tag, the '<' char
+ * *pcnode = current cnode
+ * filename = filename
+ * *plinenum = current line number
+ *
+ * Return: just after the tag
+ * *pcnode and *plinenum updated if applicable
+ */
+static const char *
+parsehtmltag(const char *start, struct cnode **pcnode,
+ const char *filename, unsigned int *plinenum)
+{
+ struct cnode *cnode = *pcnode;
+ const char *end = start + 1, *endname = 0, *name = end;
+ int ch = *end;
+ int quote = 0;
+ int close = 0;
+ unsigned int linenum = *plinenum;
+ const struct htmleldesc *htmleldesc;
+ if (ch == '/') {
+ close = 1;
+ ch = *++end;
+ name = end;
+ }
+ /* Find the end of the tag. */
+ for (;;) {
+ if (!ch)
+ locerrorexit(filename, *plinenum, "unterminated HTML tag");
+ if (ch == '\n')
+ linenum++;
+ else if (iswhitespace(ch) || ch == '/') {
+ if (!endname)
+ endname = end;
+ } else if (!quote) {
+ if (ch == '"' || ch == '\'')
+ quote = ch;
+ else if (ch == '>')
+ break;
+ } else {
+ if (ch == quote)
+ quote = 0;
+ }
+ ch = *++end;
+ }
+ if (!endname)
+ endname = end;
+ end++;
+ /* See if it's an xml open-close tag. */
+ if (!close && endname != name && end[-2] == '/')
+ close = 2;
+ /* Find the tag from our list. */
+ htmleldesc = htmleldescs;
+ for (;;) {
+ if (!htmleldesc->namelen) {
+ locerrorexit(filename, *plinenum, "unrecognized HTML tag %.*s",
+ end - start, start);
+ }
+ if (htmleldesc->namelen == endname - name
+ && !strncasecmp(htmleldesc->name, name, endname - name))
+ {
+ break;
+ }
+ htmleldesc++;
+ }
+ if (close == 1) {
+ /* Closing tag. Find open element to close. */
+ for (;;) {
+ struct htmlcnode *htmlcnode;
+ if (cnode->funcs != &text_funcs) {
+ if (cnode->funcs != &html_funcs) {
+ locerrorexit(filename, *plinenum, "mismatched %.*s",
+ end - start, start);
+ }
+ htmlcnode = (struct htmlcnode *)cnode;
+ if (htmlcnode->desc == htmleldesc)
+ break;
+ if (!(htmlcnode->desc->flags & HTMLEL_AUTOCLOSE)) {
+ locerrorexit(filename, htmlcnode->cn.linenum,
+ "mismatched <%.*s>",
+ htmlcnode->desc->namelen, htmlcnode->desc->name);
+ }
+ }
+ cnode = endcnode(cnode);
+ }
+ cnode = endcnode(cnode);
+ } else {
+ /* Opening tag. */
+ if (close !=2)
+ cnode = starthtmlcnode(cnode, htmleldesc, endname, end - 1 - endname, filename, *plinenum);
+ else // don't include the closing "/" in the attributes list
+ cnode = starthtmlcnode(cnode, htmleldesc, endname, end - 2 - endname, filename, *plinenum);
+ if (close == 2 || (htmleldesc->content & HTMLEL_EMPTY)) {
+ /* Empty element -- close it again. */
+ cnode = endcnode(cnode);
+ }
+ }
+ *pcnode = cnode;
+ *plinenum = linenum;
+ return end;
+}
+
+/***********************************************************************
+ * parsecomment : parse one comment
+ *
+ * Enter: comment struct
+ */
+static void
+parsecomment(struct comment *comment)
+{
+ struct cnode *cnode = &comment->root;
+ const char *p = comment->text + comment->back;
+ unsigned int linenum = comment->linenum - 1;
+ int ch;
+ curcomment = comment;
+ incode = 0;
+ inhtmlblock = 0;
+ cnode->funcs = &root_funcs;
+ for (;;) {
+ /* Start of new line. */
+ const char *starttext;
+ ch = *p;
+ linenum++;
+ {
+ /* Find first non-whitespace character. */
+ const char *p2 = p;
+ int ch2 = ch;
+ while (iswhitespace(ch2))
+ ch2 = *++p2;
+ if (comment->type == TOK_BLOCKCOMMENT && ch2 == '*') {
+ /* Ignore initial * in block comment (even in \code block). */
+ ch2 = *++p2;
+ ch = ch2;
+ p = p2;
+ if (ch == '*')
+ goto checkforlineofstars;
+ while (iswhitespace(ch2))
+ ch2 = *++p2;
+ }
+ if (comment->type == TOK_INLINECOMMENT && ch2 == '/') {
+checkforlineofstars:
+ if (!incode) {
+ /* Ignore whole line of * for block comment or / for inline
+ * comment if that is the only thing on the line. */
+ const char *p3 = p2;
+ int ch3;
+ do ch3 = *++p3; while (ch3 == ch2);
+ while (iswhitespace(ch3)) ch3 = *++p3;
+ if (!ch3 || ch3 == '\n') {
+ /* Reached end of line (or whole comment) -- treat as
+ * empty line. */
+ ch2 = ch3;
+ p2 = p3;
+ }
+ }
+ }
+ if (!incode) {
+ /* Only allow whitespace omission above to take effect if
+ * not in \code block. */
+ ch = ch2;
+ p = p2;
+ }
+ }
+ if (!ch) {
+ /* End of comments -- finish. */
+ break;
+ }
+ if (!incode && !inhtmlblock && ch == '\n') {
+ /* Blank line -- finish any para, but only if not in code and
+ * not in any HTML block element. */
+ while ((*cnode->funcs->askend)(cnode, 0))
+ cnode = endcnode(cnode);
+ p++;
+ continue;
+ }
+ /* Start new para if there isn't already one going. */
+ if (cnode->funcs->needpara)
+ cnode = startpara(cnode, &para_funcs);
+ /* Process text on the line. */
+ starttext = p;
+ while (ch && ch != '\n') {
+ if (ch != '\\' && ch != '<' /* && ch != '@' */ && ch != '$'
+ && ch != '&' && ch != '\r')
+ {
+ ch = *++p;
+ continue;
+ }
+ /* Output any pending text. */
+ if (p - starttext)
+ cnode = addtext(cnode, starttext, p - starttext);
+ /* Ignore \r in DOS line returns */
+ if (ch == '\r') {
+ ch = *++p;
+ starttext = p;
+ continue;
+ }
+ if (ch == '$')
+ locerrorexit(comment->filename, linenum, "use \\$ instead of $");
+ /* See if it is an html named entity. */
+ if (ch == '&' && p[1] != '#') {
+ const char *entity = ENTITIES;
+ /* This search could be faster if the entity names were put
+ * in a hash table or something. */
+ const char *semicolon = strchr(p, ';');
+ unsigned int len;
+ if (!semicolon)
+ locerrorexit(comment->filename, linenum, "unterminated HTML entity");
+ p++;
+ for (;;) {
+ len = strlen(entity);
+ if (!len)
+ locerrorexit(comment->filename, linenum, "unrecognised HTML entity &%.*s;", semicolon - p, p);
+ if (len == semicolon - p && !memcmp(p, entity, len))
+ break;
+ entity += len + 1;
+ entity += strlen(entity) + 1;
+ }
+ entity += len + 1;
+ cnode = addtext(cnode, entity, strlen(entity));
+ p = semicolon + 1;
+ ch = *p;
+ starttext = p;
+ continue;
+ }
+ /* See if it is a backslash escape sequence. */
+ else if (ch == '\\') {
+ const char *match = "\\@&$#<>%";
+ const char *pos;
+ ch = p[1];
+ pos = strchr(match, ch);
+ if (pos) {
+ /* Got a \ escape sequence. */
+ const char *text =
+ "\\\0 @\0 &amp;\0$\0 #\0 &lt;\0 >\0 %"
+ + 6 * (pos - match);
+ cnode = addtext(cnode, text, strlen(text));
+ p += 2;
+ ch = *p;
+ starttext = p;
+ continue;
+ }
+ } else if (ch == '<') {
+ if (incode) {
+ ch = *++p;
+ starttext = p;
+ continue;
+ }
+ /* It's an html tag. */
+ p = parsehtmltag(p, &cnode, comment->filename, &linenum);
+ ch = *p;
+ starttext = p;
+ continue;
+ }
+ {
+ /* Got a doxygen command. First work out its length. */
+ const char *start = ++p;
+ unsigned int cmdlen;
+ const struct command *command;
+ ch = *p;
+ while ((unsigned)((ch & ~0x20) - 'A') <= 'Z' - 'A'
+ || (unsigned)(ch - '0') < 10 || ch == '_' || ch == '-')
+ {
+ ch = *++p;
+ }
+ cmdlen = p - start;
+ if (!cmdlen)
+ locerrorexit(comment->filename, linenum, "\\ or @ without Doxygen command");
+ /* Look it up in the table. */
+ command = commands;
+ for (;;) {
+ if (!command->namelen) {
+ locerrorexit(comment->filename, linenum, "unrecognized Doxygen command '%.*s'",
+ cmdlen + 1, start - 1);
+ }
+ if (command->namelen == cmdlen
+ && !memcmp(command->name, start, cmdlen))
+ {
+ break;
+ }
+ command++;
+ }
+ p = (*command->func)(p, &cnode, command->type,
+ comment->filename, linenum, command->name);
+ ch = *p;
+ starttext = p;
+ }
+ }
+ if (p - starttext) {
+ /* Start new para if there isn't already one going. */
+ if (cnode->funcs->needpara)
+ cnode = startpara(cnode, &para_funcs);
+ cnode = addtext(cnode, starttext, p - starttext);
+ }
+ if (!ch)
+ break;
+ if (cnode->funcs == &text_funcs)
+ addtext(cnode, "\n", 1);
+ p++;
+ }
+ /* Finish the root cnode. */
+ do
+ cnode = endcnode(cnode);
+ while (cnode);
+ assert(!incode);
+ assert(!inhtmlblock);
+}
+
+/***********************************************************************
+ * parsecomments : parse comments
+ *
+ * Enter: comment = first comment in list
+ */
+static void
+parsecomments(struct comment *comment)
+{
+ while (comment) {
+ parsecomment(comment);
+ comment = comment->next;
+ }
+}
+
+/***********************************************************************
+ * attachcommenttonode : attach comment struct to node
+ *
+ * Enter: node = parse node for identifier
+ * comment = comment struct
+ */
+static void
+attachcommenttonode(struct node *node, struct comment *comment)
+{
+ comment->next = node->comments;
+ node->comments = comment;
+}
+
+/***********************************************************************
+ * attachcomments : attach comments to applicable parse nodes
+ *
+ * Enter: comment = first in (reversed) list of comment structs
+ * root = root parse node (for attaching \file comment blocks to)
+ */
+static void
+attachcomments(struct comment *comment, struct node *root)
+{
+ while (comment) {
+ struct comment *next = comment->next;
+ /* See if there are any \param, \return, \throw, \def-api-feature or
+ * \def-device-cap cnodes to detach and attach
+ * elsewhere. (This only looks at top-level nodes, direct children
+ * of the root, so does not detach a \param inside a
+ * \def-device-cap.) */
+ struct cnode **pcnode = &comment->root.children;
+ for (;;) {
+ struct cnode *cnode = *pcnode;
+ if (!cnode)
+ break;
+ if (cnode->funcs == &param_funcs || cnode->funcs == &return_funcs
+ || cnode->funcs == &throw_funcs)
+ {
+ /* Found a \param or \return or \throw to detach. Find the
+ * parameter/exception of the same name, or the return type. */
+ struct node *node;
+ struct comment *newcomment;
+ if (cnode->funcs == &param_funcs) {
+ node = findparamidentifier(comment->node,
+ ((struct paramcnode *)cnode)->name);
+ if (!node)
+ locerrorexit(comment->filename, cnode->linenum, "no parameter '%s' found", ((struct paramcnode *)cnode)->name);
+ } else if (cnode->funcs == &return_funcs) {
+ node = findreturntype(comment->node);
+ if (!node)
+ locerrorexit(comment->filename, cnode->linenum, "no return type found");
+ } else {
+ node = findthrowidentifier(comment->node,
+ ((struct paramcnode *)cnode)->name);
+ if (!node)
+ locerrorexit(comment->filename, cnode->linenum, "no exception '%s' found", ((struct paramcnode *)cnode)->name);
+ }
+ /* Detach the cnode from its old comment. */
+ *pcnode = cnode->next;
+ /* Create a new comment struct to contain this cnode. */
+ newcomment = memalloc(sizeof(struct comment));
+ newcomment->root.funcs = &root_funcs;
+ newcomment->linenum = cnode->linenum;
+ /* Attach the cnode. */
+ newcomment->root.children = cnode;
+ cnode->parent = &newcomment->root;
+ cnode->next = 0;
+ /* Make the cnode a \return one, just so even a \param
+ * uses return_output. */
+ cnode->funcs = &return_funcs;
+ /* Attach the new comment struct to the parse node. */
+ attachcommenttonode(node, newcomment);
+ } else {
+ pcnode = &cnode->next;
+ }
+ }
+ /* Now attach the comment to its identifier parse node. */
+ {
+ struct node *node = comment->node;
+ if (!node)
+ node = root;
+ attachcommenttonode(node, comment);
+ }
+ comment = next;
+ }
+}
+
+/***********************************************************************
+ * processcomments : join, parse and attach comments
+ *
+ * Enter: root = root parse node
+ */
+void
+processcomments(struct node *root)
+{
+ comments = joininlinecomments(comments);
+ parsecomments(comments);
+ attachcomments(comments, root);
+}
+
+/***********************************************************************
+ * outputdescriptive : output descriptive elements for a node
+ *
+ * Enter: node = identifier node that might have some comments
+ * indent = indent (nesting) level
+ */
+void
+outputdescriptive(struct node *node, unsigned int indent)
+{
+ struct comment *comment = node->comments;
+ int indescriptive = 0;
+ while (comment) {
+ struct cnode *root = &comment->root;
+ if (!indescriptive)
+ printf("%*s<descriptive>\n", indent, "");
+ indescriptive = 1;
+ (*root->funcs->output)(root, indent + 2);
+ comment = comment->next;
+ }
+ if (indescriptive)
+ printf("%*s</descriptive>\n", indent, "");
+}
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.h b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.h
new file mode 100644
index 000000000..96d18e2cc
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/comment.h
@@ -0,0 +1,25 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#ifndef comment_h
+#define comment_h
+
+struct tok;
+struct node;
+
+void addcomment(struct tok *tok);
+void setcommentnode(struct node *node2);
+void processcomments(struct node *root);
+void outputdescriptive(struct node *node, unsigned int indent);
+
+#endif /* ndef comment_h */
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/entities.h b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/entities.h
new file mode 100644
index 000000000..ff74c1cb3
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/entities.h
@@ -0,0 +1,271 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#ifndef entities_h
+#define entities_h
+
+#define ENTITIES \
+"nbsp\0&#160;\0" \
+"iexcl\0&#161;\0" \
+"cent\0&#162;\0" \
+"pound\0&#163;\0" \
+"curren\0&#164;\0" \
+"yen\0&#165;\0" \
+"brvbar\0&#166;\0" \
+"sect\0&#167;\0" \
+"uml\0&#168;\0" \
+"copy\0&#169;\0" \
+"ordf\0&#170;\0" \
+"laquo\0&#171;\0" \
+"not\0&#172;\0" \
+"shy\0&#173;\0" \
+"reg\0&#174;\0" \
+"macr\0&#175;\0" \
+"deg\0&#176;\0" \
+"plusmn\0&#177;\0" \
+"sup2\0&#178;\0" \
+"sup3\0&#179;\0" \
+"acute\0&#180;\0" \
+"micro\0&#181;\0" \
+"para\0&#182;\0" \
+"middot\0&#183;\0" \
+"cedil\0&#184;\0" \
+"sup1\0&#185;\0" \
+"ordm\0&#186;\0" \
+"raquo\0&#187;\0" \
+"frac14\0&#188;\0" \
+"frac12\0&#189;\0" \
+"frac34\0&#190;\0" \
+"iquest\0&#191;\0" \
+"Agrave\0&#192;\0" \
+"Aacute\0&#193;\0" \
+"Acirc\0&#194;\0" \
+"Atilde\0&#195;\0" \
+"Auml\0&#196;\0" \
+"Aring\0&#197;\0" \
+"AElig\0&#198;\0" \
+"Ccedil\0&#199;\0" \
+"Egrave\0&#200;\0" \
+"Eacute\0&#201;\0" \
+"Ecirc\0&#202;\0" \
+"Euml\0&#203;\0" \
+"Igrave\0&#204;\0" \
+"Iacute\0&#205;\0" \
+"Icirc\0&#206;\0" \
+"Iuml\0&#207;\0" \
+"ETH\0&#208;\0" \
+"Ntilde\0&#209;\0" \
+"Ograve\0&#210;\0" \
+"Oacute\0&#211;\0" \
+"Ocirc\0&#212;\0" \
+"Otilde\0&#213;\0" \
+"Ouml\0&#214;\0" \
+"times\0&#215;\0" \
+"Oslash\0&#216;\0" \
+"Ugrave\0&#217;\0" \
+"Uacute\0&#218;\0" \
+"Ucirc\0&#219;\0" \
+"Uuml\0&#220;\0" \
+"Yacute\0&#221;\0" \
+"THORN\0&#222;\0" \
+"szlig\0&#223;\0" \
+"agrave\0&#224;\0" \
+"aacute\0&#225;\0" \
+"acirc\0&#226;\0" \
+"atilde\0&#227;\0" \
+"auml\0&#228;\0" \
+"aring\0&#229;\0" \
+"aelig\0&#230;\0" \
+"ccedil\0&#231;\0" \
+"egrave\0&#232;\0" \
+"eacute\0&#233;\0" \
+"ecirc\0&#234;\0" \
+"euml\0&#235;\0" \
+"igrave\0&#236;\0" \
+"iacute\0&#237;\0" \
+"icirc\0&#238;\0" \
+"iuml\0&#239;\0" \
+"eth\0&#240;\0" \
+"ntilde\0&#241;\0" \
+"ograve\0&#242;\0" \
+"oacute\0&#243;\0" \
+"ocirc\0&#244;\0" \
+"otilde\0&#245;\0" \
+"ouml\0&#246;\0" \
+"divide\0&#247;\0" \
+"oslash\0&#248;\0" \
+"ugrave\0&#249;\0" \
+"uacute\0&#250;\0" \
+"ucirc\0&#251;\0" \
+"uuml\0&#252;\0" \
+"yacute\0&#253;\0" \
+"thorn\0&#254;\0" \
+"yuml\0&#255;\0" \
+"fnof\0&#402;\0" \
+"Alpha\0&#913;\0" \
+"Beta\0&#914;\0" \
+"Gamma\0&#915;\0" \
+"Delta\0&#916;\0" \
+"Epsilon\0&#917;\0" \
+"Zeta\0&#918;\0" \
+"Eta\0&#919;\0" \
+"Theta\0&#920;\0" \
+"Iota\0&#921;\0" \
+"Kappa\0&#922;\0" \
+"Lambda\0&#923;\0" \
+"Mu\0&#924;\0" \
+"Nu\0&#925;\0" \
+"Xi\0&#926;\0" \
+"Omicron\0&#927;\0" \
+"Pi\0&#928;\0" \
+"Rho\0&#929;\0" \
+"Sigma\0&#931;\0" \
+"Tau\0&#932;\0" \
+"Upsilon\0&#933;\0" \
+"Phi\0&#934;\0" \
+"Chi\0&#935;\0" \
+"Psi\0&#936;\0" \
+"Omega\0&#937;\0" \
+"alpha\0&#945;\0" \
+"beta\0&#946;\0" \
+"gamma\0&#947;\0" \
+"delta\0&#948;\0" \
+"epsilon\0&#949;\0" \
+"zeta\0&#950;\0" \
+"eta\0&#951;\0" \
+"theta\0&#952;\0" \
+"iota\0&#953;\0" \
+"kappa\0&#954;\0" \
+"lambda\0&#955;\0" \
+"mu\0&#956;\0" \
+"nu\0&#957;\0" \
+"xi\0&#958;\0" \
+"omicron\0&#959;\0" \
+"pi\0&#960;\0" \
+"rho\0&#961;\0" \
+"sigmaf\0&#962;\0" \
+"sigma\0&#963;\0" \
+"tau\0&#964;\0" \
+"upsilon\0&#965;\0" \
+"phi\0&#966;\0" \
+"chi\0&#967;\0" \
+"psi\0&#968;\0" \
+"omega\0&#969;\0" \
+"thetasym\0&#977;\0" \
+"upsih\0&#978;\0" \
+"piv\0&#982;\0" \
+"bull\0&#8226;\0" \
+"hellip\0&#8230;\0" \
+"prime\0&#8242;\0" \
+"Prime\0&#8243;\0" \
+"oline\0&#8254;\0" \
+"frasl\0&#8260;\0" \
+"weierp\0&#8472;\0" \
+"image\0&#8465;\0" \
+"real\0&#8476;\0" \
+"trade\0&#8482;\0" \
+"alefsym\0&#8501;\0" \
+"larr\0&#8592;\0" \
+"uarr\0&#8593;\0" \
+"rarr\0&#8594;\0" \
+"darr\0&#8595;\0" \
+"harr\0&#8596;\0" \
+"crarr\0&#8629;\0" \
+"lArr\0&#8656;\0" \
+"uArr\0&#8657;\0" \
+"rArr\0&#8658;\0" \
+"dArr\0&#8659;\0" \
+"hArr\0&#8660;\0" \
+"forall\0&#8704;\0" \
+"part\0&#8706;\0" \
+"exist\0&#8707;\0" \
+"empty\0&#8709;\0" \
+"nabla\0&#8711;\0" \
+"isin\0&#8712;\0" \
+"notin\0&#8713;\0" \
+"ni\0&#8715;\0" \
+"prod\0&#8719;\0" \
+"sum\0&#8721;\0" \
+"minus\0&#8722;\0" \
+"lowast\0&#8727;\0" \
+"radic\0&#8730;\0" \
+"prop\0&#8733;\0" \
+"infin\0&#8734;\0" \
+"ang\0&#8736;\0" \
+"and\0&#8743;\0" \
+"or\0&#8744;\0" \
+"cap\0&#8745;\0" \
+"cup\0&#8746;\0" \
+"int\0&#8747;\0" \
+"there4\0&#8756;\0" \
+"sim\0&#8764;\0" \
+"cong\0&#8773;\0" \
+"asymp\0&#8776;\0" \
+"ne\0&#8800;\0" \
+"equiv\0&#8801;\0" \
+"le\0&#8804;\0" \
+"ge\0&#8805;\0" \
+"sub\0&#8834;\0" \
+"sup\0&#8835;\0" \
+"nsub\0&#8836;\0" \
+"sube\0&#8838;\0" \
+"supe\0&#8839;\0" \
+"oplus\0&#8853;\0" \
+"otimes\0&#8855;\0" \
+"perp\0&#8869;\0" \
+"sdot\0&#8901;\0" \
+"lceil\0&#8968;\0" \
+"rceil\0&#8969;\0" \
+"lfloor\0&#8970;\0" \
+"rfloor\0&#8971;\0" \
+"lang\0&#9001;\0" \
+"rang\0&#9002;\0" \
+"loz\0&#9674;\0" \
+"spades\0&#9824;\0" \
+"clubs\0&#9827;\0" \
+"hearts\0&#9829;\0" \
+"diams\0&#9830;\0" \
+"quot\0&#34;\0" \
+"amp\0&#38;\0" \
+"lt\0&#60;\0" \
+"gt\0&#62;\0" \
+"OElig\0&#338;\0" \
+"oelig\0&#339;\0" \
+"Scaron\0&#352;\0" \
+"scaron\0&#353;\0" \
+"Yuml\0&#376;\0" \
+"circ\0&#710;\0" \
+"tilde\0&#732;\0" \
+"ensp\0&#8194;\0" \
+"emsp\0&#8195;\0" \
+"thinsp\0&#8201;\0" \
+"zwnj\0&#8204;\0" \
+"zwj\0&#8205;\0" \
+"lrm\0&#8206;\0" \
+"rlm\0&#8207;\0" \
+"ndash\0&#8211;\0" \
+"mdash\0&#8212;\0" \
+"lsquo\0&#8216;\0" \
+"rsquo\0&#8217;\0" \
+"sbquo\0&#8218;\0" \
+"ldquo\0&#8220;\0" \
+"rdquo\0&#8221;\0" \
+"bdquo\0&#8222;\0" \
+"dagger\0&#8224;\0" \
+"Dagger\0&#8225;\0" \
+"permil\0&#8240;\0" \
+"lsaquo\0&#8249;\0" \
+"rsaquo\0&#8250;\0" \
+"euro\0&#8364;\0"
+
+#endif /* ndef entities_h */
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/lex.c b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/lex.c
new file mode 100644
index 000000000..9f9103386
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/lex.c
@@ -0,0 +1,560 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "lex.h"
+#include "misc.h"
+#include "node.h"
+#include "process.h"
+
+struct file {
+ struct file *next;
+ const char *filename;
+ char *buf;
+ const char *pos, *end;
+ unsigned int linenum;
+};
+
+const char keywords[] = KEYWORDS;
+
+static struct file *file, *firstfile;
+static struct tok tok;
+
+/***********************************************************************
+ * readinput : read all input files into memory
+ *
+ * Enter: argv = 0-terminated array of filenames
+ */
+void
+readinput(const char *const *argv)
+{
+ struct file **pfile = &file;
+ for (;;) {
+ struct file *file;
+ const char *filename = *argv++;
+ char *buf = 0;
+ int len = 0, thislen, isstdin;
+ FILE *handle;
+ if (!filename)
+ break;
+ /* Read the file. */
+ isstdin = !strcmp(filename, "-");
+ if (isstdin) {
+ handle = stdin;
+ filename = "<stdin>";
+ } else {
+ handle = fopen(filename, "rb");
+ if (!handle)
+ errorexit("%s: %s", filename, strerror(errno));
+ }
+ for (;;) {
+ thislen = len ? len * 2 : 4096;
+ buf = memrealloc(buf, len + thislen + 1);
+ thislen = fread(buf + len, 1, thislen, handle);
+ if (!thislen)
+ break;
+ len += thislen;
+ }
+ if (ferror(handle))
+ errorexit("%s: I/O error", filename);
+ if (!isstdin)
+ fclose(handle);
+ buf[len] = 0;
+ buf = memrealloc(buf, len + 1);
+ /* Create the file struct for it. */
+ file = memalloc(sizeof(struct file));
+ *pfile = file;
+ pfile = &file->next;
+ file->filename = filename;
+ file->pos = file->buf = buf;
+ file->end = buf + len;
+ file->linenum = 1;
+ }
+ *pfile = 0;
+ firstfile = file;
+}
+
+/***********************************************************************
+ * lexerrorexit : error and exit with line number
+ */
+static void
+lexerrorexit(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlocerrorexit(file->filename, file->linenum, format, ap);
+ va_end(ap);
+}
+
+/***********************************************************************
+ * lexblockcomment : lex a block comment
+ *
+ * Enter: start = start of comment
+ *
+ * Return: tok struct, lifetime until next call to lex
+ */
+static struct tok *
+lexblockcomment(const char *start)
+{
+ const char *p = start + 1;
+ tok.filename = file->filename;
+ tok.linenum = file->linenum;
+ for (;;) {
+ int ch = *++p;
+ if (!ch)
+ lexerrorexit("unterminated block comment");
+ if (ch != '*') {
+ if (ch == '\n')
+ file->linenum++;
+ continue;
+ }
+ ch = p[1];
+ if (!ch)
+ lexerrorexit("unterminated block comment");
+ if (ch == '/')
+ break;
+ }
+ p += 2;
+ file->pos = p;
+ tok.type = TOK_BLOCKCOMMENT;
+ tok.start = start + 2;
+ tok.len = p - start - 4;
+ return &tok;
+}
+
+/***********************************************************************
+ * lexinlinecomment : lex an inline comment
+ *
+ * Enter: start = start of comment, starts with "//"
+ *
+ * Return: tok struct, lifetime until next call to lex
+ */
+static struct tok *
+lexinlinecomment(const char *start)
+{
+ const char *p = start + 2;
+ p = start + 1;
+ for (;;) {
+ int ch = *++p;
+ if (!ch || ch == '\n')
+ break;
+ }
+ p++;
+ file->pos = p;
+ tok.type = TOK_INLINECOMMENT;
+ tok.start = start + 2;
+ tok.len = p - start - 2;
+ tok.filename = file->filename;
+ tok.linenum = file->linenum++;
+ return &tok;
+}
+
+/***********************************************************************
+ * lexnumber : lex a number (or just a '-' symbol)
+ *
+ * Enter: start = start of token
+ *
+ * Return: tok struct, lifetime until next call to lex
+ *
+ * The IDL grammar seems to say that a float can't start with a
+ * decimal point, so that's what we have implemented here.
+ */
+static struct tok *
+lexnumber(const char *start)
+{
+ for (;;) {
+ const char *p = start;
+ const char *octalend = start;
+ int ch = *p;
+ enum { STATE_START, STATE_INT, STATE_HEX, STATE_OCTAL, STATE_BADOCTAL,
+ STATE_DP, STATE_EXPSTART, STATE_EXPSIGN, STATE_EXP
+ } state = STATE_START;
+ if (ch == '-') {
+ ch = *++p;
+ if (ch == 'I') { // starts of Infinity
+ char * infinity = "-Infinity";
+ unsigned int len = strlen(infinity);
+ if (!memcmp(start, infinity, len)) {
+ tok.type = TOK_minusinfinity;
+ tok.start = start;
+ tok.len = len;
+ tok.filename = file->filename;
+ tok.linenum = file->linenum;
+ file->pos = start + len;
+ return &tok;
+ }
+ }
+ }
+ if (ch == '0') {
+ state = STATE_OCTAL;
+ ch = *++p;
+ if ((ch & ~0x20) == 'X') {
+ state = STATE_HEX;
+ ch = *++p;
+ }
+ }
+
+ for (;;) {
+ if ((unsigned)(ch - '0') >= 8) {
+ if ((ch & -2) == '8') {
+ if (state == STATE_OCTAL) {
+ state = STATE_BADOCTAL;
+ octalend = p;
+ }
+ } else if ((unsigned)((ch & ~0x20) - 'A') <= 'F' - 'A') {
+ if (state != STATE_HEX) {
+ if ((ch & ~0x20) != 'E')
+ break;
+ if (state == STATE_HEX || state >= STATE_EXPSTART || state == STATE_START)
+ break;
+ state = STATE_EXPSTART;
+ }
+ } else if (ch == '.') {
+ if (state == STATE_HEX || state >= STATE_DP)
+ break;
+ state = STATE_DP;
+ } else if (ch == '-') {
+ if (state != STATE_EXPSTART)
+ break;
+ state = STATE_EXPSIGN;
+ } else
+ break;
+ }
+ ch = *++p;
+ if (state == STATE_START)
+ state = STATE_INT;
+ else if (state == STATE_EXPSTART || state == STATE_EXPSIGN)
+ state = STATE_EXP;
+ }
+ switch (state) {
+ case STATE_START:
+ /* Must have just been a - character by itself. */
+ tok.type = '-';
+ p = start + 1;
+ break;
+ case STATE_BADOCTAL:
+ p = octalend;
+ /* fall through... */
+ case STATE_INT:
+ case STATE_OCTAL:
+ tok.type = TOK_INTEGER;
+ break;
+ case STATE_HEX:
+ if (p - start == 2 || (p - start == 3 && *start == '-'))
+ p = start + 1;
+ tok.type = TOK_INTEGER;
+ break;
+ case STATE_EXP:
+ case STATE_DP:
+ tok.type = TOK_FLOAT;
+ break;
+ case STATE_EXPSIGN:
+ p--;
+ /* fall through... */
+ case STATE_EXPSTART:
+ p--;
+ tok.type = TOK_FLOAT;
+ break;
+ }
+ tok.start = start;
+ tok.len = p - start;
+ tok.filename = file->filename;
+ tok.linenum = file->linenum;
+ file->pos = p;
+ return &tok;
+ }
+}
+
+/***********************************************************************
+ * lexstring : lex a quoted string
+ *
+ * Enter: start = start of token
+ *
+ * Return: tok struct, lifetime until next call to lex
+ */
+static struct tok *
+lexstring(const char *start)
+{
+ for (;;) {
+ const char *p = start + 1;
+ int ch = *p;
+ for (;;) {
+ if (!ch || ch == '\n')
+ lexerrorexit("unterminated string");
+ if (ch == '"') {
+ tok.type = TOK_STRING;
+ tok.start = start + 1;
+ tok.len = p - start - 1;
+ tok.filename = file->filename;
+ tok.linenum = file->linenum;
+ file->pos = p + 1;
+ return &tok;
+ }
+ /* Note the IDL spec doesn't seem to allow for escape sequences
+ * in strings. */
+ ch = *++p;
+ }
+ }
+}
+
+/***********************************************************************
+ * lexidentifier : lex an identifier
+ *
+ * Enter: start = start of token
+ *
+ * Return: tok struct, lifetime until next call to lex
+ */
+static struct tok *
+lexidentifier(const char *start)
+{
+ const char *p = start + 1;
+ for (;;) {
+ int ch = *p;
+ if (ch != '_' && (unsigned)(ch - '0') >= 10
+ && (unsigned)((ch & ~0x20) - 'A') > 'Z' - 'A')
+ {
+ break;
+ }
+ p++;
+ }
+ tok.type = TOK_IDENTIFIER;
+ tok.start = start;
+ tok.len = p - start;
+ tok.filename = file->filename;
+ tok.linenum = file->linenum;
+ file->pos = p;
+ /* See if this is a keyword. (This search is a bit n-squared.) */
+ {
+ unsigned int type = TOK_DOMString;
+ p = keywords;
+ for (;;) {
+ unsigned int len = strlen(p);
+ if (!len)
+ break;
+ if (len == tok.len && !memcmp(start, p, len)) {
+ tok.type = type;
+ break;
+ }
+ p += len + 1;
+ type++;
+ }
+ }
+ return &tok;
+}
+
+/***********************************************************************
+ * lex : retrieve next token
+ *
+ * Return: tok struct, lifetime until next call to lex
+ */
+struct tok *
+lex(void)
+{
+ const char *p;
+ int ch;
+ for (;;) {
+ if (!file) {
+ tok.type = TOK_EOF;
+ tok.start = "end of file";
+ tok.len = strlen(tok.start);
+ return &tok;
+ }
+ tok.prestart = p = file->pos;
+ /* Flush whitespace. */
+ for (;;) {
+ ch = *p++;
+ switch (ch) {
+ case ' ':
+ case '\t':
+ case '\r':
+ continue;
+ case '\n':
+ ++file->linenum;
+ tok.prestart = p;
+ continue;
+ }
+ break;
+ }
+ p--;
+ if (ch)
+ break;
+ if (p != file->end)
+ lexerrorexit("\\0 byte not allowed");
+ file = file->next;
+ }
+ /* See if we have a comment. */
+ tok.start = p;
+ if (ch == '/') {
+ switch (*++p) {
+ case '*':
+ return lexblockcomment(p - 1);
+ case '/':
+ return lexinlinecomment(p - 1);
+ }
+ tok.type = '/';
+ } else {
+ /* Handle things that start with '-', which is either '-' as a token,
+ * or a number. Handle numbers. */
+ if (ch == '-' || (unsigned)(ch - '0') < 10)
+ return lexnumber(p);
+ /* Handle string. */
+ if (ch == '"')
+ return lexstring(p);
+ /* Handle identifier. */
+ if (ch == '_' || (unsigned)((ch & ~0x20) - 'A') <= 'Z' - 'A')
+ return lexidentifier(p);
+ /* The only multi-symbol token are ... and [] */
+ if (ch == '.') {
+ tok.type = '.';
+ if (*++p == '.' && p[1] == '.') {
+ tok.type = TOK_ELLIPSIS;
+ p += 2;
+ }
+ goto done;
+ }
+ if (ch == '[') {
+ tok.type = '[';
+ if (*++p == ']') {
+ tok.type = TOK_DOUBLEBRACKET;
+ p++;
+ }
+ goto done;
+ }
+ }
+ /* Single symbol token. */
+ tok.type = ch;
+ p++;
+done:
+ tok.filename = file->filename;
+ tok.linenum = file->linenum;
+ tok.len = p - tok.start;
+ file->pos = p;
+ return &tok;
+}
+
+/***********************************************************************
+ * outputwidl : output literal Web IDL input that node was parsed from
+ *
+ * Enter: node = parse node to output literal Web IDL for
+ */
+void
+outputwidl(struct node *node)
+{
+ const char *start = node->wsstart, *end = node->end;
+ /* Find the file that start is in. */
+ struct file *file = firstfile;
+ while (start < file->buf || start >= file->end) {
+ file = file->next;
+ assert(file);
+ }
+ /* Find the (current or) next node that has node->start set. Any such
+ * node needs to be put inside a <ref> element. */
+ while (node && !node->start)
+ node = nodewalk(node);
+ /* Output until we get to the end. This has to cope with the text
+ * spanning multiple input files. */
+ for (;;) {
+ int final = end >= file->buf && end <= file->end;
+ const char *thisend = final ? end : file->end;
+ /* Output the Web IDL, omitting comments. */
+ while (start != end) {
+ const char *p, *p2, *comment, *endcomment;
+ int ch;
+ if (node && start == node->start) {
+ /* We are on the start of the present node in the tree
+ * walk. Put it in a <ref>. */
+ fputs("<ref>", stdout);
+ printtext(node->start, node->end - node->start, 1);
+ fputs("</ref>", stdout);
+ start = node->end;
+ /* Skip to the next node with node->start set if any. */
+ do
+ node = nodewalk(node);
+ while (node && !node->start);
+ continue;
+ }
+ p2 = thisend;
+ if (node && node->start >= file->buf && node->start < p2)
+ p2 = node->start;
+ p = memchr(start, '/', p2 - start);
+ if (!p) {
+ printtext(start, p2 - start, 1);
+ if (p2 != thisend) {
+ start = p2;
+ continue;
+ }
+ break;
+ }
+ /* See if we're at the start of a comment. If so find the end. */
+ comment = 0;
+ if (p + 1 != thisend) {
+ switch (p[1]) {
+ case '*':
+ /* Block comment. */
+ comment = p;
+ p++;
+ do
+ p = memchr(p + 1, '*', thisend - p - 1);
+ while (p[1] != '/');
+ endcomment = p + 2;
+ break;
+ case '/':
+ /* Inline comment. */
+ comment = p;
+ p = memchr(p, '\n', thisend - p);
+ if (!p)
+ p = thisend;
+ endcomment = p;
+ break;
+ }
+ }
+ if (!comment) {
+ /* Not at start of comment. */
+ p++;
+ printtext(start, p - start, 1);
+ start = p;
+ assert(start <= end);
+ continue;
+ }
+ /* If the comment has only whitespace before it on the line,
+ * eat that up. */
+ p = comment;
+ while (p != start && ((ch = p[-1]) == ' ' || ch == '\t'))
+ p--;
+ if (p == start || p[-1] == '\n') {
+ comment = p;
+ /* If the comment has only whitespace after it to the end
+ * of the line, eat that and the newline up. This always
+ * happens for an inline comment on a line by itself. */
+ p = endcomment;
+ while (p != thisend && ((ch = *p) == ' ' || ch == '\t'))
+ p++;
+ if (p != thisend && *p == '\n')
+ p++;
+ endcomment = p;
+ }
+ printtext(start, comment - start, 1);
+ start = endcomment;
+ if (start > thisend)
+ start = thisend;
+ }
+ if (final)
+ break;
+ file = file->next;
+ assert(file);
+ start = file->buf;
+ }
+}
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/lex.h b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/lex.h
new file mode 100644
index 000000000..e30b77b36
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/lex.h
@@ -0,0 +1,141 @@
+
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#ifndef lex_h
+#define lex_h
+
+// starting from "attribute" are the list of names allowed as arguments identifier
+#define KEYWORDS \
+ "DOMString\0" \
+ "ByteString\0" \
+ "Date\0" \
+ "RegExp\0" \
+ "false\0" \
+ "object\0" \
+ "true\0" \
+ "any\0" \
+ "boolean\0" \
+ "byte\0" \
+ "double\0" \
+ "float\0" \
+ "Infinity\0" \
+ "-Infinity\0" \
+ "iterator\0" \
+ "long\0" \
+ "NaN\0" \
+ "null\0" \
+ "octet\0" \
+ "optional\0" \
+ "or\0" \
+ "readonly\0" \
+ "sequence\0" \
+ "short\0" \
+ "unsigned\0" \
+ "void\0" \
+ "attribute\0" \
+ "callback\0" \
+ "const\0" \
+ "creator\0" \
+ "deleter\0" \
+ "dictionary\0" \
+ "enum\0" \
+ "exception\0" \
+ "getter\0" \
+ "implements\0" \
+ "inherit\0" \
+ "interface\0" \
+ "legacycaller\0" \
+ "partial\0" \
+ "serializer\0" \
+ "setter\0" \
+ "static\0" \
+ "stringifier\0" \
+ "typedef\0" \
+ "unrestricted\0"
+
+
+enum toktype {
+ TOK_EOF = -1,
+ TOK_BLOCKCOMMENT = 0x80,
+ TOK_INLINECOMMENT, TOK_INTEGER, TOK_FLOAT, TOK_IDENTIFIER,
+ TOK_STRING, TOK_ELLIPSIS, TOK_DOUBLEBRACKET,
+ /* Keywords must be in the same order as above. */
+ TOK_DOMString,
+ TOK_ByteString,
+ TOK_Date,
+ TOK_RegExp,
+ TOK_false,
+ TOK_object,
+ TOK_true,
+ TOK_any,
+ TOK_boolean,
+ TOK_byte,
+ TOK_double,
+ TOK_float,
+ TOK_infinity,
+ TOK_minusinfinity,
+ TOK_iterator,
+ TOK_long,
+ TOK_NaN,
+ TOK_null,
+ TOK_octet,
+ TOK_optional,
+ TOK_or,
+ TOK_readonly,
+ TOK_sequence,
+ TOK_short,
+ TOK_unsigned,
+ TOK_void,
+ /* Below that line are keywords that are allowed as arguments names */
+ TOK_attribute,
+ TOK_callback,
+ TOK_const,
+ TOK_creator,
+ TOK_deleter,
+ TOK_dictionary,
+ TOK_enum,
+ TOK_exception,
+ TOK_getter,
+ TOK_implements,
+ TOK_inherit,
+ TOK_interface,
+ TOK_legacycaller,
+ TOK_partial,
+ TOK_serializer,
+ TOK_setter,
+ TOK_static,
+ TOK_stringifier,
+ TOK_typedef,
+ TOK_unrestricted,
+};
+
+struct tok {
+ enum toktype type;
+ const char *filename;
+ unsigned int linenum;
+ const char *prestart;
+ const char *start;
+ unsigned int len;
+};
+
+extern const char *filename;
+extern const char keywords[];
+
+struct node;
+
+void readinput(const char *const *argv);
+struct tok *lex(void);
+void outputwidl(struct node *node);
+
+#endif /* ndef lex_h */
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/main.c b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/main.c
new file mode 100644
index 000000000..df90e347d
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/main.c
@@ -0,0 +1,63 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#include <string.h>
+#include "misc.h"
+#include "process.h"
+
+static const char nodtdopt[] = "-no-dtd-ref";
+const char *progname;
+
+/***********************************************************************
+ * options : process command line options
+ *
+ * Enter: argv
+ *
+ * Return: argv stepped to point to first non-option argument
+ */
+static const char *const *
+options(int argc, const char *const *argv)
+{
+ /* Set progname for error messages etc. */
+ {
+ const char *base;
+ progname = argv[0];
+ base = strrchr(progname, '/');
+#ifdef DIRSEP
+ {
+ const char *base2 = strrchr(base, '\\');
+ if (base2 > base)
+ base = base2;
+ }
+#endif /* def DIRSEP */
+ if (base)
+ progname = base + 1;
+ }
+ return (argc > 1 && strncmp(argv[1], nodtdopt, sizeof nodtdopt) == 0)
+ ? argv + 2 : argv + 1;
+}
+
+/***********************************************************************
+ * main : main code for bondiidl command
+ */
+int
+main(int argc, char **argv)
+{
+ const char *const *parg;
+ parg = options(argc, (const char *const *)argv);
+ if (!*parg)
+ errorexit("usage: %s [-no-dtd-ref] <interface>.widl ...", progname);
+ processfiles(parg, parg == (const char *const *)argv + 1);
+ return 0;
+}
+
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/misc.c b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/misc.c
new file mode 100644
index 000000000..37aff3f34
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/misc.c
@@ -0,0 +1,119 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "misc.h"
+#include "os.h" /* to get va_copy on windows */
+
+extern const char *progname;
+
+/***********************************************************************
+ * memory allocation wrappers
+ */
+void *
+memalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (!ptr)
+ errorexit("out of memory");
+ /* Zero initialise memory from memalloc. */
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void *
+memrealloc(void *ptr, size_t size)
+{
+ void *newptr = realloc(ptr, size);
+ if (!newptr)
+ errorexit("out of memory");
+ return newptr;
+}
+
+void
+memfree(void *ptr)
+{
+ *(int *)ptr = 0xfefefefe;
+ free(ptr);
+}
+
+/***********************************************************************
+ * vmemprintf, memprintf : allocate buffer and sprintf into it
+ */
+char *
+memprintf(const char *format, ...)
+{
+ va_list ap;
+ char *buf;
+ va_start(ap, format);
+ buf = vmemprintf(format, ap);
+ va_end(ap);
+ return buf;
+}
+
+char *
+vmemprintf(const char *format, va_list ap)
+{
+ char *buf;
+ unsigned int max, len;
+ va_list ap2;
+ max = 16;
+ for (;;) {
+ va_copy(ap2, ap);
+ buf = memalloc(max);
+ len = vsnprintf(buf, max, format, ap2);
+ va_end(ap2);
+ if (len < max)
+ break;
+ memfree(buf);
+ max *= 2;
+ }
+ return buf;
+}
+
+/***********************************************************************
+ * errorexit : print error message then exit
+ */
+void
+vlocerrorexit(const char *filename, unsigned int linenum,
+ const char *format, va_list ap)
+{
+ if (filename)
+ fprintf(stderr, linenum ? "%s: %i: " : "%s: ", filename, linenum);
+ vfprintf(stderr, format, ap);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+void
+locerrorexit(const char *filename, unsigned int linenum,
+ const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlocerrorexit(filename, linenum, format, ap);
+ va_end(ap);
+}
+
+void
+errorexit(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlocerrorexit(0, 0, format, ap);
+ va_end(ap);
+}
+
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/misc.h b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/misc.h
new file mode 100644
index 000000000..01c36d218
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/misc.h
@@ -0,0 +1,31 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#ifndef misc_h
+#define misc_h
+#include <stdarg.h>
+#include <stdlib.h>
+
+void *memalloc(size_t size);
+void *memrealloc(void *ptr, size_t size);
+void memfree(void *ptr);
+
+char *vmemprintf(const char *format, va_list ap);
+char *memprintf(const char *format, ...);
+
+void vlocerrorexit(const char *filename, unsigned int linenum, const char *format, va_list ap);
+void locerrorexit(const char *filename, unsigned int linenum, const char *format, ...);
+void errorexit(const char *format, ...);
+
+#endif /* ndef misc_h */
+
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/node.c b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/node.c
new file mode 100644
index 000000000..d8f737909
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/node.c
@@ -0,0 +1,331 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Node-specific functions
+ ***********************************************************************/
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "comment.h"
+#include "lex.h"
+#include "misc.h"
+#include "node.h"
+#include "process.h"
+
+struct node *
+newelement(const char *name)
+{
+ struct element *element = memalloc(sizeof(struct element));
+ element->n.type = NODE_ELEMENT;
+ element->name = name;
+ return &element->n;
+}
+
+struct node *
+newattr(const char *name, const char *val)
+{
+ struct attr *attr = memalloc(sizeof(struct attr));
+ attr->n.type = NODE_ATTR;
+ attr->name = name;
+ attr->value = val;
+ return &attr->n;
+}
+
+struct node *
+newattrlist(void)
+{
+ struct attrlist *attrlist = memalloc(sizeof(struct attrlist));
+ attrlist->n.type = NODE_ATTRLIST;
+ return &attrlist->n;
+}
+
+/***********************************************************************
+ * addnode : add node as child of another node
+ *
+ * Enter: parent node
+ * child node
+ *
+ * The children list is constructed backwards. This is fixed later with
+ * a call to reversechildren.
+ *
+ * If child is an attrlist, its children are added to parent and the
+ * attrlist is freed.
+ */
+void
+addnode(struct node *parent, struct node *child)
+{
+ if (!child)
+ return;
+ if (child->type == NODE_ATTRLIST) {
+ /* Add the attrs in the attrlist to parent. */
+ struct node *child2;
+ reversechildren(child);
+ child2 = child->children;
+ memfree(child);
+ while (child2) {
+ struct node *next = child2->next;
+ addnode(parent, child2);
+ child2 = next;
+ }
+ } else {
+ child->next = parent->children;
+ parent->children = child;
+ child->parent = parent;
+ }
+}
+
+/***********************************************************************
+ * reversechildren : recursively reverse child lists
+ *
+ * Also sets parent field on each node.
+ */
+void
+reversechildren(struct node *node)
+{
+ struct node *newlist = 0;
+ struct node *child = node->children;
+ while (child) {
+ struct node *next = child->next;
+ child->parent = node;
+ child->next = newlist;
+ newlist = child;
+ reversechildren(child);
+ child = next;
+ }
+ node->children = newlist;
+}
+
+/***********************************************************************
+ * nodeisempty : test if node is empty (has no children)
+ */
+int
+nodeisempty(struct node *node)
+{
+ return !node->children;
+}
+
+/***********************************************************************
+ * nodewalk : single step of depth last traversal of node tree
+ *
+ * Return: next node in walk, 0 if finished
+ */
+struct node *
+nodewalk(struct node *node)
+{
+ if (node->children)
+ return node->children;
+ if (node->next)
+ return node->next;
+ do {
+ node = node->parent;
+ if (!node)
+ return 0;
+ } while (!node->next);
+ return node->next;
+}
+
+/***********************************************************************
+ * findchildelement : find child element of a particular name
+ *
+ * Enter: node = element
+ * name = name to find
+ *
+ * Return: 0 else child element of that name
+ */
+static struct node *
+findchildelement(struct node *node, const char *name)
+{
+ node = node->children;
+ while (node) {
+ if (node->type == NODE_ELEMENT) {
+ struct element *element = (void *)node;
+ if (!strcmp(element->name, name))
+ break;
+ }
+ node = node->next;
+ }
+ return node;
+}
+
+/***********************************************************************
+ * getattr : get value of attribute
+ *
+ * Enter: node = element to find attribute in
+ * name = name of attribute
+ *
+ * Return: 0 if not found, else 0-terminated string value
+ */
+const char *
+getattr(struct node *node, const char *name)
+{
+ node = node->children;
+ while (node) {
+ if (node->type == NODE_ATTR) {
+ struct attr *attr = (void *)node;
+ if (!strcmp(attr->name, name))
+ return attr->value;
+ }
+ node = node->next;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * findchildelementwithnameattr : find child element with a name attribute
+ * of a particular value
+ *
+ * Enter: node = element
+ * name = name to find
+ *
+ * Return: 0 else child element with name attr of that value
+ */
+static struct node *
+findchildelementwithnameattr(struct node *node, const char *name)
+{
+ node = node->children;
+ while (node) {
+ if (node->type == NODE_ELEMENT) {
+ const char *s = getattr(node, "name");
+ if (s && !strcmp(s, name))
+ break;
+ }
+ node = node->next;
+ }
+ return node;
+}
+
+/***********************************************************************
+ * findreturntype : find Type parse node for return type
+ *
+ * Enter: node = Operation element
+ *
+ * Return: 0 if not found, else Type parse node for return type
+ */
+struct node *
+findreturntype(struct node *node)
+{
+ return findchildelement(node, "Type");
+}
+
+/***********************************************************************
+ * findparamidentifier : find identifier parse node for parameter
+ *
+ * Enter: node = Operation element
+ * name = parameter name to find
+ *
+ * Return: 0 if not found, else node struct for parameter identifier
+ */
+struct node *
+findparamidentifier(struct node *node, const char *name)
+{
+ node = findchildelement(node, "ArgumentList");
+ if (node)
+ node = findchildelementwithnameattr(node, name);
+ return node;
+}
+
+/***********************************************************************
+ * findthrowidentifier : find identifier parse node for exception name
+ *
+ * Enter: node = Operation element
+ * name = exception name to find
+ *
+ * Return: 0 if not found, else node for Name element, child of Raises
+ * or SetRaises
+ */
+struct node *
+findthrowidentifier(struct node *node, const char *name)
+{
+ struct node *node2 = findchildelement(node, "Raises");
+ if (node2)
+ node2 = findchildelementwithnameattr(node2, name);
+ if (!node2) {
+ node2 = findchildelement(node, "SetRaises");
+ if (node2)
+ node2 = findchildelementwithnameattr(node2, name);
+ }
+ return node2;
+}
+
+/***********************************************************************
+ * outputid : output the id of a node
+ */
+static void
+outputid(struct node *node)
+{
+ if (node->parent)
+ outputid(node->parent);
+ if (node->id) {
+ fputs("::", stdout);
+ printtext(node->id, strlen(node->id), 1);
+ }
+}
+
+/***********************************************************************
+ * outputnode : output node and its children
+ *
+ * Enter: node = node to output, assumed to be an element
+ * indent
+ */
+void
+outputnode(struct node *node, unsigned int indent)
+{
+ struct element *element = (void *)node;
+ struct node *child;
+ int empty = 1;
+ printf("%*s<%s", indent, "", element->name);
+ child = element->n.children;
+ while (child) {
+ switch(child->type) {
+ case NODE_ELEMENT:
+ empty = 0;
+ break;
+ case NODE_ATTR:
+ {
+ struct attr *attr = (void *)child;
+ printf(" %s=\"", attr->name);
+ printtext(attr->value, strlen(attr->value), 1);
+ printf("\"");
+ }
+ break;
+ }
+ child = child->next;
+ }
+ if (node->id) {
+ printf(" id=\"");
+ outputid(node);
+ printf("\"");
+ }
+ if (!empty || node->comments || node->wsstart) {
+ printf(">\n");
+ if (node->wsstart) {
+ printf("%*s <webidl>", indent, "");
+ outputwidl(node);
+ printf("</webidl>\n");
+ }
+ outputdescriptive(node, indent + 2);
+ child = element->n.children;
+ while (child) {
+ switch(child->type) {
+ case NODE_ELEMENT:
+ outputnode(child, indent + 2);
+ break;
+ }
+ child = child->next;
+ }
+ printf("%*s</%s>\n", indent, "", element->name);
+ } else
+ printf("/>\n");
+}
+
+
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/node.h b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/node.h
new file mode 100644
index 000000000..2d6e38e53
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/node.h
@@ -0,0 +1,65 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#ifndef node_h
+#define node_h
+
+/* struct node : a node in the parse tree (excluding comments) */
+enum { NODE_ELEMENT, NODE_ATTR, NODE_ATTRLIST };
+struct node {
+ int type;
+ struct node *next;
+ struct node *parent;
+ struct node *children;
+ struct comment *comments; /* list of comments attached to this node */
+ /* If wsstart and end are set, they give the literal Web IDL that can
+ * be output in a <webidl> element. */
+ const char *wsstart;
+ /* If start and end are set, they give the text of a scoped name that
+ * can be enclosed in a <ref> when outputting a <webidl> element for
+ * an ancestor element. */
+ const char *start;
+ const char *end;
+ const char *id;
+};
+
+struct element {
+ struct node n;
+ const char *name;
+};
+
+struct attr {
+ struct node n;
+ const char *name;
+ const char *value;
+};
+
+struct attrlist {
+ struct node n;
+};
+
+struct node *newelement(const char *name);
+struct node *newattr(const char *name, const char *val);
+struct node *newattrlist(void);
+void addnode(struct node *parent, struct node *child);
+void reversechildren(struct node *node);
+int nodeisempty(struct node *node);
+const char *getattr(struct node *node, const char *name);
+struct node *nodewalk(struct node *node);
+struct node *findreturntype(struct node *node);
+struct node *findparamidentifier(struct node *node, const char *name);
+struct node *findthrowidentifier(struct node *node, const char *name);
+void outputnode(struct node *node, unsigned int indent);
+
+#endif /* ndef node_h */
+
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/os.h b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/os.h
new file mode 100644
index 000000000..ac8f4189d
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/os.h
@@ -0,0 +1,31 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#ifndef os_h
+#define os_h
+
+/* Linux configuration */
+#if defined(__gnu_linux__)
+
+
+/* Windows configuration */
+#elif defined(_MSC_VER)
+
+#define inline __inline
+#define strncasecmp strnicmp
+#define snprintf _snprintf
+#define va_copy(a,b) ((a)=(b))
+
+#endif
+
+#endif /* ndef os_h */
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/parse.c b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/parse.c
new file mode 100644
index 000000000..c0e8454ce
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/parse.c
@@ -0,0 +1,1414 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Hand-crafted recursive descent parser for Web IDL grammar.
+ ***********************************************************************/
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "comment.h"
+#include "lex.h"
+#include "misc.h"
+#include "node.h"
+#include "parse.h"
+
+/***********************************************************************
+ * tokerrorexit : error and exit with line number from token
+ */
+static void
+tokerrorexit(struct tok *tok, const char *format, ...)
+{
+ va_list ap;
+ char *m;
+ va_start(ap, format);
+ m = vmemprintf(format, ap);
+ if (tok->type == TOK_EOF)
+ locerrorexit(tok->filename, tok->linenum, "at end of input: %s", m);
+ else
+ locerrorexit(tok->filename, tok->linenum, "at '%.*s': %s", tok->len, tok->start, m);
+ va_end(ap);
+}
+
+/***********************************************************************
+ * lexnocomment : lex next token, discarding or storing comments
+ *
+ * A block comment starting with |** or |*! is a doxygen comment.
+ * If it starts with |**< or |*!< then it refers to the previous
+ * identifier, not the next one. (I am using | to represent / otherwise
+ * this comment would be illegal.)
+ *
+ * An inline comment starting with /// or //! is a doxygen comment.
+ * If it starts with ///< or //!< then it refers to the previous
+ * identifier, not the next one.
+ */
+static struct tok *
+lexnocomment(void)
+{
+ struct tok *tok;
+ for (;;) {
+ tok = lex();
+ if (tok->type != TOK_BLOCKCOMMENT && tok->type != TOK_INLINECOMMENT)
+ break;
+ addcomment(tok);
+ }
+ return tok;
+}
+
+/***********************************************************************
+ * eat : check token then read the following one
+ *
+ * Enter: tok struct
+ * type = type of token expected, error given if no match
+ *
+ * On return, tok is updated to the following token.
+ */
+static void
+eat(struct tok *tok, int type)
+{
+ if (tok->type != type) {
+ const char *p;
+ if (type < TOK_DOMString)
+ tokerrorexit(tok, "expected '%c'", type);
+ p = keywords;
+ while (type != TOK_DOMString) {
+ p += strlen(p) + 1;
+ type--;
+ }
+ tokerrorexit(tok, "expected '%s'", p);
+ }
+ lexnocomment();
+}
+
+/***********************************************************************
+ * setid : flag that an id attribute is required on node
+ *
+ * Enter: node
+ *
+ * node->id is set to the value of the name attribute. This makes
+ * outputnode give it an id attribute whose value is the id attribute
+ * of the parent if any, then "::", then node->id.
+ */
+static void
+setid(struct node *node)
+{
+ node->id = getattr(node, "name");
+}
+
+/***********************************************************************
+ * setidentifier : allocate 0-terminated string for identifier token
+ *
+ * Enter: tok = token, error given if not identifier
+ *
+ * Return: allocated 0-terminated string
+ */
+static char *
+setidentifier(struct tok *tok)
+{
+ char *s;
+ if (tok->type != TOK_IDENTIFIER)
+ tokerrorexit(tok, "expected identifier");
+ s = memprintf("%.*s", tok->len, tok->start);
+ return s;
+}
+
+/***********************************************************************
+ * setargumentname : allocate 0-terminated string for identifier token
+ *
+ * Enter: tok = token, error given if not identifier
+ *
+ * Return: allocated 0-terminated string
+ */
+static char *
+setargumentname(struct tok *tok)
+{
+ char *s;
+ if (tok->type != TOK_IDENTIFIER && tok->type < TOK_attribute)
+ tokerrorexit(tok, "expected argument name");
+ s = memprintf("%.*s", tok->len, tok->start);
+ return s;
+}
+
+
+/* Prototypes for funcs that have a forward reference. */
+static struct node *parsetype(struct tok *tok);
+static struct node *parsedefaultvalue(struct tok *tok, struct node *parent);
+static struct node *parseuniontype(struct tok *tok);
+static struct node *parseargumentlist(struct tok *tok);
+static void parsedefinitions(struct tok *tok, struct node *parent);
+static struct node *parsetypesuffixstartingwitharray(struct tok *tok, struct node *node);
+
+/***********************************************************************
+ * parsescopedname : parse [53] ScopedName
+ *
+ * Enter: tok = next token
+ * name = name of attribute to put scoped name in
+ * ref = whether to enable enclosing of the name in <ref> in
+ * outputwidl
+ *
+ * Return: node struct for new attribute
+ * tok updated
+ */
+static struct node *
+parsescopedname(struct tok *tok, const char *name, int ref)
+{
+ const char *start = tok->start, *end;
+ struct node *node;
+ unsigned int len = 0;
+ char *s = memalloc(3);
+ if (tok->type != TOK_IDENTIFIER)
+ tokerrorexit(tok, "expected identifier");
+ s = memrealloc(s, len + tok->len + 1);
+ memcpy(s + len, tok->start, tok->len);
+ len += tok->len;
+ end = tok->start + tok->len;
+ lexnocomment();
+ s[len] = 0;
+ node = newattr(name, s);
+ if (ref) {
+ node->start = start;
+ node->end = end;
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parsescopednamelist : parse [51] ScopedNameList
+ *
+ * Enter: tok = next token
+ * name = name of element for scoped name list
+ * name2 = name of element for entry in list
+ * comment = whether to attach documentation to each name
+ *
+ * Return: node for list of scoped names
+ * tok updated
+ */
+static struct node *
+parsescopednamelist(struct tok *tok, const char *name, const char *name2,
+ int comment)
+{
+ struct node *node = newelement(name);
+ for (;;) {
+ struct node *attr = parsescopedname(tok, "name", 1);
+ struct node *n = newelement(name2);
+ if (comment)
+ setcommentnode(n);
+ addnode(n, attr);
+ addnode(node, n);
+ if (tok->type != ',')
+ break;
+ lexnocomment();
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parsereturntype : parse [50] ReturnType
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for type
+ * tok updated
+ */
+static struct node *
+parsereturntype(struct tok *tok)
+{
+ if (tok->type == TOK_void) {
+ struct node *node = newelement("Type");
+ addnode(node, newattr("type", "void"));
+ lexnocomment();
+ return node;
+ }
+ return parsetype(tok);
+}
+
+/***********************************************************************
+ * parseunsignedintegertype : parse [46] UnsignedIntegerType
+ *
+ * Enter: tok = next token (one of "unsigned", "short" or "long")
+ *
+ * Return: 0-terminated canonical string for the type
+ * tok updated to just past UnsignedIntegerType
+ */
+static const char *
+parseunsignedintegertype(struct tok *tok)
+{
+ static const char *names[] = {
+ "short", "long", "long long", 0,
+ "unsigned short", "unsigned long", "unsigned long long" };
+ enum { TYPE_SHORT, TYPE_LONG, TYPE_LONGLONG,
+ TYPE_UNSIGNED = 4 };
+ int type = 0;
+ if (tok->type == TOK_unsigned) {
+ type = TYPE_UNSIGNED;
+ lexnocomment();
+ }
+ if (tok->type == TOK_short) {
+ type |= TYPE_SHORT;
+ lexnocomment();
+ } else if (tok->type != TOK_long)
+ tokerrorexit(tok, "expected 'short' or 'long' after 'unsigned'");
+ else {
+ type |= TYPE_LONG;
+ lexnocomment();
+ if (tok->type == TOK_long) {
+ type += TYPE_LONGLONG - TYPE_LONG;
+ lexnocomment();
+ }
+ }
+ return names[type];
+}
+/***********************************************************************
+ * parsetypesuffix : parse [44] TypeSuffix
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for type
+ * tok updated
+ */
+static struct node *
+parsetypesuffix(struct tok *tok, struct node *node)
+{
+ if (tok->type == TOK_DOUBLEBRACKET) {
+ struct node *typenode = node;
+ node = newelement("Type");
+ addnode(node, newattr("type", "array"));
+ addnode(node, typenode);
+ lexnocomment();
+ node = parsetypesuffix(tok, node);
+ } else if (tok->type == '?') {
+ addnode(node, newattr("nullable", "nullable"));
+ lexnocomment();
+ node = parsetypesuffixstartingwitharray(tok, node);
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parsetypesuffixstartingwitharray : parse [44] TypeSuffixStartingWithArray
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for type
+ * tok updated
+ */
+static struct node *
+parsetypesuffixstartingwitharray(struct tok *tok, struct node *node)
+{
+ if (tok->type == TOK_DOUBLEBRACKET) {
+ struct node *typenode = node;
+ node = newelement("Type");
+ addnode(node, newattr("type", "array"));
+ addnode(node, typenode);
+ lexnocomment();
+ node = parsetypesuffix(tok, node);
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parseprimitiveorstringtype : parse [45] PrimitiveOrString
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for type
+ * tok updated
+ */
+static struct node *
+parseprimitiveorstringtype(struct tok *tok)
+{
+ struct node *node;
+ switch (tok->type) {
+ case TOK_unsigned:
+ case TOK_short:
+ case TOK_long:
+ node = newelement("Type");
+ addnode(node, newattr("type", parseunsignedintegertype(tok)));
+ break;
+ default:
+ node = newelement("Type");
+ switch (tok->type) {
+ default:
+ tokerrorexit(tok, "expected type");
+ break;
+ case TOK_unrestricted:
+ lexnocomment();
+ if (tok->type == TOK_float) {
+ addnode(node, newattr("type", "unrestricted float"));
+ } else if (tok->type == TOK_double) {
+ addnode(node, newattr("type", "unrestricted double"));
+ } else {
+ tokerrorexit(tok, "expected float or double after unrestricted");
+ }
+ break;
+ case TOK_boolean:
+ addnode(node, newattr("type", "boolean"));
+ break;
+ case TOK_byte:
+ addnode(node, newattr("type", "byte"));
+ break;
+ case TOK_octet:
+ addnode(node, newattr("type", "octet"));
+ break;
+ case TOK_float:
+ addnode(node, newattr("type", "float"));
+ break;
+ case TOK_double:
+ addnode(node, newattr("type", "double"));
+ break;
+ case TOK_DOMString:
+ addnode(node, newattr("type", "DOMString"));
+ break;
+ case TOK_ByteString:
+ addnode(node, newattr("type", "ByteString"));
+ break;
+ case TOK_Date:
+ addnode(node, newattr("type", "Date"));
+ break;
+ case TOK_RegExp:
+ addnode(node, newattr("type", "RegExp"));
+ break;
+
+ }
+ lexnocomment();
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parsenonanytype : parse NonAnyType
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for type
+ * tok updated
+ */
+static struct node *
+parsenonanytype(struct tok *tok)
+{
+ struct node *node;
+ switch (tok->type) {
+ case TOK_IDENTIFIER:
+ node = newelement("Type");
+ addnode(node, parsescopedname(tok, "name", 1));
+ node = parsetypesuffix(tok, node);
+ break;
+ case TOK_sequence:
+ node = newelement("Type");
+ addnode(node, newattr("type", "sequence"));
+ lexnocomment();
+ eat(tok, '<');
+ addnode(node, parsetype(tok));
+ eat(tok, '>');
+ if (tok->type == '?') {
+ addnode(node, newattr("nullable", "nullable"));
+ lexnocomment();
+ }
+ break;
+ case TOK_object:
+ node = newelement("Type");
+ addnode(node, newattr("type", "object"));
+ lexnocomment();
+ node = parsetypesuffix(tok, node);
+ break;
+ default:
+ node = parseprimitiveorstringtype(tok);
+ node = parsetypesuffix(tok, node);
+ break;
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parseunionmembertype: parse UnionMemberType
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for type
+ * tok updated
+ */
+static struct node *
+parseunionmembertype(struct tok *tok)
+{
+ struct node *node;
+ if (tok->type == TOK_any) {
+ struct node *typenode = newelement("Type");
+ addnode(typenode, newattr("type", "any"));
+ lexnocomment();
+ eat(tok, TOK_DOUBLEBRACKET);
+ node = newelement("Type");
+ addnode(node, newattr("type", "array"));
+ addnode(node, typenode);
+ lexnocomment();
+ node = parsetypesuffix(tok, node);
+ } else if (tok->type == '(') {
+ node = parseuniontype(tok);
+ } else {
+ node = parsenonanytype(tok);
+ }
+ return node;
+}
+
+
+/***********************************************************************
+ * parseuniontype : parse UnionType
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for type
+ * tok updated
+ */
+static struct node *
+parseuniontype(struct tok *tok)
+{
+ struct node *node;
+ eat(tok, '(');
+ node = newelement("Type");
+ addnode(node, newattr("type", "union"));
+ if (tok->type != ')') {
+ for (;;) {
+ addnode(node, parseunionmembertype(tok));
+ if (tok->type != TOK_or)
+ break;
+ lexnocomment();
+ }
+ }
+ eat(tok, ')');
+ node = parsetypesuffix(tok, node);
+ return node;
+}
+
+/***********************************************************************
+ * parsetype : parse [44] Type
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for type
+ * tok updated
+ */
+static struct node *
+parsetype(struct tok *tok)
+{
+ struct node *node;
+ if (tok->type == '(') {
+ node = parseuniontype(tok);
+ } else if (tok->type == TOK_any) {
+ node = newelement("Type");
+ addnode(node, newattr("type", "any"));
+ lexnocomment();
+ node = parsetypesuffixstartingwitharray(tok, node);
+ } else {
+ node = parsenonanytype(tok);
+ }
+ return node;
+}
+
+
+/***********************************************************************
+ * parseextendedattribute : parse [39] ExtendedAttribute
+ *
+ * Enter: tok = next token
+ *
+ * Return: node for extended attribute
+ *
+ * This parses the various forms of extended attribute, as in
+ * rules [57] [58] [59] [60] [61].
+ *
+ * This does not spot the error that you cannot have a ScopedName
+ * and an ArgumentList.
+ */
+static struct node *
+parseextendedattribute(struct tok *tok)
+{
+ const char *start ;
+ struct node *node = newelement("ExtendedAttribute");
+ char *attrname = setidentifier(tok);
+ addnode(node, newattr("name", attrname));
+ start = tok->prestart;
+ node->wsstart = start;
+ node->end = tok->start + tok->len;
+ if(!strcmp(attrname, "Constructor") || !strcmp(attrname, "NamedConstructor")) {
+ setcommentnode(node);
+ }
+ lexnocomment();
+ if (tok->type == '=') {
+ lexnocomment();
+ addnode(node, parsescopedname(tok, "value", 0));
+ }
+ if (tok->type == '(') {
+ lexnocomment();
+ addnode(node, parseargumentlist(tok));
+ node->end = tok->start + tok->len;
+ eat(tok, ')');
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parseextendedattributelist : parse [37] ExtendedAttributeList
+ *
+ * Enter: tok = next token
+ *
+ * Return: 0 else node for extended attribute list
+ * tok updated if anything parsed
+ */
+static struct node *
+parseextendedattributelist(struct tok *tok)
+{
+ struct node *node;
+ if (tok->type != '[')
+ return 0;
+ node = newelement("ExtendedAttributeList");
+ for (;;) {
+ lexnocomment();
+ addnode(node, parseextendedattribute(tok));
+ if (tok->type != ',')
+ break;
+ }
+ if (tok->type != ']')
+ tokerrorexit(tok, "expected ',' or ']'");
+ lexnocomment();
+ return node;
+}
+
+/***********************************************************************
+ * parseexceptionfield : parse [36] ExceptionField
+ *
+ * Enter: tok = next token
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the exceptionfield
+ * tok updated
+ */
+static struct node *
+parseexceptionfield(struct tok *tok, struct node *eal)
+{
+ struct node *node = newelement("ExceptionField");
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ addnode(node, parsetype(tok));
+ addnode(node, newattr("name", setidentifier(tok)));
+ tok = lexnocomment();
+ return node;
+}
+
+/***********************************************************************
+ * parseargument : parse [31] Argument
+ *
+ * Enter: tok = next token
+ *
+ * Return: new node
+ *
+ * tok updated on return
+ */
+static struct node *
+parseargument(struct tok *tok)
+{
+ struct node *node = newelement("Argument");
+ struct node *eal = parseextendedattributelist(tok);
+ setcommentnode(node);
+ if (eal) addnode(node, eal);
+ if (tok->type == TOK_optional) {
+ addnode(node, newattr("optional", "optional"));
+ lexnocomment();
+ }
+ addnode(node, parsetype(tok));
+ if (tok->type == TOK_ELLIPSIS) {
+ addnode(node, newattr("ellipsis", "ellipsis"));
+ lexnocomment();
+ }
+ addnode(node, newattr("name", setargumentname(tok)));
+ lexnocomment();
+ // Optional default value
+ if (tok->type == '=') {
+ tok = lexnocomment();
+ node = parsedefaultvalue(tok, node);
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parseargumentlist : parse [29] ArgumentList
+ *
+ * Enter: tok = next token
+ *
+ * Return: new node for the arglist
+ * tok updated
+ */
+static struct node *
+parseargumentlist(struct tok *tok)
+{
+ struct node *node = newelement("ArgumentList");
+ /* We rely on the fact that ArgumentList is always followed by ')'. */
+ if (tok->type != ')') {
+ for (;;) {
+ addnode(node, parseargument(tok));
+ if (tok->type != ',')
+ break;
+ lexnocomment();
+ }
+ }
+ return node;
+}
+
+
+/***********************************************************************
+ * parseoperationrest : parse [25] OperationRest
+ *
+ * Enter: tok = next token
+ * node
+ *
+ * Return: node
+ * tok on terminating ';'
+ */
+static struct node *
+parseoperationrest(struct tok *tok, struct node *node)
+{
+ if (tok->type == TOK_IDENTIFIER) {
+ addnode(node, newattr("name", setidentifier(tok)));
+ lexnocomment();
+ }
+ eat(tok, '(');
+ addnode(node, parseargumentlist(tok));
+ eat(tok, ')');
+ return node;
+}
+
+/***********************************************************************
+ * parsereturntypeandoperationrest: parse ReturnType OperationRest
+ * Enter: tok = next token
+ * eal
+ * attrs list of attributes
+ * Return: node
+ * tok on terminating ';'
+ */
+static struct node *
+parsereturntypeandoperationrest(struct tok *tok, struct node *eal, struct node *attrs)
+{
+ struct node *node = newelement("Operation");
+ struct node *nodeType = parsereturntype(tok);
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ addnode(node, attrs);
+ addnode(node, nodeType);
+ return parseoperationrest(tok, node);
+}
+
+/***********************************************************************
+ * parseiteratorrest : parse OptionalIteratorInterface
+ *
+ * Enter: tok = next token
+ * node
+ *
+ * Return: node
+ * tok on terminating ';'
+ */
+static struct node *
+parseoptionaliteratorinterface(struct tok *tok, struct node *node)
+{
+ if (tok->type == '=') {
+ lexnocomment();
+ addnode(node, newattr("interface", setidentifier(tok)));
+ lexnocomment();
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parseoperationoriteratorrest : parse [25] OperationOrIteratorRest
+ *
+ * Enter: tok = next token
+ * eal = 0 else extended attribute list node
+ * attrs = list-of-attrs node containing attrs to add to new node
+ *
+ * Return: new node
+ * tok on terminating ';'
+ */
+static struct node *
+parseoperationoriteratorrest(struct tok *tok, struct node *eal, struct node *attrs)
+{
+ struct node *node;
+ struct node *nodeType = parsereturntype(tok);
+ unsigned int isIterator = 0;
+ if (tok->type == TOK_iterator) {
+ lexnocomment();
+ if (tok->type == TOK_object) {
+ lexnocomment();
+ node = newelement("IteratorObject");
+ addnode(node, nodeType);
+ return node;
+ } else {
+ node = newelement("Iterator");
+ isIterator = 1;
+ }
+ } else {
+ node = newelement("Operation");
+ }
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ addnode(node, attrs);
+ addnode(node, nodeType);
+ if (isIterator)
+ return parseoptionaliteratorinterface(tok, node);
+ else
+ return parseoperationrest(tok, node);
+}
+
+
+/***********************************************************************
+ * parseattribute : parse [17] Attribute
+ *
+ * Enter: tok = next token ("readonly" or "attribute")
+ * eal = 0 else extended attribute list node
+ * attrs = list-of-attrs node containing attrs to add to new node
+ *
+ * Return: node
+ * tok on terminating ';'
+ */
+static struct node *
+parseattribute(struct tok *tok, struct node *eal, struct node *attrs)
+{
+ struct node *node = newelement("Attribute");
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ addnode(node, attrs);
+ if (tok->type == TOK_inherit) {
+ lexnocomment();
+ addnode(node, newattr("inherit", "inherit"));
+ }
+ if (tok->type == TOK_readonly) {
+ lexnocomment();
+ addnode(node, newattr("readonly", "readonly"));
+ }
+ eat(tok, TOK_attribute);
+ addnode(node, parsetype(tok));
+ addnode(node, newattr("name", setidentifier(tok)));
+ lexnocomment();
+ return node;
+}
+
+/***********************************************************************
+ * parseserializer : parse Serializer
+ *
+ * Enter: tok = next token
+ * eal
+ *
+ * Return: node updated with value
+ * tok updated
+ */
+static struct node *
+parseserializer (struct tok *tok, struct node *eal) {
+ struct node *nodeAttribute;
+ struct node *node = newelement("Serializer");
+ if (tok->type == '=') {
+ if (eal) addnode(node, eal);
+ lexnocomment();
+ if (tok->type == TOK_IDENTIFIER) {
+ addnode(node, newattr("attribute", setidentifier(tok)));
+ lexnocomment();
+ } else if (tok->type == '{') {
+ unsigned int done = 0;
+ struct node *nodeMap = newelement("Map");
+ lexnocomment();
+ if (tok->type == TOK_getter) {
+ addnode(nodeMap, newattr("pattern", "getter"));
+ done = 1;
+ } else if (tok->type == TOK_attribute) {
+ addnode(nodeMap, newattr("pattern", "all"));
+ done = 1;
+ } else if (tok->type == TOK_inherit) {
+ addnode(nodeMap, newattr("inherit", "inherit"));
+ lexnocomment();
+ eat(tok, ',');
+ if (tok->type == TOK_attribute) {
+ addnode(nodeMap, newattr("pattern", "all"));
+ done = 1;
+ }
+ } else if (tok->type != TOK_IDENTIFIER) {
+ tokerrorexit(tok, "expected 'attribute', 'getter', 'inherit' or attribute identifiers in serializer map");
+ }
+ if (done) {
+ lexnocomment();
+ eat(tok, '}');
+ } else {
+ addnode(nodeMap, newattr("pattern", "selection"));
+ do {
+ if (tok->type != TOK_IDENTIFIER)
+ tokerrorexit(tok, "expected attribute identifiers in serializer map %s", tok->prestart);
+ nodeAttribute = newelement("PatternAttribute");
+ addnode(nodeAttribute, newattr("name", setidentifier(tok)));
+ addnode(nodeMap, nodeAttribute);
+ lexnocomment();
+ if (tok->type == ',')
+ lexnocomment();
+ } while (tok->type != '}');
+ eat(tok, '}');
+ }
+ addnode(node, nodeMap);
+ } else if (tok->type == '[') {
+ struct node *nodeList = newelement("List");
+ lexnocomment();
+ if (tok->type == TOK_getter) {
+ addnode(nodeList, newattr("pattern", "getter"));
+ lexnocomment();
+ eat(tok, ']');
+ } else {
+ addnode(nodeList, newattr("pattern", "selection"));
+ do {
+ if (tok->type != TOK_IDENTIFIER)
+ tokerrorexit(tok, "expected attribute identifiers in serializer list");
+ nodeAttribute = newelement("PatternAttribute");
+ addnode(nodeAttribute, newattr("name", setidentifier(tok)));
+ addnode(nodeList, nodeAttribute);
+ lexnocomment();
+ if (tok->type == ',')
+ lexnocomment();
+ } while (tok->type != ']');
+ eat(tok, ']');
+ }
+ addnode(node, nodeList);
+ } else {
+ tokerrorexit(tok, "Expected '{', '[' or an attribute identifier in the serializer declaration");
+ }
+ return node;
+ } else {
+ if (eal) addnode(node, eal);
+ return node;
+ }
+}
+
+/***********************************************************************
+ * parseattributeoroperationoriterator : parse [15] AttributeOrOperationOrIterator
+ *
+ * Enter: tok = next token
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node
+ * tok on terminating ';'
+ */
+static struct node *
+parseattributeoroperationoriterator(struct tok *tok, struct node *eal)
+{
+ int alreadyseen ;
+ struct node *attrs = newattrlist();
+ if (tok->type == TOK_serializer) {
+ lexnocomment();
+ if (tok->type == '=' || tok->type ==';') {
+ return parseserializer(tok, eal);
+ } else {
+ addnode(attrs, newattr("serializer", "serializer"));
+ return parsereturntypeandoperationrest(tok, eal, attrs);
+ }
+ }
+ if (tok->type == TOK_stringifier) {
+ addnode(attrs, newattr("stringifier", "stringifier"));
+ lexnocomment();
+ if (tok->type == ';') {
+ struct node *node = newelement("Stringifier");
+ if (eal) addnode(node, eal);
+ return node;
+ }
+ }
+ if (tok->type == TOK_static) {
+ lexnocomment();
+ addnode(attrs, newattr("static", "static"));
+ }
+ if (tok->type == TOK_inherit || tok->type == TOK_readonly || tok->type == TOK_attribute)
+ return parseattribute(tok, eal, attrs);
+ if (!nodeisempty(attrs))
+ return parsereturntypeandoperationrest(tok, eal, attrs);
+ alreadyseen = 0;
+ for (;;) {
+ static const int t[] = { TOK_getter,
+ TOK_setter, TOK_creator, TOK_deleter, TOK_legacycaller,
+ 0 };
+ const int *tt = t;
+ char *s;
+ while (*tt && *tt != tok->type)
+ tt++;
+ if (!*tt)
+ break;
+ s = memprintf("%.*s", tok->len, tok->start);
+ if (alreadyseen & (1 << (tt - t)))
+ tokerrorexit(tok, "'%s' qualifier cannot be repeated", s);
+ alreadyseen |= 1 << (tt - t);
+ addnode(attrs, newattr(s, s));
+ lexnocomment();
+ }
+ if (!nodeisempty(attrs))
+ return parsereturntypeandoperationrest(tok, eal, attrs);
+ else
+ return parseoperationoriteratorrest(tok, eal, attrs);
+}
+
+
+/***********************************************************************
+ * parseconstexpr : parse ConstValue
+ *
+ * Enter: tok = next token
+ * node
+ *
+ * Return: node updated with value
+ * tok updated
+ */
+static struct node *
+parseconstexpr (struct tok *tok, struct node *node) {
+ char *s;
+ switch(tok->type) {
+ case TOK_true:
+ case TOK_false:
+ case TOK_minusinfinity:
+ case TOK_INTEGER:
+ case TOK_FLOAT:
+ case TOK_null:
+ case TOK_infinity:
+ case TOK_NaN:
+ break;
+ default:
+ tokerrorexit(tok, "expected constant value");
+ break;
+ }
+ s = memalloc(tok->len + 1);
+ memcpy(s, tok->start, tok->len);
+ s[tok->len] = 0;
+ if (tok->type != TOK_STRING) {
+ addnode(node, newattr("value", s));
+ } else {
+ addnode(node, newattr("stringvalue", s));
+ }
+ lexnocomment();
+ return node;
+}
+
+/***********************************************************************
+ * parsedefaultvalue : parse DefaultValue
+ *
+ * Enter: tok = next token
+ * node
+ *
+ * Return: node updated with value
+ * tok updated
+ */
+static struct node *
+parsedefaultvalue (struct tok *tok, struct node *node) {
+ char *s;
+ if (tok->type == TOK_STRING) {
+ s = memalloc(tok->len + 1);
+ memcpy(s, tok->start, tok->len);
+ s[tok->len] = 0;
+ addnode(node, newattr("stringvalue", s));
+ lexnocomment();
+ return node;
+ } else {
+ return parseconstexpr(tok, node);
+ }
+}
+
+
+
+/***********************************************************************
+ * parsedictionarymember : parse DictionaryMember
+ *
+ * Enter: tok = next token
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node
+ * tok on terminating ';'
+ */
+static struct node *
+parsedictionarymember(struct tok *tok, struct node *eal)
+{
+ struct node *node = newelement("DictionaryMember");
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ addnode(node, parsetype(tok));
+ addnode(node, newattr("name", setidentifier(tok)));
+ tok = lexnocomment();
+ // Optional value
+ if (tok->type == '=') {
+ tok = lexnocomment();
+ node = parsedefaultvalue(tok, node);
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parseconst : parse [12] Const
+ *
+ * Enter: tok = next token, known to be TOK_const
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the const
+ * tok on terminating ';'
+ */
+static struct node *
+parseconst(struct tok *tok, struct node *eal)
+{
+ struct node *node = newelement("Const");
+ setcommentnode(node);
+ if (eal) addnode(node, eal);
+ tok = lexnocomment();
+ switch(tok->type) {
+ case TOK_boolean:
+ case TOK_byte:
+ case TOK_octet:
+ case TOK_float:
+ case TOK_double:
+ case TOK_unsigned:
+ case TOK_unrestricted:
+ case TOK_short:
+ case TOK_long:
+ addnode(node, parsetype(tok));
+ break;
+ default:
+ tokerrorexit(tok, "expected acceptable constant type");
+ break;
+ }
+ addnode(node, newattr("name", setidentifier(tok)));
+ tok = lexnocomment();
+ eat(tok, '=');
+ node = parseconstexpr(tok, node);
+ return node;
+}
+
+/***********************************************************************
+ * parseimplementsstatement : parse [11] ImplementsStatement
+ *
+ * Enter: tok = next token, known to be :: or TOK_IDENTIFIER
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the typedef
+ * tok updated to the terminating ';'
+ */
+static struct node *
+parseimplementsstatement(struct tok *tok, struct node *eal)
+{
+ struct node *node = newelement("Implements");
+ setcommentnode(node);
+ if (eal) addnode(node, eal);
+ addnode(node, parsescopedname(tok, "name1", 1));
+ eat(tok, TOK_implements);
+ addnode(node, parsescopedname(tok, "name2", 1));
+ return node;
+}
+
+/***********************************************************************
+ * parsetypedef : parse [10] Typedef
+ *
+ * Enter: tok = next token, known to be TOK_typedef
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the typedef
+ * tok updated to the terminating ';'
+ */
+static struct node *
+parsetypedef(struct tok *tok, struct node *eal)
+{
+struct node *ealtype;
+struct node *typenode;
+ struct node *node = newelement("Typedef");
+ setcommentnode(node);
+ if (eal) addnode(node, eal);
+ tok = lexnocomment();
+ ealtype = parseextendedattributelist(tok);
+ typenode = parsetype(tok);
+ if (ealtype) addnode(typenode, ealtype);
+ addnode(node, typenode);
+ addnode(node, newattr("name", setidentifier(tok)));
+ tok = lexnocomment();
+ return node;
+}
+
+/***********************************************************************
+ * parseexception : parse [8] Exception
+ *
+ * Enter: tok = next token, known to be TOK_exception
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the exception
+ * tok updated to the terminating ';'
+ */
+static struct node *
+parseexception(struct tok *tok, struct node *eal)
+{
+ struct node *node = newelement("Exception");
+ setcommentnode(node);
+ if (eal) addnode(node, eal);
+ tok = lexnocomment();
+ addnode(node, newattr("name", setidentifier(tok)));
+ lexnocomment();
+ if (tok->type == ':') {
+ lexnocomment();
+ addnode(node, parsescopednamelist(tok, "ExceptionInheritance", "Name", 1));
+ }
+ eat(tok, '{');
+ while (tok->type != '}') {
+ const char *start = tok->prestart;
+ struct node *node2;
+ struct node *eal = parseextendedattributelist(tok);
+ if (tok->type == TOK_const)
+ node2 = parseconst(tok, eal);
+ else
+ node2 = parseexceptionfield(tok, eal);
+ addnode(node, node2);
+ node2->wsstart = start;
+ node2->end = tok->start + tok->len;
+ setid(node2);
+ eat(tok, ';');
+ }
+ lexnocomment();
+ return node;
+}
+
+/***********************************************************************
+ * parseinterface : parse [4] Interface
+ *
+ * Enter: tok = next token, known to be TOK_interface
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the interface
+ * tok updated to the terminating ';'
+ */
+static struct node *
+parseinterface(struct tok *tok, struct node *eal)
+{
+ struct node *node = newelement("Interface");
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ tok = lexnocomment();
+ addnode(node, newattr("name", setidentifier(tok)));
+ tok = lexnocomment();
+ if (tok->type == ':') {
+ lexnocomment();
+ addnode(node, parsescopednamelist(tok, "InterfaceInheritance", "Name", 1));
+ }
+ eat(tok, '{');
+ while (tok->type != '}') {
+ const char *start = tok->prestart;
+ struct node *eal = parseextendedattributelist(tok);
+ struct node *node2;
+ if (tok->type == TOK_const)
+ addnode(node, node2 = parseconst(tok, eal));
+ else
+ addnode(node, node2 = parseattributeoroperationoriterator(tok, eal));
+ node2->wsstart = start;
+ node2->end = tok->start + tok->len;
+ setid(node2);
+ eat(tok, ';');
+ }
+ lexnocomment();
+ return node;
+}
+
+/***********************************************************************
+ * parsecallback : parse Callback
+ *
+ * Enter: tok = next token, known to be TOK_dictionary
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the enum
+ * tok updated to the terminating ';'
+ */
+static struct node *
+parsecallback(struct tok *tok, struct node *eal)
+{
+ struct node *node;
+ if (tok->type == TOK_interface) {
+ node = parseinterface(tok, eal);
+ addnode(node, newattr("callback", "callback"));
+ } else {
+ node = newelement("Callback");
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ addnode(node, newattr("name", setidentifier(tok)));
+ tok = lexnocomment();
+ eat(tok, '=');
+ addnode(node, parsereturntype(tok));
+ eat(tok, '(');
+ addnode(node, parseargumentlist(tok));
+ eat(tok, ')');
+ }
+ return node;
+}
+
+/***********************************************************************
+ * parsedictionary : parse Dictionary
+ *
+ * Enter: tok = next token, known to be TOK_dictionary
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the dictionary
+ * tok updated to the terminating ';'
+ */
+static struct node *
+parsedictionary(struct tok *tok, struct node *eal)
+{
+ struct node *node = newelement("Dictionary");
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ tok = lexnocomment();
+ addnode(node, newattr("name", setidentifier(tok)));
+ tok = lexnocomment();
+ if (tok->type == ':') {
+ lexnocomment();
+ addnode(node, parsescopednamelist(tok, "DictionaryInheritance", "Name", 1));
+ }
+ eat(tok, '{');
+ while (tok->type != '}') {
+ const char *start = tok->prestart;
+ struct node *eal = parseextendedattributelist(tok);
+ struct node *node2;
+ if (tok->type == TOK_const)
+ addnode(node, node2 = parseconst(tok, eal));
+ else
+ addnode(node, node2 = parsedictionarymember(tok, eal));
+ node2->wsstart = start;
+ node2->end = tok->start + tok->len;
+ setid(node2);
+ eat(tok, ';');
+ }
+ lexnocomment();
+ return node;
+}
+
+/***********************************************************************
+ * parseenum : parse Enum
+ *
+ * Enter: tok = next token, known to be TOK_dictionary
+ * eal = 0 else extended attribute list node
+ *
+ * Return: new node for the enum
+ * tok updated to the terminating ';'
+ */
+static struct node *
+parseenum(struct tok *tok, struct node *eal)
+{
+ char *s;
+ struct node *node = newelement("Enum");
+ if (eal) addnode(node, eal);
+ setcommentnode(node);
+ tok = lexnocomment();
+ addnode(node, newattr("name", setidentifier(tok)));
+ tok = lexnocomment();
+ eat(tok, '{');
+ while (tok->type != '}') {
+ if (tok->type == TOK_STRING) {
+ const char *start = tok->prestart;
+ struct node *node2 = newelement("EnumValue");
+ setcommentnode(node2);
+
+ s = memalloc(tok->len + 1);
+ memcpy(s, tok->start, tok->len);
+ s[tok->len] = 0;
+ addnode(node2, newattr("stringvalue", s));
+ node2->wsstart = start;
+ node2->end = tok->start + tok->len;
+ setid(node2);
+ addnode(node, node2);
+ } else {
+ tokerrorexit(tok, "expected string in enum");
+ }
+ lexnocomment();
+ if (tok->type == ',') {
+ lexnocomment();
+ }
+ }
+ eat(tok, '}');
+ return node;
+}
+
+/***********************************************************************
+ * parsedefinitions : parse [1] Definitions
+ *
+ * Enter: tok = next token
+ * parent = parent node to add definitions to
+ *
+ * On return, tok has been updated.
+ */
+static void
+parsedefinitions(struct tok *tok, struct node *parent)
+{
+ parent->wsstart = tok->prestart;
+ for (;;) {
+ const char *wsstart = tok->prestart;
+ struct node *eal = parseextendedattributelist(tok);
+ struct node *node;
+ switch (tok->type) {
+ case TOK_partial:
+ eat(tok, TOK_partial);
+ if (tok->type == TOK_dictionary) {
+ node = parsedictionary(tok, eal);
+ } else {
+ node = parseinterface(tok, eal);
+ }
+ addnode(node, newattr("partial", "partial"));
+ break;
+ case TOK_interface:
+ node = parseinterface(tok, eal);
+ break;
+ case TOK_callback:
+ eat(tok, TOK_callback);
+ node = parsecallback(tok, eal);
+ break;
+ case TOK_dictionary:
+ node = parsedictionary(tok, eal);
+ break;
+ case TOK_enum:
+ node = parseenum(tok, eal);
+ break;
+ case TOK_exception:
+ node = parseexception(tok, eal);
+ break;
+ case TOK_typedef:
+ node = parsetypedef(tok, eal);
+ break;
+ case TOK_IDENTIFIER:
+ node = parseimplementsstatement(tok, eal);
+ break;
+ default:
+ if (eal)
+ tokerrorexit(tok, "expected definition after extended attribute list");
+ node = 0;
+ break;
+ }
+ if (!node)
+ break;
+ node->wsstart = wsstart;
+ node->end = tok->start + tok->len;
+ eat(tok, ';');
+ addnode(parent, node);
+ setid(node);
+ parent->end = node->end;
+ }
+}
+
+/***********************************************************************
+ * parse
+ *
+ * Return: root element containing (possibly empty) list of definitions
+ */
+struct node *
+parse(void)
+{
+ struct tok *tok;
+ struct node *root = newelement("Definitions");
+ setcommentnode(root);
+ tok = lexnocomment();
+ parsedefinitions(tok, root);
+ if (tok->type != TOK_EOF)
+ tokerrorexit(tok, "expected end of input");
+ reversechildren(root);
+ return root;
+}
+
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/parse.h b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/parse.h
new file mode 100644
index 000000000..ad9071b45
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/parse.h
@@ -0,0 +1,19 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#ifndef parse_h
+#define parse_h
+
+struct node *parse(void);
+
+#endif /* ndef parse_h */
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/process.c b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/process.c
new file mode 100644
index 000000000..d6a343b8a
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/process.c
@@ -0,0 +1,319 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "comment.h"
+#include "lex.h"
+#include "misc.h"
+#include "node.h"
+#include "os.h"
+#include "parse.h"
+#include "process.h"
+
+#if 0
+static const char ntnames[] = { NTNAMES };
+#endif /*0*/
+
+/***********************************************************************
+ * printtext : print text with xml entity escapes
+ *
+ * Enter: s = text
+ * len = number of bytes
+ * escamp = whether to escape &
+ *
+ * This also escapes double quote mark so it can be used for an
+ * attribute value. It also turns a tab into spaces.
+ */
+void
+printtext(const char *s, unsigned int len, int escamp)
+{
+ const char *p = s, *end = s + len;
+ unsigned int count = 0;
+ while (p != end) {
+ int ch = *p;
+ char buf[9];
+ const char *seq = 0;
+ count++;
+ switch (ch) {
+ case '<':
+ seq = "&lt;";
+ break;
+ case '&':
+ seq = escamp ? "&amp;" : "&";
+ break;
+ case '"':
+ seq = "&quot;";
+ break;
+ case '\n':
+ p++;
+ count = 0;
+ continue;
+ case '\t':
+ seq = " " + ((count - 1) & 7);
+ count = 0;
+ break;
+ default:
+ if ((unsigned char)ch >= 0x20) {
+ p++;
+ continue;
+ }
+ snprintf(buf, 9, "&#%i;", ch);
+ seq = buf;
+ break;
+ }
+ if (p - s != fwrite(s, 1, p - s, stdout))
+ errorexit("write error");
+ fputs(seq, stdout);
+ s = ++p;
+ }
+ if (p - s != fwrite(s, 1, p - s, stdout))
+ errorexit("write error");
+}
+
+#if 0
+/***********************************************************************
+ * outputnodeastext : output parse node and descendants as deparsed text
+ *
+ * Enter: node = parse node
+ * needspace = true if last output char was an identifier char
+ *
+ * Return: updated needspace value
+ */
+static int
+outputnodeastext(struct node *node, int needspace)
+{
+ if (node->type >= NT_START) {
+ struct node *child = node->children;
+ while (child) {
+ needspace = outputnodeastext(child, needspace);
+ child = child->next;
+ }
+ } else {
+ unsigned int len = strlen(node->name);
+ if (len) {
+ int ch = node->name[0];
+ if (ch == '_' || ((unsigned)(ch - '0') < 10
+ || (unsigned)((ch & ~0x20) - 'A') < 26))
+ {
+ if (needspace) putchar(' ');
+ }
+ ch = node->name[len - 1];
+ if (ch == '_' || ((unsigned)(ch - '0') < 10
+ || (unsigned)((ch & ~0x20) - 'A') < 26))
+ {
+ needspace = 1;
+ }
+ printtext(node->name, len, 1);
+ }
+ }
+ return needspace;
+}
+
+/***********************************************************************
+ * printfqid : print fully-qualified id
+ *
+ * Enter: node struct
+ *
+ * Return: whether anything printed
+ */
+static int
+printfqid(struct node *node)
+{
+ int any = 0;
+ struct node *identifier;
+ if (node->parent) {
+ any = printfqid(node->parent);
+ }
+ switch (node->type) {
+ case NT_Module:
+ case NT_Interface:
+ case NT_Typedef:
+ case NT_Operation:
+ case NT_Attribute:
+ case NT_Const:
+ if (any)
+ printf(":");
+ /* Find identifier child if any. */
+ identifier = node->children;
+ while (identifier) {
+ if (identifier->type == TOK_IDENTIFIER)
+ break;
+ if (identifier->type == NT_TypedefRest) {
+ identifier = identifier->children;
+ continue;
+ }
+ identifier = identifier->next;
+ }
+ if (identifier) {
+ printtext(identifier->name, strlen(identifier->name), 1);
+ any = 1;
+ }
+ break;
+ }
+ return any;
+}
+
+/***********************************************************************
+ * output : output subtree of parse tree
+ *
+ * Enter: node = root of subtree
+ * extendedattributelist = 0 else extended attribute list node
+ * applying to node
+ * indent = indent (nesting) level
+ */
+static void outputchildren(struct node *node, struct node *identifier, unsigned int indent);
+
+static void
+output(struct node *node, struct node *extendedattributelist,
+ unsigned int indent)
+{
+ if (extendedattributelist) {
+ node->wsstart = extendedattributelist->wsstart;
+ node->start = extendedattributelist->start;
+ }
+ if (node->type == NT_ExtendedAttribute) {
+ printf("%*s<ExtendedAttribute value=\"", indent, "");
+ outputnodeastext(node, 0);
+ printf("\"/>\n");
+ } else if (node->type == NT_BooleanLiteral) {
+ printf("%*s<BooleanLiteral value=\"%s\"/>", indent, "",
+ node->children->name);
+ } else if (node->type == NT_ReadOnly) {
+ printf("%*s<ReadOnly/>\n", indent, "");
+ } else if (node->type >= NT_START) {
+ const char *ntname;
+ /* Find identifier child if any. */
+ struct node *identifier = node->children;
+ while (identifier) {
+ if (identifier->type == TOK_IDENTIFIER)
+ break;
+ identifier = identifier->next;
+ }
+ /* Find nonterminal name. */
+ ntname = ntnames + 2;
+ while (node->type - NT_START != ((unsigned char)ntname[-2] | (unsigned char)ntname[-1] << 8))
+ ntname += strlen(ntname) + 3;
+ /* Output start of element. */
+ printf("%*s<%s", indent, "", ntname);
+ /* Output identifier if any as attribute. */
+ if (identifier) {
+ printf(" identifier=\"");
+ printtext(identifier->name, strlen(identifier->name), 1);
+ printf("\"");
+ }
+ switch (node->type) {
+ case NT_Module:
+ case NT_Interface:
+ case NT_Typedef:
+ case NT_Const:
+ /* Output fully qualified id. */
+ printf(" fqid=\"");
+ printfqid(node);
+ printf("\"");
+ break;
+ }
+ if (!identifier && !extendedattributelist && !node->children && !node->comments)
+ printf("/>\n");
+ else {
+ printf(">\n");
+ /* Output descriptive elements (doxygen comments) for node. */
+ outputdescriptive(node, indent + 2);
+ /* Output descriptive elements (doxygen comments) for identifier. */
+ if (identifier)
+ outputdescriptive(identifier, indent + 2);
+ /* Output extended attribute list. */
+ if (extendedattributelist)
+ output(extendedattributelist, 0, indent + 2);
+ /* Output children (excluding identifier child). */
+ outputchildren(node, identifier, indent + 2);
+ printf("%*s</%s>\n", indent, "", ntname);
+ }
+ } else switch (node->type) {
+ case TOK_DOMString:
+ case TOK_any:
+ case TOK_boolean:
+ case TOK_octet:
+ case TOK_float:
+ case TOK_double:
+ case TOK_Object:
+ case TOK_unsigned:
+ case TOK_short:
+ case TOK_long:
+ case TOK_void:
+ printf("%*s<%s/>\n", indent, "", node->name);
+ break;
+ case TOK_INTEGER:
+ printf("%*s<integer value=\"", indent, "");
+ printtext(node->name, strlen(node->name), 1);
+ printf("\"/>\n");
+ break;
+ case TOK_FLOAT:
+ printf("%*s<Float value=\"", indent, "");
+ printtext(node->name, strlen(node->name), 1);
+ printf("\"/>\n");
+ break;
+ case TOK_STRING:
+ printf("%*s<string value=\"", indent, "");
+ printtext(node->name, strlen(node->name), 1);
+ printf("\"/>\n");
+ break;
+ }
+}
+
+/***********************************************************************
+ * outputchildren : call output for each child of node
+ *
+ * Enter: node
+ * identifier = child node to omit from output
+ * indent = indent (nesting) level
+ */
+static void
+outputchildren(struct node *node, struct node *identifier, unsigned int indent)
+{
+ struct node *extendedattributelist;
+ struct node *child;
+ child = node->children;
+ extendedattributelist = 0;
+ while (child) {
+ if (child->type == NT_ExtendedAttributeList && node->type != NT_Argument)
+ extendedattributelist = child;
+ else {
+ if (identifier != child)
+ output(child, extendedattributelist, indent);
+ extendedattributelist = 0;
+ }
+ child = child->next;
+ }
+}
+#endif /*0*/
+
+/***********************************************************************
+ * processfiles : process input files
+ *
+ * Enter: name = filename
+ */
+void
+processfiles(const char *const *names, int dtdref)
+{
+ struct node *root;
+ readinput(names);
+ root = parse();
+ processcomments(root);
+ printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ if(dtdref)
+ printf("<!DOCTYPE Definitions SYSTEM \"widlprocxml.dtd\">\n");
+ outputnode(root, 0);
+}
+
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/process.h b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/process.h
new file mode 100644
index 000000000..bb92b22ce
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/process.h
@@ -0,0 +1,27 @@
+/***********************************************************************
+ * $Id$
+ * Copyright 2009 Aplix Corporation. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+#ifndef process_h
+#define process_h
+
+#if 0
+#define NT_START 0x100
+#include "nonterminals.h"
+#endif/*0*/
+
+void printtext(const char *s, unsigned int len, int escamp);
+
+void processfiles(const char *const *names, int dtdref);
+
+#endif /* ndef process_h */
+
diff --git a/testing/web-platform/tests/resources/webidl2/test/widlproc/src/widlprocxmltohtml.xsl b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/widlprocxmltohtml.xsl
new file mode 100644
index 000000000..2b583371e
--- /dev/null
+++ b/testing/web-platform/tests/resources/webidl2/test/widlproc/src/widlprocxmltohtml.xsl
@@ -0,0 +1,828 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--====================================================================
+$Id: widlprocxmltohtml.xsl 407 2009-10-26 13:48:48Z tpr $
+Copyright 2009 Aplix Corporation. All rights reserved.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+XSLT stylesheet to convert widlprocxml into html documentation.
+=====================================================================-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="html" encoding="utf-8" indent="yes" doctype-public="html"/>
+
+<xsl:param name="date" select="'error: missing date'"/>
+
+<xsl:variable name="title" select="concat('The ',/Definitions/descriptive/name,' Module - Version ',/Definitions/descriptive/version)"/>
+
+<!--Root of document.-->
+<xsl:template match="/">
+ <html>
+ <head>
+ <link rel="stylesheet" type="text/css" href="widlhtml.css" media="screen"/>
+ <title>
+ <xsl:value-of select="$title"/>
+ </title>
+ </head>
+ <body>
+ <xsl:apply-templates/>
+ </body>
+ </html>
+</xsl:template>
+
+<!--Root of Definitions.-->
+<xsl:template match="Definitions">
+ <div class="api" id="{@id}">
+ <a href="http://bondi.omtp.org"><img src="http://www.omtp.org/images/BondiSmall.jpg" alt="Bondi logo"/></a>
+ <h1><xsl:value-of select="$title"/></h1>
+ <h3>12 May 2009</h3>
+
+ <h2>Authors</h2>
+ <ul class="authors">
+ <xsl:apply-templates select="descriptive/author"/>
+ </ul>
+
+ <p class="copyright"><small>© The authors, 2012. All rights reserved.</small></p>
+
+ <hr/>
+
+ <h2>Abstract</h2>
+
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="descriptive/description"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+
+ <h2>Table of Contents</h2>
+ <ul class="toc">
+ <li><a href="#intro">Introduction</a>
+ <ul>
+ <xsl:if test="descriptive/def-api-feature-set">
+ <li><a href="#def-api-feature-sets">Feature set</a></li>
+ </xsl:if>
+ <xsl:if test="descriptive/def-api-feature">
+ <li><a href="#def-api-features">Features</a></li>
+ </xsl:if>
+ <xsl:if test="descriptive/def-device-cap">
+ <li><a href="#def-device-caps">Device Capabilities</a></li>
+ </xsl:if>
+ </ul>
+ </li>
+ <xsl:if test="Typedef">
+ <li><a href="#typedefs">Type Definitions</a>
+ <ul class="toc">
+ <xsl:for-each select="Typedef[descriptive]">
+ <li><a href="#{@id}"><code><xsl:value-of select="@name"/></code></a></li>
+ </xsl:for-each>
+ </ul>
+ </li>
+ </xsl:if>
+ <xsl:if test="Interface">
+ <li><a href="#interfaces">Interfaces</a>
+ <ul class="toc">
+ <xsl:for-each select="Interface[descriptive]">
+ <li><a href="#{@id}"><code><xsl:value-of select="@name"/></code></a></li>
+ </xsl:for-each>
+ </ul>
+ </li>
+ </xsl:if>
+ <xsl:if test="Dictionary">
+ <li><a href="#dictionaries">Dictionary types</a>
+ <ul class="toc">
+ <xsl:for-each select="Dictionary[descriptive]">
+ <li><a href="#{@id}"><code><xsl:value-of select="@name"/></code></a></li>
+ </xsl:for-each>
+ </ul>
+ </li>
+ </xsl:if>
+ <xsl:if test="Callback">
+ <li><a href="#callbacks">Callbacks</a>
+ <ul class="toc">
+ <xsl:for-each select="Callback[descriptive]">
+ <li><a href="#{@id}"><code><xsl:value-of select="@name"/></code></a></li>
+ </xsl:for-each>
+ </ul>
+ </li>
+ </xsl:if>
+ <xsl:if test="Enum">
+ <li><a href="#enums">Enums</a>
+ <ul class="toc">
+ <xsl:for-each select="Enum[descriptive]">
+ <li><a href="#{@id}"><code><xsl:value-of select="@name"/></code></a></li>
+ </xsl:for-each>
+ </ul>
+ </li>
+ </xsl:if>
+ </ul>
+
+ <hr/>
+
+ <h2>Summary of Methods</h2>
+ <xsl:call-template name="summary"/>
+
+ <h2 id="intro">Introduction</h2>
+
+ <xsl:apply-templates select="descriptive/description"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+
+ <xsl:if test="descriptive/def-api-feature-set">
+ <div id="def-api-feature-sets" class="def-api-feature-sets">
+ <h3 id="features">Feature set</h3>
+ <p>This is the URI used to declare this API's feature set, for use in bondi.requestFeature. For the URL, the list of features included by the feature set is provided.</p>
+ <xsl:apply-templates select="descriptive/def-api-feature-set"/>
+ </div>
+ </xsl:if>
+ <xsl:if test="descriptive/def-api-feature">
+ <div id="def-api-features" class="def-api-features">
+ <h3 id="features">Features</h3>
+ <p>This is the list of URIs used to declare this API's features, for use in bondi.requestFeature. For each URL, the list of functions covered is provided.</p>
+ <xsl:apply-templates select="Interface/descriptive/def-instantiated"/>
+ <xsl:apply-templates select="descriptive/def-api-feature"/>
+ </div>
+ </xsl:if>
+ <xsl:if test="descriptive/def-device-cap">
+ <div class="def-device-caps" id="def-device-caps">
+ <h3>Device capabilities</h3>
+ <dl>
+ <xsl:apply-templates select="descriptive/def-device-cap"/>
+ </dl>
+ </div>
+ </xsl:if>
+ <xsl:if test="Typedef">
+ <div class="typedefs" id="typedefs">
+ <h2>Type Definitions</h2>
+ <xsl:apply-templates select="Typedef[descriptive]"/>
+ </div>
+ </xsl:if>
+ <xsl:if test="Interface">
+ <div class="interfaces" id="interfaces">
+ <h2>Interfaces</h2>
+ <xsl:apply-templates select="Interface"/>
+ </div>
+ </xsl:if>
+ <xsl:if test="Dictionary">
+ <div class="dictionaries" id="dictionaries">
+ <h2>Dictionary types</h2>
+ <xsl:apply-templates select="Dictionary"/>
+ </div>
+ </xsl:if>
+ <xsl:if test="Callback">
+ <div class="callbacks" id="callbacks">
+ <h2>Callbacks</h2>
+ <xsl:apply-templates select="Callback"/>
+ </div>
+ </xsl:if>
+ <xsl:if test="Enum">
+ <div class="enums" id="enums">
+ <h2>Enums</h2>
+ <xsl:apply-templates select="Enum"/>
+ </div>
+ </xsl:if>
+ </div>
+</xsl:template>
+
+<!--def-api-feature-set-->
+<xsl:template match="def-api-feature-set">
+ <dl class="def-api-feature-set">
+ <dt><xsl:value-of select="@identifier"/></dt>
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ <xsl:if test="descriptive/api-feature">
+ <div class="api-features">
+ <p>
+ Includes API features:
+ </p>
+ <ul>
+ <xsl:for-each select="descriptive/api-feature">
+ <li><code><xsl:value-of select="@identifier"/></code></li>
+ </xsl:for-each>
+ </ul>
+ </div>
+ </xsl:if>
+ </dd>
+ </dl>
+</xsl:template>
+
+<!--def-api-feature-->
+<xsl:template match="def-api-feature">
+ <dl class="def-api-feature">
+ <dt><xsl:value-of select="@identifier"/></dt>
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ <xsl:if test="descriptive/device-cap">
+ <div class="device-caps">
+ <p>
+ Device capabilities:
+ </p>
+ <ul>
+ <xsl:for-each select="descriptive/device-cap">
+ <li><code><xsl:value-of select="@identifier"/></code></li>
+ </xsl:for-each>
+ </ul>
+ </div>
+ </xsl:if>
+ </dd>
+ </dl>
+</xsl:template>
+
+<!--def-device-cap-->
+<xsl:template match="def-device-cap">
+ <dt class="def-device-cap"><code><xsl:value-of select="@identifier"/></code></dt>
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ <xsl:if test="descriptive/param">
+ <div class="device-caps">
+ <p>Security parameters:</p>
+ <ul>
+ <xsl:apply-templates select="descriptive/param"/>
+ </ul>
+ </div>
+ </xsl:if>
+ </dd>
+</xsl:template>
+
+<!--Exception: not implemented-->
+<!--Valuetype: not implemented-->
+<xsl:template match="Exception|Valuetype|Const">
+ <xsl:if test="descriptive">
+ <xsl:message terminate="yes">element <xsl:value-of select="name()"/> not supported</xsl:message>
+ </xsl:if>
+</xsl:template>
+
+<!--Typedef.-->
+<xsl:template match="Typedef[descriptive]">
+ <div class="typedef" id="{@id}">
+ <h3>2.<xsl:number value="position()"/>. <code><xsl:value-of select="@name"/></code></h3>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="webidl"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ </div>
+</xsl:template>
+
+<!--Interface.-->
+<xsl:template match="Interface[descriptive]">
+ <xsl:variable name="name" select="@name"/>
+ <div class="interface" id="{@id}">
+ <h3><code><xsl:value-of select="@name"/></code></h3>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="webidl"/>
+ <xsl:apply-templates select="../Implements[@name2=$name]/webidl"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ <xsl:apply-templates select="InterfaceInheritance"/>
+ <xsl:if test="Const/descriptive">
+ <div class="consts">
+ <h4>Constants</h4>
+ <dl>
+ <xsl:apply-templates select="Const"/>
+ </dl>
+ </div>
+ </xsl:if>
+ <xsl:if test="ExtendedAttributeList/ExtendedAttribute/descriptive">
+ <div class="constructors">
+ <h4>Constructors</h4>
+ <dl>
+ <xsl:apply-templates select="ExtendedAttributeList/ExtendedAttribute"/>
+ </dl>
+ </div>
+ </xsl:if>
+ <xsl:if test="Attribute/descriptive">
+ <div class="attributes">
+ <h4>Attributes</h4>
+ <dl>
+ <xsl:apply-templates select="Attribute"/>
+ </dl>
+ </div>
+ </xsl:if>
+ <xsl:if test="Operation/descriptive">
+ <div class="methods">
+ <h4>Methods</h4>
+ <dl>
+ <xsl:apply-templates select="Operation"/>
+ </dl>
+ </div>
+ </xsl:if>
+ </div>
+</xsl:template>
+<xsl:template match="Interface[not(descriptive)]">
+</xsl:template>
+
+<!--Dictionary.-->
+<xsl:template match="Dictionary[descriptive]">
+ <xsl:variable name="name" select="@name"/>
+ <div class="dictionary" id="{@id}">
+ <h3><code><xsl:value-of select="@name"/></code></h3>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="webidl"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ <xsl:apply-templates select="InterfaceInheritance"/>
+ <xsl:if test="Const/descriptive">
+ <div class="consts">
+ <h4>Constants</h4>
+ <dl>
+ <xsl:apply-templates select="Const"/>
+ </dl>
+ </div>
+ </xsl:if>
+ <xsl:if test="Attribute/descriptive">
+ <div class="attributes">
+ <h4>Attributes</h4>
+ <dl>
+ <xsl:apply-templates select="Attribute"/>
+ </dl>
+ </div>
+ </xsl:if>
+ </div>
+</xsl:template>
+<xsl:template match="Dictionary[not(descriptive)]">
+</xsl:template>
+
+<xsl:template match="InterfaceInheritance/ScopedNameList">
+ <p>
+ <xsl:text>This interface inherits from: </xsl:text>
+ <xsl:for-each select="Name">
+ <code><xsl:value-of select="@name"/></code>
+ <xsl:if test="position!=last()">, </xsl:if>
+ </xsl:for-each>
+ </p>
+</xsl:template>
+
+<!--Attribute-->
+<xsl:template match="Attribute">
+ <dt class="attribute" id="{@name}">
+ <code>
+ <xsl:if test="@stringifier">
+ stringifier
+ </xsl:if>
+ <xsl:if test="@readonly">
+ readonly
+ </xsl:if>
+ <xsl:apply-templates select="Type"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>
+ </code></dt>
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="GetRaises"/>
+ <xsl:apply-templates select="SetRaises"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ </dd>
+</xsl:template>
+
+<!--Const-->
+<xsl:template match="Const">
+ <dt class="const" id="{@id}">
+ <code>
+ <xsl:apply-templates select="Type"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>
+ </code>
+ </dt>
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ </dd>
+</xsl:template>
+
+<!--ExtendedAttribute name==Constructor || name==NamedConstructor-->
+<xsl:template match="ExtendedAttributeList/ExtendedAttribute">
+ <dt class="constructor" id="{concat(@name,generate-id(.))}">
+ <code>
+ <xsl:value-of select="../../@name"/>
+ <xsl:text>(</xsl:text>
+ <xsl:apply-templates select="ArgumentList">
+ <xsl:with-param name="nodesc" select="1"/>
+ </xsl:apply-templates>
+ <xsl:text>);</xsl:text>
+ </code>
+ </dt>
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="ArgumentList"/>
+ <xsl:apply-templates select="Raises"/>
+ <xsl:if test="descriptive/api-feature">
+ <div class="api-features">
+ <h6>API features</h6>
+ <dl>
+ <xsl:apply-templates select="descriptive/api-feature"/>
+ </dl>
+ </div>
+ </xsl:if>
+ <xsl:apply-templates select="webidl"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ </dd>
+</xsl:template>
+
+<!--Operation-->
+<xsl:template match="Operation">
+ <dt class="method" id="{concat(@name,generate-id(.))}">
+ <code>
+ <xsl:if test="@stringifier">
+ <xsl:value-of select="concat(@stringifier, ' ')"/>
+ </xsl:if>
+ <xsl:if test="@omittable">
+ <xsl:value-of select="concat(@omittable, ' ')"/>
+ </xsl:if>
+ <xsl:if test="@getter">
+ <xsl:value-of select="concat(@getter, ' ')"/>
+ </xsl:if>
+ <xsl:if test="@setter">
+ <xsl:value-of select="concat(@setter, ' ')"/>
+ </xsl:if>
+ <xsl:if test="@creator">
+ <xsl:value-of select="concat(@creator, ' ')"/>
+ </xsl:if>
+ <xsl:if test="@deleter">
+ <xsl:value-of select="concat(@deleter, ' ')"/>
+ </xsl:if>
+ <xsl:if test="@caller">
+ <xsl:value-of select="concat(@caller, ' ')"/>
+ </xsl:if>
+ <xsl:apply-templates select="Type"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>(</xsl:text>
+ <xsl:apply-templates select="ArgumentList">
+ <xsl:with-param name="nodesc" select="1"/>
+ </xsl:apply-templates>
+ <xsl:text>);</xsl:text>
+ </code>
+ </dt>
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="webidl"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="ArgumentList"/>
+ <xsl:if test="Type/descriptive">
+ <div class="returntype">
+ <h5>Return value</h5>
+ <xsl:apply-templates select="Type/descriptive"/>
+ </div>
+ </xsl:if>
+ <xsl:apply-templates select="Raises"/>
+ <xsl:if test="descriptive/api-feature">
+ <div class="api-features">
+ <h6>API features</h6>
+ <dl>
+ <xsl:apply-templates select="descriptive/api-feature"/>
+ </dl>
+ </div>
+ </xsl:if>
+ <xsl:apply-templates select="descriptive/Code"/>
+ </dd>
+</xsl:template>
+
+<!--Callback-->
+<xsl:template match="Callback">
+ <xsl:variable name="name" select="@name"/>
+ <div class="callback" id="{@id}">
+ <h3><code><xsl:value-of select="@name"/></code></h3>
+
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="webidl"/>
+ <xsl:apply-templates select="descriptive"/>
+ <div class="synopsis">
+ <h6>Signature</h6>
+ <pre>
+ <xsl:apply-templates select="Type"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>(</xsl:text>
+ <xsl:apply-templates select="ArgumentList">
+ <xsl:with-param name="nodesc" select="1"/>
+ </xsl:apply-templates>
+ <xsl:text>);
+</xsl:text></pre>
+ </div>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="ArgumentList"/>
+ <xsl:if test="Type/descriptive">
+ <div class="returntype">
+ <h5>Return value</h5>
+ <xsl:apply-templates select="Type/descriptive"/>
+ </div>
+ </xsl:if>
+ <xsl:apply-templates select="descriptive/Code"/>
+ </dd>
+ </div>
+</xsl:template>
+
+<!--ArgumentList. This is passed $nodesc=true to output just the argument
+ types and names, and not any documentation for them.-->
+<xsl:template match="ArgumentList">
+ <xsl:param name="nodesc"/>
+ <xsl:choose>
+ <xsl:when test="$nodesc">
+ <!--$nodesc is true: just output the types and names-->
+ <xsl:apply-templates select="Argument[1]">
+ <xsl:with-param name="nodesc" select="'nocomma'"/>
+ </xsl:apply-templates>
+ <xsl:apply-templates select="Argument[position() != 1]">
+ <xsl:with-param name="nodesc" select="'comma'"/>
+ </xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="Argument">
+ <!--$nodesc is false: output the documentation-->
+ <div class="parameters">
+ <h6>Parameters</h6>
+ <ul>
+ <xsl:apply-templates/>
+ </ul>
+ </div>
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+<!--Argument. This is passed $nodesc=false to output the documentation,
+ or $nodesc="nocomma" to output the type and name, or $nodesc="comma"
+ to output a comma then the type and name. -->
+<xsl:template match="Argument">
+ <xsl:param name="nodesc"/>
+ <xsl:choose>
+ <xsl:when test="$nodesc">
+ <!--$nodesc is true: just output the types and names-->
+ <xsl:if test="$nodesc = 'comma'">
+ <!--Need a comma first.-->
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ <xsl:if test="@in"><xsl:value-of select="concat(@in, ' ')"/></xsl:if>
+ <xsl:if test="@optional"><xsl:value-of select="concat(@optional, ' ')"/></xsl:if>
+ <xsl:apply-templates select="Type"/>
+ <xsl:if test="@ellipsis"><xsl:text>...</xsl:text></xsl:if>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:if test="@value">
+ <xsl:text>Default value: </xsl:text><xsl:value-of select="@value"/>
+ </xsl:if>
+ <xsl:if test="@stringvalue">
+ <xsl:text>Default value: "</xsl:text><xsl:value-of select="@stringvalue"/><xsl:text>"</xsl:text>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <!--$nodesc is false: output the documentation-->
+ <li class="param">
+ <xsl:value-of select="@name"/>:
+ <xsl:apply-templates select="descriptive"/>
+ </li>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--Raises (for an Operation). It is already known that the list
+ is not empty.-->
+<xsl:template match="Raises">
+ <div class="exceptionlist">
+ <h5>Exceptions</h5>
+ <ul>
+ <xsl:apply-templates/>
+ </ul>
+ </div>
+</xsl:template>
+
+<!--RaiseException, the name of an exception in a Raises.-->
+<xsl:template match="RaiseException">
+ <li class="exception">
+ <xsl:value-of select="@name"/>:
+ <xsl:apply-templates select="descriptive"/>
+ </li>
+</xsl:template>
+
+<!--Type.-->
+<xsl:template match="Type">
+ <xsl:choose>
+ <xsl:when test="Type">
+ <xsl:text>sequence &lt;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>></xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ <xsl:value-of select="@type"/>
+ <xsl:if test="@nullable">
+ <xsl:text>?</xsl:text>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--Enum.-->
+<xsl:template match="Enum[descriptive]">
+ <xsl:variable name="name" select="@name"/>
+ <div class="enum" id="{@id}">
+ <h3><code><xsl:value-of select="@name"/></code></h3>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="webidl"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ <div class="enumvalues">
+ <h4>Values</h4>
+ <dl>
+ <xsl:apply-templates select="EnumValue"/>
+ </dl>
+ </div>
+ </div>
+</xsl:template>
+<xsl:template match="Enum[not(descriptive)]">
+</xsl:template>
+
+<!--EnumValue-->
+<xsl:template match="EnumValue">
+ <dt class="enumvalue" id="{@id}">
+ <code>
+ <xsl:value-of select="@stringvalue"/>
+ </code>
+ </dt>
+ <dd>
+ <xsl:apply-templates select="descriptive/brief"/>
+ <xsl:apply-templates select="descriptive"/>
+ <xsl:apply-templates select="descriptive/Code"/>
+ </dd>
+</xsl:template>
+
+<xsl:template match="descriptive[not(author)]">
+ <xsl:apply-templates select="version"/>
+ <xsl:if test="author">
+ </xsl:if>
+ <xsl:apply-templates select="description"/>
+</xsl:template>
+
+<!--brief-->
+<xsl:template match="brief">
+ <div class="brief">
+ <p>
+ <xsl:apply-templates/>
+ </p>
+ </div>
+</xsl:template>
+
+<!--description in ReturnType or Argument or ScopedName-->
+<xsl:template match="Type/descriptive/description|Argument/descriptive/description|Name/descriptive/description">
+ <!--If the description contains just a single <p> then we omit
+ the <p> and just do its contents.-->
+ <xsl:choose>
+ <xsl:when test="p and count(*) = 1">
+ <xsl:apply-templates select="p/*|p/text()"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <div class="description">
+ <xsl:apply-templates/>
+ </div>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!--Other description-->
+<xsl:template match="description">
+ <div class="description">
+ <xsl:apply-templates/>
+ </div>
+</xsl:template>
+
+<!--Code-->
+<xsl:template match="Code">
+ <div class="example">
+ <xsl:choose>
+ <xsl:when test="@lang">
+ <h5><xsl:value-of select="@lang"/></h5>
+ </xsl:when>
+ <xsl:otherwise>
+ <h5>Code example</h5>
+ </xsl:otherwise>
+ </xsl:choose>
+ <pre class="examplecode"><xsl:apply-templates/></pre>
+ </div>
+</xsl:template>
+
+<!--webidl : literal Web IDL from input-->
+<xsl:template match="webidl">
+ <h5>WebIDL</h5>
+ <pre class="webidl"><xsl:apply-templates/></pre>
+</xsl:template>
+
+<!--author-->
+<xsl:template match="author">
+ <li class="author"><xsl:apply-templates/></li>
+</xsl:template>
+
+<!--version-->
+<xsl:template match="version">
+ <div class="version">
+ <h2>
+ Version: <xsl:apply-templates/>
+ </h2>
+ </div>
+</xsl:template>
+
+<!--api-feature-->
+<xsl:template match="api-feature">
+ <dt>
+ <xsl:value-of select="@identifier"/>
+ </dt>
+ <dd>
+ <xsl:apply-templates/>
+ </dd>
+</xsl:template>
+
+<!--param-->
+<xsl:template match="param">
+ <li>
+ <code><xsl:value-of select="@identifier"/></code>:
+ <xsl:apply-templates/>
+ </li>
+</xsl:template>
+
+<!--def-instantiated.
+ This assumes that only one interface in the module has a def-instantiated,
+ and that interface contains just one attribute.-->
+<xsl:template match="def-instantiated">
+ <xsl:variable name="ifacename" select="../../@name"/>
+ <p>
+ <xsl:choose>
+ <xsl:when test="count(descriptive/api-feature)=1">
+ When the feature
+ </xsl:when>
+ <xsl:otherwise>
+ When any of the features
+ </xsl:otherwise>
+ </xsl:choose>
+ </p>
+ <ul>
+ <xsl:for-each select="descriptive/api-feature">
+ <li><code>
+ <xsl:value-of select="@identifier"/>
+ </code></li>
+ </xsl:for-each>
+ </ul>
+ <p>
+ is successfully requested, the interface
+ <code><xsl:apply-templates select="../../Attribute/Type"/></code>
+ is instantiated, and the resulting object appears in the global
+ namespace as
+ <code><xsl:value-of select="../../../Implements[@name2=$ifacename]/@name1"/>.<xsl:value-of select="../../Attribute/@name"/></code>.
+ </p>
+</xsl:template>
+
+
+
+<!--html elements-->
+<xsl:template match="a|b|br|dd|dl|dt|em|li|p|table|td|th|tr|ul">
+ <xsl:element name="{name()}"><xsl:for-each select="@*"><xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute></xsl:for-each><xsl:apply-templates/></xsl:element>
+</xsl:template>
+
+<xsl:template name="summary">
+ <table class="summary">
+ <thead>
+ <tr><th>Interface</th><th>Method</th></tr>
+ </thead>
+ <tbody>
+ <xsl:for-each select="Interface[descriptive]">
+ <tr><td><a href="#{@id}"><xsl:value-of select="@name"/></a></td>
+ <td>
+ <xsl:for-each select="Operation">
+
+ <xsl:apply-templates select="Type"/>
+ <xsl:text> </xsl:text>
+ <a href="#{concat(@name,generate-id(.))}"><xsl:value-of select="@name"/></a>
+ <xsl:text>(</xsl:text>
+ <xsl:for-each select="ArgumentList/Argument">
+ <xsl:variable name="type"><xsl:apply-templates select="Type"/></xsl:variable>
+ <xsl:value-of select="concat(normalize-space($type),' ',@name)"/>
+ <xsl:if test="position() != last()">, </xsl:if>
+ </xsl:for-each>
+ <xsl:text>)</xsl:text>
+ <xsl:if test="position()!=last()"><br/></xsl:if>
+ </xsl:for-each>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </tbody>
+ </table>
+</xsl:template>
+
+<!--<ref> element in literal Web IDL.-->
+<xsl:template match="ref[@ref]">
+ <a href="{@ref}">
+ <xsl:apply-templates/>
+ </a>
+</xsl:template>
+
+</xsl:stylesheet>
+