mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
add goto & Threaded VM
This commit is contained in:
parent
2192941bc8
commit
7079b66a64
@ -15,4 +15,6 @@
|
||||
#include <chrono>
|
||||
#include <string_view>
|
||||
#include <queue>
|
||||
#include <iomanip>
|
||||
#include <iomanip>
|
||||
|
||||
#include <thread>
|
@ -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){
|
||||
|
@ -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())));
|
||||
|
@ -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
|
@ -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",
|
||||
|
@ -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]);
|
||||
|
69
src/vm.h
69
src/vm.h
@ -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 *****/
|
||||
@ -892,4 +904,57 @@ 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;
|
||||
}
|
||||
}
|
||||
};
|
11
tests/3.py
11
tests/3.py
@ -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")
|
Loading…
x
Reference in New Issue
Block a user