[gob] Git is STUPID!



commit de60a40db3b700ec7f92066bb8b2ef7e368be491
Author: Jiri (George) Lebl <jirka 5z com>
Date:   Fri Jul 10 10:22:30 2009 -0500

    Git is STUPID!
    
    IT IS SO STUPID I CAN'T EVEN SAY IT LOUD ENOUGH
    
    IT IS .... STUUUUUUUUUUUUUPID!
    
    -Jiri

 ChangeLog         |   16 +++++
 doc/gob2.1.in     |   38 ++++++++---
 src/checks.c      |   24 +++++++
 src/checks.h      |    1 +
 src/lexer.l       |    6 ++
 src/main.c        |   89 +++++++++++++++++-------
 src/parse.y       |  196 +++++++++++++++++++++++++++++++++++++++++++++++++----
 src/test.gob      |   54 ++++++++++++++-
 src/treefuncs.c   |   18 +++++
 src/treefuncs.def |    1 +
 src/treefuncs.h   |    1 +
 11 files changed, 392 insertions(+), 52 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 44d4eba..29565e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+Fri Jul 10 10:22:10 2009  Jiri (George) Lebl <jirka 5z com>
+
+	* doc/gob2.1.in: fix the _GET_CLASS documentation.  Thanks to
+	  Andrew Feren acferen at yahoo dot com.  I guess this has been an
+	  error in the docs since the GTK 1.x days
+
+Fri Jul 10 09:57:29 2009  Jiri (George) Lebl <jirka 5z com>
+
+	* doc/gob2.1.in, src/checks.c, src/checks.h, src/lexer.l, src/main.c,
+	  src/parse.y, src/str.gob, src/str_test.c, src/test.gob,
+	  src/treefuncs.def: Apply patch by Britton Kerin
+	  bkerin at fastmail dot fm, to allow function attributes
+	  like G_GNUC_PRINTF, etc...
+
+	* src/main.c: fix a warning
+
 Tue Nov 20 23:22:57 2007  Jiri (George) Lebl <jirka 5z com>
 
 	* Release 2.0.15
diff --git a/doc/gob2.1.in b/doc/gob2.1.in
index 9a53cff..663d56b 100644
--- a/doc/gob2.1.in
+++ b/doc/gob2.1.in
@@ -282,11 +282,12 @@ member foo:
   classwide int foo;
 
 .fi
-To access the member you do the standard voodoo of getting the class from the
-object and casting it to your class pointer.  Thus the following would work:
+To access the member you can use the SELF_GET_CLASS macro (or
+YOUR_OBJECT_NAME_GET_CLASS) to get at the class.
+Thus the following would work:
 .nf
 
-  SELF_CLASS(GTK_OBJECT(object)->klass)->foo = 20;
+  SELF_GET_CLASS(object)->foo = 20;
 
 .fi
 .PP
@@ -604,15 +605,34 @@ to be more then 0 and less then 11, and a pointer to a GtkWidget object
 instance and it is checked for being null and the type will also be
 checked.
 .PP
+.B "Function attributes:
+.PP
+For method that aren't virtual, signal or override methods, and aren't
+init or class_init, the GLib function attribute macros G_GNUC_PRINTF,
+G_GNUC_SCANF, and G_GNUC_FORMAT can optionally be included after the
+argument list, for example:
+.nf
+
+  public void
+  print (self, const char *format (check null), ...) G_GNUC_PRINTF(2, 3)
+
+.fi
+.PP
+This will produce a prototype which will generate a warning at compile
+time if the contents of the format argument (argument number 2) aren't
+consistent with the types and number of the subsequent variadic
+arguments (the first of which is argument number 3).
+.PP
 .B "Error return:"
 .PP
 Methods which have a return value, there also has to be something
-returned if there is an error, such as if a precondition is not met.  The
-default is 0, casted to the type of the method.  If you need to return
-something else then you can specify an "onerror" keyword after the
-prototype and after that a number, a token (an identifier) or a bit of C
-code enclosed in braces {}.  The braces will not be printed into the
-output, they just delimit the string.  For example:
+returned if there is an error, such as if a precondition is not met.
+The default is 0, casted to the type of the method.  If you need to
+return something else then you can specify an "onerror" keyword after
+the prototype and any optional function attribute macros, and after
+that a number, a token (an identifier) or a bit of C code enclosed in
+braces {}.  The braces will not be printed into the output, they just
+delimit the string.  For example:
 .nf
 
   public void * get_something (self, int i (check >= 0)) onerror NULL {
diff --git a/src/checks.c b/src/checks.c
index cccdedb..c651e9a 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -479,6 +479,30 @@ check_func_arg_checks(Class *c)
 }
 
 void
