Skip to content

Commit

Permalink
Implement flow control opcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff5 committed Jul 13, 2023
1 parent c9da398 commit e9eeb64
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 12 deletions.
90 changes: 89 additions & 1 deletion core/src/main/java/org/python/core/CPython311Frame.java
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,14 @@ Object eval() {
s[sp] = new PyList(s, sp++, oparg);
break;

case Opcode311.LIST_EXTEND: {
Object iterable = s[--sp];
PyList list = (PyList)s[sp - oparg];
list.list_extend(iterable,
() -> Abstract.typeError(VALUE_AFTER_STAR, iterable));
break;
}

case Opcode311.BUILD_MAP:
// k1 | v1 | ... | kN | vN | -> | map |
// -------------------------^sp -------^sp
Expand Down Expand Up @@ -389,6 +397,86 @@ Object eval() {
break;
}

case Opcode311.JUMP_FORWARD:
ip += oparg;
break;

case Opcode311.JUMP_BACKWARD: {
ip -= oparg;
break;
}

case Opcode311.POP_JUMP_BACKWARD_IF_FALSE: {
if (!Abstract.isTrue(s[--sp])) { ip -= oparg; }
break;
}
case Opcode311.POP_JUMP_FORWARD_IF_FALSE: {
if (!Abstract.isTrue(s[--sp])) { ip += oparg; }
break;
}

case Opcode311.POP_JUMP_BACKWARD_IF_TRUE: {
if (Abstract.isTrue(s[--sp])) { ip -= oparg; }
break;

}

case Opcode311.POP_JUMP_FORWARD_IF_TRUE: {
if (Abstract.isTrue(s[--sp])) { ip += oparg; }
break;

}

case Opcode311.POP_JUMP_BACKWARD_IF_NOT_NONE: {
if (s[--sp] != Py.None) { ip -= oparg; }
break;
}

case Opcode311.POP_JUMP_FORWARD_IF_NOT_NONE: {
if (s[--sp] != Py.None) { ip += oparg; }
break;
}

case Opcode311.POP_JUMP_BACKWARD_IF_NONE: {
if (s[--sp] == Py.None) { ip -= oparg; }
break;
}

case Opcode311.POP_JUMP_FORWARD_IF_NONE: {
if (s[--sp] == Py.None) { ip += oparg; }
break;
}

case Opcode311.JUMP_IF_FALSE_OR_POP: {
Object v = s[--sp]; // POP
if (!Abstract.isTrue(v)) {
sp += 1; // UNPOP
ip += oparg;
}
break;
}

case Opcode311.JUMP_IF_TRUE_OR_POP: {
Object v = s[--sp]; // POP
if (Abstract.isTrue(v)) {
sp += 1; // UNPOP
ip += oparg;
}
break;
}

case Opcode311.JUMP_BACKWARD_NO_INTERRUPT: {
// Same as plain JUMP_BACKWARD for us
ip -= oparg;
break;
}

case Opcode311.JUMP_BACKWARD_QUICK: {
// Same as plain JUMP_BACKWARD for us
ip -= oparg;
break;
}

case Opcode311.LOAD_METHOD:
/*
* Emitted when compiling obj.meth(...). Works in tandem with CALL.
Expand Down Expand Up @@ -571,8 +659,8 @@ Object eval() {
// Supporting definitions and methods -----------------------------

private static final Object[] EMPTY_OBJECT_ARRAY = Py.EMPTY_ARRAY;

private static final String NAME_ERROR_MSG = "name '%.200s' is not defined";
private static final String VALUE_AFTER_STAR = "Value after * must be an iterable, not %.200s";

/**
* A specialised version of {@code object.__getattribute__}
Expand Down
29 changes: 23 additions & 6 deletions core/src/main/java/org/python/core/PyList.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.ListIterator;
import java.util.StringJoiner;
import java.util.function.Function;
import java.util.function.Supplier;

import org.python.base.InterpreterError;
import org.python.core.PyObjectUtil.NoConversion;
Expand All @@ -27,11 +28,11 @@
* <p>
* It is {@code synchronized} so that competing threads should be
* able to access it with roughly the same protection against
* concurrent modification that CPython offers.
* There are also necessary safeguards during {@code sort()} to
* detect modification from within the current thread as a side
* effect of comparison. Java brings its own safeguard within
* iterators against structural concurrent modification.
* concurrent modification that CPython offers. There are also
* necessary safeguards during {@code sort()} to 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
Expand Down Expand Up @@ -479,8 +480,24 @@ final synchronized Object list_pop(int n) {
*/
// @ExposedMethod(doc = BuiltinDocs.list_extend_doc)
final synchronized void list_extend(Object o) throws Throwable {
list_extend(o, null);
}

/**
* Append the elements in the argument sequence to the end of the
* list, {@code s[len(s):len(s)] = o}.
*
* @param <E> the type of exception to throw
* @param o the sequence of items to append to the list.
* @param exc a supplier (e.g. lambda expression) for the exception
* to throw if an iterator cannot be formed (or {@code null} for
* a default {@code TypeError})
* @throws E to throw if an iterator cannot be formed
* @throws Throwable from the implementation of {@code o}.
*/
final <E extends PyException> void list_extend(Object o, Supplier<E> exc) throws E, Throwable {
changed = true;
list.addAll(PySequence.fastList(o, null));
list.addAll(PySequence.fastList(o, exc));
}

// @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.list___iadd___doc)
Expand Down
30 changes: 25 additions & 5 deletions core/src/test/java/org/python/core/CPython311CodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import java.nio.file.Path;
import java.util.Map;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
Expand Down Expand Up @@ -90,10 +89,32 @@ void co_filename() {
@Test
protected void co_name() { assertEquals("<module>", code.name); }

abstract void co_names();
void co_names() { checkNames(code.co_names(), EMPTY_STRINGS); }

@Test
void co_varnames() { assertEquals(0, code.co_varnames().size()); }
void co_varnames() { checkNames(code.co_varnames(), EMPTY_STRINGS); }

/**
* Check {@code code} name enquiry against the expected list.
*
* @param names result from code object
* @param exp expected names in expected order
*/
void checkNames(PyTuple names, String... exp) {
assertEquals(exp.length, names.size());
for (int i = 0; i < exp.length; i++) { assertPythonEquals(exp[i], names.get(i)); }
}

/**
* Check {@code code} values enquiry against the expected list.
*
* @param values result from code object
* @param exp expected values in expected order
*/
void checkValues(PyTuple values, Object... exp) {
assertEquals(exp.length, values.size());
for (int i = 0; i < exp.length; i++) { assertPythonEquals(exp[i], values.get(i)); }
}
}

@Nested
Expand Down Expand Up @@ -145,8 +166,6 @@ void executeSimple(String name) {
*
* @param name of the Python example
*/
@Disabled("Not yet implementing 3.11 byte code")
// FIXME and re-enable test
@SuppressWarnings("static-method")
@DisplayName("We can execute branches and while loops ...")
@ParameterizedTest(name = "{0}.py")
Expand Down Expand Up @@ -192,6 +211,7 @@ void executeBranchAndLoop(String name) {

private static final String PYC_SUFFIX = "pyc";
private static final String VAR_SUFFIX = "var";
private static final String[] EMPTY_STRINGS = {};

/**
* Read a {@code code} object with {@code marshal}. The method looks
Expand Down

0 comments on commit e9eeb64

Please sign in to comment.