mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 03:50:16 +00:00
add goto & Threaded VM
This commit is contained in:
parent
2192941bc8
commit
7079b66a64
@ -15,4 +15,6 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include <thread>
|
@ -39,6 +39,19 @@ struct CodeObject {
|
|||||||
PyVarList co_consts;
|
PyVarList co_consts;
|
||||||
std::vector<std::shared_ptr<NamePointer>> co_names;
|
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){
|
int addName(const _Str& name, NameScope scope){
|
||||||
auto p = std::make_shared<NamePointer>(name, scope);
|
auto p = std::make_shared<NamePointer>(name, scope);
|
||||||
for(int i=0; i<co_names.size(); i++){
|
for(int i=0; i<co_names.size(); i++){
|
||||||
@ -139,6 +152,10 @@ public:
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __clearDataStack(){
|
||||||
|
s_data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
inline PyVar __deref_pointer(VM*, PyVar);
|
inline PyVar __deref_pointer(VM*, PyVar);
|
||||||
|
|
||||||
inline PyVar popValue(VM* vm){
|
inline PyVar popValue(VM* vm){
|
||||||
|
@ -755,6 +755,17 @@ __LISTCOMP:
|
|||||||
EXPR();
|
EXPR();
|
||||||
emitCode(OP_ASSERT);
|
emitCode(OP_ASSERT);
|
||||||
consumeEndStatement();
|
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"))){
|
} else if(match(TK("raise"))){
|
||||||
consume(TK("@id")); // dummy exception type
|
consume(TK("@id")); // dummy exception type
|
||||||
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(parser->previous.str())));
|
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_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(BUILD_STRING) // arg is the expr count, build a string from the top of the stack
|
||||||
|
|
||||||
|
OPCODE(GOTO)
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -14,6 +14,7 @@ constexpr const char* __TOKENS[] = {
|
|||||||
/** KW_BEGIN **/
|
/** KW_BEGIN **/
|
||||||
"class", "import", "as", "def", "lambda", "pass", "del",
|
"class", "import", "as", "def", "lambda", "pass", "del",
|
||||||
"None", "in", "is", "and", "or", "not", "True", "False", "global",
|
"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",
|
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise",
|
||||||
/** KW_END **/
|
/** KW_END **/
|
||||||
"is not", "not in",
|
"is not", "not in",
|
||||||
|
@ -47,6 +47,13 @@ void __initializeBuiltinFunctions(VM* _vm) {
|
|||||||
return vm->None;
|
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->bindBuiltinFunc("eval", [](VM* vm, PyVarList args) {
|
||||||
vm->__checkArgSize(args, 1);
|
vm->__checkArgSize(args, 1);
|
||||||
const _Str& expr = vm->PyStr_AS_C(args[0]);
|
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);
|
frame->push(ret);
|
||||||
} break;
|
} break;
|
||||||
case OP_JUMP_ABSOLUTE: frame->jumpTo(byte.arg); 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:
|
case OP_GET_ITER:
|
||||||
{
|
{
|
||||||
PyVar obj = frame->popValue(this);
|
PyVar obj = frame->popValue(this);
|
||||||
@ -315,7 +325,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PyVarDict _types; // builtin types
|
PyVarDict _types;
|
||||||
PyVar None, True, False;
|
PyVar None, True, False;
|
||||||
|
|
||||||
PrintFn _stdout = [](const VM* vm, auto s){};
|
PrintFn _stdout = [](const VM* vm, auto s){};
|
||||||
@ -774,6 +784,8 @@ public:
|
|||||||
void _assert(bool val, const _Str& msg){
|
void _assert(bool val, const _Str& msg){
|
||||||
if (!val) _error("AssertionError", msg);
|
if (!val) _error("AssertionError", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual ~VM() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/***** Pointers' Impl *****/
|
/***** Pointers' Impl *****/
|
||||||
@ -892,4 +904,57 @@ PyVar RangeIterator::next(){
|
|||||||
|
|
||||||
PyVar StringIterator::next(){
|
PyVar StringIterator::next(){
|
||||||
return vm->PyStr(str->u8_getitem(index++));
|
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
|
print("Welcome to the Python world!")
|
||||||
for i in range(2, 10000000):
|
a = input()
|
||||||
if i % 2 == 0:
|
print("You entered: " + a)
|
||||||
k += 1
|
b = input()
|
||||||
print(k)
|
print("You entered: " + b)
|
||||||
|
print("END")
|
Loading…
x
Reference in New Issue
Block a user