summaryrefslogtreecommitdiff
path: root/src/webidl-ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/webidl-ast.c')
-rw-r--r--src/webidl-ast.c278
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);
}