[gob] Git is STUPID!
- From: George Lebl <jirka src gnome org>
- To: svn-commits-list gnome org
- Subject: [gob] Git is STUPID!
- Date: Fri, 10 Jul 2009 15:23:20 +0000 (UTC)
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]