Commit 898b18cb authored by Michael Arntzenius's avatar Michael Arntzenius

handle 3-argument form of generator throw() method

parent 17846279
......@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// See https://docs.python.org/2/reference/expressions.html#yieldexpr for the relevant Python language reference
// documentation on generators.
#include "runtime/generator.h"
#include <algorithm>
......@@ -144,12 +147,15 @@ Box* generatorSend(Box* s, Box* v) {
return self->returnValue;
}
Box* generatorThrow(Box* s, BoxedClass* e) {
Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** args = nullptr) {
assert(s->cls == generator_cls);
assert(isSubclass(e, Exception));
BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
Box* ex = runtimeCall(e, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
self->exception = ExcInfo(ex->cls, ex, None);
Box* exc_tb = args ? nullptr : args[0];
if (!exc_val)
exc_val = None;
if (!exc_tb)
exc_tb = None;
self->exception = excInfoForRaise(exc_cls, exc_val, exc_tb);
return generatorSend(self, None);
}
......@@ -161,7 +167,7 @@ Box* generatorClose(Box* s) {
if (self->entryExited)
return None;
return generatorThrow(self, GeneratorExit);
return generatorThrow(self, GeneratorExit, nullptr, nullptr);
}
Box* generatorNext(Box* s) {
......@@ -331,7 +337,8 @@ void setupGenerator() {
generator_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)generatorClose, UNKNOWN, 1)));
generator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)generatorNext, UNKNOWN, 1)));
generator_cls->giveAttr("send", new BoxedFunction(boxRTFunction((void*)generatorSend, UNKNOWN, 2)));
generator_cls->giveAttr("throw", new BoxedFunction(boxRTFunction((void*)generatorThrow, UNKNOWN, 2)));
auto gthrow = new BoxedFunction(boxRTFunction((void*)generatorThrow, UNKNOWN, 4, 2, false, false), { NULL, NULL });
generator_cls->giveAttr("throw", gthrow);
generator_cls->giveAttr("__name__", new (pyston_getset_cls) BoxedGetsetDescriptor(generatorName, NULL, NULL));
......
......@@ -32,6 +32,7 @@ class BoxedGenerator;
class BoxedTuple;
// user-level raise functions that implement python-level semantics
ExcInfo excInfoForRaise(Box*, Box*, Box*);
extern "C" void raise0() __attribute__((__noreturn__));
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
......
......@@ -208,7 +208,7 @@ extern "C" void exit(int code) {
__builtin_unreachable();
}
void raise0() {
extern "C" void raise0() {
ExcInfo* exc_info = getFrameExcInfo();
assert(exc_info->type);
......@@ -238,38 +238,44 @@ bool ExcInfo::matches(BoxedClass* cls) const {
return isSubclass(static_cast<BoxedClass*>(this->type), cls);
}
void raise3(Box* arg0, Box* arg1, Box* arg2) {
// takes the three arguments of a `raise' and produces the ExcInfo to throw
ExcInfo excInfoForRaise(Box* exc_cls, Box* exc_val, Box* exc_tb) {
assert(exc_cls && exc_val && exc_tb); // use None for default behavior, not nullptr
// TODO switch this to PyErr_Normalize
if (arg2 == None)
arg2 = getTraceback();
if (exc_tb == None)
exc_tb = getTraceback();
if (isSubclass(arg0->cls, type_cls)) {
BoxedClass* c = static_cast<BoxedClass*>(arg0);
if (isSubclass(exc_cls->cls, type_cls)) {
BoxedClass* c = static_cast<BoxedClass*>(exc_cls);
if (isSubclass(c, BaseException)) {
Box* exc_obj;
if (isSubclass(arg1->cls, BaseException)) {
exc_obj = arg1;
if (isSubclass(exc_val->cls, BaseException)) {
exc_obj = exc_val;
c = exc_obj->cls;
} else if (arg1 != None) {
exc_obj = runtimeCall(c, ArgPassSpec(1), arg1, NULL, NULL, NULL, NULL);
} else if (exc_val != None) {
exc_obj = runtimeCall(c, ArgPassSpec(1), exc_val, NULL, NULL, NULL, NULL);
} else {
exc_obj = runtimeCall(c, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
raiseRaw(ExcInfo(c, exc_obj, arg2));
return ExcInfo(c, exc_obj, exc_tb);
}
}
if (isSubclass(arg0->cls, BaseException)) {
if (arg1 != None)
if (isSubclass(exc_cls->cls, BaseException)) {
if (exc_val != None)
raiseExcHelper(TypeError, "instance exception may not have a separate value");
raiseRaw(ExcInfo(arg0->cls, arg0, arg2));
return ExcInfo(exc_cls->cls, exc_cls, exc_tb);
}
raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not %s",
getTypeName(arg0));
getTypeName(exc_cls));
}
extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) {
raiseRaw(excInfoForRaise(arg0, arg1, arg2));
}
void raiseExcHelper(BoxedClass* cls, Box* arg) {
......
import sys
def generate(lst):
for x in lst: yield x
def f():
g = generate([1])
print g.next()
try:
g.throw(ZeroDivisionError)
except ZeroDivisionError as e:
print e
# check that we have a traceback
print sys.exc_info()[2] is None
else:
print "shouldn't happen"
f()
def f2():
g = generate([1])
print g.next()
try:
g.throw(ZeroDivisionError(2))
print 'hello'
except ZeroDivisionError as e:
print e
# check that we have a traceback
print sys.exc_info()[2] is None
else:
print "shouldn't happen"
f2()
def f3():
g = generate([1,2])
print g.next()
try:
g.throw(ZeroDivisionError, 2, None)
except ZeroDivisionError as e:
print e
cls, val, tb = sys.exc_info()
print cls
print val
print isinstance(val, ZeroDivisionError)
print tb is None
else:
print "shouldn't happen"
f3()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment