From 42a4d680b17d6ed4d0cc1108cef5d1b299495f01 Mon Sep 17 00:00:00 2001
From: Mathias Hasselmann <mathias.hasselmann@gmx.de>
Date: Tue, 4 Sep 2007 22:34:15 +0200
Subject: [PATCH] c2xml: Add support for custom attributes and omit end position information when
equal to start position. Custom attributes are needed for GObject introspection
to express details like this:

      GList* create_list() __attribute__((element_type(char*)))

Signed-off-by: Mathias Hasselmann <mathias.hasselmann@gmx.de>
---
 c2xml.c |  222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 192 insertions(+), 30 deletions(-)

diff --git a/c2xml.c b/c2xml.c
index 37f29cf..36baa68 100644
--- a/c2xml.c
+++ b/c2xml.c
@@ -46,39 +46,48 @@ static xmlAttrPtr newIdProp(xmlNodePtr node, const char *name, unsigned int id)
 	return newProp(node, name, buf);
 }
 
-static xmlNodePtr new_sym_node(struct symbol *sym, const char *name, xmlNodePtr parent)
+static void newPositionProps(xmlNodePtr node, struct position pos, struct position endpos)
 {
+	newProp(node, "file", stream_name(pos.stream));
+
+	newNumProp(node, "start-line", pos.line);
+	newNumProp(node, "start-col", pos.pos);
+
+	if (endpos.type 
+            && (pos.line != endpos.line 
+            ||  pos.pos != endpos.pos 
+            ||  pos.stream != endpos.stream)) {
+		newNumProp(node, "end-line", endpos.line);
+		newNumProp(node, "end-col", endpos.pos);
+		if (pos.stream != endpos.stream)
+			newProp(node, "end-file", stream_name(endpos.stream));
+        }
+}
+
+static xmlNodePtr new_sym_node(struct symbol *sym, const char *type, xmlNodePtr parent)
+{
+	const char *ident = NULL;
 	xmlNodePtr node;
-	const char *ident = show_ident(sym->ident);
 
-	assert(name != NULL);
+	assert(type != NULL);
 	assert(sym != NULL);
 	assert(parent != NULL);
 
 	node = xmlNewChild(parent, NULL, BAD_CAST "symbol", NULL);
 
-	newProp(node, "type", name);
-
+	newProp(node, "type", type);
 	newIdProp(node, "id", idcount);
 
-	if (sym->ident && ident)
+	if (sym->ident)
+		ident = show_ident(sym->ident);
+	if (ident)
 		newProp(node, "ident", ident);
-	newProp(node, "file", stream_name(sym->pos.stream));
 
-	newNumProp(node, "start-line", sym->pos.line);
-	newNumProp(node, "start-col", sym->pos.pos);
-
-	if (sym->endpos.type) {
-		newNumProp(node, "end-line", sym->endpos.line);
-		newNumProp(node, "end-col", sym->endpos.pos);
-		if (sym->pos.stream != sym->endpos.stream)
-			newProp(node, "end-file", stream_name(sym->endpos.stream));
-        }
-	sym->aux = node;
+	newPositionProps (node, sym->pos, sym->endpos);
 
 	idcount++;
 
-	return node;
+	return (sym->aux = node);
 }
 
 static inline void examine_members(struct symbol_list *list, xmlNodePtr node)
@@ -151,10 +160,106 @@ examine_layout(struct symbol *sym, xmlNodePtr node)
 	}
 }
 
