This commit is contained in:
blueloveTH 2023-04-15 18:37:23 +08:00
parent 37db7bc29b
commit c01a77d4b4
9 changed files with 77 additions and 30 deletions

View File

@ -165,6 +165,16 @@ __NEXT_STEP:;
TARGET(STORE_FAST) TARGET(STORE_FAST)
frame->_locals[byte.arg] = POPX(); frame->_locals[byte.arg] = POPX();
DISPATCH(); DISPATCH();
TARGET(STORE_NAME) {
StrName name(byte.arg);
PyObject* val = POPX();
if(frame->_locals.is_valid()){
bool ok = frame->_locals.try_set(name, val);
if(!ok) vm->NameError(name);
}else{
frame->f_globals().set(name, val);
}
} DISPATCH();
TARGET(STORE_GLOBAL) { TARGET(STORE_GLOBAL) {
StrName name(byte.arg); StrName name(byte.arg);
frame->f_globals().set(name, POPX()); frame->f_globals().set(name, POPX());
@ -188,6 +198,16 @@ __NEXT_STEP:;
if(val == nullptr) vm->NameError(co->varnames[byte.arg]); if(val == nullptr) vm->NameError(co->varnames[byte.arg]);
frame->_locals[byte.arg] = nullptr; frame->_locals[byte.arg] = nullptr;
} DISPATCH(); } DISPATCH();
TARGET(DELETE_NAME) {
StrName name(byte.arg);
if(frame->_locals.is_valid()){
if(!frame->_locals.contains(name)) vm->NameError(name);
frame->_locals.erase(name);
}else{
if(!frame->f_globals().contains(name)) vm->NameError(name);
frame->f_globals().erase(name);
}
} DISPATCH();
TARGET(DELETE_GLOBAL) { TARGET(DELETE_GLOBAL) {
StrName name(byte.arg); StrName name(byte.arg);
if(frame->f_globals().contains(name)){ if(frame->f_globals().contains(name)){

View File

@ -5,7 +5,7 @@
namespace pkpy{ namespace pkpy{
enum NameScope { NAME_LOCAL, NAME_GLOBAL }; enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
enum Opcode { enum Opcode {
#define OPCODE(name) OP_##name, #define OPCODE(name) OP_##name,

View File

@ -21,6 +21,7 @@ class Compiler {
std::unique_ptr<Lexer> lexer; std::unique_ptr<Lexer> lexer;
stack<CodeEmitContext> contexts; stack<CodeEmitContext> contexts;
VM* vm; VM* vm;
bool unknown_global_scope; // for eval/exec() call
bool used; bool used;
// for parsing token stream // for parsing token stream
int i = 0; int i = 0;
@ -37,7 +38,11 @@ class Compiler {
CodeEmitContext* ctx() { return &contexts.top(); } CodeEmitContext* ctx() { return &contexts.top(); }
CompileMode mode() const{ return lexer->src->mode; } CompileMode mode() const{ return lexer->src->mode; }
NameScope name_scope() const { return contexts.size()>1 ? NAME_LOCAL : NAME_GLOBAL; } NameScope name_scope() const {
auto s = contexts.size()>1 ? NAME_LOCAL : NAME_GLOBAL;
if(unknown_global_scope && s == NAME_GLOBAL) s = NAME_GLOBAL_UNKNOWN;
return s;
}
CodeObject_ push_global_context(){ CodeObject_ push_global_context(){
CodeObject_ co = make_sp<CodeObject>(lexer->src, lexer->src->filename); CodeObject_ co = make_sp<CodeObject>(lexer->src, lexer->src->filename);
@ -977,9 +982,10 @@ __SUBSCR_END:
void IndentationError(Str msg){ lexer->throw_err("IndentationError", msg, err().line, err().start); } void IndentationError(Str msg){ lexer->throw_err("IndentationError", msg, err().line, err().start); }
public: public:
Compiler(VM* vm, const Str& source, const Str& filename, CompileMode mode){ Compiler(VM* vm, const Str& source, const Str& filename, CompileMode mode, bool unknown_global_scope=false){
this->vm = vm; this->vm = vm;
this->used = false; this->used = false;
this->unknown_global_scope = unknown_global_scope;
this->lexer = std::make_unique<Lexer>( this->lexer = std::make_unique<Lexer>(
make_sp<SourceData>(source, filename, mode) make_sp<SourceData>(source, filename, mode)
); );

View File

@ -136,6 +136,8 @@ struct NameExpr: Expr{
ctx->emit(OP_LOAD_FAST, index, line); ctx->emit(OP_LOAD_FAST, index, line);
}else{ }else{
Opcode op = ctx->level <= 1 ? OP_LOAD_GLOBAL : OP_LOAD_NONLOCAL; Opcode op = ctx->level <= 1 ? OP_LOAD_GLOBAL : OP_LOAD_NONLOCAL;
// we cannot determine the scope when calling exec()/eval()
if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
ctx->emit(op, StrName(name).index, line); ctx->emit(op, StrName(name).index, line);
} }
} }
@ -148,6 +150,9 @@ struct NameExpr: Expr{
case NAME_GLOBAL: case NAME_GLOBAL:
ctx->emit(OP_DELETE_GLOBAL, StrName(name).index, line); ctx->emit(OP_DELETE_GLOBAL, StrName(name).index, line);
break; break;
case NAME_GLOBAL_UNKNOWN:
ctx->emit(OP_DELETE_NAME, StrName(name).index, line);
break;
default: FATAL_ERROR(); break; default: FATAL_ERROR(); break;
} }
return true; return true;
@ -166,6 +171,9 @@ struct NameExpr: Expr{
case NAME_GLOBAL: case NAME_GLOBAL:
ctx->emit(OP_STORE_GLOBAL, StrName(name).index, line); ctx->emit(OP_STORE_GLOBAL, StrName(name).index, line);
break; break;
case NAME_GLOBAL_UNKNOWN:
ctx->emit(OP_STORE_NAME, StrName(name).index, line);
break;
default: FATAL_ERROR(); break; default: FATAL_ERROR(); break;
} }
return true; return true;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "codeobject.h" #include "codeobject.h"
#include "common.h"
#include "memory.h" #include "memory.h"
#include "vector.h" #include "vector.h"
@ -35,6 +36,17 @@ struct FastLocals{
return a[index]; return a[index];
} }
bool contains(StrName name){
return varnames_inv->contains(name);
}
void erase(StrName name){
if(!is_valid()) return;
int index = varnames_inv->try_get(name);
if(index == -1) FATAL_ERROR();
a[index] = nullptr;
}
bool try_set(StrName name, PyObject* value){ bool try_set(StrName name, PyObject* value){
if(!is_valid()) return false; if(!is_valid()) return false;
int index = varnames_inv->try_get(name); int index = varnames_inv->try_get(name);

View File

@ -27,11 +27,13 @@ OPCODE(LOAD_METHOD)
OPCODE(LOAD_SUBSCR) OPCODE(LOAD_SUBSCR)
OPCODE(STORE_FAST) OPCODE(STORE_FAST)
OPCODE(STORE_NAME)
OPCODE(STORE_GLOBAL) OPCODE(STORE_GLOBAL)
OPCODE(STORE_ATTR) OPCODE(STORE_ATTR)
OPCODE(STORE_SUBSCR) OPCODE(STORE_SUBSCR)
OPCODE(DELETE_FAST) OPCODE(DELETE_FAST)
OPCODE(DELETE_NAME)
OPCODE(DELETE_GLOBAL) OPCODE(DELETE_GLOBAL)
OPCODE(DELETE_ATTR) OPCODE(DELETE_ATTR)
OPCODE(DELETE_SUBSCR) OPCODE(DELETE_SUBSCR)

View File

@ -11,8 +11,8 @@
namespace pkpy { namespace pkpy {
inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) { inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode, bool unknown_global_scope) {
Compiler compiler(this, source, filename, mode); Compiler compiler(this, source, filename, mode, unknown_global_scope);
try{ try{
return compiler.compile(); return compiler.compile();
}catch(Exception& e){ }catch(Exception& e){
@ -97,13 +97,13 @@ inline void init_builtins(VM* _vm) {
}); });
_vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) { _vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) {
CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<eval>", EVAL_MODE); CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<eval>", EVAL_MODE, true);
FrameId frame = vm->top_frame(); FrameId frame = vm->top_frame();
return vm->_exec(code.get(), frame->_module, frame->_locals, nullptr); return vm->_exec(code.get(), frame->_module, frame->_locals, nullptr);
}); });
_vm->bind_builtin_func<1>("exec", [](VM* vm, Args& args) { _vm->bind_builtin_func<1>("exec", [](VM* vm, Args& args) {
CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<exec>", EXEC_MODE); CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<exec>", EXEC_MODE, true);
FrameId frame = vm->top_frame(); FrameId frame = vm->top_frame();
vm->_exec(code.get(), frame->_module, frame->_locals, nullptr); vm->_exec(code.get(), frame->_module, frame->_locals, nullptr);
return vm->None; return vm->None;

View File

@ -333,7 +333,7 @@ public:
_lazy_modules.clear(); _lazy_modules.clear();
} }
CodeObject_ compile(Str source, Str filename, CompileMode mode); CodeObject_ compile(Str source, Str filename, CompileMode mode, bool unknown_global_scope=false);
PyObject* num_negated(PyObject* obj); PyObject* num_negated(PyObject* obj);
f64 num_to_float(PyObject* obj); f64 num_to_float(PyObject* obj);
bool asBool(PyObject* obj); bool asBool(PyObject* obj);

View File

@ -1,33 +1,32 @@
assert eval('1+1') == 2 assert eval('1+1') == 2
assert eval('[1,2,3]') == [1,2,3] assert eval('[1,2,3]') == [1,2,3]
# some bugs here def f(x):
# def f(x): return eval('x')
# return eval('x')
# assert f(1) == 1 assert f(1) == 1
# a = 0 a = 0
# assert eval('a') == 0 assert eval('a') == 0
# exec('a = 1') exec('a = 1')
# assert a == 1 assert a == 1
# def f(x): def f(a):
# exec('a = x') exec('a = 3')
# return a return a
# assert f(2) == 2 assert f(2) == 3
# exec( exec(
# "exec('a = eval(\"3 + 5\")')" "exec('a = eval(\"3 + 5\")')"
# ) )
# assert a == 8 assert a == 8
# def f(): def f():
# b = 1 b = 1
# exec( exec(
# "exec('b = eval(\"3 + 5\")')" "exec('b = eval(\"3 + 5\")')"
# ) )
# assert b == 8 assert b == 8