patch allowing to add GCC attributes to methods

View: New views
3 Messages — Rating Filter:   Alert me  

patch allowing to add GCC attributes to methods

by Jean-Yves Lefort :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The attached patch allows to add GCC attributes to methods, using a
syntax borrowed from C#. For instance:

        [G_GNUC_PRINTF(1, 2)]
        private void say_something (const char *format, ...)
        {
        }

The text enclosed in brackets is not parsed (the lexer returns a CCODE
token). It is inserted verbatim in the function declaration, before
the trailing semicolon.

With this patch, gob no longer unconditionally adds G_GNUC_UNUSED to
methods, which is a bad idea since it might hide programming
errors. Users should now specify it manually when needed.

Attributes are not supported for overriden methods since these methods
are not meant to be called directly. For signals and virtual methods,
the attributes are added to the declaration of the invocation wrapper,
but not to the "__real" default implementation method that gob emits.

Two patches are provided:

        gob2-2.0.15-attr.diff

                The attributes feature alone.

        gob2-2.0.15-gobject-overrides-and-attr.diff

                The attributes feature and another feature I've
                implemented previously (see the message with subject
                "patch adding first-class support of
                constructor/dispose/finalize methods"). This unified
                patch is provided because the two individual patches
                conflict with each other and require merging.

--
Jean-Yves Lefort <jylefort@...>

[gob2-2.0.15-attr.diff]

--- src/lexer.l.orig 2007-09-28 06:26:49.000000000 +0200
+++ src/lexer.l 2008-01-28 16:04:28.000000000 +0100
@@ -31,6 +31,7 @@
 #include "main.h"
 #include "util.h"
 
+static int bracket_depth = 0;
 static int parenth_depth = 0;
 static int before_comment
 /* New flex is on drugs */
@@ -102,6 +103,7 @@
 
 %x COMMENT
 %x C_CODE
+%x ATTR_CODE
 %x CODE_STRING
 %x CLASS_CODE
 %x CLASS_STRING
@@ -267,7 +269,7 @@
  add_to_cbuf(yytext);
  }
 
-<C_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
+<C_CODE,ATTR_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
 <CLASS_CODE>\/\/.*$ { ; /*comment, ignore*/ }
 <CLASS_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
 <PROPERTY_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
@@ -277,20 +279,25 @@
  BEGIN(COMMENT);
  before_comment = C_CODE;
 }
+<ATTR_CODE>\/\* {
+ add_to_cbuf(yytext);
+ BEGIN(COMMENT);
+ before_comment = ATTR_CODE;
+}
 <CLASS_CODE>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE; }
 <CLASS_CODE_I>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE_I; }
 <PROPERTY_CODE_I>\/\* {BEGIN(COMMENT); before_comment = PROPERTY_CODE_I; }
 <COMMENT>\*\/ {
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  BEGIN(before_comment);
  }
 <COMMENT>. {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 <COMMENT>\n {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 
 ^\%(a|all)\{ {
@@ -353,14 +360,14 @@
  return code_type;
  }
 
-<C_CODE>\'\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\"\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\"\' { add_to_cbuf(yytext); }
 
-<C_CODE>\\. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\\. { add_to_cbuf(yytext); }
 
 
 <C_CODE>\" {
@@ -368,6 +375,11 @@
  before_string = C_CODE;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\" {
+ BEGIN(CODE_STRING);
+ before_string = ATTR_CODE;
+ add_to_cbuf(yytext);
+ }
 <PROPERTY_CODE_I>\" {
  BEGIN(CODE_STRING);
  before_string = PROPERTY_CODE_I;
@@ -391,6 +403,10 @@
  parenth_depth++;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\[ {
+ bracket_depth++;
+ add_to_cbuf(yytext);
+ }
 <C_CODE>\} {
  parenth_depth--;
  if(parenth_depth<0) {
@@ -403,9 +419,21 @@
  }
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\] {
+ bracket_depth--;
+ if(bracket_depth<0) {
+ REJECT;
+ } else if(bracket_depth==0) {
+ BEGIN(CLASS_CODE_I);
+ yylval.cbuf = cbuf;
+ cbuf = NULL;
+ return CCODE;
+ }
+ add_to_cbuf(yytext);
+ }
 
-<C_CODE>. { add_to_cbuf(yytext); }
-<C_CODE>\n { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\n { add_to_cbuf(yytext); }
 
 class {
  static int found_classes = 0;
@@ -612,6 +640,13 @@
  BEGIN(INITIAL);
  return '}';
  }
+<CLASS_CODE_I>\[ {
+ BEGIN(ATTR_CODE);
+ bracket_depth=1;
+ yylval.line = line_no;
+ clear_cbuf();
+ return '[';
+ }
 
 <CLASS_CODE,CLASS_CODE_I,INITIAL,PROPERTY_CODE,PROPERTY_CODE_I>[\f\t ] ;  /*ignore*/
 
--- src/main.c.orig 2007-10-17 16:49:04.000000000 +0200
+++ src/main.c 2008-01-28 17:01:49.000000000 +0100
@@ -189,21 +189,25 @@
  g_free(s);
 }
 
-
-static void
-print_method (FILE *fp,
-      const char *typeprefix,
-      const char *nameprefix,
-      const char *subnameprefix,
-      const char *namepostfix,
-      const char *afterargs,
-      const char *postfix,
-      const Method *m,
-      gboolean one_arg_per_line,
-      gboolean no_funcbase,
-      gboolean kill_underscore,
-      gboolean first_unused,
-      gboolean fake_names)
+typedef enum
+{
+  PRINT_METHOD_ONE_ARG_PER_LINE = 1 << 0,
+  PRINT_METHOD_NO_FUNCBASE = 1 << 1,
+  PRINT_METHOD_FIRST_UNUSED = 1 << 2,
+  PRINT_METHOD_FAKE_NAMES = 1 << 3,
+  PRINT_METHOD_NO_ATTR = 1 << 4
+} PrintMethodFlags;
+
+static void
+print_method2 (FILE *fp,
+       const char *typeprefix,
+       const char *nameprefix,
+       const char *subnameprefix,
+       const char *namepostfix,
+       const char *afterargs,
+       const char *postfix,
+       const Method *m,
+       PrintMethodFlags flags)
 {
  GList *li;
  const char *id;
@@ -213,7 +217,7 @@
 
  id = m->id;
 
- if(no_funcbase)
+ if ((flags & PRINT_METHOD_NO_FUNCBASE) != 0)
  out_printf(fp, "%s%s%s%s(",
    nameprefix, subnameprefix, id, namepostfix);
  else
@@ -229,19 +233,19 @@
  if ( ! no_gnu &&
      ! for_cpp && /* g++ has a cow with this */
     li == m->args &&
-    first_unused) {
+     (flags & PRINT_METHOD_FIRST_UNUSED) != 0) {
  unused = " G_GNUC_UNUSED";
  }
 
  print_type(fp, arg->atype, FALSE);
- if (fake_names)
+ if ((flags & PRINT_METHOD_FAKE_NAMES) != 0)
  out_printf (fp, "___fake___");
  if(li->next)
  out_printf(fp, "%s%s%s,%s", arg->name,
    arg->atype->postfix ?
    arg->atype->postfix : "",
    unused,
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  else
  out_printf(fp, "%s%s%s", arg->name,
    arg->atype->postfix ?
@@ -250,11 +254,54 @@
  }
  if(m->vararg)
  out_printf(fp, ",%s...",
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  } else {
  out_printf(fp, "void");
  }
- out_printf(fp, "%s)%s", afterargs, postfix);
+
+ out_printf(fp, "%s)", afterargs);
+
+ if (m->attr && (flags & PRINT_METHOD_NO_ATTR) == 0)
+ out_printf(fp, " %s", m->attr);
+
+ out_printf(fp, "%s", postfix);
+}
+
+static void
+print_method (FILE *fp,
+      const char *typeprefix,
+      const char *nameprefix,
+      const char *subnameprefix,
+      const char *namepostfix,
+      const char *afterargs,
+      const char *postfix,
+      const Method *m,
+      gboolean one_arg_per_line,
+      gboolean no_funcbase,
+      gboolean kill_underscore,
+      gboolean first_unused,
+      gboolean fake_names)
+{
+ PrintMethodFlags flags = 0;
+
+ if (one_arg_per_line)
+ flags |= PRINT_METHOD_ONE_ARG_PER_LINE;
+ if (no_funcbase)
+ flags |= PRINT_METHOD_NO_FUNCBASE;
+ if (first_unused)
+ flags |= PRINT_METHOD_FIRST_UNUSED;
+ if (fake_names)
+ flags |= PRINT_METHOD_FAKE_NAMES;
+
+ print_method2(fp,
+      typeprefix,
+      nameprefix,
+      subnameprefix,
+      namepostfix,
+      afterargs,
+      postfix,
+      m,
+      flags);
 }
 
 static gboolean
@@ -371,11 +418,13 @@
 
  /* 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_method2(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
  else
- print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
-     m, FALSE, TRUE, TRUE, FALSE, FALSE);
+ print_method2(outh, "\t", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
 }
 
 static void
@@ -422,8 +471,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_after */
@@ -433,8 +485,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_data */
@@ -445,8 +500,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data), (destroy_data), (GConnectFlags)(flags))\n", m->id);
  }
 }
@@ -526,9 +584,9 @@
    m->method == SIGNAL_FIRST_METHOD ||
    m->method == VIRTUAL_METHOD) {
  if(m->cbuf)
- print_method(out,
-     "static ", "___real_", "", " ", "", ";\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out,
+      "static ", "___real_", "", " ", "", ";\n",
+      m, PRINT_METHOD_NO_ATTR);
  }
  /* no else, here, it might still have a private prototype, it's not
  * exclusive */
@@ -537,15 +595,13 @@
     m->cbuf)) {
  /* add unique ID */
  char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
- print_method(out, "static ", s, "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+ print_method(out, "static ", s, "", " ", "", ";\n",
      m, FALSE, FALSE, FALSE, FALSE, FALSE);
  g_free(s);
  } else if(m->scope == PRIVATE_SCOPE ||
   m->method == INIT_METHOD ||
   m->method == CLASS_INIT_METHOD) {
- print_method(out, "static ", "", "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+ print_method(out, "static ", "", "", " ", "", ";\n",
      m, FALSE, FALSE, TRUE, FALSE, FALSE);
  }
 }
@@ -2831,11 +2887,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, TRUE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2844,11 +2900,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile (out);
 
  out_printf (out, "{\n");
@@ -2966,8 +3022,8 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2975,11 +3031,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope==PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile(out);
  out_printf(out, "{\n"
  "\t%sClass *klass;\n", typebase);
@@ -3024,8 +3080,9 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_FIRST_UNUSED
+      | PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
--- src/parse.y.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/parse.y 2008-01-28 16:58:25.000000000 +0100
@@ -146,7 +146,7 @@
 
 static void
 push_function (int scope, int method, char *oid, char *id,
-       GString *cbuf, int line_no, int ccode_line,
+       GString *attr, GString *cbuf, int line_no, int ccode_line,
        gboolean vararg, GList *flags)
 {
  Node *node;
@@ -207,6 +207,7 @@
  "args:steal", funcargs,
  "onerror:steal", onerror,
  "defreturn:steal", defreturn,
+ "attr:steal", attr ? attr->str : NULL,
  "cbuf:steal", c_cbuf,
  "line_no", line_no,
  "ccode_line", ccode_line,
@@ -216,6 +217,8 @@
 
  last_added_method = (Method *)node;
 
+ if(attr)
+ g_string_free(attr, FALSE);
  if(cbuf)
  g_string_free(cbuf,
       /*only free segment if we haven't passed it
@@ -405,7 +408,7 @@
  push_funcarg ("self", FALSE);
 
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       get_id, get_cbuf, get_lineno,
+       get_id, NULL, get_cbuf, get_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -439,7 +442,7 @@
 
  typestack = g_list_prepend (typestack, node2);
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       set_id, set_cbuf, set_lineno,
+       set_id, NULL, set_cbuf, set_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -1678,9 +1681,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>3,NULL,
-      $<id>5, $<cbuf>10,$<line>1,
+      $<id>5, NULL, $<cbuf>10,$<line>1,
       ccode_line, vararg, $<list>2);
  }
+ | '[' CCODE SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>5,NULL,
+      $<id>7, $<cbuf>2, $<cbuf>12,$<line>3,
+      ccode_line, vararg, $<list>4);
+ }
  | scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("signal without 'self' as "
@@ -1694,9 +1713,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>4, NULL,
-      $<id>6, $<cbuf>11, $<line>2,
+      $<id>6, NULL, $<cbuf>11, $<line>2,
       ccode_line, vararg, $<list>3);
  }
+ | '[' CCODE scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>6, NULL,
+      $<id>8, $<cbuf>2, $<cbuf>13, $<line>4,
+      ccode_line, vararg, $<list>5);
+ }
  | VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("virtual method without 'self' as "
@@ -1710,7 +1745,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>1,
+      NULL, $<cbuf>9, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | '[' CCODE VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>6,
+      $<cbuf>2, $<cbuf>11, $<line>3,
       ccode_line, vararg, NULL);
  }
  | scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1726,7 +1777,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>2,
+      NULL, $<cbuf>9, $<line>2,
+      ccode_line, vararg, NULL);
+ }
+ | '[' CCODE scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>6,
+      $<cbuf>2, $<cbuf>11, $<line>4,
       ccode_line, vararg, NULL);
  }
  | VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1737,12 +1804,23 @@
  YYERROR;
  }
  push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
-      $<id>3, $<cbuf>8, $<line>1,
+      $<id>3, NULL, $<cbuf>8, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | '[' CCODE VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
+      $<id>5, $<cbuf>2, $<cbuf>10, $<line>3,
       ccode_line, vararg, NULL);
  }
  | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode {
  push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
-      $<id>6, $<cbuf>11,
+      $<id>6, NULL, $<cbuf>11,
       $<line>1, ccode_line,
       vararg, NULL);
  }
@@ -1753,19 +1831,29 @@
  YYERROR;
  }
  push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
-      $<cbuf>8, $<line>1, ccode_line,
+      NULL, $<cbuf>8, $<line>1, ccode_line,
+      vararg, NULL);
+ }
+ | '[' CCODE scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, REGULAR_METHOD, NULL, $<id>5,
+      $<cbuf>2, $<cbuf>10, $<line>3, ccode_line,
       vararg, NULL);
  }
  | TOKEN '(' TOKEN ')' codenocode {
  if(strcmp($<id>1, "init")==0) {
  push_init_arg($<id>3,FALSE);
  push_function(NO_SCOPE, INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else if(strcmp($<id>1, "class_init")==0) {
  push_init_arg($<id>3,TRUE);
  push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else {
  g_free($<id>1);
--- src/treefuncs.def.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/treefuncs.def 2008-01-28 16:16:21.000000000 +0100
@@ -126,6 +126,7 @@
   NODELIST args
   STRING onerror
   STRING defreturn
+  STRING attr
   STRING cbuf
   INT line_no
   INT ccode_line


[gob2-2.0.15-gobject-overrides-and-attr.diff]

--- src/lexer.l.orig 2007-09-28 06:26:49.000000000 +0200
+++ src/lexer.l 2008-01-28 17:15:53.000000000 +0100
@@ -31,6 +31,7 @@
 #include "main.h"
 #include "util.h"
 
+static int bracket_depth = 0;
 static int parenth_depth = 0;
 static int before_comment
 /* New flex is on drugs */
@@ -102,6 +103,7 @@
 
 %x COMMENT
 %x C_CODE
+%x ATTR_CODE
 %x CODE_STRING
 %x CLASS_CODE
 %x CLASS_STRING
@@ -267,7 +269,7 @@
  add_to_cbuf(yytext);
  }
 
-<C_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
+<C_CODE,ATTR_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
 <CLASS_CODE>\/\/.*$ { ; /*comment, ignore*/ }
 <CLASS_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
 <PROPERTY_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
@@ -277,20 +279,25 @@
  BEGIN(COMMENT);
  before_comment = C_CODE;
 }
