Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement indexed access opcodes
We add simple examples to exercise them. This discovers a bug in
list.__setitem__ (actually PyList.Delegate.setItem) which we fix. We add
a PyList constructor from stack slices. (Other PyList change is
trivial.)
  • Loading branch information
jeff5 committed Jan 6, 2023
commit e6c26d125af0b77ea2b3c830625304913703d5a0
65 changes: 51 additions & 14 deletions core/src/main/java/org/python/core/CPython38Frame.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,21 @@ Object eval() {
s[sp - 1] = PyNumber.subtract(s[sp - 1], w);
break;

case Opcode.BINARY_SUBSCR: // w[v]
// w | v | -> | w[v] |
// -------^sp --------^sp
v = s[--sp];
s[sp - 1] = PySequence.getItem(s[sp - 1], v);
break;

case Opcode.STORE_SUBSCR: // w[v] = u
// u | w | v | -> |
// -----------^sp -^sp
sp -= 3;
// setItem(w, v, u)
PySequence.setItem(s[sp + 1], s[sp + 2], s[sp]);
break;

case Opcode.RETURN_VALUE:
returnValue = s[--sp]; // POP
// ip = END; ?
Expand Down Expand Up @@ -201,6 +216,28 @@ Object eval() {
s[sp++] = v; // PUSH
break;

case Opcode.BUILD_TUPLE:
// w[0] | ... | w[oparg-1] | -> | tpl |
// -------------------------^sp -------^sp
// Group the N=oparg elements on the stack
// into a single tuple.
oparg |= opword & 0xff;
sp -= oparg;
s[sp] = new PyTuple(s, sp++, oparg);
oparg = 0;
break;

case Opcode.BUILD_LIST:
// w[0] | ... | w[oparg-1] | -> | lst |
// -------------------------^sp -------^sp
// Group the N=oparg elements on the stack
// into a single list.
oparg |= opword & 0xff;
sp -= oparg;
s[sp] = new PyList(s, sp++, oparg);
oparg = 0;
break;

case Opcode.LOAD_ATTR:
// v | -> | v.name |
// ---^sp ----------^sp
Expand All @@ -209,20 +246,6 @@ Object eval() {
s[sp - 1] = Abstract.getAttr(s[sp - 1], name);
break;

case Opcode.LOAD_METHOD:
// Designed to work in tandem with CALL_METHOD.
// If we can bypass temporary bound method:
// obj | -> | desc | self |
// -----^sp ---------------^sp
// Otherwise almost conventional LOAD_ATTR:
// obj | -> | null | meth |
// -----^sp ---------------^sp
name = names[oparg | opword & 0xff];
oparg = 0;
getMethod(s[--sp], name, sp);
sp += 2;
break;

case Opcode.JUMP_FORWARD:
ip += (oparg | opword & 0xff) >> 1;
oparg = 0;
Expand Down Expand Up @@ -265,6 +288,20 @@ Object eval() {
oparg = 0;
break;

case Opcode.LOAD_METHOD:
// Designed to work in tandem with CALL_METHOD.
// If we can bypass temporary bound method:
// obj | -> | desc | self |
// -----^sp ---------------^sp
// Otherwise almost conventional LOAD_ATTR:
// obj | -> | null | meth |
// -----^sp ---------------^sp
name = names[oparg | opword & 0xff];
oparg = 0;
getMethod(s[--sp], name, sp);
sp += 2;
break;

case Opcode.CALL_METHOD:
// Designed to work in tandem with LOAD_METHOD.
// If bypassed the method binding:
Expand Down
69 changes: 51 additions & 18 deletions core/src/main/java/org/python/core/PyList.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c)2022 Jython Developers.
// Copyright (c)2023 Jython Developers.
// Licensed to PSF under a contributor agreement.
// Copyright (c) Corporation for National Research Initiatives
package org.python.core;
Expand Down Expand Up @@ -32,7 +32,7 @@
* detect modification from within the current thread as a side
* effect of comparison. Java brings its own safeguard within
* iterators against structural concurrent modification.
*
*
* @implNote The design follows that in Jython 2 with a private Java
* list member to which operations are delegated directly or
* indirectly. In the present design, the indirect delegation is
Expand Down Expand Up @@ -68,7 +68,7 @@ public class PyList implements List<Object>, CraftedPyObject {
/**
* Fundamental constructor, specifying actual type and the list that
* will become the storage object.
*
*
* @param type actual type
* @param list storage object
*/
Expand All @@ -80,7 +80,7 @@ private PyList(PyType type, List<Object> list) {
/**
* Construct a Python {@code list} object, specifying actual type
* and initial capacity.
*
*
* @param type actual type
* @param initialCapacity capacity
*/
Expand All @@ -91,15 +91,15 @@ public PyList(PyType type, int initialCapacity) {
/**
* Construct a Python {@code list} object, specifying initial
* capacity.
*
*
* @param initialCapacity capacity
*/
public PyList(int initialCapacity) { this(TYPE, new ArrayList<>(initialCapacity)); }

/**
* Construct an empty Python {@code list} object, specifying actual
* type.
*
*
* @param type actual type
*/
public PyList(PyType type) { this(type, 0); }
Expand All @@ -111,7 +111,7 @@ public PyList(PyType type, int initialCapacity) {
* Construct a Python {@code list} object, specifying actual type
* and initial contents. The contents will be a (shallow) copy of
* the collection.
*
*
* @param type actual type
* @param c initial contents
*/
Expand All @@ -124,15 +124,29 @@ public PyList(PyType type, Collection<?> c) {
* Construct a Python {@code list} object, specifying initial
* contents. The contents will be a (shallow) copy of the
* collection.
*
*
* @param c initial contents
*/
public PyList(Collection<?> c) { this(TYPE, c); }

/**
* Construct a {@code list} with initial contents from an array
* slice.
*
* @param a the array
* @param start of slice
* @param count of elements to take
*/
PyList(Object[] a, int start, int count) {
this(TYPE, count);
int stop = start + count;
for (int i = start; i < stop; i++) { add(a[i]); }
}

/**
* Return a Python {@code list} object, specifying initial
* contents.
*
*
* @param elements initial element values
* @return list of elements
*/
Expand Down Expand Up @@ -383,11 +397,13 @@ final synchronized int list_index(Object v, Object start, Object stop) throws Ty
*
* @param index the position where the element will be inserted.
* @param o the element to insert.
* @throws TypeError from bad {@code index} type
* @throws Throwable from other conversion errors
*/
// @ExposedMethod(doc = BuiltinDocs.list_insert_doc)
final synchronized void list_insert(int index, Object o) {
final synchronized void list_insert(Object index, Object o) throws TypeError, Throwable {
changed = true;
list.add(boundedIndex(index), o);
delegate.insert(index, o);
}

/**
Expand All @@ -411,7 +427,7 @@ final synchronized void list_remove(Object v) throws Throwable {
/**
* Return the index of {@code v} in {@link #list} or -1 if not
* found.
*
*
* @param v the element to search for and remove.
* @return the index of {@code v} or -1 if not found.
* @throws Throwable from the implementation of {@code __eq__}
Expand Down Expand Up @@ -642,14 +658,17 @@ public Iterator<Object> iterator() {

private final Iterator<Object> iter = list.iterator();

@Override
public boolean hasNext() { return iter.hasNext(); }

@Override
public Object next() {
synchronized (PyList.this) {
return iter.next();
}
}

@Override
public void remove() {
synchronized (PyList.this) {
changed = true;
Expand All @@ -675,40 +694,49 @@ public ListIterator<Object> listIterator(final int index) {

private final ListIterator<Object> iter = list.listIterator(index);

@Override
public boolean hasNext() { return iter.hasNext(); }

@Override
public Object next() {
synchronized (PyList.this) {
return iter.next();
}
}

@Override
public boolean hasPrevious() { return iter.hasPrevious(); }

@Override
public Object previous() {
synchronized (PyList.this) {
return iter.previous();
}
}

@Override
public int nextIndex() { return iter.nextIndex(); }

@Override
public int previousIndex() { return iter.previousIndex(); }

@Override
public void remove() {
synchronized (PyList.this) {
changed = true;
iter.remove();
}
}

@Override
public void set(Object o) {
synchronized (PyList.this) {
changed = true;
iter.set(o);
}
}

@Override
public void add(Object o) {
synchronized (PyList.this) {
changed = true;
Expand Down Expand Up @@ -859,7 +887,7 @@ public boolean equals(Object other) {
* This comparator is used in
* {@link PyList#sort(Function, boolean)}, sub-classed for the type
* of sort.
*
*
* @param <T> type of element to sort (on practice {@code Object} or
* {@code KV}.
*/
Expand Down Expand Up @@ -891,7 +919,7 @@ boolean raisedException() {

/**
* Defines the comparison operation to use.
*
*
* @param o1 left operand
* @param o2 right operand
* @return true iff o1 is less than o2
Expand Down Expand Up @@ -933,7 +961,7 @@ private int boundedIndex(int index) {
/**
* Given an ordered ascending list of indices into {@link #list},
* remove the elements at those indices.
*
*
* @param erasures to remove
* @return {@code true} if {@code erasures} is not empty
*/
Expand Down Expand Up @@ -1004,8 +1032,10 @@ public PyList getSlice(Indices slice) throws Throwable {
return v;
}

public void setItem(int i, Object value) throws Throwable { list.add(i, value); }
@Override
public void setItem(int i, Object value) throws Throwable { list.set(i, value); }

@Override
public void setSlice(PySlice.Indices slice, Object value) throws Throwable {
/*
* Accept iterables (and iterators) by creating a Java List Jython 2
Expand Down Expand Up @@ -1048,10 +1078,12 @@ public void setSlice(PySlice.Indices slice, Object value) throws Throwable {
}
}

@Override
public void delItem(int i) throws Throwable {
list.remove(i);
}

@Override
public void delSlice(PySlice.Indices slice) throws Throwable {
final int M = slice.slicelength;
if (M > 0) {
Expand Down Expand Up @@ -1153,9 +1185,10 @@ public int count(Object v) throws Throwable {
* @param index position to insert
* @param v value to insert
* @return the number of times found
* @throws Throwable from the implementation of {@code __eq__}
* @throws TypeError from bad {@code index} type
* @throws Throwable from other conversion errors
*/
public void insert(Object index, Object v) throws Throwable {
public void insert(Object index, Object v) throws TypeError, Throwable {
list.add(boundedIndex(index), v);
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/test/java/org/python/core/CPython38CodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void co_consts() {
@DisplayName("We can execute simple ...")
@ParameterizedTest(name = "{0}.py")
@ValueSource(strings = {"load_store_name", "unary_op", "binary_op", "bool_left_arith",
"bool_right_arith", "call_method_builtin"})
"bool_right_arith", "tuple_index", "list_index", "call_method_builtin"})
void executeSimple(String name) {
CPython38Code code = readCode(name);
PyDict globals = new PyDict();
Expand Down
12 changes: 12 additions & 0 deletions core/src/test/pythonExample/list_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# list_index.py

# Just enough to exercise indexed access opcodes and methods

c = 22.0

d = [20, "hello", c]
a = d[0]
b = d[1]
d[2] = a + c
c = d[2]

9 changes: 9 additions & 0 deletions core/src/test/pythonExample/tuple_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# tuple_index.py

# Just enough to exercise indexed access opcodes and methods

c = 22.0

d = (20, "hello", c)
b = d[1]
c = d[2] + d[0]