diff options
author | Jürg Billeter <j@bitron.ch> | 2008-11-07 09:07:08 +0000 |
---|---|---|
committer | Jürg Billeter <juergbi@src.gnome.org> | 2008-11-07 09:07:08 +0000 |
commit | db5f3f9062a7dd32a41a37031835e4cecff30656 (patch) | |
tree | 8880a12bf9077397cb27c8dec69552565c985bdc /vala/valaelementaccess.vala | |
parent | 6f58267f4fecde1c38eacf12340f2f12b311e5ed (diff) | |
download | vala-db5f3f9062a7dd32a41a37031835e4cecff30656.tar.gz |
Move element access checking to ElementAccess.check
2008-11-07 Jürg Billeter <j@bitron.ch>
* vala/valaelementaccess.vala:
* vala/valasemanticanalyzer.vala:
Move element access checking to ElementAccess.check
svn path=/trunk/; revision=1994
Diffstat (limited to 'vala/valaelementaccess.vala')
-rw-r--r-- | vala/valaelementaccess.vala | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala index 640bd3e31..0734944d4 100644 --- a/vala/valaelementaccess.vala +++ b/vala/valaelementaccess.vala @@ -85,4 +85,127 @@ public class Vala.ElementAccess : Expression { } return container.is_pure (); } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + container.accept (analyzer); + + if (container.value_type == null) { + /* don't proceed if a child expression failed */ + error = true; + return false; + } + + var container_type = container.value_type.data_type; + + if (container is MemberAccess && container.symbol_reference is Signal) { + // signal detail access + if (get_indices ().size != 1) { + error = true; + Report.error (source_reference, "Element access with more than one dimension is not supported for signals"); + return false; + } + get_indices ().get (0).target_type = analyzer.string_type.copy (); + } + + foreach (Expression index in get_indices ()) { + index.accept (analyzer); + } + + bool index_int_type_check = true; + + var pointer_type = container.value_type as PointerType; + + /* assign a value_type when possible */ + if (container.value_type is ArrayType) { + var array_type = (ArrayType) container.value_type; + value_type = array_type.element_type.copy (); + if (!lvalue) { + value_type.value_owned = false; + } + } else if (pointer_type != null && !pointer_type.base_type.is_reference_type_or_type_parameter ()) { + value_type = pointer_type.base_type.copy (); + } else if (container_type == analyzer.string_type.data_type) { + if (get_indices ().size != 1) { + error = true; + Report.error (source_reference, "Element access with more than one dimension is not supported for strings"); + return false; + } + + value_type = analyzer.unichar_type; + } else if (container_type != null && analyzer.list_type != null && analyzer.map_type != null && + (container_type.is_subtype_of (analyzer.list_type) || container_type.is_subtype_of (analyzer.map_type))) { + Gee.List<Expression> indices = get_indices (); + if (indices.size != 1) { + error = true; + Report.error (source_reference, "Element access with more than one dimension is not supported for the specified type"); + return false; + } + Iterator<Expression> indices_it = indices.iterator (); + indices_it.next (); + var index = indices_it.get (); + index_int_type_check = false; + + // lookup symbol in interface instead of class as implemented interface methods are not in VAPI files + Symbol get_sym = null; + if (container_type.is_subtype_of (analyzer.list_type)) { + get_sym = analyzer.list_type.scope.lookup ("get"); + } else if (container_type.is_subtype_of (analyzer.map_type)) { + get_sym = analyzer.map_type.scope.lookup ("get"); + } + var get_method = (Method) get_sym; + Gee.List<FormalParameter> get_params = get_method.get_parameters (); + Iterator<FormalParameter> get_params_it = get_params.iterator (); + get_params_it.next (); + var get_param = get_params_it.get (); + + var index_type = get_param.parameter_type; + if (index_type.type_parameter != null) { + index_type = analyzer.get_actual_type (container.value_type, get_method, get_param.parameter_type, this); + } + + if (!index.value_type.compatible (index_type)) { + error = true; + Report.error (source_reference, "index expression: Cannot convert from `%s' to `%s'".printf (index.value_type.to_string (), index_type.to_string ())); + return false; + } + + value_type = analyzer.get_actual_type (container.value_type, get_method, get_method.return_type, this).copy (); + if (lvalue) { + // get () returns owned value, set () accepts unowned value + value_type.value_owned = false; + } + } else if (container is MemberAccess && container.symbol_reference is Signal) { + index_int_type_check = false; + + symbol_reference = container.symbol_reference; + value_type = container.value_type; + } else { + error = true; + Report.error (source_reference, "The expression `%s' does not denote an Array".printf (container.value_type.to_string ())); + } + + if (index_int_type_check) { + /* check if the index is of type integer */ + foreach (Expression e in get_indices ()) { + /* don't proceed if a child expression failed */ + if (e.value_type == null) { + return false; + } + + /* check if the index is of type integer */ + if (!(e.value_type.data_type is Struct) || !((Struct) e.value_type.data_type).is_integer_type ()) { + error = true; + Report.error (e.source_reference, "Expression of integer type expected"); + } + } + } + + return !error; + } } |