+<ATTR_CODE>\/\* {
+ add_to_cbuf(yytext);
+ BEGIN(COMMENT);
+ before_comment = ATTR_CODE;
+}
 <CLASS_CODE>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE; }
 <CLASS_CODE_I>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE_I; }
 <PROPERTY_CODE_I>\/\* {BEGIN(COMMENT); before_comment = PROPERTY_CODE_I; }
 <COMMENT>\*\/ {
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  BEGIN(before_comment);
  }
 <COMMENT>. {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 <COMMENT>\n {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 
 ^\%(a|all)\{ {
@@ -353,14 +360,14 @@
  return code_type;
  }
 
-<C_CODE>\'\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\"\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\"\' { add_to_cbuf(yytext); }
 
-<C_CODE>\\. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\\. { add_to_cbuf(yytext); }
 
 
 <C_CODE>\" {
@@ -368,6 +375,11 @@
  before_string = C_CODE;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\" {
+ BEGIN(CODE_STRING);
+ before_string = ATTR_CODE;
+ add_to_cbuf(yytext);
+ }
 <PROPERTY_CODE_I>\" {
  BEGIN(CODE_STRING);
  before_string = PROPERTY_CODE_I;
@@ -391,6 +403,10 @@
  parenth_depth++;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\[ {
+ bracket_depth++;
+ add_to_cbuf(yytext);
+ }
 <C_CODE>\} {
  parenth_depth--;
  if(parenth_depth<0) {
@@ -403,9 +419,21 @@
  }
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\] {
+ bracket_depth--;
+ if(bracket_depth<0) {
+ REJECT;
+ } else if(bracket_depth==0) {
+ BEGIN(CLASS_CODE_I);
+ yylval.cbuf = cbuf;
+ cbuf = NULL;
+ return CCODE;
+ }
+ add_to_cbuf(yytext);
+ }
 
-<C_CODE>. { add_to_cbuf(yytext); }
-<C_CODE>\n { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\n { add_to_cbuf(yytext); }
 
 class {
  static int found_classes = 0;
@@ -612,6 +640,13 @@
  BEGIN(INITIAL);
  return '}';
  }
+<CLASS_CODE_I>\[ {
+ BEGIN(ATTR_CODE);
+ bracket_depth=1;
+ yylval.line = line_no;
+ clear_cbuf();
+ return '[';
+ }
 
 <CLASS_CODE,CLASS_CODE_I,INITIAL,PROPERTY_CODE,PROPERTY_CODE_I>[\f\t ] ;  /*ignore*/
 
--- src/main.c.orig 2007-10-17 16:49:04.000000000 +0200
+++ src/main.c 2008-01-28 17:15:53.000000000 +0100
@@ -92,11 +92,16 @@
 static gboolean special_array[SPECIAL_LAST] = {0};
 static gboolean any_special = FALSE;
 
+static gboolean need_constructor = FALSE;
+static Method * user_constructor = NULL;
+
 static gboolean need_dispose = FALSE;
 static Method * dispose_handler = NULL;
+static Method * user_dispose_method = NULL;
 
 static gboolean need_finalize = FALSE;
 static Method * finalize_handler = NULL;
+static Method * user_finalize_method = NULL;
 
 FILE *out = NULL;
 FILE *outh = NULL;
@@ -189,21 +194,25 @@
  g_free(s);
 }
 
-
-static void
-print_method (FILE *fp,
-      const char *typeprefix,
-      const char *nameprefix,
-      const char *subnameprefix,
-      const char *namepostfix,
-      const char *afterargs,
-      const char *postfix,
-      const Method *m,
-      gboolean one_arg_per_line,
-      gboolean no_funcbase,
-      gboolean kill_underscore,
-      gboolean first_unused,
-      gboolean fake_names)
+typedef enum
+{
+  PRINT_METHOD_ONE_ARG_PER_LINE = 1 << 0,
+  PRINT_METHOD_NO_FUNCBASE = 1 << 1,
+  PRINT_METHOD_FIRST_UNUSED = 1 << 2,
+  PRINT_METHOD_FAKE_NAMES = 1 << 3,
+  PRINT_METHOD_NO_ATTR = 1 << 4
+} PrintMethodFlags;
+
+static void
+print_method2 (FILE *fp,
+       const char *typeprefix,
+       const char *nameprefix,
+       const char *subnameprefix,
+       const char *namepostfix,
+       const char *afterargs,
+       const char *postfix,
+       const Method *m,
+       PrintMethodFlags flags)
 {
  GList *li;
  const char *id;
@@ -213,7 +222,7 @@
 
  id = m->id;
 
- if(no_funcbase)
+ if ((flags & PRINT_METHOD_NO_FUNCBASE) != 0)
  out_printf(fp, "%s%s%s%s(",
    nameprefix, subnameprefix, id, namepostfix);
  else
@@ -229,19 +238,19 @@
  if ( ! no_gnu &&
      ! for_cpp && /* g++ has a cow with this */
     li == m->args &&
-    first_unused) {
+     (flags & PRINT_METHOD_FIRST_UNUSED) != 0) {
  unused = " G_GNUC_UNUSED";
  }
 
  print_type(fp, arg->atype, FALSE);
- if (fake_names)
+ if ((flags & PRINT_METHOD_FAKE_NAMES) != 0)
  out_printf (fp, "___fake___");
  if(li->next)
  out_printf(fp, "%s%s%s,%s", arg->name,
    arg->atype->postfix ?
    arg->atype->postfix : "",
    unused,
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  else
  out_printf(fp, "%s%s%s", arg->name,
    arg->atype->postfix ?
@@ -250,11 +259,54 @@
  }
  if(m->vararg)
  out_printf(fp, ",%s...",
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  } else {
  out_printf(fp, "void");
  }
- out_printf(fp, "%s)%s", afterargs, postfix);
+
+ out_printf(fp, "%s)", afterargs);
+
+ if (m->attr && (flags & PRINT_METHOD_NO_ATTR) == 0)
+ out_printf(fp, " %s", m->attr);
+
+ out_printf(fp, "%s", postfix);
+}
+
+static void
+print_method (FILE *fp,
+      const char *typeprefix,
+      const char *nameprefix,
+      const char *subnameprefix,
+      const char *namepostfix,
+      const char *afterargs,
+      const char *postfix,
+      const Method *m,
+      gboolean one_arg_per_line,
+      gboolean no_funcbase,
+      gboolean kill_underscore,
+      gboolean first_unused,
+      gboolean fake_names)
+{
+ PrintMethodFlags flags = 0;
+
+ if (one_arg_per_line)
+ flags |= PRINT_METHOD_ONE_ARG_PER_LINE;
+ if (no_funcbase)
+ flags |= PRINT_METHOD_NO_FUNCBASE;
+ if (first_unused)
+ flags |= PRINT_METHOD_FIRST_UNUSED;
+ if (fake_names)
+ flags |= PRINT_METHOD_FAKE_NAMES;
+
+ print_method2(fp,
+      typeprefix,
+      nameprefix,
+      subnameprefix,
+      namepostfix,
+      afterargs,
+      postfix,
+      m,
+      flags);
 }
 
 static gboolean
@@ -269,6 +321,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -291,6 +346,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -330,6 +388,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -371,11 +432,13 @@
 
  /* 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_method2(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
  else
- print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
-     m, FALSE, TRUE, TRUE, FALSE, FALSE);
+ print_method2(outh, "\t", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
 }
 
 static void
@@ -422,8 +485,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_after */
@@ -433,8 +499,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_data */
@@ -445,8 +514,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data), (destroy_data), (GConnectFlags)(flags))\n", m->id);
  }
 }
@@ -526,9 +598,9 @@
    m->method == SIGNAL_FIRST_METHOD ||
    m->method == VIRTUAL_METHOD) {
  if(m->cbuf)
- print_method(out,
-     "static ", "___real_", "", " ", "", ";\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out,
+      "static ", "___real_", "", " ", "", ";\n",
+      m, PRINT_METHOD_NO_ATTR);
  }
  /* no else, here, it might still have a private prototype, it's not
  * exclusive */
@@ -537,15 +609,16 @@
     m->cbuf)) {
  /* add unique ID */
  char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
- print_method(out, "static ", s, "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+ print_method(out, "static ", s, "", " ", "", ";\n",
      m, FALSE, FALSE, FALSE, FALSE, FALSE);
  g_free(s);
  } else if(m->scope == PRIVATE_SCOPE ||
   m->method == INIT_METHOD ||
-  m->method == CLASS_INIT_METHOD) {
- print_method(out, "static ", "", "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+  m->method == CLASS_INIT_METHOD ||
+  m->method == CONSTRUCTOR_METHOD ||
+  m->method == DISPOSE_METHOD ||
+  m->method == FINALIZE_METHOD) {
+ print_method(out, "static ", "", "", " ", "", ";\n",
      m, FALSE, FALSE, TRUE, FALSE, FALSE);
  }
 }
@@ -629,66 +702,68 @@
  }
 }
 
-static void
-find_dispose(const Class *cl)
+static Method *
+find_method(const Class *cl, int method, const char *id)
 {
  GList *li;
 
- dispose_handler = NULL;
  for(li=cl->nodes;li;li=g_list_next(li)) {
  Node *n = li->data;
  if(n->type == METHOD_NODE) {
  Method *m = (Method *)n;
- if(m->method == OVERRIDE_METHOD &&
-   strcmp(m->id, "dispose")==0) {
- if(strcmp(m->otype, "G:Object") != 0) {
- error_print(GOB_ERROR, m->line_no,
-    "dispose method override "
-    "of class other then "
-    "G:Object");
- }
- if(g_list_length(m->args) != 1) {
- error_print(GOB_ERROR, m->line_no,
-    "dispose method override "
-    "with more then one "
-    "parameter");
- }
- dispose_handler = m;
- break;
- }
+ if (m->method == method
+    && (id == NULL || strcmp(m->id, id)==0))
+ return m;
  }
  }
+
+ return NULL;
 }
 
 static void
-find_finalize(const Class *cl)
+find_constructor(const Class *cl)
 {
- GList *li;
+ user_constructor = find_method(cl, CONSTRUCTOR_METHOD, NULL);
+}
 
- finalize_handler = NULL;
- for(li=cl->nodes;li;li=g_list_next(li)) {
- Node *n = li->data;
- if(n->type == METHOD_NODE) {
- Method *m = (Method *)n;
- if(m->method == OVERRIDE_METHOD &&
-   strcmp(m->id, "finalize")==0) {
- if(strcmp(m->otype, "G:Object") != 0) {
- error_print(GOB_ERROR, m->line_no,
-    "finalize method override "
-    "of class other then "
-    "G:Object");
- }
- if(g_list_length(m->args) != 1) {
- error_print(GOB_ERROR, m->line_no,
-    "finalize method override "
-    "with more then one "
-    "parameter");
- }
- finalize_handler = m;
- break;
- }
- }
+static void
+find_dispose(const Class *cl)
+{
+ dispose_handler = find_method(cl, OVERRIDE_METHOD, "dispose");
+ if (dispose_handler != NULL) {
+ if(strcmp(dispose_handler->otype, "G:Object") != 0)
+ error_print(GOB_ERROR, dispose_handler->line_no,
+    "dispose method override "
+    "of class other then "
+    "G:Object");
+ if(g_list_length(dispose_handler->args) != 1)
+ error_print(GOB_ERROR, dispose_handler->line_no,
+    "dispose method override "
+    "with more then one "
+    "parameter");
+ }
+
+ user_dispose_method = find_method(cl, DISPOSE_METHOD, NULL);
+}
+
+static void
+find_finalize(const Class *cl)
+{
+ finalize_handler = find_method(cl, OVERRIDE_METHOD, "finalize");
+ if (finalize_handler != NULL) {
+ if(strcmp(finalize_handler->otype, "G:Object") != 0)
+ error_print(GOB_ERROR, finalize_handler->line_no,
+    "finalize method override "
+    "of class other then "
+    "G:Object");
+ if(g_list_length(finalize_handler->args) != 1)
+ error_print(GOB_ERROR, finalize_handler->line_no,
+    "finalize method override "
+    "with more then one "
+    "parameter");
  }
+
+ user_finalize_method = find_method(cl, FINALIZE_METHOD, NULL);
 }
 
 
@@ -2118,6 +2193,33 @@
 }
 
 static void
