diff options
Diffstat (limited to 'src/webidl-ast.c')
-rw-r--r-- | src/webidl-ast.c | 278 |
1 files changed, 251 insertions, 27 deletions
diff --git a/src/webidl-ast.c b/src/webidl-ast.c index d75a186..87e3485 100644 --- a/src/webidl-ast.c +++ b/src/webidl-ast.c @@ -11,18 +11,25 @@ #include <stdio.h> #include <string.h> #include <errno.h> +#include <stdarg.h> +#include "utils.h" #include "webidl-ast.h" #include "options.h" +/** + * standard IO handle for parse trace logging. + */ +static FILE *webidl_parsetracef; + extern int webidl_debug; extern int webidl__flex_debug; extern void webidl_restart(FILE*); extern int webidl_parse(struct webidl_node **webidl_ast); struct webidl_node { - enum webidl_node_type type; - struct webidl_node *l; + enum webidl_node_type type; /* the type of the node */ + struct webidl_node *l; /* link to the next sibling node */ union { void *value; struct webidl_node *node; /* node has a list of nodes */ @@ -93,7 +100,7 @@ webidl_node_add(struct webidl_node *node, struct webidl_node *list) case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE: case WEBIDL_NODE_TYPE_ATTRIBUTE: case WEBIDL_NODE_TYPE_OPERATION: - case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT: + case WEBIDL_NODE_TYPE_OPTIONAL: case WEBIDL_NODE_TYPE_ARGUMENT: case WEBIDL_NODE_TYPE_TYPE: case WEBIDL_NODE_TYPE_CONST: @@ -162,6 +169,26 @@ int webidl_cmp_node_type(struct webidl_node *node, void *ctx) return 0; } +static int webidl_enumerate_node(struct webidl_node *node, void *ctx) +{ + node = node; + (*((int *)ctx))++; + return 0; +} + +/* exported interface defined in nsgenbind-ast.h */ +int +webidl_node_enumerate_type(struct webidl_node *node, + enum webidl_node_type type) +{ + int count = 0; + webidl_node_for_each_type(node, + type, + webidl_enumerate_node, + &count); + return count; +} + /* exported interface defined in webidl-ast.h */ struct webidl_node * webidl_node_find(struct webidl_node *node, @@ -203,6 +230,7 @@ webidl_node_find_type(struct webidl_node *node, } +/* exported interface defined in webidl-ast.h */ struct webidl_node * webidl_node_find_type_ident(struct webidl_node *root_node, enum webidl_node_type type, @@ -230,6 +258,7 @@ webidl_node_find_type_ident(struct webidl_node *root_node, } +/* exported interface defined in webidl-ast.h */ char *webidl_node_gettext(struct webidl_node *node) { if (node != NULL) { @@ -238,16 +267,18 @@ char *webidl_node_gettext(struct webidl_node *node) case WEBIDL_NODE_TYPE_IDENT: case WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE: case WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS: + case WEBIDL_NODE_TYPE_LITERAL_STRING: return node->r.text; default: - break; + break; } } return NULL; } -int +/* exported interface defined in webidl-ast.h */ +int * webidl_node_getint(struct webidl_node *node) { if (node != NULL) { @@ -255,22 +286,25 @@ webidl_node_getint(struct webidl_node *node) case WEBIDL_NODE_TYPE_MODIFIER: case WEBIDL_NODE_TYPE_TYPE_BASE: case WEBIDL_NODE_TYPE_LITERAL_INT: - return node->r.number; + case WEBIDL_NODE_TYPE_SPECIAL: + case WEBIDL_NODE_TYPE_LITERAL_BOOL: + return &node->r.number; default: break; } } - return -1; - + return NULL; } +/* exported interface defined in webidl-ast.h */ enum webidl_node_type webidl_node_gettype(struct webidl_node *node) { return node->type; } +/* exported interface defined in webidl-ast.h */ struct webidl_node *webidl_node_getnode(struct webidl_node *node) { if (node != NULL) { @@ -281,7 +315,7 @@ struct webidl_node *webidl_node_getnode(struct webidl_node *node) case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE: case WEBIDL_NODE_TYPE_ATTRIBUTE: case WEBIDL_NODE_TYPE_OPERATION: - case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT: + case WEBIDL_NODE_TYPE_OPTIONAL: case WEBIDL_NODE_TYPE_ARGUMENT: case WEBIDL_NODE_TYPE_TYPE: case WEBIDL_NODE_TYPE_CONST: @@ -294,6 +328,7 @@ struct webidl_node *webidl_node_getnode(struct webidl_node *node) } +/* exported interface defined in webidl-ast.h */ static const char *webidl_node_type_to_str(enum webidl_node_type type) { switch(type) { @@ -321,8 +356,8 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type) case WEBIDL_NODE_TYPE_OPERATION: return "Operation"; - case WEBIDL_NODE_TYPE_OPTIONAL_ARGUMENT: - return "Argument(opt)"; + case WEBIDL_NODE_TYPE_OPTIONAL: + return "Optional"; case WEBIDL_NODE_TYPE_ARGUMENT: return "Argument"; @@ -348,24 +383,44 @@ static const char *webidl_node_type_to_str(enum webidl_node_type type) case WEBIDL_NODE_TYPE_CONST: return "Const"; + case WEBIDL_NODE_TYPE_LITERAL_NULL: + return "Literal (null)"; + case WEBIDL_NODE_TYPE_LITERAL_INT: return "Literal (int)"; + case WEBIDL_NODE_TYPE_LITERAL_BOOL: + return "Literal (bool)"; + + case WEBIDL_NODE_TYPE_LITERAL_FLOAT: + return "Literal (string)"; + + case WEBIDL_NODE_TYPE_LITERAL_STRING: + return "Literal (string)"; + case WEBIDL_NODE_TYPE_EXTENDED_ATTRIBUTE: return "Extended Attribute"; + case WEBIDL_NODE_TYPE_SPECIAL: + return "Special"; + default: return "Unknown"; } } - -int webidl_ast_dump(struct webidl_node *node, int indent) +/** + * Recursively dump the AST nodes increasing indent as appropriate + */ +static int webidl_ast_dump(FILE *dumpf, struct webidl_node *node, int indent) { - const char *SPACES=" "; char *txt; + const char *SPACES=" "; + char *txt; + int *value; while (node != NULL) { - printf("%.*s%s", indent, SPACES, webidl_node_type_to_str(node->type)); + fprintf(dumpf, "%.*s%s", indent, SPACES, + webidl_node_type_to_str(node->type)); txt = webidl_node_gettext(node); if (txt == NULL) { @@ -374,32 +429,61 @@ int webidl_ast_dump(struct webidl_node *node, int indent) next = webidl_node_getnode(node); if (next != NULL) { - printf("\n"); - webidl_ast_dump(next, indent + 2); + fprintf(dumpf, "\n"); + webidl_ast_dump(dumpf, next, indent + 2); } else { - /* not txt or node has to be an int */ - printf(": %d\n", webidl_node_getint(node)); + /* not txt or node try an int */ + value = webidl_node_getint(node); + if (value != NULL) { + fprintf(dumpf, ": %d\n", *value); + } else { + /* no value */ + fprintf(dumpf, "\n"); + } } } else { - printf(": \"%s\"\n", txt); + fprintf(dumpf, ": \"%s\"\n", txt); } node = node->l; } return 0; } +/* exported interface documented in webidl-ast.h */ +int webidl_dump_ast(struct webidl_node *node) +{ + FILE *dumpf; + + /* only dump AST to file if required */ + if (!options->debug) { + return 0; + } + + dumpf = genb_fopen("webidl-ast", "w"); + if (dumpf == NULL) { + return 2; + } + + webidl_ast_dump(dumpf, node, 0); + + fclose(dumpf); + + return 0; +} + +/* exported interface defined in webidl-ast.h */ static FILE *idlopen(const char *filename) { FILE *idlfile; char *fullname; - int fulllen; + int fulllen; if (options->idlpath == NULL) { if (options->verbose) { printf("Opening IDL file %s\n", filename); } return fopen(filename, "r"); - } + } fulllen = strlen(options->idlpath) + strlen(filename) + 2; fullname = malloc(fulllen); @@ -409,14 +493,15 @@ static FILE *idlopen(const char *filename) } idlfile = fopen(fullname, "r"); free(fullname); - + return idlfile; } +/* exported interface defined in webidl-ast.h */ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast) { - FILE *idlfile; + int ret; idlfile = idlopen(filename); if (!idlfile) { @@ -426,14 +511,153 @@ int webidl_parsefile(char *filename, struct webidl_node **webidl_ast) return 2; } - if (options->debug) { + /* if debugging enabled enable parser tracing and send to file */ + if (options->debug) { + char *tracename; + int tracenamelen; webidl_debug = 1; webidl__flex_debug = 1; - } + + tracenamelen = SLEN("webidl--trace") + strlen(filename) + 1; + tracename = malloc(tracenamelen); + snprintf(tracename, tracenamelen,"webidl-%s-trace", filename); + webidl_parsetracef = genb_fopen(tracename, "w"); + free(tracename); + } else { + webidl_parsetracef = NULL; + } /* set flex to read from file */ webidl_restart(idlfile); /* parse the file */ - return webidl_parse(webidl_ast); + ret = webidl_parse(webidl_ast); + + /* close tracefile if open */ + if (webidl_parsetracef != NULL) { + fclose(webidl_parsetracef); + } + return ret; +} + +/* exported interface defined in webidl-ast.h */ +int webidl_fprintf(FILE *stream, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + + if (webidl_parsetracef == NULL) { + ret = vfprintf(stream, format, ap); + } else { + ret = vfprintf(webidl_parsetracef, format, ap); + } + va_end(ap); + + return ret; +} + +/* unlink a child node from a parent */ +static int +webidl_unlink(struct webidl_node *parent, struct webidl_node *node) +{ + struct webidl_node *child; + + child = webidl_node_getnode(parent); + if (child == NULL) { + /* parent does not have children to remove node from */ + return -1; + } + + if (child == node) { + /* parent is pointing at the node we want to remove */ + parent->r.node = node->l; /* point parent at next sibing */ + node->l = NULL; + return 0; + } + + while (child->l != NULL) { + if (child->l == node) { + /* found node, unlink from list */ + child->l = node->l; + node->l = NULL; + return 0; + } + child = child->l; + } + return -1; /* failed to remove node */ +} + +static int implements_copy_nodes(struct webidl_node *src_node, + struct webidl_node *dst_node) +{ + struct webidl_node *src; + struct webidl_node *dst; + + src = webidl_node_getnode(src_node); + dst = webidl_node_getnode(dst_node); + + while (src != NULL) { + if (src->type == WEBIDL_NODE_TYPE_LIST) { + /** @todo technicaly this should copy WEBIDL_NODE_TYPE_INTERFACE_INHERITANCE */ + dst = webidl_node_new(src->type, dst, src->r.text); + } + src = src->l; + } + + dst_node->r.node = dst; + + return 0; +} + +static int +intercalate_implements(struct webidl_node *interface_node, void *ctx) +{ + struct webidl_node *implements_node; + struct webidl_node *implements_interface_node; + struct webidl_node *webidl_ast = ctx; + + implements_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + NULL, + WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS); + while (implements_node != NULL) { + + implements_interface_node = webidl_node_find_type_ident( + webidl_ast, + WEBIDL_NODE_TYPE_INTERFACE, + webidl_node_gettext(implements_node)); + + /* recurse, ensuring all subordinate interfaces have + * their implements intercalated first + */ + intercalate_implements(implements_interface_node, webidl_ast); + + implements_copy_nodes(implements_interface_node, interface_node); + + /* once we have copied the implemntation remove entry */ + webidl_unlink(interface_node, implements_node); + + implements_node = webidl_node_find_type( + webidl_node_getnode(interface_node), + implements_node, + WEBIDL_NODE_TYPE_INTERFACE_IMPLEMENTS); + } + return 0; +} + +/* exported interface defined in webidl-ast.h */ +int webidl_intercalate_implements(struct webidl_node *webidl_ast) +{ + /* for each interface: + * for each implements entry: + * find interface from implemets + * recusrse into that interface + * copy the interface into this one + */ + return webidl_node_for_each_type(webidl_ast, + WEBIDL_NODE_TYPE_INTERFACE, + intercalate_implements, + webidl_ast); } |