summaryrefslogtreecommitdiff
path: root/vala
diff options
context:
space:
mode:
authorJürg Billeter <j@bitron.ch>2008-11-07 11:10:31 +0000
committerJürg Billeter <juergbi@src.gnome.org>2008-11-07 11:10:31 +0000
commit955c4f6c3e8bf120d363015897528567b2df23ed (patch)
treebfbcfdbf98058f2de5f17491ee63934b98ca8355 /vala
parent4ed3719f219f7ee4d3c40544df7ec75719fae8fd (diff)
downloadvala-955c4f6c3e8bf120d363015897528567b2df23ed.tar.gz
Move statement checking to code nodes
2008-11-07 Jürg Billeter <j@bitron.ch> * vala/valablock.vala: * vala/valacatchclause.vala: * vala/valadeclarationstatement.vala: * vala/valadeletestatement.vala: * vala/valadostatement.vala: * vala/valaexpressionstatement.vala: * vala/valaforstatement.vala: * vala/valaifstatement.vala: * vala/valainitializerlist.vala: * vala/valalocalvariable.vala: * vala/valalockstatement.vala: * vala/valasemanticanalyzer.vala: * vala/valaswitchsection.vala: * vala/valatrystatement.vala: * vala/valawhilestatement.vala: Move statement checking to code nodes svn path=/trunk/; revision=2003
Diffstat (limited to 'vala')
-rw-r--r--vala/valablock.vala25
-rw-r--r--vala/valacatchclause.vala27
-rw-r--r--vala/valadeclarationstatement.vala21
-rw-r--r--vala/valadeletestatement.vala22
-rw-r--r--vala/valadostatement.vala27
-rw-r--r--vala/valaexpressionstatement.vala20
-rw-r--r--vala/valaforstatement.vala36
-rw-r--r--vala/valaifstatement.vala31
-rw-r--r--vala/valainitializerlist.vala86
-rw-r--r--vala/valalocalvariable.vala92
-rw-r--r--vala/valalockstatement.vala27
-rw-r--r--vala/valasemanticanalyzer.vala334
-rw-r--r--vala/valaswitchsection.vala27
-rw-r--r--vala/valatrystatement.vala12
-rw-r--r--vala/valawhilestatement.vala27
15 files changed, 486 insertions, 328 deletions
diff --git a/vala/valablock.vala b/vala/valablock.vala
index 9de484064..7f050e314 100644
--- a/vala/valablock.vala
+++ b/vala/valablock.vala
@@ -90,4 +90,29 @@ public class Vala.Block : Symbol, Statement {
stmt.accept (visitor);
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ owner = analyzer.current_symbol.scope;
+ analyzer.current_symbol = this;
+
+ accept_children (analyzer);
+
+ foreach (LocalVariable local in get_local_variables ()) {
+ local.active = false;
+ }
+
+ foreach (Statement stmt in get_statements()) {
+ add_error_types (stmt.get_error_types ());
+ }
+
+ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
+
+ return !error;
+ }
}
diff --git a/vala/valacatchclause.vala b/vala/valacatchclause.vala
index 4d4894567..0f1411032 100644
--- a/vala/valacatchclause.vala
+++ b/vala/valacatchclause.vala
@@ -1,4 +1,4 @@
-/* valacatchclause.vala
+/* valacatchvala
*
* Copyright (C) 2007-2008 Jürg Billeter
*
@@ -62,7 +62,7 @@ public class Vala.CatchClause : CodeNode {
private DataType _data_type;
/**
- * Creates a new catch clause.
+ * Creates a new catch
*
* @param type_reference error type
* @param variable_name error variable name
@@ -94,4 +94,27 @@ public class Vala.CatchClause : CodeNode {
error_type = new_type;
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ if (error_type != null) {
+ analyzer.current_source_file.add_type_dependency (error_type, SourceFileDependencyType.SOURCE);
+
+ error_variable = new LocalVariable (error_type.copy (), variable_name);
+
+ body.scope.add (variable_name, error_variable);
+ body.add_local_variable (error_variable);
+ } else {
+ error_type = new ErrorType (null, null, source_reference);
+ }
+
+ accept_children (analyzer);
+
+ return !error;
+ }
}
diff --git a/vala/valadeclarationstatement.vala b/vala/valadeclarationstatement.vala
index 6e981287a..d29c0d6e4 100644
--- a/vala/valadeclarationstatement.vala
+++ b/vala/valadeclarationstatement.vala
@@ -48,4 +48,25 @@ public class Vala.DeclarationStatement : CodeNode, Statement {
visitor.visit_declaration_statement (this);
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ var local = declaration as LocalVariable;
+ if (local != null && local.initializer != null) {
+ foreach (DataType error_type in local.initializer.get_error_types ()) {
+ // ensure we can trace back which expression may throw errors of this type
+ var initializer_error_type = error_type.copy ();
+ initializer_error_type.source_reference = local.initializer.source_reference;
+
+ add_error_type (initializer_error_type);
+ }
+ }
+
+ return !error;
+ }
}
diff --git a/vala/valadeletestatement.vala b/vala/valadeletestatement.vala
index 84097defc..3bbdd6283 100644
--- a/vala/valadeletestatement.vala
+++ b/vala/valadeletestatement.vala
@@ -43,4 +43,26 @@ public class Vala.DeleteStatement : CodeNode, Statement {
public override void accept_children (CodeVisitor visitor) {
expression.accept (visitor);
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ accept_children (analyzer);
+
+ if (expression.error) {
+ // if there was an error in the inner expression, skip this check
+ return false;
+ }
+
+ if (!(expression.value_type is PointerType)) {
+ error = true;
+ Report.error (source_reference, "delete operator not supported for `%s'".printf (expression.value_type.to_string ()));
+ }
+
+ return !error;
+ }
}
diff --git a/vala/valadostatement.vala b/vala/valadostatement.vala
index a2f2d0a76..73db90d41 100644
--- a/vala/valadostatement.vala
+++ b/vala/valadostatement.vala
@@ -86,4 +86,31 @@ public class Vala.DoStatement : CodeNode, Statement {
condition = new_node;
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ accept_children (analyzer);
+
+ if (condition.error) {
+ /* if there was an error in the condition, skip this check */
+ error = true;
+ return false;
+ }
+
+ if (!condition.value_type.compatible (analyzer.bool_type)) {
+ error = true;
+ Report.error (condition.source_reference, "Condition must be boolean");
+ return false;
+ }
+
+ add_error_types (condition.get_error_types ());
+ add_error_types (body.get_error_types ());
+
+ return !error;
+ }
}
diff --git a/vala/valaexpressionstatement.vala b/vala/valaexpressionstatement.vala
index e3fb6ecb3..179b8078c 100644
--- a/vala/valaexpressionstatement.vala
+++ b/vala/valaexpressionstatement.vala
@@ -1,6 +1,6 @@
/* valaexpressionstatement.vala
*
- * Copyright (C) 2006-2007 Jürg Billeter
+ * Copyright (C) 2006-2008 Jürg Billeter
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -85,4 +85,22 @@ public class Vala.ExpressionStatement : CodeNode, Statement {
return null;
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ if (expression.error) {
+ // ignore inner error
+ error = true;
+ return false;
+ }
+
+ add_error_types (expression.get_error_types ());
+
+ return !error;
+ }
}
diff --git a/vala/valaforstatement.vala b/vala/valaforstatement.vala
index 657f95c88..6e309ecdc 100644
--- a/vala/valaforstatement.vala
+++ b/vala/valaforstatement.vala
@@ -156,4 +156,40 @@ public class Vala.ForStatement : CodeNode, Statement {
}
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ accept_children (analyzer);
+
+ if (condition != null && condition.error) {
+ /* if there was an error in the condition, skip this check */
+ error = true;
+ return false;
+ }
+
+ if (condition != null && !condition.value_type.compatible (analyzer.bool_type)) {
+ error = true;
+ Report.error (condition.source_reference, "Condition must be boolean");
+ return false;
+ }
+
+ if (condition != null) {
+ add_error_types (condition.get_error_types ());
+ }
+
+ add_error_types (body.get_error_types ());
+ foreach (Expression exp in get_initializer ()) {
+ add_error_types (exp.get_error_types ());
+ }
+ foreach (Expression exp in get_iterator ()) {
+ add_error_types (exp.get_error_types ());
+ }
+
+ return !error;
+ }
}
diff --git a/vala/valaifstatement.vala b/vala/valaifstatement.vala
index ed11c0c0a..4602097c1 100644
--- a/vala/valaifstatement.vala
+++ b/vala/valaifstatement.vala
@@ -86,4 +86,35 @@ public class Vala.IfStatement : CodeNode, Statement {
condition = new_node;
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ accept_children (analyzer);
+
+ if (condition.error) {
+ /* if there was an error in the condition, skip this check */
+ error = true;
+ return false;
+ }
+
+ if (!condition.value_type.compatible (analyzer.bool_type)) {
+ error = true;
+ Report.error (condition.source_reference, "Condition must be boolean");
+ return false;
+ }
+
+ add_error_types (condition.get_error_types ());
+ add_error_types (true_statement.get_error_types ());
+
+ if (false_statement != null) {
+ add_error_types (false_statement.get_error_types ());
+ }
+
+ return !error;
+ }
}
diff --git a/vala/valainitializerlist.vala b/vala/valainitializerlist.vala
index 35f9ce3f4..b6a58d5d7 100644
--- a/vala/valainitializerlist.vala
+++ b/vala/valainitializerlist.vala
@@ -1,4 +1,4 @@
-/* valainitializerlist.vala
+/* valainitializervala
*
* Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
*
@@ -31,7 +31,7 @@ public class Vala.InitializerList : Expression {
private Gee.List<Expression> initializers = new ArrayList<Expression> ();
/**
- * Appends the specified expression to this initializer list.
+ * Appends the specified expression to this initializer
*
* @param expr an expression
*/
@@ -41,7 +41,7 @@ public class Vala.InitializerList : Expression {
}
/**
- * Returns a copy of the expression list.
+ * Returns a copy of the expression
*
* @return expression list
*/
@@ -50,14 +50,14 @@ public class Vala.InitializerList : Expression {
}
/**
- * Returns the initializer count in this initializer list.
+ * Returns the initializer count in this initializer
*/
public int size {
get { return initializers.size; }
}
/**
- * Creates a new initializer list.
+ * Creates a new initializer
*
* @param source_reference reference to source code
* @return newly created initializer list
@@ -92,4 +92,80 @@ public class Vala.InitializerList : Expression {
}
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ if (target_type == null) {
+ error = true;
+ Report.error (source_reference, "initializer list used for unknown type");
+ return false;
+ } else if (target_type is ArrayType) {
+ /* initializer is used as array initializer */
+ var array_type = (ArrayType) target_type;
+
+ foreach (Expression e in get_initializers ()) {
+ e.target_type = array_type.element_type.copy ();
+ }
+ } else if (target_type.data_type is Struct) {
+ /* initializer is used as struct initializer */
+ var st = (Struct) target_type.data_type;
+
+ var field_it = st.get_fields ().iterator ();
+ foreach (Expression e in get_initializers ()) {
+ Field field = null;
+ while (field == null) {
+ if (!field_it.next ()) {
+ error = true;
+ Report.error (e.source_reference, "too many expressions in initializer list for `%s'".printf (target_type.to_string ()));
+ return false;
+ }
+ field = field_it.get ();
+ if (field.binding != MemberBinding.INSTANCE) {
+ // we only initialize instance fields
+ field = null;
+ }
+ }
+
+ e.target_type = field.field_type.copy ();
+ if (!target_type.value_owned) {
+ e.target_type.value_owned = false;
+ }
+ }
+ } else {
+ error = true;
+ Report.error (source_reference, "initializer list used for `%s', which is neither array nor struct".printf (target_type.to_string ()));
+ return false;
+ }
+
+ accept_children (analyzer);
+
+ bool error = false;
+ foreach (Expression e in get_initializers ()) {
+ if (e.value_type == null) {
+ error = true;
+ continue;
+ }
+
+ var unary = e as UnaryExpression;
+ if (unary != null && (unary.operator == UnaryOperator.REF || unary.operator == UnaryOperator.OUT)) {
+ // TODO check type for ref and out expressions
+ } else if (!e.value_type.compatible (e.target_type)) {
+ error = true;
+ e.error = true;
+ Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (e.target_type.to_string (), e.value_type.to_string ()));
+ }
+ }
+
+ if (!error) {
+ /* everything seems to be correct */
+ value_type = target_type;
+ }
+
+ return !error;
+ }
}
diff --git a/vala/valalocalvariable.vala b/vala/valalocalvariable.vala
index f8767118b..1f1e922b9 100644
--- a/vala/valalocalvariable.vala
+++ b/vala/valalocalvariable.vala
@@ -98,4 +98,96 @@ public class Vala.LocalVariable : Symbol {
variable_type = new_type;
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ if (initializer != null) {
+ initializer.target_type = variable_type;
+ }
+
+ accept_children (analyzer);
+
+ if (variable_type == null) {
+ /* var type */
+
+ if (initializer == null) {
+ error = true;
+ Report.error (source_reference, "var declaration not allowed without initializer");
+ return false;
+ }
+ if (initializer.value_type == null) {
+ error = true;
+ Report.error (source_reference, "var declaration not allowed with non-typed initializer");
+ return false;
+ }
+
+ variable_type = initializer.value_type.copy ();
+ variable_type.value_owned = true;
+ variable_type.floating_reference = false;
+
+ initializer.target_type = variable_type;
+ }
+
+ if (initializer != null) {
+ if (initializer.value_type == null) {
+ if (!(initializer is MemberAccess) && !(initializer is LambdaExpression)) {
+ error = true;
+ Report.error (source_reference, "expression type not allowed as initializer");
+ return false;
+ }
+
+ if (initializer.symbol_reference is Method &&
+ variable_type is DelegateType) {
+ var m = (Method) initializer.symbol_reference;
+ var dt = (DelegateType) variable_type;
+ var cb = dt.delegate_symbol;
+
+ /* check whether method matches callback type */
+ if (!cb.matches_method (m)) {
+ error = true;
+ Report.error (source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
+ return false;
+ }
+
+ initializer.value_type = variable_type;
+ } else {
+ error = true;
+ Report.error (source_reference, "expression type not allowed as initializer");
+ return false;
+ }
+ }
+
+ if (!initializer.value_type.compatible (variable_type)) {
+ error = true;
+ Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (initializer.value_type.to_string (), variable_type.to_string ()));
+ return false;
+ }
+
+ if (initializer.value_type.is_disposable ()) {
+ /* rhs transfers ownership of the expression */
+ if (!(variable_type is PointerType) && !variable_type.value_owned) {
+ /* lhs doesn't own the value */
+ error = true;
+ Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
+ return false;
+ }
+ }
+ }
+
+ analyzer.current_source_file.add_type_dependency (variable_type, SourceFileDependencyType.SOURCE);
+
+ analyzer.current_symbol.scope.add (name, this);
+
+ var block = (Block) analyzer.current_symbol;
+ block.add_local_variable (this);
+
+ active = true;
+
+ return !error;
+ }
}
diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala
index c20763168..49a0224c7 100644
--- a/vala/valalockstatement.vala
+++ b/vala/valalockstatement.vala
@@ -47,4 +47,31 @@ public class Vala.LockStatement : CodeNode, Statement {
body.accept (visitor);
visitor.visit_lock_statement (this);
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ /* resource must be a member access and denote a Lockable */
+ if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) {
+ error = true;
+ resource.error = true;
+ Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
+ return false;
+ }
+
+ /* parent symbol must be the current class */
+ if (resource.symbol_reference.parent_symbol != analyzer.current_class) {
+ error = true;
+ resource.error = true;
+ Report.error (resource.source_reference, "Only members of the current class are lockable");
+ }
+
+ ((Lockable) resource.symbol_reference).set_lock_used (true);
+
+ return !error;
+ }
}
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 826c93714..bcf7b5228 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -229,308 +229,43 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
public override void visit_block (Block b) {
- b.owner = current_symbol.scope;
- current_symbol = b;
-
- b.accept_children (this);
-
- foreach (LocalVariable local in b.get_local_variables ()) {
- local.active = false;
- }
-
- foreach (Statement stmt in b.get_statements()) {
- b.add_error_types (stmt.get_error_types ());
- }
-
- current_symbol = current_symbol.parent_symbol;
+ b.check (this);
}
public override void visit_declaration_statement (DeclarationStatement stmt) {
- var local = stmt.declaration as LocalVariable;
- if (local != null && local.initializer != null) {
- foreach (DataType error_type in local.initializer.get_error_types ()) {
- // ensure we can trace back which expression may throw errors of this type
- var initializer_error_type = error_type.copy ();
- initializer_error_type.source_reference = local.initializer.source_reference;
-
- stmt.add_error_type (initializer_error_type);
- }
- }
+ stmt.check (this);
}
public override void visit_local_variable (LocalVariable local) {
- if (local.initializer != null) {
- local.initializer.target_type = local.variable_type;
- }
-
- local.accept_children (this);
-
- if (local.variable_type == null) {
- /* var type */
-
- if (local.initializer == null) {
- local.error = true;
- Report.error (local.source_reference, "var declaration not allowed without initializer");
- return;
- }
- if (local.initializer.value_type == null) {
- local.error = true;
- Report.error (local.source_reference, "var declaration not allowed with non-typed initializer");
- return;
- }
-
- local.variable_type = local.initializer.value_type.copy ();
- local.variable_type.value_owned = true;
- local.variable_type.floating_reference = false;
-
- local.initializer.target_type = local.variable_type;
- }
-
- if (local.initializer != null) {
- if (local.initializer.value_type == null) {
- if (!(local.initializer is MemberAccess) && !(local.initializer is LambdaExpression)) {
- local.error = true;
- Report.error (local.source_reference, "expression type not allowed as initializer");
- return;
- }
-
- if (local.initializer.symbol_reference is Method &&
- local.variable_type is DelegateType) {
- var m = (Method) local.initializer.symbol_reference;
- var dt = (DelegateType) local.variable_type;
- var cb = dt.delegate_symbol;
-
- /* check whether method matches callback type */
- if (!cb.matches_method (m)) {
- local.error = true;
- Report.error (local.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
- return;
- }
-
- local.initializer.value_type = local.variable_type;
- } else {
- local.error = true;
- Report.error (local.source_reference, "expression type not allowed as initializer");
- return;
- }
- }
-
- if (!local.initializer.value_type.compatible (local.variable_type)) {
- local.error = true;
- Report.error (local.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (local.initializer.value_type.to_string (), local.variable_type.to_string ()));
- return;
- }
-
- if (local.initializer.value_type.is_disposable ()) {
- /* rhs transfers ownership of the expression */
- if (!(local.variable_type is PointerType) && !local.variable_type.value_owned) {
- /* lhs doesn't own the value */
- local.error = true;
- Report.error (local.source_reference, "Invalid assignment from owned expression to unowned variable");
- return;
- }
- }
- }
-
- current_source_file.add_type_dependency (local.variable_type, SourceFileDependencyType.SOURCE);
-
- current_symbol.scope.add (local.name, local);
-
- var block = (Block) current_symbol;
- block.add_local_variable (local);
-
- local.active = true;
+ local.check (this);
}
- /**
- * Visit operation called for initializer lists
- *
- * @param list an initializer list
- */
public override void visit_initializer_list (InitializerList list) {
- if (list.target_type == null) {
- list.error = true;
- Report.error (list.source_reference, "initializer list used for unknown type");
- return;
- } else if (list.target_type is ArrayType) {
- /* initializer is used as array initializer */
- var array_type = (ArrayType) list.target_type;
-
- foreach (Expression e in list.get_initializers ()) {
- e.target_type = array_type.element_type.copy ();
- }
- } else if (list.target_type.data_type is Struct) {
- /* initializer is used as struct initializer */
- var st = (Struct) list.target_type.data_type;
-
- var field_it = st.get_fields ().iterator ();
- foreach (Expression e in list.get_initializers ()) {
- Field field = null;
- while (field == null) {
- if (!field_it.next ()) {
- list.error = true;
- Report.error (e.source_reference, "too many expressions in initializer list for `%s'".printf (list.target_type.to_string ()));
- return;
- }
- field = field_it.get ();
- if (field.binding != MemberBinding.INSTANCE) {
- // we only initialize instance fields
- field = null;
- }
- }
-
- e.target_type = field.field_type.copy ();
- if (!list.target_type.value_owned) {
- e.target_type.value_owned = false;
- }
- }
- } else {
- list.error = true;
- Report.error (list.source_reference, "initializer list used for `%s', which is neither array nor struct".printf (list.target_type.to_string ()));
- return;
- }
-
- list.accept_children (this);
-
- bool error = false;
- foreach (Expression e in list.get_initializers ()) {
- if (e.value_type == null) {
- error = true;
- continue;
- }
-
- var unary = e as UnaryExpression;
- if (unary != null && (unary.operator == UnaryOperator.REF || unary.operator == UnaryOperator.OUT)) {
- // TODO check type for ref and out expressions
- } else if (!e.value_type.compatible (e.target_type)) {
- error = true;
- e.error = true;
- Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (e.target_type.to_string (), e.value_type.to_string ()));
- }
- }
-
- if (!error) {
- /* everything seems to be correct */
- list.value_type = list.target_type;
- }
+ list.check (this);
}
public override void visit_expression_statement (ExpressionStatement stmt) {
- if (stmt.expression.error) {
- // ignore inner error
- stmt.error = true;
- return;
- }
-
- stmt.add_error_types (stmt.expression.get_error_types ());
+ stmt.check (this);
}
public override void visit_if_statement (IfStatement stmt) {
- stmt.accept_children (this);
-
- if (stmt.condition.error) {
- /* if there was an error in the condition, skip this check */
- stmt.error = true;
- return;
- }
-
- if (!stmt.condition.value_type.compatible (bool_type)) {
- stmt.error = true;
- Report.error (stmt.condition.source_reference, "Condition must be boolean");
- return;
- }
-
- stmt.add_error_types (stmt.condition.get_error_types ());
- stmt.add_error_types (stmt.true_statement.get_error_types ());
-
- if (stmt.false_statement != null) {
- stmt.add_error_types (stmt.false_statement.get_error_types ());
- }
+ stmt.check (this);
}
public override void visit_switch_section (SwitchSection section) {
- foreach (SwitchLabel label in section.get_labels ()) {
- label.accept (this);
- }
-
- section.owner = current_symbol.scope;
- current_symbol = section;
-
- foreach (Statement st in section.get_statements ()) {
- st.accept (this);
- }
-
- foreach (LocalVariable local in section.get_local_variables ()) {
- local.active = false;
- }
-
- current_symbol = current_symbol.parent_symbol;
+ section.check (this);
}
public override void visit_while_statement (WhileStatement stmt) {
- stmt.accept_children (this);
-
- if (stmt.condition.error) {
- /* if there was an error in the condition, skip this check */
- stmt.error = true;
- return;
- }
-
- if (!stmt.condition.value_type.compatible (bool_type)) {
- stmt.error = true;
- Report.error (stmt.condition.source_reference, "Condition must be boolean");
- return;
- }
-
- stmt.add_error_types (stmt.condition.get_error_types ());
- stmt.add_error_types (stmt.body.get_error_types ());
+ stmt.check (this);
}
public override void visit_do_statement (DoStatement stmt) {
- stmt.accept_children (this);
-
- if (stmt.condition.error) {
- /* if there was an error in the condition, skip this check */
- stmt.error = true;
- return;
- }
-
- if (!stmt.condition.value_type.compatible (bool_type)) {
- stmt.error = true;
- Report.error (stmt.condition.source_reference, "Condition must be boolean");
- return;
- }
-
- stmt.add_error_types (stmt.condition.get_error_types ());
- stmt.add_error_types (stmt.body.get_error_types ());
+ stmt.check (this);
}
public override void visit_for_statement (ForStatement stmt) {
- stmt.accept_children (this);
-
- if (stmt.condition != null && stmt.condition.error) {
- /* if there was an error in the condition, skip this check */
- stmt.error = true;
- return;
- }
-
- if (stmt.condition != null && !stmt.condition.value_type.compatible (bool_type)) {
- stmt.error = true;
- Report.error (stmt.condition.source_reference, "Condition must be boolean");
- return;
- }
-
- if (stmt.condition != null) {
- stmt.add_error_types (stmt.condition.get_error_types ());
- }
-
- stmt.add_error_types (stmt.body.get_error_types ());
- foreach (Expression exp in stmt.get_initializer ()) {
- stmt.add_error_types (exp.get_error_types ());
- }
- foreach (Expression exp in stmt.get_iterator ()) {
- stmt.add_error_types (exp.get_error_types ());
- }
+ stmt.check (this);
}
public override void visit_foreach_statement (ForeachStatement stmt) {
@@ -550,62 +285,21 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
public override void visit_try_statement (TryStatement stmt) {
- stmt.accept_children (this);
+ stmt.check (this);
}
public override void visit_catch_clause (CatchClause clause) {
- if (clause.error_type != null) {
- current_source_file.add_type_dependency (clause.error_type, SourceFileDependencyType.SOURCE);
-
- clause.error_variable = new LocalVariable (clause.error_type.copy (), clause.variable_name);
-
- clause.body.scope.add (clause.variable_name, clause.error_variable);
- clause.body.add_local_variable (clause.error_variable);
- } else {
- clause.error_type = new ErrorType (null, null, clause.source_reference);
- }
-
- clause.accept_children (this);
+ clause.check (this);
}
public override void visit_lock_statement (LockStatement stmt) {
- /* resource must be a member access and denote a Lockable */
- if (!(stmt.resource is MemberAccess && stmt.resource.symbol_reference is Lockable)) {
- stmt.error = true;
- stmt.resource.error = true;
- Report.error (stmt.resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
- return;
- }
-
- /* parent symbol must be the current class */
- if (stmt.resource.symbol_reference.parent_symbol != current_class) {
- stmt.error = true;
- stmt.resource.error = true;
- Report.error (stmt.resource.source_reference, "Only members of the current class are lockable");
- }
-
- ((Lockable) stmt.resource.symbol_reference).set_lock_used (true);
+ stmt.check (this);
}
public override void visit_delete_statement (DeleteStatement stmt) {
- stmt.accept_children (this);
-
- if (stmt.expression.error) {
- // if there was an error in the inner expression, skip this check
- return;
- }
-
- if (!(stmt.expression.value_type is PointerType)) {
- stmt.error = true;
- Report.error (stmt.source_reference, "delete operator not supported for `%s'".printf (stmt.expression.value_type.to_string ()));
- }
+ stmt.check (this);
}
- /**
- * Visit operations called for array creation expresions.
- *
- * @param expr an array creation expression
- */
public override void visit_array_creation_expression (ArrayCreationExpression expr) {
expr.check (this);
}
diff --git a/vala/valaswitchsection.vala b/vala/valaswitchsection.vala
index 2212c47b9..2f38944eb 100644
--- a/vala/valaswitchsection.vala
+++ b/vala/valaswitchsection.vala
@@ -80,4 +80,31 @@ public class Vala.SwitchSection : Block {
st.accept (visitor);
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ foreach (SwitchLabel label in get_labels ()) {
+ label.accept (analyzer);
+ }
+
+ owner = analyzer.current_symbol.scope;
+ analyzer.current_symbol = this;
+
+ foreach (Statement st in get_statements ()) {
+ st.accept (analyzer);
+ }
+
+ foreach (LocalVariable local in get_local_variables ()) {
+ local.active = false;
+ }
+
+ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
+
+ return !error;
+ }
}
diff --git a/vala/valatrystatement.vala b/vala/valatrystatement.vala
index d4eec46a2..456724d60 100644
--- a/vala/valatrystatement.vala
+++ b/vala/valatrystatement.vala
@@ -86,4 +86,16 @@ public class Vala.TryStatement : CodeNode, Statement {
finally_body.accept (visitor);
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ accept_children (analyzer);
+
+ return !error;
+ }
}
diff --git a/vala/valawhilestatement.vala b/vala/valawhilestatement.vala
index 947a70831..ee3a43c67 100644
--- a/vala/valawhilestatement.vala
+++ b/vala/valawhilestatement.vala
@@ -86,4 +86,31 @@ public class Vala.WhileStatement : CodeNode, Statement {
condition = new_node;
}
}
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ accept_children (analyzer);
+
+ if (condition.error) {
+ /* if there was an error in the condition, skip this check */
+ error = true;
+ return false;
+ }
+
+ if (!condition.value_type.compatible (analyzer.bool_type)) {
+ error = true;
+ Report.error (condition.source_reference, "Condition must be boolean");
+ return false;
+ }
+
+ add_error_types (condition.get_error_types ());
+ add_error_types (body.get_error_types ());
+
+ return !error;
+ }
}