+add_constructor (Class *c)
+{
+ out_printf(out, "\nstatic GObject *\n"
+   "___constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties)\n"
+   "{\n");
+ out_printf(out,
+   "#define __GOB_FUNCTION__ \"%s::constructor\"\n",
+   c->otype);
+
+ out_printf(out, "\tGObject *obj_self;\n");
+ out_printf(out, "\t%s *self;\n", typebase);
+
+ out_printf(out, "\tobj_self = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties, construct_properties);\n");
+ out_printf(out, "\tself = %s (obj_self);\n", macrobase);
+
+ if (user_constructor->line_no > 0)
+ out_addline_infile (out, user_constructor->line_no);
+ out_printf (out, "\t%s_constructor (self);\n", funcbase);
+ if (user_constructor->line_no > 0)
+ out_addline_outfile (out);
+
+ out_printf(out, "\treturn obj_self;\n");
+ out_printf(out, "}\n"
+   "#undef __GOB_FUNCTION__\n\n");
+}
+
+static void
 add_dispose (Class *c)
 {
  out_printf(out, "\nstatic void\n"
@@ -2127,7 +2229,7 @@
    "#define __GOB_FUNCTION__ \"%s::dispose\"\n",
    c->otype);
 
- if (unreftors > 0) {
+ if (unreftors > 0 || user_dispose_method != NULL) {
  out_printf (out, "\t%s *self%s = %s (obj_self);\n",
     typebase,
     ! no_gnu ? " G_GNUC_UNUSED" : "",
@@ -2143,6 +2245,14 @@
  if (dispose_handler->line_no > 0)
  out_addline_outfile (out);
  } else {
+ if (user_dispose_method != NULL) {
+ if (user_dispose_method->line_no > 0)
+ out_addline_infile (out, user_dispose_method->line_no);
+ out_printf (out, "\t%s_dispose (self);\n", funcbase);
+ if (user_dispose_method->line_no > 0)
+ out_addline_outfile (out);
+ }
+
  out_printf (out,
     "\tif (G_OBJECT_CLASS (parent_class)->dispose) \\\n"
     "\t\t(* G_OBJECT_CLASS (parent_class)->dispose) (obj_self);\n");
@@ -2178,7 +2288,8 @@
    c->otype);
 
  if (privates > 0 ||
-    destructors > 0) {
+    destructors > 0 ||
+    user_finalize_method != NULL) {
  const char *unused = "";
  if ( ! no_gnu)
  unused = " G_GNUC_UNUSED";
@@ -2202,6 +2313,14 @@
  if(finalize_handler->line_no > 0)
  out_addline_outfile(out);
  } else {
+ if (user_finalize_method != NULL) {
+ if (user_finalize_method->line_no > 0)
+ out_addline_infile (out, user_finalize_method->line_no);
+ out_printf (out, "\t%s_finalize (self);\n", funcbase);
+ if (user_finalize_method->line_no > 0)
+ out_addline_outfile (out);
+ }
+
  out_printf(out,
    "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
    "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n");
@@ -2381,6 +2500,9 @@
 
  /* if there are no handlers for these things, we
  * need to set them up here */
+ if(need_constructor)
+ out_printf(out, "\tg_object_class->constructor "
+   "= ___constructor;\n");
  if(need_dispose && !dispose_handler)
  out_printf(out, "\tg_object_class->dispose "
    "= ___dispose;\n");
@@ -2831,11 +2953,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, TRUE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2844,11 +2966,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile (out);
 
  out_printf (out, "{\n");
@@ -2966,8 +3088,8 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2975,11 +3097,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope==PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile(out);
  out_printf(out, "{\n"
  "\t%sClass *klass;\n", typebase);
@@ -3024,8 +3146,9 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_FIRST_UNUSED
+      | PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
@@ -3064,6 +3187,15 @@
  /* the outfile line was added above */
  out_printf(out, "#undef PARENT_HANDLER\n");
  break;
+ case CONSTRUCTOR_METHOD:
+ case DISPOSE_METHOD:
+ case FINALIZE_METHOD:
+ if(m->line_no > 0)
+ out_addline_infile(out, m->line_no);
+ print_method(out, "static ", "\n", "", " ", "", "\n",
+     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method_body(m, TRUE, TRUE);
+ /* the outfile line was added above */
  default:
  break;
  }
@@ -3633,6 +3765,9 @@
     funcbase);
  }
 
+ if (need_constructor)
+ add_constructor (c);
+
  if (need_dispose)
  add_dispose (c);
 
@@ -4441,15 +4576,24 @@
 
  make_bases ();
  make_inits ((Class *)class);
- if(unreftors > 0) {
+
+ find_constructor ((Class *)class);
+ if (user_constructor != NULL)
+ need_constructor = TRUE;
+
+ find_dispose ((Class *)class);
+ if (unreftors > 0 ||
+    dispose_handler != NULL ||
+    user_dispose_method != NULL)
  need_dispose = TRUE;
- find_dispose ((Class *)class);
- }
+
+ find_finalize ((Class *)class);
  if (destructors > 0 ||
-    privates > 0) {
+    privates > 0 ||
+    user_finalize_method != NULL) {
  need_finalize = TRUE;
- find_finalize ((Class *)class);
  }
+
  check_bad_symbols ((Class *)class);
  check_duplicate_symbols ((Class *)class);
  check_duplicate_overrides ((Class *)class);
--- src/parse.y.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/parse.y 2008-01-28 17:16:24.000000000 +0100
@@ -146,7 +146,7 @@
 
 static void
 push_function (int scope, int method, char *oid, char *id,
-       GString *cbuf, int line_no, int ccode_line,
+       GString *attr, GString *cbuf, int line_no, int ccode_line,
        gboolean vararg, GList *flags)
 {
  Node *node;
@@ -155,7 +155,11 @@
 
  g_assert(scope != CLASS_SCOPE);
       
- if(method == INIT_METHOD || method == CLASS_INIT_METHOD) {
+ if(method == INIT_METHOD
+   || method == CLASS_INIT_METHOD
+   || method == CONSTRUCTOR_METHOD
+   || method == DISPOSE_METHOD
+   || method == FINALIZE_METHOD) {
  type = (Type *)node_new (TYPE_NODE,
  "name", "void",
  NULL);
@@ -207,6 +211,7 @@
  "args:steal", funcargs,
  "onerror:steal", onerror,
  "defreturn:steal", defreturn,
+ "attr:steal", attr ? attr->str : NULL,
  "cbuf:steal", c_cbuf,
  "line_no", line_no,
  "ccode_line", ccode_line,
@@ -216,6 +221,8 @@
 
  last_added_method = (Method *)node;
 
+ if(attr)
+ g_string_free(attr, FALSE);
  if(cbuf)
  g_string_free(cbuf,
       /*only free segment if we haven't passed it
@@ -405,7 +412,7 @@
  push_funcarg ("self", FALSE);
 
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       get_id, get_cbuf, get_lineno,
+       get_id, NULL, get_cbuf, get_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -439,7 +446,7 @@
 
  typestack = g_list_prepend (typestack, node2);
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       set_id, set_cbuf, set_lineno,
+       set_id, NULL, set_cbuf, set_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -1678,9 +1685,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>3,NULL,
-      $<id>5, $<cbuf>10,$<line>1,
+      $<id>5, NULL, $<cbuf>10,$<line>1,
       ccode_line, vararg, $<list>2);
  }
+ | '[' CCODE SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>5,NULL,
+      $<id>7, $<cbuf>2, $<cbuf>12,$<line>3,
+      ccode_line, vararg, $<list>4);
+ }
  | scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("signal without 'self' as "
@@ -1694,9 +1717,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>4, NULL,
-      $<id>6, $<cbuf>11, $<line>2,
+      $<id>6, NULL, $<cbuf>11, $<line>2,
       ccode_line, vararg, $<list>3);
  }
+ | '[' CCODE scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>6, NULL,
+      $<id>8, $<cbuf>2, $<cbuf>13, $<line>4,
+      ccode_line, vararg, $<list>5);
+ }
  | VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("virtual method without 'self' as "
@@ -1710,7 +1749,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>1,
+      NULL, $<cbuf>9, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | '[' CCODE VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>6,
+      $<cbuf>2, $<cbuf>11, $<line>3,
       ccode_line, vararg, NULL);
  }
  | scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1726,7 +1781,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>2,
+      NULL, $<cbuf>9, $<line>2,
+      ccode_line, vararg, NULL);
+ }
+ | '[' CCODE scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>6,
+      $<cbuf>2, $<cbuf>11, $<line>4,
       ccode_line, vararg, NULL);
  }
  | VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1737,12 +1808,23 @@
  YYERROR;
  }
  push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
-      $<id>3, $<cbuf>8, $<line>1,
+      $<id>3, NULL, $<cbuf>8, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | '[' CCODE VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
+      $<id>5, $<cbuf>2, $<cbuf>10, $<line>3,
       ccode_line, vararg, NULL);
  }
  | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode {
  push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
-      $<id>6, $<cbuf>11,
+      $<id>6, NULL, $<cbuf>11,
       $<line>1, ccode_line,
       vararg, NULL);
  }
@@ -1753,27 +1835,53 @@
  YYERROR;
  }
  push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
-      $<cbuf>8, $<line>1, ccode_line,
+      NULL, $<cbuf>8, $<line>1, ccode_line,
+      vararg, NULL);
+ }
+ | '[' CCODE scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, REGULAR_METHOD, NULL, $<id>5,
+      $<cbuf>2, $<cbuf>10, $<line>3, ccode_line,
       vararg, NULL);
  }
  | TOKEN '(' TOKEN ')' codenocode {
  if(strcmp($<id>1, "init")==0) {
  push_init_arg($<id>3,FALSE);
  push_function(NO_SCOPE, INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else if(strcmp($<id>1, "class_init")==0) {
  push_init_arg($<id>3,TRUE);
  push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "constructor")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, CONSTRUCTOR_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "dispose")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, DISPOSE_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "finalize")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, FINALIZE_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else {
  g_free($<id>1);
  g_free($<id>3);
  g_string_free($<cbuf>5,TRUE);
  yyerror(_("parse error "
-  "(untyped blocks must be init or "
-  "class_init)"));
+  "(untyped blocks must be init, "
+  "class_init, constructor, dispose "
+  "or finalize)"));
  YYERROR;
  }
  }
--- src/treefuncs.def.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/treefuncs.def 2008-01-28 17:15:53.000000000 +0100
@@ -40,6 +40,9 @@
  REGULAR_METHOD,
  INIT_METHOD,
  CLASS_INIT_METHOD,
+ CONSTRUCTOR_METHOD,
+ DISPOSE_METHOD,
+ FINALIZE_METHOD,
  VIRTUAL_METHOD,
  SIGNAL_LAST_METHOD,
  SIGNAL_FIRST_METHOD,
@@ -126,6 +129,7 @@
   NODELIST args
   STRING onerror
   STRING defreturn
+  STRING attr
   STRING cbuf
   INT line_no
   INT ccode_line



--
to unsubscribe:
send mail to minimalist@... with "unsubscribe gob-list" in the subject

attachment0 (196 bytes) Download Attachment

Re: patch allowing to add GCC attributes to methods

by Jean-Yves Lefort :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, 28 Jan 2008 18:10:20 +0100
Jean-Yves Lefort <jylefort@...> wrote:

> The attached patch allows to add GCC attributes to methods, using a
> syntax borrowed from C#.

There was a lexer conflict between array dimensions and
attributes. The fixed patches are attached.

--
Jean-Yves Lefort <jylefort@...>

[gob2-2.0.15-attr.diff]

--- src/lexer.l.orig 2007-09-28 06:26:49.000000000 +0200
+++ src/lexer.l 2008-01-29 00:04:49.000000000 +0100
@@ -31,6 +31,7 @@
 #include "main.h"
 #include "util.h"
 
+static int bracket_depth = 0;
 static int parenth_depth = 0;
 static int before_comment
 /* New flex is on drugs */
@@ -102,6 +103,7 @@
 
 %x COMMENT
 %x C_CODE
+%x ATTR_CODE
 %x CODE_STRING
 %x CLASS_CODE
 %x CLASS_STRING
@@ -267,7 +269,7 @@
  add_to_cbuf(yytext);
  }
 
-<C_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
+<C_CODE,ATTR_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
 <CLASS_CODE>\/\/.*$ { ; /*comment, ignore*/ }
 <CLASS_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
 <PROPERTY_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
@@ -277,20 +279,25 @@
  BEGIN(COMMENT);
  before_comment = C_CODE;
 }
+<ATTR_CODE>\/\* {
+ add_to_cbuf(yytext);
+ BEGIN(COMMENT);
+ before_comment = ATTR_CODE;
+}
 <CLASS_CODE>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE; }
 <CLASS_CODE_I>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE_I; }
 <PROPERTY_CODE_I>\/\* {BEGIN(COMMENT); before_comment = PROPERTY_CODE_I; }
 <COMMENT>\*\/ {
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  BEGIN(before_comment);
  }
 <COMMENT>. {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 <COMMENT>\n {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 
 ^\%(a|all)\{ {
@@ -353,14 +360,14 @@
  return code_type;
  }
 
-<C_CODE>\'\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\"\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\"\' { add_to_cbuf(yytext); }
 
-<C_CODE>\\. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\\. { add_to_cbuf(yytext); }
 
 
 <C_CODE>\" {
@@ -368,6 +375,11 @@
  before_string = C_CODE;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\" {
+ BEGIN(CODE_STRING);
+ before_string = ATTR_CODE;
+ add_to_cbuf(yytext);
+ }
 <PROPERTY_CODE_I>\" {
  BEGIN(CODE_STRING);
  before_string = PROPERTY_CODE_I;
@@ -391,6 +403,10 @@
  parenth_depth++;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\[ {
+ bracket_depth++;
+ add_to_cbuf(yytext);
+ }
 <C_CODE>\} {
  parenth_depth--;
  if(parenth_depth<0) {
@@ -403,9 +419,21 @@
  }
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\] {
+ bracket_depth--;
+ if(bracket_depth<0) {
+ REJECT;
+ } else if(bracket_depth==0) {
+ BEGIN(CLASS_CODE_I);
+ yylval.cbuf = cbuf;
+ cbuf = NULL;
+ return CCODE;
+ }
+ add_to_cbuf(yytext);
+ }
 
-<C_CODE>. { add_to_cbuf(yytext); }
-<C_CODE>\n { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\n { add_to_cbuf(yytext); }
 
 class {
  static int found_classes = 0;
@@ -588,12 +616,12 @@
 
 <CLASS_CODE_I>(\[[0-9]*\]|\[[A-Za-z_][A-Za-z0-9_]*\])+ {
  yylval.id = g_strdup(yytext);
- return ARRAY_DIM;
+ return ARRAY_DIM_OR_ATTR;
  }
 <CLASS_CODE_I>:[0-9]+ {
  /* cheat for bitfield */
  yylval.id = g_strdup(yytext);
- return ARRAY_DIM;
+ return BITFIELD;
  }
 <CLASS_CODE>\{ {
  BEGIN(CLASS_CODE_I);
@@ -612,6 +640,13 @@
  BEGIN(INITIAL);
  return '}';
  }
+<CLASS_CODE_I>\[ {
+ BEGIN(ATTR_CODE);
+ bracket_depth=1;
+ yylval.line = line_no;
+ clear_cbuf();
+ return '[';
+ }
 
 <CLASS_CODE,CLASS_CODE_I,INITIAL,PROPERTY_CODE,PROPERTY_CODE_I>[\f\t ] ;  /*ignore*/
 
--- src/main.c.orig 2007-10-17 16:49:04.000000000 +0200
+++ src/main.c 2008-01-29 00:02:09.000000000 +0100
@@ -189,21 +189,25 @@
  g_free(s);
 }
 
-
-static void
-print_method (FILE *fp,
-      const char *typeprefix,
-      const char *nameprefix,
-      const char *subnameprefix,
-      const char *namepostfix,
-      const char *afterargs,
-      const char *postfix,
-      const Method *m,
-      gboolean one_arg_per_line,
-      gboolean no_funcbase,
-      gboolean kill_underscore,
-      gboolean first_unused,
-      gboolean fake_names)
+typedef enum
+{
+  PRINT_METHOD_ONE_ARG_PER_LINE = 1 << 0,
+  PRINT_METHOD_NO_FUNCBASE = 1 << 1,
+  PRINT_METHOD_FIRST_UNUSED = 1 << 2,
+  PRINT_METHOD_FAKE_NAMES = 1 << 3,
+  PRINT_METHOD_NO_ATTR = 1 << 4
+} PrintMethodFlags;
+
+static void
+print_method2 (FILE *fp,
+       const char *typeprefix,
+       const char *nameprefix,
+       const char *subnameprefix,
+       const char *namepostfix,
+       const char *afterargs,
+       const char *postfix,
+       const Method *m,
+       PrintMethodFlags flags)
 {
  GList *li;
  const char *id;
@@ -213,7 +217,7 @@
 
  id = m->id;
 
- if(no_funcbase)
+ if ((flags & PRINT_METHOD_NO_FUNCBASE) != 0)
  out_printf(fp, "%s%s%s%s(",
    nameprefix, subnameprefix, id, namepostfix);
  else
@@ -229,19 +233,19 @@
  if ( ! no_gnu &&
      ! for_cpp && /* g++ has a cow with this */
     li == m->args &&
-    first_unused) {
+     (flags & PRINT_METHOD_FIRST_UNUSED) != 0) {
  unused = " G_GNUC_UNUSED";
  }
 
  print_type(fp, arg->atype, FALSE);
- if (fake_names)
+ if ((flags & PRINT_METHOD_FAKE_NAMES) != 0)
  out_printf (fp, "___fake___");
  if(li->next)
  out_printf(fp, "%s%s%s,%s", arg->name,
    arg->atype->postfix ?
    arg->atype->postfix : "",
    unused,
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  else
  out_printf(fp, "%s%s%s", arg->name,
    arg->atype->postfix ?
@@ -250,11 +254,54 @@
  }
  if(m->vararg)
  out_printf(fp, ",%s...",
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  } else {
  out_printf(fp, "void");
  }
- out_printf(fp, "%s)%s", afterargs, postfix);
+
+ out_printf(fp, "%s)", afterargs);
+
+ if (m->attr && (flags & PRINT_METHOD_NO_ATTR) == 0)
+ out_printf(fp, " %s", m->attr);
+
+ out_printf(fp, "%s", postfix);
+}
+
+static void
+print_method (FILE *fp,
+      const char *typeprefix,
+      const char *nameprefix,
+      const char *subnameprefix,
+      const char *namepostfix,
+      const char *afterargs,
+      const char *postfix,
+      const Method *m,
+      gboolean one_arg_per_line,
+      gboolean no_funcbase,
+      gboolean kill_underscore,
+      gboolean first_unused,
+      gboolean fake_names)
+{
+ PrintMethodFlags flags = 0;
+
+ if (one_arg_per_line)
+ flags |= PRINT_METHOD_ONE_ARG_PER_LINE;
+ if (no_funcbase)
+ flags |= PRINT_METHOD_NO_FUNCBASE;
+ if (first_unused)
+ flags |= PRINT_METHOD_FIRST_UNUSED;
+ if (fake_names)
+ flags |= PRINT_METHOD_FAKE_NAMES;
+
+ print_method2(fp,
+      typeprefix,
+      nameprefix,
+      subnameprefix,
+      namepostfix,
+      afterargs,
+      postfix,
+      m,
+      flags);
 }
 
 static gboolean
@@ -371,11 +418,13 @@
 
  /* 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_method2(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
  else
- print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
-     m, FALSE, TRUE, TRUE, FALSE, FALSE);
+ print_method2(outh, "\t", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
 }
 
 static void
@@ -422,8 +471,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_after */
@@ -433,8 +485,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_data */
@@ -445,8 +500,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data), (destroy_data), (GConnectFlags)(flags))\n", m->id);
  }
 }
@@ -526,9 +584,9 @@
    m->method == SIGNAL_FIRST_METHOD ||
    m->method == VIRTUAL_METHOD) {
  if(m->cbuf)
- print_method(out,
-     "static ", "___real_", "", " ", "", ";\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out,
+      "static ", "___real_", "", " ", "", ";\n",
+      m, PRINT_METHOD_NO_ATTR);
  }
  /* no else, here, it might still have a private prototype, it's not
  * exclusive */
@@ -537,15 +595,13 @@
     m->cbuf)) {
  /* add unique ID */
  char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
- print_method(out, "static ", s, "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+ print_method(out, "static ", s, "", " ", "", ";\n",
      m, FALSE, FALSE, FALSE, FALSE, FALSE);
  g_free(s);
  } else if(m->scope == PRIVATE_SCOPE ||
   m->method == INIT_METHOD ||
   m->method == CLASS_INIT_METHOD) {
- print_method(out, "static ", "", "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+ print_method(out, "static ", "", "", " ", "", ";\n",
      m, FALSE, FALSE, TRUE, FALSE, FALSE);
  }
 }
