[vala] Add alternative iterator protocol for foreach
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [vala] Add alternative iterator protocol for foreach
- Date: Mon, 15 Feb 2010 20:07:52 +0000 (UTC)
commit 5afa47385519ed9eddb3ff0131bc5d87f580dec4
Author: Ryan Lortie <desrt desrt ca>
Date: Sat Feb 13 01:16:12 2010 -0500
Add alternative iterator protocol for foreach
If the iterator object has a .next_value() function that returns a
nullable type then we iterate by calling this function until it returns
null.
Fixes bug 609812.
vala/valaforeachstatement.vala | 117 ++++++++++++++++++++++++++--------------
1 files changed, 76 insertions(+), 41 deletions(-)
---
diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala
index 0975c82..401e43a 100644
--- a/vala/valaforeachstatement.vala
+++ b/vala/valaforeachstatement.vala
@@ -209,40 +209,86 @@ public class Vala.ForeachStatement : Block {
error = true;
return false;
}
+
+ var iterator_call = new MethodCall (new MemberAccess (collection, "iterator"));
+ add_statement (new DeclarationStatement (new LocalVariable (iterator_type, "_%s_it".printf (variable_name), iterator_call, source_reference), source_reference));
+
+ var next_value_method = iterator_type.get_member ("next_value") as Method;
var next_method = iterator_type.get_member ("next") as Method;
- if (next_method == null) {
- Report.error (collection.source_reference, "`%s' does not have a `next' method".printf (iterator_type.to_string ()));
- error = true;
- return false;
- }
- if (next_method.get_parameters ().size != 0) {
- Report.error (collection.source_reference, "`%s' must not have any parameters".printf (next_method.get_full_name ()));
- error = true;
- return false;
- }
- if (!next_method.return_type.compatible (analyzer.bool_type)) {
- Report.error (collection.source_reference, "`%s' must return a boolean value".printf (next_method.get_full_name ()));
- error = true;
- return false;
- }
- var get_method = iterator_type.get_member ("get") as Method;
- if (get_method == null) {
- Report.error (collection.source_reference, "`%s' does not have a `get' method".printf (iterator_type.to_string ()));
- error = true;
- return false;
- }
- if (get_method.get_parameters ().size != 0) {
- Report.error (collection.source_reference, "`%s' must not have any parameters".printf (get_method.get_full_name ()));
- error = true;
- return false;
- }
- var element_type = get_method.return_type.get_actual_type (iterator_type, null, this);
- if (element_type is VoidType) {
- Report.error (collection.source_reference, "`%s' must return an element".printf (get_method.get_full_name ()));
+ if (next_value_method != null) {
+ if (next_value_method.get_parameters ().size != 0) {
+ Report.error (collection.source_reference, "`%s' must not have any parameters".printf (next_value_method.get_full_name ()));
+ error = true;
+ return false;
+ }
+ var element_type = next_value_method.return_type.get_actual_type (iterator_type, null, this);
+ if (!element_type.nullable) {
+ Report.error (collection.source_reference, "return type of `%s' must be nullable".printf (next_value_method.get_full_name ()));
+ error = true;
+ return false;
+ }
+
+ if (!analyze_element_type (element_type)) {
+ return false;
+ }
+
+ add_statement (new DeclarationStatement (new LocalVariable (type_reference, variable_name, null, source_reference), source_reference));
+
+ var next_value_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_it".printf (variable_name), source_reference), "next_value", source_reference), source_reference);
+ var assignment = new Assignment (new MemberAccess (null, variable_name, source_reference), next_value_call, AssignmentOperator.SIMPLE, source_reference);
+ var conditional = new BinaryExpression (BinaryOperator.INEQUALITY, assignment, new NullLiteral (source_reference), source_reference);
+ var loop = new WhileStatement (conditional, body, source_reference);
+ add_statement (loop);
+ } else if (next_method != null) {
+ if (next_method.get_parameters ().size != 0) {
+ Report.error (collection.source_reference, "`%s' must not have any parameters".printf (next_method.get_full_name ()));
+ error = true;
+ return false;
+ }
+ if (!next_method.return_type.compatible (analyzer.bool_type)) {
+ Report.error (collection.source_reference, "`%s' must return a boolean value".printf (next_method.get_full_name ()));
+ error = true;
+ return false;
+ }
+ var get_method = iterator_type.get_member ("get") as Method;
+ if (get_method == null) {
+ Report.error (collection.source_reference, "`%s' does not have a `get' method".printf (iterator_type.to_string ()));
+ error = true;
+ return false;
+ }
+ if (get_method.get_parameters ().size != 0) {
+ Report.error (collection.source_reference, "`%s' must not have any parameters".printf (get_method.get_full_name ()));
+ error = true;
+ return false;
+ }
+ var element_type = get_method.return_type.get_actual_type (iterator_type, null, this);
+ if (element_type is VoidType) {
+ Report.error (collection.source_reference, "`%s' must return an element".printf (get_method.get_full_name ()));
+ error = true;
+ return false;
+ }
+
+ if (!analyze_element_type (element_type)) {
+ return false;
+ }
+
+ var next_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_it".printf (variable_name), source_reference), "next", source_reference), source_reference);
+ var loop = new WhileStatement (next_call, body, source_reference);
+ add_statement (loop);
+
+ var get_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_it".printf (variable_name), source_reference), "get", source_reference), source_reference);
+ body.insert_statement (0, new DeclarationStatement (new LocalVariable (type_reference, variable_name, get_call, source_reference), source_reference));
+ } else {
+ Report.error (collection.source_reference, "`%s' does not have a `next_value' or `next' method".printf (iterator_type.to_string ()));
error = true;
return false;
}
+ checked = false;
+ return base.check (analyzer);
+ }
+
+ bool analyze_element_type (DataType element_type) {
// analyze element type
if (type_reference == null) {
// var type
@@ -257,18 +303,7 @@ public class Vala.ForeachStatement : Block {
return false;
}
- var iterator_call = new MethodCall (new MemberAccess (collection, "iterator"));
- add_statement (new DeclarationStatement (new LocalVariable (iterator_type, "_%s_it".printf (variable_name), iterator_call, source_reference), source_reference));
-
- var next_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_it".printf (variable_name), source_reference), "next", source_reference), source_reference);
- var loop = new WhileStatement (next_call, body, source_reference);
- add_statement (loop);
-
- var get_call = new MethodCall (new MemberAccess (new MemberAccess.simple ("_%s_it".printf (variable_name), source_reference), "get", source_reference), source_reference);
- body.insert_statement (0, new DeclarationStatement (new LocalVariable (type_reference, variable_name, get_call, source_reference), source_reference));
-
- checked = false;
- return base.check (analyzer);
+ return true;
}
bool check_without_iterator (SemanticAnalyzer analyzer, DataType collection_type, DataType element_type) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]