vala r838 - in trunk: . gobject vala



Author: juergbi
Date: Tue Jan 15 21:01:26 2008
New Revision: 838
URL: http://svn.gnome.org/viewvc/vala?rev=838&view=rev

Log:
2008-01-15  Juerg Billeter  <j bitron ch>

	* vala/parser.y, vala/scanner.l, vala/valaclass.vala,
	  vala/valainterface.vala, vala/valamethod.vala,
	  vala/valasemanticanalyzer.vala, vala/valastruct.vala,
	  gobject/valaccodegeneratormethod.vala: add basic support for
	  method pre- and postconditions


Modified:
   trunk/ChangeLog
   trunk/gobject/valaccodegeneratormethod.vala
   trunk/vala/parser.y
   trunk/vala/scanner.l
   trunk/vala/valaclass.vala
   trunk/vala/valainterface.vala
   trunk/vala/valamethod.vala
   trunk/vala/valasemanticanalyzer.vala
   trunk/vala/valastruct.vala

Modified: trunk/gobject/valaccodegeneratormethod.vala
==============================================================================
--- trunk/gobject/valaccodegeneratormethod.vala	(original)
+++ trunk/gobject/valaccodegeneratormethod.vala	Tue Jan 15 21:01:26 2008
@@ -418,6 +418,10 @@
 					// GTypeModule-based plug-in, register types
 					cinit.append (module_init_fragment);
 				}
+
+				foreach (Expression precondition in m.get_preconditions ()) {
+					cinit.append (create_precondition_statement (m, creturn_type, precondition));
+				}
 			}
 		}
 		
@@ -436,7 +440,11 @@
 			vfunc.add_parameter (cparam);
 			
 			var vblock = new CCodeBlock ();
-			
+
+			foreach (Expression precondition in m.get_preconditions ()) {
+				vblock.add_statement (create_precondition_statement (m, creturn_type, precondition));
+			}
+
 			CCodeFunctionCall vcast = null;
 			if (m.parent_symbol is Interface) {
 				var iface = (Interface) m.parent_symbol;
@@ -491,15 +499,27 @@
 			}
 
 			CCodeStatement cstmt;
-			if (creturn_type.data_type == null && creturn_type.type_parameter == null) {
+			if (creturn_type is VoidType) {
 				cstmt = new CCodeExpressionStatement (vcall);
 			} else {
-				/* pass method return value */
-				cstmt = new CCodeReturnStatement (vcall);
+				/* store method return value */
+				var cdecl = new CCodeDeclaration (creturn_type.get_cname ());
+				cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("result", vcall));
+				cstmt = cdecl;
 			}
 			cstmt.line = vfunc.line;
 			vblock.add_statement (cstmt);
 
+			foreach (Expression postcondition in m.get_postconditions ()) {
+				vblock.add_statement (create_postcondition_statement (postcondition));
+			}
+
+			if (!(creturn_type is VoidType)) {
+				var cret_stmt = new CCodeReturnStatement (new CCodeIdentifier ("result"));
+				cret_stmt.line = vfunc.line;
+				vblock.add_statement (cret_stmt);
+			}
+
 			if (visible) {
 				header_type_member_declaration.append (vfunc.copy ());
 			} else {
@@ -592,7 +612,7 @@
 			return create_type_check_statement (prop, new VoidType (), t, non_null, var_name);
 		}
 	}
-	
+
 	private CCodeStatement create_type_check_statement (CodeNode! method_node, DataType ret_type, Typesymbol! t, bool non_null, string! var_name) {
 		var ccheck = new CCodeFunctionCall ();
 		
@@ -632,6 +652,37 @@
 		return new CCodeExpressionStatement (ccheck);
 	}
 