+check_func_attrs(Class *c)
+{
+  GList *li;
+  for (li = c->nodes; li != NULL; li = li->next) {
+    Node *n = li->data;
+    if (n->type == METHOD_NODE) {
+      Method *m = (Method *)n;
+      if ((m->method == INIT_METHOD ||
+	   m->method == CLASS_INIT_METHOD)
+	  && (m->funcattrs != NULL && strlen(m->funcattrs) != 0)) {
+	/* This is actually dead code at the moment, since the parser
+	   doesn't accept attributes to the init or class_init
+	   syntactic forms anyway.  But it could easily be made to do
+	   so, and also for virtual override and signal methods, and
+	   then we could give kinder error messages here.  */
+	error_print (GOB_ERROR, m->line_no,
+		     "function attributes (G_GNUC_PRINTF, etc.) aren't "
+                     "supported for the init or class_init methods");
+      }
+    }
+  }
+}
+
+void
 check_for_class_destructors (Class *c)
 {
 	GList *li;
diff --git a/src/checks.h b/src/checks.h
index 88dd8d1..870ce05 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -36,6 +36,7 @@ void		check_signal_args		(Class *c);
 void		check_argument_types		(Class *c);
 void		check_property_types		(Class *c);
 void		check_func_arg_checks		(Class *c);
+void            check_func_attrs                (Class *c);
 void		check_for_class_destructors	(Class *c);
 
 int		count_signals			(Class *c);
diff --git a/src/lexer.l b/src/lexer.l
index b3b2d59..72a849a 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -567,6 +567,12 @@ flags		{ return FLAGS; }
 				REJECT;
 			}
 		}
+
+<CLASS_CODE_I>G_GNUC_PRINTF|G_GNUC_SCANF|G_GNUC_FORMAT {
+                        yylval.id = g_strdup(yytext);
+                        return FUNCATTR;
+}
+
 <CLASS_CODE,CLASS_CODE_I,PROPERTY_CODE,PROPERTY_CODE_I,INITIAL>[A-Za-z_][A-Za-z0-9_]*(:[A-Za-z_][A-Za-z0-9_]*)+	{
 			/* this one is for a classname with a namespace */
 			yylval.id = g_strdup(yytext);
diff --git a/src/main.c b/src/main.c
index e1cfe4b..7874014 100644
--- a/src/main.c
+++ b/src/main.c
@@ -199,6 +199,7 @@ print_method (FILE *fp,
 	      const char *afterargs,
 	      const char *postfix,
 	      const Method *m,
+	      gboolean print_funcattrs,
 	      gboolean one_arg_per_line,
 	      gboolean no_funcbase,
 	      gboolean kill_underscore,
@@ -254,7 +255,28 @@ print_method (FILE *fp,
 	} else {
 		out_printf(fp, "void"); 
 	}
-	out_printf(fp, "%s)%s", afterargs, postfix); 
+	/* Slightly icky: sometimes we are called st m->funcattrs
+	   hasn't been set, but if so it should be NULL since its been
+	   zero-initialized.  */
+	if(print_funcattrs && m->funcattrs != NULL
+	   && strlen(m->funcattrs) > 0) {
+	        /* To keep the output neat, we trim off the trailing '\n'
+	           from the end of funcattrs for a moment.  */
+	        size_t funcattrs_len = strlen(m->funcattrs);
+                gboolean funcattrs_chomped = FALSE;
+	        if((m->funcattrs)[funcattrs_len - 1] == '\n') {
+	                m->funcattrs[funcattrs_len - 1] = '\0';
+                        funcattrs_chomped = TRUE;
+		} 
+	        out_printf(fp, "%s)\n%s%s", afterargs, m->funcattrs, postfix);
+                /* Put it back like it was (though it shouldn't matter).  */
+		if (funcattrs_chomped) {
+		        (m->funcattrs)[funcattrs_len - 1] = '\n';
+		}
+	}
+	else {
+	        out_printf(fp, "%s)%s", afterargs, postfix); 
+	}
 }
 
 static gboolean
@@ -371,11 +393,12 @@ put_vs_method(const Method *m)
 
 	/* if a signal mark it as such */
 	if(m->method != VIRTUAL_METHOD)
-		print_method(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
-			     m, FALSE, TRUE, TRUE, FALSE, FALSE);
+	        print_method(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
+			     m, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE);
 	else
-		print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
-			     m, FALSE, TRUE, TRUE, FALSE, FALSE);
+	        print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
+			     m, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE);
+
 }
 
 static void
@@ -385,7 +408,7 @@ put_pub_method(const Method *m)
 		return;
 
 	print_method(outh, "", "\t", "", "\t", "", ";\n", m,
-		     TRUE, FALSE, TRUE, FALSE, FALSE);
+		     TRUE, TRUE, FALSE, TRUE, FALSE, FALSE);
 }
 
 static void
@@ -423,7 +446,7 @@ put_signal_macro (const Method *m, gboolean gnu)
 			    "(GCallback) __extension__ ({",
 			    funcbase, m->id, macrobase, typebase, m->id);
 		print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-			      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+			      " = (func); ", m, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE);
 		out_printf (outh, "___%s; }), (data))\n", m->id);
 
 		/* connect_after */
@@ -434,7 +457,7 @@ put_signal_macro (const Method *m, gboolean gnu)
 			    "(GCallback) __extension__ ({",
 			    funcbase, m->id, macrobase, typebase, m->id);
 		print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-			      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+			      " = (func); ", m, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE);
 		out_printf (outh, "___%s; }), (data))\n", m->id);
 
 		/* connect_data */
@@ -446,7 +469,7 @@ put_signal_macro (const Method *m, gboolean gnu)
 			    "(GCallback) __extension__ ({",
 			    funcbase, m->id, macrobase, typebase, m->id);
 		print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-			      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+			      " = (func); ", m, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE);
 		out_printf (outh, "___%s; }), (data), (destroy_data), (GConnectFlags)(flags))\n", m->id);
 	}
 }
@@ -513,10 +536,10 @@ put_prot_method(const Method *m)
 
 	if(outph)
 		print_method(outph, "", "\t", "", "\t", "", ";\n",
-			     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+			     m, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE);
 	else
 		print_method(out, "", "\t", "", "\t", "", ";\n",
-			     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+			     m, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE);
 }
 
 static void
@@ -528,7 +551,7 @@ put_priv_method_prot(const Method *m)
 		if(m->cbuf)
 			print_method(out,
 				     "static ", "___real_", "", " ", "", ";\n",
-				     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
 	}
 	/* no else, here, it might still have a private prototype, it's not
 	 * exclusive */
@@ -539,14 +562,21 @@ put_priv_method_prot(const Method *m)
 		char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
 		print_method(out, "static ", s, "", " ", "",
 			     no_gnu?";\n":" G_GNUC_UNUSED;\n",
-			     m, FALSE, FALSE, FALSE, FALSE, FALSE);
+			     m, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE);
 		g_free(s);
 	} else if(m->scope == PRIVATE_SCOPE ||
 		  m->method == INIT_METHOD ||
 		  m->method == CLASS_INIT_METHOD) {
+	           /* The parser and check_* code is currently set up to
+	              reject attributes to init and class_init methods.  So we
+	              shouldn't see any.  */
+	        if(m->method == INIT_METHOD ||
+                   m->method == CLASS_INIT_METHOD) {
+		  g_assert (m->funcattrs == NULL || strlen(m->funcattrs) == 0);
+	        }
 		print_method(out, "static ", "", "", " ", "",
 			     no_gnu?";\n":" G_GNUC_UNUSED;\n",
-			     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+			     m, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE);
 	}
 }
 
@@ -2033,10 +2063,12 @@ print_initializer(Method *m, Variable *v)
 	if (v->initializer_simple)
 		out_printf(out, "\t%s->%s = %s;\n",
 		   root, v->id, v->initializer);
-	else if (!strcmp(v->id, "_glade_xml"))
+	else if (strcmp(v->id, "_glade_xml") == 0)
+		/* This is OK, this v->initializer string is set internally
+		   and it will eat exactly one string! */
 		out_printf(out,v->initializer, ((FuncArg *)m->args->data)->name);
 	else
-		out_printf(out,v->initializer);
+		out_printf(out, "%s", v->initializer);
 
 	if(v->initializer_line > 0)
 		out_addline_outfile(out);
