patch adding first-class support of constructor/dispose/finalize methods

Jean-Yves Lefort <[email protected]> Mon, 21 Jan 2008 01:24:53 +0100
Newsgroups gmane.comp.gnome.devtools.gob.general
Message-ID <[email protected]>
This is a multi-part message in MIME format.

[email protected]
Content-Type: multipart/signed; protocol="application/pgp-signature";
 micalg="PGP-SHA1";
 boundary="Signature=_Mon__21_Jan_2008_01_24_53_+0100_mjxTGpyGhEDKKoaL"

--Signature=_Mon__21_Jan_2008_01_24_53_+0100_mjxTGpyGhEDKKoaL
Content-Type: multipart/mixed;
 boundary="Multipart=_Mon__21_Jan_2008_01_24_53_+0100_Hgdi2Ufe.N5IVgbd"


--Multipart=_Mon__21_Jan_2008_01_24_53_+0100_Hgdi2Ufe.N5IVgbd
Content-Type: text/plain; charset=US-ASCII
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

The attached patch allows to write:

	constructor (self)
	{
		/* hi */
	}

	dispose (self)
	{
		/* hi */
	}

	finalize (self)
	{
		/* hi */
	}

instead of:

	override (G:Object) GObject *
	constructor (GType type, unsigned int n_construct_properties, GObjectConst=
ructParam *construct_params)
	{
		GObject *object;
		Self *self;

		object =3D PARENT_HANDLER(type, n_construct_properties, construct_params);
		self =3D SELF(object);

		/* hi */

		return object;
	}

	override (G:Object) void
	dispose (GObject *object)
	{
		Self *self =3D SELF(object);

		/* hi */

		PARENT_HANDLER(object);
	}

	override (G:Object) void
	finalize (GObject *object)
	{
		Self *self =3D SELF(object);

		/* hi */

		PARENT_HANDLER(object);
	}

In my opinion, these virtual methods are used so often that they
deserve such first-class support.

Of course, to preserve backwards compatibility, the normal override
syntax is still supported.

--=20
Jean-Yves Lefort <[email protected]>

--Multipart=_Mon__21_Jan_2008_01_24_53_+0100_Hgdi2Ufe.N5IVgbd
Content-Type: text/x-diff;
 name="gob2-2.0.15-gobject-overrides.diff"
Content-Disposition: attachment;
 filename="gob2-2.0.15-gobject-overrides.diff"
Content-Transfer-Encoding: quoted-printable

--- src/main.c.orig	2007-10-17 16:49:04.000000000 +0200
+++ src/main.c	2008-01-21 00:53:57.000000000 +0100
@@ -92,11 +92,16 @@
 static gboolean special_array[SPECIAL_LAST] =3D {0};
 static gboolean any_special =3D FALSE;
=20
+static gboolean need_constructor =3D FALSE;
+static Method * user_constructor =3D NULL;
+
 static gboolean need_dispose =3D FALSE;
 static Method * dispose_handler =3D NULL;
+static Method * user_dispose_method =3D NULL;
=20
 static gboolean need_finalize =3D FALSE;
 static Method * finalize_handler =3D NULL;
+static Method * user_finalize_method =3D NULL;
=20
 FILE *out =3D NULL;
 FILE *outh =3D NULL;
@@ -269,6 +274,9 @@
 		=09
 			if(m->method =3D=3D INIT_METHOD ||
 			   m->method =3D=3D CLASS_INIT_METHOD ||
+			   m->method =3D=3D CONSTRUCTOR_METHOD ||
+			   m->method =3D=3D DISPOSE_METHOD ||
+			   m->method =3D=3D FINALIZE_METHOD ||
 			   m->method =3D=3D OVERRIDE_METHOD)
 				continue;
=20
@@ -291,6 +299,9 @@
 		=09
 			if(m->method =3D=3D INIT_METHOD ||
 			   m->method =3D=3D CLASS_INIT_METHOD ||
+			   m->method =3D=3D CONSTRUCTOR_METHOD ||
+			   m->method =3D=3D DISPOSE_METHOD ||
+			   m->method =3D=3D FINALIZE_METHOD ||
 			   m->method =3D=3D OVERRIDE_METHOD)
 				continue;
=20
@@ -330,6 +341,9 @@
 		=09
 			if(m->method =3D=3D INIT_METHOD ||
 			   m->method =3D=3D CLASS_INIT_METHOD ||
+			   m->method =3D=3D CONSTRUCTOR_METHOD ||
+			   m->method =3D=3D DISPOSE_METHOD ||
+			   m->method =3D=3D FINALIZE_METHOD ||
 			   m->method =3D=3D OVERRIDE_METHOD)
 				continue;
