diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /testing/web-platform/tests/resources/webidl2/test/widlproc/src | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-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')
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, + ¶_end, /* end */ + ¶_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(¶mcnode->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 */ + ¶m_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 = ¶m_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, ¶mcnode->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 == ¶_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 == ¶_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 == ¶_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 == ¶_funcs || type == ¶m_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, ¶m_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, ¶_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 &\0$\0 #\0 <\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, ¶_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 == ¶m_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 == ¶m_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 \0" \ +"iexcl\0¡\0" \ +"cent\0¢\0" \ +"pound\0£\0" \ +"curren\0¤\0" \ +"yen\0¥\0" \ +"brvbar\0¦\0" \ +"sect\0§\0" \ +"uml\0¨\0" \ +"copy\0©\0" \ +"ordf\0ª\0" \ +"laquo\0«\0" \ +"not\0¬\0" \ +"shy\0­\0" \ +"reg\0®\0" \ +"macr\0¯\0" \ +"deg\0°\0" \ +"plusmn\0±\0" \ +"sup2\0²\0" \ +"sup3\0³\0" \ +"acute\0´\0" \ +"micro\0µ\0" \ +"para\0¶\0" \ +"middot\0·\0" \ +"cedil\0¸\0" \ +"sup1\0¹\0" \ +"ordm\0º\0" \ +"raquo\0»\0" \ +"frac14\0¼\0" \ +"frac12\0½\0" \ +"frac34\0¾\0" \ +"iquest\0¿\0" \ +"Agrave\0À\0" \ +"Aacute\0Á\0" \ +"Acirc\0Â\0" \ +"Atilde\0Ã\0" \ +"Auml\0Ä\0" \ +"Aring\0Å\0" \ +"AElig\0Æ\0" \ +"Ccedil\0Ç\0" \ +"Egrave\0È\0" \ +"Eacute\0É\0" \ +"Ecirc\0Ê\0" \ +"Euml\0Ë\0" \ +"Igrave\0Ì\0" \ +"Iacute\0Í\0" \ +"Icirc\0Î\0" \ +"Iuml\0Ï\0" \ +"ETH\0Ð\0" \ +"Ntilde\0Ñ\0" \ +"Ograve\0Ò\0" \ +"Oacute\0Ó\0" \ +"Ocirc\0Ô\0" \ +"Otilde\0Õ\0" \ +"Ouml\0Ö\0" \ +"times\0×\0" \ +"Oslash\0Ø\0" \ +"Ugrave\0Ù\0" \ +"Uacute\0Ú\0" \ +"Ucirc\0Û\0" \ +"Uuml\0Ü\0" \ +"Yacute\0Ý\0" \ +"THORN\0Þ\0" \ +"szlig\0ß\0" \ +"agrave\0à\0" \ +"aacute\0á\0" \ +"acirc\0â\0" \ +"atilde\0ã\0" \ +"auml\0ä\0" \ +"aring\0å\0" \ +"aelig\0æ\0" \ +"ccedil\0ç\0" \ +"egrave\0è\0" \ +"eacute\0é\0" \ +"ecirc\0ê\0" \ +"euml\0ë\0" \ +"igrave\0ì\0" \ +"iacute\0í\0" \ +"icirc\0î\0" \ +"iuml\0ï\0" \ +"eth\0ð\0" \ +"ntilde\0ñ\0" \ +"ograve\0ò\0" \ +"oacute\0ó\0" \ +"ocirc\0ô\0" \ +"otilde\0õ\0" \ +"ouml\0ö\0" \ +"divide\0÷\0" \ +"oslash\0ø\0" \ +"ugrave\0ù\0" \ +"uacute\0ú\0" \ +"ucirc\0û\0" \ +"uuml\0ü\0" \ +"yacute\0ý\0" \ +"thorn\0þ\0" \ +"yuml\0ÿ\0" \ +"fnof\0ƒ\0" \ +"Alpha\0Α\0" \ +"Beta\0Β\0" \ +"Gamma\0Γ\0" \ +"Delta\0Δ\0" \ +"Epsilon\0Ε\0" \ +"Zeta\0Ζ\0" \ +"Eta\0Η\0" \ +"Theta\0Θ\0" \ +"Iota\0Ι\0" \ +"Kappa\0Κ\0" \ +"Lambda\0Λ\0" \ +"Mu\0Μ\0" \ +"Nu\0Ν\0" \ +"Xi\0Ξ\0" \ +"Omicron\0Ο\0" \ +"Pi\0Π\0" \ +"Rho\0Ρ\0" \ +"Sigma\0Σ\0" \ +"Tau\0Τ\0" \ +"Upsilon\0Υ\0" \ +"Phi\0Φ\0" \ +"Chi\0Χ\0" \ +"Psi\0Ψ\0" \ +"Omega\0Ω\0" \ +"alpha\0α\0" \ +"beta\0β\0" \ +"gamma\0γ\0" \ +"delta\0δ\0" \ +"epsilon\0ε\0" \ +"zeta\0ζ\0" \ +"eta\0η\0" \ +"theta\0θ\0" \ +"iota\0ι\0" \ +"kappa\0κ\0" \ +"lambda\0λ\0" \ +"mu\0μ\0" \ +"nu\0ν\0" \ +"xi\0ξ\0" \ +"omicron\0ο\0" \ +"pi\0π\0" \ +"rho\0ρ\0" \ +"sigmaf\0ς\0" \ +"sigma\0σ\0" \ +"tau\0τ\0" \ +"upsilon\0υ\0" \ +"phi\0φ\0" \ +"chi\0χ\0" \ +"psi\0ψ\0" \ +"omega\0ω\0" \ +"thetasym\0ϑ\0" \ +"upsih\0ϒ\0" \ +"piv\0ϖ\0" \ +"bull\0•\0" \ +"hellip\0…\0" \ +"prime\0′\0" \ +"Prime\0″\0" \ +"oline\0‾\0" \ +"frasl\0⁄\0" \ +"weierp\0℘\0" \ +"image\0ℑ\0" \ +"real\0ℜ\0" \ +"trade\0™\0" \ +"alefsym\0ℵ\0" \ +"larr\0←\0" \ +"uarr\0↑\0" \ +"rarr\0→\0" \ +"darr\0↓\0" \ +"harr\0↔\0" \ +"crarr\0↵\0" \ +"lArr\0⇐\0" \ +"uArr\0⇑\0" \ +"rArr\0⇒\0" \ +"dArr\0⇓\0" \ +"hArr\0⇔\0" \ +"forall\0∀\0" \ +"part\0∂\0" \ +"exist\0∃\0" \ +"empty\0∅\0" \ +"nabla\0∇\0" \ +"isin\0∈\0" \ +"notin\0∉\0" \ +"ni\0∋\0" \ +"prod\0∏\0" \ +"sum\0∑\0" \ +"minus\0−\0" \ +"lowast\0∗\0" \ +"radic\0√\0" \ +"prop\0∝\0" \ +"infin\0∞\0" \ +"ang\0∠\0" \ +"and\0∧\0" \ +"or\0∨\0" \ +"cap\0∩\0" \ +"cup\0∪\0" \ +"int\0∫\0" \ +"there4\0∴\0" \ +"sim\0∼\0" \ +"cong\0≅\0" \ +"asymp\0≈\0" \ +"ne\0≠\0" \ +"equiv\0≡\0" \ +"le\0≤\0" \ +"ge\0≥\0" \ +"sub\0⊂\0" \ +"sup\0⊃\0" \ +"nsub\0⊄\0" \ +"sube\0⊆\0" \ +"supe\0⊇\0" \ +"oplus\0⊕\0" \ +"otimes\0⊗\0" \ +"perp\0⊥\0" \ +"sdot\0⋅\0" \ +"lceil\0⌈\0" \ +"rceil\0⌉\0" \ +"lfloor\0⌊\0" \ +"rfloor\0⌋\0" \ +"lang\0〈\0" \ +"rang\0〉\0" \ +"loz\0◊\0" \ +"spades\0♠\0" \ +"clubs\0♣\0" \ +"hearts\0♥\0" \ +"diams\0♦\0" \ +"quot\0"\0" \ +"amp\0&\0" \ +"lt\0<\0" \ +"gt\0>\0" \ +"OElig\0Œ\0" \ +"oelig\0œ\0" \ +"Scaron\0Š\0" \ +"scaron\0š\0" \ +"Yuml\0Ÿ\0" \ +"circ\0ˆ\0" \ +"tilde\0˜\0" \ +"ensp\0 \0" \ +"emsp\0 \0" \ +"thinsp\0 \0" \ +"zwnj\0‌\0" \ +"zwj\0‍\0" \ +"lrm\0‎\0" \ +"rlm\0‏\0" \ +"ndash\0–\0" \ +"mdash\0—\0" \ +"lsquo\0‘\0" \ +"rsquo\0’\0" \ +"sbquo\0‚\0" \ +"ldquo\0“\0" \ +"rdquo\0”\0" \ +"bdquo\0„\0" \ +"dagger\0†\0" \ +"Dagger\0‡\0" \ +"permil\0‰\0" \ +"lsaquo\0‹\0" \ +"rsaquo\0›\0" \ +"euro\0€\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 = "<"; + break; + case '&': + seq = escamp ? "&" : "&"; + break; + case '"': + seq = """; + 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 <</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> + |