@@ -2831,11 +2887,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, TRUE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2844,11 +2900,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile (out);
 
  out_printf (out, "{\n");
@@ -2966,8 +3022,8 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2975,11 +3031,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope==PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile(out);
  out_printf(out, "{\n"
  "\t%sClass *klass;\n", typebase);
@@ -3024,8 +3080,9 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_FIRST_UNUSED
+      | PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
--- src/parse.y.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/parse.y 2008-01-29 00:19:27.000000000 +0100
@@ -146,7 +146,7 @@
 
 static void
 push_function (int scope, int method, char *oid, char *id,
-       GString *cbuf, int line_no, int ccode_line,
+       GString *attr, GString *cbuf, int line_no, int ccode_line,
        gboolean vararg, GList *flags)
 {
  Node *node;
@@ -207,6 +207,7 @@
  "args:steal", funcargs,
  "onerror:steal", onerror,
  "defreturn:steal", defreturn,
+ "attr:steal", attr ? attr->str : NULL,
  "cbuf:steal", c_cbuf,
  "line_no", line_no,
  "ccode_line", ccode_line,
@@ -216,6 +217,8 @@
 
  last_added_method = (Method *)node;
 
+ if(attr)
+ g_string_free(attr, FALSE);
  if(cbuf)
  g_string_free(cbuf,
       /*only free segment if we haven't passed it
@@ -405,7 +408,7 @@
  push_funcarg ("self", FALSE);
 
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       get_id, get_cbuf, get_lineno,
+       get_id, NULL, get_cbuf, get_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -439,7 +442,7 @@
 
  typestack = g_list_prepend (typestack, node2);
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       set_id, set_cbuf, set_lineno,
+       set_id, NULL, set_cbuf, set_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -677,7 +680,7 @@
 %token CONST VOID STRUCT UNION ENUM THREEDOTS
 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
 
-%token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM SINGLE_CHAR
+%token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM_OR_ATTR BITFIELD SINGLE_CHAR
 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE STRING
 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE PROPERTY ARGUMENT
 %token <line> VIRTUAL SIGNAL OVERRIDE
@@ -982,7 +985,7 @@
 variable: scope type TOKEN varoptions ';' {
  push_variable($<id>3, the_scope,$<line>1, NULL);
  }
- | scope type TOKEN ARRAY_DIM varoptions ';' {
+ | scope type TOKEN array_dim varoptions ';' {
  push_variable($<id>3, the_scope, $<line>1, $<id>4);
  }
  ;
@@ -1678,9 +1681,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>3,NULL,
-      $<id>5, $<cbuf>10,$<line>1,
+      $<id>5, NULL, $<cbuf>10,$<line>1,
       ccode_line, vararg, $<list>2);
  }
+ | attrs SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>4,NULL,
+      $<id>6, $<cbuf>1, $<cbuf>11,$<line>2,
+      ccode_line, vararg, $<list>3);
+ }
  | scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("signal without 'self' as "
@@ -1694,9 +1713,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>4, NULL,
-      $<id>6, $<cbuf>11, $<line>2,
+      $<id>6, NULL, $<cbuf>11, $<line>2,
       ccode_line, vararg, $<list>3);
  }
+ | attrs scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>5, NULL,
+      $<id>7, $<cbuf>1, $<cbuf>12, $<line>3,
+      ccode_line, vararg, $<list>4);
+ }
  | VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("virtual method without 'self' as "
@@ -1710,7 +1745,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>1,
+      NULL, $<cbuf>9, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | attrs VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>5,
+      $<cbuf>1, $<cbuf>10, $<line>2,
       ccode_line, vararg, NULL);
  }
  | scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1726,7 +1777,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>2,
+      NULL, $<cbuf>9, $<line>2,
+      ccode_line, vararg, NULL);
+ }
+ | attrs scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>5,
+      $<cbuf>1, $<cbuf>10, $<line>3,
       ccode_line, vararg, NULL);
  }
  | VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1737,12 +1804,23 @@
  YYERROR;
  }
  push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
-      $<id>3, $<cbuf>8, $<line>1,
+      $<id>3, NULL, $<cbuf>8, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | attrs VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
+      $<id>4, $<cbuf>1, $<cbuf>9, $<line>2,
       ccode_line, vararg, NULL);
  }
  | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode {
  push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
-      $<id>6, $<cbuf>11,
+      $<id>6, NULL, $<cbuf>11,
       $<line>1, ccode_line,
       vararg, NULL);
  }
@@ -1753,19 +1831,29 @@
  YYERROR;
  }
  push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
-      $<cbuf>8, $<line>1, ccode_line,
+      NULL, $<cbuf>8, $<line>1, ccode_line,
+      vararg, NULL);
+ }
+ | attrs scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, REGULAR_METHOD, NULL, $<id>4,
+      $<cbuf>1, $<cbuf>9, $<line>2, ccode_line,
       vararg, NULL);
  }
  | TOKEN '(' TOKEN ')' codenocode {
  if(strcmp($<id>1, "init")==0) {
  push_init_arg($<id>3,FALSE);
  push_function(NO_SCOPE, INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else if(strcmp($<id>1, "class_init")==0) {
  push_init_arg($<id>3,TRUE);
  push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else {
  g_free($<id>1);
@@ -1779,6 +1867,22 @@
  }
  ;
 
+attrs:
+ '[' CCODE {
+ $<cbuf>$ = $<cbuf>2;
+ }
+ | ARRAY_DIM_OR_ATTR {
+ int len = strlen($<id>1);
+
+ g_assert($<id>1[0] == '[');
+ g_assert(len >= 2 && $<id>1[len - 1] == ']');
+
+ /* strip the brackets */
+ $<cbuf>$ = g_string_new_len($<id>1 + 1, len - 2);
+ g_free($<id>1);
+ }
+ ;
+
 returnvals: TOKEN retcode {
  g_free(onerror); onerror = NULL;
  g_free(defreturn); defreturn = NULL;
@@ -1900,7 +2004,7 @@
 arg: type TOKEN {
  push_funcarg($<id>2,NULL);
  }
- | type TOKEN ARRAY_DIM {
+ | type TOKEN array_dim {
  push_funcarg($<id>2,$<id>3);
  }
  | type TOKEN '(' TOKEN checklist ')' {
@@ -1911,7 +2015,7 @@
  g_free($<id>4);
  push_funcarg($<id>2,NULL);
  }
- | type TOKEN ARRAY_DIM '(' TOKEN checklist ')' {
+ | type TOKEN array_dim '(' TOKEN checklist ')' {
  if(strcmp($<id>5,"check")!=0) {
  yyerror(_("parse error"));
  YYERROR;
@@ -2105,5 +2209,10 @@
  | SINGLE_CHAR { $<id>$ = $<id>1; }
  | TOKEN { $<id>$ = $<id>1; }
  ;
+
+array_dim:
+ ARRAY_DIM_OR_ATTR
+ | BITFIELD
+ ;
 
 %%
--- src/treefuncs.def.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/treefuncs.def 2008-01-29 00:02:09.000000000 +0100
@@ -126,6 +126,7 @@
   NODELIST args
   STRING onerror
   STRING defreturn
+  STRING attr
   STRING cbuf
   INT line_no
   INT ccode_line


[gob2-2.0.15-gobject-overrides-and-attr.diff]

--- src/lexer.l.orig 2007-09-28 06:26:49.000000000 +0200
+++ src/lexer.l 2008-01-29 00:24:30.000000000 +0100
@@ -31,6 +31,7 @@
 #include "main.h"
 #include "util.h"
 
+static int bracket_depth = 0;
 static int parenth_depth = 0;
 static int before_comment
 /* New flex is on drugs */
@@ -102,6 +103,7 @@
 
 %x COMMENT
 %x C_CODE
+%x ATTR_CODE
 %x CODE_STRING
 %x CLASS_CODE
 %x CLASS_STRING
@@ -267,7 +269,7 @@
  add_to_cbuf(yytext);
  }
 
-<C_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
+<C_CODE,ATTR_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
 <CLASS_CODE>\/\/.*$ { ; /*comment, ignore*/ }
 <CLASS_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
 <PROPERTY_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
@@ -277,20 +279,25 @@
  BEGIN(COMMENT);
  before_comment = C_CODE;
 }
+<ATTR_CODE>\/\* {
+ add_to_cbuf(yytext);
+ BEGIN(COMMENT);
+ before_comment = ATTR_CODE;
+}
 <CLASS_CODE>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE; }
 <CLASS_CODE_I>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE_I; }
 <PROPERTY_CODE_I>\/\* {BEGIN(COMMENT); before_comment = PROPERTY_CODE_I; }
 <COMMENT>\*\/ {
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  BEGIN(before_comment);
  }
 <COMMENT>. {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 <COMMENT>\n {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 
 ^\%(a|all)\{ {
@@ -353,14 +360,14 @@
  return code_type;
  }
 
-<C_CODE>\'\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\"\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\"\' { add_to_cbuf(yytext); }
 
-<C_CODE>\\. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\\. { add_to_cbuf(yytext); }
 
 
 <C_CODE>\" {
@@ -368,6 +375,11 @@
  before_string = C_CODE;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\" {
+ BEGIN(CODE_STRING);
+ before_string = ATTR_CODE;
+ add_to_cbuf(yytext);
+ }
 <PROPERTY_CODE_I>\" {
  BEGIN(CODE_STRING);
  before_string = PROPERTY_CODE_I;
@@ -391,6 +403,10 @@
  parenth_depth++;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\[ {
+ bracket_depth++;
+ add_to_cbuf(yytext);
+ }
 <C_CODE>\} {
  parenth_depth--;
  if(parenth_depth<0) {
@@ -403,9 +419,21 @@
  }
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\] {
+ bracket_depth--;
+ if(bracket_depth<0) {
+ REJECT;
+ } else if(bracket_depth==0) {
+ BEGIN(CLASS_CODE_I);
+ yylval.cbuf = cbuf;
+ cbuf = NULL;
+ return CCODE;
+ }
+ add_to_cbuf(yytext);
+ }
 
-<C_CODE>. { add_to_cbuf(yytext); }
-<C_CODE>\n { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\n { add_to_cbuf(yytext); }
 
 class {
  static int found_classes = 0;
@@ -588,12 +616,12 @@
 
 <CLASS_CODE_I>(\[[0-9]*\]|\[[A-Za-z_][A-Za-z0-9_]*\])+ {
  yylval.id = g_strdup(yytext);
- return ARRAY_DIM;
+ return ARRAY_DIM_OR_ATTR;
  }
 <CLASS_CODE_I>:[0-9]+ {
  /* cheat for bitfield */
  yylval.id = g_strdup(yytext);
- return ARRAY_DIM;
+ return BITFIELD;
  }
 <CLASS_CODE>\{ {
  BEGIN(CLASS_CODE_I);
@@ -612,6 +640,13 @@
  BEGIN(INITIAL);
  return '}';
  }
+<CLASS_CODE_I>\[ {
+ BEGIN(ATTR_CODE);
+ bracket_depth=1;
+ yylval.line = line_no;
+ clear_cbuf();
+ return '[';
+ }
 
 <CLASS_CODE,CLASS_CODE_I,INITIAL,PROPERTY_CODE,PROPERTY_CODE_I>[\f\t ] ;  /*ignore*/
 
--- src/main.c.orig 2007-10-17 16:49:04.000000000 +0200
+++ src/main.c 2008-01-29 00:24:30.000000000 +0100
@@ -92,11 +92,16 @@
 static gboolean special_array[SPECIAL_LAST] = {0};
 static gboolean any_special = FALSE;
 
+static gboolean need_constructor = FALSE;
+static Method * user_constructor = NULL;
+
 static gboolean need_dispose = FALSE;
 static Method * dispose_handler = NULL;
+static Method * user_dispose_method = NULL;
 
 static gboolean need_finalize = FALSE;
 static Method * finalize_handler = NULL;
+static Method * user_finalize_method = NULL;
 
 FILE *out = NULL;
 FILE *outh = NULL;
@@ -189,21 +194,25 @@
  g_free(s);
 }
 
-
-static void
-print_method (FILE *fp,
-      const char *typeprefix,
-      const char *nameprefix,
-      const char *subnameprefix,
-      const char *namepostfix,
-      const char *afterargs,
-      const char *postfix,
-      const Method *m,
-      gboolean one_arg_per_line,
-      gboolean no_funcbase,
-      gboolean kill_underscore,
-      gboolean first_unused,
-      gboolean fake_names)
+typedef enum
+{
+  PRINT_METHOD_ONE_ARG_PER_LINE = 1 << 0,
+  PRINT_METHOD_NO_FUNCBASE = 1 << 1,
+  PRINT_METHOD_FIRST_UNUSED = 1 << 2,
+  PRINT_METHOD_FAKE_NAMES = 1 << 3,
+  PRINT_METHOD_NO_ATTR = 1 << 4
+} PrintMethodFlags;
+
+static void
+print_method2 (FILE *fp,
+       const char *typeprefix,
+       const char *nameprefix,
+       const char *subnameprefix,
+       const char *namepostfix,
+       const char *afterargs,
+       const char *postfix,
+       const Method *m,
+       PrintMethodFlags flags)
 {
  GList *li;
  const char *id;
@@ -213,7 +222,7 @@
 
  id = m->id;
 
- if(no_funcbase)
+ if ((flags & PRINT_METHOD_NO_FUNCBASE) != 0)
  out_printf(fp, "%s%s%s%s(",
    nameprefix, subnameprefix, id, namepostfix);
  else
@@ -229,19 +238,19 @@
  if ( ! no_gnu &&
      ! for_cpp && /* g++ has a cow with this */
     li == m->args &&
-    first_unused) {
+     (flags & PRINT_METHOD_FIRST_UNUSED) != 0) {
  unused = " G_GNUC_UNUSED";
  }
 
  print_type(fp, arg->atype, FALSE);
- if (fake_names)
+ if ((flags & PRINT_METHOD_FAKE_NAMES) != 0)
  out_printf (fp, "___fake___");
  if(li->next)
  out_printf(fp, "%s%s%s,%s", arg->name,
    arg->atype->postfix ?
    arg->atype->postfix : "",
    unused,
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  else
  out_printf(fp, "%s%s%s", arg->name,
    arg->atype->postfix ?
@@ -250,11 +259,54 @@
  }
  if(m->vararg)
  out_printf(fp, ",%s...",
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  } else {
  out_printf(fp, "void");
  }
- out_printf(fp, "%s)%s", afterargs, postfix);
+
+ out_printf(fp, "%s)", afterargs);
+
+ if (m->attr && (flags & PRINT_METHOD_NO_ATTR) == 0)
+ out_printf(fp, " %s", m->attr);
+
+ out_printf(fp, "%s", postfix);
+}
+
+static void
+print_method (FILE *fp,
+      const char *typeprefix,
+      const char *nameprefix,
+      const char *subnameprefix,
+      const char *namepostfix,
+      const char *afterargs,
+      const char *postfix,
+      const Method *m,
+      gboolean one_arg_per_line,
+      gboolean no_funcbase,
+      gboolean kill_underscore,
+      gboolean first_unused,
+      gboolean fake_names)
+{
+ PrintMethodFlags flags = 0;
+
+ if (one_arg_per_line)
+ flags |= PRINT_METHOD_ONE_ARG_PER_LINE;
+ if (no_funcbase)
+ flags |= PRINT_METHOD_NO_FUNCBASE;
+ if (first_unused)
+ flags |= PRINT_METHOD_FIRST_UNUSED;
+ if (fake_names)
+ flags |= PRINT_METHOD_FAKE_NAMES;
+
+ print_method2(fp,
+      typeprefix,
+      nameprefix,
+      subnameprefix,
+      namepostfix,
+      afterargs,
+      postfix,
+      m,
+      flags);
 }
 
 static gboolean
@@ -269,6 +321,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -291,6 +346,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -330,6 +388,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -371,11 +432,13 @@
 
  /* 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_method2(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
  else
- print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
-     m, FALSE, TRUE, TRUE, FALSE, FALSE);
+ print_method2(outh, "\t", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
 }
 
 static void
@@ -422,8 +485,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_after */
@@ -433,8 +499,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_data */
@@ -445,8 +514,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data), (destroy_data), (GConnectFlags)(flags))\n", m->id);
  }
 }
@@ -526,9 +598,9 @@
    m->method == SIGNAL_FIRST_METHOD ||
    m->method == VIRTUAL_METHOD) {
  if(m->cbuf)
- print_method(out,
-     "static ", "___real_", "", " ", "", ";\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out,
+      "static ", "___real_", "", " ", "", ";\n",
+      m, PRINT_METHOD_NO_ATTR);
  }
  /* no else, here, it might still have a private prototype, it's not
  * exclusive */
@@ -537,15 +609,16 @@
     m->cbuf)) {
  /* add unique ID */
  char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
- print_method(out, "static ", s, "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+ print_method(out, "static ", s, "", " ", "", ";\n",
      m, FALSE, FALSE, FALSE, FALSE, FALSE);
  g_free(s);
  } else if(m->scope == PRIVATE_SCOPE ||
   m->method == INIT_METHOD ||
-  m->method == CLASS_INIT_METHOD) {
- print_method(out, "static ", "", "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+  m->method == CLASS_INIT_METHOD ||
+  m->method == CONSTRUCTOR_METHOD ||
+  m->method == DISPOSE_METHOD ||
+  m->method == FINALIZE_METHOD) {
+ print_method(out, "static ", "", "", " ", "", ";\n",
      m, FALSE, FALSE, TRUE, FALSE, FALSE);
  }
 }
@@ -629,66 +702,68 @@
  }
 }
 
