[vala] Support virtual default handler for signals



commit 9b37307b035e75c858ed648728db83a8bc70a4c8
Author: Jürg Billeter <j bitron ch>
Date:   Tue Jul 28 17:20:37 2009 +0200

    Support virtual default handler for signals
    
    Based on patch by Yu Feng, fixes part of 571685.

 codegen/valaccodemethodcallmodule.vala |    2 +-
 codegen/valaccodemethodmodule.vala     |    7 +++-
 codegen/valagsignalmodule.vala         |   12 +++++-
 codegen/valagtypemodule.vala           |   16 ++++++++
 vala/valamethod.vala                   |    2 +-
 vala/valaparser.vala                   |    5 ++-
 vala/valasignal.vala                   |   61 +++++++++++++++++++++-----------
 7 files changed, 78 insertions(+), 27 deletions(-)
---
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index 8fc87db..4cf641d 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -53,7 +53,7 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 		} else if (itype is SignalType) {
 			var sig_type = (SignalType) itype;
 			if (ma != null && ma.inner is BaseAccess && sig_type.signal_symbol.is_virtual) {
-				m = sig_type.signal_symbol.get_method_handler ();
+				m = sig_type.signal_symbol.default_handler;
 			} else {
 				ccall = (CCodeFunctionCall) expr.call.ccodenode;
 			}
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index d76fbce..d8342a6 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -599,7 +599,12 @@ internal class Vala.CCodeMethodModule : CCodeStructModule {
 			}
 		}
 
-		if ((m.is_abstract || m.is_virtual) && !m.coroutine) {
+		if ((m.is_abstract || m.is_virtual) && !m.coroutine &&
+		/* If the method is a signal handler, the declaration
+		 * is not needed. -- the name should be reserved for the
+		 * emitter! */
+			    m.signal_reference == null) {
+
 			cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
 			var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
 
diff --git a/codegen/valagsignalmodule.vala b/codegen/valagsignalmodule.vala
index f4ed94d..fe7c864 100644
--- a/codegen/valagsignalmodule.vala
+++ b/codegen/valagsignalmodule.vala
@@ -355,10 +355,18 @@ internal class Vala.GSignalModule : GObjectModule {
 
 	public override CCodeFunctionCall get_signal_creation (Signal sig, TypeSymbol type) {	
 		var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new"));
+		var cl = sig.parent_symbol as Class;
 		csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.get_cname ())));
 		csignew.add_argument (new CCodeIdentifier (type.get_type_id ()));
 		csignew.add_argument (new CCodeConstant ("G_SIGNAL_RUN_LAST"));
-		csignew.add_argument (new CCodeConstant ("0"));
+		if (sig.default_handler == null) {
+			csignew.add_argument (new CCodeConstant ("0"));
+		} else {
+			var struct_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET"));
+			struct_offset.add_argument (new CCodeIdentifier ("%sClass".printf (cl.get_cname ())));
+			struct_offset.add_argument (new CCodeIdentifier (sig.default_handler.vfunc_name));
+			csignew.add_argument (struct_offset);
+		}
 		csignew.add_argument (new CCodeConstant ("NULL"));
 		csignew.add_argument (new CCodeConstant ("NULL"));
 
@@ -608,7 +616,7 @@ internal class Vala.GSignalModule : GObjectModule {
 			var cl = (TypeSymbol) sig.parent_symbol;
 			
 			if (expr.inner is BaseAccess && sig.is_virtual) {
-				var m = sig.get_method_handler ();
+				var m = sig.default_handler;
 				var base_class = (Class) m.parent_symbol;
 				var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
 				vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala
index e5bf70e..81573a6 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -206,6 +206,12 @@ internal class Vala.GTypeModule : GErrorModule {
 			generate_virtual_method_declaration (m, decl_space, type_struct);
 		}
 
+		foreach (Signal sig in cl.get_signals ()) {
+			if (sig.default_handler != null) {
+				generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct);
+			}
+		}
+
 		foreach (Property prop in cl.get_properties ()) {
 			if (!prop.is_abstract && !prop.is_virtual) {
 				continue;
@@ -1140,6 +1146,16 @@ internal class Vala.GTypeModule : GErrorModule {
 			init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.base_method.vfunc_name), new CCodeIdentifier (m.get_real_cname ()))));
 		}
 