+	private CCodeStatement create_precondition_statement (CodeNode! method_node, DataType ret_type, Expression precondition) {
+		var ccheck = new CCodeFunctionCall ();
+
+		ccheck.add_argument ((CCodeExpression) precondition.ccodenode);
+
+		if (ret_type is VoidType) {
+			/* void function */
+			ccheck.call = new CCodeIdentifier ("g_return_if_fail");
+		} else {
+			ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
+
+			var cdefault = default_value_for_type (ret_type);
+			if (cdefault != null) {
+				ccheck.add_argument (cdefault);
+			} else {
+				Report.warning (method_node.source_reference, "not supported return type for runtime type checks");
+				return new CCodeExpressionStatement (new CCodeConstant ("0"));
+			}
+		}
+		
+		return new CCodeExpressionStatement (ccheck);
+	}
+
+	private CCodeStatement create_postcondition_statement (Expression postcondition) {
+		var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_assert"));
+
+		cassert.add_argument ((CCodeExpression) postcondition.ccodenode);
+
+		return new CCodeExpressionStatement (cassert);
+	}
+
 	private CCodeExpression default_value_for_type (DataType! type) {
 		if ((type.data_type != null && type.data_type.is_reference_type ()) || type is PointerType) {
 			return new CCodeConstant ("NULL");

Modified: trunk/vala/parser.y
==============================================================================
--- trunk/vala/parser.y	(original)
+++ trunk/vala/parser.y	Tue Jan 15 21:01:26 2008
@@ -169,6 +169,7 @@
 %token DELEGATE "delegate"
 %token DO "do"
 %token ELSE "else"
+%token ENSURES "ensures"
 %token ENUM "enum"
 %token VALA_FALSE "false"
 %token FINALLY "finally"
@@ -190,6 +191,7 @@
 %token PROTECTED "protected"
 %token PUBLIC "public"
 %token REF "ref"
+%token REQUIRES "requires"
 %token RETURN "return"
 %token SET "set"
 %token SIGNAL "signal"
@@ -358,6 +360,12 @@
 %type <formal_parameter> fixed_parameter
 %type <list> opt_throws_declaration
 %type <list> throws_declaration
+%type <list> opt_requires_declarations
+%type <list> requires_declarations
+%type <expression> requires_declaration
+%type <list> opt_ensures_declarations
+%type <list> ensures_declarations
+%type <expression> ensures_declaration
 %type <signal> signal_declaration
 %type <constructor> constructor_declaration
 %type <destructor> destructor_declaration
@@ -393,7 +401,7 @@
 	| COMMA
 	;
 
-/* identifiers never conflict with context-specific keywords get or set */
+/* identifiers never conflict with context-specific keywords get, set, requires, or ensures */
 identifier
 	: IDENTIFIER
 	| GET
@@ -404,6 +412,14 @@
 	  {
 		$$ = g_strdup ("set");
 	  }
+	| REQUIRES
+	  {
+		$$ = g_strdup ("requires");
+	  }
+	| ENSURES
+	  {
+		$$ = g_strdup ("ensures");
+	  }
 	;
 
 literal
@@ -3001,7 +3017,7 @@
 	;
 
 method_header
-	: comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS opt_throws_declaration
+	: comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS opt_throws_declaration opt_requires_declarations opt_ensures_declarations
 	  {
 	  	GList *l;
 		ValaSourceReference *src;
@@ -3059,6 +3075,22 @@
 			g_list_free ($10);
 		}
 
+		if ($11 != NULL) {
+			for (l = $11; l != NULL; l = l->next) {
+				vala_method_add_precondition ($$, l->data);
+				g_object_unref (l->data);
+			}
+			g_list_free ($11);
+		}
+
+		if ($12 != NULL) {
+			for (l = $12; l != NULL; l = l->next) {
+				vala_method_add_postcondition ($$, l->data);
+				g_object_unref (l->data);
+			}
+			g_list_free ($12);
+		}
+
 		g_object_unref ($5);
 		g_free ($6);
 	  }
@@ -3219,6 +3251,58 @@
 	  }
 	;
 
