mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
...
This commit is contained in:
parent
e4c8c47c2e
commit
400b8fbef4
@ -42,7 +42,6 @@ typedef struct pk_VM {
|
||||
pk_NameDict modules;
|
||||
c11_vector /*T=pk_TypeInfo*/ types;
|
||||
|
||||
py_TValue StopIteration; // a special Exception class
|
||||
py_TValue builtins; // builtins module
|
||||
py_TValue main; // __main__ module
|
||||
|
||||
@ -53,6 +52,7 @@ typedef struct pk_VM {
|
||||
|
||||
py_TValue last_retval;
|
||||
bool has_error;
|
||||
bool is_stopiteration;
|
||||
|
||||
py_TValue reg[8]; // users' registers
|
||||
|
||||
@ -91,6 +91,7 @@ py_Type pk_VM__new_type(pk_VM* self,
|
||||
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
|
||||
|
||||
const char* pk_opname(Opcode op);
|
||||
py_TValue* pk_arrayview(py_Ref self, int* size);
|
||||
|
||||
// type registration
|
||||
void pk_object__register();
|
||||
@ -101,6 +102,8 @@ py_Type pk_bytes__register();
|
||||
py_Type pk_list__register();
|
||||
py_Type pk_function__register();
|
||||
py_Type pk_nativefunc__register();
|
||||
py_Type pk_range__register();
|
||||
py_Type pk_range_iterator__register();
|
||||
|
||||
py_TValue pk_builtins__register();
|
||||
|
||||
|
@ -244,13 +244,14 @@ void py_formatexc(char* out);
|
||||
#define TypeError(...) py_exception("TypeError", __VA_ARGS__)
|
||||
#define ValueError(...) py_exception("ValueError", __VA_ARGS__)
|
||||
#define IndexError(...) py_exception("IndexError", __VA_ARGS__)
|
||||
#define StopIteration() py_exception("StopIteration", "")
|
||||
#define NotImplementedError() py_exception("NotImplementedError", "")
|
||||
#define AttributeError(self, n) \
|
||||
py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n))
|
||||
#define UnboundLocalError(n) \
|
||||
py_exception("UnboundLocalError", "local variable '%n' referenced before assignment", (n))
|
||||
|
||||
bool StopIteration();
|
||||
|
||||
/************* Operators *************/
|
||||
/// Equivalent to `bool(val)`.
|
||||
/// Returns 1 if `val` is truthy, otherwise 0.
|
||||
@ -385,6 +386,7 @@ enum py_PredefinedTypes {
|
||||
tp_tuple, // N slots
|
||||
tp_slice, // 3 slots (start, stop, step)
|
||||
tp_range,
|
||||
tp_range_iterator,
|
||||
tp_module,
|
||||
tp_function,
|
||||
tp_nativefunc,
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||
static bool stack_unpack_sequence(pk_VM* self, uint16_t arg);
|
||||
|
||||
#define DISPATCH() \
|
||||
do { \
|
||||
@ -32,7 +33,7 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||
#define STACK_SHRINK(n) (self->stack.sp -= n)
|
||||
#define PUSH(v) \
|
||||
do { \
|
||||
*self->stack.sp = *v; \
|
||||
*self->stack.sp = *(v); \
|
||||
self->stack.sp++; \
|
||||
} while(0)
|
||||
#define POP() (--self->stack.sp)
|
||||
@ -693,6 +694,13 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
case OP_UNPACK_SEQUENCE: {
|
||||
if(!stack_unpack_sequence(self, byte.arg)) goto __ERROR;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
///////////
|
||||
case OP_RAISE_ASSERT: {
|
||||
if(byte.arg) {
|
||||
@ -756,3 +764,14 @@ bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop) {
|
||||
STACK_SHRINK(2);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool stack_unpack_sequence(pk_VM* self, uint16_t arg) {
|
||||
int length;
|
||||
py_TValue* p = pk_arrayview(TOP(), &length);
|
||||
if(!p) return TypeError("expected list or tuple to unpack, got '%t'", TOP()->type);
|
||||
if(length != arg) return ValueError("expected %d values to unpack, got %d", arg, length);
|
||||
POP();
|
||||
for(int i = 0; i < length; i++)
|
||||
PUSH(p + i);
|
||||
return true;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -62,7 +62,6 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
pk_NameDict__ctor(&self->modules);
|
||||
c11_vector__ctor(&self->types, sizeof(pk_TypeInfo));
|
||||
|
||||
self->StopIteration = PY_NIL;
|
||||
self->builtins = PY_NIL;
|
||||
self->main = PY_NIL;
|
||||
|
||||
@ -73,6 +72,7 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
|
||||
self->last_retval = PY_NIL;
|
||||
self->has_error = false;
|
||||
self->is_stopiteration = false;
|
||||
|
||||
self->__curr_class = PY_NIL;
|
||||
self->__dynamic_func_decl = NULL;
|
||||
@ -102,7 +102,8 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false));
|
||||
|
||||
validate(tp_slice, pk_VM__new_type(self, "slice", tp_object, NULL, false));
|
||||
validate(tp_range, pk_VM__new_type(self, "range", tp_object, NULL, false));
|
||||
validate(tp_range, pk_range__register());
|
||||
validate(tp_range_iterator, pk_range_iterator__register());
|
||||
validate(tp_module, pk_VM__new_type(self, "module", tp_object, NULL, false));
|
||||
|
||||
validate(tp_function, pk_function__register());
|
||||
@ -130,7 +131,6 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
validate(tp_stop_iteration, pk_VM__new_type(self, "StopIteration", tp_exception, NULL, false));
|
||||
#undef validate
|
||||
|
||||
self->StopIteration = *py_tpobject(tp_stop_iteration);
|
||||
self->builtins = pk_builtins__register();
|
||||
|
||||
/* Setup Public Builtin Types */
|
||||
|
@ -117,11 +117,8 @@ static bool _py_builtins__next(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int res = py_next(argv);
|
||||
if(res == -1) return false;
|
||||
if(res) {
|
||||
return true;
|
||||
} else {
|
||||
return StopIteration();
|
||||
}
|
||||
if(res) return true;
|
||||
return py_exception("StopIteration", "");
|
||||
}
|
||||
|
||||
py_TValue pk_builtins__register() {
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
static bool _py_object__new__(int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
py_Type cls = argv[0].type;
|
||||
py_Type cls = py_totype(py_arg(0));
|
||||
py_newobject(py_retval(), cls, 0, 0);
|
||||
return true;
|
||||
}
|
||||
@ -42,10 +42,24 @@ static bool _py_object__repr__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_type__repr__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
pk_sprintf(&buf, "<class '%t'>", py_totype(argv));
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk_object__register() {
|
||||
py_bindmagic(tp_object, __new__, _py_object__new__);
|
||||
py_bindmagic(tp_object, __hash__, _py_object__hash__);
|
||||
py_bindmagic(tp_object, __eq__, _py_object__eq__);
|
||||
py_bindmagic(tp_object, __ne__, _py_object__ne__);
|
||||
py_bindmagic(tp_object, __repr__, _py_object__repr__);
|
||||
|
||||
// type patch...
|
||||
py_bindmagic(tp_type, __repr__, _py_type__repr__);
|
||||
}
|
@ -67,15 +67,13 @@ bool py_iter(const py_Ref val) {
|
||||
}
|
||||
|
||||
int py_next(const py_Ref val) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
vm->is_stopiteration = false;
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __next__);
|
||||
if(!tmp) return TypeError("'%t' object is not an iterator", val->type);
|
||||
bool ok = py_call(tmp, 1, val);
|
||||
if(ok) {
|
||||
py_Ref retval = py_retval();
|
||||
bool is_end = retval->type == tp_type && py_totype(retval) == tp_stop_iteration;
|
||||
return !is_end;
|
||||
}
|
||||
return -1;
|
||||
if(ok) return true;
|
||||
return vm->is_stopiteration ? 0 : -1;
|
||||
}
|
||||
|
||||
int py_getattr(const py_Ref self, py_Name name, py_Ref out) { return -1; }
|
||||
|
99
src/public/py_range.c
Normal file
99
src/public/py_range.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
typedef struct Range {
|
||||
py_i64 start;
|
||||
py_i64 stop;
|
||||
py_i64 step;
|
||||
} Range;
|
||||
|
||||
static bool _py_range__new__(int argc, py_Ref argv) {
|
||||
Range* ud = py_newobject(py_retval(), tp_range, 0, sizeof(Range));
|
||||
switch(argc - 1) { // skip cls
|
||||
case 1: {
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
ud->start = 0;
|
||||
ud->stop = py_toint(py_arg(1));
|
||||
ud->step = 1;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
PY_CHECK_ARG_TYPE(2, tp_int);
|
||||
ud->start = py_toint(py_arg(1));
|
||||
ud->stop = py_toint(py_arg(2));
|
||||
ud->step = 1;
|
||||
break;
|
||||
case 3:
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
PY_CHECK_ARG_TYPE(2, tp_int);
|
||||
PY_CHECK_ARG_TYPE(3, tp_int);
|
||||
ud->start = py_toint(py_arg(1));
|
||||
ud->stop = py_toint(py_arg(2));
|
||||
ud->step = py_toint(py_arg(3));
|
||||
break;
|
||||
default: return TypeError("range() expected at most 3 arguments, got %d", argc - 1);
|
||||
}
|
||||
if(ud->step == 0) return ValueError("range() arg 3 must not be zero");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_range__iter__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
return py_tpcall(tp_range_iterator, 1, argv);
|
||||
}
|
||||
|
||||
py_Type pk_range__register() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Type type = pk_VM__new_type(vm, "range", tp_object, NULL, false);
|
||||
|
||||
py_bindmagic(type, __new__, _py_range__new__);
|
||||
py_bindmagic(type, __iter__, _py_range__iter__);
|
||||
return type;
|
||||
}
|
||||
|
||||
typedef struct RangeIterator {
|
||||
Range range;
|
||||
py_i64 current;
|
||||
} RangeIterator;
|
||||
|
||||
static bool _py_range_iterator__new__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
PY_CHECK_ARG_TYPE(1, tp_range);
|
||||
RangeIterator* ud = py_newobject(py_retval(), tp_range_iterator, 0, sizeof(RangeIterator));
|
||||
ud->range = *(Range*)py_touserdata(py_arg(1));
|
||||
ud->current = ud->range.start;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_range_iterator__iter__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
*py_retval() = *py_arg(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_range_iterator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
RangeIterator* ud = py_touserdata(py_arg(0));
|
||||
if(ud->range.step > 0) {
|
||||
if(ud->current >= ud->range.stop) return StopIteration();
|
||||
} else {
|
||||
if(ud->current <= ud->range.stop) return StopIteration();
|
||||
}
|
||||
py_newint(py_retval(), ud->current);
|
||||
ud->current += ud->range.step;
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_range_iterator__register() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Type type = pk_VM__new_type(vm, "range_iterator", tp_object, NULL, false);
|
||||
|
||||
py_bindmagic(type, __new__, _py_range_iterator__new__);
|
||||
py_bindmagic(type, __iter__, _py_range_iterator__iter__);
|
||||
py_bindmagic(type, __next__, _py_range_iterator__next__);
|
||||
return type;
|
||||
}
|
@ -521,10 +521,7 @@ static bool _py_str_iterator__next__(int argc, py_Ref argv) {
|
||||
int* ud = py_touserdata(&argv[0]);
|
||||
int size;
|
||||
const char* data = py_tostrn(py_getslot(argv, 0), &size);
|
||||
if(*ud == size) {
|
||||
*py_retval() = pk_current_vm->StopIteration;
|
||||
return true;
|
||||
}
|
||||
if(*ud == size) return StopIteration();
|
||||
int start = *ud;
|
||||
int len = c11__u8_header(data[*ud], false);
|
||||
*ud += len;
|
||||
|
@ -35,6 +35,18 @@ const char* pk_opname(Opcode op) {
|
||||
return OP_NAMES[op];
|
||||
}
|
||||
|
||||
py_TValue* pk_arrayview(py_Ref self, int* length) {
|
||||
if(self->type == tp_list) {
|
||||
*length = py_list__len(self);
|
||||
return py_list__getitem(self, 0);
|
||||
}
|
||||
if(self->type == tp_tuple) {
|
||||
*length = py_tuple__len(self);
|
||||
return py_tuple__getitem(self, 0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void disassemble(CodeObject* co) {
|
||||
c11_vector /*T=int*/ jumpTargets;
|
||||
c11_vector__ctor(&jumpTargets, sizeof(int));
|
||||
@ -305,3 +317,10 @@ bool py_callmagic(py_Name name, int argc, py_Ref argv) {
|
||||
if(!tmp) return AttributeError(argv, name);
|
||||
return py_call(tmp, argc, argv);
|
||||
}
|
||||
|
||||
bool StopIteration() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
assert(!vm->is_stopiteration); // flag is already set
|
||||
vm->is_stopiteration = true;
|
||||
return false;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user