+		/* connect default signal handlers */
+		foreach (Signal sig in cl.get_signals ()) {
+			if (sig.default_handler == null) {
+				continue;
+			}
+			var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
+			ccast.add_argument (new CCodeIdentifier ("klass"));
+			init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, sig.default_handler.vfunc_name), new CCodeIdentifier (sig.default_handler.get_real_cname ()))));
+		}
+
 		/* connect overridden properties */
 		foreach (Property prop in cl.get_properties ()) {
 			if (prop.base_property == null) {
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 5fa7dd0..79e9d5c 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -593,7 +593,7 @@ public class Vala.Method : Member {
 		} else if (sym is Signal) {
 			var sig = (Signal) sym;
 			if (sig.is_virtual) {
-				var base_method = sig.get_method_handler ();
+				var base_method = sig.default_handler;
 				string invalid_match;
 				if (!compatible (base_method, out invalid_match)) {
 					error = true;
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 88dacd5..93e5cbf 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -2390,7 +2390,10 @@ public class Vala.Parser : CodeVisitor {
 			} while (accept (TokenType.COMMA));
 		}
 		expect (TokenType.CLOSE_PARENS);
-		expect (TokenType.SEMICOLON);
+		if (!accept (TokenType.SEMICOLON)) {
+			sig.body = parse_block ();
+		}
+
 		return sig;
 	}
 
diff --git a/vala/valasignal.vala b/vala/valasignal.vala
index 9b85e89..3a69f59 100644
--- a/vala/valasignal.vala
+++ b/vala/valasignal.vala
@@ -38,6 +38,16 @@ public class Vala.Signal : Member, Lockable {
 		}
 	}
 
+	public Block body {
+		get { return _body; }
+		set {
+			_body = value;
+			if (_body != null) {
+				_body.owner = scope;
+			}
+		}
+	}
+
 	/**
 	 * Specifies whether this signal has an emitter wrapper function.
 	 */
@@ -49,7 +59,11 @@ public class Vala.Signal : Member, Lockable {
 	public bool is_virtual { get; set; }
 
 	private Gee.List<FormalParameter> parameters = new ArrayList<FormalParameter> ();
-	private Method generated_method;
+	/**
+	 * Refers to the default signal handler, which is an anonymous
+	 * function in the scope.
+	 * */
+	public Method default_handler { get; private set; }
 
 	private string cname;
 	
@@ -57,6 +71,8 @@ public class Vala.Signal : Member, Lockable {
 
 	private DataType _return_type;
 
+	private Block _body;
+
 	/**
 	 * Creates a new signal.
 	 *
@@ -179,6 +195,9 @@ public class Vala.Signal : Member, Lockable {
 		foreach (FormalParameter param in parameters) {
 			param.accept (visitor);
 		}
+		if (default_handler != null) {
+			default_handler.accept (visitor);
+		}
 	}
 
 	/**
@@ -206,26 +225,6 @@ public class Vala.Signal : Member, Lockable {
 		}
 	}
 
-	public Method get_method_handler () {
-		assert (is_virtual);
-
-		if (generated_method == null) {
-			generated_method = new Method (name, return_type, source_reference);
-			generated_method.access = access;
-			generated_method.is_virtual = true;
-			generated_method.vfunc_name = name;
-			generated_method.signal_reference = this;
-
-			foreach (FormalParameter param in parameters) {
-				generated_method.add_parameter (param);
-			}
-
-			parent_symbol.scope.add (null, generated_method);
-		}
-		
-		return generated_method;
-	}
-
 	public override bool check (SemanticAnalyzer analyzer) {
 		if (checked) {
 			return !error;
@@ -241,6 +240,26 @@ public class Vala.Signal : Member, Lockable {
 			param.check (analyzer);
 		}
 
+		if (!is_virtual && body != null) {
+			Report.error (source_reference, "Only virtual signals can have a default signal handler body");
+		}
+
+
+		if (is_virtual) {
+			default_handler = new Method (name, return_type, source_reference);
+			default_handler.access = access;
+			default_handler.is_virtual = true;
+			default_handler.vfunc_name = name;
+			default_handler.signal_reference = this;
+			default_handler.body = body;
+
+			foreach (FormalParameter param in parameters) {
+				default_handler.add_parameter (param);
+			}
+
+			parent_symbol.scope.add (null, default_handler);
+			default_handler.check (analyzer);
+		}
 		return !error;
 	}
 }



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