1/* valasliceexpression.vala 2 * 3 * Copyright (C) 2009 Robin Sonefors 4 * Copyright (C) 2009-2013 Jürg Billeter 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 * Author: 21 * Robin Sonefors <ozamosi@flukkost.nu> 22 * Jürg Billeter <j@bitron.ch> 23 */ 24 25using GLib; 26 27/** 28 * Represents an array slice expression. 29 * 30 * {{{ foo[1:5] }}} 31 */ 32public class Vala.SliceExpression : Expression { 33 public Expression container { 34 get { 35 return _container; 36 } 37 set { 38 _container = value; 39 _container.parent_node = this; 40 } 41 } 42 43 public Expression start { 44 get { 45 return _start; 46 } 47 private set { 48 _start = value; 49 _start.parent_node = this; 50 } 51 } 52 53 public Expression stop { 54 get { 55 return _stop; 56 } 57 private set { 58 _stop = value; 59 _stop.parent_node = this; 60 } 61 } 62 63 Expression _container; 64 Expression _start; 65 Expression _stop; 66 67 public SliceExpression (Expression container, Expression start, Expression stop, SourceReference? source_reference = null) { 68 this.container = container; 69 this.start = start; 70 this.stop = stop; 71 this.source_reference = source_reference; 72 } 73 74 public override void accept (CodeVisitor visitor) { 75 visitor.visit_slice_expression (this); 76 77 visitor.visit_expression (this); 78 } 79 80 public override void accept_children (CodeVisitor visitor) { 81 container.accept (visitor); 82 83 start.accept (visitor); 84 stop.accept (visitor); 85 } 86 87 public override void replace_expression (Expression old_node, Expression new_node) { 88 if (container == old_node) { 89 container = new_node; 90 } 91 if (start == old_node) { 92 start = new_node; 93 } 94 if (stop == old_node) { 95 stop = new_node; 96 } 97 } 98 99 public override bool is_pure () { 100 return false; 101 } 102 103 public override bool is_accessible (Symbol sym) { 104 return container.is_accessible (sym) && start.is_accessible (sym) && stop.is_accessible (sym); 105 } 106 107 public override bool check (CodeContext context) { 108 if (checked) { 109 return !error; 110 } 111 112 checked = true; 113 114 if (!container.check (context)) { 115 error = true; 116 return false; 117 } 118 119 if (container.value_type is ArrayType) { 120 unowned ArrayType array_type = (ArrayType) container.value_type; 121 start.target_type = array_type.length_type.copy (); 122 stop.target_type = array_type.length_type.copy (); 123 } 124 125 if (!start.check (context)) { 126 error = true; 127 return false; 128 } 129 130 if (!stop.check (context)) { 131 error = true; 132 return false; 133 } 134 135 if (container.value_type == null) { 136 error = true; 137 Report.error (container.source_reference, "Invalid container expression"); 138 return false; 139 } 140 141 if (lvalue) { 142 error = true; 143 Report.error (container.source_reference, "Slice expressions cannot be used as lvalue"); 144 return false; 145 } 146 147 if (container.value_type is ArrayType) { 148 value_type = container.value_type.copy (); 149 value_type.value_owned = false; 150 151 // inline allocated results are not compatible with non-constant start/stop expressions 152 unowned ArrayType array_type = (ArrayType) value_type; 153 array_type.fixed_length = false; 154 array_type.inline_allocated = false; 155 array_type.length = null; 156 157 value_type.check (context); 158 159 /* check if the index is of type integer */ 160 if (!(start.value_type is IntegerType || start.value_type is EnumValueType)) { 161 error = true; 162 Report.error (start.source_reference, "Expression of integer type expected"); 163 } 164 if (!(stop.value_type is IntegerType || stop.value_type is EnumValueType)) { 165 error = true; 166 Report.error (stop.source_reference, "Expression of integer type expected"); 167 } 168 } else { 169 var slice_method = container.value_type.get_member ("slice") as Method; 170 if (slice_method != null) { 171 var slice_call = new MethodCall (new MemberAccess (container, "slice")); 172 slice_call.add_argument (start); 173 slice_call.add_argument (stop); 174 slice_call.target_type = this.target_type; 175 parent_node.replace_expression (this, slice_call); 176 return slice_call.check (context); 177 } 178 179 error = true; 180 Report.error (source_reference, "The expression `%s' does not denote an array".printf (container.value_type.to_string ())); 181 } 182 183 return !error; 184 } 185 186 public override void emit (CodeGenerator codegen) { 187 container.emit (codegen); 188 189 start.emit (codegen); 190 stop.emit (codegen); 191 192 codegen.visit_slice_expression (this); 193 194 codegen.visit_expression (this); 195 } 196 197 public override void get_defined_variables (Collection<Variable> collection) { 198 container.get_defined_variables (collection); 199 start.get_defined_variables (collection); 200 stop.get_defined_variables (collection); 201 } 202 203 public override void get_used_variables (Collection<Variable> collection) { 204 container.get_used_variables (collection); 205 start.get_used_variables (collection); 206 stop.get_used_variables (collection); 207 } 208} 209