mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-25 05:50:17 +00:00
...
This commit is contained in:
parent
468f7a3c22
commit
849c6aabb5
@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
icon: dot
|
icon: dot
|
||||||
order: 100
|
order: 100
|
||||||
|
title: Basic Features
|
||||||
---
|
---
|
||||||
|
|
||||||
# basic
|
# basic
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
icon: dot
|
icon: dot
|
||||||
|
title: Goto Statement
|
||||||
---
|
---
|
||||||
|
|
||||||
# goto/label
|
# goto/label
|
||||||
@ -25,7 +26,3 @@ for i in range(10):
|
|||||||
|
|
||||||
label .exit
|
label .exit
|
||||||
```
|
```
|
||||||
|
|
||||||
!!!
|
|
||||||
If we detect an illegal divert, you will get an `UnexpectedError` or the behaviour is undefined.
|
|
||||||
!!!
|
|
||||||
|
|||||||
10
docs/features/ub.md
Normal file
10
docs/features/ub.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
icon: dot
|
||||||
|
title: Undefined Behaviour
|
||||||
|
---
|
||||||
|
|
||||||
|
These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined if you do the following things.
|
||||||
|
|
||||||
|
1. Delete a builtin object. For example, `del int.__add__`.
|
||||||
|
2. Call an unbound method with the wrong type of `self`. For example, `int.__add__('1', 2)`.
|
||||||
|
3. Use goto statement to jump out of a context block.
|
||||||
@ -83,11 +83,12 @@ __NEXT_STEP:;
|
|||||||
TARGET(LOAD_FUNCTION) {
|
TARGET(LOAD_FUNCTION) {
|
||||||
FuncDecl_ decl = co->func_decls[byte.arg];
|
FuncDecl_ decl = co->func_decls[byte.arg];
|
||||||
bool is_simple = decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator;
|
bool is_simple = decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator;
|
||||||
|
int argc = decl->args.size();
|
||||||
PyObject* obj;
|
PyObject* obj;
|
||||||
if(decl->nested){
|
if(decl->nested){
|
||||||
obj = VAR(Function({decl, is_simple, frame->_module, frame->_locals.to_namedict()}));
|
obj = VAR(Function({decl, is_simple, argc, frame->_module, frame->_locals.to_namedict()}));
|
||||||
}else{
|
}else{
|
||||||
obj = VAR(Function({decl, is_simple, frame->_module}));
|
obj = VAR(Function({decl, is_simple, argc, frame->_module}));
|
||||||
}
|
}
|
||||||
PUSH(obj);
|
PUSH(obj);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
|
|||||||
@ -63,8 +63,9 @@ struct ValueStackImpl {
|
|||||||
// We allocate extra MAX_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
|
// We allocate extra MAX_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
|
||||||
PyObject* _begin[MAX_SIZE + MAX_SIZE/128];
|
PyObject* _begin[MAX_SIZE + MAX_SIZE/128];
|
||||||
PyObject** _sp;
|
PyObject** _sp;
|
||||||
|
PyObject** _max_end;
|
||||||
|
|
||||||
ValueStackImpl(): _sp(_begin) {}
|
ValueStackImpl(): _sp(_begin), _max_end(_begin + MAX_SIZE) {}
|
||||||
|
|
||||||
PyObject*& top(){ return _sp[-1]; }
|
PyObject*& top(){ return _sp[-1]; }
|
||||||
PyObject* top() const { return _sp[-1]; }
|
PyObject* top() const { return _sp[-1]; }
|
||||||
@ -90,7 +91,7 @@ struct ValueStackImpl {
|
|||||||
_sp = sp;
|
_sp = sp;
|
||||||
}
|
}
|
||||||
void clear() { _sp = _begin; }
|
void clear() { _sp = _begin; }
|
||||||
bool is_overflow() const { return _sp >= _begin + MAX_SIZE; }
|
bool is_overflow() const { return _sp >= _max_end; }
|
||||||
|
|
||||||
ValueStackImpl(const ValueStackImpl&) = delete;
|
ValueStackImpl(const ValueStackImpl&) = delete;
|
||||||
ValueStackImpl(ValueStackImpl&&) = delete;
|
ValueStackImpl(ValueStackImpl&&) = delete;
|
||||||
|
|||||||
@ -47,6 +47,7 @@ using FuncDecl_ = shared_ptr<FuncDecl>;
|
|||||||
struct Function{
|
struct Function{
|
||||||
FuncDecl_ decl;
|
FuncDecl_ decl;
|
||||||
bool is_simple;
|
bool is_simple;
|
||||||
|
int argc; // cached argc
|
||||||
PyObject* _module;
|
PyObject* _module;
|
||||||
NameDict_ _closure;
|
NameDict_ _closure;
|
||||||
};
|
};
|
||||||
|
|||||||
17
src/vm.h
17
src/vm.h
@ -1001,12 +1001,11 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
|
|||||||
|
|
||||||
const Function& fn = CAST(Function&, callable);
|
const Function& fn = CAST(Function&, callable);
|
||||||
const CodeObject* co = fn.decl->code.get();
|
const CodeObject* co = fn.decl->code.get();
|
||||||
PyObject* _module = fn._module != nullptr ? fn._module : callstack.top()._module;
|
|
||||||
|
|
||||||
if(args.size() < fn.decl->args.size()){
|
if(args.size() < fn.argc){
|
||||||
vm->TypeError(fmt(
|
vm->TypeError(fmt(
|
||||||
"expected ",
|
"expected ",
|
||||||
fn.decl->args.size(),
|
fn.argc,
|
||||||
" positional arguments, but got ",
|
" positional arguments, but got ",
|
||||||
args.size(),
|
args.size(),
|
||||||
" (", fn.decl->code->name, ')'
|
" (", fn.decl->code->name, ')'
|
||||||
@ -1015,11 +1014,11 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
|
|||||||
|
|
||||||
// if this function is simple, a.k.a, no kwargs and no *args and not a generator
|
// if this function is simple, a.k.a, no kwargs and no *args and not a generator
|
||||||
// we can use a fast path to avoid using buffer copy
|
// we can use a fast path to avoid using buffer copy
|
||||||
if(fn.is_simple && kwargs.size()==0){
|
if(fn.is_simple){
|
||||||
if(args.size() > fn.decl->args.size()) TypeError("too many positional arguments");
|
if(args.size() > fn.argc) TypeError("too many positional arguments");
|
||||||
int spaces = co->varnames.size() - fn.decl->args.size();
|
int spaces = co->varnames.size() - fn.argc;
|
||||||
for(int j=0; j<spaces; j++) PUSH(nullptr);
|
for(int j=0; j<spaces; j++) PUSH(nullptr);
|
||||||
callstack.emplace(&s_data, p0, co, _module, callable, FastLocals(co, args.begin()));
|
callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1062,7 +1061,7 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
|
|||||||
if(co->is_generator){
|
if(co->is_generator){
|
||||||
PyObject* ret = PyIter(Generator(
|
PyObject* ret = PyIter(Generator(
|
||||||
this,
|
this,
|
||||||
Frame(&s_data, nullptr, co, _module, callable),
|
Frame(&s_data, nullptr, co, fn._module, callable),
|
||||||
ArgsView(buffer, buffer + co->varnames.size())
|
ArgsView(buffer, buffer + co->varnames.size())
|
||||||
));
|
));
|
||||||
return ret;
|
return ret;
|
||||||
@ -1070,7 +1069,7 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
|
|||||||
|
|
||||||
// copy buffer to stack
|
// copy buffer to stack
|
||||||
for(int i=0; i<co->varnames.size(); i++) PUSH(buffer[i]);
|
for(int i=0; i<co->varnames.size(); i++) PUSH(buffer[i]);
|
||||||
callstack.emplace(&s_data, p0, co, _module, callable);
|
callstack.emplace(&s_data, p0, co, fn._module, callable);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user