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

handle 3-argument form of generator throw() method

parent 17846279
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // 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 "runtime/generator.h"
#include <algorithm> #include <algorithm>
...@@ -144,12 +147,15 @@ Box* generatorSend(Box* s, Box* v) { ...@@ -144,12 +147,15 @@ Box* generatorSend(Box* s, Box* v) {
return self->returnValue; 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(s->cls == generator_cls);
assert(isSubclass(e, Exception));
BoxedGenerator* self = static_cast<BoxedGenerator*>(s); BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
Box* ex = runtimeCall(e, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); Box* exc_tb = args ? nullptr : args[0];
self->exception = ExcInfo(ex->cls, ex, None); 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); return generatorSend(self, None);
} }
...@@ -161,7 +167,7 @@ Box* generatorClose(Box* s) { ...@@ -161,7 +167,7 @@ Box* generatorClose(Box* s) {
if (self->entryExited) if (self->entryExited)
return None; return None;
return generatorThrow(self, GeneratorExit); return generatorThrow(self, GeneratorExit, nullptr, nullptr);
} }
Box* generatorNext(Box* s) { Box* generatorNext(Box* s) {
...@@ -331,7 +337,8 @@ void setupGenerator() { ...@@ -331,7 +337,8 @@ void setupGenerator() {
generator_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)generatorClose, UNKNOWN, 1))); 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("next", new BoxedFunction(boxRTFunction((void*)generatorNext, UNKNOWN, 1)));
generator_cls->giveAttr("send", new BoxedFunction(boxRTFunction((void*)generatorSend, UNKNOWN, 2))); 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)); generator_cls->giveAttr("__name__", new (pyston_getset_cls) BoxedGetsetDescriptor(generatorName, NULL, NULL));
......
...@@ -32,6 +32,7 @@ class BoxedGenerator; ...@@ -32,6 +32,7 @@ class BoxedGenerator;
class BoxedTuple; class BoxedTuple;
// user-level raise functions that implement python-level semantics // user-level raise functions that implement python-level semantics
ExcInfo excInfoForRaise(Box*, Box*, Box*);
extern "C" void raise0() __attribute__((__noreturn__)); extern "C" void raise0() __attribute__((__noreturn__));
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__)); extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
void raiseExc(Box* exc_obj) __attribute__((__noreturn__)); void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
......
...@@ -208,7 +208,7 @@ extern "C" void exit(int code) { ...@@ -208,7 +208,7 @@ extern "C" void exit(int code) {
__builtin_unreachable(); __builtin_unreachable();
} }
void raise0() { extern "C" void raise0() {
ExcInfo* exc_info = getFrameExcInfo(); ExcInfo* exc_info = getFrameExcInfo();
assert(exc_info->type); assert(exc_info->type);
...@@ -238,38 +238,44 @@ bool ExcInfo::matches(BoxedClass* cls) const { ...@@ -238,38 +238,44 @@ bool ExcInfo::matches(BoxedClass* cls) const {
return isSubclass(static_cast<BoxedClass*>(this->type), cls); 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 // TODO switch this to PyErr_Normalize
if (arg2 == None) if (exc_tb == None)
arg2 = getTraceback(); exc_tb = getTraceback();
if (isSubclass(arg0->cls, type_cls)) { if (isSubclass(exc_cls->cls, type_cls)) {
BoxedClass* c = static_cast<BoxedClass*>(arg0); BoxedClass* c = static_cast<BoxedClass*>(exc_cls);
if (isSubclass(c, BaseException)) { if (isSubclass(c, BaseException)) {
Box* exc_obj; Box* exc_obj;
if (isSubclass(arg1->cls, BaseException)) { if (isSubclass(exc_val->cls, BaseException)) {
exc_obj = arg1; exc_obj = exc_val;
c = exc_obj->cls; c = exc_obj->cls;
} else if (arg1 != None) { } else if (exc_val != None) {
exc_obj = runtimeCall(c, ArgPassSpec(1), arg1, NULL, NULL, NULL, NULL); exc_obj = runtimeCall(c, ArgPassSpec(1), exc_val, NULL, NULL, NULL, NULL);
} else { } else {
exc_obj = runtimeCall(c, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); 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 (isSubclass(exc_cls->cls, BaseException)) {
if (arg1 != None) if (exc_val != None)
raiseExcHelper(TypeError, "instance exception may not have a separate value"); 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", 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) { 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