-static void
-find_dispose(const Class *cl)
+static Method *
+find_method(const Class *cl, int method, const char *id)
 {
  GList *li;
 
- dispose_handler = NULL;
  for(li=cl->nodes;li;li=g_list_next(li)) {
  Node *n = li->data;
  if(n->type == METHOD_NODE) {
  Method *m = (Method *)n;
- if(m->method == OVERRIDE_METHOD &&
-   strcmp(m->id, "dispose")==0) {
- if(strcmp(m->otype, "G:Object") != 0) {
- error_print(GOB_ERROR, m->line_no,
-    "dispose method override "
-    "of class other then "
-    "G:Object");
- }
- if(g_list_length(m->args) != 1) {
- error_print(GOB_ERROR, m->line_no,
-    "dispose method override "
-    "with more then one "
-    "parameter");
- }
- dispose_handler = m;
- break;
- }
+ if (m->method == method
+    && (id == NULL || strcmp(m->id, id)==0))
+ return m;
  }
  }
+
+ return NULL;
 }
 
 static void
-find_finalize(const Class *cl)
+find_constructor(const Class *cl)
 {
- GList *li;
+ user_constructor = find_method(cl, CONSTRUCTOR_METHOD, NULL);
+}
 
- finalize_handler = NULL;
- for(li=cl->nodes;li;li=g_list_next(li)) {
- Node *n = li->data;
- if(n->type == METHOD_NODE) {
- Method *m = (Method *)n;
- if(m->method == OVERRIDE_METHOD &&
-   strcmp(m->id, "finalize")==0) {
- if(strcmp(m->otype, "G:Object") != 0) {
- error_print(GOB_ERROR, m->line_no,
-    "finalize method override "
-    "of class other then "
-    "G:Object");
- }
- if(g_list_length(m->args) != 1) {
- error_print(GOB_ERROR, m->line_no,
-    "finalize method override "
-    "with more then one "
-    "parameter");
- }
- finalize_handler = m;
- break;
- }
- }
+static void
+find_dispose(const Class *cl)
+{
+ dispose_handler = find_method(cl, OVERRIDE_METHOD, "dispose");
+ if (dispose_handler != NULL) {
+ if(strcmp(dispose_handler->otype, "G:Object") != 0)
+ error_print(GOB_ERROR, dispose_handler->line_no,
+    "dispose method override "
+    "of class other then "
+    "G:Object");
+ if(g_list_length(dispose_handler->args) != 1)
+ error_print(GOB_ERROR, dispose_handler->line_no,
+    "dispose method override "
+    "with more then one "
+    "parameter");
+ }
+
+ user_dispose_method = find_method(cl, DISPOSE_METHOD, NULL);
+}
+
+static void
+find_finalize(const Class *cl)
+{
+ finalize_handler = find_method(cl, OVERRIDE_METHOD, "finalize");
+ if (finalize_handler != NULL) {
+ if(strcmp(finalize_handler->otype, "G:Object") != 0)
+ error_print(GOB_ERROR, finalize_handler->line_no,
+    "finalize method override "
+    "of class other then "
+    "G:Object");
+ if(g_list_length(finalize_handler->args) != 1)
+ error_print(GOB_ERROR, finalize_handler->line_no,
+    "finalize method override "
+    "with more then one "
+    "parameter");
  }
+
+ user_finalize_method = find_method(cl, FINALIZE_METHOD, NULL);
 }
 
 
@@ -2118,6 +2193,33 @@
 }
 
 static void
