blob: a2b6036e2893444c876a2fa443125a950f4c979e [file] [log] [blame]
Vladimir Moskva8d610c62016-09-15 14:36:41 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.syntax;
15
16import com.google.devtools.build.lib.events.Location;
brandjone2ffd5d2017-06-27 18:14:54 +020017import java.io.IOException;
Vladimir Moskva8d610c62016-09-15 14:36:41 +000018import java.util.List;
19
brandjon990622b2017-07-11 19:56:45 +020020/** Syntax node for a slice expression, e.g. obj[:len(obj):2]. */
Vladimir Moskva8d610c62016-09-15 14:36:41 +000021public final class SliceExpression extends Expression {
22
brandjon990622b2017-07-11 19:56:45 +020023 private final Expression object;
Vladimir Moskva8d610c62016-09-15 14:36:41 +000024 private final Expression start;
25 private final Expression end;
26 private final Expression step;
27
brandjon990622b2017-07-11 19:56:45 +020028 public SliceExpression(Expression object, Expression start, Expression end, Expression step) {
29 this.object = object;
Vladimir Moskva8d610c62016-09-15 14:36:41 +000030 this.start = start;
31 this.end = end;
32 this.step = step;
33 }
34
35 public Expression getObject() {
brandjon990622b2017-07-11 19:56:45 +020036 return object;
Vladimir Moskva8d610c62016-09-15 14:36:41 +000037 }
38
39 public Expression getStart() {
40 return start;
41 }
42
43 public Expression getEnd() {
44 return end;
45 }
46
47 public Expression getStep() {
48 return step;
49 }
50
51 @Override
brandjone2ffd5d2017-06-27 18:14:54 +020052 public void prettyPrint(Appendable buffer) throws IOException {
53 boolean startIsDefault =
54 (start instanceof Identifier) && ((Identifier) start).getName().equals("None");
55 boolean endIsDefault =
56 (end instanceof Identifier) && ((Identifier) end).getName().equals("None");
57 boolean stepIsDefault =
laurentlbf2854bd2017-08-16 12:43:15 +020058 (step instanceof IntegerLiteral) && ((IntegerLiteral) step).getValue() == 1;
brandjone2ffd5d2017-06-27 18:14:54 +020059
brandjon990622b2017-07-11 19:56:45 +020060 object.prettyPrint(buffer);
brandjone2ffd5d2017-06-27 18:14:54 +020061 buffer.append('[');
62 // Start and end are omitted if they are the literal identifier None, which is the default value
63 // inserted by the parser if no bound is given. Likewise, step is omitted if it is the literal
64 // integer 1.
65 //
66 // The first separator colon is unconditional. The second separator appears only if step is
67 // printed.
68 if (!startIsDefault) {
69 start.prettyPrint(buffer);
70 }
71 buffer.append(':');
72 if (!endIsDefault) {
73 end.prettyPrint(buffer);
74 }
75 if (!stepIsDefault) {
76 buffer.append(':');
77 step.prettyPrint(buffer);
78 }
79 buffer.append(']');
Vladimir Moskva8d610c62016-09-15 14:36:41 +000080 }
81
82 @Override
83 Object doEval(Environment env) throws EvalException, InterruptedException {
brandjon990622b2017-07-11 19:56:45 +020084 Object objValue = object.eval(env);
Vladimir Moskva8d610c62016-09-15 14:36:41 +000085 Object startValue = start.eval(env);
86 Object endValue = end.eval(env);
87 Object stepValue = step.eval(env);
Vladimir Moskva4ce70d22016-09-15 15:10:09 +000088 Location loc = getLocation();
Vladimir Moskva8d610c62016-09-15 14:36:41 +000089
Vladimir Moskva8d610c62016-09-15 14:36:41 +000090 if (objValue instanceof SkylarkList) {
brandjon0528d5d2017-08-04 16:00:56 +020091 return ((SkylarkList<?>) objValue).getSlice(
92 startValue, endValue, stepValue, loc, env.mutability());
Vladimir Moskva8d610c62016-09-15 14:36:41 +000093 } else if (objValue instanceof String) {
94 String string = (String) objValue;
Jon Brandveinfab84872016-11-11 16:27:01 +000095 List<Integer> indices = EvalUtils.getSliceIndices(startValue, endValue, stepValue,
Vladimir Moskva8d610c62016-09-15 14:36:41 +000096 string.length(), loc);
97 char[] result = new char[indices.size()];
98 char[] original = ((String) objValue).toCharArray();
99 int resultIndex = 0;
100 for (int originalIndex : indices) {
101 result[resultIndex] = original[originalIndex];
102 ++resultIndex;
103 }
104 return new String(result);
105 }
106
107 throw new EvalException(
108 loc,
vladmos46907932017-06-30 14:01:45 +0200109 String.format(
Laurent Le Brunc31f3512016-12-29 21:41:33 +0000110 "type '%s' has no operator [:](%s, %s, %s)",
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000111 EvalUtils.getDataTypeName(objValue),
112 EvalUtils.getDataTypeName(startValue),
113 EvalUtils.getDataTypeName(endValue),
114 EvalUtils.getDataTypeName(stepValue)));
115 }
116
117 @Override
118 public void accept(SyntaxTreeVisitor visitor) {
119 visitor.visit(this);
120 }
laurentlbaf682d12017-08-24 20:32:02 +0200121
122 @Override
123 public Kind kind() {
124 return Kind.SLICE;
125 }
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000126}