=20
@@ -543,7 +557,10 @@
 		g_free(s);
 	} else if(m->scope =3D=3D PRIVATE_SCOPE ||
 		  m->method =3D=3D INIT_METHOD ||
-		  m->method =3D=3D CLASS_INIT_METHOD) {
+		  m->method =3D=3D CLASS_INIT_METHOD ||=20
+		  m->method =3D=3D CONSTRUCTOR_METHOD ||
+		  m->method =3D=3D DISPOSE_METHOD ||
+		  m->method =3D=3D FINALIZE_METHOD) {
 		print_method(out, "static ", "", "", " ", "",
 			     no_gnu?";\n":" G_GNUC_UNUSED;\n",
 			     m, FALSE, FALSE, TRUE, FALSE, FALSE);
@@ -629,66 +646,68 @@
 	}
 }
=20
-static void
-find_dispose(const Class *cl)
+static Method *
+find_method(const Class *cl, int method, const char *id)
 {
 	GList *li;
=20
-	dispose_handler =3D NULL;
 	for(li=3Dcl->nodes;li;li=3Dg_list_next(li)) {
 		Node *n =3D li->data;
 		if(n->type =3D=3D METHOD_NODE) {
 			Method *m =3D (Method *)n;
-			if(m->method =3D=3D OVERRIDE_METHOD &&
-			   strcmp(m->id, "dispose")=3D=3D0) {
-				if(strcmp(m->otype, "G:Object") !=3D 0) {
-					error_print(GOB_ERROR, m->line_no,
-						    "dispose method override "
-						    "of class other then "
-						    "G:Object");
-				}
-				if(g_list_length(m->args) !=3D 1) {
-					error_print(GOB_ERROR, m->line_no,
-						    "dispose method override "
-						    "with more then one "
-						    "parameter");
-				}
-				dispose_handler =3D m;
-				break;
-			}
+			if (m->method =3D=3D method
+			    && (id =3D=3D NULL || strcmp(m->id, id)=3D=3D0))
+				return m;
 		}
 	}
+
+	return NULL;
 }
=20
 static void
-find_finalize(const Class *cl)
+find_constructor(const Class *cl)
 {
-	GList *li;
+	user_constructor =3D find_method(cl, CONSTRUCTOR_METHOD, NULL);
+}
=20
-	finalize_handler =3D NULL;
-	for(li=3Dcl->nodes;li;li=3Dg_list_next(li)) {
-		Node *n =3D li->data;
-		if(n->type =3D=3D METHOD_NODE) {
-			Method *m =3D (Method *)n;
-			if(m->method =3D=3D OVERRIDE_METHOD &&
-			   strcmp(m->id, "finalize")=3D=3D0) {
-				if(strcmp(m->otype, "G:Object") !=3D 0) {
-					error_print(GOB_ERROR, m->line_no,
-						    "finalize method override "
-						    "of class other then "
-						    "G:Object");
-				}
-				if(g_list_length(m->args) !=3D 1) {
-					error_print(GOB_ERROR, m->line_no,
-						    "finalize method override "
-						    "with more then one "
-						    "parameter");
-				}
-				finalize_handler =3D m;
-				break;
-			}
-		}
+static void
+find_dispose(const Class *cl)
+{
+	dispose_handler =3D find_method(cl, OVERRIDE_METHOD, "dispose");
+	if (dispose_handler !=3D NULL) {
+		if(strcmp(dispose_handler->otype, "G:Object") !=3D 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) !=3D 1)
+			error_print(GOB_ERROR, dispose_handler->line_no,
+				    "dispose method override "
+				    "with more then one "
+				    "parameter");
 	}
+
+	user_dispose_method =3D find_method(cl, DISPOSE_METHOD, NULL);
+}
+
+static void
+find_finalize(const Class *cl)
+{
+	finalize_handler =3D find_method(cl, OVERRIDE_METHOD, "finalize");
+	if (finalize_handler !=3D NULL) {
+		if(strcmp(finalize_handler->otype, "G:Object") !=3D 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) !=3D 1)
+			error_print(GOB_ERROR, finalize_handler->line_no,
+				    "finalize method override "
+				    "with more then one "
+				    "parameter");
+	}
+
+	user_finalize_method =3D find_method(cl, FINALIZE_METHOD, NULL);
 }
=20
=20
@@ -2118,6 +2137,33 @@
 }
=20
 static void