+opt_requires_declarations
+	: /* empty */
+	  {
+		$$ = NULL;
+	  }
+	| requires_declarations
+	;
+
+requires_declarations
+	: requires_declaration
+	  {
+		$$ = g_list_append (NULL, $1);
+	  }
+	| requires_declarations requires_declaration
+	  {
+		$$ = g_list_append ($1, $2);
+	  }
+	;
+
+requires_declaration
+	: REQUIRES open_parens expression CLOSE_PARENS
+	  {
+		$$ = $3;
+	  }
+	;
+
+opt_ensures_declarations
+	: /* empty */
+	  {
+		$$ = NULL;
+	  }
+	| ensures_declarations
+	;
+
+ensures_declarations
+	: ensures_declaration
+	  {
+		$$ = g_list_append (NULL, $1);
+	  }
+	| ensures_declarations ensures_declaration
+	  {
+		$$ = g_list_append ($1, $2);
+	  }
+	;
+
+ensures_declaration
+	: ENSURES open_parens expression CLOSE_PARENS
+	  {
+		$$ = $3;
+	  }
+	;
+
 property_declaration
 	: comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_BRACE get_accessor_declaration opt_set_accessor_declaration CLOSE_BRACE
 	  {

Modified: trunk/vala/scanner.l
==============================================================================
--- trunk/vala/scanner.l	(original)
+++ trunk/vala/scanner.l	Tue Jan 15 21:01:26 2008
@@ -146,6 +146,7 @@
 "delegate"	{ uploc; return DELEGATE; }
 "do"		{ uploc; return DO; }
 "else"		{ uploc; return ELSE; }
+"ensures"	{ uploc; return ENSURES; }
 "enum"		{ uploc; return ENUM; }
 "false"		{ uploc; return VALA_FALSE; }
 "finally"	{ uploc; return FINALLY; }
@@ -167,6 +168,7 @@
 "protected"	{ uploc; return PROTECTED; }
 "public"	{ uploc; return PUBLIC; }
 "ref"		{ uploc; return REF; }
+"requires"	{ uploc; return REQUIRES; }
 "set"		{ uploc; return SET; }
 "signal"	{ uploc; return SIGNAL; }
 "sizeof"	{ uploc; return SIZEOF; }

Modified: trunk/vala/valaclass.vala
==============================================================================
--- trunk/vala/valaclass.vala	(original)
+++ trunk/vala/valaclass.vala	Tue Jan 15 21:01:26 2008
@@ -190,6 +190,11 @@
 			m.this_parameter = new FormalParameter ("this", new ClassType (this));
 			m.scope.add (m.this_parameter.name, m.this_parameter);
 		}
