add goto & Threaded VM

This commit is contained in:
blueloveTH 2022-11-14 15:19:39 +08:00
parent 2192941bc8
commit 7079b66a64
8 changed files with 114 additions and 8 deletions

View File

@ -16,3 +16,5 @@
#include <string_view>
#include <queue>
#include <iomanip>
#include <thread>

View File

@ -39,6 +39,19 @@ struct CodeObject {
PyVarList co_consts;
std::vector<std::shared_ptr<NamePointer>> co_names;
// for goto use
// note: some opcodes moves the bytecode, such as listcomp
// goto/label should be put at toplevel statements
std::unordered_map<_Str, int> co_labels;
void addLabel(const _Str& label){
if(co_labels.find(label) != co_labels.end()){
_Str msg = "label '" + label + "' already exists";
throw std::runtime_error(msg.c_str());
}
co_labels[label] = co_code.size();
}
int addName(const _Str& name, NameScope scope){
auto p = std::make_shared<NamePointer>(name, scope);
for(int i=0; i<co_names.size(); i++){
@ -139,6 +152,10 @@ public:
return v;
}
void __clearDataStack(){
s_data.clear();
}
inline PyVar __deref_pointer(VM*, PyVar);
inline PyVar popValue(VM* vm){

View File

@ -755,6 +755,17 @@ __LISTCOMP:
EXPR();
emitCode(OP_ASSERT);
consumeEndStatement();
} else if(match(TK("label"))){
if(mode() != EXEC_MODE) syntaxError("'label' is only available in EXEC_MODE");
consume(TK("@id"));
getCode()->addLabel(parser->previous.str());
consumeEndStatement();
} else if(match(TK("goto"))){
if(mode() != EXEC_MODE) syntaxError("'goto' is only available in EXEC_MODE");
consume(TK("@id"));
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));
emitCode(OP_GOTO);
consumeEndStatement();
} else if(match(TK("raise"))){
consume(TK("@id")); // dummy exception type
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));

View File

@ -56,4 +56,6 @@ OPCODE(DELETE_PTR) // no arg, [ptr] -> [] -> delete ptr
OPCODE(BUILD_SMART_TUPLE) // if all elements are pointers, build a compound pointer, otherwise build a tuple
OPCODE(BUILD_STRING) // arg is the expr count, build a string from the top of the stack
OPCODE(GOTO)
#endif

View File

@ -14,6 +14,7 @@ constexpr const char* __TOKENS[] = {
/** KW_BEGIN **/
"class", "import", "as", "def", "lambda", "pass", "del",
"None", "in", "is", "and", "or", "not", "True", "False", "global",
"goto", "label", // extended keywords, not available in cpython
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise",
/** KW_END **/
"is not", "not in",

View File

@ -47,6 +47,13 @@ void __initializeBuiltinFunctions(VM* _vm) {
return vm->None;
});
_vm->bindBuiltinFunc("input", [](VM* vm, PyVarList args) {
vm->__checkArgSize(args, 0);
ThreadedVM* tvm = dynamic_cast<ThreadedVM*>(vm);
if(tvm == nullptr) vm->typeError("input() can only be called in threaded mode");
return vm->PyStr(tvm->readStdin());
});
_vm->bindBuiltinFunc("eval", [](VM* vm, PyVarList args) {
vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]);

View File

@ -247,6 +247,16 @@ private:
frame->push(ret);
} break;
case OP_JUMP_ABSOLUTE: frame->jumpTo(byte.arg); break;
case OP_GOTO: {
PyVar obj = frame->popValue(this);
const _Str& label = PyStr_AS_C(obj);
auto it = frame->code->co_labels.find(label);
if(it == frame->code->co_labels.end()){
_error("KeyError", "label '" + label + "' not found");
}
frame->__clearDataStack();
frame->jumpTo(it->second);
} break;
case OP_GET_ITER:
{
PyVar obj = frame->popValue(this);
@ -315,7 +325,7 @@ private:
}
public:
PyVarDict _types; // builtin types
PyVarDict _types;
PyVar None, True, False;
PrintFn _stdout = [](const VM* vm, auto s){};
@ -774,6 +784,8 @@ public:
void _assert(bool val, const _Str& msg){
if (!val) _error("AssertionError", msg);
}
virtual ~VM() = default;
};
/***** Pointers' Impl *****/
@ -893,3 +905,56 @@ PyVar RangeIterator::next(){
PyVar StringIterator::next(){
return vm->PyStr(str->u8_getitem(index++));
}
class ThreadedVM : public VM {
std::thread* _thread;
bool _flag_thread_sleeping = false;
public:
_Str _stdin;
void sleep(){
if(_thread == nullptr) UNREACHABLE();
_flag_thread_sleeping = true;
// 50 fps is enough
while(!_flag_thread_sleeping) std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
void writeStdin(const _Str& s){
if(_thread == nullptr) UNREACHABLE();
_stdin = s;
wakeUp();
}
_Str readStdin(){
if(_thread == nullptr) UNREACHABLE();
_Str copy = _stdin;
_stdin = "";
return copy;
}
bool isSleeping(){
if(_thread == nullptr) UNREACHABLE();
return _flag_thread_sleeping;
}
void wakeUp(){
if(_thread == nullptr) UNREACHABLE();
_flag_thread_sleeping = false;
}
void startExec(const _Code& code){
if(_thread != nullptr) UNREACHABLE();
_thread = new std::thread([this, code](){
this->exec(code);
});
}
~ThreadedVM(){
if(_thread != nullptr){
_thread->join();
delete _thread;
}
}
};

View File

@ -1,5 +1,6 @@
k = 0
for i in range(2, 10000000):
if i % 2 == 0:
k += 1
print(k)
print("Welcome to the Python world!")
a = input()
print("You entered: " + a)
b = input()
print("You entered: " + b)
print("END")