+add_constructor (Class *c)
+{
+	out_printf(out, "\nstatic GObject *\n"
+		   "___constructor (GType type, guint n_construct_properties, GObjectCon=
structParam *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 =3D G_OBJECT_CLASS (parent_class)->constructo=
r (type, n_construct_properties, construct_properties);\n");
+	out_printf(out, "\tself =3D %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 +2173,7 @@
 		   "#define __GOB_FUNCTION__ \"%s::dispose\"\n",
 		   c->otype);
=20
-	if (unreftors > 0) {
+	if (unreftors > 0 || user_dispose_method !=3D NULL) {
 		out_printf (out, "\t%s *self%s =3D %s (obj_self);\n",
 			    typebase,
 			    ! no_gnu ? " G_GNUC_UNUSED" : "",
@@ -2143,6 +2189,14 @@
 		if (dispose_handler->line_no > 0)
 			out_addline_outfile (out);
 	} else {
+		if (user_dispose_method !=3D 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 +2232,8 @@
 		   c->otype);
=20
 	if (privates > 0 ||
-	    destructors > 0) {
+	    destructors > 0 ||
+	    user_finalize_method !=3D NULL) {
 		const char *unused =3D "";
 		if ( ! no_gnu)
 			unused =3D " G_GNUC_UNUSED";
@@ -2202,6 +2257,14 @@
 		if(finalize_handler->line_no > 0)
 			out_addline_outfile(out);
 	} else {
+		if (user_finalize_method !=3D 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 +2444,9 @@
=20
 			/* 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 "
+					   "=3D ___constructor;\n");
 			if(need_dispose && !dispose_handler)
 				out_printf(out, "\tg_object_class->dispose "
 					   "=3D ___dispose;\n");
@@ -3064,6 +3130,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 +3708,9 @@
 			    funcbase);
 	}
=20
+	if (need_constructor)
+		add_constructor (c);
+
 	if (need_dispose)
 		add_dispose (c);
=20
@@ -4441,15 +4519,24 @@
=20
 	make_bases ();
 	make_inits ((Class *)class);
-	if(unreftors > 0) {
+
+	find_constructor ((Class *)class);
+	if (user_constructor !=3D NULL)
+		need_constructor =3D TRUE;
+
+	find_dispose ((Class *)class);
+	if (unreftors > 0 ||
+	    dispose_handler !=3D NULL ||
+	    user_dispose_method !=3D NULL)
 		need_dispose =3D TRUE;
-		find_dispose ((Class *)class);
-	}
+
+	find_finalize ((Class *)class);
 	if (destructors > 0 ||
-	    privates > 0) {
+	    privates > 0 ||
+	    user_finalize_method !=3D NULL) {
 		need_finalize =3D 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-21 00:53:13.000000000 +0100
@@ -155,7 +155,11 @@
=20
 	g_assert(scope !=3D CLASS_SCOPE);
       =20
-	if(method =3D=3D INIT_METHOD || method =3D=3D CLASS_INIT_METHOD) {
+	if(method =3D=3D INIT_METHOD
+	   || method =3D=3D CLASS_INIT_METHOD
+	   || method =3D=3D CONSTRUCTOR_METHOD
+	   || method =3D=3D DISPOSE_METHOD
+	   || method =3D=3D FINALIZE_METHOD) {
 		type =3D (Type *)node_new (TYPE_NODE,
 					 "name", "void",
 					 NULL);
@@ -1767,13 +1771,29 @@
 				push_function(NO_SCOPE, CLASS_INIT_METHOD, NULL,
 					      $<id>1, $<cbuf>5, $<line>2,
 					      ccode_line, FALSE, NULL);
+			} else if(strcmp($<id>1, "constructor")=3D=3D0) {
+				push_init_arg($<id>3, FALSE);
+				push_function(NO_SCOPE, CONSTRUCTOR_METHOD, NULL,
+					      $<id>1, $<cbuf>5, $<line>2,
+					      ccode_line, FALSE, NULL);
+			} else if(strcmp($<id>1, "dispose")=3D=3D0) {
+				push_init_arg($<id>3, FALSE);
+				push_function(NO_SCOPE, DISPOSE_METHOD, NULL,
+					      $<id>1, $<cbuf>5, $<line>2,
+					      ccode_line, FALSE, NULL);
+			} else if(strcmp($<id>1, "finalize")=3D=3D0) {
+				push_init_arg($<id>3, FALSE);
+				push_function(NO_SCOPE, FINALIZE_METHOD, NULL,
+					      $<id>1, $<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-21 00:53:13.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,

--Multipart=_Mon__21_Jan_2008_01_24_53_+0100_Hgdi2Ufe.N5IVgbd--

--Signature=_Mon__21_Jan_2008_01_24_53_+0100_mjxTGpyGhEDKKoaL
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFHk+ZayzD7UaO4AGoRAtbxAJwKeeeegdN9rgh4q/KbMQceKnCdkgCfcZOE
wB3RowcRSaAlBAC+iFeQf6E=
=DUn9
-----END PGP SIGNATURE-----

--Signature=_Mon__21_Jan_2008_01_24_53_+0100_mjxTGpyGhEDKKoaL--


[email protected]
Content-Type: text/plain; charset=us-ascii; name="footer.txt"
Content-Disposition: inline
Content-Transfer-Encoding: 8bit

--
to unsubscribe:
send mail to [email protected] with "unsubscribe gob-list" in the subject

[email protected]