-static void examine_symbol(struct symbol *sym, xmlNodePtr node)
+static void examine_expression(struct expression *expr, xmlNodePtr node)
 {
 	xmlNodePtr child = NULL;
+
+	if (expr) {
+		switch (expr->type) {
+			case EXPR_COMMA:
+				examine_expression(expr->left, node);
+				examine_expression(expr->right, node);
+				break;
+
+			case EXPR_STRING:
+				child = xmlNewChild(node, NULL, BAD_CAST "expression", NULL);
+
+				newProp(child, "type", "string");
+				newProp(child, "value", expr->string->data);
+				break;
+
+			default:
+				child = xmlNewChild(node, NULL, BAD_CAST "expression", NULL);
+
+				newProp(child, "type", "value");
+				newNumProp(child, "value", const_expression_value (expr));
+
+				break;
+		}
+
+		if (child)
+			newPositionProps(child, expr->pos, expr->pos);
+	}
+}
+
+static void examine_typeref(struct symbol *typeref, xmlNodePtr node)
+{
+	xmlNodePtr child;
 	const char *base;
+
+	child = xmlNewChild(node, NULL, BAD_CAST "type-reference", NULL);
+
+	if ((base = builtin_typename(typeref)) == NULL) {
+		if (!typeref->aux) {
+			examine_symbol(typeref, root_node);
+		}
+
+		xmlNewProp(child, BAD_CAST "type", xmlGetProp((xmlNodePtr)typeref->aux, BAD_CAST "id"));
+	} else {
+		newProp(child, "type-builtin", base);
+	}
+}
+
+static void examine_attribute(struct attribute *attr, xmlNodePtr node)
+{
+	xmlNodePtr child;
+
+	child = xmlNewChild(node, NULL, BAD_CAST "attribute", NULL);
+
+	newProp(child, "name", attr->symbol->ident->name);
+	newPositionProps(child, attr->pos, attr->endpos);
+
+	switch (attr->type) {
+		case AT_EXPRESSION:
+			examine_expression(attr->expr, child);
+			break;
+
+		case AT_TYPEREF:
+			examine_typeref(attr->typeref, child);
+			break;
+	}
+}
+
+static void examine_ctype(struct ctype *ctype, xmlNodePtr node)
+{
+	struct attribute *attr;
+	const char *base;
+
+	assert(ctype != NULL);
+	assert(node != NULL);
+
+	if (ctype->base_type) {
+		if ((base = builtin_typename(ctype->base_type)) == NULL) {
+			if (!ctype->base_type->aux) {
+				examine_symbol(ctype->base_type, root_node);
+			}
+			xmlNewProp(node, BAD_CAST "base-type",
+				   xmlGetProp((xmlNodePtr)ctype->base_type->aux, BAD_CAST "id"));
+		} else {
+			newProp(node, "base-type-builtin", base);
+		}
+	}
+
+	if (ctype->attributes) {
+		FOR_EACH_PTR(ctype->attributes, attr) {
+			examine_attribute(attr, node);
+		} END_FOR_EACH_PTR(attr);
+	}
+}
+
+static void examine_symbol(struct symbol *sym, xmlNodePtr node)
+{
+	xmlNodePtr child = NULL;
 	int array_size;
 
 	if (!sym)
@@ -168,18 +273,8 @@ static void examine_symbol(struct symbol *sym, xmlNodePtr node)
 	child = new_sym_node(sym, get_type_name(sym->type), node);
 	examine_modifiers(sym, child);
 	examine_layout(sym, child);
+	examine_ctype (&sym->ctype, child);
 
-	if (sym->ctype.base_type) {
-		if ((base = builtin_typename(sym->ctype.base_type)) == NULL) {
-			if (!sym->ctype.base_type->aux) {
-				examine_symbol(sym->ctype.base_type, root_node);
-			}
-			xmlNewProp(child, BAD_CAST "base-type",
-			           xmlGetProp((xmlNodePtr)sym->ctype.base_type->aux, BAD_CAST "id"));
-		} else {
-			newProp(child, "base-type-builtin", base);
-		}
-	}
 	if (sym->array_size) {
 		/* TODO: modify get_expression_value to give error return */
 		array_size = get_expression_value(sym->array_size);
@@ -281,6 +376,72 @@ static inline void examine_symbol_list(const char *file, struct symbol_list *lis
 	} END_FOR_EACH_PTR(sym);
 }
 
+static struct token *expr_attribute(struct token *token, struct symbol *symbol, struct ctype *ctype)
+{
+	struct attribute *attr = alloc_attribute (token->pos, AT_EXPRESSION, symbol);
+
+	add_attribute(&ctype->attributes, attr);
+
+	if (match_op(token, '('))
+		token = parens_expression(token, &attr->expr, "in attribute");
+
+	attr->endpos = token->pos;
+
+	return token;
+}
+
+static struct token *typename_attribute(struct token *token, struct symbol *symbol, struct ctype *ctype)
+{
+	struct attribute *attr = alloc_attribute (token->pos, AT_TYPEREF, symbol);
+
+	add_attribute(&ctype->attributes, attr);
+
+	token = expect (token, '(', "at attribute");
+
+	if (lookup_type(token)) {
+		struct symbol *sym;
+		int is_force;
+
+		token = typename(token, &sym, MOD_FORCE);
+		is_force = sym->ctype.modifiers & MOD_FORCE;
+		sym->ctype.modifiers &= ~MOD_FORCE;
+		token = expect(token, ')', "at end of attribute");
+
+		assert (SYM_NODE == sym->type);
+
+		attr->typeref = sym->ctype.base_type;
+	} else {
+		sparse_error (token->pos, "typename expected for %s attibute", symbol->ident->name);
+	}
+
+	attr->endpos = token->pos;
+
+	return token;
+}
+
+static struct symbol_op store_expr_attribute_op = {
+	.attribute = expr_attribute,
+};
+
+static struct symbol_op store_typename_attribute_op = {
+	.attribute = typename_attribute,
+};
+
+static struct init_keyword attribute_table[] = {
+	{ "owns_elements",	NS_KEYWORD, .op = &store_expr_attribute_op },
+	{ "element_type",	NS_KEYWORD, .op = &store_typename_attribute_op },
+};
+
+static void initialize_attributes()
+{
+	struct symbol *keyword;
+
+	keyword = lookup_keyword(&unused_ident, NS_KEYWORD | NS_TYPEDEF);
+	keyword->op->attribute = expr_attribute;
+
+	init_keyword_table (-1, attribute_table, sizeof attribute_table/sizeof attribute_table[0]);
+}
+
 int main(int argc, char **argv)
 {
 	struct string_list *filelist = NULL;
@@ -300,6 +461,7 @@ int main(int argc, char **argv)
 	xmlSetNs(root_node, ns);
 */
 	symlist = sparse_initialize(argc, argv, &filelist);
+	initialize_attributes();
 
 	FOR_EACH_PTR_NOTAG(filelist, file) {
 		examine_symbol_list(file, symlist);
-- 
1.5.2.3