+add_constructor (Class *c)
+{
+ out_printf(out, "\nstatic GObject *\n"
+   "___constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties)\n"
+   "{\n");
+ out_printf(out,
+   "#define __GOB_FUNCTION__ \"%s::constructor\"\n",
+   c->otype);
+
+ out_printf(out, "\tGObject *obj_self;\n");
+ out_printf(out, "\t%s *self;\n", typebase);
+
+ out_printf(out, "\tobj_self = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties, construct_properties);\n");
+ out_printf(out, "\tself = %s (obj_self);\n", macrobase);
+
+ if (user_constructor->line_no > 0)
+ out_addline_infile (out, user_constructor->line_no);
+ out_printf (out, "\t%s_constructor (self);\n", funcbase);
+ if (user_constructor->line_no > 0)
+ out_addline_outfile (out);
+
+ out_printf(out, "\treturn obj_self;\n");
+ out_printf(out, "}\n"
+   "#undef __GOB_FUNCTION__\n\n");
+}
+
+static void
 add_dispose (Class *c)
 {
  out_printf(out, "\nstatic void\n"
@@ -2127,7 +2229,7 @@
    "#define __GOB_FUNCTION__ \"%s::dispose\"\n",
    c->otype);
 
- if (unreftors > 0) {
+ if (unreftors > 0 || user_dispose_method != NULL) {
  out_printf (out, "\t%s *self%s = %s (obj_self);\n",
     typebase,
     ! no_gnu ? " G_GNUC_UNUSED" : "",
@@ -2143,6 +2245,14 @@
  if (dispose_handler->line_no > 0)
  out_addline_outfile (out);
  } else {
+ if (user_dispose_method != NULL) {
+ if (user_dispose_method->line_no > 0)
+ out_addline_infile (out, user_dispose_method->line_no);
+ out_printf (out, "\t%s_dispose (self);\n", funcbase);
+ if (user_dispose_method->line_no > 0)
+ out_addline_outfile (out);
+ }
+
  out_printf (out,
     "\tif (G_OBJECT_CLASS (parent_class)->dispose) \\\n"
     "\t\t(* G_OBJECT_CLASS (parent_class)->dispose) (obj_self);\n");
@@ -2178,7 +2288,8 @@
    c->otype);
 
  if (privates > 0 ||
-    destructors > 0) {
+    destructors > 0 ||
+    user_finalize_method != NULL) {
  const char *unused = "";
  if ( ! no_gnu)
  unused = " G_GNUC_UNUSED";
@@ -2202,6 +2313,14 @@
  if(finalize_handler->line_no > 0)
  out_addline_outfile(out);
  } else {
+ if (user_finalize_method != NULL) {
+ if (user_finalize_method->line_no > 0)
+ out_addline_infile (out, user_finalize_method->line_no);
+ out_printf (out, "\t%s_finalize (self);\n", funcbase);
+ if (user_finalize_method->line_no > 0)
+ out_addline_outfile (out);
+ }
+
  out_printf(out,
    "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
    "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n");
@@ -2381,6 +2500,9 @@
 
  /* if there are no handlers for these things, we
  * need to set them up here */
+ if(need_constructor)
+ out_printf(out, "\tg_object_class->constructor "
+   "= ___constructor;\n");
  if(need_dispose && !dispose_handler)
  out_printf(out, "\tg_object_class->dispose "
    "= ___dispose;\n");
@@ -2831,11 +2953,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, TRUE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2844,11 +2966,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile (out);
 
  out_printf (out, "{\n");
@@ -2966,8 +3088,8 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2975,11 +3097,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope==PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile(out);
  out_printf(out, "{\n"
  "\t%sClass *klass;\n", typebase);
@@ -3024,8 +3146,9 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_FIRST_UNUSED
+      | PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
@@ -3064,6 +3187,15 @@
  /* the outfile line was added above */
  out_printf(out, "#undef PARENT_HANDLER\n");
  break;
+ case CONSTRUCTOR_METHOD:
+ case DISPOSE_METHOD:
+ case FINALIZE_METHOD:
+ if(m->line_no > 0)
+ out_addline_infile(out, m->line_no);
+ print_method(out, "static ", "\n", "", " ", "", "\n",
+     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method_body(m, TRUE, TRUE);
+ /* the outfile line was added above */
  default:
  break;
  }
@@ -3633,6 +3765,9 @@
     funcbase);
  }
 
+ if (need_constructor)
+ add_constructor (c);
+
  if (need_dispose)
  add_dispose (c);
 
@@ -4441,15 +4576,24 @@
 
  make_bases ();
  make_inits ((Class *)class);
- if(unreftors > 0) {
+
+ find_constructor ((Class *)class);
+ if (user_constructor != NULL)
+ need_constructor = TRUE;
+
+ find_dispose ((Class *)class);
+ if (unreftors > 0 ||
+    dispose_handler != NULL ||
+    user_dispose_method != NULL)
  need_dispose = TRUE;
- find_dispose ((Class *)class);
- }
+
+ find_finalize ((Class *)class);
  if (destructors > 0 ||
-    privates > 0) {
+    privates > 0 ||
+    user_finalize_method != NULL) {
  need_finalize = TRUE;
- find_finalize ((Class *)class);
  }
+
  check_bad_symbols ((Class *)class);
  check_duplicate_symbols ((Class *)class);
  check_duplicate_overrides ((Class *)class);
--- src/parse.y.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/parse.y 2008-01-29 00:24:30.000000000 +0100
@@ -146,7 +146,7 @@
 
 static void
 push_function (int scope, int method, char *oid, char *id,
-       GString *cbuf, int line_no, int ccode_line,
+       GString *attr, GString *cbuf, int line_no, int ccode_line,
        gboolean vararg, GList *flags)
 {
  Node *node;
@@ -155,7 +155,11 @@
 
  g_assert(scope != CLASS_SCOPE);
       
- if(method == INIT_METHOD || method == CLASS_INIT_METHOD) {
+ if(method == INIT_METHOD
+   || method == CLASS_INIT_METHOD
+   || method == CONSTRUCTOR_METHOD
+   || method == DISPOSE_METHOD
+   || method == FINALIZE_METHOD) {
  type = (Type *)node_new (TYPE_NODE,
  "name", "void",
  NULL);
@@ -207,6 +211,7 @@
  "args:steal", funcargs,
  "onerror:steal", onerror,
  "defreturn:steal", defreturn,
+ "attr:steal", attr ? attr->str : NULL,
  "cbuf:steal", c_cbuf,
  "line_no", line_no,
  "ccode_line", ccode_line,
@@ -216,6 +221,8 @@
 
  last_added_method = (Method *)node;
 
+ if(attr)
+ g_string_free(attr, FALSE);
  if(cbuf)
  g_string_free(cbuf,
       /*only free segment if we haven't passed it
@@ -405,7 +412,7 @@
  push_funcarg ("self", FALSE);
 
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       get_id, get_cbuf, get_lineno,
+       get_id, NULL, get_cbuf, get_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -439,7 +446,7 @@
 
  typestack = g_list_prepend (typestack, node2);
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       set_id, set_cbuf, set_lineno,
+       set_id, NULL, set_cbuf, set_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -677,7 +684,7 @@
 %token CONST VOID STRUCT UNION ENUM THREEDOTS
 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
 
-%token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM SINGLE_CHAR
+%token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM_OR_ATTR BITFIELD SINGLE_CHAR
 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE STRING
 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE PROPERTY ARGUMENT
 %token <line> VIRTUAL SIGNAL OVERRIDE
@@ -982,7 +989,7 @@
 variable: scope type TOKEN varoptions ';' {
  push_variable($<id>3, the_scope,$<line>1, NULL);
  }
- | scope type TOKEN ARRAY_DIM varoptions ';' {
+ | scope type TOKEN array_dim varoptions ';' {
  push_variable($<id>3, the_scope, $<line>1, $<id>4);
  }
  ;
@@ -1678,9 +1685,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>3,NULL,
-      $<id>5, $<cbuf>10,$<line>1,
+      $<id>5, NULL, $<cbuf>10,$<line>1,
       ccode_line, vararg, $<list>2);
  }
+ | attrs SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>4,NULL,
+      $<id>6, $<cbuf>1, $<cbuf>11,$<line>2,
+      ccode_line, vararg, $<list>3);
+ }
  | scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("signal without 'self' as "
@@ -1694,9 +1717,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>4, NULL,
-      $<id>6, $<cbuf>11, $<line>2,
+      $<id>6, NULL, $<cbuf>11, $<line>2,
       ccode_line, vararg, $<list>3);
  }
+ | attrs scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>5, NULL,
+      $<id>7, $<cbuf>1, $<cbuf>12, $<line>3,
+      ccode_line, vararg, $<list>4);
+ }
  | VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("virtual method without 'self' as "
@@ -1710,7 +1749,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>1,
+      NULL, $<cbuf>9, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | attrs VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>5,
+      $<cbuf>1, $<cbuf>10, $<line>2,
       ccode_line, vararg, NULL);
  }
  | scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1726,7 +1781,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>2,
+      NULL, $<cbuf>9, $<line>2,
+      ccode_line, vararg, NULL);
+ }
+ | attrs scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>5,
+      $<cbuf>1, $<cbuf>10, $<line>3,
       ccode_line, vararg, NULL);
  }
  | VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1737,12 +1808,23 @@
  YYERROR;
  }
  push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
-      $<id>3, $<cbuf>8, $<line>1,
+      $<id>3, NULL, $<cbuf>8, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | attrs VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
+      $<id>4, $<cbuf>1, $<cbuf>9, $<line>2,
       ccode_line, vararg, NULL);
  }
  | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode {
  push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
-      $<id>6, $<cbuf>11,
+      $<id>6, NULL, $<cbuf>11,
       $<line>1, ccode_line,
       vararg, NULL);
  }
@@ -1753,32 +1835,74 @@
  YYERROR;
  }
  push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
-      $<cbuf>8, $<line>1, ccode_line,
+      NULL, $<cbuf>8, $<line>1, ccode_line,
+      vararg, NULL);
+ }
+ | attrs scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, REGULAR_METHOD, NULL, $<id>4,
+      $<cbuf>1, $<cbuf>9, $<line>2, ccode_line,
       vararg, NULL);
  }
  | TOKEN '(' TOKEN ')' codenocode {
  if(strcmp($<id>1, "init")==0) {
  push_init_arg($<id>3,FALSE);
  push_function(NO_SCOPE, INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else if(strcmp($<id>1, "class_init")==0) {
  push_init_arg($<id>3,TRUE);
  push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "constructor")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, CONSTRUCTOR_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "dispose")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, DISPOSE_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "finalize")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, FINALIZE_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else {
  g_free($<id>1);
  g_free($<id>3);
  g_string_free($<cbuf>5,TRUE);
  yyerror(_("parse error "
-  "(untyped blocks must be init or "
-  "class_init)"));
+  "(untyped blocks must be init, "
+  "class_init, constructor, dispose "
+  "or finalize)"));
  YYERROR;
  }
  }
  ;
 
+attrs:
+ '[' CCODE {
+ $<cbuf>$ = $<cbuf>2;
+ }
+ | ARRAY_DIM_OR_ATTR {
+ int len = strlen($<id>1);
+
+ g_assert($<id>1[0] == '[');
+ g_assert(len >= 2 && $<id>1[len - 1] == ']');
+
+ /* strip the brackets */
+ $<cbuf>$ = g_string_new_len($<id>1 + 1, len - 2);
+ g_free($<id>1);
+ }
+ ;
+
 returnvals: TOKEN retcode {
  g_free(onerror); onerror = NULL;
  g_free(defreturn); defreturn = NULL;
@@ -1900,7 +2024,7 @@
 arg: type TOKEN {
  push_funcarg($<id>2,NULL);
  }
- | type TOKEN ARRAY_DIM {
+ | type TOKEN array_dim {
  push_funcarg($<id>2,$<id>3);
  }
  | type TOKEN '(' TOKEN checklist ')' {
@@ -1911,7 +2035,7 @@
  g_free($<id>4);
  push_funcarg($<id>2,NULL);
  }
- | type TOKEN ARRAY_DIM '(' TOKEN checklist ')' {
+ | type TOKEN array_dim '(' TOKEN checklist ')' {
  if(strcmp($<id>5,"check")!=0) {
  yyerror(_("parse error"));
  YYERROR;
@@ -2105,5 +2229,10 @@
  | SINGLE_CHAR { $<id>$ = $<id>1; }
  | TOKEN { $<id>$ = $<id>1; }
  ;
+
+array_dim:
+ ARRAY_DIM_OR_ATTR
+ | BITFIELD
+ ;
 
 %%
--- src/treefuncs.def.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/treefuncs.def 2008-01-29 00:24:30.000000000 +0100
@@ -40,6 +40,9 @@
  REGULAR_METHOD,
  INIT_METHOD,
  CLASS_INIT_METHOD,
+ CONSTRUCTOR_METHOD,
+ DISPOSE_METHOD,
+ FINALIZE_METHOD,
  VIRTUAL_METHOD,
  SIGNAL_LAST_METHOD,
  SIGNAL_FIRST_METHOD,
@@ -126,6 +129,7 @@
   NODELIST args
   STRING onerror
   STRING defreturn
+  STRING attr
   STRING cbuf
   INT line_no
   INT ccode_line



--
to unsubscribe:
send mail to minimalist@... with "unsubscribe gob-list" in the subject

attachment0 (196 bytes) Download Attachment

Re: patch allowing to add GCC attributes to methods

by Jean-Yves Lefort :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, 28 Jan 2008 18:10:20 +0100
Jean-Yves Lefort <jylefort@...> wrote:

> The attached patch allows to add GCC attributes to methods, using a
> syntax borrowed from C#.

I've fixed my other patch (gob2-2.0.15-gobject-overrides.diff), so I'm
attaching the new unified patch.

--
Jean-Yves Lefort <jylefort@...>

[gob2-2.0.15-gobject-overrides-and-attr.diff]

--- src/lexer.l.orig 2007-09-28 06:26:49.000000000 +0200
+++ src/lexer.l 2008-01-29 01:25:46.000000000 +0100
@@ -31,6 +31,7 @@
 #include "main.h"
 #include "util.h"
 
+static int bracket_depth = 0;
 static int parenth_depth = 0;
 static int before_comment
 /* New flex is on drugs */
@@ -102,6 +103,7 @@
 
 %x COMMENT
 %x C_CODE
+%x ATTR_CODE
 %x CODE_STRING
 %x CLASS_CODE
 %x CLASS_STRING
@@ -267,7 +269,7 @@
  add_to_cbuf(yytext);
  }
 
-<C_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
+<C_CODE,ATTR_CODE>\/\/.*$ { add_to_cbuf(yytext); /*comment, ignore*/ }
 <CLASS_CODE>\/\/.*$ { ; /*comment, ignore*/ }
 <CLASS_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
 <PROPERTY_CODE_I>\/\/.*$ { ; /*comment, ignore*/ }
@@ -277,20 +279,25 @@
  BEGIN(COMMENT);
  before_comment = C_CODE;
 }
+<ATTR_CODE>\/\* {
+ add_to_cbuf(yytext);
+ BEGIN(COMMENT);
+ before_comment = ATTR_CODE;
+}
 <CLASS_CODE>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE; }
 <CLASS_CODE_I>\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE_I; }
 <PROPERTY_CODE_I>\/\* {BEGIN(COMMENT); before_comment = PROPERTY_CODE_I; }
 <COMMENT>\*\/ {
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  BEGIN(before_comment);
  }
 <COMMENT>. {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 <COMMENT>\n {
  /* comment, ignore */
- if(before_comment == C_CODE) add_to_cbuf(yytext);
+ if(before_comment == C_CODE || before_comment == ATTR_CODE) add_to_cbuf(yytext);
  }
 
 ^\%(a|all)\{ {
@@ -353,14 +360,14 @@
  return code_type;
  }
 
-<C_CODE>\'\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\{\' { add_to_cbuf(yytext); }
-<C_CODE>\'\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\}\' { add_to_cbuf(yytext); }
-<C_CODE>\'\"\' { add_to_cbuf(yytext); }
-<C_CODE>\'\\\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\{\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\}\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\"\' { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\'\\\"\' { add_to_cbuf(yytext); }
 
-<C_CODE>\\. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\\. { add_to_cbuf(yytext); }
 
 
 <C_CODE>\" {
@@ -368,6 +375,11 @@
  before_string = C_CODE;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\" {
+ BEGIN(CODE_STRING);
+ before_string = ATTR_CODE;
+ add_to_cbuf(yytext);
+ }
 <PROPERTY_CODE_I>\" {
  BEGIN(CODE_STRING);
  before_string = PROPERTY_CODE_I;
@@ -391,6 +403,10 @@
  parenth_depth++;
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\[ {
+ bracket_depth++;
+ add_to_cbuf(yytext);
+ }
 <C_CODE>\} {
  parenth_depth--;
  if(parenth_depth<0) {
@@ -403,9 +419,21 @@
  }
  add_to_cbuf(yytext);
  }
+<ATTR_CODE>\] {
+ bracket_depth--;
+ if(bracket_depth<0) {
+ REJECT;
+ } else if(bracket_depth==0) {
+ BEGIN(CLASS_CODE_I);
+ yylval.cbuf = cbuf;
+ cbuf = NULL;
+ return CCODE;
+ }
+ add_to_cbuf(yytext);
+ }
 
-<C_CODE>. { add_to_cbuf(yytext); }
-<C_CODE>\n { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>. { add_to_cbuf(yytext); }
+<C_CODE,ATTR_CODE>\n { add_to_cbuf(yytext); }
 
 class {
  static int found_classes = 0;
@@ -588,12 +616,12 @@
 
 <CLASS_CODE_I>(\[[0-9]*\]|\[[A-Za-z_][A-Za-z0-9_]*\])+ {
  yylval.id = g_strdup(yytext);
- return ARRAY_DIM;
+ return ARRAY_DIM_OR_ATTR;
  }
 <CLASS_CODE_I>:[0-9]+ {
  /* cheat for bitfield */
  yylval.id = g_strdup(yytext);
- return ARRAY_DIM;
+ return BITFIELD;
  }
 <CLASS_CODE>\{ {
  BEGIN(CLASS_CODE_I);
@@ -612,6 +640,13 @@
  BEGIN(INITIAL);
  return '}';
  }
+<CLASS_CODE_I>\[ {
+ BEGIN(ATTR_CODE);
+ bracket_depth=1;
+ yylval.line = line_no;
+ clear_cbuf();
+ return '[';
+ }
 
 <CLASS_CODE,CLASS_CODE_I,INITIAL,PROPERTY_CODE,PROPERTY_CODE_I>[\f\t ] ;  /*ignore*/
 
--- src/main.c.orig 2007-10-17 16:49:04.000000000 +0200
+++ src/main.c 2008-01-29 01:25:46.000000000 +0100
@@ -92,11 +92,16 @@
 static gboolean special_array[SPECIAL_LAST] = {0};
 static gboolean any_special = FALSE;
 
+static gboolean need_constructor = FALSE;
+static Method * user_constructor = NULL;
+
 static gboolean need_dispose = FALSE;
 static Method * dispose_handler = NULL;
+static Method * user_dispose_method = NULL;
 
 static gboolean need_finalize = FALSE;
 static Method * finalize_handler = NULL;
+static Method * user_finalize_method = NULL;
 
 FILE *out = NULL;
 FILE *outh = NULL;
@@ -189,21 +194,25 @@
  g_free(s);
 }
 
-
-static void
-print_method (FILE *fp,
-      const char *typeprefix,
-      const char *nameprefix,
-      const char *subnameprefix,
-      const char *namepostfix,
-      const char *afterargs,
-      const char *postfix,
-      const Method *m,
-      gboolean one_arg_per_line,
-      gboolean no_funcbase,
-      gboolean kill_underscore,
-      gboolean first_unused,
-      gboolean fake_names)
+typedef enum
+{
+  PRINT_METHOD_ONE_ARG_PER_LINE = 1 << 0,
+  PRINT_METHOD_NO_FUNCBASE = 1 << 1,
+  PRINT_METHOD_FIRST_UNUSED = 1 << 2,
+  PRINT_METHOD_FAKE_NAMES = 1 << 3,
+  PRINT_METHOD_NO_ATTR = 1 << 4
+} PrintMethodFlags;
+
+static void
+print_method2 (FILE *fp,
+       const char *typeprefix,
+       const char *nameprefix,
+       const char *subnameprefix,
+       const char *namepostfix,
+       const char *afterargs,
+       const char *postfix,
+       const Method *m,
+       PrintMethodFlags flags)
 {
  GList *li;
  const char *id;
@@ -213,7 +222,7 @@
 
  id = m->id;
 
- if(no_funcbase)
+ if ((flags & PRINT_METHOD_NO_FUNCBASE) != 0)
  out_printf(fp, "%s%s%s%s(",
    nameprefix, subnameprefix, id, namepostfix);
  else
@@ -229,19 +238,19 @@
  if ( ! no_gnu &&
      ! for_cpp && /* g++ has a cow with this */
     li == m->args &&
-    first_unused) {
+     (flags & PRINT_METHOD_FIRST_UNUSED) != 0) {
  unused = " G_GNUC_UNUSED";
  }
 
  print_type(fp, arg->atype, FALSE);
- if (fake_names)
+ if ((flags & PRINT_METHOD_FAKE_NAMES) != 0)
  out_printf (fp, "___fake___");
  if(li->next)
  out_printf(fp, "%s%s%s,%s", arg->name,
    arg->atype->postfix ?
    arg->atype->postfix : "",
    unused,
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  else
  out_printf(fp, "%s%s%s", arg->name,
    arg->atype->postfix ?
@@ -250,11 +259,54 @@
  }
  if(m->vararg)
  out_printf(fp, ",%s...",
-   one_arg_per_line ? "\n\t\t\t\t\t" : " ");
+   (flags & PRINT_METHOD_ONE_ARG_PER_LINE) != 0 ? "\n\t\t\t\t\t" : " ");
  } else {
  out_printf(fp, "void");
  }
- out_printf(fp, "%s)%s", afterargs, postfix);
+
+ out_printf(fp, "%s)", afterargs);
+
+ if (m->attr && (flags & PRINT_METHOD_NO_ATTR) == 0)
+ out_printf(fp, " %s", m->attr);
+
+ out_printf(fp, "%s", postfix);
+}
+
+static void
+print_method (FILE *fp,
+      const char *typeprefix,
+      const char *nameprefix,
+      const char *subnameprefix,
+      const char *namepostfix,
+      const char *afterargs,
+      const char *postfix,
+      const Method *m,
+      gboolean one_arg_per_line,
+      gboolean no_funcbase,
+      gboolean kill_underscore,
+      gboolean first_unused,
+      gboolean fake_names)
+{
+ PrintMethodFlags flags = 0;
+
+ if (one_arg_per_line)
+ flags |= PRINT_METHOD_ONE_ARG_PER_LINE;
+ if (no_funcbase)
+ flags |= PRINT_METHOD_NO_FUNCBASE;
+ if (first_unused)
+ flags |= PRINT_METHOD_FIRST_UNUSED;
+ if (fake_names)
+ flags |= PRINT_METHOD_FAKE_NAMES;
+
+ print_method2(fp,
+      typeprefix,
+      nameprefix,
+      subnameprefix,
+      namepostfix,
+      afterargs,
+      postfix,
+      m,
+      flags);
 }
 
 static gboolean
@@ -269,6 +321,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -291,6 +346,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -330,6 +388,9 @@
 
  if(m->method == INIT_METHOD ||
    m->method == CLASS_INIT_METHOD ||
+   m->method == CONSTRUCTOR_METHOD ||
+   m->method == DISPOSE_METHOD ||
+   m->method == FINALIZE_METHOD ||
    m->method == OVERRIDE_METHOD)
  continue;
 
@@ -371,11 +432,13 @@
 
  /* 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_method2(outh, "\t/*signal*/", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
  else
- print_method(outh, "\t", "(* ", "", ") ", "", ";\n",
-     m, FALSE, TRUE, TRUE, FALSE, FALSE);
+ print_method2(outh, "\t", "(* ", "", ") ", "", ";\n",
+      m, PRINT_METHOD_NO_FUNCBASE |
+      PRINT_METHOD_NO_ATTR);
 }
 
 static void
@@ -422,8 +485,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_after */
@@ -433,8 +499,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data))\n", m->id);
 
  /* connect_data */
@@ -445,8 +514,11 @@
     "\"%s\","
     "(GCallback) __extension__ ({",
     funcbase, m->id, macrobase, typebase, m->id);
- print_method (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
-      " = (func); ", m, FALSE, TRUE, TRUE, FALSE, TRUE);
+ print_method2 (outh, "", "(* ___", "", ") ", ", gpointer ___data ",
+       " = (func); ", m,
+       PRINT_METHOD_NO_FUNCBASE
+       | PRINT_METHOD_FAKE_NAMES
+       | PRINT_METHOD_NO_ATTR);
  out_printf (outh, "___%s; }), (data), (destroy_data), (GConnectFlags)(flags))\n", m->id);
  }
 }
@@ -526,9 +598,9 @@
    m->method == SIGNAL_FIRST_METHOD ||
    m->method == VIRTUAL_METHOD) {
  if(m->cbuf)
- print_method(out,
-     "static ", "___real_", "", " ", "", ";\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out,
+      "static ", "___real_", "", " ", "", ";\n",
+      m, PRINT_METHOD_NO_ATTR);
  }
  /* no else, here, it might still have a private prototype, it's not
  * exclusive */
@@ -537,15 +609,16 @@
     m->cbuf)) {
  /* add unique ID */
  char *s = g_strdup_printf("___%x_", (guint)m->unique_id);
- print_method(out, "static ", s, "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+ print_method(out, "static ", s, "", " ", "", ";\n",
      m, FALSE, FALSE, FALSE, FALSE, FALSE);
  g_free(s);
  } else if(m->scope == PRIVATE_SCOPE ||
   m->method == INIT_METHOD ||
-  m->method == CLASS_INIT_METHOD) {
- print_method(out, "static ", "", "", " ", "",
-     no_gnu?";\n":" G_GNUC_UNUSED;\n",
+  m->method == CLASS_INIT_METHOD ||
+  m->method == CONSTRUCTOR_METHOD ||
+  m->method == DISPOSE_METHOD ||
+  m->method == FINALIZE_METHOD) {
+ print_method(out, "static ", "", "", " ", "", ";\n",
      m, FALSE, FALSE, TRUE, FALSE, FALSE);
  }
 }
