Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 1 | // 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. |
| 14 | package com.google.devtools.build.lib.syntax; |
| 15 | |
| 16 | import com.google.devtools.build.lib.events.Location; |
brandjon | e2ffd5d | 2017-06-27 18:14:54 +0200 | [diff] [blame] | 17 | import java.io.IOException; |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 18 | import java.util.List; |
| 19 | |
brandjon | 990622b | 2017-07-11 19:56:45 +0200 | [diff] [blame] | 20 | /** Syntax node for a slice expression, e.g. obj[:len(obj):2]. */ |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 21 | public final class SliceExpression extends Expression { |
| 22 | |
brandjon | 990622b | 2017-07-11 19:56:45 +0200 | [diff] [blame] | 23 | private final Expression object; |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 24 | private final Expression start; |
| 25 | private final Expression end; |
| 26 | private final Expression step; |
| 27 | |
brandjon | 990622b | 2017-07-11 19:56:45 +0200 | [diff] [blame] | 28 | public SliceExpression(Expression object, Expression start, Expression end, Expression step) { |
| 29 | this.object = object; |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 30 | this.start = start; |
| 31 | this.end = end; |
| 32 | this.step = step; |
| 33 | } |
| 34 | |
| 35 | public Expression getObject() { |
brandjon | 990622b | 2017-07-11 19:56:45 +0200 | [diff] [blame] | 36 | return object; |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 37 | } |
| 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 |
brandjon | e2ffd5d | 2017-06-27 18:14:54 +0200 | [diff] [blame] | 52 | 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 = |
laurentlb | f2854bd | 2017-08-16 12:43:15 +0200 | [diff] [blame] | 58 | (step instanceof IntegerLiteral) && ((IntegerLiteral) step).getValue() == 1; |
brandjon | e2ffd5d | 2017-06-27 18:14:54 +0200 | [diff] [blame] | 59 | |
brandjon | 990622b | 2017-07-11 19:56:45 +0200 | [diff] [blame] | 60 | object.prettyPrint(buffer); |
brandjon | e2ffd5d | 2017-06-27 18:14:54 +0200 | [diff] [blame] | 61 | 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 Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | @Override |
| 83 | Object doEval(Environment env) throws EvalException, InterruptedException { |
brandjon | 990622b | 2017-07-11 19:56:45 +0200 | [diff] [blame] | 84 | Object objValue = object.eval(env); |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 85 | Object startValue = start.eval(env); |
| 86 | Object endValue = end.eval(env); |
| 87 | Object stepValue = step.eval(env); |
Vladimir Moskva | 4ce70d2 | 2016-09-15 15:10:09 +0000 | [diff] [blame] | 88 | Location loc = getLocation(); |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 89 | |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 90 | if (objValue instanceof SkylarkList) { |
brandjon | 0528d5d | 2017-08-04 16:00:56 +0200 | [diff] [blame] | 91 | return ((SkylarkList<?>) objValue).getSlice( |
| 92 | startValue, endValue, stepValue, loc, env.mutability()); |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 93 | } else if (objValue instanceof String) { |
| 94 | String string = (String) objValue; |
Jon Brandvein | fab8487 | 2016-11-11 16:27:01 +0000 | [diff] [blame] | 95 | List<Integer> indices = EvalUtils.getSliceIndices(startValue, endValue, stepValue, |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 96 | 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, |
vladmos | 4690793 | 2017-06-30 14:01:45 +0200 | [diff] [blame] | 109 | String.format( |
Laurent Le Brun | c31f351 | 2016-12-29 21:41:33 +0000 | [diff] [blame] | 110 | "type '%s' has no operator [:](%s, %s, %s)", |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 111 | 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 | } |
laurentlb | af682d1 | 2017-08-24 20:32:02 +0200 | [diff] [blame] | 121 | |
| 122 | @Override |
| 123 | public Kind kind() { |
| 124 | return Kind.SLICE; |
| 125 | } |
Vladimir Moskva | 8d610c6 | 2016-09-15 14:36:41 +0000 | [diff] [blame] | 126 | } |