diff options
author | Jürg Billeter <j@bitron.ch> | 2008-11-07 11:10:31 +0000 |
---|---|---|
committer | Jürg Billeter <juergbi@src.gnome.org> | 2008-11-07 11:10:31 +0000 |
commit | 955c4f6c3e8bf120d363015897528567b2df23ed (patch) | |
tree | bfbcfdbf98058f2de5f17491ee63934b98ca8355 /vala | |
parent | 4ed3719f219f7ee4d3c40544df7ec75719fae8fd (diff) | |
download | vala-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.vala | 25 | ||||
-rw-r--r-- | vala/valacatchclause.vala | 27 | ||||
-rw-r--r-- | vala/valadeclarationstatement.vala | 21 | ||||
-rw-r--r-- | vala/valadeletestatement.vala | 22 | ||||
-rw-r--r-- | vala/valadostatement.vala | 27 | ||||
-rw-r--r-- | vala/valaexpressionstatement.vala | 20 | ||||
-rw-r--r-- | vala/valaforstatement.vala | 36 | ||||
-rw-r--r-- | vala/valaifstatement.vala | 31 | ||||
-rw-r--r-- | vala/valainitializerlist.vala | 86 | ||||
-rw-r--r-- | vala/valalocalvariable.vala | 92 | ||||
-rw-r--r-- | vala/valalockstatement.vala | 27 | ||||
-rw-r--r-- | vala/valasemanticanalyzer.vala | 334 | ||||
-rw-r--r-- | vala/valaswitchsection.vala | 27 | ||||
-rw-r--r-- | vala/valatrystatement.vala | 12 | ||||
-rw-r--r-- | vala/valawhilestatement.vala | 27 |
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; + } } |