mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
Merge branch 'starred_kwargs'
This commit is contained in:
commit
d5500c246c
@ -20,17 +20,16 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
|
|||||||
|
|
||||||
## Unimplemented features
|
## Unimplemented features
|
||||||
|
|
||||||
1. `**kwargs` in function definition.
|
1. `__getattr__` and `__setattr__`.
|
||||||
2. `__getattr__` and `__setattr__`.
|
2. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
|
||||||
3. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
|
3. `__slots__` in class definition.
|
||||||
4. `__slots__` in class definition.
|
4. One element tuple. `(1,)` is not supported.
|
||||||
5. One element tuple. `(1,)` is not supported.
|
5. Unpacking in `list` and `dict` literals, e.g. `[1, 2, *a]`.
|
||||||
6. Unpacking in `list` and `dict` literals, e.g. `[1, 2, *a]`.
|
6. Access the exception object in try..except.
|
||||||
7. Access the exception object in try..except.
|
7. `else` clause in try..except.
|
||||||
8. `else` clause in try..except.
|
8. Inplace methods like `__iadd__` and `__imul__`.
|
||||||
9. Inplace methods like `__iadd__` and `__imul__`.
|
9. `__del__` in class definition.
|
||||||
10. `__del__` in class definition.
|
10. Multiple inheritance.
|
||||||
11. Multiple inheritance.
|
|
||||||
|
|
||||||
## Different behaviors
|
## Different behaviors
|
||||||
|
|
||||||
|
78
src/ceval.h
78
src/ceval.h
@ -91,7 +91,7 @@ __NEXT_STEP:;
|
|||||||
TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH();
|
TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH();
|
||||||
TARGET(LOAD_FUNCTION) {
|
TARGET(LOAD_FUNCTION) {
|
||||||
FuncDecl_ decl = co->func_decls[byte.arg];
|
FuncDecl_ decl = co->func_decls[byte.arg];
|
||||||
bool is_simple = decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator;
|
bool is_simple = decl->starred_kwarg==-1 && decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator;
|
||||||
int argc = decl->args.size();
|
int argc = decl->args.size();
|
||||||
PyObject* obj;
|
PyObject* obj;
|
||||||
if(decl->nested){
|
if(decl->nested){
|
||||||
@ -236,6 +236,11 @@ __NEXT_STEP:;
|
|||||||
}
|
}
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
|
TARGET(BUILD_TUPLE)
|
||||||
|
_0 = VAR(STACK_VIEW(byte.arg).to_tuple());
|
||||||
|
STACK_SHRINK(byte.arg);
|
||||||
|
PUSH(_0);
|
||||||
|
DISPATCH();
|
||||||
TARGET(BUILD_LIST)
|
TARGET(BUILD_LIST)
|
||||||
_0 = VAR(STACK_VIEW(byte.arg).to_list());
|
_0 = VAR(STACK_VIEW(byte.arg).to_list());
|
||||||
STACK_SHRINK(byte.arg);
|
STACK_SHRINK(byte.arg);
|
||||||
@ -263,11 +268,6 @@ __NEXT_STEP:;
|
|||||||
_0 = POPX(); // start
|
_0 = POPX(); // start
|
||||||
PUSH(VAR(Slice(_0, _1, _2)));
|
PUSH(VAR(Slice(_0, _1, _2)));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(BUILD_TUPLE)
|
|
||||||
_0 = VAR(STACK_VIEW(byte.arg).to_tuple());
|
|
||||||
STACK_SHRINK(byte.arg);
|
|
||||||
PUSH(_0);
|
|
||||||
DISPATCH();
|
|
||||||
TARGET(BUILD_STRING) {
|
TARGET(BUILD_STRING) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ArgsView view = STACK_VIEW(byte.arg);
|
ArgsView view = STACK_VIEW(byte.arg);
|
||||||
@ -276,6 +276,40 @@ __NEXT_STEP:;
|
|||||||
PUSH(VAR(ss.str()));
|
PUSH(VAR(ss.str()));
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
|
TARGET(BUILD_TUPLE_UNPACK) {
|
||||||
|
auto _lock = heap.gc_scope_lock();
|
||||||
|
List list;
|
||||||
|
_unpack_as_list(STACK_VIEW(byte.arg), list);
|
||||||
|
STACK_SHRINK(byte.arg);
|
||||||
|
_0 = VAR(Tuple(std::move(list)));
|
||||||
|
PUSH(_0);
|
||||||
|
} DISPATCH();
|
||||||
|
TARGET(BUILD_LIST_UNPACK) {
|
||||||
|
auto _lock = heap.gc_scope_lock();
|
||||||
|
List list;
|
||||||
|
_unpack_as_list(STACK_VIEW(byte.arg), list);
|
||||||
|
STACK_SHRINK(byte.arg);
|
||||||
|
_0 = VAR(std::move(list));
|
||||||
|
PUSH(_0);
|
||||||
|
} DISPATCH();
|
||||||
|
TARGET(BUILD_DICT_UNPACK) {
|
||||||
|
auto _lock = heap.gc_scope_lock();
|
||||||
|
Dict dict(this);
|
||||||
|
_unpack_as_dict(STACK_VIEW(byte.arg), dict);
|
||||||
|
STACK_SHRINK(byte.arg);
|
||||||
|
_0 = VAR(std::move(dict));
|
||||||
|
PUSH(_0);
|
||||||
|
} DISPATCH();
|
||||||
|
TARGET(BUILD_SET_UNPACK) {
|
||||||
|
auto _lock = heap.gc_scope_lock();
|
||||||
|
List list;
|
||||||
|
_unpack_as_list(STACK_VIEW(byte.arg), list);
|
||||||
|
STACK_SHRINK(byte.arg);
|
||||||
|
_0 = VAR(std::move(list));
|
||||||
|
_0 = call(builtins->attr(set), _0);
|
||||||
|
PUSH(_0);
|
||||||
|
} DISPATCH();
|
||||||
|
/*****************************************/
|
||||||
#define PREDICT_INT_OP(op) \
|
#define PREDICT_INT_OP(op) \
|
||||||
if(is_both_int(TOP(), SECOND())){ \
|
if(is_both_int(TOP(), SECOND())){ \
|
||||||
_1 = POPX(); \
|
_1 = POPX(); \
|
||||||
@ -426,9 +460,6 @@ __NEXT_STEP:;
|
|||||||
frame->jump_abs_break(index);
|
frame->jump_abs_break(index);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(BEGIN_CALL)
|
|
||||||
PUSH(PY_BEGIN_CALL);
|
|
||||||
DISPATCH();
|
|
||||||
TARGET(CALL)
|
TARGET(CALL)
|
||||||
_0 = vectorcall(
|
_0 = vectorcall(
|
||||||
byte.arg & 0xFFFF, // ARGC
|
byte.arg & 0xFFFF, // ARGC
|
||||||
@ -438,6 +469,23 @@ __NEXT_STEP:;
|
|||||||
if(_0 == PY_OP_CALL) DISPATCH_OP_CALL();
|
if(_0 == PY_OP_CALL) DISPATCH_OP_CALL();
|
||||||
PUSH(_0);
|
PUSH(_0);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
TARGET(CALL_TP)
|
||||||
|
// [callable, <self>, args: tuple, kwargs: dict]
|
||||||
|
_2 = POPX();
|
||||||
|
_1 = POPX();
|
||||||
|
for(PyObject* obj: _CAST(Tuple&, _1)) PUSH(obj);
|
||||||
|
_CAST(Dict&, _2).apply([this](PyObject* k, PyObject* v){
|
||||||
|
PUSH(VAR(StrName(CAST(Str&, k)).index));
|
||||||
|
PUSH(v);
|
||||||
|
});
|
||||||
|
_0 = vectorcall(
|
||||||
|
_CAST(Tuple&, _1).size(), // ARGC
|
||||||
|
_CAST(Dict&, _2).size(), // KWARGC
|
||||||
|
true
|
||||||
|
);
|
||||||
|
if(_0 == PY_OP_CALL) DISPATCH_OP_CALL();
|
||||||
|
PUSH(_0);
|
||||||
|
DISPATCH();
|
||||||
TARGET(RETURN_VALUE)
|
TARGET(RETURN_VALUE)
|
||||||
_0 = POPX();
|
_0 = POPX();
|
||||||
_pop_frame();
|
_pop_frame();
|
||||||
@ -471,6 +519,9 @@ __NEXT_STEP:;
|
|||||||
TARGET(UNARY_NOT)
|
TARGET(UNARY_NOT)
|
||||||
TOP() = VAR(!py_bool(TOP()));
|
TOP() = VAR(!py_bool(TOP()));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
TARGET(UNARY_STAR)
|
||||||
|
TOP() = VAR(StarWrapper(byte.arg, TOP()));
|
||||||
|
DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(GET_ITER)
|
TARGET(GET_ITER)
|
||||||
TOP() = py_iter(TOP());
|
TOP() = py_iter(TOP());
|
||||||
@ -528,15 +579,6 @@ __NEXT_STEP:;
|
|||||||
}
|
}
|
||||||
PUSH(VAR(extras));
|
PUSH(VAR(extras));
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
TARGET(UNPACK_UNLIMITED) {
|
|
||||||
auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!!
|
|
||||||
_0 = py_iter(POPX());
|
|
||||||
_1 = py_next(_0);
|
|
||||||
while(_1 != StopIteration){
|
|
||||||
PUSH(_1);
|
|
||||||
_1 = py_next(_0);
|
|
||||||
}
|
|
||||||
} DISPATCH();
|
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(BEGIN_CLASS)
|
TARGET(BEGIN_CLASS)
|
||||||
_name = StrName(byte.arg);
|
_name = StrName(byte.arg);
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#define PK_VERSION "1.0.1"
|
#define PK_VERSION "1.0.2"
|
||||||
|
|
||||||
// debug macros
|
// debug macros
|
||||||
#define DEBUG_NO_BUILTIN_MODULES 0
|
#define DEBUG_NO_BUILTIN_MODULES 0
|
||||||
@ -153,6 +153,8 @@ struct Type {
|
|||||||
#define FATAL_ERROR() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " FATAL_ERROR()!");
|
#define FATAL_ERROR() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " FATAL_ERROR()!");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PK_ASSERT(x) if(!(x)) FATAL_ERROR();
|
||||||
|
|
||||||
inline const float kInstAttrLoadFactor = 0.67f;
|
inline const float kInstAttrLoadFactor = 0.67f;
|
||||||
inline const float kTypeAttrLoadFactor = 0.5f;
|
inline const float kTypeAttrLoadFactor = 0.5f;
|
||||||
|
|
||||||
@ -173,7 +175,6 @@ inline bool is_both_int(PyObject* a, PyObject* b) noexcept {
|
|||||||
|
|
||||||
// special singals, is_tagged() for them is true
|
// special singals, is_tagged() for them is true
|
||||||
inline PyObject* const PY_NULL = (PyObject*)0b000011; // tagged null
|
inline PyObject* const PY_NULL = (PyObject*)0b000011; // tagged null
|
||||||
inline PyObject* const PY_BEGIN_CALL = (PyObject*)0b010011;
|
|
||||||
inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
|
inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
|
||||||
inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
|
inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class Compiler {
|
|||||||
rules[TK("*")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_FACTOR };
|
rules[TK("*")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_FACTOR };
|
||||||
rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
||||||
rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
|
||||||
rules[TK("**")] = { nullptr, METHOD(exprBinaryOp), PREC_EXPONENT };
|
rules[TK("**")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_EXPONENT };
|
||||||
rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
||||||
rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
||||||
rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
|
||||||
@ -280,7 +280,10 @@ class Compiler {
|
|||||||
ctx()->s_expr.push(make_expr<NegatedExpr>(ctx()->s_expr.popx()));
|
ctx()->s_expr.push(make_expr<NegatedExpr>(ctx()->s_expr.popx()));
|
||||||
break;
|
break;
|
||||||
case TK("*"):
|
case TK("*"):
|
||||||
ctx()->s_expr.push(make_expr<StarredExpr>(ctx()->s_expr.popx()));
|
ctx()->s_expr.push(make_expr<StarredExpr>(1, ctx()->s_expr.popx()));
|
||||||
|
break;
|
||||||
|
case TK("**"):
|
||||||
|
ctx()->s_expr.push(make_expr<StarredExpr>(2, ctx()->s_expr.popx()));
|
||||||
break;
|
break;
|
||||||
default: FATAL_ERROR();
|
default: FATAL_ERROR();
|
||||||
}
|
}
|
||||||
@ -319,7 +322,6 @@ class Compiler {
|
|||||||
if (curr().type == TK("]")) break;
|
if (curr().type == TK("]")) break;
|
||||||
EXPR();
|
EXPR();
|
||||||
items.push_back(ctx()->s_expr.popx());
|
items.push_back(ctx()->s_expr.popx());
|
||||||
if(items.back()->is_starred()) SyntaxError();
|
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(items.size()==1 && match(TK("for"))){
|
if(items.size()==1 && match(TK("for"))){
|
||||||
_consume_comp<ListCompExpr>(std::move(items[0]));
|
_consume_comp<ListCompExpr>(std::move(items[0]));
|
||||||
@ -341,19 +343,24 @@ class Compiler {
|
|||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if (curr().type == TK("}")) break;
|
if (curr().type == TK("}")) break;
|
||||||
EXPR();
|
EXPR();
|
||||||
if(curr().type == TK(":")) parsing_dict = true;
|
int star_level = ctx()->s_expr.top()->star_level();
|
||||||
|
if(star_level==2 || curr().type == TK(":")){
|
||||||
|
parsing_dict = true;
|
||||||
|
}
|
||||||
if(parsing_dict){
|
if(parsing_dict){
|
||||||
consume(TK(":"));
|
|
||||||
EXPR();
|
|
||||||
auto dict_item = make_expr<DictItemExpr>();
|
auto dict_item = make_expr<DictItemExpr>();
|
||||||
dict_item->key = ctx()->s_expr.popx();
|
if(star_level == 2){
|
||||||
dict_item->value = ctx()->s_expr.popx();
|
dict_item->key = nullptr;
|
||||||
if(dict_item->key->is_starred()) SyntaxError();
|
dict_item->value = ctx()->s_expr.popx();
|
||||||
if(dict_item->value->is_starred()) SyntaxError();
|
}else{
|
||||||
|
consume(TK(":"));
|
||||||
|
EXPR();
|
||||||
|
dict_item->key = ctx()->s_expr.popx();
|
||||||
|
dict_item->value = ctx()->s_expr.popx();
|
||||||
|
}
|
||||||
items.push_back(std::move(dict_item));
|
items.push_back(std::move(dict_item));
|
||||||
}else{
|
}else{
|
||||||
items.push_back(ctx()->s_expr.popx());
|
items.push_back(ctx()->s_expr.popx());
|
||||||
if(items.back()->is_starred()) SyntaxError();
|
|
||||||
}
|
}
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(items.size()==1 && match(TK("for"))){
|
if(items.size()==1 && match(TK("for"))){
|
||||||
@ -387,9 +394,15 @@ class Compiler {
|
|||||||
EXPR();
|
EXPR();
|
||||||
e->kwargs.push_back({key, ctx()->s_expr.popx()});
|
e->kwargs.push_back({key, ctx()->s_expr.popx()});
|
||||||
} else{
|
} else{
|
||||||
if(!e->kwargs.empty()) SyntaxError("positional argument follows keyword argument");
|
|
||||||
EXPR();
|
EXPR();
|
||||||
e->args.push_back(ctx()->s_expr.popx());
|
if(ctx()->s_expr.top()->star_level() == 2){
|
||||||
|
// **kwargs
|
||||||
|
e->kwargs.push_back({"**", ctx()->s_expr.popx()});
|
||||||
|
}else{
|
||||||
|
// positional argument
|
||||||
|
if(!e->kwargs.empty()) SyntaxError("positional argument follows keyword argument");
|
||||||
|
e->args.push_back(ctx()->s_expr.popx());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
} while (match(TK(",")));
|
} while (match(TK(",")));
|
||||||
@ -876,6 +889,7 @@ __SUBSCR_END:
|
|||||||
void _compile_f_args(FuncDecl_ decl, bool enable_type_hints){
|
void _compile_f_args(FuncDecl_ decl, bool enable_type_hints){
|
||||||
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
||||||
do {
|
do {
|
||||||
|
if(state > 3) SyntaxError();
|
||||||
if(state == 3) SyntaxError("**kwargs should be the last argument");
|
if(state == 3) SyntaxError("**kwargs should be the last argument");
|
||||||
match_newlines();
|
match_newlines();
|
||||||
if(match(TK("*"))){
|
if(match(TK("*"))){
|
||||||
@ -894,14 +908,17 @@ __SUBSCR_END:
|
|||||||
SyntaxError("duplicate argument name");
|
SyntaxError("duplicate argument name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(decl->starred_arg!=-1 && decl->code->varnames[decl->starred_arg] == name){
|
|
||||||
SyntaxError("duplicate argument name");
|
|
||||||
}
|
|
||||||
for(auto& kv: decl->kwargs){
|
for(auto& kv: decl->kwargs){
|
||||||
if(decl->code->varnames[kv.key] == name){
|
if(decl->code->varnames[kv.key] == name){
|
||||||
SyntaxError("duplicate argument name");
|
SyntaxError("duplicate argument name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(decl->starred_arg!=-1 && decl->code->varnames[decl->starred_arg] == name){
|
||||||
|
SyntaxError("duplicate argument name");
|
||||||
|
}
|
||||||
|
if(decl->starred_kwarg!=-1 && decl->code->varnames[decl->starred_kwarg] == name){
|
||||||
|
SyntaxError("duplicate argument name");
|
||||||
|
}
|
||||||
|
|
||||||
// eat type hints
|
// eat type hints
|
||||||
if(enable_type_hints && match(TK(":"))) consume_type_hints();
|
if(enable_type_hints && match(TK(":"))) consume_type_hints();
|
||||||
@ -924,7 +941,10 @@ __SUBSCR_END:
|
|||||||
}
|
}
|
||||||
decl->kwargs.push_back(FuncDecl::KwArg{index, value});
|
decl->kwargs.push_back(FuncDecl::KwArg{index, value});
|
||||||
} break;
|
} break;
|
||||||
case 3: SyntaxError("**kwargs is not supported yet"); break;
|
case 3:
|
||||||
|
decl->starred_kwarg = index;
|
||||||
|
state+=1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} while (match(TK(",")));
|
} while (match(TK(",")));
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,14 @@ struct Dict{
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename __Func>
|
||||||
|
void apply(__Func f) const {
|
||||||
|
for(int i=0; i<_capacity; i++){
|
||||||
|
if(_items[i].first == nullptr) continue;
|
||||||
|
f(_items[i].first, _items[i].second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void clear(){
|
void clear(){
|
||||||
memset(_items, 0, _capacity * sizeof(Item));
|
memset(_items, 0, _capacity * sizeof(Item));
|
||||||
_size = 0;
|
_size = 0;
|
||||||
|
109
src/expr.h
109
src/expr.h
@ -19,11 +19,12 @@ struct Expr{
|
|||||||
virtual void emit(CodeEmitContext* ctx) = 0;
|
virtual void emit(CodeEmitContext* ctx) = 0;
|
||||||
virtual std::string str() const = 0;
|
virtual std::string str() const = 0;
|
||||||
|
|
||||||
virtual bool is_starred() const { return false; }
|
|
||||||
virtual bool is_literal() const { return false; }
|
virtual bool is_literal() const { return false; }
|
||||||
virtual bool is_json_object() const { return false; }
|
virtual bool is_json_object() const { return false; }
|
||||||
virtual bool is_attrib() const { return false; }
|
virtual bool is_attrib() const { return false; }
|
||||||
virtual bool is_compare() const { return false; }
|
virtual bool is_compare() const { return false; }
|
||||||
|
virtual int star_level() const { return 0; }
|
||||||
|
bool is_starred() const { return star_level() > 0; }
|
||||||
|
|
||||||
// for OP_DELETE_XXX
|
// for OP_DELETE_XXX
|
||||||
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
|
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
|
||||||
@ -183,24 +184,25 @@ struct NameExpr: Expr{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct StarredExpr: Expr{
|
struct StarredExpr: Expr{
|
||||||
|
int level;
|
||||||
Expr_ child;
|
Expr_ child;
|
||||||
StarredExpr(Expr_&& child): child(std::move(child)) {}
|
StarredExpr(int level, Expr_&& child): level(level), child(std::move(child)) {}
|
||||||
std::string str() const override { return "Starred()"; }
|
std::string str() const override { return fmt("Starred(level=", level, ")"); }
|
||||||
|
|
||||||
bool is_starred() const override { return true; }
|
int star_level() const override { return level; }
|
||||||
|
|
||||||
void emit(CodeEmitContext* ctx) override {
|
void emit(CodeEmitContext* ctx) override {
|
||||||
child->emit(ctx);
|
child->emit(ctx);
|
||||||
ctx->emit(OP_UNPACK_UNLIMITED, BC_NOARG, line);
|
ctx->emit(OP_UNARY_STAR, level, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emit_store(CodeEmitContext* ctx) override {
|
bool emit_store(CodeEmitContext* ctx) override {
|
||||||
|
if(level != 1) return false;
|
||||||
// simply proxy to child
|
// simply proxy to child
|
||||||
return child->emit_store(ctx);
|
return child->emit_store(ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct NotExpr: Expr{
|
struct NotExpr: Expr{
|
||||||
Expr_ child;
|
Expr_ child;
|
||||||
NotExpr(Expr_&& child): child(std::move(child)) {}
|
NotExpr(Expr_&& child): child(std::move(child)) {}
|
||||||
@ -265,16 +267,13 @@ struct LiteralExpr: Expr{
|
|||||||
if(std::holds_alternative<i64>(value)){
|
if(std::holds_alternative<i64>(value)){
|
||||||
return std::to_string(std::get<i64>(value));
|
return std::to_string(std::get<i64>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std::holds_alternative<f64>(value)){
|
if(std::holds_alternative<f64>(value)){
|
||||||
return std::to_string(std::get<f64>(value));
|
return std::to_string(std::get<f64>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std::holds_alternative<Str>(value)){
|
if(std::holds_alternative<Str>(value)){
|
||||||
Str s = std::get<Str>(value).escape();
|
Str s = std::get<Str>(value).escape();
|
||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
FATAL_ERROR();
|
FATAL_ERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,14 +366,21 @@ struct SliceExpr: Expr{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct DictItemExpr: Expr{
|
struct DictItemExpr: Expr{
|
||||||
Expr_ key;
|
Expr_ key; // maybe nullptr if it is **kwargs
|
||||||
Expr_ value;
|
Expr_ value;
|
||||||
std::string str() const override { return "DictItem()"; }
|
std::string str() const override { return "DictItem()"; }
|
||||||
|
|
||||||
|
int star_level() const override { return value->star_level(); }
|
||||||
|
|
||||||
void emit(CodeEmitContext* ctx) override {
|
void emit(CodeEmitContext* ctx) override {
|
||||||
value->emit(ctx);
|
if(is_starred()){
|
||||||
key->emit(ctx); // reverse order
|
PK_ASSERT(key == nullptr);
|
||||||
ctx->emit(OP_BUILD_TUPLE, 2, line);
|
value->emit(ctx);
|
||||||
|
}else{
|
||||||
|
value->emit(ctx);
|
||||||
|
key->emit(ctx); // reverse order
|
||||||
|
ctx->emit(OP_BUILD_TUPLE, 2, line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -392,7 +398,11 @@ struct SequenceExpr: Expr{
|
|||||||
struct ListExpr: SequenceExpr{
|
struct ListExpr: SequenceExpr{
|
||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
std::string str() const override { return "List()"; }
|
std::string str() const override { return "List()"; }
|
||||||
Opcode opcode() const override { return OP_BUILD_LIST; }
|
|
||||||
|
Opcode opcode() const override {
|
||||||
|
for(auto& e: items) if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
|
||||||
|
return OP_BUILD_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_json_object() const override { return true; }
|
bool is_json_object() const override { return true; }
|
||||||
};
|
};
|
||||||
@ -400,7 +410,10 @@ struct ListExpr: SequenceExpr{
|
|||||||
struct DictExpr: SequenceExpr{
|
struct DictExpr: SequenceExpr{
|
||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
std::string str() const override { return "Dict()"; }
|
std::string str() const override { return "Dict()"; }
|
||||||
Opcode opcode() const override { return OP_BUILD_DICT; }
|
Opcode opcode() const override {
|
||||||
|
for(auto& e: items) if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
|
||||||
|
return OP_BUILD_DICT;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_json_object() const override { return true; }
|
bool is_json_object() const override { return true; }
|
||||||
};
|
};
|
||||||
@ -408,13 +421,19 @@ struct DictExpr: SequenceExpr{
|
|||||||
struct SetExpr: SequenceExpr{
|
struct SetExpr: SequenceExpr{
|
||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
std::string str() const override { return "Set()"; }
|
std::string str() const override { return "Set()"; }
|
||||||
Opcode opcode() const override { return OP_BUILD_SET; }
|
Opcode opcode() const override {
|
||||||
|
for(auto& e: items) if(e->is_starred()) return OP_BUILD_SET_UNPACK;
|
||||||
|
return OP_BUILD_SET;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TupleExpr: SequenceExpr{
|
struct TupleExpr: SequenceExpr{
|
||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
std::string str() const override { return "Tuple()"; }
|
std::string str() const override { return "Tuple()"; }
|
||||||
Opcode opcode() const override { return OP_BUILD_TUPLE; }
|
Opcode opcode() const override {
|
||||||
|
for(auto& e: items) if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
|
||||||
|
return OP_BUILD_TUPLE;
|
||||||
|
}
|
||||||
|
|
||||||
bool emit_store(CodeEmitContext* ctx) override {
|
bool emit_store(CodeEmitContext* ctx) override {
|
||||||
// TOS is an iterable
|
// TOS is an iterable
|
||||||
@ -644,37 +663,55 @@ struct AttribExpr: Expr{
|
|||||||
struct CallExpr: Expr{
|
struct CallExpr: Expr{
|
||||||
Expr_ callable;
|
Expr_ callable;
|
||||||
std::vector<Expr_> args;
|
std::vector<Expr_> args;
|
||||||
|
// **a will be interpreted as a special keyword argument: {"**": a}
|
||||||
std::vector<std::pair<Str, Expr_>> kwargs;
|
std::vector<std::pair<Str, Expr_>> kwargs;
|
||||||
std::string str() const override { return "Call()"; }
|
std::string str() const override { return "Call()"; }
|
||||||
|
|
||||||
bool need_unpack() const {
|
|
||||||
for(auto& item: args) if(item->is_starred()) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void emit(CodeEmitContext* ctx) override {
|
void emit(CodeEmitContext* ctx) override {
|
||||||
VM* vm = ctx->vm;
|
bool vargs = false;
|
||||||
if(need_unpack()) ctx->emit(OP_BEGIN_CALL, BC_NOARG, line);
|
bool vkwargs = false;
|
||||||
|
for(auto& arg: args) if(arg->is_starred()) vargs = true;
|
||||||
|
for(auto& item: kwargs) if(item.second->is_starred()) vkwargs = true;
|
||||||
|
|
||||||
// if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy
|
// if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy
|
||||||
if(callable->is_attrib()){
|
if(callable->is_attrib()){
|
||||||
auto p = static_cast<AttribExpr*>(callable.get());
|
auto p = static_cast<AttribExpr*>(callable.get());
|
||||||
p->emit_method(ctx);
|
p->emit_method(ctx); // OP_LOAD_METHOD
|
||||||
}else{
|
}else{
|
||||||
callable->emit(ctx);
|
callable->emit(ctx);
|
||||||
ctx->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
|
ctx->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
// emit args
|
|
||||||
for(auto& item: args) item->emit(ctx);
|
if(vargs || vkwargs){
|
||||||
// emit kwargs
|
for(auto& item: args) item->emit(ctx);
|
||||||
for(auto& item: kwargs){
|
ctx->emit(OP_BUILD_TUPLE_UNPACK, (int)args.size(), line);
|
||||||
int index = StrName::get(item.first.sv()).index;
|
|
||||||
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(index)), line);
|
for(auto& item: kwargs){
|
||||||
item.second->emit(ctx);
|
if(item.second->is_starred()){
|
||||||
|
if(item.second->star_level() != 2) FATAL_ERROR();
|
||||||
|
item.second->emit(ctx);
|
||||||
|
}else{
|
||||||
|
// k=v
|
||||||
|
int index = ctx->add_const(py_var(ctx->vm, item.first));
|
||||||
|
ctx->emit(OP_LOAD_CONST, index, line);
|
||||||
|
item.second->emit(ctx);
|
||||||
|
ctx->emit(OP_BUILD_TUPLE, 2, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->emit(OP_BUILD_DICT_UNPACK, (int)kwargs.size(), line);
|
||||||
|
ctx->emit(OP_CALL_TP, BC_NOARG, line);
|
||||||
|
}else{
|
||||||
|
// vectorcall protocal
|
||||||
|
for(auto& item: args) item->emit(ctx);
|
||||||
|
for(auto& item: kwargs){
|
||||||
|
int index = StrName(item.first.sv()).index;
|
||||||
|
ctx->emit(OP_LOAD_INTEGER, index, line);
|
||||||
|
item.second->emit(ctx);
|
||||||
|
}
|
||||||
|
int KWARGC = (int)kwargs.size();
|
||||||
|
int ARGC = (int)args.size();
|
||||||
|
ctx->emit(OP_CALL, (KWARGC<<16)|ARGC, line);
|
||||||
}
|
}
|
||||||
int KWARGC = (int)kwargs.size();
|
|
||||||
int ARGC = (int)args.size();
|
|
||||||
if(need_unpack()) ARGC = 0xFFFF;
|
|
||||||
ctx->emit(OP_CALL, (KWARGC<<16)|ARGC, line);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -238,6 +238,7 @@ struct MemoryPool{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: make them thread-safe
|
||||||
inline MemoryPool<64> pool64;
|
inline MemoryPool<64> pool64;
|
||||||
inline MemoryPool<128> pool128;
|
inline MemoryPool<128> pool128;
|
||||||
|
|
||||||
|
19
src/obj.h
19
src/obj.h
@ -60,8 +60,9 @@ struct FuncDecl {
|
|||||||
};
|
};
|
||||||
CodeObject_ code; // code object of this function
|
CodeObject_ code; // code object of this function
|
||||||
pod_vector<int> args; // indices in co->varnames
|
pod_vector<int> args; // indices in co->varnames
|
||||||
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
|
||||||
pod_vector<KwArg> kwargs; // indices in co->varnames
|
pod_vector<KwArg> kwargs; // indices in co->varnames
|
||||||
|
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
||||||
|
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
||||||
bool nested = false; // whether this function is nested
|
bool nested = false; // whether this function is nested
|
||||||
void _gc_mark() const;
|
void _gc_mark() const;
|
||||||
};
|
};
|
||||||
@ -101,6 +102,12 @@ struct Range {
|
|||||||
i64 step = 1;
|
i64 step = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StarWrapper{
|
||||||
|
int level; // either 1 or 2
|
||||||
|
PyObject* obj;
|
||||||
|
StarWrapper(int level, PyObject* obj) : level(level), obj(obj) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct Bytes{
|
struct Bytes{
|
||||||
std::vector<char> _data;
|
std::vector<char> _data;
|
||||||
bool _ok;
|
bool _ok;
|
||||||
@ -335,6 +342,16 @@ struct Py_<BoundMethod> final: PyObject {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Py_<StarWrapper> final: PyObject {
|
||||||
|
StarWrapper _value;
|
||||||
|
void* value() override { return &_value; }
|
||||||
|
Py_(Type type, StarWrapper val): PyObject(type), _value(val) {}
|
||||||
|
void _obj_gc_mark() override {
|
||||||
|
OBJ_MARK(_value.obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct Py_<Property> final: PyObject {
|
struct Py_<Property> final: PyObject {
|
||||||
Property _value;
|
Property _value;
|
||||||
|
@ -38,13 +38,18 @@ OPCODE(DELETE_GLOBAL)
|
|||||||
OPCODE(DELETE_ATTR)
|
OPCODE(DELETE_ATTR)
|
||||||
OPCODE(DELETE_SUBSCR)
|
OPCODE(DELETE_SUBSCR)
|
||||||
/**************************/
|
/**************************/
|
||||||
|
OPCODE(BUILD_TUPLE)
|
||||||
OPCODE(BUILD_LIST)
|
OPCODE(BUILD_LIST)
|
||||||
OPCODE(BUILD_DICT)
|
OPCODE(BUILD_DICT)
|
||||||
OPCODE(BUILD_SET)
|
OPCODE(BUILD_SET)
|
||||||
OPCODE(BUILD_SLICE)
|
OPCODE(BUILD_SLICE)
|
||||||
OPCODE(BUILD_TUPLE)
|
|
||||||
OPCODE(BUILD_STRING)
|
OPCODE(BUILD_STRING)
|
||||||
/**************************/
|
/**************************/
|
||||||
|
OPCODE(BUILD_TUPLE_UNPACK)
|
||||||
|
OPCODE(BUILD_LIST_UNPACK)
|
||||||
|
OPCODE(BUILD_DICT_UNPACK)
|
||||||
|
OPCODE(BUILD_SET_UNPACK)
|
||||||
|
/**************************/
|
||||||
OPCODE(BINARY_TRUEDIV)
|
OPCODE(BINARY_TRUEDIV)
|
||||||
OPCODE(BINARY_POW)
|
OPCODE(BINARY_POW)
|
||||||
|
|
||||||
@ -81,8 +86,8 @@ OPCODE(LOOP_CONTINUE)
|
|||||||
OPCODE(LOOP_BREAK)
|
OPCODE(LOOP_BREAK)
|
||||||
OPCODE(GOTO)
|
OPCODE(GOTO)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(BEGIN_CALL)
|
|
||||||
OPCODE(CALL)
|
OPCODE(CALL)
|
||||||
|
OPCODE(CALL_TP)
|
||||||
OPCODE(RETURN_VALUE)
|
OPCODE(RETURN_VALUE)
|
||||||
OPCODE(YIELD_VALUE)
|
OPCODE(YIELD_VALUE)
|
||||||
/**************************/
|
/**************************/
|
||||||
@ -92,6 +97,7 @@ OPCODE(SET_ADD)
|
|||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(UNARY_NEGATIVE)
|
OPCODE(UNARY_NEGATIVE)
|
||||||
OPCODE(UNARY_NOT)
|
OPCODE(UNARY_NOT)
|
||||||
|
OPCODE(UNARY_STAR)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(GET_ITER)
|
OPCODE(GET_ITER)
|
||||||
OPCODE(FOR_ITER)
|
OPCODE(FOR_ITER)
|
||||||
@ -102,7 +108,6 @@ OPCODE(IMPORT_STAR)
|
|||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(UNPACK_SEQUENCE)
|
OPCODE(UNPACK_SEQUENCE)
|
||||||
OPCODE(UNPACK_EX)
|
OPCODE(UNPACK_EX)
|
||||||
OPCODE(UNPACK_UNLIMITED)
|
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(BEGIN_CLASS)
|
OPCODE(BEGIN_CLASS)
|
||||||
OPCODE(END_CLASS)
|
OPCODE(END_CLASS)
|
||||||
|
22
src/str.h
22
src/str.h
@ -124,19 +124,37 @@ struct Str{
|
|||||||
return memcmp(data, other.data, size) != 0;
|
return memcmp(data, other.data, size) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const std::string_view other) const {
|
||||||
|
if(size != (int)other.size()) return false;
|
||||||
|
return memcmp(data, other.data(), size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const std::string_view other) const {
|
||||||
|
if(size != (int)other.size()) return true;
|
||||||
|
return memcmp(data, other.data(), size) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const char* p) const {
|
||||||
|
return *this == std::string_view(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const char* p) const {
|
||||||
|
return *this != std::string_view(p);
|
||||||
|
}
|
||||||
|
|
||||||
bool operator<(const Str& other) const {
|
bool operator<(const Str& other) const {
|
||||||
int ret = strncmp(data, other.data, std::min(size, other.size));
|
int ret = strncmp(data, other.data, std::min(size, other.size));
|
||||||
if(ret != 0) return ret < 0;
|
if(ret != 0) return ret < 0;
|
||||||
return size < other.size;
|
return size < other.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const std::string_view& other) const {
|
bool operator<(const std::string_view other) const {
|
||||||
int ret = strncmp(data, other.data(), std::min(size, (int)other.size()));
|
int ret = strncmp(data, other.data(), std::min(size, (int)other.size()));
|
||||||
if(ret != 0) return ret < 0;
|
if(ret != 0) return ret < 0;
|
||||||
return size < (int)other.size();
|
return size < (int)other.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator<(const std::string_view& other, const Str& str){
|
friend bool operator<(const std::string_view other, const Str& str){
|
||||||
return str > other;
|
return str > other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
81
src/vm.h
81
src/vm.h
@ -134,7 +134,7 @@ public:
|
|||||||
Type tp_function, tp_native_func, tp_bound_method;
|
Type tp_function, tp_native_func, tp_bound_method;
|
||||||
Type tp_slice, tp_range, tp_module;
|
Type tp_slice, tp_range, tp_module;
|
||||||
Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
|
Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
|
||||||
Type tp_dict, tp_property;
|
Type tp_dict, tp_property, tp_star_wrapper;
|
||||||
|
|
||||||
const bool enable_os;
|
const bool enable_os;
|
||||||
|
|
||||||
@ -637,6 +637,8 @@ public:
|
|||||||
#if DEBUG_CEVAL_STEP
|
#if DEBUG_CEVAL_STEP
|
||||||
void _log_s_data(const char* title = nullptr);
|
void _log_s_data(const char* title = nullptr);
|
||||||
#endif
|
#endif
|
||||||
|
void _unpack_as_list(ArgsView args, List& list);
|
||||||
|
void _unpack_as_dict(ArgsView args, Dict& dict);
|
||||||
PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false);
|
PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false);
|
||||||
CodeObject_ compile(Str source, Str filename, CompileMode mode, bool unknown_global_scope=false);
|
CodeObject_ compile(Str source, Str filename, CompileMode mode, bool unknown_global_scope=false);
|
||||||
PyObject* py_negate(PyObject* obj);
|
PyObject* py_negate(PyObject* obj);
|
||||||
@ -686,6 +688,7 @@ DEF_NATIVE_2(Bytes, tp_bytes)
|
|||||||
DEF_NATIVE_2(MappingProxy, tp_mappingproxy)
|
DEF_NATIVE_2(MappingProxy, tp_mappingproxy)
|
||||||
DEF_NATIVE_2(Dict, tp_dict)
|
DEF_NATIVE_2(Dict, tp_dict)
|
||||||
DEF_NATIVE_2(Property, tp_property)
|
DEF_NATIVE_2(Property, tp_property)
|
||||||
|
DEF_NATIVE_2(StarWrapper, tp_star_wrapper)
|
||||||
|
|
||||||
#undef DEF_NATIVE_2
|
#undef DEF_NATIVE_2
|
||||||
|
|
||||||
@ -1063,7 +1066,6 @@ inline void VM::_log_s_data(const char* title) {
|
|||||||
if(sp_bases[p] > 0) ss << " ";
|
if(sp_bases[p] > 0) ss << " ";
|
||||||
PyObject* obj = *p;
|
PyObject* obj = *p;
|
||||||
if(obj == nullptr) ss << "(nil)";
|
if(obj == nullptr) ss << "(nil)";
|
||||||
else if(obj == PY_BEGIN_CALL) ss << "BEGIN_CALL";
|
|
||||||
else if(obj == PY_NULL) ss << "NULL";
|
else if(obj == PY_NULL) ss << "NULL";
|
||||||
else if(is_int(obj)) ss << CAST(i64, obj);
|
else if(is_int(obj)) ss << CAST(i64, obj);
|
||||||
else if(is_float(obj)) ss << CAST(f64, obj);
|
else if(is_float(obj)) ss << CAST(f64, obj);
|
||||||
@ -1121,6 +1123,7 @@ inline void VM::init_builtin_types(){
|
|||||||
tp_mappingproxy = _new_type_object("mappingproxy");
|
tp_mappingproxy = _new_type_object("mappingproxy");
|
||||||
tp_dict = _new_type_object("dict");
|
tp_dict = _new_type_object("dict");
|
||||||
tp_property = _new_type_object("property");
|
tp_property = _new_type_object("property");
|
||||||
|
tp_star_wrapper = _new_type_object("_star_wrapper");
|
||||||
|
|
||||||
this->None = heap._new<Dummy>(_new_type_object("NoneType"), {});
|
this->None = heap._new<Dummy>(_new_type_object("NoneType"), {});
|
||||||
this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {});
|
this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {});
|
||||||
@ -1154,21 +1157,47 @@ inline void VM::init_builtin_types(){
|
|||||||
this->_main = new_module("__main__");
|
this->_main = new_module("__main__");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
// `heap.gc_scope_lock();` needed before calling this function
|
||||||
bool is_varargs = ARGC == 0xFFFF;
|
inline void VM::_unpack_as_list(ArgsView args, List& list){
|
||||||
PyObject** p0;
|
for(PyObject* obj: args){
|
||||||
PyObject** p1 = s_data._sp - KWARGC*2;
|
if(is_non_tagged_type(obj, tp_star_wrapper)){
|
||||||
if(is_varargs){
|
const StarWrapper& w = _CAST(StarWrapper&, obj);
|
||||||
p0 = p1 - 1;
|
// maybe this check should be done in the compile time
|
||||||
while(*p0 != PY_BEGIN_CALL) p0--;
|
if(w.level != 1) TypeError("expected level 1 star wrapper");
|
||||||
// [BEGIN_CALL, callable, <self>, args..., kwargs...]
|
PyObject* _0 = py_iter(w.obj);
|
||||||
// ^p0 ^p1 ^_sp
|
PyObject* _1 = py_next(_0);
|
||||||
ARGC = p1 - (p0 + 3);
|
while(_1 != StopIteration){
|
||||||
}else{
|
list.push_back(_1);
|
||||||
p0 = p1 - ARGC - 2 - (int)is_varargs;
|
_1 = py_next(_0);
|
||||||
// [callable, <self>, args..., kwargs...]
|
}
|
||||||
// ^p0 ^p1 ^_sp
|
}else{
|
||||||
|
list.push_back(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `heap.gc_scope_lock();` needed before calling this function
|
||||||
|
inline void VM::_unpack_as_dict(ArgsView args, Dict& dict){
|
||||||
|
for(PyObject* obj: args){
|
||||||
|
if(is_non_tagged_type(obj, tp_star_wrapper)){
|
||||||
|
const StarWrapper& w = _CAST(StarWrapper&, obj);
|
||||||
|
// maybe this check should be done in the compile time
|
||||||
|
if(w.level != 2) TypeError("expected level 2 star wrapper");
|
||||||
|
const Dict& other = CAST(Dict&, w.obj);
|
||||||
|
dict.update(other);
|
||||||
|
}else{
|
||||||
|
const Tuple& t = CAST(Tuple&, obj);
|
||||||
|
if(t.size() != 2) TypeError("expected tuple of length 2");
|
||||||
|
dict.set(t[0], t[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||||
|
PyObject** p1 = s_data._sp - KWARGC*2;
|
||||||
|
PyObject** p0 = p1 - ARGC - 2;
|
||||||
|
// [callable, <self>, args..., kwargs...]
|
||||||
|
// ^p0 ^p1 ^_sp
|
||||||
PyObject* callable = p1[-(ARGC + 2)];
|
PyObject* callable = p1[-(ARGC + 2)];
|
||||||
bool method_call = p1[-(ARGC + 1)] != PY_NULL;
|
bool method_call = p1[-(ARGC + 1)] != PY_NULL;
|
||||||
|
|
||||||
@ -1249,11 +1278,27 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
|||||||
if(i < args.size()) TypeError(fmt("too many arguments", " (", fn.decl->code->name, ')'));
|
if(i < args.size()) TypeError(fmt("too many arguments", " (", fn.decl->code->name, ')'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject* vkwargs;
|
||||||
|
if(fn.decl->starred_kwarg != -1){
|
||||||
|
vkwargs = VAR(Dict(this));
|
||||||
|
buffer[fn.decl->starred_kwarg] = vkwargs;
|
||||||
|
}else{
|
||||||
|
vkwargs = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0; i<kwargs.size(); i+=2){
|
for(int i=0; i<kwargs.size(); i+=2){
|
||||||
StrName key = CAST(int, kwargs[i]);
|
StrName key = CAST(int, kwargs[i]);
|
||||||
int index = co->varnames_inv.try_get(key);
|
int index = co->varnames_inv.try_get(key);
|
||||||
if(index<0) TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()"));
|
if(index < 0){
|
||||||
buffer[index] = kwargs[i+1];
|
if(vkwargs == nullptr){
|
||||||
|
TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()"));
|
||||||
|
}else{
|
||||||
|
Dict& dict = _CAST(Dict&, vkwargs);
|
||||||
|
dict.set(VAR(key.sv()), kwargs[i+1]);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
buffer[index] = kwargs[i+1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(co->is_generator){
|
if(co->is_generator){
|
||||||
|
@ -75,3 +75,12 @@ assert a == [8, 2, 4, 2, 9]
|
|||||||
b = [(1, 2), (3, 3), (5, 1)]
|
b = [(1, 2), (3, 3), (5, 1)]
|
||||||
b.sort(key=lambda x:x[1])
|
b.sort(key=lambda x:x[1])
|
||||||
assert b == [(5, 1), (1, 2), (3,3)]
|
assert b == [(5, 1), (1, 2), (3,3)]
|
||||||
|
|
||||||
|
# unpack expression
|
||||||
|
a = [1, 2, 3]
|
||||||
|
b = [*a, 4, 5]
|
||||||
|
assert b == [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
|
a = []
|
||||||
|
b = [*a, 1, 2, 3, *a, *a]
|
||||||
|
assert b == [1, 2, 3]
|
@ -6,3 +6,12 @@ a,b = b,a
|
|||||||
assert a == 2
|
assert a == 2
|
||||||
assert b == 1
|
assert b == 1
|
||||||
assert len(tup) == 6
|
assert len(tup) == 6
|
||||||
|
|
||||||
|
# unpack expression
|
||||||
|
a = 1, 2, 3
|
||||||
|
b = *a, 4, 5
|
||||||
|
assert b == (1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
a = tuple([])
|
||||||
|
b = *a, 1, 2, 3, *a, *a
|
||||||
|
assert b == (1, 2, 3)
|
@ -53,3 +53,17 @@ assert a.pop(1) == 2
|
|||||||
assert a == {3: 4}
|
assert a == {3: 4}
|
||||||
assert a.pop(3) == 4
|
assert a.pop(3) == 4
|
||||||
assert a == {}
|
assert a == {}
|
||||||
|
|
||||||
|
# unpack expression
|
||||||
|
a = {1:2, 3:4}
|
||||||
|
b = {**a, 5:6, **a}
|
||||||
|
assert b == {1: 2, 3: 4, 5: 6}
|
||||||
|
|
||||||
|
a = {}
|
||||||
|
b = {**a, 1:2, 3:4}
|
||||||
|
assert b == {1: 2, 3: 4}
|
||||||
|
|
||||||
|
a = {1:2, 3:4, 7:8}
|
||||||
|
b = {**a, 1:5, 3:6}
|
||||||
|
c = {**a, **b}
|
||||||
|
assert c == {1: 5, 3: 6, 7: 8}
|
@ -77,3 +77,12 @@ assert {1,2}.issubset({1,2,3})
|
|||||||
assert {1,2,3}.issuperset({1,2})
|
assert {1,2,3}.issuperset({1,2})
|
||||||
assert {1,2,3}.isdisjoint({4,5,6})
|
assert {1,2,3}.isdisjoint({4,5,6})
|
||||||
assert not {1,2,3}.isdisjoint({2,3,4})
|
assert not {1,2,3}.isdisjoint({2,3,4})
|
||||||
|
|
||||||
|
# unpack expression
|
||||||
|
a = {1, 2, 3}
|
||||||
|
b = {*a, 4, 5, *a, *a}
|
||||||
|
assert b == {1, 2, 3, 4, 5}
|
||||||
|
|
||||||
|
a = set()
|
||||||
|
b = {*a, 1, 2, 3, *a, *a}
|
||||||
|
assert b == {1, 2, 3}
|
@ -47,6 +47,9 @@ assert f(10, 1, 2, 3) == 18
|
|||||||
def f(a, b, *c, d=2, e=5):
|
def f(a, b, *c, d=2, e=5):
|
||||||
return a + b + d + e + sum(c)
|
return a + b + d + e + sum(c)
|
||||||
|
|
||||||
|
def g(*args, **kwargs):
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
assert f(1, 2, 3, 4) == 17
|
assert f(1, 2, 3, 4) == 17
|
||||||
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 62
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 62
|
||||||
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1, e=2) == 58
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1, e=2) == 58
|
||||||
@ -56,6 +59,13 @@ assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, e=1) == 58
|
|||||||
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) == 217
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) == 217
|
||||||
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, d=1, e=2) == 213
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, d=1, e=2) == 213
|
||||||
|
|
||||||
|
assert g(1, 2, 3, 4) == 17
|
||||||
|
assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 62
|
||||||
|
assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1, e=2) == 58
|
||||||
|
assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, e=1, d=2) == 58
|
||||||
|
assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1) == 61
|
||||||
|
assert g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, e=1) == 58
|
||||||
|
|
||||||
a = 1
|
a = 1
|
||||||
b = 2
|
b = 2
|
||||||
|
|
||||||
@ -67,3 +77,18 @@ def f():
|
|||||||
f()
|
f()
|
||||||
assert a == 3
|
assert a == 3
|
||||||
assert b == 4
|
assert b == 4
|
||||||
|
|
||||||
|
def g(a, b, *args, c=1, d=2, **kwargs):
|
||||||
|
S = a + b + c + d + sum(args)
|
||||||
|
return S, kwargs
|
||||||
|
|
||||||
|
S, kwargs = g(1, 2, 3, 4, 5, c=4, e=5, f=6)
|
||||||
|
# a = 1
|
||||||
|
# b = 2
|
||||||
|
# c = 4
|
||||||
|
# d = 2
|
||||||
|
# sum(args) = 3 + 4 + 5 = 12
|
||||||
|
# S = 1 + 2 + 4 + 2 + 12 = 21
|
||||||
|
|
||||||
|
assert S == 21
|
||||||
|
assert kwargs == {'e': 5, 'f': 6}
|
@ -53,3 +53,14 @@ try:
|
|||||||
exit(1)
|
exit(1)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def g(*args, **kwargs):
|
||||||
|
return args, kwargs
|
||||||
|
|
||||||
|
def f(a, b, *args, c=1, **kwargs):
|
||||||
|
return g(a, b, *args, c=c, **kwargs)
|
||||||
|
|
||||||
|
args, kwargs = f(1, 2, 3, 4, c=5, d=6, e=-6.0)
|
||||||
|
assert args == (1, 2, 3, 4)
|
||||||
|
assert kwargs == {'c': 5, 'd': 6, 'e': -6.0}
|
Loading…
x
Reference in New Issue
Block a user