+		if (!(m.return_type is VoidType)) {
+			m.result_var = new VariableDeclarator ("result");
+			m.result_var.type_reference = m.return_type.copy ();
+			m.scope.add (m.result_var.name, m.result_var);
+		}
 		if (m is CreationMethod) {
 			if (m.name == null) {
 				default_construction_method = m;

Modified: trunk/vala/valainterface.vala
==============================================================================
--- trunk/vala/valainterface.vala	(original)
+++ trunk/vala/valainterface.vala	Tue Jan 15 21:01:26 2008
@@ -125,6 +125,11 @@
 			m.this_parameter = new FormalParameter ("this", new InterfaceType (this));
 			m.scope.add (m.this_parameter.name, m.this_parameter);
 		}
+		if (!(m.return_type is VoidType)) {
+			m.result_var = new VariableDeclarator ("result");
+			m.result_var.type_reference = m.return_type.copy ();
+			m.scope.add (m.result_var.name, m.result_var);
+		}
 
 		methods.add (m);
 		scope.add (m.name, m);

Modified: trunk/vala/valamethod.vala
==============================================================================
--- trunk/vala/valamethod.vala	(original)
+++ trunk/vala/valamethod.vala	Tue Jan 15 21:01:26 2008
@@ -1,6 +1,6 @@
 /* valamethod.vala
  *
- * Copyright (C) 2006-2007  JÃrg Billeter, Raffaele Sandrini
+ * Copyright (C) 2006-2008  JÃrg Billeter, Raffaele Sandrini
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -141,7 +141,12 @@
 	 * Specifies the generated `this' parameter for instance methods.
 	 */
 	public FormalParameter this_parameter { get; set; }
-	
+
+	/**
+	 * Specifies the generated `result' variable for postconditions.
+	 */
+	public VariableDeclarator result_var { get; set; }
+
 	/**
 	 * Specifies whether the array length should implicitly be passed
 	 * if the parameter type is an array.
@@ -170,6 +175,8 @@
 	private string _sentinel;
 	private bool _no_array_length;
 	private Gee.List<DataType> error_domains = new ArrayList<DataType> ();
+	private Gee.List<Expression> preconditions = new ArrayList<Expression> ();
+	private Gee.List<Expression> postconditions = new ArrayList<Expression> ();
 	private DataType _return_type;
 
 	/**
@@ -220,6 +227,18 @@
 			error_domain.accept (visitor);
 		}
 
+		if (result_var != null) {
+			result_var.type_reference.accept (visitor);
+		}
+
+		foreach (Expression precondition in preconditions) {
+			precondition.accept (visitor);
+		}
+
+		foreach (Expression postcondition in postconditions) {
+			postcondition.accept (visitor);
+		}
+
 		if (body != null) {
 			body.accept (visitor);
 		}
@@ -378,6 +397,44 @@
 		return new ReadOnlyCollection<DataType> (error_domains);
 	}
 
+	/**
+	 * Adds a precondition to this method.
+	 *
+	 * @param precondition a boolean precondition expression
+	 */
+	public void add_precondition (Expression! precondition) {
+		preconditions.add (precondition);
+		precondition.parent_node = this;
+	}
+
+	/**
+	 * Returns a copy of the list of preconditions of this method.
+	 *
+	 * @return list of preconditions
+	 */
+	public Collection<Expression> get_preconditions () {
+		return new ReadOnlyCollection<Expression> (preconditions);
+	}
+
+	/**
+	 * Adds a postcondition to this method.
+	 *
+	 * @param postcondition a boolean postcondition expression
+	 */
+	public void add_postcondition (Expression! postcondition) {
+		postconditions.add (postcondition);
+		postcondition.parent_node = this;
+	}
+
+	/**
+	 * Returns a copy of the list of postconditions of this method.
+	 *
+	 * @return list of postconditions
+	 */
+	public Collection<Expression> get_postconditions () {
+		return new ReadOnlyCollection<Expression> (postconditions);
+	}
+
 	public override void replace_type (DataType! old_type, DataType! new_type) {
 		if (return_type == old_type) {
 			return_type = new_type;

Modified: trunk/vala/valasemanticanalyzer.vala
==============================================================================
--- trunk/vala/valasemanticanalyzer.vala	(original)
+++ trunk/vala/valasemanticanalyzer.vala	Tue Jan 15 21:01:26 2008
@@ -391,6 +391,34 @@
 				return;
 			}
 		}
+
+		/*foreach (Expression precondition in m.get_preconditions ()) {
+			if (precondition.error) {
+				// if there was an error in the precondition, skip this check
+				m.error = true;
+				return;
+			}
+
+			if (!precondition.static_type.compatible (bool_type)) {
+				m.error = true;
+				Report.error (precondition.source_reference, "Precondition must be boolean");
+				return;
+			}
+		}
+
+		foreach (Expression postcondition in m.get_postconditions ()) {
+			if (postcondition.error) {
+				// if there was an error in the postcondition, skip this check
+				m.error = true;
+				return;
+			}
+
+			if (!postcondition.static_type.compatible (bool_type)) {
+				m.error = true;
+				Report.error (postcondition.source_reference, "Postcondition must be boolean");
+				return;
+			}
+		}*/
 	}
 
 	private void find_base_class_method (Method! m, Class! cl) {

Modified: trunk/vala/valastruct.vala
==============================================================================
--- trunk/vala/valastruct.vala	(original)
+++ trunk/vala/valastruct.vala	Tue Jan 15 21:01:26 2008
@@ -117,6 +117,11 @@
 			m.this_parameter = new FormalParameter ("this", new ValueType (this));
 			m.scope.add (m.this_parameter.name, m.this_parameter);
 		}
+		if (!(m.return_type is VoidType)) {
+			m.result_var = new VariableDeclarator ("result");
+			m.result_var.type_reference = m.return_type.copy ();
+			m.scope.add (m.result_var.name, m.result_var);
+		}
 		if (m is CreationMethod) {
 			if (m.name == null) {
 				default_construction_method = m;



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