List<Expression> size = ((ArrayCreationExpression) array_expr).get_sizes ();
var length_expr = size[dim - 1];
return (CCodeExpression) get_ccodenode (length_expr);
- } else if (array_expr is MethodCall || array_expr is CastExpression) {
+ } else if (array_expr is MethodCall || array_expr is CastExpression || array_expr is SliceExpression) {
List<CCodeExpression> size = array_expr.get_array_sizes ();
if (size.size >= dim) {
return size[dim - 1];
}
}
+ public override void visit_slice_expression (SliceExpression expr) {
+ expr.accept_children (codegen);
+
+ var ccontainer = (CCodeExpression) expr.container.ccodenode;
+ var cstart = (CCodeExpression) expr.start.ccodenode;
+ var cstop = (CCodeExpression) expr.stop.ccodenode;
+
+ var ccomma = new CCodeCommaExpression ();
+
+ var len_var = get_temp_variable (int_type);
+ len_var.source_reference = expr.source_reference;
+ temp_vars.insert (0, len_var);
+
+ var slice_var = get_temp_variable (expr.value_type, true, expr);
+ temp_vars.insert (0, slice_var);
+
+ if (!is_pure_ccode_expression (cstart)) {
+ // avoid double evaluation of start
+ var start_var = get_temp_variable (int_type);
+ temp_vars.insert (0, start_var);
+
+ var start_assignment = new CCodeAssignment (get_variable_cexpression (start_var.name), cstart);
+ ccomma.append_expression (start_assignment);
+
+ cstart = get_variable_cexpression (start_var.name);
+ }
+
+ var cstartpointer = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, ccontainer, cstart);
+ var slice_assignment = new CCodeAssignment (get_variable_cexpression (slice_var.name), cstartpointer);
+ ccomma.append_expression (slice_assignment);
+
+ var splicelen = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, cstop, cstart);
+ var len_assignment = new CCodeAssignment (get_variable_cexpression (len_var.name), splicelen);
+ ccomma.append_expression (len_assignment);
+
+ ccomma.append_expression (get_variable_cexpression (slice_var.name));
+
+ expr.ccodenode = ccomma;
+ expr.append_array_size (get_variable_cexpression (len_var.name));
+ }
+
private CCodeForStatement get_struct_array_free_loop (Struct st) {
var cbody = new CCodeBlock ();
var cptrarray = new CCodeIdentifier ("array");
head.visit_element_access (expr);
}
+ public override void visit_slice_expression (SliceExpression expr) {
+ head.visit_slice_expression (expr);
+ }
+
public override void visit_base_access (BaseAccess expr) {
head.visit_base_access (expr);
}
next.visit_element_access (expr);
}
+ public virtual void visit_slice_expression (SliceExpression expr) {
+ next.visit_slice_expression (expr);
+ }
+
public virtual void visit_base_access (BaseAccess expr) {
next.visit_base_access (expr);
}
assert (b.length == 2);
assert (b[0] == 42);
assert (b[1] == 23);
+
+ // slices
+ int[] c = a[1:3];
+ assert (c.length == 2);
+ assert (c[0] == 23);
+ assert (c[1] == 11);
}
void test_string_array () {
assert (!(s >= "i"));
assert (s > "g");
assert (!(s > "i"));
+
+ // slices
+ t = s[2:4];
+ assert (t.length == 2);
+ assert (t[0] == 'l');
+ assert (t[1] == 'l');
}
void main () {
valasignal.vala \
valasignaltype.vala \
valasizeofexpression.vala \
+ valasliceexpression.vala \
valasourcefile.vala \
valasourcelocation.vala \
valasourcereference.vala \
public virtual void visit_element_access (ElementAccess expr) {
}
+ /**
+ * Visit operation called for array slice expressions.
+ *
+ * @param expr an array slice expression
+ */
+ public virtual void visit_slice_expression (SliceExpression expr) {
+ }
+
/**
* Visit operation called for base access expressions.
*
write_string ("]");
}
+ public override void visit_slice_expression (SliceExpression expr) {
+ expr.container.accept (this);
+ write_string ("[");
+ expr.start.accept (this);
+ write_string ("..");
+ expr.stop.accept (this);
+ write_string ("]");
+ }
+
public override void visit_base_access (BaseAccess expr) {
write_string ("base");
}
Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
expect (TokenType.OPEN_BRACKET);
var index_list = parse_expression_list ();
+ Expression? stop = null;
+ if (index_list.size == 1 && accept (TokenType.COLON)) {
+ // slice expression
+ stop = parse_expression ();
+ }
expect (TokenType.CLOSE_BRACKET);
- var expr = new ElementAccess (inner, get_src (begin));
- foreach (Expression index in index_list) {
- expr.append_index (index);
+ if (stop == null) {
+ var expr = new ElementAccess (inner, get_src (begin));
+ foreach (Expression index in index_list) {
+ expr.append_index (index);
+ }
+ return expr;
+ } else {
+ return new SliceExpression (inner, index_list[0], stop, get_src (begin));
}
- return expr;
}
List<Expression> parse_expression_list () throws ParseError {
--- /dev/null
+/* valasliceexpression.vala
+ *
+ * Copyright (C) 2009 Robin Sonefors
+ * Copyright (C) 2009 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Robin Sonefors <ozamosi@flukkost.nu>
+ * Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents an array slice expression e.g "a[1:5]".
+ */
+public class Vala.SliceExpression : Expression {
+ public Expression container {
+ get {
+ return _container;
+ }
+ set {
+ _container = value;
+ _container.parent_node = this;
+ }
+ }
+
+ public Expression start {
+ get {
+ return _start;
+ }
+ private set {
+ _start = value;
+ _start.parent_node = this;
+ }
+ }
+
+ public Expression stop {
+ get {
+ return _stop;
+ }
+ private set {
+ _stop = value;
+ _stop.parent_node = this;
+ }
+ }
+
+ Expression _container;
+ Expression _start;
+ Expression _stop;
+
+ public SliceExpression (Expression container, Expression start, Expression stop, SourceReference? source_reference = null) {
+ this.container = container;
+ this.start = start;
+ this.stop = stop;
+ this.source_reference = source_reference;
+ }
+
+ public override void accept (CodeVisitor visitor) {
+ visitor.visit_slice_expression (this);
+
+ visitor.visit_expression (this);
+ }
+
+ public override void accept_children (CodeVisitor visitor) {
+ container.accept (visitor);
+
+ start.accept (visitor);
+ stop.accept (visitor);
+ }
+
+ public override void replace_expression (Expression old_node, Expression new_node) {
+ if (container == old_node) {
+ container = new_node;
+ }
+ if (start == old_node) {
+ start = new_node;
+ }
+ if (stop == old_node) {
+ stop = new_node;
+ }
+ }
+
+ public override bool is_pure () {
+ return false;
+ }
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ if (!container.check (analyzer)) {
+ error = true;
+ return false;
+ }
+
+ if (!start.check (analyzer)) {
+ error = true;
+ return false;
+ }
+
+ if (!stop.check (analyzer)) {
+ error = true;
+ return false;
+ }
+
+ if (container.value_type == null) {
+ error = true;
+ Report.error (container.source_reference, "Invalid container expression");
+ return false;
+ }
+
+ if (lvalue) {
+ error = true;
+ Report.error (container.source_reference, "Slice expressions cannot be used as lvalue");
+ return false;
+ }
+
+ if (container.value_type is ArrayType) {
+ value_type = container.value_type.copy ();
+ value_type.value_owned = false;
+
+ /* check if the index is of type integer */
+ if (!(start.value_type is IntegerType || start.value_type is EnumValueType)) {
+ error = true;
+ Report.error (start.source_reference, "Expression of integer type expected");
+ }
+ if (!(stop.value_type is IntegerType || stop.value_type is EnumValueType)) {
+ error = true;
+ Report.error (stop.source_reference, "Expression of integer type expected");
+ }
+ } else {
+ var slice_method = container.value_type.get_member ("slice") as Method;
+ if (slice_method != null) {
+ var slice_call = new MethodCall (new MemberAccess (container, "slice"));
+ slice_call.add_argument (start);
+ slice_call.add_argument (stop);
+ slice_call.target_type = this.target_type;
+ parent_node.replace_expression (this, slice_call);
+ return slice_call.check (analyzer);
+ }
+
+ error = true;
+ Report.error (source_reference, "The expression `%s' does not denote an array".printf (container.value_type.to_string ()));
+ }
+
+ return !error;
+ }
+
+ public override void get_defined_variables (Collection<LocalVariable> collection) {
+ container.get_defined_variables (collection);
+ start.get_defined_variables (collection);
+ stop.get_defined_variables (collection);
+ }
+
+ public override void get_used_variables (Collection<LocalVariable> collection) {
+ container.get_used_variables (collection);
+ start.get_used_variables (collection);
+ stop.get_used_variables (collection);
+ }
+}
expr.accept_children (this);
}
+ public override void visit_slice_expression (SliceExpression expr) {
+ expr.accept_children (this);
+ }
+
public override void visit_object_creation_expression (ObjectCreationExpression expr) {
expr.accept_children (this);
}