mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
4 Commits
4b4351e3fa
...
79012a6b08
Author | SHA1 | Date | |
---|---|---|---|
|
79012a6b08 | ||
|
18fe69d579 | ||
|
5c959e7274 | ||
|
803e7f1791 |
@ -34,6 +34,7 @@ c11_vector c11_vector__copy(const c11_vector* self);
|
||||
void c11_vector__reserve(c11_vector* self, int capacity);
|
||||
void c11_vector__clear(c11_vector* self);
|
||||
void* c11_vector__emplace(c11_vector* self);
|
||||
bool c11_vector__contains(const c11_vector* self, void* elem);
|
||||
c11_array c11_vector__submit(c11_vector* self);
|
||||
|
||||
#define c11__getitem(T, self, index) (((T*)(self)->data)[index])
|
||||
|
@ -47,7 +47,7 @@ typedef struct Frame {
|
||||
} Frame;
|
||||
|
||||
Frame* Frame__new(const CodeObject* co,
|
||||
const py_TValue* module,
|
||||
PyObject* module,
|
||||
const py_TValue* function,
|
||||
py_TValue* p0,
|
||||
py_TValue* locals,
|
||||
|
@ -95,6 +95,8 @@ void pk_number__register();
|
||||
py_Type pk_str__register();
|
||||
py_Type pk_bytes__register();
|
||||
py_Type pk_list__register();
|
||||
py_Type pk_function__register();
|
||||
py_Type pk_nativefunc__register();
|
||||
|
||||
py_TValue pk_builtins__register();
|
||||
|
||||
|
@ -7,20 +7,20 @@
|
||||
#include "pocketpy/common/smallmap.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/namedict.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BC_NOARG 0
|
||||
#define BC_KEEPLINE -1
|
||||
#define BC_NOARG 0
|
||||
#define BC_KEEPLINE -1
|
||||
|
||||
typedef enum FuncType {
|
||||
FuncType_UNSET,
|
||||
FuncType_NORMAL,
|
||||
FuncType_SIMPLE,
|
||||
FuncType_EMPTY,
|
||||
FuncType_GENERATOR,
|
||||
} FuncType;
|
||||
|
||||
@ -39,9 +39,10 @@ typedef enum CodeBlockType {
|
||||
} CodeBlockType;
|
||||
|
||||
typedef enum Opcode {
|
||||
#define OPCODE(name) OP_##name,
|
||||
#include "pocketpy/xmacros/opcodes.h"
|
||||
#undef OPCODE
|
||||
|
||||
#define OPCODE(name) OP_##name,
|
||||
#include "pocketpy/xmacros/opcodes.h"
|
||||
#undef OPCODE
|
||||
} Opcode;
|
||||
|
||||
typedef struct Bytecode {
|
||||
@ -70,18 +71,18 @@ typedef struct CodeObject {
|
||||
pk_SourceData_ src;
|
||||
c11_string* name;
|
||||
|
||||
c11_vector/*T=Bytecode*/ codes;
|
||||
c11_vector/*T=CodeObjectByteCodeEx*/ codes_ex;
|
||||
c11_vector /*T=Bytecode*/ codes;
|
||||
c11_vector /*T=CodeObjectByteCodeEx*/ codes_ex;
|
||||
|
||||
c11_vector/*T=py_TValue*/ consts; // constants
|
||||
c11_vector/*T=py_Name*/ varnames; // local variables
|
||||
c11_vector /*T=py_TValue*/ consts; // constants
|
||||
c11_vector /*T=py_Name*/ varnames; // local variables
|
||||
int nlocals; // cached varnames.size()
|
||||
|
||||
c11_smallmap_n2i varnames_inv;
|
||||
c11_smallmap_n2i labels;
|
||||
|
||||
c11_vector/*T=CodeBlock*/ blocks;
|
||||
c11_vector/*T=FuncDecl_*/ func_decls;
|
||||
c11_vector /*T=CodeBlock*/ blocks;
|
||||
c11_vector /*T=FuncDecl_*/ func_decls;
|
||||
|
||||
int start_line;
|
||||
int end_line;
|
||||
@ -91,18 +92,18 @@ void CodeObject__ctor(CodeObject* self, pk_SourceData_ src, c11_sv name);
|
||||
void CodeObject__dtor(CodeObject* self);
|
||||
void CodeObject__gc_mark(const CodeObject* self);
|
||||
|
||||
typedef struct FuncDeclKwArg{
|
||||
int index; // index in co->varnames
|
||||
uint16_t key; // name of this argument
|
||||
typedef struct FuncDeclKwArg {
|
||||
int index; // index in co->varnames
|
||||
uint16_t key; // name of this argument
|
||||
py_TValue value; // default value
|
||||
} FuncDeclKwArg;
|
||||
|
||||
typedef struct FuncDecl {
|
||||
RefCounted rc;
|
||||
CodeObject code; // strong ref
|
||||
CodeObject code; // strong ref
|
||||
|
||||
c11_vector/*T=int*/ args; // indices in co->varnames
|
||||
c11_vector/*T=KwArg*/ kwargs; // indices in co->varnames
|
||||
c11_vector /*T=int*/ args; // indices in co->varnames
|
||||
c11_vector /*T=KwArg*/ kwargs; // indices in co->varnames
|
||||
|
||||
int starred_arg; // index in co->varnames, -1 if no *arg
|
||||
int starred_kwarg; // index in co->varnames, -1 if no **kwarg
|
||||
@ -121,6 +122,17 @@ void FuncDecl__dtor(FuncDecl* self);
|
||||
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value);
|
||||
void FuncDecl__gc_mark(const FuncDecl* self);
|
||||
|
||||
// runtime function
|
||||
typedef struct Function {
|
||||
FuncDecl_ decl;
|
||||
PyObject* module; // weak ref
|
||||
PyObject* clazz; // weak ref
|
||||
pk_NameDict* closure; // strong ref
|
||||
} Function;
|
||||
|
||||
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module);
|
||||
void Function__dtor(Function* self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -38,13 +38,7 @@ enum BindType {
|
||||
BindType_CLASSMETHOD,
|
||||
};
|
||||
|
||||
enum CompileMode {
|
||||
EXEC_MODE,
|
||||
EVAL_MODE,
|
||||
REPL_MODE,
|
||||
JSON_MODE,
|
||||
CELL_MODE
|
||||
};
|
||||
enum CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, JSON_MODE, CELL_MODE };
|
||||
|
||||
/************* Global VMs *************/
|
||||
void py_initialize();
|
||||
@ -294,7 +288,9 @@ bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv);
|
||||
bool py_callmagic(py_Name name, int argc, py_Ref argv);
|
||||
|
||||
bool py_str(py_Ref val);
|
||||
bool py_repr(py_Ref val);
|
||||
|
||||
#define py_repr(val) py_callmagic(__repr__, 1, val)
|
||||
#define py_len(val) py_callmagic(__len__, 1, val)
|
||||
|
||||
/// The return value of the most recent call.
|
||||
py_GlobalRef py_retval();
|
||||
|
@ -63,6 +63,14 @@ void* c11_vector__emplace(c11_vector* self){
|
||||
return p;
|
||||
}
|
||||
|
||||
bool c11_vector__contains(const c11_vector *self, void *elem){
|
||||
for(int i = 0; i < self->count; i++){
|
||||
void* p = (char*)self->data + self->elem_size * i;
|
||||
if(memcmp(p, elem, self->elem_size) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
c11_array c11_vector__submit(c11_vector* self){
|
||||
c11_array retval = {
|
||||
.data = self->data,
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include <ctype.h>
|
||||
@ -635,7 +636,6 @@ static void _load_simple_expr(Ctx* ctx, c11_sv expr, int line) {
|
||||
// name or name.name
|
||||
bool is_fastpath = false;
|
||||
if(is_identifier(expr)) {
|
||||
// ctx->emit_(OP_LOAD_NAME, py_Name(expr.sv()).index, line);
|
||||
Ctx__emit_(ctx, OP_LOAD_NAME, py_name2(expr), line);
|
||||
is_fastpath = true;
|
||||
} else {
|
||||
@ -1639,15 +1639,9 @@ static Error* pop_context(Compiler* self) {
|
||||
|
||||
if(is_simple) {
|
||||
func->type = FuncType_SIMPLE;
|
||||
|
||||
bool is_empty = false;
|
||||
if(func->code.codes.count == 1) {
|
||||
Bytecode bc = c11__getitem(Bytecode, &func->code.codes, 0);
|
||||
if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; }
|
||||
}
|
||||
if(is_empty) func->type = FuncType_EMPTY;
|
||||
} else
|
||||
} else {
|
||||
func->type = FuncType_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
assert(func->type != FuncType_UNSET);
|
||||
@ -2188,6 +2182,291 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FuncDecl_ push_f_context(Compiler* self, c11_sv name, int* out_index) {
|
||||
FuncDecl_ decl = FuncDecl__rcnew(self->src, name);
|
||||
decl->code.start_line = self->i == 0 ? 1 : prev()->line;
|
||||
decl->nested = name_scope(self) == NAME_LOCAL;
|
||||
// add_func_decl
|
||||
Ctx* top_ctx = ctx();
|
||||
c11_vector__push(FuncDecl_, &top_ctx->co->func_decls, decl);
|
||||
*out_index = top_ctx->co->func_decls.count - 1;
|
||||
// push new context
|
||||
top_ctx = c11_vector__emplace(&self->contexts);
|
||||
Ctx__ctor(top_ctx, &decl->code, decl, self->contexts.count);
|
||||
return decl;
|
||||
}
|
||||
|
||||
static Error* read_literal(Compiler* self, py_Ref out) {
|
||||
Error* err;
|
||||
advance();
|
||||
const TokenValue* value = &prev()->value;
|
||||
bool negated = false;
|
||||
switch(prev()->type) {
|
||||
case TK_SUB:
|
||||
consume(TK_NUM);
|
||||
value = &prev()->value;
|
||||
negated = true;
|
||||
case TK_NUM: {
|
||||
if(value->index == TokenValue_I64) {
|
||||
py_newint(out, negated ? -value->_i64 : value->_i64);
|
||||
} else if(value->index == TokenValue_F64) {
|
||||
py_newfloat(out, negated ? -value->_f64 : value->_f64);
|
||||
} else {
|
||||
return SyntaxError();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
case TK_STR: py_newstr(out, value->_str->data); return NULL;
|
||||
case TK_TRUE: py_newbool(out, true); return NULL;
|
||||
case TK_FALSE: py_newbool(out, false); return NULL;
|
||||
case TK_NONE: py_newnone(out); return NULL;
|
||||
case TK_DOTDOTDOT: py_newellipsis(out); return NULL;
|
||||
case TK_LPAREN: {
|
||||
py_TValue cpnts[4];
|
||||
int count = 0;
|
||||
while(true) {
|
||||
if(count == 4) return SyntaxError("default argument tuple exceeds 4 elements");
|
||||
check(read_literal(self, &cpnts[count]));
|
||||
count += 1;
|
||||
if(curr()->type == TK_RPAREN) break;
|
||||
consume(TK_COMMA);
|
||||
if(curr()->type == TK_RPAREN) break;
|
||||
}
|
||||
consume(TK_RPAREN);
|
||||
py_newtuple(out, count);
|
||||
for(int i = 0; i < count; i++) {
|
||||
py_tuple__setitem(out, i, &cpnts[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
default: *out = PY_NIL; return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static Error* _compile_f_args(Compiler* self, FuncDecl* decl, bool enable_type_hints) {
|
||||
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
||||
Error* err;
|
||||
do {
|
||||
if(state > 3) return SyntaxError();
|
||||
if(state == 3) return SyntaxError("**kwargs should be the last argument");
|
||||
match_newlines();
|
||||
if(match(TK_MUL)) {
|
||||
if(state < 1)
|
||||
state = 1;
|
||||
else
|
||||
return SyntaxError("*args should be placed before **kwargs");
|
||||
} else if(match(TK_POW)) {
|
||||
state = 3;
|
||||
}
|
||||
consume(TK_ID);
|
||||
py_Name name = py_name2(Token__sv(prev()));
|
||||
|
||||
// check duplicate argument name
|
||||
py_Name tmp_name;
|
||||
c11__foreach(int, &decl->args, j) {
|
||||
tmp_name = c11__getitem(py_Name, &decl->args, *j);
|
||||
if(tmp_name == name) return SyntaxError("duplicate argument name");
|
||||
}
|
||||
c11__foreach(FuncDeclKwArg, &decl->kwargs, kv) {
|
||||
tmp_name = c11__getitem(py_Name, &decl->code.varnames, kv->index);
|
||||
if(tmp_name == name) return SyntaxError("duplicate argument name");
|
||||
}
|
||||
if(decl->starred_arg != -1) {
|
||||
tmp_name = c11__getitem(py_Name, &decl->code.varnames, decl->starred_arg);
|
||||
if(tmp_name == name) return SyntaxError("duplicate argument name");
|
||||
}
|
||||
if(decl->starred_kwarg != -1) {
|
||||
tmp_name = c11__getitem(py_Name, &decl->code.varnames, decl->starred_kwarg);
|
||||
if(tmp_name == name) return SyntaxError("duplicate argument name");
|
||||
}
|
||||
|
||||
// eat type hints
|
||||
if(enable_type_hints && match(TK_COLON)) check(consume_type_hints(self));
|
||||
if(state == 0 && curr()->type == TK_ASSIGN) state = 2;
|
||||
int index = Ctx__add_varname(ctx(), name);
|
||||
switch(state) {
|
||||
case 0: c11_vector__push(int, &decl->args, index); break;
|
||||
case 1:
|
||||
decl->starred_arg = index;
|
||||
state += 1;
|
||||
break;
|
||||
case 2: {
|
||||
consume(TK_ASSIGN);
|
||||
py_TValue value;
|
||||
check(read_literal(self, &value));
|
||||
if(py_isnil(&value)) return SyntaxError("default argument must be a literal");
|
||||
FuncDecl__add_kwarg(decl, index, name, &value);
|
||||
} break;
|
||||
case 3:
|
||||
decl->starred_kwarg = index;
|
||||
state += 1;
|
||||
break;
|
||||
}
|
||||
} while(match(TK_COMMA));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Error* compile_function(Compiler* self, int decorators) {
|
||||
Error* err;
|
||||
consume(TK_ID);
|
||||
c11_sv decl_name = Token__sv(prev());
|
||||
int decl_index;
|
||||
FuncDecl_ decl = push_f_context(self, decl_name, &decl_index);
|
||||
consume(TK_LPAREN);
|
||||
if(!match(TK_RPAREN)) {
|
||||
check(_compile_f_args(self, decl, true));
|
||||
consume(TK_RPAREN);
|
||||
}
|
||||
if(match(TK_ARROW)) check(consume_type_hints(self));
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(pop_context(self));
|
||||
|
||||
if(decl->code.codes.count >= 2) {
|
||||
Bytecode* codes = (Bytecode*)decl->code.codes.data;
|
||||
|
||||
if(codes[0].op == OP_LOAD_CONST && codes[1].op == OP_POP_TOP) {
|
||||
// handle optional docstring
|
||||
py_TValue* consts = decl->code.consts.data;
|
||||
py_TValue* c = &consts[codes[0].arg];
|
||||
if(py_isstr(c)) {
|
||||
decl->docstring = py_tostr(c);
|
||||
codes[0].op = OP_NO_OP;
|
||||
codes[1].op = OP_NO_OP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ctx__emit_(ctx(), OP_LOAD_FUNCTION, decl_index, prev()->line);
|
||||
Ctx__s_emit_decorators(ctx(), decorators);
|
||||
|
||||
if(ctx()->is_compiling_class) {
|
||||
Ctx__emit_(ctx(), OP_STORE_CLASS_ATTR, py_name2(decl_name), prev()->line);
|
||||
} else {
|
||||
NameExpr* e = NameExpr__new(prev()->line, py_name2(decl_name), name_scope(self));
|
||||
vtemit_store((Expr*)e, ctx());
|
||||
vtdelete((Expr*)e);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Error* compile_decorated(Compiler* self) {
|
||||
Error* err;
|
||||
int count = 0;
|
||||
do {
|
||||
check(EXPR(self));
|
||||
count += 1;
|
||||
if(!match_newlines()) return SyntaxError("expected a newline after '@'");
|
||||
} while(match(TK_DECORATOR));
|
||||
|
||||
if(match(TK_CLASS)) {
|
||||
// check(compile_class(count));
|
||||
} else {
|
||||
consume(TK_DEF);
|
||||
check(compile_function(self, count));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// import a [as b]
|
||||
// import a [as b], c [as d]
|
||||
static Error* compile_normal_import(Compiler* self) {
|
||||
do {
|
||||
consume(TK_ID);
|
||||
c11_sv name = Token__sv(prev());
|
||||
int index = Ctx__add_const_string(ctx(), name);
|
||||
Ctx__emit_(ctx(), OP_IMPORT_PATH, index, prev()->line);
|
||||
if(match(TK_AS)) {
|
||||
consume(TK_ID);
|
||||
name = Token__sv(prev());
|
||||
}
|
||||
Ctx__emit_store_name(ctx(), name_scope(self), py_name2(name), prev()->line);
|
||||
} while(match(TK_COMMA));
|
||||
consume_end_stmt();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// from a import b [as c], d [as e]
|
||||
// from a.b import c [as d]
|
||||
// from . import a [as b]
|
||||
// from .a import b [as c]
|
||||
// from ..a import b [as c]
|
||||
// from .a.b import c [as d]
|
||||
// from xxx import *
|
||||
static Error* compile_from_import(c11_sbuf* buf, Compiler* self) {
|
||||
int dots = 0;
|
||||
|
||||
while(true) {
|
||||
switch(curr()->type) {
|
||||
case TK_DOT: dots += 1; break;
|
||||
case TK_DOTDOT: dots += 2; break;
|
||||
case TK_DOTDOTDOT: dots += 3; break;
|
||||
default: goto __EAT_DOTS_END;
|
||||
}
|
||||
advance();
|
||||
}
|
||||
__EAT_DOTS_END:
|
||||
for(int i = 0; i < dots; i++) {
|
||||
c11_sbuf__write_char(buf, '.');
|
||||
}
|
||||
|
||||
if(dots > 0) {
|
||||
// @id is optional if dots > 0
|
||||
if(match(TK_ID)) {
|
||||
c11_sbuf__write_sv(buf, Token__sv(prev()));
|
||||
while(match(TK_DOT)) {
|
||||
consume(TK_ID);
|
||||
c11_sbuf__write_char(buf, '.');
|
||||
c11_sbuf__write_sv(buf, Token__sv(prev()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// @id is required if dots == 0
|
||||
consume(TK_ID);
|
||||
c11_sbuf__write_sv(buf, Token__sv(prev()));
|
||||
while(match(TK_DOT)) {
|
||||
consume(TK_ID);
|
||||
c11_sbuf__write_char(buf, '.');
|
||||
c11_sbuf__write_sv(buf, Token__sv(prev()));
|
||||
}
|
||||
}
|
||||
|
||||
c11_string* path = c11_sbuf__submit(buf);
|
||||
Ctx__emit_(ctx(),
|
||||
OP_IMPORT_PATH,
|
||||
Ctx__add_const_string(ctx(), c11_string__sv(path)),
|
||||
prev()->line);
|
||||
consume(TK_IMPORT);
|
||||
|
||||
if(match(TK_MUL)) {
|
||||
if(name_scope(self) != NAME_GLOBAL)
|
||||
return SyntaxError("from <module> import * can only be used in global scope");
|
||||
// pop the module and import __all__
|
||||
Ctx__emit_(ctx(), OP_POP_IMPORT_STAR, BC_NOARG, prev()->line);
|
||||
consume_end_stmt();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||
consume(TK_ID);
|
||||
c11_sv name = Token__sv(prev());
|
||||
Ctx__emit_(ctx(), OP_LOAD_ATTR, py_name2(name), prev()->line);
|
||||
if(match(TK_AS)) {
|
||||
consume(TK_ID);
|
||||
name = Token__sv(prev());
|
||||
}
|
||||
Ctx__emit_store_name(ctx(), name_scope(self), py_name2(name), prev()->line);
|
||||
} while(match(TK_COMMA));
|
||||
Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||
consume_end_stmt();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Error* compile_try_except(Compiler* self) {
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Error* compile_stmt(Compiler* self) {
|
||||
Error* err;
|
||||
if(match(TK_CLASS)) {
|
||||
@ -2242,11 +2521,18 @@ static Error* compile_stmt(Compiler* self) {
|
||||
case TK_IF: check(compile_if_stmt(self)); break;
|
||||
case TK_WHILE: check(compile_while_loop(self)); break;
|
||||
case TK_FOR: check(compile_for_loop(self)); break;
|
||||
// case TK_IMPORT: check(compile_normal_import()); break;
|
||||
// case TK_FROM: check(compile_from_import()); break;
|
||||
// case TK_DEF: check(compile_function()); break;
|
||||
// case TK_DECORATOR: check(compile_decorated()); break;
|
||||
// case TK_TRY: check(compile_try_except()); break;
|
||||
case TK_IMPORT: check(compile_normal_import(self)); break;
|
||||
case TK_FROM: {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
err = compile_from_import(&buf, self);
|
||||
c11_sbuf__dtor(&buf);
|
||||
if(err) return err;
|
||||
break;
|
||||
}
|
||||
case TK_DEF: check(compile_function(self, 0)); break;
|
||||
case TK_DECORATOR: check(compile_decorated(self)); break;
|
||||
case TK_TRY: check(compile_try_except(self)); break;
|
||||
case TK_PASS: consume_end_stmt(); break;
|
||||
/*************************************************/
|
||||
case TK_ASSERT: {
|
||||
|
@ -51,10 +51,7 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||
pk_FrameResult res = pk_VM__vectorcall(self, (argc), (kwargc), true); \
|
||||
switch(res) { \
|
||||
case RES_RETURN: PUSH(&self->last_retval); break; \
|
||||
case RES_CALL: \
|
||||
frame = self->top_frame; \
|
||||
PUSH(&self->last_retval); \
|
||||
goto __NEXT_FRAME; \
|
||||
case RES_CALL: frame = self->top_frame; goto __NEXT_FRAME; \
|
||||
case RES_ERROR: goto __ERROR; \
|
||||
default: c11__unreachedable(); \
|
||||
} \
|
||||
@ -164,20 +161,17 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
/*****************************************/
|
||||
case OP_LOAD_ELLIPSIS: py_newellipsis(SP()++); DISPATCH();
|
||||
case OP_LOAD_FUNCTION: {
|
||||
// FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
|
||||
// py_TValue obj;
|
||||
// if(decl->nested) {
|
||||
// NameDict* captured = frame->_locals.to_namedict();
|
||||
// obj =
|
||||
// new_object<Function>(tp_function, decl, frame->_module, nullptr,
|
||||
// captured);
|
||||
// uint16_t name = py_Name__map2(py_Str__sv(&decl->code->name));
|
||||
// captured->set(name, obj);
|
||||
// } else {
|
||||
// obj = new_object<Function>(tp_function, decl, frame->_module, nullptr,
|
||||
// nullptr);
|
||||
// }
|
||||
// PUSH(obj);DISPATCH();
|
||||
FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
|
||||
Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
|
||||
Function__ctor(ud, decl, frame->module);
|
||||
if(decl->nested) {
|
||||
ud->closure = FastLocals__to_namedict(frame->locals, frame->locals_co);
|
||||
py_Name name = py_name2(c11_string__sv(decl->code.name));
|
||||
// capture itself to allow recursion
|
||||
pk_NameDict__set(ud->closure, name, *SP());
|
||||
}
|
||||
SP()++;
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_LOAD_NULL:
|
||||
py_newnil(SP()++);
|
||||
@ -699,6 +693,18 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
*TOP() = self->last_retval;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
///////////
|
||||
case OP_RAISE_ASSERT: {
|
||||
if(byte.arg) {
|
||||
if(!py_str(TOP())) goto __ERROR;
|
||||
POP();
|
||||
py_exception("AssertionError", "%s", py_tostr(py_retval()));
|
||||
} else {
|
||||
py_exception("AssertionError", "");
|
||||
}
|
||||
goto __ERROR;
|
||||
}
|
||||
default: c11__unreachedable();
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,9 @@ void ValueStack__ctor(ValueStack* self) {
|
||||
self->end = self->begin + PK_VM_STACK_SIZE;
|
||||
}
|
||||
|
||||
void ValueStack__clear(ValueStack* self) {
|
||||
self->sp = self->begin;
|
||||
}
|
||||
void ValueStack__clear(ValueStack* self) { self->sp = self->begin; }
|
||||
|
||||
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name){
|
||||
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name) {
|
||||
int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1);
|
||||
if(index == -1) return NULL;
|
||||
return &locals[index];
|
||||
@ -20,14 +18,12 @@ pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) {
|
||||
pk_NameDict* dict = pk_NameDict__new();
|
||||
c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
|
||||
py_TValue value = locals[entry->value];
|
||||
if(!py_isnil(&value)){
|
||||
pk_NameDict__set(dict, entry->key, value);
|
||||
}
|
||||
if(!py_isnil(&value)) { pk_NameDict__set(dict, entry->key, value); }
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset){
|
||||
UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset) {
|
||||
UnwindTarget* self = malloc(sizeof(UnwindTarget));
|
||||
self->next = next;
|
||||
self->iblock = iblock;
|
||||
@ -35,17 +31,20 @@ UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset){
|
||||
return self;
|
||||
}
|
||||
|
||||
void UnwindTarget__delete(UnwindTarget* self){
|
||||
free(self);
|
||||
}
|
||||
void UnwindTarget__delete(UnwindTarget* self) { free(self); }
|
||||
|
||||
Frame* Frame__new(const CodeObject* co, const py_TValue* module, const py_TValue* function, py_TValue* p0, py_TValue* locals, const CodeObject* locals_co){
|
||||
Frame* Frame__new(const CodeObject* co,
|
||||
PyObject* module,
|
||||
const py_TValue* function,
|
||||
py_TValue* p0,
|
||||
py_TValue* locals,
|
||||
const CodeObject* locals_co) {
|
||||
static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)");
|
||||
Frame* self = PoolFrame_alloc();
|
||||
self->f_back = NULL;
|
||||
self->ip = (Bytecode*)co->codes.data - 1;
|
||||
self->co = co;
|
||||
self->module = module->_obj;
|
||||
self->module = module;
|
||||
self->function = function ? function->_obj : NULL;
|
||||
self->p0 = p0;
|
||||
self->locals = locals;
|
||||
@ -54,7 +53,7 @@ Frame* Frame__new(const CodeObject* co, const py_TValue* module, const py_TValue
|
||||
return self;
|
||||
}
|
||||
|
||||
void Frame__delete(Frame* self){
|
||||
void Frame__delete(Frame* self) {
|
||||
while(self->uw_list) {
|
||||
UnwindTarget* p = self->uw_list;
|
||||
self->uw_list = p->next;
|
||||
@ -63,7 +62,7 @@ void Frame__delete(Frame* self){
|
||||
PoolFrame_dealloc(self);
|
||||
}
|
||||
|
||||
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s){
|
||||
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) {
|
||||
// try to find a parent try block
|
||||
int iblock = Frame__iblock(self);
|
||||
while(iblock >= 0) {
|
||||
@ -74,15 +73,16 @@ int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s){
|
||||
if(iblock < 0) return -1;
|
||||
py_TValue obj = *--_s->sp; // pop exception object
|
||||
UnwindTarget* uw = Frame__find_unwind_target(self, iblock);
|
||||
_s->sp = (self->locals + uw->offset); // unwind the stack
|
||||
*(_s->sp++) = obj; // push it back
|
||||
_s->sp = (self->locals + uw->offset); // unwind the stack
|
||||
*(_s->sp++) = obj; // push it back
|
||||
return c11__at(CodeBlock, &self->co->blocks, iblock)->end;
|
||||
}
|
||||
|
||||
void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target){
|
||||
void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target) {
|
||||
int iblock = Frame__iblock(self);
|
||||
if(target >= self->co->codes.count) {
|
||||
while(iblock >= 0) iblock = Frame__exit_block(self, _s, iblock);
|
||||
while(iblock >= 0)
|
||||
iblock = Frame__exit_block(self, _s, iblock);
|
||||
} else {
|
||||
// BUG (solved)
|
||||
// for i in range(4):
|
||||
@ -96,14 +96,14 @@ void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target){
|
||||
}
|
||||
}
|
||||
|
||||
int Frame__prepare_loop_break(Frame* self, ValueStack* _s){
|
||||
int Frame__prepare_loop_break(Frame* self, ValueStack* _s) {
|
||||
int iblock = Frame__iblock(self);
|
||||
int target = c11__getitem(CodeBlock, &self->co->blocks, iblock).end;
|
||||
Frame__prepare_jump_break(self, _s, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
int Frame__exit_block(Frame* self, ValueStack* _s, int iblock){
|
||||
int Frame__exit_block(Frame* self, ValueStack* _s, int iblock) {
|
||||
CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, iblock);
|
||||
if(block->type == CodeBlockType_FOR_LOOP) {
|
||||
_s->sp--; // pop iterator
|
||||
@ -113,7 +113,7 @@ int Frame__exit_block(Frame* self, ValueStack* _s, int iblock){
|
||||
return block->parent;
|
||||
}
|
||||
|
||||
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock){
|
||||
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock) {
|
||||
UnwindTarget* uw;
|
||||
for(uw = self->uw_list; uw; uw = uw->next) {
|
||||
if(uw->iblock == iblock) return uw;
|
||||
@ -132,7 +132,7 @@ void Frame__set_unwind_target(Frame* self, py_TValue* sp) {
|
||||
}
|
||||
}
|
||||
|
||||
py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name){
|
||||
py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name) {
|
||||
// if(self->function == NULL) return NULL;
|
||||
// pkpy::Function* fn = PyObject__as(pkpy::Function, self->function);
|
||||
// if(fn->_closure == nullptr) return nullptr;
|
||||
|
@ -56,8 +56,6 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self,
|
||||
|
||||
void pk_TypeInfo__dtor(pk_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); }
|
||||
|
||||
|
||||
|
||||
void pk_VM__ctor(pk_VM* self) {
|
||||
self->top_frame = NULL;
|
||||
|
||||
@ -106,8 +104,8 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
validate(tp_range, pk_VM__new_type(self, "range", tp_object, NULL, false));
|
||||
validate(tp_module, pk_VM__new_type(self, "module", tp_object, NULL, false));
|
||||
|
||||
validate(tp_function, pk_VM__new_type(self, "function", tp_object, NULL, false));
|
||||
validate(tp_nativefunc, pk_VM__new_type(self, "nativefunc", tp_object, NULL, false));
|
||||
validate(tp_function, pk_function__register());
|
||||
validate(tp_nativefunc, pk_nativefunc__register());
|
||||
validate(tp_bound_method, pk_VM__new_type(self, "bound_method", tp_object, NULL, false));
|
||||
|
||||
validate(tp_super, pk_VM__new_type(self, "super", tp_object, NULL, false));
|
||||
@ -220,74 +218,64 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
|
||||
// [unbound, self, args..., kwargs...]
|
||||
}
|
||||
|
||||
// PyVar* _base = args.begin();
|
||||
py_Ref argv = py_isnil(p0 + 1) ? p0 + 2 : p0 + 1;
|
||||
int argc2 = argv - p0;
|
||||
|
||||
#if 0
|
||||
if(callable_t == tp_function) {
|
||||
if(p0->type == tp_function) {
|
||||
/*****************_py_call*****************/
|
||||
// check stack overflow
|
||||
if(self->stack.sp > self->stack.end){
|
||||
StackOverflowError();
|
||||
if(self->stack.sp > self->stack.end) {
|
||||
py_exception("StackOverflowError", "");
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
const Function& fn = PK_OBJ_GET(Function, callable);
|
||||
const CodeObject* co = fn.decl->code;
|
||||
Function* fn = py_touserdata(p0);
|
||||
const CodeObject* co = &fn->decl->code;
|
||||
|
||||
switch(fn.decl->type) {
|
||||
switch(fn->decl->type) {
|
||||
case FuncType_NORMAL:
|
||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||
// copy buffer back to stack
|
||||
s_data.reset(_base + co->nlocals);
|
||||
for(int j = 0; j < co->nlocals; j++)
|
||||
_base[j] = __vectorcall_buffer[j];
|
||||
assert(false);
|
||||
// __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||
// // copy buffer back to stack
|
||||
// self->stack.sp = argv + co->nlocals;
|
||||
// for(int j = 0; j < co->nlocals; j++)
|
||||
// argv[j] = self->__vectorcall_buffer[j];
|
||||
break;
|
||||
case FuncType_SIMPLE:
|
||||
if(args.size() != fn.decl->args.count) {
|
||||
TypeError(pk_format("{} takes {} positional arguments but {} were given",
|
||||
&co->name,
|
||||
fn.decl->args.count,
|
||||
args.size()));
|
||||
if(argc2 != fn->decl->args.count) {
|
||||
const char* fmt = "%s() takes %d positional arguments but %d were given";
|
||||
TypeError(fmt, co->name, fn->decl->args.count, argc2);
|
||||
return RES_ERROR;
|
||||
}
|
||||
if(!kwargs.empty()) {
|
||||
TypeError(pk_format("{} takes no keyword arguments", &co->name));
|
||||
if(kwargc) {
|
||||
TypeError("%s() takes no keyword arguments", co->name->data);
|
||||
return RES_ERROR;
|
||||
}
|
||||
// [callable, <self>, args..., local_vars...]
|
||||
// ^p0 ^p1 ^_sp
|
||||
s_data.reset(_base + co->nlocals);
|
||||
self->stack.sp = argv + co->nlocals;
|
||||
// initialize local variables to PY_NIL
|
||||
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
|
||||
memset(p1, 0, (char*)self->stack.sp - (char*)p1);
|
||||
break;
|
||||
case FuncType_EMPTY:
|
||||
if(args.size() != fn.decl->args.count) {
|
||||
TypeError(pk_format("{} takes {} positional arguments but {} were given",
|
||||
&co->name,
|
||||
fn.decl->args.count,
|
||||
args.size()));
|
||||
}
|
||||
if(!kwargs.empty()) {
|
||||
TypeError(pk_format("{} takes no keyword arguments", &co->name));
|
||||
}
|
||||
s_data.reset(p0);
|
||||
return None;
|
||||
case FuncType_GENERATOR:
|
||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||
s_data.reset(p0);
|
||||
callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
|
||||
return __py_generator(
|
||||
callstack.popx(),
|
||||
ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals));
|
||||
default: c11__unreachedable()
|
||||
assert(false);
|
||||
break;
|
||||
// __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||
// s_data.reset(p0);
|
||||
// callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
|
||||
// return __py_generator(
|
||||
// callstack.popx(),
|
||||
// ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals));
|
||||
default: c11__unreachedable();
|
||||
};
|
||||
|
||||
// simple or normal
|
||||
callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
|
||||
if(op_call) return pkpy_OP_CALL;
|
||||
return __run_top_frame();
|
||||
Frame* frame = Frame__new(co, fn->module, p0, p0, argv, co);
|
||||
pk_VM__push_frame(self, frame);
|
||||
if(opcall) return RES_CALL;
|
||||
return pk_VM__run_top_frame(self);
|
||||
/*****************_py_call*****************/
|
||||
}
|
||||
#endif
|
||||
|
||||
if(p0->type == tp_nativefunc) {
|
||||
// const auto& f = PK_OBJ_GET(NativeFunc, callable);
|
||||
|
@ -91,4 +91,17 @@ void CodeObject__dtor(CodeObject* self) {
|
||||
PK_DECREF(decl);
|
||||
}
|
||||
c11_vector__dtor(&self->func_decls);
|
||||
}
|
||||
|
||||
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module) {
|
||||
PK_INCREF(decl);
|
||||
self->decl = decl;
|
||||
self->module = module;
|
||||
self->clazz = NULL;
|
||||
self->closure = NULL;
|
||||
}
|
||||
|
||||
void Function__dtor(Function* self) {
|
||||
PK_DECREF(self->decl);
|
||||
if(self->closure) pk_NameDict__delete(self->closure);
|
||||
}
|
@ -53,15 +53,15 @@ py_Ref py_newmodule(const char* name, const char* package) {
|
||||
|
||||
//////////////////////////
|
||||
|
||||
static bool _py_builtins__repr(int argc, py_Ref argv){
|
||||
static bool _py_builtins__repr(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
return py_repr(argv);
|
||||
}
|
||||
|
||||
static bool _py_builtins__exit(int argc, py_Ref argv){
|
||||
static bool _py_builtins__exit(int argc, py_Ref argv) {
|
||||
int code = 0;
|
||||
if(argc > 1) return TypeError("exit() takes at most 1 argument");
|
||||
if(argc == 1){
|
||||
if(argc == 1) {
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
code = py_toint(argv);
|
||||
}
|
||||
@ -70,9 +70,36 @@ static bool _py_builtins__exit(int argc, py_Ref argv){
|
||||
return false;
|
||||
}
|
||||
|
||||
py_TValue pk_builtins__register(){
|
||||
static bool _py_builtins__len(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
return py_len(argv);
|
||||
}
|
||||
|
||||
py_TValue pk_builtins__register() {
|
||||
py_Ref builtins = py_newmodule("builtins", NULL);
|
||||
py_bindnativefunc(builtins, "repr", _py_builtins__repr);
|
||||
py_bindnativefunc(builtins, "exit", _py_builtins__exit);
|
||||
py_bindnativefunc(builtins, "len", _py_builtins__len);
|
||||
return *builtins;
|
||||
}
|
||||
|
||||
py_Type pk_function__register() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Type type = pk_VM__new_type(vm, "function", tp_object, NULL, false);
|
||||
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &vm->types, type);
|
||||
ti->dtor = (void (*)(void*))Function__dtor;
|
||||
return type;
|
||||
}
|
||||
|
||||
static bool _py_nativefunc__repr(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_newstr(py_retval(), "<nativefunc object>");
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_nativefunc__register() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Type type = pk_VM__new_type(vm, "nativefunc", tp_object, NULL, false);
|
||||
py_bindmagic(type, __repr__, _py_nativefunc__repr);
|
||||
return type;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include <math.h>
|
||||
@ -197,9 +198,12 @@ static bool _py_int__repr__(int argc, py_Ref argv) {
|
||||
static bool _py_float__repr__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_f64 val = py_tofloat(&argv[0]);
|
||||
char buf[32];
|
||||
int size = snprintf(buf, sizeof(buf), "%f", val);
|
||||
py_newstrn(py_retval(), buf, size);
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
c11_sbuf__write_f64(&buf, val, -1);
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -341,11 +345,18 @@ static bool _py_float__new__(int argc, py_Ref argv) {
|
||||
|
||||
// tp_bool
|
||||
static bool _py_bool__new__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int res = py_bool(argv);
|
||||
if(res == -1) return false;
|
||||
py_newbool(py_retval(), res);
|
||||
return true;
|
||||
assert(argc > 0);
|
||||
if(argc == 1){
|
||||
py_newbool(py_retval(), false);
|
||||
return true;
|
||||
}
|
||||
if(argc == 2){
|
||||
int res = py_bool(py_arg(1));
|
||||
if(res == -1) return false;
|
||||
py_newbool(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
return TypeError("bool() takes at most 1 argument");
|
||||
}
|
||||
|
||||
static bool _py_bool__hash__(int argc, py_Ref argv) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
static bool _py_object__new__(int argc, py_Ref argv) {
|
||||
@ -29,9 +30,22 @@ static bool _py_object__ne__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_object__repr__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
assert(argv->is_ptr);
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
pk_sprintf(&buf, "<%t object at %p>", argv->type, argv->_obj);
|
||||
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__);
|
||||
}
|
@ -145,8 +145,15 @@ static bool _py_str__str__(int argc, py_Ref argv) {
|
||||
|
||||
static bool _py_str__repr__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
assert(false);
|
||||
return false;
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
int size;
|
||||
const char* data = py_tostrn(&argv[0], &size);
|
||||
c11_sbuf__write_quoted(&buf, (c11_sv){data, size}, '\'');
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__iter__(int argc, py_Ref argv) {
|
||||
@ -294,5 +301,3 @@ bool py_str(py_Ref val) {
|
||||
if(!tmp) return py_repr(val);
|
||||
return py_call(tmp, 1, val);
|
||||
}
|
||||
|
||||
bool py_repr(py_Ref val) { return py_callmagic(__repr__, 1, val); }
|
@ -170,7 +170,7 @@ static bool
|
||||
|
||||
// disassemble(&co);
|
||||
|
||||
Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co);
|
||||
Frame* frame = Frame__new(&co, vm->main._obj, NULL, vm->stack.sp, vm->stack.sp, &co);
|
||||
pk_VM__push_frame(vm, frame);
|
||||
pk_FrameResult res = pk_VM__run_top_frame(vm);
|
||||
CodeObject__dtor(&co);
|
||||
|
32
src2/main.c
32
src2/main.c
@ -27,32 +27,42 @@ int main(int argc, char** argv) {
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
if(argc > 2){
|
||||
if(argc > 2) {
|
||||
printf("Usage: pocketpy [filename]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
py_initialize();
|
||||
|
||||
if(argc == 1){
|
||||
if(argc == 1) {
|
||||
printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
|
||||
printf("[%d bit] on %s" "\n", (int)(sizeof(void*) * 8), PY_SYS_PLATFORM_STRING);
|
||||
printf("https://github.com/pocketpy/pocketpy" "\n");
|
||||
printf("Type \"exit()\" to exit." "\n");
|
||||
printf(
|
||||
"[%d bit] on %s"
|
||||
"\n",
|
||||
(int)(sizeof(void*) * 8),
|
||||
PY_SYS_PLATFORM_STRING);
|
||||
printf(
|
||||
"https://github.com/pocketpy/pocketpy"
|
||||
"\n");
|
||||
printf(
|
||||
"Type \"exit()\" to exit."
|
||||
"\n");
|
||||
|
||||
while(true){
|
||||
while(true) {
|
||||
int size = py_replinput(buf);
|
||||
assert(size < sizeof(buf));
|
||||
if(size >= 0){
|
||||
if(size >= 0) {
|
||||
if(!py_exec2(buf, "<stdin>", REPL_MODE)) py_printexc();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
char* source = read_file(argv[1]);
|
||||
if(!py_exec(source)) py_printexc();
|
||||
free(source);
|
||||
if(source) {
|
||||
if(!py_exec(source)) py_printexc();
|
||||
free(source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
py_finalize();
|
||||
return 0;
|
||||
}
|
||||
|
105
tests/00_tmp.py
105
tests/00_tmp.py
@ -1,103 +1,4 @@
|
||||
# test int literals
|
||||
assert 0xffff == 65535
|
||||
assert 0xAAFFFF == 11206655
|
||||
assert 0x7fffffff == 2147483647
|
||||
assert -0xffff == -65535
|
||||
assert -0xAAFFFF == -11206655
|
||||
assert -0x7fffffff == -2147483647
|
||||
# test 64-bit
|
||||
assert 2**60-1 + 546 - 0xfffffffffffff == 1148417904979477026
|
||||
def f(a, b):
|
||||
return a+b
|
||||
|
||||
# test oct literals
|
||||
assert 0o1234 == 668
|
||||
assert 0o17777777777 == 2147483647
|
||||
assert -0o1234 == -668
|
||||
assert -0o17777777777 == -2147483647
|
||||
|
||||
# test binary literals
|
||||
assert 0b10010 == 18
|
||||
assert -0b10010 == -18
|
||||
assert 0b11111111111111111111111111111111 == 4294967295
|
||||
assert -0b11111 == -31
|
||||
|
||||
# test == != >= <= < >
|
||||
assert -1 == -1
|
||||
assert -1 != 1
|
||||
assert -1 >= -1
|
||||
assert -1 <= -1
|
||||
assert -1 < 1
|
||||
assert -1 > -2
|
||||
|
||||
# test + - * % ** //
|
||||
assert -1 + 1 == 0
|
||||
assert -1 - 1 == -2
|
||||
assert 4 * -1 == -4
|
||||
assert 5 % 2 == 1
|
||||
assert 2 ** 3 == 8
|
||||
assert 4 // 2 == 2
|
||||
assert 5 // 2 == 2
|
||||
|
||||
# test += -= *= //=
|
||||
x = 3
|
||||
x += 1
|
||||
assert x == 4
|
||||
x -= 1
|
||||
assert x == 3
|
||||
x *= 2
|
||||
assert x == 6
|
||||
x //= 2
|
||||
assert x == 3
|
||||
|
||||
# test bit_length
|
||||
assert (1).bit_length() == 1
|
||||
assert (2).bit_length() == 2
|
||||
assert (3).bit_length() == 2
|
||||
|
||||
assert (-1).bit_length() == 1
|
||||
assert (-2).bit_length() == 2
|
||||
assert (-3).bit_length() == 2
|
||||
|
||||
assert (123123123123123).bit_length() == 47
|
||||
assert (-3123123123).bit_length() == 32
|
||||
|
||||
# test int()
|
||||
assert int() == 0
|
||||
assert int(True) == 1
|
||||
assert int(False) == 0
|
||||
|
||||
assert int(1) == 1
|
||||
assert int(1.0) == 1
|
||||
assert int(1.1) == 1
|
||||
assert int(1.9) == 1
|
||||
assert int(-1.9) == -1
|
||||
assert int(1.5) == 1
|
||||
assert int(-1.5) == -1
|
||||
assert int("123") == 123
|
||||
|
||||
assert int("0x123", 16) == 291
|
||||
assert int("0o123", 8) == 83
|
||||
assert int("-0x123", 16) == -291
|
||||
assert int("-0o123", 8) == -83
|
||||
assert int("-123") == -123
|
||||
assert int("+123") == 123
|
||||
|
||||
# test >> << & | ^
|
||||
assert 12 >> 1 == 6
|
||||
assert 12 << 1 == 24
|
||||
assert 12 & 1 == 0
|
||||
assert 12 | 1 == 13
|
||||
assert 12 ^ 1 == 13
|
||||
|
||||
# test high precision int pow
|
||||
assert 7**21 == 558545864083284007
|
||||
assert 2**60 == 1152921504606846976
|
||||
assert -2**60 == -1152921504606846976
|
||||
assert 4**13 == 67108864
|
||||
assert (-4)**13 == -67108864
|
||||
|
||||
assert ~3 == -4
|
||||
assert ~-3 == 2
|
||||
assert ~0 == -1
|
||||
|
||||
# tmp code
|
||||
assert [1, 2].__len__() == 2
|
||||
assert f(1, 2) == 3
|
||||
|
@ -1,7 +1,3 @@
|
||||
def eq(a, b):
|
||||
dt = a - b
|
||||
return dt > -0.001 and dt < 0.001
|
||||
|
||||
# test == != >= <= < >
|
||||
assert 1.0 == 1.0
|
||||
assert 1.0 != 1.1
|
||||
@ -10,6 +6,10 @@ assert 1.0 <= 1.0
|
||||
assert 1.0 < 1.1
|
||||
assert 1.1 > 1.0
|
||||
|
||||
def eq(a, b):
|
||||
dt = a - b
|
||||
return dt > -0.001 and dt < 0.001
|
||||
|
||||
# test + - * ** /
|
||||
assert eq(1.5 + 3, 4.5)
|
||||
assert eq(1.5 + 3.9, 5.4)
|
||||
@ -53,14 +53,11 @@ assert eq(float("123"), 123.0)
|
||||
assert eq(float("123.456"), 123.456)
|
||||
|
||||
|
||||
import math
|
||||
|
||||
inf = float("inf")
|
||||
assert 1/0 == inf
|
||||
assert -1/0 == -inf
|
||||
assert 1/inf == 0
|
||||
assert -1/inf == 0
|
||||
assert math.isnan(0/0)
|
||||
|
||||
assert 2**-6000 == 0.0
|
||||
assert 2.0 ** 6000 == inf
|
||||
@ -74,7 +71,6 @@ assert eq(2 * .5, 1.0)
|
||||
assert eq(2 * (.5), 1.0)
|
||||
assert eq(2 * (.5 + 1), 3.0)
|
||||
|
||||
|
||||
assert 1e3 == 1000.0
|
||||
assert 1e-3 == 0.001
|
||||
assert -1e3 == -1000.0
|
||||
@ -83,15 +79,18 @@ assert 1e0 == 1.0
|
||||
assert 1e-0 == 1.0
|
||||
|
||||
assert 2e3 == 2000.0
|
||||
assert 2e3j == 2000j
|
||||
assert -2e-3 == -0.002
|
||||
assert -2e-3j == -0.002j
|
||||
|
||||
assert 3.4e-3 == 0.0034
|
||||
assert 3.4e+3 == 3400.0
|
||||
|
||||
try:
|
||||
float('-x13')
|
||||
exit(1)
|
||||
except ValueError:
|
||||
pass
|
||||
# import math
|
||||
# assert math.isnan(0/0)
|
||||
|
||||
# assert 2e3j == 2000j
|
||||
# assert -2e-3j == -0.002j
|
||||
|
||||
# try:
|
||||
# float('-x13')
|
||||
# exit(1)
|
||||
# except ValueError:
|
||||
# pass
|
||||
|
@ -12,6 +12,7 @@ assert True or False
|
||||
assert not False
|
||||
assert not (not True)
|
||||
|
||||
assert bool() == False
|
||||
assert bool(0) == False
|
||||
assert bool(1) == True
|
||||
assert bool([]) == False
|
||||
@ -19,7 +20,14 @@ assert bool("abc") == True
|
||||
assert bool([1,2]) == True
|
||||
assert bool('') == False
|
||||
|
||||
# extra compare for None
|
||||
# is operator
|
||||
assert None == None
|
||||
assert None is None
|
||||
assert ... == ...
|
||||
assert ... is ...
|
||||
assert NotImplemented == NotImplemented
|
||||
assert NotImplemented is NotImplemented
|
||||
|
||||
assert True is True
|
||||
assert False is False
|
||||
|
||||
|
153
tests/04_str.py
153
tests/04_str.py
@ -44,7 +44,6 @@ assert s.replace("foo","ball") == "balltball"
|
||||
assert s.startswith('f') == True;assert s.endswith('o') == False
|
||||
assert t.startswith('this') == True;
|
||||
|
||||
|
||||
assert t.split('w') == ['this is string example....', 'o', '!!!']
|
||||
assert "a,b,c".split(',') == ['a', 'b', 'c']
|
||||
assert 'a,'.split(',') == ['a']
|
||||
@ -110,29 +109,9 @@ num = 6
|
||||
assert str(num) == '6'
|
||||
|
||||
# test Lo group names
|
||||
|
||||
测试 = "test"
|
||||
assert 测试 == "test"
|
||||
|
||||
assert "Hello, {}!".format("World") == "Hello, World!"
|
||||
assert "{} {} {}".format("I", "love", "Python") == "I love Python"
|
||||
assert "{0} {1} {2}".format("I", "love", "Python") == "I love Python"
|
||||
assert "{2} {1} {0}".format("I", "love", "Python") == "Python love I"
|
||||
assert "{0}{1}{0}".format("abra", "cad") == "abracadabra"
|
||||
|
||||
assert "{k}={v}".format(k="key", v="value") == "key=value"
|
||||
assert "{k}={k}".format(k="key") == "key=key"
|
||||
assert "{0}={1}".format('{0}', '{1}') == "{0}={1}"
|
||||
assert "{{{0}}}".format(1) == "{1}"
|
||||
assert "{0}{1}{1}".format(1, 2, 3) == "122"
|
||||
try:
|
||||
"{0}={1}}".format(1, 2)
|
||||
exit(1)
|
||||
except ValueError:
|
||||
pass
|
||||
assert "{{{}xxx{}x}}".format(1, 2) == "{1xxx2x}"
|
||||
assert "{{abc}}".format() == "{abc}"
|
||||
|
||||
# 3rd slice
|
||||
a = "Hello, World!"
|
||||
assert a[::-1] == "!dlroW ,olleH"
|
||||
@ -152,20 +131,35 @@ assert b[5:2:-2] == [',', 'l']
|
||||
a = '123'
|
||||
assert a.rjust(5) == ' 123'
|
||||
assert a.rjust(5, '0') == '00123'
|
||||
try:
|
||||
a.rjust(5, '00')
|
||||
exit(1)
|
||||
except TypeError:
|
||||
pass
|
||||
assert a.ljust(5) == '123 '
|
||||
assert a.ljust(5, '0') == '12300'
|
||||
try:
|
||||
a.ljust(5, '00')
|
||||
exit(1)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
assert '\x30\x31\x32' == '012'
|
||||
assert '\b\b\b' == '\x08\x08\x08'
|
||||
assert repr('\x1f\x1e\x1f') == '\'\\x1f\\x1e\\x1f\''
|
||||
|
||||
assert hex(-42) == '-0x2a'
|
||||
assert hex(42) == '0x2a'
|
||||
|
||||
assert hex(0) == '0x0'
|
||||
assert hex(1) == '0x1'
|
||||
assert hex(15) == '0xf'
|
||||
assert hex(16) == '0x10'
|
||||
assert hex(255) == '0xff'
|
||||
assert hex(256) == '0x100'
|
||||
assert hex(257) == '0x101'
|
||||
assert hex(17) == '0x11'
|
||||
|
||||
a = '123'
|
||||
assert a.index('2') == 1
|
||||
assert a.index('1') == 0
|
||||
assert a.index('3') == 2
|
||||
|
||||
assert a.index('2', 1) == 1
|
||||
assert a.index('1', 0) == 0
|
||||
|
||||
assert a.find('1') == 0
|
||||
assert a.find('1', 1) == -1
|
||||
|
||||
a = 'abcd'
|
||||
assert list(a) == ['a', 'b', 'c', 'd']
|
||||
@ -184,78 +178,27 @@ assert list(a) == ['b']
|
||||
a = '测'
|
||||
assert list(a) == ['测']
|
||||
|
||||
assert '\b\b\b' == '\x08\x08\x08'
|
||||
# test format()
|
||||
assert "Hello, {}!".format("World") == "Hello, World!"
|
||||
assert "{} {} {}".format("I", "love", "Python") == "I love Python"
|
||||
assert "{0} {1} {2}".format("I", "love", "Python") == "I love Python"
|
||||
assert "{2} {1} {0}".format("I", "love", "Python") == "Python love I"
|
||||
assert "{0}{1}{0}".format("abra", "cad") == "abracadabra"
|
||||
|
||||
assert "{k}={v}".format(k="key", v="value") == "key=value"
|
||||
assert "{k}={k}".format(k="key") == "key=key"
|
||||
assert "{0}={1}".format('{0}', '{1}') == "{0}={1}"
|
||||
assert "{{{0}}}".format(1) == "{1}"
|
||||
assert "{0}{1}{1}".format(1, 2, 3) == "122"
|
||||
|
||||
# try:
|
||||
# "{0}={1}}".format(1, 2)
|
||||
# exit(1)
|
||||
# except ValueError:
|
||||
# pass
|
||||
|
||||
assert "{{{}xxx{}x}}".format(1, 2) == "{1xxx2x}"
|
||||
assert "{{abc}}".format() == "{abc}"
|
||||
|
||||
# test f-string
|
||||
stack=[1,2,3,4]; assert f"{stack[2:]}" == '[3, 4]'
|
||||
|
||||
assert repr('\x1f\x1e\x1f') == '\'\\x1f\\x1e\\x1f\''
|
||||
|
||||
|
||||
assert hex(-42) == '-0x2a'
|
||||
assert hex(42) == '0x2a'
|
||||
|
||||
assert hex(0) == '0x0'
|
||||
assert hex(1) == '0x1'
|
||||
assert hex(15) == '0xf'
|
||||
assert hex(16) == '0x10'
|
||||
assert hex(255) == '0xff'
|
||||
assert hex(256) == '0x100'
|
||||
assert hex(257) == '0x101'
|
||||
assert hex(17) == '0x11'
|
||||
|
||||
import c
|
||||
assert repr(c.NULL) == '<void* at 0x0>'
|
||||
assert repr(c.void_p(1)) == '<void* at 0x1>'
|
||||
assert repr(c.void_p(15)) == '<void* at 0xf>'
|
||||
assert repr(c.void_p(16)) == '<void* at 0x10>'
|
||||
assert repr(c.void_p(255)) == '<void* at 0xff>'
|
||||
assert repr(c.void_p(256)) == '<void* at 0x100>'
|
||||
assert repr(c.void_p(257)) == '<void* at 0x101>'
|
||||
assert repr(c.void_p(17)) == '<void* at 0x11>'
|
||||
|
||||
# random hex test
|
||||
import random
|
||||
|
||||
|
||||
def test(__min, __max):
|
||||
for _ in range(100):
|
||||
num = random.randint(__min, __max)
|
||||
hex_num = hex(num)
|
||||
assert eval(hex_num) == num
|
||||
if num >= 0:
|
||||
assert repr(c.void_p(num)) == f'<void* at 0x{hex_num[2:]}>'
|
||||
|
||||
test(0, 100)
|
||||
test(0, 100000)
|
||||
test(-100, 100)
|
||||
test(-100000, 100000)
|
||||
test(-2**30, 2**30)
|
||||
|
||||
|
||||
a = '123'
|
||||
assert a.index('2') == 1
|
||||
assert a.index('1') == 0
|
||||
assert a.index('3') == 2
|
||||
|
||||
assert a.index('2', 1) == 1
|
||||
assert a.index('1', 0) == 0
|
||||
|
||||
try:
|
||||
a.index('1', 1)
|
||||
exit(1)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
a.index('1', -1)
|
||||
exit(1)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
assert a.find('1') == 0
|
||||
assert a.find('1', 1) == -1
|
||||
|
||||
try:
|
||||
a.find('1', -1)
|
||||
exit(1)
|
||||
except ValueError:
|
||||
pass
|
||||
|
Loading…
x
Reference in New Issue
Block a user