This commit is contained in:
blueloveTH 2023-04-02 14:46:59 +08:00
parent 449fb9a2f8
commit d54cd84138
7 changed files with 131 additions and 315 deletions

View File

@ -8,7 +8,7 @@ with open("src/opcodes.h", "rt", encoding='utf-8') as f:
pipeline = [
["common.h", "memory.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
["obj.h", "codeobject.h", "frame.h"],
["gc.h", "vm.h", "ref.h", "ceval.h", "compiler.h", "repl.h"],
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
["iter.h", "cffi.h", "io.h", "_generated.h", "pocketpy.h"]
]

View File

@ -2,7 +2,6 @@
#include "common.h"
#include "vm.h"
#include "ref.h"
namespace pkpy{
@ -135,10 +134,11 @@ inline PyObject* VM::run_frame(Frame* frame){
PyObject* cls = frame->top();
cls->attr().set(name.first, std::move(obj));
} continue;
case OP_RETURN_VALUE: return frame->pop_value(this);
case OP_RETURN_VALUE: return frame->popx();
case OP_PRINT_EXPR: {
PyObject* expr = frame->top_value(this);
PyObject* expr = frame->top(); // use top() here to avoid accidental gc
if(expr != None) *_stdout << CAST(Str, asRepr(expr)) << '\n';
frame->pop();
} continue;
case OP_POP_TOP: frame->_pop(); continue;
case OP_BINARY_OP: {
@ -239,7 +239,7 @@ inline PyObject* VM::run_frame(Frame* frame){
PyObject* obj = frame->pop_value(this);
call(frame->top_1(), "add", Args{obj});
} continue;
case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
case OP_DUP_TOP: frame->push(frame->top()); continue;
case OP_UNARY_STAR: {
if(byte.arg > 0){ // rvalue
frame->top() = VAR(StarWrapper(frame->top_value(this), true));

View File

@ -5,12 +5,7 @@
namespace pkpy{
enum NameScope {
NAME_LOCAL = 0,
NAME_GLOBAL,
NAME_ATTR,
NAME_SPECIAL,
};
enum NameScope { NAME_LOCAL, NAME_GLOBAL };
enum Opcode {
#define OPCODE(name) OP_##name,

View File

@ -24,10 +24,18 @@ class Compiler {
std::unique_ptr<Lexer> lexer;
stack<CodeEmitContext> contexts;
std::map<TokenIndex, PrattRule> rules;
bool used = false;
VM* vm;
bool used;
// for parsing token stream
int i = 0;
std::vector<Token> tokens;
const Token& prev() { return tokens.at(i-1); }
const Token& curr() { return tokens.at(i); }
const Token& next() { return tokens.at(i+1); }
const Token& peek(int offset) { return tokens.at(i+offset); }
void advance() { i++; }
CodeObject* co() const{ return contexts.top().co.get(); }
CodeEmitContext* ctx() { return &contexts.top(); }
CompileMode mode() const{ return lexer->src->mode; }
NameScope name_scope() const { return contexts.size()>1 ? NAME_LOCAL : NAME_GLOBAL; }
@ -41,6 +49,7 @@ class Compiler {
void pop_context(){
if(!ctx()->s_expr.empty()) UNREACHABLE();
// if last instruction is not return, add a default return None
if(ctx()->co->codes.back().op != OP_RETURN_VALUE){
ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
@ -52,6 +61,7 @@ class Compiler {
public:
Compiler(VM* vm, const char* source, Str filename, CompileMode mode){
this->vm = vm;
this->used = false;
this->lexer = std::make_unique<Lexer>(
make_sp<SourceData>(source, filename, mode)
);
@ -60,25 +70,32 @@ public:
#define METHOD(name) &Compiler::name
#define NO_INFIX nullptr, PREC_NONE
for(TokenIndex i=0; i<kTokenCount; i++) rules[i] = { nullptr, NO_INFIX };
rules[TK(".")] = { nullptr, METHOD(exprAttrib), PREC_ATTRIB };
rules[TK("(")] = { METHOD(exprGroup), METHOD(exprCall), PREC_CALL };
rules[TK("[")] = { METHOD(exprList), METHOD(exprSubscr), PREC_SUBSCRIPT };
rules[TK("{")] = { METHOD(exprMap), NO_INFIX };
rules[TK("%")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM };
rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM };
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_EXPONENT };
rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY };
rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY };
rules[TK(">=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
rules[TK("<=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
rules[TK(".")] = { nullptr, METHOD(exprAttrib), PREC_ATTRIB };
rules[TK("(")] = { METHOD(exprGroup), METHOD(exprCall), PREC_CALL };
rules[TK("[")] = { METHOD(exprList), METHOD(exprSubscr), PREC_SUBSCRIPT };
rules[TK("{")] = { METHOD(exprMap), NO_INFIX };
rules[TK("%")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM };
rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM };
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_EXPONENT };
rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY };
rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY };
rules[TK(">=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
rules[TK("<=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION };
rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
rules[TK("<<")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT };
rules[TK(">>")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT };
rules[TK("&")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_AND };
rules[TK("|")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_OR };
rules[TK("^")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_XOR };
rules[TK("?")] = { nullptr, METHOD(exprTernary), PREC_TERNARY };
rules[TK(",")] = { nullptr, METHOD(exprTuple), PREC_TUPLE };
rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
rules[TK("is not")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };
rules[TK("and") ] = { nullptr, METHOD(exprAnd), PREC_LOGICAL_AND };
@ -93,13 +110,6 @@ public:
rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX };
rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX };
rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX };
rules[TK("?")] = { nullptr, METHOD(exprTernary), PREC_TERNARY };
rules[TK(",")] = { nullptr, METHOD(exprTuple), PREC_TUPLE };
rules[TK("<<")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT };
rules[TK(">>")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT };
rules[TK("&")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_AND };
rules[TK("|")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_OR };
rules[TK("^")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_XOR };
#undef METHOD
#undef NO_INFIX
@ -118,15 +128,6 @@ public:
}
private:
int i = 0;
std::vector<Token> tokens;
const Token& prev() { return tokens.at(i-1); }
const Token& curr() { return tokens.at(i); }
const Token& next() { return tokens.at(i+1); }
const Token& peek(int offset) { return tokens.at(i+offset); }
void advance() { i++; }
bool match(TokenIndex expected) {
if (curr().type != expected) return false;
advance();
@ -164,12 +165,14 @@ private:
if (!match_end_stmt()) SyntaxError("expected statement end");
}
void EXPR(ExprAction action=EXPR_PUSH_STACK) {
parse_expression(PREC_TUPLE + 1, action);
/*************************************************/
void EXPR(bool push_stack=true) {
parse_expression(PREC_TUPLE+1, push_stack);
}
void EXPR_TUPLE(ExprAction action=EXPR_PUSH_STACK) {
parse_expression(PREC_TUPLE, action);
void EXPR_TUPLE(bool push_stack=true) {
parse_expression(PREC_TUPLE, push_stack);
}
template <typename T, typename... Args>
@ -179,8 +182,6 @@ private:
return expr;
}
/********************************************/
// PASS
void exprLiteral(){
ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value));
@ -201,63 +202,12 @@ private:
consume(TK(":"));
}
e->func.code = push_context(lexer->src, "<lambda>");
// https://github.com/blueloveTH/pocketpy/issues/37
EXPR(true);
EXPR(true); // https://github.com/blueloveTH/pocketpy/issues/37
ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
pop_context();
ctx()->s_expr.push(std::move(e));
}
void exprAssign(){
// if(co()->codes.empty()) UNREACHABLE();
// bool is_load_name_ref = co()->codes.back().op == OP_LOAD_NAME_REF;
// int _name_arg = co()->codes.back().arg;
// // if the last op is OP_LOAD_NAME_REF, remove it
// // because we will emit OP_STORE_NAME or OP_STORE_CLASS_ATTR
// if(is_load_name_ref) co()->codes.pop_back();
// co()->_rvalue += 1;
// TokenIndex op = prev().type;
// if(op == TK("=")) { // a = (expr)
// EXPR_TUPLE();
// if(is_load_name_ref){
// auto op = ctx()->is_compiling_class ? OP_STORE_CLASS_ATTR : OP_STORE_NAME;
// emit(op, _name_arg);
// }else{
// if(ctx()->is_compiling_class) SyntaxError();
// emit(OP_STORE_REF);
// }
// }else{ // a += (expr) -> a = a + (expr)
// if(ctx()->is_compiling_class) SyntaxError();
// if(is_load_name_ref){
// emit(OP_LOAD_NAME, _name_arg);
// }else{
// emit(OP_DUP_TOP_VALUE);
// }
// EXPR();
// switch (op) {
// case TK("+="): emit(OP_BINARY_OP, 0); break;
// case TK("-="): emit(OP_BINARY_OP, 1); break;
// case TK("*="): emit(OP_BINARY_OP, 2); break;
// case TK("/="): emit(OP_BINARY_OP, 3); break;
// case TK("//="): emit(OP_BINARY_OP, 4); break;
// case TK("%="): emit(OP_BINARY_OP, 5); break;
// case TK("<<="): emit(OP_BITWISE_OP, 0); break;
// case TK(">>="): emit(OP_BITWISE_OP, 1); break;
// case TK("&="): emit(OP_BITWISE_OP, 2); break;
// case TK("|="): emit(OP_BITWISE_OP, 3); break;
// case TK("^="): emit(OP_BITWISE_OP, 4); break;
// default: UNREACHABLE();
// }
// if(is_load_name_ref){
// emit(OP_STORE_NAME, _name_arg);
// }else{
// emit(OP_STORE_REF);
// }
// }
// co()->_rvalue -= 1;
}
// PASS
void exprTuple(){
auto e = make_expr<TupleExpr>();
@ -540,17 +490,17 @@ private:
return;
}
do {
ctx()->emit(OP_DUP_TOP_VALUE, BC_NOARG, BC_KEEPLINE);
ctx()->emit(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
consume(TK("@id"));
Str name = prev().str();
int index = ctx()->add_name(name, NAME_ATTR);
ctx()->emit(OP_BUILD_ATTR, index, prev().line);
int index = ctx()->add_name(name);
ctx()->emit(OP_LOAD_ATTR, index, prev().line);
if (match(TK("as"))) {
consume(TK("@id"));
name = prev().str();
}
index = ctx()->add_name(name, name_scope());
ctx()->emit(OP_STORE_NAME, index, prev().line);
index = ctx()->add_name(name);
ctx()->emit(OP_STORE_GLOBAL, index, prev().line);
} while (match(TK(",")));
ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
consume_end_stmt();
@ -650,7 +600,20 @@ private:
}
bool try_compile_assignment(){
// switch (op) {
// case TK("+="): emit(OP_BINARY_OP, 0); break;
// case TK("-="): emit(OP_BINARY_OP, 1); break;
// case TK("*="): emit(OP_BINARY_OP, 2); break;
// case TK("/="): emit(OP_BINARY_OP, 3); break;
// case TK("//="): emit(OP_BINARY_OP, 4); break;
// case TK("%="): emit(OP_BINARY_OP, 5); break;
// case TK("<<="): emit(OP_BITWISE_OP, 0); break;
// case TK(">>="): emit(OP_BITWISE_OP, 1); break;
// case TK("&="): emit(OP_BITWISE_OP, 2); break;
// case TK("|="): emit(OP_BITWISE_OP, 3); break;
// case TK("^="): emit(OP_BITWISE_OP, 4); break;
// default: UNREACHABLE();
// }
}
void compile_stmt() {
@ -728,16 +691,18 @@ private:
consume_end_stmt();
} break;
case TK("with"): {
EXPR(true);
consume(TK("as"));
consume(TK("@id"));
int index = ctx()->add_name(prev().str(), name_scope());
emit(OP_STORE_NAME, index);
emit(OP_LOAD_NAME_REF, index);
emit(OP_WITH_ENTER);
compile_block_body();
emit(OP_LOAD_NAME_REF, index);
emit(OP_WITH_EXIT);
// TODO: reimpl this
UNREACHABLE();
// EXPR(true);
// consume(TK("as"));
// consume(TK("@id"));
// int index = ctx()->add_name(prev().str(), name_scope());
// emit(OP_STORE_NAME, index);
// emit(OP_LOAD_NAME_REF, index);
// emit(OP_WITH_ENTER);
// compile_block_body();
// emit(OP_LOAD_NAME_REF, index);
// emit(OP_WITH_EXIT);
} break;
/*************************************************/
// TODO: refactor goto/label use special $ syntax
@ -749,21 +714,21 @@ private:
consume_end_stmt();
break;
case TK("goto"):
if(mode() != EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
if(mode()!=EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
consume(TK(".")); consume(TK("@id"));
emit(OP_GOTO, co()->add_name(prev().str(), NAME_SPECIAL));
consume_end_stmt();
break;
/*************************************************/
// dangling expression or assignment
// handle dangling expression or assignment
default: {
EXPR_TUPLE(true);
bool assigment = try_compile_assignment();
if(!assigment){
if(!try_compile_assignment()){
if(mode()==REPL_MODE && name_scope()==NAME_GLOBAL){
emit(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE);
}else{
emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
}
emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
}
consume_end_stmt();
}

View File

@ -594,4 +594,46 @@ struct TernaryExpr: Expr{
};
} // namespace pkpy
} // namespace pkpy
// struct TupleRef : BaseRef {
// Tuple objs;
// TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
// PyObject* get(VM* vm, Frame* frame) const{
// Tuple args(objs.size());
// for (int i = 0; i < objs.size(); i++) {
// args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
// }
// return VAR(std::move(args));
// }
// void set(VM* vm, Frame* frame, PyObject* val) const{
// val = vm->asIter(val);
// BaseIter* iter = vm->PyIter_AS_C(val);
// for(int i=0; i<objs.size(); i++){
// PyObject* x;
// if(is_type(objs[i], vm->tp_star_wrapper)){
// auto& star = _CAST(StarWrapper&, objs[i]);
// if(star.rvalue) vm->ValueError("can't use starred expression here");
// if(i != objs.size()-1) vm->ValueError("* can only be used at the end");
// auto ref = vm->PyRef_AS_C(star.obj);
// List list;
// while((x = iter->next()) != nullptr) list.push_back(x);
// ref->set(vm, frame, VAR(std::move(list)));
// return;
// }else{
// x = iter->next();
// if(x == nullptr) vm->ValueError("not enough values to unpack");
// vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
// }
// }
// PyObject* x = iter->next();
// if(x != nullptr) vm->ValueError("too many values to unpack");
// }
// void del(VM* vm, Frame* frame) const{
// for(int i=0; i<objs.size(); i++) vm->PyRef_AS_C(objs[i])->del(vm, frame);
// }
// };

View File

@ -2,7 +2,7 @@
OPCODE(NO_OP)
OPCODE(POP_TOP)
OPCODE(DUP_TOP_VALUE)
OPCODE(DUP_TOP)
OPCODE(CALL)
OPCODE(CALL_UNPACK)
OPCODE(CALL_KWARGS)
@ -57,20 +57,13 @@ OPCODE(LOAD_FALSE)
OPCODE(LOAD_EVAL_FN)
OPCODE(LOAD_FUNCTION)
OPCODE(LOAD_ELLIPSIS)
OPCODE(LOAD_NAME)
OPCODE(LOAD_NAME_REF)
OPCODE(ASSERT)
OPCODE(EXCEPTION_MATCH)
OPCODE(RAISE)
OPCODE(RE_RAISE)
OPCODE(BUILD_INDEX)
OPCODE(BUILD_ATTR)
OPCODE(BUILD_ATTR_REF)
OPCODE(STORE_NAME)
OPCODE(STORE_FUNCTION)
OPCODE(STORE_REF)
OPCODE(TRY_BLOCK_ENTER)
OPCODE(TRY_BLOCK_EXIT)

179
src/ref.h
View File

@ -1,179 +0,0 @@
#pragma once
#include "obj.h"
#include "vm.h"
namespace pkpy {
struct BaseRef {
virtual PyObject* get(VM*, Frame*) const = 0;
virtual void set(VM*, Frame*, PyObject*) const = 0;
virtual void del(VM*, Frame*) const = 0;
virtual ~BaseRef() = default;
};
struct NameRef : BaseRef {
const std::pair<StrName, NameScope> pair;
StrName name() const { return pair.first; }
NameScope scope() const { return pair.second; }
NameRef(const std::pair<StrName, NameScope>& pair) : pair(pair) {}
PyObject* get(VM* vm, Frame* frame) const{
PyObject* val;
val = frame->f_locals().try_get(name());
if(val != nullptr) return val;
val = frame->f_closure_try_get(name());
if(val != nullptr) return val;
val = frame->f_globals().try_get(name());
if(val != nullptr) return val;
val = vm->builtins->attr().try_get(name());
if(val != nullptr) return val;
vm->NameError(name());
return nullptr;
}
void set(VM* vm, Frame* frame, PyObject* val) const{
switch(scope()) {
case NAME_LOCAL: frame->f_locals().set(name(), val); break;
case NAME_GLOBAL:
if(frame->f_locals().try_set(name(), val)) return;
frame->f_globals().set(name(), val);
break;
default: UNREACHABLE();
}
}
void del(VM* vm, Frame* frame) const{
switch(scope()) {
case NAME_LOCAL: {
if(frame->f_locals().contains(name())){
frame->f_locals().erase(name());
}else{
vm->NameError(name());
}
} break;
case NAME_GLOBAL:
{
if(frame->f_locals().contains(name())){
frame->f_locals().erase(name());
}else{
if(frame->f_globals().contains(name())){
frame->f_globals().erase(name());
}else{
vm->NameError(name());
}
}
} break;
default: UNREACHABLE();
}
}
};
struct AttrRef : BaseRef {
mutable PyObject* obj;
NameRef attr;
AttrRef(PyObject* obj, NameRef attr) : obj(obj), attr(attr) {}
PyObject* get(VM* vm, Frame* frame) const{
return vm->getattr(obj, attr.name());
}
void set(VM* vm, Frame* frame, PyObject* val) const{
vm->setattr(obj, attr.name(), std::move(val));
}
};
struct IndexRef : BaseRef {
mutable PyObject* obj;
PyObject* index;
IndexRef(PyObject* obj, PyObject* index) : obj(obj), index(index) {}
PyObject* get(VM* vm, Frame* frame) const{
return vm->fast_call(__getitem__, Args{obj, index});
}
void set(VM* vm, Frame* frame, PyObject* val) const{
vm->fast_call(__setitem__, Args{obj, index, val});
}
void del(VM* vm, Frame* frame) const{
vm->fast_call(__delitem__, Args{obj, index});
}
};
struct TupleRef : BaseRef {
Tuple objs;
TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
PyObject* get(VM* vm, Frame* frame) const{
Tuple args(objs.size());
for (int i = 0; i < objs.size(); i++) {
args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
}
return VAR(std::move(args));
}
void set(VM* vm, Frame* frame, PyObject* val) const{
val = vm->asIter(val);
BaseIter* iter = vm->PyIter_AS_C(val);
for(int i=0; i<objs.size(); i++){
PyObject* x;
if(is_type(objs[i], vm->tp_star_wrapper)){
auto& star = _CAST(StarWrapper&, objs[i]);
if(star.rvalue) vm->ValueError("can't use starred expression here");
if(i != objs.size()-1) vm->ValueError("* can only be used at the end");
auto ref = vm->PyRef_AS_C(star.obj);
List list;
while((x = iter->next()) != nullptr) list.push_back(x);
ref->set(vm, frame, VAR(std::move(list)));
return;
}else{
x = iter->next();
if(x == nullptr) vm->ValueError("not enough values to unpack");
vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
}
}
PyObject* x = iter->next();
if(x != nullptr) vm->ValueError("too many values to unpack");
}
void del(VM* vm, Frame* frame) const{
for(int i=0; i<objs.size(); i++) vm->PyRef_AS_C(objs[i])->del(vm, frame);
}
};
template<typename P>
PyObject* VM::PyRef(P&& value) {
static_assert(std::is_base_of_v<BaseRef, std::decay_t<P>>);
return heap.gcnew<P>(tp_ref, std::forward<P>(value));
}
inline const BaseRef* VM::PyRef_AS_C(PyObject* obj)
{
if(!is_type(obj, tp_ref)) TypeError("expected an l-value");
return static_cast<const BaseRef*>(obj->value());
}
/***** Frame's Impl *****/
inline void Frame::try_deref(VM* vm, PyObject*& v){
if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this);
}
/***** GC's Impl *****/
template<> inline void _mark<AttrRef>(AttrRef& t){
OBJ_MARK(t.obj);
}
template<> inline void _mark<IndexRef>(IndexRef& t){
OBJ_MARK(t.obj);
OBJ_MARK(t.index);
}
template<> inline void _mark<TupleRef>(TupleRef& t){
_mark<Tuple>(t.objs);
}
} // namespace pkpy