summaryrefslogtreecommitdiff
path: root/vala/valaforeachstatement.vala
diff options
context:
space:
mode:
authorRyan Lortie <desrt@desrt.ca>2010-02-13 01:16:12 -0500
committerJürg Billeter <j@bitron.ch>2010-02-15 21:07:43 +0100
commit5afa47385519ed9eddb3ff0131bc5d87f580dec4 (patch)
tree80dc7a5a0c0ceaa7f6b18f28bb862d476e4946c4 /vala/valaforeachstatement.vala
parent5ea9ebff4dde79e296182a5a36f258ca59e30b24 (diff)
downloadvala-5afa47385519ed9eddb3ff0131bc5d87f580dec4.tar.gz
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.
Diffstat (limited to 'vala/valaforeachstatement.vala')
-rw-r--r--vala/valaforeachstatement.vala117
1 files changed, 76 insertions, 41 deletions
diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala
index 0975c82d4..401e43aa2 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) {