@@ -629,66 +702,68 @@
  }
 }
 
-static void
-find_dispose(const Class *cl)
+static Method *
+find_method(const Class *cl, int method, const char *id)
 {
  GList *li;
 
- dispose_handler = NULL;
  for(li=cl->nodes;li;li=g_list_next(li)) {
  Node *n = li->data;
  if(n->type == METHOD_NODE) {
  Method *m = (Method *)n;
- if(m->method == OVERRIDE_METHOD &&
-   strcmp(m->id, "dispose")==0) {
- if(strcmp(m->otype, "G:Object") != 0) {
- error_print(GOB_ERROR, m->line_no,
-    "dispose method override "
-    "of class other then "
-    "G:Object");
- }
- if(g_list_length(m->args) != 1) {
- error_print(GOB_ERROR, m->line_no,
-    "dispose method override "
-    "with more then one "
-    "parameter");
- }
- dispose_handler = m;
- break;
- }
+ if (m->method == method
+    && (id == NULL || strcmp(m->id, id)==0))
+ return m;
  }
  }
+
+ return NULL;
 }
 
 static void
-find_finalize(const Class *cl)
+find_constructor(const Class *cl)
 {
- GList *li;
+ user_constructor = find_method(cl, CONSTRUCTOR_METHOD, NULL);
+}
 
- finalize_handler = NULL;
- for(li=cl->nodes;li;li=g_list_next(li)) {
- Node *n = li->data;
- if(n->type == METHOD_NODE) {
- Method *m = (Method *)n;
- if(m->method == OVERRIDE_METHOD &&
-   strcmp(m->id, "finalize")==0) {
- if(strcmp(m->otype, "G:Object") != 0) {
- error_print(GOB_ERROR, m->line_no,
-    "finalize method override "
-    "of class other then "
-    "G:Object");
- }
- if(g_list_length(m->args) != 1) {
- error_print(GOB_ERROR, m->line_no,
-    "finalize method override "
-    "with more then one "
-    "parameter");
- }
- finalize_handler = m;
- break;
- }
- }
+static void
+find_dispose(const Class *cl)
+{
+ dispose_handler = find_method(cl, OVERRIDE_METHOD, "dispose");
+ if (dispose_handler != NULL) {
+ if(strcmp(dispose_handler->otype, "G:Object") != 0)
+ error_print(GOB_ERROR, dispose_handler->line_no,
+    "dispose method override "
+    "of class other then "
+    "G:Object");
+ if(g_list_length(dispose_handler->args) != 1)
+ error_print(GOB_ERROR, dispose_handler->line_no,
+    "dispose method override "
+    "with more then one "
+    "parameter");
+ }
+
+ user_dispose_method = find_method(cl, DISPOSE_METHOD, NULL);
+}
+
+static void
+find_finalize(const Class *cl)
+{
+ finalize_handler = find_method(cl, OVERRIDE_METHOD, "finalize");
+ if (finalize_handler != NULL) {
+ if(strcmp(finalize_handler->otype, "G:Object") != 0)
+ error_print(GOB_ERROR, finalize_handler->line_no,
+    "finalize method override "
+    "of class other then "
+    "G:Object");
+ if(g_list_length(finalize_handler->args) != 1)
+ error_print(GOB_ERROR, finalize_handler->line_no,
+    "finalize method override "
+    "with more then one "
+    "parameter");
  }
+
+ user_finalize_method = find_method(cl, FINALIZE_METHOD, NULL);
 }
 
 
@@ -2118,6 +2193,33 @@
 }
 
 static void
