mirror of
https://github.com/pocketpy/pocketpy
synced 2025-12-13 13:40:16 +00:00
Compare commits
4 Commits
7967852eb9
...
18fc4c02d3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18fc4c02d3 | ||
|
|
0a77c96c0a | ||
|
|
571a080127 | ||
|
|
95d5e3e437 |
@ -115,6 +115,7 @@ py_Type pk_range__register();
|
|||||||
py_Type pk_range_iterator__register();
|
py_Type pk_range_iterator__register();
|
||||||
py_Type pk_BaseException__register();
|
py_Type pk_BaseException__register();
|
||||||
py_Type pk_Exception__register();
|
py_Type pk_Exception__register();
|
||||||
|
py_Type pk_StopIteration__register();
|
||||||
py_Type pk_super__register();
|
py_Type pk_super__register();
|
||||||
py_Type pk_property__register();
|
py_Type pk_property__register();
|
||||||
py_Type pk_staticmethod__register();
|
py_Type pk_staticmethod__register();
|
||||||
|
|||||||
@ -83,6 +83,7 @@ OPCODE(UNARY_INVERT)
|
|||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(GET_ITER)
|
OPCODE(GET_ITER)
|
||||||
OPCODE(FOR_ITER)
|
OPCODE(FOR_ITER)
|
||||||
|
OPCODE(FOR_ITER_YIELD_VALUE)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(IMPORT_PATH)
|
OPCODE(IMPORT_PATH)
|
||||||
OPCODE(POP_IMPORT_STAR)
|
OPCODE(POP_IMPORT_STAR)
|
||||||
|
|||||||
@ -1494,19 +1494,12 @@ static Error* pop_context(Compiler* self) {
|
|||||||
int codes_length = func->code.codes.length;
|
int codes_length = func->code.codes.length;
|
||||||
|
|
||||||
for(int i = 0; i < codes_length; i++) {
|
for(int i = 0; i < codes_length; i++) {
|
||||||
if(codes[i].op == OP_YIELD_VALUE) {
|
if(codes[i].op == OP_YIELD_VALUE || codes[i].op == OP_FOR_ITER_YIELD_VALUE) {
|
||||||
func->type = FuncType_GENERATOR;
|
func->type = FuncType_GENERATOR;
|
||||||
for(int j = 0; j < codes_length; j++) {
|
|
||||||
if(codes[j].op == OP_RETURN_VALUE && codes[j].arg == BC_NOARG) {
|
|
||||||
Error* err =
|
|
||||||
SyntaxError(self, "'return' with argument inside generator function");
|
|
||||||
err->lineno = c11__at(BytecodeEx, &func->code.codes_ex, j)->lineno;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(func->type == FuncType_UNSET) {
|
if(func->type == FuncType_UNSET) {
|
||||||
bool is_simple = true;
|
bool is_simple = true;
|
||||||
if(func->kwargs.length > 0) is_simple = false;
|
if(func->kwargs.length > 0) is_simple = false;
|
||||||
@ -2035,6 +2028,20 @@ static Error* compile_for_loop(Compiler* self) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Error* compile_yield_from(Compiler* self, int kw_line) {
|
||||||
|
Error* err;
|
||||||
|
if(self->contexts.length <= 1) return SyntaxError(self, "'yield from' outside function");
|
||||||
|
check(EXPR_TUPLE(self));
|
||||||
|
Ctx__s_emit_top(ctx());
|
||||||
|
Ctx__emit_(ctx(), OP_GET_ITER, BC_NOARG, kw_line);
|
||||||
|
Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP);
|
||||||
|
Ctx__emit_(ctx(), OP_FOR_ITER_YIELD_VALUE, ctx()->curr_iblock, kw_line);
|
||||||
|
Ctx__emit_(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), kw_line);
|
||||||
|
Ctx__exit_block(ctx());
|
||||||
|
// StopIteration.value will be pushed onto the stack
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
||||||
Error* err;
|
Error* err;
|
||||||
switch(curr()->type) {
|
switch(curr()->type) {
|
||||||
@ -2074,15 +2081,24 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
case TK_ASSIGN: {
|
case TK_ASSIGN: {
|
||||||
|
consume(TK_ASSIGN);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while(match(TK_ASSIGN)) {
|
|
||||||
check(EXPR_TUPLE(self));
|
if(match(TK_YIELD_FROM)) {
|
||||||
n += 1;
|
check(compile_yield_from(self, prev()->line));
|
||||||
|
n = 1;
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
check(EXPR_TUPLE(self));
|
||||||
|
n += 1;
|
||||||
|
} while(match(TK_ASSIGN));
|
||||||
|
|
||||||
|
// stack size is n+1
|
||||||
|
Ctx__s_emit_top(ctx());
|
||||||
|
for(int j = 1; j < n; j++)
|
||||||
|
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
// stack size is n+1
|
|
||||||
Ctx__s_emit_top(ctx());
|
|
||||||
for(int j = 1; j < n; j++)
|
|
||||||
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
|
||||||
for(int j = 0; j < n; j++) {
|
for(int j = 0; j < n; j++) {
|
||||||
if(Ctx__s_top(ctx())->vt->is_starred)
|
if(Ctx__s_top(ctx())->vt->is_starred)
|
||||||
return SyntaxError(self, "can't use starred expression here");
|
return SyntaxError(self, "can't use starred expression here");
|
||||||
@ -2482,22 +2498,18 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
break;
|
break;
|
||||||
case TK_YIELD:
|
case TK_YIELD:
|
||||||
if(self->contexts.length <= 1) return SyntaxError(self, "'yield' outside function");
|
if(self->contexts.length <= 1) return SyntaxError(self, "'yield' outside function");
|
||||||
check(EXPR_TUPLE(self));
|
if(match_end_stmt(self)) {
|
||||||
Ctx__s_emit_top(ctx());
|
Ctx__emit_(ctx(), OP_YIELD_VALUE, 1, kw_line);
|
||||||
Ctx__emit_(ctx(), OP_YIELD_VALUE, BC_NOARG, kw_line);
|
} else {
|
||||||
consume_end_stmt();
|
check(EXPR_TUPLE(self));
|
||||||
|
Ctx__s_emit_top(ctx());
|
||||||
|
Ctx__emit_(ctx(), OP_YIELD_VALUE, BC_NOARG, kw_line);
|
||||||
|
consume_end_stmt();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TK_YIELD_FROM:
|
case TK_YIELD_FROM:
|
||||||
if(self->contexts.length <= 1)
|
check(compile_yield_from(self, kw_line));
|
||||||
return SyntaxError(self, "'yield from' outside function");
|
Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, kw_line);
|
||||||
check(EXPR_TUPLE(self));
|
|
||||||
Ctx__s_emit_top(ctx());
|
|
||||||
Ctx__emit_(ctx(), OP_GET_ITER, BC_NOARG, kw_line);
|
|
||||||
Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP);
|
|
||||||
Ctx__emit_(ctx(), OP_FOR_ITER, ctx()->curr_iblock, kw_line);
|
|
||||||
Ctx__emit_(ctx(), OP_YIELD_VALUE, BC_NOARG, kw_line);
|
|
||||||
Ctx__emit_(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), kw_line);
|
|
||||||
Ctx__exit_block(ctx());
|
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK_RETURN:
|
case TK_RETURN:
|
||||||
|
|||||||
@ -715,8 +715,12 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_YIELD_VALUE: {
|
case OP_YIELD_VALUE: {
|
||||||
py_assign(py_retval(), TOP());
|
if(byte.arg == 1) {
|
||||||
POP();
|
py_newnone(py_retval());
|
||||||
|
} else {
|
||||||
|
py_assign(py_retval(), TOP());
|
||||||
|
POP();
|
||||||
|
}
|
||||||
return RES_YIELD;
|
return RES_YIELD;
|
||||||
}
|
}
|
||||||
/////////
|
/////////
|
||||||
@ -781,10 +785,25 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
PUSH(py_retval());
|
PUSH(py_retval());
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
} else {
|
} else {
|
||||||
|
assert(self->last_retval.type == tp_StopIteration);
|
||||||
int target = Frame__prepare_loop_break(frame, &self->stack);
|
int target = Frame__prepare_loop_break(frame, &self->stack);
|
||||||
DISPATCH_JUMP_ABSOLUTE(target);
|
DISPATCH_JUMP_ABSOLUTE(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case OP_FOR_ITER_YIELD_VALUE: {
|
||||||
|
int res = py_next(TOP());
|
||||||
|
if(res == -1) goto __ERROR;
|
||||||
|
if(res) {
|
||||||
|
return RES_YIELD;
|
||||||
|
} else {
|
||||||
|
assert(self->last_retval.type == tp_StopIteration);
|
||||||
|
py_ObjectRef value = py_getslot(&self->last_retval, 0);
|
||||||
|
int target = Frame__prepare_loop_break(frame, &self->stack);
|
||||||
|
if(py_isnil(value)) value = py_None();
|
||||||
|
PUSH(value);
|
||||||
|
DISPATCH_JUMP_ABSOLUTE(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
////////
|
////////
|
||||||
case OP_IMPORT_PATH: {
|
case OP_IMPORT_PATH: {
|
||||||
py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
||||||
@ -1040,6 +1059,33 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
return RES_RETURN;
|
return RES_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const static char* op2str(py_Name op) {
|
||||||
|
switch(op) {
|
||||||
|
case __eq__: return "==";
|
||||||
|
case __ne__: return "!=";
|
||||||
|
case __lt__: return "<";
|
||||||
|
case __le__: return "<=";
|
||||||
|
case __gt__: return ">";
|
||||||
|
case __ge__: return ">=";
|
||||||
|
case __add__: return "+";
|
||||||
|
case __sub__: return "-";
|
||||||
|
case __mul__: return "*";
|
||||||
|
case __truediv__: return "/";
|
||||||
|
case __floordiv__: return "//";
|
||||||
|
case __mod__: return "%";
|
||||||
|
case __pow__: return "**";
|
||||||
|
case __lshift__: return "<<";
|
||||||
|
case __rshift__: return ">>";
|
||||||
|
case __and__: return "&";
|
||||||
|
case __or__: return "|";
|
||||||
|
case __xor__: return "^";
|
||||||
|
case __neg__: return "-";
|
||||||
|
case __invert__: return "~";
|
||||||
|
case __matmul__: return "@";
|
||||||
|
default: return py_name2str(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
|
bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
|
||||||
// [a, b]
|
// [a, b]
|
||||||
py_Ref magic = py_tpfindmagic(SECOND()->type, op);
|
py_Ref magic = py_tpfindmagic(SECOND()->type, op);
|
||||||
@ -1071,7 +1117,7 @@ bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
|
|||||||
py_newbool(py_retval(), !res);
|
py_newbool(py_retval(), !res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return TypeError("unsupported operand type(s) for '%n'", op);
|
return TypeError("unsupported operand type(s) for '%s'", op2str(op));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
|
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
|
||||||
|
|||||||
@ -67,7 +67,10 @@ static bool generator__next__(int argc, py_Ref argv) {
|
|||||||
} else {
|
} else {
|
||||||
assert(res == RES_RETURN);
|
assert(res == RES_RETURN);
|
||||||
ud->state = 2;
|
ud->state = 2;
|
||||||
return StopIteration();
|
// raise StopIteration(<retval>)
|
||||||
|
bool ok = py_tpcall(tp_StopIteration, 1, py_retval());
|
||||||
|
if(!ok) return false;
|
||||||
|
return py_raise(py_retval());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -147,7 +147,10 @@ void VM__ctor(VM* self) {
|
|||||||
INJECT_BUILTIN_EXC(SystemExit, tp_BaseException);
|
INJECT_BUILTIN_EXC(SystemExit, tp_BaseException);
|
||||||
INJECT_BUILTIN_EXC(KeyboardInterrupt, tp_BaseException);
|
INJECT_BUILTIN_EXC(KeyboardInterrupt, tp_BaseException);
|
||||||
|
|
||||||
INJECT_BUILTIN_EXC(StopIteration, tp_Exception);
|
// INJECT_BUILTIN_EXC(StopIteration, tp_Exception);
|
||||||
|
validate(tp_StopIteration, pk_StopIteration__register());
|
||||||
|
py_setdict(&self->builtins, py_name("StopIteration"), py_tpobject(tp_StopIteration));
|
||||||
|
|
||||||
INJECT_BUILTIN_EXC(SyntaxError, tp_Exception);
|
INJECT_BUILTIN_EXC(SyntaxError, tp_Exception);
|
||||||
INJECT_BUILTIN_EXC(StackOverflowError, tp_Exception);
|
INJECT_BUILTIN_EXC(StackOverflowError, tp_Exception);
|
||||||
INJECT_BUILTIN_EXC(IOError, tp_Exception);
|
INJECT_BUILTIN_EXC(IOError, tp_Exception);
|
||||||
|
|||||||
@ -255,4 +255,8 @@ bool pk_callmagic(py_Name name, int argc, py_Ref argv) {
|
|||||||
return py_call(tmp, argc, argv);
|
return py_call(tmp, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StopIteration() { return py_exception(tp_StopIteration, ""); }
|
bool StopIteration() {
|
||||||
|
bool ok = py_tpcall(tp_StopIteration, 0, NULL);
|
||||||
|
if(!ok) return false;
|
||||||
|
return py_raise(py_retval());
|
||||||
|
}
|
||||||
|
|||||||
@ -243,11 +243,17 @@ static bool builtins_iter(int argc, py_Ref argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool builtins_next(int argc, py_Ref argv) {
|
static bool builtins_next(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
if(argc == 0 || argc > 2) return TypeError("next() takes 1 or 2 arguments");
|
||||||
int res = py_next(argv);
|
int res = py_next(argv);
|
||||||
if(res == -1) return false;
|
if(res == -1) return false;
|
||||||
if(res) return true;
|
if(res) return true;
|
||||||
return py_exception(tp_StopIteration, "");
|
if(argc == 1) {
|
||||||
|
// StopIteration stored in py_retval()
|
||||||
|
return py_raise(py_retval());
|
||||||
|
} else {
|
||||||
|
py_assign(py_retval(), py_arg(1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool builtins_hash(int argc, py_Ref argv) {
|
static bool builtins_hash(int argc, py_Ref argv) {
|
||||||
|
|||||||
@ -96,6 +96,17 @@ static bool BaseException_args(int argc, py_Ref argv){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool StopIteration_value(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(1);
|
||||||
|
py_Ref arg = py_getslot(argv, 0);
|
||||||
|
if(py_isnil(arg)) {
|
||||||
|
py_newnone(py_retval());
|
||||||
|
}else{
|
||||||
|
py_assign(py_retval(), arg);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
py_Type pk_BaseException__register() {
|
py_Type pk_BaseException__register() {
|
||||||
py_Type type = pk_newtype("BaseException", tp_object, NULL, BaseException__dtor, false, false);
|
py_Type type = pk_newtype("BaseException", tp_object, NULL, BaseException__dtor, false, false);
|
||||||
|
|
||||||
@ -112,6 +123,12 @@ py_Type pk_Exception__register() {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
py_Type pk_StopIteration__register() {
|
||||||
|
py_Type type = pk_newtype("StopIteration", tp_Exception, NULL, NULL, false, false);
|
||||||
|
py_bindproperty(type, "value", StopIteration_value, NULL);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
bool py_checkexc(bool ignore_handled) {
|
bool py_checkexc(bool ignore_handled) {
|
||||||
VM* vm = pk_current_vm;
|
VM* vm = pk_current_vm;
|
||||||
@ -134,13 +151,10 @@ bool py_matchexc(py_Type type) {
|
|||||||
|
|
||||||
void py_clearexc(py_StackRef p0) {
|
void py_clearexc(py_StackRef p0) {
|
||||||
VM* vm = pk_current_vm;
|
VM* vm = pk_current_vm;
|
||||||
vm->last_retval = *py_NIL();
|
|
||||||
vm->curr_exception = *py_NIL();
|
vm->curr_exception = *py_NIL();
|
||||||
vm->is_curr_exc_handled = false;
|
vm->is_curr_exc_handled = false;
|
||||||
|
|
||||||
/* Don't clear this, because StopIteration() may corrupt the class defination */
|
/* Don't clear this, because StopIteration() may corrupt the class defination */
|
||||||
// vm->__curr_class = NULL;
|
// vm->__curr_class = NULL;
|
||||||
|
|
||||||
vm->__curr_function = NULL;
|
vm->__curr_function = NULL;
|
||||||
if(p0) vm->stack.sp = p0;
|
if(p0) vm->stack.sp = p0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,6 +77,7 @@ int py_next(py_Ref val) {
|
|||||||
}
|
}
|
||||||
if(py_call(tmp, 1, val)) return 1;
|
if(py_call(tmp, 1, val)) return 1;
|
||||||
if(vm->curr_exception.type == tp_StopIteration) {
|
if(vm->curr_exception.type == tp_StopIteration) {
|
||||||
|
vm->last_retval = vm->curr_exception;
|
||||||
py_clearexc(NULL);
|
py_clearexc(NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,6 +110,37 @@ static bool tuple__ne__(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool tuple__lt__(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
if(!py_istype(py_arg(1), tp_tuple)) {
|
||||||
|
py_newnotimplemented(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
py_TValue *p0, *p1;
|
||||||
|
int lhs_length = py_tuple_len(py_arg(0));
|
||||||
|
int rhs_length = py_tuple_len(py_arg(1));
|
||||||
|
p0 = py_tuple_data(py_arg(0));
|
||||||
|
p1 = py_tuple_data(py_arg(1));
|
||||||
|
int length = lhs_length < rhs_length ? lhs_length : rhs_length;
|
||||||
|
for(int i = 0; i < length; i++) {
|
||||||
|
int res_lt = py_less(p0 + i, p1 + i);
|
||||||
|
if(res_lt == -1) return false;
|
||||||
|
if(res_lt) {
|
||||||
|
py_newbool(py_retval(), true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
int res_eq = py_equal(p0 + i, p1 + i);
|
||||||
|
if(res_eq == -1) return false;
|
||||||
|
if(!res_eq) {
|
||||||
|
py_newbool(py_retval(), false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
py_newbool(py_retval(), lhs_length < rhs_length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool tuple__iter__(int argc, py_Ref argv) {
|
static bool tuple__iter__(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
PY_CHECK_ARGC(1);
|
||||||
return pk_arrayiter(argv);
|
return pk_arrayiter(argv);
|
||||||
@ -144,6 +175,7 @@ py_Type pk_tuple__register() {
|
|||||||
py_bindmagic(type, __getitem__, tuple__getitem__);
|
py_bindmagic(type, __getitem__, tuple__getitem__);
|
||||||
py_bindmagic(type, __eq__, tuple__eq__);
|
py_bindmagic(type, __eq__, tuple__eq__);
|
||||||
py_bindmagic(type, __ne__, tuple__ne__);
|
py_bindmagic(type, __ne__, tuple__ne__);
|
||||||
|
py_bindmagic(type, __lt__, tuple__lt__);
|
||||||
py_bindmagic(type, __iter__, tuple__iter__);
|
py_bindmagic(type, __iter__, tuple__iter__);
|
||||||
py_bindmagic(type, __contains__, tuple__contains__);
|
py_bindmagic(type, __contains__, tuple__contains__);
|
||||||
py_bindmagic(type, __hash__, tuple__hash__);
|
py_bindmagic(type, __hash__, tuple__hash__);
|
||||||
|
|||||||
@ -35,3 +35,20 @@ assert repr(tuple()) == '()'
|
|||||||
# test in and not in
|
# test in and not in
|
||||||
assert 1 in (1, 2, 3)
|
assert 1 in (1, 2, 3)
|
||||||
assert 4 not in (1, 2, 3)
|
assert 4 not in (1, 2, 3)
|
||||||
|
|
||||||
|
# test < and == and !=
|
||||||
|
assert (1,2) == (1,2)
|
||||||
|
assert (2,1) == (2,1)
|
||||||
|
assert (1,) == (1,)
|
||||||
|
assert (1,2) != (1,3)
|
||||||
|
assert (1,2) != (1,2,3)
|
||||||
|
assert (1,2) != (1,)
|
||||||
|
|
||||||
|
assert (1,2) < (1,3)
|
||||||
|
assert (1,2) < (2,1)
|
||||||
|
assert (1,2) < (2,2)
|
||||||
|
assert (1,2) < (1,2,3)
|
||||||
|
assert (1,2) < (1,2,1)
|
||||||
|
assert (1,2) < (1,2,2)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
def g():
|
def g():
|
||||||
yield 1
|
yield 1
|
||||||
yield 2
|
yield 2
|
||||||
|
yield
|
||||||
|
|
||||||
a = g()
|
a = g()
|
||||||
assert next(a) == 1
|
assert next(a) == 1
|
||||||
assert next(a) == 2
|
assert next(a, None) == 2
|
||||||
|
assert next(a) == None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
next(a)
|
next(a)
|
||||||
@ -12,6 +14,9 @@ try:
|
|||||||
except StopIteration:
|
except StopIteration:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
assert next(a, 3) == 3
|
||||||
|
assert next(a, 4) == 4
|
||||||
|
|
||||||
def f(n):
|
def f(n):
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
yield i
|
yield i
|
||||||
@ -99,16 +104,27 @@ def f():
|
|||||||
|
|
||||||
assert list(f()) == [1, 2]
|
assert list(f()) == [1, 2]
|
||||||
|
|
||||||
src = '''
|
|
||||||
def g():
|
def g():
|
||||||
yield 1
|
yield 1
|
||||||
yield 2
|
yield 2
|
||||||
return 3
|
return 3
|
||||||
yield 4
|
yield 4
|
||||||
'''
|
|
||||||
|
assert StopIteration().value == None
|
||||||
|
assert StopIteration(3).value == 3
|
||||||
|
|
||||||
try:
|
try:
|
||||||
exec(src)
|
iter = g()
|
||||||
|
assert next(iter) == 1
|
||||||
|
assert next(iter) == 2
|
||||||
|
next(iter) # raises StopIteration
|
||||||
|
print('UNREACHABLE!!')
|
||||||
exit(1)
|
exit(1)
|
||||||
except SyntaxError:
|
except StopIteration as e:
|
||||||
pass
|
assert e.value == 3
|
||||||
|
|
||||||
|
def f():
|
||||||
|
a = yield from g()
|
||||||
|
yield a
|
||||||
|
|
||||||
|
assert list(f()) == [1, 2, 3]
|
||||||
@ -574,11 +574,12 @@ assert max(1, 2, 3) == 3
|
|||||||
assert max([1, 2]) == 2
|
assert max([1, 2]) == 2
|
||||||
assert max([1, 2, 3], key=lambda x: -x) == 1
|
assert max([1, 2, 3], key=lambda x: -x) == 1
|
||||||
|
|
||||||
# assert min([
|
assert min([
|
||||||
# (1, 2),
|
(3, 1),
|
||||||
# (1, 3),
|
(1, 2),
|
||||||
# (1, 4),
|
(1, 3),
|
||||||
# ]) == (1, 2)
|
(1, 4),
|
||||||
|
]) == (1, 2)
|
||||||
|
|
||||||
assert min(1, 2) == 1
|
assert min(1, 2) == 1
|
||||||
assert max(1, 2) == 2
|
assert max(1, 2) == 2
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user