From: Jürg Billeter Date: Mon, 10 Nov 2008 18:56:28 +0000 (+0000) Subject: Move expression checking to code nodes X-Git-Tag: VALA_0_5_2~102 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=67649405484570ae012df33b302e0b708a027b2e;p=thirdparty%2Fvala.git Move expression checking to code nodes 2008-11-10 Jürg Billeter * vala/valaaddressofexpression.vala: * vala/valabaseaccess.vala: * vala/valabooleanliteral.vala: * vala/valacastexpression.vala: * vala/valacharacterliteral.vala: * vala/valaconditionalexpression.vala: * vala/valaintegerliteral.vala: * vala/valalambdaexpression.vala: * vala/valanullliteral.vala: * vala/valaobjectcreationexpression.vala: * vala/valaparenthesizedexpression.vala: * vala/valapointerindirection.vala: * vala/valapostfixexpression.vala: * vala/valarealliteral.vala: * vala/valareferencetransferexpression.vala: * vala/valasemanticanalyzer.vala: * vala/valasizeofexpression.vala: * vala/valastringliteral.vala: * vala/valatypecheck.vala: * vala/valatypeofexpression.vala: * vala/valaunaryexpression.vala: Move expression checking to code nodes svn path=/trunk/; revision=2009 --- diff --git a/ChangeLog b/ChangeLog index 0d7530e0e..b5b677a64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2008-11-10 Jürg Billeter + + * vala/valaaddressofexpression.vala: + * vala/valabaseaccess.vala: + * vala/valabooleanliteral.vala: + * vala/valacastexpression.vala: + * vala/valacharacterliteral.vala: + * vala/valaconditionalexpression.vala: + * vala/valaintegerliteral.vala: + * vala/valalambdaexpression.vala: + * vala/valanullliteral.vala: + * vala/valaobjectcreationexpression.vala: + * vala/valaparenthesizedexpression.vala: + * vala/valapointerindirection.vala: + * vala/valapostfixexpression.vala: + * vala/valarealliteral.vala: + * vala/valareferencetransferexpression.vala: + * vala/valasemanticanalyzer.vala: + * vala/valasizeofexpression.vala: + * vala/valastringliteral.vala: + * vala/valatypecheck.vala: + * vala/valatypeofexpression.vala: + * vala/valaunaryexpression.vala: + + Move expression checking to code nodes + 2008-11-10 Jürg Billeter * gobject/valadbusservermodule.vala: diff --git a/vala/valaaddressofexpression.vala b/vala/valaaddressofexpression.vala index 1d1f714bc..38781bb89 100644 --- a/vala/valaaddressofexpression.vala +++ b/vala/valaaddressofexpression.vala @@ -1,6 +1,6 @@ /* valaaddressofexpression.vala * - * Copyright (C) 2007 Jürg Billeter + * Copyright (C) 2007-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 @@ -69,4 +69,31 @@ public class Vala.AddressofExpression : Expression { public override bool is_pure () { return inner.is_pure (); } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + if (inner.error) { + return false; + } + if (!(inner.value_type is ValueType + || inner.value_type is ObjectType + || inner.value_type is PointerType)) { + error = true; + Report.error (source_reference, "Address-of operator not supported for this expression"); + return false; + } + + if (inner.value_type.is_reference_type_or_type_parameter ()) { + value_type = new PointerType (new PointerType (inner.value_type)); + } else { + value_type = new PointerType (inner.value_type); + } + + return !error; + } } diff --git a/vala/valabaseaccess.vala b/vala/valabaseaccess.vala index 7c650b8ed..1de0c7a78 100644 --- a/vala/valabaseaccess.vala +++ b/vala/valabaseaccess.vala @@ -1,6 +1,6 @@ /* valabaseaccess.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 @@ -20,7 +20,7 @@ * Jürg Billeter */ -using GLib; +using Gee; /** * Represents an access to base class members in the source code. @@ -49,4 +49,43 @@ public class Vala.BaseAccess : Expression { public override bool is_pure () { return true; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + if (!analyzer.is_in_instance_method ()) { + error = true; + Report.error (source_reference, "Base access invalid outside of instance methods"); + return false; + } + + if (analyzer.current_class == null) { + if (analyzer.current_struct == null) { + error = true; + Report.error (source_reference, "Base access invalid outside of class and struct"); + return false; + } else if (analyzer.current_struct.get_base_types ().size != 1) { + error = true; + Report.error (source_reference, "Base access invalid without base type %d".printf (analyzer.current_struct.get_base_types ().size)); + return false; + } + Iterator base_type_it = analyzer.current_struct.get_base_types ().iterator (); + base_type_it.next (); + value_type = base_type_it.get (); + } else if (analyzer.current_class.base_class == null) { + error = true; + Report.error (source_reference, "Base access invalid without base class"); + return false; + } else { + value_type = new ObjectType (analyzer.current_class.base_class); + } + + symbol_reference = value_type.data_type; + + return !error; + } } diff --git a/vala/valabooleanliteral.vala b/vala/valabooleanliteral.vala index 24eb3fd9d..db05f0afd 100644 --- a/vala/valabooleanliteral.vala +++ b/vala/valabooleanliteral.vala @@ -60,4 +60,16 @@ public class Vala.BooleanLiteral : Literal { public override bool is_pure () { return true; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = analyzer.bool_type; + + return !error; + } } diff --git a/vala/valacastexpression.vala b/vala/valacastexpression.vala index 830ab6894..5703815f6 100644 --- a/vala/valacastexpression.vala +++ b/vala/valacastexpression.vala @@ -1,6 +1,6 @@ /* valacastexpression.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 @@ -97,4 +97,28 @@ public class Vala.CastExpression : Expression { type_reference = new_type; } } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + if (inner.error) { + error = true; + return false; + } + + // FIXME: check whether cast is allowed + + analyzer.current_source_file.add_type_dependency (type_reference, SourceFileDependencyType.SOURCE); + + value_type = type_reference; + value_type.value_owned = inner.value_type.value_owned; + + inner.target_type = inner.value_type.copy (); + + return !error; + } } diff --git a/vala/valacharacterliteral.vala b/vala/valacharacterliteral.vala index 422be4d4a..019439fe7 100644 --- a/vala/valacharacterliteral.vala +++ b/vala/valacharacterliteral.vala @@ -77,4 +77,16 @@ public class Vala.CharacterLiteral : Literal { public override bool is_pure () { return true; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = new ValueType ((TypeSymbol) analyzer.root_symbol.scope.lookup ("char")); + + return !error; + } } diff --git a/vala/valaconditionalexpression.vala b/vala/valaconditionalexpression.vala index 59357259b..e0d665181 100644 --- a/vala/valaconditionalexpression.vala +++ b/vala/valaconditionalexpression.vala @@ -1,6 +1,6 @@ /* valaconditionalexpression.vala * - * Copyright (C) 2006 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 @@ -69,4 +69,35 @@ public class Vala.ConditionalExpression : Expression { public override bool is_pure () { return condition.is_pure () && true_expression.is_pure () && false_expression.is_pure (); } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + if (condition.error || false_expression.error || true_expression.error) { + return false; + } + + if (!condition.value_type.compatible (analyzer.bool_type)) { + error = true; + Report.error (condition.source_reference, "Condition must be boolean"); + return false; + } + + /* FIXME: support memory management */ + if (false_expression.value_type.compatible (true_expression.value_type)) { + value_type = true_expression.value_type.copy (); + } else if (true_expression.value_type.compatible (false_expression.value_type)) { + value_type = false_expression.value_type.copy (); + } else { + error = true; + Report.error (condition.source_reference, "Incompatible expressions"); + return false; + } + + return !error; + } } diff --git a/vala/valaintegerliteral.vala b/vala/valaintegerliteral.vala index 2a952b455..73a2910de 100644 --- a/vala/valaintegerliteral.vala +++ b/vala/valaintegerliteral.vala @@ -106,4 +106,16 @@ public class Vala.IntegerLiteral : Literal { public override bool is_pure () { return true; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = new IntegerType ((TypeSymbol) analyzer.root_symbol.scope.lookup (get_type_name ()), value, get_type_name ()); + + return !error; + } } diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala index 9af274766..3cd074cfa 100644 --- a/vala/valalambdaexpression.vala +++ b/vala/valalambdaexpression.vala @@ -1,6 +1,6 @@ /* valalambdaexpression.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 @@ -111,4 +111,88 @@ public class Vala.LambdaExpression : Expression { public override bool is_pure () { return false; } + + string get_lambda_name (SemanticAnalyzer analyzer) { + var result = "__lambda%d".printf (analyzer.next_lambda_id); + + analyzer.next_lambda_id++; + + return result; + } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + if (!(target_type is DelegateType)) { + error = true; + Report.error (source_reference, "lambda expression not allowed in this context"); + return false; + } + + bool in_instance_method = false; + var current_method = analyzer.find_current_method (); + if (current_method != null) { + in_instance_method = (current_method.binding == MemberBinding.INSTANCE); + } else { + in_instance_method = analyzer.is_in_constructor (); + } + + var cb = (Delegate) ((DelegateType) target_type).delegate_symbol; + method = new Method (get_lambda_name (analyzer), cb.return_type); + if (!cb.has_target || !in_instance_method) { + method.binding = MemberBinding.STATIC; + } + method.owner = analyzer.current_symbol.scope; + + var lambda_params = get_parameters (); + Iterator lambda_param_it = lambda_params.iterator (); + foreach (FormalParameter cb_param in cb.get_parameters ()) { + if (!lambda_param_it.next ()) { + /* lambda expressions are allowed to have less parameters */ + break; + } + + string lambda_param = lambda_param_it.get (); + + var param = new FormalParameter (lambda_param, cb_param.parameter_type); + + method.add_parameter (param); + } + + if (lambda_param_it.next ()) { + /* lambda expressions may not expect more parameters */ + error = true; + Report.error (source_reference, "lambda expression: too many parameters"); + return false; + } + + if (expression_body != null) { + var block = new Block (source_reference); + block.scope.parent_scope = method.scope; + + if (method.return_type.data_type != null) { + block.add_statement (new ReturnStatement (expression_body, source_reference)); + } else { + block.add_statement (new ExpressionStatement (expression_body, source_reference)); + } + + method.body = block; + } else { + method.body = statement_body; + } + method.body.owner = method.scope; + + /* lambda expressions should be usable like MemberAccess of a method */ + symbol_reference = method; + + accept_children (analyzer); + + value_type = new MethodType (method); + + return !error; + } } diff --git a/vala/valanullliteral.vala b/vala/valanullliteral.vala index 69321a890..daa714512 100644 --- a/vala/valanullliteral.vala +++ b/vala/valanullliteral.vala @@ -49,4 +49,16 @@ public class Vala.NullLiteral : Literal { public override bool is_pure () { return true; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = new NullType (source_reference); + + return !error; + } } diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala index 04b5f07d8..c458c042a 100644 --- a/vala/valaobjectcreationexpression.vala +++ b/vala/valaobjectcreationexpression.vala @@ -1,6 +1,6 @@ /* valaobjectcreationexpression.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 diff --git a/vala/valaparenthesizedexpression.vala b/vala/valaparenthesizedexpression.vala index 2c2db7a33..c7e2dd5af 100644 --- a/vala/valaparenthesizedexpression.vala +++ b/vala/valaparenthesizedexpression.vala @@ -72,4 +72,38 @@ public class Vala.ParenthesizedExpression : Expression { public override bool is_pure () { return inner.is_pure (); } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + inner.target_type = target_type; + + accept_children (analyzer); + + if (inner.error) { + // ignore inner error + error = true; + return false; + } + + if (inner.value_type == null) { + // static type may be null for method references + error = true; + Report.error (inner.source_reference, "Invalid expression type"); + return false; + } + + value_type = inner.value_type.copy (); + // don't call g_object_ref_sink on inner and outer expression + value_type.floating_reference = false; + + // don't transform expression twice + inner.target_type = inner.value_type.copy (); + + return !error; + } } diff --git a/vala/valapointerindirection.vala b/vala/valapointerindirection.vala index 5606a3ca2..7ea1354dd 100644 --- a/vala/valapointerindirection.vala +++ b/vala/valapointerindirection.vala @@ -1,6 +1,6 @@ /* valapointerindirection.vala * - * Copyright (C) 2007 Jürg Billeter + * Copyright (C) 2007-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 @@ -69,4 +69,36 @@ public class Vala.PointerIndirection : Expression { public override bool is_pure () { return inner.is_pure (); } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + if (inner.error) { + return false; + } + if (inner.value_type == null) { + error = true; + Report.error (source_reference, "internal error: unknown type of inner expression"); + return false; + } + if (inner.value_type is PointerType) { + var pointer_type = (PointerType) inner.value_type; + if (pointer_type.base_type is ReferenceType) { + error = true; + Report.error (source_reference, "Pointer indirection not supported for this expression"); + return false; + } + value_type = pointer_type.base_type; + } else { + error = true; + Report.error (source_reference, "Pointer indirection not supported for this expression"); + return false; + } + + return !error; + } } diff --git a/vala/valapostfixexpression.vala b/vala/valapostfixexpression.vala index 9c5f13c11..c1d8eba6f 100644 --- a/vala/valapostfixexpression.vala +++ b/vala/valapostfixexpression.vala @@ -1,6 +1,6 @@ /* valapostfixexpression.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 @@ -61,4 +61,16 @@ public class Vala.PostfixExpression : Expression { public override bool is_pure () { return false; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = inner.value_type; + + return !error; + } } diff --git a/vala/valarealliteral.vala b/vala/valarealliteral.vala index 562d8389d..19d598da8 100644 --- a/vala/valarealliteral.vala +++ b/vala/valarealliteral.vala @@ -69,4 +69,16 @@ public class Vala.RealLiteral : Literal { public override string to_string () { return value; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = new ValueType ((TypeSymbol) analyzer.root_symbol.scope.lookup (get_type_name ())); + + return !error; + } } diff --git a/vala/valareferencetransferexpression.vala b/vala/valareferencetransferexpression.vala index 2c6b4e292..71b965ac6 100644 --- a/vala/valareferencetransferexpression.vala +++ b/vala/valareferencetransferexpression.vala @@ -71,4 +71,40 @@ public class Vala.ReferenceTransferExpression : Expression { public override bool is_pure () { return false; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + inner.lvalue = true; + + accept_children (analyzer); + + if (inner.error) { + /* if there was an error in the inner expression, skip type check */ + error = true; + return false; + } + + if (!(inner is MemberAccess || inner is ElementAccess)) { + error = true; + Report.error (source_reference, "Reference transfer not supported for this expression"); + return false; + } + + if (!inner.value_type.is_disposable () + && !(inner.value_type is PointerType)) { + error = true; + Report.error (source_reference, "No reference to be transferred"); + return false; + } + + value_type = inner.value_type.copy (); + value_type.value_owned = true; + + return !error; + } } diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index b3ef26433..522dade92 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -63,7 +63,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { public Interface collection_type; public Interface map_type; - private int next_lambda_id = 0; + public int next_lambda_id = 0; // keep replaced alive to make sure they remain valid // for the whole execution of CodeNode.accept @@ -300,27 +300,27 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } public override void visit_boolean_literal (BooleanLiteral expr) { - expr.value_type = bool_type; + expr.check (this); } public override void visit_character_literal (CharacterLiteral expr) { - expr.value_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup ("char")); + expr.check (this); } public override void visit_integer_literal (IntegerLiteral expr) { - expr.value_type = new IntegerType ((TypeSymbol) root_symbol.scope.lookup (expr.get_type_name ()), expr.value, expr.get_type_name ()); + expr.check (this); } public override void visit_real_literal (RealLiteral expr) { - expr.value_type = new ValueType ((TypeSymbol) root_symbol.scope.lookup (expr.get_type_name ())); + expr.check (this); } public override void visit_string_literal (StringLiteral expr) { - expr.value_type = string_type.copy (); + expr.check (this); } public override void visit_null_literal (NullLiteral expr) { - expr.value_type = new NullType (expr.source_reference); + expr.check (this); } public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) { @@ -421,29 +421,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } public override void visit_parenthesized_expression (ParenthesizedExpression expr) { - expr.inner.target_type = expr.target_type; - - expr.accept_children (this); - - if (expr.inner.error) { - // ignore inner error - expr.error = true; - return; - } - - if (expr.inner.value_type == null) { - // static type may be null for method references - expr.error = true; - Report.error (expr.inner.source_reference, "Invalid expression type"); - return; - } - - expr.value_type = expr.inner.value_type.copy (); - // don't call g_object_ref_sink on inner and outer expression - expr.value_type.floating_reference = false; - - // don't transform expression twice - expr.inner.target_type = expr.inner.value_type.copy (); + expr.check (this); } public override void visit_member_access (MemberAccess expr) { @@ -799,38 +777,11 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } public override void visit_base_access (BaseAccess expr) { - if (!is_in_instance_method ()) { - expr.error = true; - Report.error (expr.source_reference, "Base access invalid outside of instance methods"); - return; - } - - if (current_class == null) { - if (current_struct == null) { - expr.error = true; - Report.error (expr.source_reference, "Base access invalid outside of class and struct"); - return; - } else if (current_struct.get_base_types ().size != 1) { - expr.error = true; - Report.error (expr.source_reference, "Base access invalid without base type %d".printf (current_struct.get_base_types ().size)); - return; - } - Iterator base_type_it = current_struct.get_base_types ().iterator (); - base_type_it.next (); - expr.value_type = base_type_it.get (); - } else if (current_class.base_class == null) { - expr.error = true; - Report.error (expr.source_reference, "Base access invalid without base class"); - return; - } else { - expr.value_type = new ObjectType (current_class.base_class); - } - - expr.symbol_reference = expr.value_type.data_type; + expr.check (this); } public override void visit_postfix_expression (PostfixExpression expr) { - expr.value_type = expr.inner.value_type; + expr.check (this); } public override void visit_object_creation_expression (ObjectCreationExpression expr) { @@ -872,213 +823,31 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } public override void visit_sizeof_expression (SizeofExpression expr) { - expr.value_type = ulong_type; + expr.check (this); } public override void visit_typeof_expression (TypeofExpression expr) { - expr.value_type = type_type; - } - - private bool is_numeric_type (DataType type) { - if (!(type.data_type is Struct)) { - return false; - } - - var st = (Struct) type.data_type; - return st.is_integer_type () || st.is_floating_type (); - } - - private bool is_integer_type (DataType type) { - if (!(type.data_type is Struct)) { - return false; - } - - var st = (Struct) type.data_type; - return st.is_integer_type (); + expr.check (this); } public override void visit_unary_expression (UnaryExpression expr) { - if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) { - expr.inner.lvalue = true; - expr.inner.target_type = expr.target_type; - } - - expr.accept_children (this); - - if (expr.inner.error) { - /* if there was an error in the inner expression, skip type check */ - expr.error = true; - return; - } - - if (expr.operator == UnaryOperator.PLUS || expr.operator == UnaryOperator.MINUS) { - // integer or floating point type - if (!is_numeric_type (expr.inner.value_type)) { - expr.error = true; - Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.value_type.to_string ())); - return; - } - - expr.value_type = expr.inner.value_type; - } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) { - // boolean type - if (!expr.inner.value_type.compatible (bool_type)) { - expr.error = true; - Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.value_type.to_string ())); - return; - } - - expr.value_type = expr.inner.value_type; - } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) { - // integer type - if (!is_integer_type (expr.inner.value_type)) { - expr.error = true; - Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.value_type.to_string ())); - return; - } - - expr.value_type = expr.inner.value_type; - } else if (expr.operator == UnaryOperator.INCREMENT || - expr.operator == UnaryOperator.DECREMENT) { - // integer type - if (!is_integer_type (expr.inner.value_type)) { - expr.error = true; - Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.value_type.to_string ())); - return; - } - - var ma = find_member_access (expr.inner); - if (ma == null) { - expr.error = true; - Report.error (expr.source_reference, "Prefix operators not supported for this expression"); - return; - } - - var old_value = new MemberAccess (ma.inner, ma.member_name, expr.inner.source_reference); - var bin = new BinaryExpression (expr.operator == UnaryOperator.INCREMENT ? BinaryOperator.PLUS : BinaryOperator.MINUS, old_value, new IntegerLiteral ("1"), expr.source_reference); - - var assignment = new Assignment (ma, bin, AssignmentOperator.SIMPLE, expr.source_reference); - var parenthexp = new ParenthesizedExpression (assignment, expr.source_reference); - parenthexp.target_type = expr.target_type; - replaced_nodes.add (expr); - expr.parent_node.replace_expression (expr, parenthexp); - parenthexp.accept (this); - return; - } else if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) { - if (expr.inner.symbol_reference is Field || expr.inner.symbol_reference is FormalParameter || expr.inner.symbol_reference is LocalVariable) { - // ref and out can only be used with fields, parameters, and local variables - expr.lvalue = true; - expr.value_type = expr.inner.value_type; - } else { - expr.error = true; - Report.error (expr.source_reference, "ref and out method arguments can only be used with fields, parameters, and local variables"); - return; - } - } else { - expr.error = true; - Report.error (expr.source_reference, "internal error: unsupported unary operator"); - return; - } - } - - private MemberAccess? find_member_access (Expression expr) { - if (expr is ParenthesizedExpression) { - var pe = (ParenthesizedExpression) expr; - return find_member_access (pe.inner); - } - - if (expr is MemberAccess) { - return (MemberAccess) expr; - } - - return null; + expr.check (this); } public override void visit_cast_expression (CastExpression expr) { - if (expr.inner.error) { - expr.error = true; - return; - } - - // FIXME: check whether cast is allowed - - current_source_file.add_type_dependency (expr.type_reference, SourceFileDependencyType.SOURCE); - - expr.value_type = expr.type_reference; - expr.value_type.value_owned = expr.inner.value_type.value_owned; - - expr.inner.target_type = expr.inner.value_type.copy (); + expr.check (this); } public override void visit_pointer_indirection (PointerIndirection expr) { - if (expr.inner.error) { - return; - } - if (expr.inner.value_type == null) { - expr.error = true; - Report.error (expr.source_reference, "internal error: unknown type of inner expression"); - return; - } - if (expr.inner.value_type is PointerType) { - var pointer_type = (PointerType) expr.inner.value_type; - if (pointer_type.base_type is ReferenceType) { - expr.error = true; - Report.error (expr.source_reference, "Pointer indirection not supported for this expression"); - return; - } - expr.value_type = pointer_type.base_type; - } else { - expr.error = true; - Report.error (expr.source_reference, "Pointer indirection not supported for this expression"); - return; - } + expr.check (this); } public override void visit_addressof_expression (AddressofExpression expr) { - if (expr.inner.error) { - return; - } - if (!(expr.inner.value_type is ValueType - || expr.inner.value_type is ObjectType - || expr.inner.value_type is PointerType)) { - expr.error = true; - Report.error (expr.source_reference, "Address-of operator not supported for this expression"); - return; - } - - if (expr.inner.value_type.is_reference_type_or_type_parameter ()) { - expr.value_type = new PointerType (new PointerType (expr.inner.value_type)); - } else { - expr.value_type = new PointerType (expr.inner.value_type); - } + expr.check (this); } public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) { - expr.inner.lvalue = true; - - expr.accept_children (this); - - if (expr.inner.error) { - /* if there was an error in the inner expression, skip type check */ - expr.error = true; - return; - } - - if (!(expr.inner is MemberAccess || expr.inner is ElementAccess)) { - expr.error = true; - Report.error (expr.source_reference, "Reference transfer not supported for this expression"); - return; - } - - if (!expr.inner.value_type.is_disposable () - && !(expr.inner.value_type is PointerType)) { - expr.error = true; - Report.error (expr.source_reference, "No reference to be transferred"); - return; - } - - expr.value_type = expr.inner.value_type.copy (); - expr.value_type.value_owned = true; + expr.check (this); } public DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) { @@ -1118,46 +887,11 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } public override void visit_type_check (TypeCheck expr) { - if (expr.type_reference.data_type == null) { - /* if type resolving didn't succeed, skip this check */ - expr.error = true; - return; - } - - current_source_file.add_type_dependency (expr.type_reference, SourceFileDependencyType.SOURCE); - - expr.value_type = bool_type; + expr.check (this); } public override void visit_conditional_expression (ConditionalExpression expr) { - if (expr.condition.error || expr.false_expression.error || expr.true_expression.error) { - return; - } - - if (!expr.condition.value_type.compatible (bool_type)) { - expr.error = true; - Report.error (expr.condition.source_reference, "Condition must be boolean"); - return; - } - - /* FIXME: support memory management */ - if (expr.false_expression.value_type.compatible (expr.true_expression.value_type)) { - expr.value_type = expr.true_expression.value_type.copy (); - } else if (expr.true_expression.value_type.compatible (expr.false_expression.value_type)) { - expr.value_type = expr.false_expression.value_type.copy (); - } else { - expr.error = true; - Report.error (expr.condition.source_reference, "Incompatible expressions"); - return; - } - } - - private string get_lambda_name () { - var result = "__lambda%d".printf (next_lambda_id); - - next_lambda_id++; - - return result; + expr.check (this); } public Method? find_current_method () { @@ -1183,71 +917,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } public override void visit_lambda_expression (LambdaExpression l) { - if (!(l.target_type is DelegateType)) { - l.error = true; - Report.error (l.source_reference, "lambda expression not allowed in this context"); - return; - } - - bool in_instance_method = false; - var current_method = find_current_method (); - if (current_method != null) { - in_instance_method = (current_method.binding == MemberBinding.INSTANCE); - } else { - in_instance_method = is_in_constructor (); - } - - var cb = (Delegate) ((DelegateType) l.target_type).delegate_symbol; - l.method = new Method (get_lambda_name (), cb.return_type); - if (!cb.has_target || !in_instance_method) { - l.method.binding = MemberBinding.STATIC; - } - l.method.owner = current_symbol.scope; - - var lambda_params = l.get_parameters (); - Iterator lambda_param_it = lambda_params.iterator (); - foreach (FormalParameter cb_param in cb.get_parameters ()) { - if (!lambda_param_it.next ()) { - /* lambda expressions are allowed to have less parameters */ - break; - } - - string lambda_param = lambda_param_it.get (); - - var param = new FormalParameter (lambda_param, cb_param.parameter_type); - - l.method.add_parameter (param); - } - - if (lambda_param_it.next ()) { - /* lambda expressions may not expect more parameters */ - l.error = true; - Report.error (l.source_reference, "lambda expression: too many parameters"); - return; - } - - if (l.expression_body != null) { - var block = new Block (l.source_reference); - block.scope.parent_scope = l.method.scope; - - if (l.method.return_type.data_type != null) { - block.add_statement (new ReturnStatement (l.expression_body, l.source_reference)); - } else { - block.add_statement (new ExpressionStatement (l.expression_body, l.source_reference)); - } - - l.method.body = block; - } else { - l.method.body = l.statement_body; - } - l.method.body.owner = l.method.scope; - - /* lambda expressions should be usable like MemberAccess of a method */ - l.symbol_reference = l.method; - - l.accept_children (this); - - l.value_type = new MethodType (l.method); + l.check (this); } public override void visit_assignment (Assignment a) { diff --git a/vala/valasizeofexpression.vala b/vala/valasizeofexpression.vala index bd858bd51..d558f100c 100644 --- a/vala/valasizeofexpression.vala +++ b/vala/valasizeofexpression.vala @@ -1,6 +1,6 @@ /* valasizeofexpression.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 @@ -68,4 +68,16 @@ public class Vala.SizeofExpression : Expression { type_reference = new_type; } } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = analyzer.ulong_type; + + return !error; + } } diff --git a/vala/valastringliteral.vala b/vala/valastringliteral.vala index 2206b744b..d6fc9ac4d 100644 --- a/vala/valastringliteral.vala +++ b/vala/valastringliteral.vala @@ -76,4 +76,16 @@ public class Vala.StringLiteral : Literal { public override string to_string () { return value; } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = analyzer.string_type.copy (); + + return !error; + } } diff --git a/vala/valatypecheck.vala b/vala/valatypecheck.vala index b408d1e52..4c2436252 100644 --- a/vala/valatypecheck.vala +++ b/vala/valatypecheck.vala @@ -1,6 +1,6 @@ /* valatypecheck.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 @@ -77,4 +77,24 @@ public class Vala.TypeCheck : Expression { type_reference = new_type; } } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + if (type_reference.data_type == null) { + /* if type resolving didn't succeed, skip this check */ + error = true; + return false; + } + + analyzer.current_source_file.add_type_dependency (type_reference, SourceFileDependencyType.SOURCE); + + value_type = analyzer.bool_type; + + return !error; + } } diff --git a/vala/valatypeofexpression.vala b/vala/valatypeofexpression.vala index d7111003f..918ae6ccd 100644 --- a/vala/valatypeofexpression.vala +++ b/vala/valatypeofexpression.vala @@ -1,6 +1,6 @@ /* valatypeofexpression.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 @@ -68,4 +68,16 @@ public class Vala.TypeofExpression : Expression { type_reference = new_type; } } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + value_type = analyzer.type_type; + + return !error; + } } diff --git a/vala/valaunaryexpression.vala b/vala/valaunaryexpression.vala index 820804bab..aea2a1578 100644 --- a/vala/valaunaryexpression.vala +++ b/vala/valaunaryexpression.vala @@ -104,6 +104,129 @@ public class Vala.UnaryExpression : Expression { return inner.is_pure (); } + + bool is_numeric_type (DataType type) { + if (!(type.data_type is Struct)) { + return false; + } + + var st = (Struct) type.data_type; + return st.is_integer_type () || st.is_floating_type (); + } + + bool is_integer_type (DataType type) { + if (!(type.data_type is Struct)) { + return false; + } + + var st = (Struct) type.data_type; + return st.is_integer_type (); + } + + MemberAccess? find_member_access (Expression expr) { + if (expr is ParenthesizedExpression) { + var pe = (ParenthesizedExpression) expr; + return find_member_access (pe.inner); + } + + if (expr is MemberAccess) { + return (MemberAccess) expr; + } + + return null; + } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) { + inner.lvalue = true; + inner.target_type = target_type; + } + + accept_children (analyzer); + + if (inner.error) { + /* if there was an error in the inner expression, skip type check */ + error = true; + return false; + } + + if (operator == UnaryOperator.PLUS || operator == UnaryOperator.MINUS) { + // integer or floating point type + if (!is_numeric_type (inner.value_type)) { + error = true; + Report.error (source_reference, "Operator not supported for `%s'".printf (inner.value_type.to_string ())); + return false; + } + + value_type = inner.value_type; + } else if (operator == UnaryOperator.LOGICAL_NEGATION) { + // boolean type + if (!inner.value_type.compatible (analyzer.bool_type)) { + error = true; + Report.error (source_reference, "Operator not supported for `%s'".printf (inner.value_type.to_string ())); + return false; + } + + value_type = inner.value_type; + } else if (operator == UnaryOperator.BITWISE_COMPLEMENT) { + // integer type + if (!is_integer_type (inner.value_type)) { + error = true; + Report.error (source_reference, "Operator not supported for `%s'".printf (inner.value_type.to_string ())); + return false; + } + + value_type = inner.value_type; + } else if (operator == UnaryOperator.INCREMENT || + operator == UnaryOperator.DECREMENT) { + // integer type + if (!is_integer_type (inner.value_type)) { + error = true; + Report.error (source_reference, "Operator not supported for `%s'".printf (inner.value_type.to_string ())); + return false; + } + + var ma = find_member_access (inner); + if (ma == null) { + error = true; + Report.error (source_reference, "Prefix operators not supported for this expression"); + return false; + } + + var old_value = new MemberAccess (ma.inner, ma.member_name, inner.source_reference); + var bin = new BinaryExpression (operator == UnaryOperator.INCREMENT ? BinaryOperator.PLUS : BinaryOperator.MINUS, old_value, new IntegerLiteral ("1"), source_reference); + + var assignment = new Assignment (ma, bin, AssignmentOperator.SIMPLE, source_reference); + var parenthexp = new ParenthesizedExpression (assignment, source_reference); + parenthexp.target_type = target_type; + analyzer.replaced_nodes.add (this); + parent_node.replace_expression (this, parenthexp); + parenthexp.accept (analyzer); + return true; + } else if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) { + if (inner.symbol_reference is Field || inner.symbol_reference is FormalParameter || inner.symbol_reference is LocalVariable) { + // ref and out can only be used with fields, parameters, and local variables + lvalue = true; + value_type = inner.value_type; + } else { + error = true; + Report.error (source_reference, "ref and out method arguments can only be used with fields, parameters, and local variables"); + return false; + } + } else { + error = true; + Report.error (source_reference, "internal error: unsupported unary operator"); + return false; + } + + return !error; + } } public enum Vala.UnaryOperator {