
com.alibaba.qlexpress4.runtime.instruction.SliceInstruction Maven / Gradle / Ivy
package com.alibaba.qlexpress4.runtime.instruction;
import com.alibaba.qlexpress4.QLOptions;
import com.alibaba.qlexpress4.exception.ErrorReporter;
import com.alibaba.qlexpress4.exception.QLErrorCodes;
import com.alibaba.qlexpress4.runtime.QContext;
import com.alibaba.qlexpress4.runtime.QResult;
import com.alibaba.qlexpress4.runtime.Value;
import com.alibaba.qlexpress4.runtime.data.DataValue;
import com.alibaba.qlexpress4.runtime.util.ValueUtils;
import com.alibaba.qlexpress4.utils.PrintlnUtils;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
* Operation: slice array or list, like a[2:4], a[4:-1], a[:4], a[5:], a[:]
* Input: 0-2
* Output: 1
*
* Author: DQinYuan
*/
public class SliceInstruction extends QLInstruction {
public enum Mode {
LEFT, RIGHT, BOTH, COPY
}
private final Mode mode;
public SliceInstruction(ErrorReporter errorReporter, Mode mode) {
super(errorReporter);
this.mode = mode;
}
@Override
public QResult execute(QContext qContext, QLOptions qlOptions) {
int startInt = 0;
int endInt = 0;
Object indexAble = null;
if (mode == Mode.BOTH) {
Object end = qContext.pop().get();
Object start = qContext.pop().get();
indexAble = qContext.pop().get();
startInt = ValueUtils.assertType(start, Number.class, QLErrorCodes.INVALID_INDEX.name(),
QLErrorCodes.INVALID_INDEX.getErrorMsg(), errorReporter).intValue();
endInt = ValueUtils.assertType(end, Number.class, QLErrorCodes.INVALID_INDEX.name(),
QLErrorCodes.INVALID_INDEX.getErrorMsg(), errorReporter).intValue();
} else if (mode == Mode.LEFT) {
Object end = qContext.pop().get();
indexAble = qContext.pop().get();
endInt = ValueUtils.assertType(end, Number.class, QLErrorCodes.INVALID_INDEX.name(),
QLErrorCodes.INVALID_INDEX.getErrorMsg(), errorReporter).intValue();
} else if (mode == Mode.RIGHT) {
Object start = qContext.pop().get();
indexAble = qContext.pop().get();
startInt = ValueUtils.assertType(start, Number.class, QLErrorCodes.INVALID_INDEX.name(),
QLErrorCodes.INVALID_INDEX.getErrorMsg(), errorReporter).intValue();
endInt = indexAbleLen(indexAble);
} else if (mode == Mode.COPY) {
indexAble = qContext.pop().get();
endInt = indexAbleLen(indexAble);
}
if (indexAble instanceof List) {
List> result = listSlice((List>) indexAble, startInt, endInt);
qContext.push(new DataValue(result));
return QResult.NEXT_INSTRUCTION;
} else if (indexAble != null && indexAble.getClass().isArray()) {
Object result = arraySlice(indexAble, startInt, endInt);
qContext.push(new DataValue(result));
return QResult.NEXT_INSTRUCTION;
} else if (indexAble == null && qlOptions.isAvoidNullPointer()) {
qContext.push(Value.NULL_VALUE);
return QResult.NEXT_INSTRUCTION;
} else {
throw errorReporter.reportFormat(QLErrorCodes.NONINDEXABLE_OBJECT.name(),
QLErrorCodes.NONINDEXABLE_OBJECT.getErrorMsg(),
indexAble == null? "null": indexAble.getClass().getName());
}
}
private int indexAbleLen(Object indexAble) {
if (indexAble instanceof List) {
return ((List>) indexAble).size();
} else if (indexAble != null && indexAble.getClass().isArray()) {
return Array.getLength(indexAble);
} else {
throw errorReporter.reportFormat(QLErrorCodes.NONINDEXABLE_OBJECT.name(), QLErrorCodes.NONINDEXABLE_OBJECT.getErrorMsg(),
indexAble == null? "null": indexAble.getClass().getName());
}
}
private List> listSlice(List> listObj, int originStart, int originEnd) {
int start = Math.max(ValueUtils.javaIndex(listObj.size(), originStart), 0);
int end = Math.min(ValueUtils.javaIndex(listObj.size(), originEnd), listObj.size());
if (start >= end) {
return new ArrayList<>(0);
}
return listObj.subList(start, end);
}
private Object arraySlice(Object arrObj, int originStart, int originEnd) {
int arrLen = Array.getLength(arrObj);
int start = Math.max(ValueUtils.javaIndex(arrLen, originStart), 0);
int end = Math.min(ValueUtils.javaIndex(arrLen, originEnd), arrLen);
if (start >= end) {
return Array.newInstance(arrObj.getClass().getComponentType(), 0);
}
Object newArr = Array.newInstance(arrObj.getClass().getComponentType(), end - start);
for (int i = start; i < end; i++) {
Array.set(newArr, i - start, Array.get(arrObj, i));
}
return newArr;
}
@Override
public int stackInput() {
if (mode == Mode.BOTH) {
return 2;
} else if (mode == Mode.COPY) {
return 0;
} else {
return 1;
}
}
@Override
public int stackOutput() {
return 1;
}
@Override
public void println(int index, int depth, Consumer debug) {
PrintlnUtils.printlnByCurDepth(depth, index + ": Slice", debug);
}
}