@@ -2275,7 +2307,8 @@ add_inits(Class *c)
 			if(m->line_no > 0)
 				out_addline_infile(out, m->line_no);
 			print_method(out, "static ", "\n", "", " ", "", "\n",
-				     m, FALSE, FALSE, TRUE, TRUE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, TRUE,
+				     FALSE);
 			if(m->line_no > 0)
 				out_addline_outfile(out);
 			out_printf(out, "{\n"
@@ -2324,7 +2357,8 @@ add_inits(Class *c)
 			if(m->line_no > 0)
 				out_addline_infile(out, m->line_no);
 			print_method(out, "static ", "\n", "", " ", "", "\n",
-				     m, FALSE, FALSE, TRUE, TRUE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, TRUE,
+				     FALSE);
 			if(m->line_no > 0)
 				out_addline_outfile(out);
 			out_printf(out, "{\n"
@@ -2832,10 +2866,10 @@ put_method(Method *m)
 			out_addline_infile(out, m->line_no);
 		if(m->scope == PRIVATE_SCOPE)
 			print_method(out, "static ", "\n", "", " ", "", "\n",
-				     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
 		else /* PUBLIC, PROTECTED */
 			print_method(out, "", "\n", "", " ", "", "\n",
-				     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
 		print_method_body(m, TRUE, TRUE);
 		/* the outfile line was added above */
 		break;
@@ -2845,10 +2879,10 @@ put_method(Method *m)
 			out_addline_infile(out, m->line_no);
 		if(m->scope == PRIVATE_SCOPE)
 			print_method(out, "static ", "\n", "", " ", "", "\n",
-				     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
 		else /* PUBLIC, PROTECTED */
 			print_method(out, "", "\n", "", " ", "", "\n",
-				     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
 		out_addline_outfile (out);
 
 		out_printf (out, "{\n");
@@ -2967,7 +3001,7 @@ put_method(Method *m)
 		if(m->line_no > 0)
 			out_addline_infile(out, m->line_no);
 		print_method(out, "static ", "\n___real_", "", " ", "", "\n",
-			     m, FALSE, FALSE, TRUE, TRUE, FALSE);
+			     m, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE);
 		print_method_body(m, FALSE, TRUE);
 		/* the outfile line was added above */
 		break;
@@ -2976,10 +3010,10 @@ put_method(Method *m)
 			out_addline_infile(out, m->line_no);
 		if(m->scope==PRIVATE_SCOPE)
 			print_method(out, "static ", "\n", "", " ", "", "\n",
-				     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
 		else /* PUBLIC, PROTECTED */
 			print_method(out, "", "\n", "", " ", "", "\n",
-				     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+				     m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE);
 		out_addline_outfile(out);
 		out_printf(out, "{\n"
 			"\t%sClass *klass;\n", typebase);
@@ -3025,7 +3059,7 @@ put_method(Method *m)
 		if(m->line_no > 0)
 			out_addline_infile(out, m->line_no);
 		print_method(out, "static ", "\n___real_", "", " ", "", "\n",
-			     m, FALSE, FALSE, TRUE, TRUE, FALSE);
+			     m, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE);
 		print_method_body(m, FALSE, TRUE);
 		/* the outfile line was added above */
 		break;
@@ -3036,7 +3070,7 @@ put_method(Method *m)
 			out_addline_infile(out, m->line_no);
 		s = g_strdup_printf("\n___%x_", (guint)m->unique_id);
 		print_method(out, "static ", s, "", " ", "", "\n",
-			     m, FALSE, FALSE, FALSE, TRUE, FALSE);
+			     m, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE);
 		g_free(s);
 		out_addline_outfile(out);
 		s = replace_sep(m->otype, '_');
@@ -4462,6 +4496,7 @@ main(int argc, char *argv[])
 	check_property_types ((Class *)class);
 	check_argument_types ((Class *)class);
 	check_func_arg_checks ((Class *)class);
+	check_func_attrs ((Class *)class);
 	check_for_class_destructors ((Class *)class);
 
 	exit_on_error = TRUE;
diff --git a/src/parse.y b/src/parse.y
index 53d32eb..55e71ff 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -65,6 +65,52 @@ static char *initializer = NULL;
 static int initializer_line = 0;
 static int glade_widget = FALSE;
 
+static GString *funcattrs = NULL;
+static GString *attrargs = NULL;
+
+static void
+clear_funcattrs(void)
+{
+	if(!funcattrs) {
+		funcattrs = g_string_new("");
+	} else {
+		funcattrs = g_string_assign(funcattrs, "");
+	}
+}
+
+static void
+add_to_funcattrs(char *s, ...) G_GNUC_PRINTF (1, 2);
+
+static void
+add_to_funcattrs(char *s, ...)
+{
+  va_list ap;
+  va_start(ap, s);
+  gchar *tmp = g_strdup_vprintf (s, ap);
+  va_end(ap);
+		 
+  if(!funcattrs)
+    funcattrs = g_string_new("");
+
+  funcattrs = g_string_append (funcattrs,tmp);
+
+  g_free(tmp);
+}
+
+static gboolean
+funcattrs_defined (void)
+{
+  return (funcattrs != NULL && funcattrs->len > 0);
+}
+
+/* Return a new string containing a copy of the contents of funcattrs,
+   but with leading and trailing whitespace removed.  */
+static gchar *
+funcattrs_strstripped (void)
+{
+  return g_strstrip (g_strdup (funcattrs->str));
+}
+
 static char *onerror = NULL;
 static char *defreturn = NULL;
 
@@ -196,6 +242,9 @@ push_function (int scope, int method, char *oid, char *id,
 	} else
 		c_cbuf = NULL;
 
+	if(funcattrs == NULL)
+	        funcattrs = g_string_new("");
+
 	node = node_new (METHOD_NODE,
 			 "scope", scope,
 			 "method", method,
@@ -205,6 +254,7 @@ push_function (int scope, int method, char *oid, char *id,
 			 "flags:steal", flags,
 			 "id:steal", id,
 			 "args:steal", funcargs,
+			 "funcattrs", funcattrs->str,
 			 "onerror:steal", onerror,
 			 "defreturn:steal", defreturn,
 			 "cbuf:steal", c_cbuf,
@@ -216,6 +266,8 @@ push_function (int scope, int method, char *oid, char *id,
 
 	last_added_method = (Method *)node;
 
+	clear_funcattrs ();
+
 	if(cbuf)
 		g_string_free(cbuf,
 			      /*only free segment if we haven't passed it
@@ -233,6 +285,9 @@ push_function (int scope, int method, char *oid, char *id,
 static void
 free_all_global_state(void)
 {
+        if(funcattrs != NULL)
+                g_string_free(funcattrs, TRUE);
+
 	g_free(onerror);
 	onerror = NULL;
 	g_free(defreturn);
@@ -473,7 +528,6 @@ add_construct_glade (char * file, char * root, char * domain)
 {
 	Node *var;
 	Type * type;
-	GList * flags = NULL;
 	
 	type = (Type *)node_new (TYPE_NODE,
 				 "name", "GladeXML",
@@ -678,7 +732,7 @@ ensure_property (void)
 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
 
 %token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM SINGLE_CHAR
-%token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE STRING
+%token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE STRING FUNCATTR
 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE PROPERTY ARGUMENT
 %token <line> VIRTUAL SIGNAL OVERRIDE
 %token <line> NICK BLURB MAXIMUM MINIMUM DEFAULT_VALUE ERROR FLAGS TYPE
@@ -1665,7 +1719,7 @@ codenocode:	'{' CCODE			{ $<cbuf>$ = $<cbuf>2; }
 	;
 
 /*here CCODE will include the ending '}' */
-method:		SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+method:		SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' methodmods codenocode {
 			if(!has_self) {
 				yyerror(_("signal without 'self' as "
 					  "first parameter"));
@@ -1677,11 +1731,19 @@ method:		SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenoc
 				free_all_global_state();
 				YYERROR;
 			}
+	                if(funcattrs_defined()) {
+	                        GString *errmsg = g_string_new("");
+	                        g_string_append_printf(errmsg, "function attribute macros ('%s' in this case) may not be used with signal methods",
+							funcattrs_strstripped()
+						       );
+	                        yyerror(_(errmsg->str));
+		                YYERROR;
+		        }
 			push_function(the_scope, $<sigtype>3,NULL,
 				      $<id>5, $<cbuf>10,$<line>1,
 				      ccode_line, vararg, $<list>2);
 									}
-	|	scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+	|	scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' methodmods codenocode {
 			if(!has_self) {
 				yyerror(_("signal without 'self' as "
 					  "first parameter"));
@@ -1693,11 +1755,19 @@ method:		SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenoc
 				free_all_global_state();
 				YYERROR;
 			}
+	                if(funcattrs_defined()) {
+	                        GString *errmsg = g_string_new("");
+	                        g_string_append_printf(errmsg, "function attribute macros ('%s' in this case) may not be used with signal methods",
+							funcattrs_strstripped()
+						       );
+	                        yyerror(_(errmsg->str));
+		                YYERROR;
+		        }
 			push_function(the_scope, $<sigtype>4, NULL,
 				      $<id>6, $<cbuf>11, $<line>2,
 				      ccode_line, vararg, $<list>3);
 									}
-	|	VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode	{
+	|	VIRTUAL scope type TOKEN '(' funcargs ')' methodmods codenocode	{
 			if(!has_self) {
 				yyerror(_("virtual method without 'self' as "
 					  "first parameter"));
@@ -1709,11 +1779,19 @@ method:		SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenoc
 				free_all_global_state();
 				YYERROR;
 			}
+	                if(funcattrs_defined()) {
+	                        GString *errmsg = g_string_new("");
+	                        g_string_append_printf(errmsg, "function attribute macros ('%s' in this case) may not be used with virtual methods",
+							funcattrs_strstripped()
+						       );
+	                        yyerror(_(errmsg->str));
+		                YYERROR;
+		        }
 			push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
 				      $<cbuf>9, $<line>1,
 				      ccode_line, vararg, NULL);
 									}
-	|	scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode	{
+	|	scope VIRTUAL type TOKEN '(' funcargs ')' methodmods codenocode	{
 			if(!has_self) {
 				yyerror(_("virtual method without 'self' as "
 					  "first parameter"));
@@ -1725,28 +1803,52 @@ method:		SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenoc
 				free_all_global_state();
 				YYERROR;
 			}
+	                if(funcattrs_defined()) {
+	                        GString *errmsg = g_string_new("");
+	                        g_string_append_printf(errmsg, "function attribute macros ('%s' in this case) may not be used with virtual methods",
+							funcattrs_strstripped()
+						       );
+	                        yyerror(_(errmsg->str));
+		                YYERROR;
+		        }
 			push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
 				      $<cbuf>9, $<line>2,
 				      ccode_line, vararg, NULL);
 									}
-	|	VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode	{
+	|	VIRTUAL type TOKEN '(' funcargs ')' methodmods codenocode	{
 			if(!has_self) {
-				yyerror(_("virtual method without 'self' as "
+				yyerror(_("virtual method without 'szelf' as "
 					  "first parameter"));
 				free_all_global_state();
 				YYERROR;
 			}
+	                if(funcattrs_defined()) {
+	                        GString *errmsg = g_string_new("");
+	                        g_string_append_printf(errmsg, "function attribute macros ('%s' in this case) may not be used with virtual methods",
+							funcattrs_strstripped()
+						       );
+	                        yyerror(_(errmsg->str));
+		                YYERROR;
+		        }
 			push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
 				      $<id>3, $<cbuf>8, $<line>1,
 				      ccode_line, vararg, NULL);
 									}
-	|	OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode	{
+	|	OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' methodmods codenocode	{
+	                if(funcattrs_defined()) {
+	                        GString *errmsg = g_string_new("");
+	                        g_string_append_printf(errmsg, "function attribute macros ('%s' in this case) may not be used with override methods",
+							funcattrs_strstripped()
+						       );
+	                        yyerror(_(errmsg->str));
+		                YYERROR;
+		        }
 			push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
 				      $<id>6, $<cbuf>11,
 				      $<line>1, ccode_line,
 				      vararg, NULL);
 									}
-	|	scope type TOKEN '(' funcargs ')' returnvals codenocode	{
+	|	scope type TOKEN '(' funcargs ')' methodmods codenocode	{
 			if(the_scope == CLASS_SCOPE) {
 				yyerror(_("a method cannot be of class scope"));
 				free_all_global_state();
@@ -1756,13 +1858,35 @@ method:		SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenoc
 				      $<cbuf>8, $<line>1, ccode_line,
 				      vararg, NULL);
 								}
+             /* It would be nice to include methodmods before
+	        codenocode here, the do error checking to make sure no
+	        function attributes or return values had been added.
+	        But I'm not certain when its safe to NULLify onerror
+	        and defreturn.  So we just settle for the generic
+	        parse error.  */
 	|	TOKEN '(' TOKEN ')' codenocode	{
 			if(strcmp($<id>1, "init")==0) {
+			        if(funcattrs_defined()) {
+			                GString *errmsg = g_string_new("");
+					g_string_append_printf(errmsg, "function attribute macros ('%s' in this case) may no be used with the init method",
+								funcattrs_strstripped()
+							       );
+					yyerror(_(errmsg->str));
+					YYERROR;
+				}
 				push_init_arg($<id>3,FALSE);
 				push_function(NO_SCOPE, INIT_METHOD, NULL,
 					      $<id>1, $<cbuf>5, $<line>2,
 					      ccode_line, FALSE, NULL);
 			} else if(strcmp($<id>1, "class_init")==0) {
+			        if(funcattrs_defined()) {
+			                GString *errmsg = g_string_new("");
+					g_string_append_printf(errmsg, "function attribute macros ('%s' in this case) may no be used with the class_init method",
+								funcattrs_strstripped()
+							       );
+					yyerror(_(errmsg->str));
+					YYERROR;
+				}
 				push_init_arg($<id>3,TRUE);
 				push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
 					      $<id>1, $<cbuf>5, $<line>2,
@@ -1779,7 +1903,53 @@ method:		SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenoc
 						}
 	;
 
-returnvals:	TOKEN retcode		{
+methodmods:     funcattrlist { ; }
+              | returnvals_spec  { ; }
+              | funcattrlist returnvals_spec  { ; }
+              | { 
+		         g_free(onerror); onerror = NULL;
+		         g_free(defreturn); defreturn = NULL;
+	        }
+        ; 
+funcattrlist:   funcattrlist funcattr  { ; }
+             |  funcattr             { ; }
+        ;
+
+funcattr:       FUNCATTR '(' attrarglist ')' {
+                         g_assert(attrargs != NULL);
+                         add_to_funcattrs("\t%s (%s)\n", $<id>1,
+                                          attrargs->str);
+                         g_string_free(attrargs, TRUE);
+			 attrargs = NULL;
+                }
+              | FUNCATTR { 
+	                 add_to_funcattrs("\t%s\n", $<id>1);
+                }
+	;
+
+attrarglist:    attrarglist  ',' NUMBER  {
+                         g_assert(attrargs != NULL); 
+                         g_string_append_printf(attrargs, ", %s", $<id>3);
+                }
+              | NUMBER {
+                         if(attrargs == NULL)
+                                 attrargs = g_string_new($<id>1);
+                         else 
+                                 attrargs = g_string_append(attrargs, $<id>1);
+                }
+        ;
+
+			/* This isn't needed anymore.
+			 *
+			 *returnvals:      returnvals_spec
+			 *               | {
+			 *		         g_free(onerror); onerror = NULL;
+			 *		         g_free(defreturn); defreturn = NULL;
+			 *                 }
+			 *        ;
+			 */
+
+returnvals_spec:	TOKEN retcode		{
 			g_free(onerror); onerror = NULL;
 			g_free(defreturn); defreturn = NULL;
 			if(!set_return_value($<id>1, $<id>2)) {
@@ -1809,10 +1979,6 @@ returnvals:	TOKEN retcode		{
 			g_free($<id>1);
 			g_free($<id>3);
 						}
-	|				{
-			g_free(onerror); onerror = NULL;
-			g_free(defreturn); defreturn = NULL;
-					}
 	;
 
 retcode:	numtok			{ $<id>$ = $<id>1; }
diff --git a/src/test.gob b/src/test.gob
index 3de497c..435bccd 100644
--- a/src/test.gob
+++ b/src/test.gob
@@ -241,7 +241,7 @@ class Test:Object from /*G:Object*/ Gtk:Container
 	public int wagawaga_should_be_after_this_in_the_header;
 
 	init(object) {
-		object->i=0;
+	        object->i=0;
 	}
 	class_init(klass);
 
@@ -418,6 +418,58 @@ class Test:Object from /*G:Object*/ Gtk:Container
 		i = 0;
 		return 25;
 	}
+	public gchar *funcattrtest(self, const char *format (check null), ...)
+	        G_GNUC_PRINTF (2, 3)
+	{
+	        gchar *result;
+
+	        va_list ap;
+	        va_start(ap, format);
+	        result = g_strdup_vprintf (format, ap);
+	        va_end(ap);
+	        return result;
+	}
+	private gchar *funcattrtest2(self, const char *format, ...)
+	        G_GNUC_SCANF(2,3)
+	{
+	        gchar *nonsense = NULL;
+	        format = format;
+                return nonsense;
+	}
+        protected gchar *funcattrtest3(self, const char *format)
+	        G_GNUC_FORMAT (2)
+        {
+	        gchar *nonsense = NULL;
+	        format = format;
+                return nonsense;	        
+	}
+	private char *funcattrtest4(self, const char *format, ...)
+	        G_GNUC_PRINTF(2,3)
+                onerror NULL
+	{
+	        gchar *nonsense = NULL;
+	        format = format;
+                return nonsense;	        
+	}
+	protected char * funcattrtest5(self, const char *format, ...)
+	        G_GNUC_PRINTF(2,3)	        
+	        onerror NULL
+	{
+	        gchar *nonsense = NULL;
+	        format = format;
+                return nonsense;	        
+	}
+	public char * funcattrtest6(self, const char *format, ...)
+	        G_GNUC_PRINTF(2,3)
+                onerror NULL 
+        {
+	        gchar *nonsense = NULL;
+	        format = format;
+                return nonsense;	        
+	}
+	// Note that the parser should accept defreturn with function
+	// attributes as well, but this may not be a good thing since
+	// it probably doesn't make sense, so we don't test it.
 	signal private first NONE (NONE)
 	void googlegoogle(self)
 	{
diff --git a/src/treefuncs.c b/src/treefuncs.c
index c385bc8..ac2fd01 100644
--- a/src/treefuncs.c
+++ b/src/treefuncs.c
@@ -158,6 +158,8 @@ enum {
 	QUARK_id_STEAL,
 	QUARK_args,
 	QUARK_args_STEAL,
+	QUARK_funcattrs,
+	QUARK_funcattrs_STEAL,
 	QUARK_onerror,
 	QUARK_onerror_STEAL,
 	QUARK_defreturn,
@@ -266,6 +268,8 @@ ensure_quarks (void)
 	g_hash_table_insert (quark_ht, "id:steal", GINT_TO_POINTER (QUARK_id_STEAL));
 	g_hash_table_insert (quark_ht, "args", GINT_TO_POINTER (QUARK_args));
 	g_hash_table_insert (quark_ht, "args:steal", GINT_TO_POINTER (QUARK_args_STEAL));
+	g_hash_table_insert (quark_ht, "funcattrs", GINT_TO_POINTER (QUARK_funcattrs));
+	g_hash_table_insert (quark_ht, "funcattrs:steal", GINT_TO_POINTER (QUARK_funcattrs_STEAL));
 	g_hash_table_insert (quark_ht, "onerror", GINT_TO_POINTER (QUARK_onerror));
 	g_hash_table_insert (quark_ht, "onerror:steal", GINT_TO_POINTER (QUARK_onerror_STEAL));
 	g_hash_table_insert (quark_ht, "defreturn", GINT_TO_POINTER (QUARK_defreturn));
@@ -451,6 +455,7 @@ copy_method (Method * self)
 	new->flags = g_list_copy (self->flags); COPY_LIST_VALS(new->flags, g_strdup);
 	new->id = g_strdup (self->id);
 	new->args = node_list_copy (self->args);
+	new->funcattrs = g_strdup (self->funcattrs);
 	new->onerror = g_strdup (self->onerror);
 	new->defreturn = g_strdup (self->defreturn);
 	new->cbuf = g_strdup (self->cbuf);
@@ -640,6 +645,7 @@ free_method (Method * self)
 	g_list_foreach (self->flags, (GFunc)g_free, NULL); g_list_free (self->flags);
 	g_free (self->id);
 	node_list_free (self->args);
+	g_free (self->funcattrs);
 	g_free (self->onerror);
 	g_free (self->defreturn);
 	g_free (self->cbuf);
@@ -1301,6 +1307,18 @@ setv_method (Method * self, va_list __ap)
 			self->args = args;
 			break;
 		}
+		case QUARK_funcattrs: {
+			char * funcattrs = va_arg (__ap, char *);
+			char * __old_value = self->funcattrs;
+			self->funcattrs = g_strdup (funcattrs);
+			g_free (__old_value);
+			break;
+		}
+		case QUARK_funcattrs_STEAL: {
+			char * funcattrs = va_arg (__ap, char *);
+			self->funcattrs = funcattrs;
+			break;
+		}
 		case QUARK_onerror: {
 			char * onerror = va_arg (__ap, char *);
 			char * __old_value = self->onerror;
diff --git a/src/treefuncs.def b/src/treefuncs.def
index 0c092c1..7f2845a 100644
--- a/src/treefuncs.def
+++ b/src/treefuncs.def
@@ -124,6 +124,7 @@ CLASS Method
   STRINGLIST	flags		# G_SIGNAL_* flags for a signal
   STRING	id
   NODELIST	args
+  STRING        funcattrs       # GLib function attribute macros
   STRING	onerror
   STRING	defreturn
   STRING	cbuf
diff --git a/src/treefuncs.h b/src/treefuncs.h
index b21c241..bf18b34 100644
--- a/src/treefuncs.h
+++ b/src/treefuncs.h
@@ -165,6 +165,7 @@ struct _Method {
 	GList * flags;
 	char * id;
 	GList * args;
+	char * funcattrs;
 	char * onerror;
 	char * defreturn;
 	char * cbuf;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]