+add_constructor (Class *c)
+{
+ out_printf(out, "\nstatic GObject *\n"
+   "___constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties)\n"
+   "{\n");
+ out_printf(out,
+   "#define __GOB_FUNCTION__ \"%s::constructor\"\n",
+   c->otype);
+
+ out_printf(out, "\tGObject *obj_self;\n");
+ out_printf(out, "\t%s *self;\n", typebase);
+
+ out_printf(out, "\tobj_self = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties, construct_properties);\n");
+ out_printf(out, "\tself = %s (obj_self);\n", macrobase);
+
+ if (user_constructor->line_no > 0)
+ out_addline_infile (out, user_constructor->line_no);
+ out_printf (out, "\t%s_constructor (self);\n", funcbase);
+ if (user_constructor->line_no > 0)
+ out_addline_outfile (out);
+
+ out_printf(out, "\treturn obj_self;\n");
+ out_printf(out, "}\n"
+   "#undef __GOB_FUNCTION__\n\n");
+}
+
+static void
 add_dispose (Class *c)
 {
  out_printf(out, "\nstatic void\n"
@@ -2127,7 +2229,7 @@
    "#define __GOB_FUNCTION__ \"%s::dispose\"\n",
    c->otype);
 
- if (unreftors > 0) {
+ if (unreftors > 0 || user_dispose_method != NULL) {
  out_printf (out, "\t%s *self%s = %s (obj_self);\n",
     typebase,
     ! no_gnu ? " G_GNUC_UNUSED" : "",
@@ -2143,6 +2245,14 @@
  if (dispose_handler->line_no > 0)
  out_addline_outfile (out);
  } else {
+ if (user_dispose_method != NULL) {
+ if (user_dispose_method->line_no > 0)
+ out_addline_infile (out, user_dispose_method->line_no);
+ out_printf (out, "\t%s_dispose (self);\n", funcbase);
+ if (user_dispose_method->line_no > 0)
+ out_addline_outfile (out);
+ }
+
  out_printf (out,
     "\tif (G_OBJECT_CLASS (parent_class)->dispose) \\\n"
     "\t\t(* G_OBJECT_CLASS (parent_class)->dispose) (obj_self);\n");
@@ -2178,7 +2288,8 @@
    c->otype);
 
  if (privates > 0 ||
-    destructors > 0) {
+    destructors > 0 ||
+    user_finalize_method != NULL) {
  const char *unused = "";
  if ( ! no_gnu)
  unused = " G_GNUC_UNUSED";
@@ -2202,6 +2313,14 @@
  if(finalize_handler->line_no > 0)
  out_addline_outfile(out);
  } else {
+ if (user_finalize_method != NULL) {
+ if (user_finalize_method->line_no > 0)
+ out_addline_infile (out, user_finalize_method->line_no);
+ out_printf (out, "\t%s_finalize (self);\n", funcbase);
+ if (user_finalize_method->line_no > 0)
+ out_addline_outfile (out);
+ }
+
  out_printf(out,
    "\tif(G_OBJECT_CLASS(parent_class)->finalize) \\\n"
    "\t\t(* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);\n");
@@ -2333,6 +2452,7 @@
  if (set_properties > 0 ||
     get_properties > 0 ||
     signals > 0 ||
+    need_constructor ||
     need_dispose ||
     need_finalize) {
  out_printf(out,
@@ -2381,6 +2501,9 @@
 
  /* if there are no handlers for these things, we
  * need to set them up here */
+ if(need_constructor)
+ out_printf(out, "\tg_object_class->constructor "
+   "= ___constructor;\n");
  if(need_dispose && !dispose_handler)
  out_printf(out, "\tg_object_class->dispose "
    "= ___dispose;\n");
@@ -2831,11 +2954,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, TRUE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2844,11 +2967,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope == PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile (out);
 
  out_printf (out, "{\n");
@@ -2966,8 +3089,8 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
@@ -2975,11 +3098,11 @@
  if(m->line_no > 0)
  out_addline_infile(out, m->line_no);
  if(m->scope==PRIVATE_SCOPE)
- print_method(out, "static ", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "static ", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  else /* PUBLIC, PROTECTED */
- print_method(out, "", "\n", "", " ", "", "\n",
-     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method2(out, "", "\n", "", " ", "", "\n",
+      m, PRINT_METHOD_NO_ATTR);
  out_addline_outfile(out);
  out_printf(out, "{\n"
  "\t%sClass *klass;\n", typebase);
@@ -3024,8 +3147,9 @@
  break;
  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);
+ print_method2(out, "static ", "\n___real_", "", " ", "", "\n",
+      m, PRINT_METHOD_FIRST_UNUSED
+      | PRINT_METHOD_NO_ATTR);
  print_method_body(m, FALSE, TRUE);
  /* the outfile line was added above */
  break;
@@ -3064,6 +3188,15 @@
  /* the outfile line was added above */
  out_printf(out, "#undef PARENT_HANDLER\n");
  break;
+ case CONSTRUCTOR_METHOD:
+ case DISPOSE_METHOD:
+ case FINALIZE_METHOD:
+ if(m->line_no > 0)
+ out_addline_infile(out, m->line_no);
+ print_method(out, "static ", "\n", "", " ", "", "\n",
+     m, FALSE, FALSE, TRUE, FALSE, FALSE);
+ print_method_body(m, TRUE, TRUE);
+ /* the outfile line was added above */
  default:
  break;
  }
@@ -3633,6 +3766,9 @@
     funcbase);
  }
 
+ if (need_constructor)
+ add_constructor (c);
+
  if (need_dispose)
  add_dispose (c);
 
@@ -4441,15 +4577,24 @@
 
  make_bases ();
  make_inits ((Class *)class);
- if(unreftors > 0) {
+
+ find_constructor ((Class *)class);
+ if (user_constructor != NULL)
+ need_constructor = TRUE;
+
+ find_dispose ((Class *)class);
+ if (unreftors > 0 ||
+    dispose_handler != NULL ||
+    user_dispose_method != NULL)
  need_dispose = TRUE;
- find_dispose ((Class *)class);
- }
+
+ find_finalize ((Class *)class);
  if (destructors > 0 ||
-    privates > 0) {
+    privates > 0 ||
+    user_finalize_method != NULL) {
  need_finalize = TRUE;
- find_finalize ((Class *)class);
  }
+
  check_bad_symbols ((Class *)class);
  check_duplicate_symbols ((Class *)class);
  check_duplicate_overrides ((Class *)class);
--- src/parse.y.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/parse.y 2008-01-29 01:25:46.000000000 +0100
@@ -146,7 +146,7 @@
 
 static void
 push_function (int scope, int method, char *oid, char *id,
-       GString *cbuf, int line_no, int ccode_line,
+       GString *attr, GString *cbuf, int line_no, int ccode_line,
        gboolean vararg, GList *flags)
 {
  Node *node;
@@ -155,7 +155,11 @@
 
  g_assert(scope != CLASS_SCOPE);
       
- if(method == INIT_METHOD || method == CLASS_INIT_METHOD) {
+ if(method == INIT_METHOD
+   || method == CLASS_INIT_METHOD
+   || method == CONSTRUCTOR_METHOD
+   || method == DISPOSE_METHOD
+   || method == FINALIZE_METHOD) {
  type = (Type *)node_new (TYPE_NODE,
  "name", "void",
  NULL);
@@ -207,6 +211,7 @@
  "args:steal", funcargs,
  "onerror:steal", onerror,
  "defreturn:steal", defreturn,
+ "attr:steal", attr ? attr->str : NULL,
  "cbuf:steal", c_cbuf,
  "line_no", line_no,
  "ccode_line", ccode_line,
@@ -216,6 +221,8 @@
 
  last_added_method = (Method *)node;
 
+ if(attr)
+ g_string_free(attr, FALSE);
  if(cbuf)
  g_string_free(cbuf,
       /*only free segment if we haven't passed it
@@ -405,7 +412,7 @@
  push_funcarg ("self", FALSE);
 
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       get_id, get_cbuf, get_lineno,
+       get_id, NULL, get_cbuf, get_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -439,7 +446,7 @@
 
  typestack = g_list_prepend (typestack, node2);
  push_function (PUBLIC_SCOPE, REGULAR_METHOD, NULL,
-       set_id, set_cbuf, set_lineno,
+       set_id, NULL, set_cbuf, set_lineno,
        lineno, FALSE, NULL);
  }
 
@@ -677,7 +684,7 @@
 %token CONST VOID STRUCT UNION ENUM THREEDOTS
 %token SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR
 
-%token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM SINGLE_CHAR
+%token <id> TOKEN NUMBER TYPETOKEN ARRAY_DIM_OR_ATTR BITFIELD SINGLE_CHAR
 %token <cbuf> CCODE HTCODE PHCODE HCODE ACODE ATCODE STRING
 %token <line> PUBLIC PRIVATE PROTECTED CLASSWIDE PROPERTY ARGUMENT
 %token <line> VIRTUAL SIGNAL OVERRIDE
@@ -982,7 +989,7 @@
 variable: scope type TOKEN varoptions ';' {
  push_variable($<id>3, the_scope,$<line>1, NULL);
  }
- | scope type TOKEN ARRAY_DIM varoptions ';' {
+ | scope type TOKEN array_dim varoptions ';' {
  push_variable($<id>3, the_scope, $<line>1, $<id>4);
  }
  ;
@@ -1678,9 +1685,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>3,NULL,
-      $<id>5, $<cbuf>10,$<line>1,
+      $<id>5, NULL, $<cbuf>10,$<line>1,
       ccode_line, vararg, $<list>2);
  }
+ | attrs SIGNAL flags fullsigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>4,NULL,
+      $<id>6, $<cbuf>1, $<cbuf>11,$<line>2,
+      ccode_line, vararg, $<list>3);
+ }
  | scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("signal without 'self' as "
@@ -1694,9 +1717,25 @@
  YYERROR;
  }
  push_function(the_scope, $<sigtype>4, NULL,
-      $<id>6, $<cbuf>11, $<line>2,
+      $<id>6, NULL, $<cbuf>11, $<line>2,
       ccode_line, vararg, $<list>3);
  }
+ | attrs scope SIGNAL flags simplesigtype type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("signal without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, $<sigtype>5, NULL,
+      $<id>7, $<cbuf>1, $<cbuf>12, $<line>3,
+      ccode_line, vararg, $<list>4);
+ }
  | VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
  if(!has_self) {
  yyerror(_("virtual method without 'self' as "
@@ -1710,7 +1749,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>1,
+      NULL, $<cbuf>9, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | attrs VIRTUAL scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>5,
+      $<cbuf>1, $<cbuf>10, $<line>2,
       ccode_line, vararg, NULL);
  }
  | scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1726,7 +1781,23 @@
  YYERROR;
  }
  push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>4,
-      $<cbuf>9, $<line>2,
+      NULL, $<cbuf>9, $<line>2,
+      ccode_line, vararg, NULL);
+ }
+ | attrs scope VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, VIRTUAL_METHOD, NULL, $<id>5,
+      $<cbuf>1, $<cbuf>10, $<line>3,
       ccode_line, vararg, NULL);
  }
  | VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
@@ -1737,12 +1808,23 @@
  YYERROR;
  }
  push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
-      $<id>3, $<cbuf>8, $<line>1,
+      $<id>3, NULL, $<cbuf>8, $<line>1,
+      ccode_line, vararg, NULL);
+ }
+ | attrs VIRTUAL type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(!has_self) {
+ yyerror(_("virtual method without 'self' as "
+  "first parameter"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(PUBLIC_SCOPE, VIRTUAL_METHOD, NULL,
+      $<id>4, $<cbuf>1, $<cbuf>9, $<line>2,
       ccode_line, vararg, NULL);
  }
  | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' returnvals codenocode {
  push_function(NO_SCOPE, OVERRIDE_METHOD, $<id>3,
-      $<id>6, $<cbuf>11,
+      $<id>6, NULL, $<cbuf>11,
       $<line>1, ccode_line,
       vararg, NULL);
  }
@@ -1753,32 +1835,74 @@
  YYERROR;
  }
  push_function(the_scope, REGULAR_METHOD, NULL, $<id>3,
-      $<cbuf>8, $<line>1, ccode_line,
+      NULL, $<cbuf>8, $<line>1, ccode_line,
+      vararg, NULL);
+ }
+ | attrs scope type TOKEN '(' funcargs ')' returnvals codenocode {
+ if(the_scope == CLASS_SCOPE) {
+ yyerror(_("a method cannot be of class scope"));
+ free_all_global_state();
+ YYERROR;
+ }
+ push_function(the_scope, REGULAR_METHOD, NULL, $<id>4,
+      $<cbuf>1, $<cbuf>9, $<line>2, ccode_line,
       vararg, NULL);
  }
  | TOKEN '(' TOKEN ')' codenocode {
  if(strcmp($<id>1, "init")==0) {
  push_init_arg($<id>3,FALSE);
  push_function(NO_SCOPE, INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else if(strcmp($<id>1, "class_init")==0) {
  push_init_arg($<id>3,TRUE);
  push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
-      $<id>1, $<cbuf>5, $<line>2,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "constructor")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, CONSTRUCTOR_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "dispose")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, DISPOSE_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
+      ccode_line, FALSE, NULL);
+ } else if(strcmp($<id>1, "finalize")==0) {
+ push_init_arg($<id>3, FALSE);
+ push_function(NO_SCOPE, FINALIZE_METHOD, NULL,
+      $<id>1, NULL, $<cbuf>5, $<line>2,
       ccode_line, FALSE, NULL);
  } else {
  g_free($<id>1);
  g_free($<id>3);
  g_string_free($<cbuf>5,TRUE);
  yyerror(_("parse error "
-  "(untyped blocks must be init or "
-  "class_init)"));
+  "(untyped blocks must be init, "
+  "class_init, constructor, dispose "
+  "or finalize)"));
  YYERROR;
  }
  }
  ;
 
+attrs:
+ '[' CCODE {
+ $<cbuf>$ = $<cbuf>2;
+ }
+ | ARRAY_DIM_OR_ATTR {
+ int len = strlen($<id>1);
+
+ g_assert($<id>1[0] == '[');
+ g_assert(len >= 2 && $<id>1[len - 1] == ']');
+
+ /* strip the brackets */
+ $<cbuf>$ = g_string_new_len($<id>1 + 1, len - 2);
+ g_free($<id>1);
+ }
+ ;
+
 returnvals: TOKEN retcode {
  g_free(onerror); onerror = NULL;
  g_free(defreturn); defreturn = NULL;
@@ -1900,7 +2024,7 @@
 arg: type TOKEN {
  push_funcarg($<id>2,NULL);
  }
- | type TOKEN ARRAY_DIM {
+ | type TOKEN array_dim {
  push_funcarg($<id>2,$<id>3);
  }
  | type TOKEN '(' TOKEN checklist ')' {
@@ -1911,7 +2035,7 @@
  g_free($<id>4);
  push_funcarg($<id>2,NULL);
  }
- | type TOKEN ARRAY_DIM '(' TOKEN checklist ')' {
+ | type TOKEN array_dim '(' TOKEN checklist ')' {
  if(strcmp($<id>5,"check")!=0) {
  yyerror(_("parse error"));
  YYERROR;
@@ -2105,5 +2229,10 @@
  | SINGLE_CHAR { $<id>$ = $<id>1; }
  | TOKEN { $<id>$ = $<id>1; }
  ;
+
+array_dim:
+ ARRAY_DIM_OR_ATTR
+ | BITFIELD
+ ;
 
 %%
--- src/treefuncs.def.orig 2007-03-09 18:46:14.000000000 +0100
+++ src/treefuncs.def 2008-01-29 01:25:46.000000000 +0100
@@ -40,6 +40,9 @@
  REGULAR_METHOD,
  INIT_METHOD,
  CLASS_INIT_METHOD,
+ CONSTRUCTOR_METHOD,
+ DISPOSE_METHOD,
+ FINALIZE_METHOD,
  VIRTUAL_METHOD,
  SIGNAL_LAST_METHOD,
  SIGNAL_FIRST_METHOD,
@@ -126,6 +129,7 @@
   NODELIST args
   STRING onerror
   STRING defreturn
+  STRING attr
   STRING cbuf
   INT line_no
   INT ccode_line



--
to unsubscribe:
send mail to minimalist@... with "unsubscribe gob-list" in the subject

attachment0 (196 bytes) Download Attachment