This commit is contained in:
blueloveTH 2023-07-06 22:06:27 +08:00
commit 3e65101a0d
11 changed files with 95 additions and 44 deletions

35
.github/workflows/website.yml vendored Normal file
View File

@ -0,0 +1,35 @@
name: website
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
###################################################
- uses: actions/setup-node@v3.1.1
- name: Retype build
run: |
cd docs
npm install retypeapp --global
retype build
###################################################
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v12
with:
version: 3.1.25
actions-cache-folder: 'emsdk-cache'
- name: Compile
run: |
bash build_web.sh
mv web docs/.retype/static
###################################################
- uses: crazy-max/ghaction-github-pages@v3
with:
target_branch: gh-pages
build_dir: docs/.retype
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -20,11 +20,13 @@ endif()
if(MSVC) if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR- /EHsc /utf-8 /O2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR- /EHsc /utf-8 /O2")
else() else()
find_program(CLANGPP clang++) if (NOT EMSCRIPTEN)
if(CLANGPP) find_program(CLANGPP clang++)
message(STATUS "Using clang with libc++") if(CLANGPP)
set(CMAKE_CXX_COMPILER ${CLANGPP}) message(STATUS "Using clang with libc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") set(CMAKE_CXX_COMPILER ${CLANGPP})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
endif() endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fexceptions -O2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fexceptions -O2")

7
build_web.sh Normal file
View File

@ -0,0 +1,7 @@
python3 prebuild.py
rm -rf web/lib
mkdir web/lib
SRC=$(find src/ -name "*.cpp")
em++ $SRC -Iinclude/ -fno-rtti -fexceptions -O3 -sEXPORTED_FUNCTIONS=_pkpy_new_repl,_pkpy_repl_input,_pkpy_new_vm -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js

View File

@ -20,7 +20,7 @@
#include <variant> #include <variant>
#include <type_traits> #include <type_traits>
#define PK_VERSION "1.0.8" #define PK_VERSION "1.0.9"
#include "config.h" #include "config.h"

View File

@ -22,10 +22,7 @@ struct FastLocals{
FastLocals(const CodeObject* co, PyObject** a): varnames_inv(&co->varnames_inv), a(a) {} FastLocals(const CodeObject* co, PyObject** a): varnames_inv(&co->varnames_inv), a(a) {}
FastLocals(const FastLocals& other): varnames_inv(other.varnames_inv), a(other.a) {} FastLocals(const FastLocals& other): varnames_inv(other.varnames_inv), a(other.a) {}
PyObject* try_get(StrName name); PyObject** try_get_name(StrName name);
bool contains(StrName name);
void erase(StrName name);
bool try_set(StrName name, PyObject* value);
NameDict_ to_namedict(); NameDict_ to_namedict();
}; };

View File

@ -351,6 +351,7 @@ public:
void IndexError(const Str& msg){ _error("IndexError", msg); } void IndexError(const Str& msg){ _error("IndexError", msg); }
void ValueError(const Str& msg){ _error("ValueError", msg); } void ValueError(const Str& msg){ _error("ValueError", msg); }
void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); } void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }
void UnboundLocalError(StrName name){ _error("UnboundLocalError", fmt("local variable ", name.escape() + " referenced before assignment")); }
void KeyError(PyObject* obj){ _error("KeyError", PK_OBJ_GET(Str, py_repr(obj))); } void KeyError(PyObject* obj){ _error("KeyError", PK_OBJ_GET(Str, py_repr(obj))); }
void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); } void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); }

View File

@ -111,11 +111,15 @@ __NEXT_STEP:;
if(_0 == PY_NULL) vm->NameError(co->varnames[byte.arg]); if(_0 == PY_NULL) vm->NameError(co->varnames[byte.arg]);
PUSH(_0); PUSH(_0);
} DISPATCH(); } DISPATCH();
TARGET(LOAD_NAME) TARGET(LOAD_NAME) {
heap._auto_collect(); heap._auto_collect();
_name = StrName(byte.arg); _name = StrName(byte.arg);
_0 = frame->_locals.try_get(_name); PyObject** slot = frame->_locals.try_get_name(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); } if(slot != nullptr) {
if(*slot == PY_NULL) vm->UnboundLocalError(_name);
PUSH(*slot);
DISPATCH();
}
_0 = frame->f_closure_try_get(_name); _0 = frame->f_closure_try_get(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); } if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
_0 = frame->f_globals().try_get(_name); _0 = frame->f_globals().try_get(_name);
@ -123,7 +127,7 @@ __NEXT_STEP:;
_0 = vm->builtins->attr().try_get(_name); _0 = vm->builtins->attr().try_get(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH(); } if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
vm->NameError(_name); vm->NameError(_name);
DISPATCH(); } DISPATCH();
TARGET(LOAD_NONLOCAL) { TARGET(LOAD_NONLOCAL) {
heap._auto_collect(); heap._auto_collect();
_name = StrName(byte.arg); _name = StrName(byte.arg);
@ -164,16 +168,17 @@ __NEXT_STEP:;
TARGET(STORE_FAST) TARGET(STORE_FAST)
frame->_locals[byte.arg] = POPX(); frame->_locals[byte.arg] = POPX();
DISPATCH(); DISPATCH();
TARGET(STORE_NAME) TARGET(STORE_NAME){
_name = StrName(byte.arg); _name = StrName(byte.arg);
_0 = POPX(); _0 = POPX();
if(frame->_callable != nullptr){ if(frame->_callable != nullptr){
bool ok = frame->_locals.try_set(_name, _0); PyObject** slot = frame->_locals.try_get_name(_name);
if(!ok) vm->NameError(_name); if(slot == nullptr) vm->UnboundLocalError(_name);
*slot = _0;
}else{ }else{
frame->f_globals().set(_name, _0); frame->f_globals().set(_name, _0);
} }
DISPATCH(); } DISPATCH();
TARGET(STORE_GLOBAL) TARGET(STORE_GLOBAL)
frame->f_globals().set(StrName(byte.arg), POPX()); frame->f_globals().set(StrName(byte.arg), POPX());
DISPATCH(); DISPATCH();
@ -202,8 +207,9 @@ __NEXT_STEP:;
TARGET(DELETE_NAME) TARGET(DELETE_NAME)
_name = StrName(byte.arg); _name = StrName(byte.arg);
if(frame->_callable != nullptr){ if(frame->_callable != nullptr){
if(!frame->_locals.contains(_name)) vm->NameError(_name); PyObject** slot = frame->_locals.try_get_name(_name);
frame->_locals.erase(_name); if(slot == nullptr) vm->UnboundLocalError(_name);
*slot = PY_NULL;
}else{ }else{
if(!frame->f_globals().contains(_name)) vm->NameError(_name); if(!frame->f_globals().contains(_name)) vm->NameError(_name);
frame->f_globals().erase(_name); frame->f_globals().erase(_name);

View File

@ -1,28 +1,10 @@
#include "pocketpy/frame.h" #include "pocketpy/frame.h"
namespace pkpy{ namespace pkpy{
PyObject** FastLocals::try_get_name(StrName name){
PyObject* FastLocals::try_get(StrName name){
int index = varnames_inv->try_get(name); int index = varnames_inv->try_get(name);
if(index == -1) return nullptr; if(index == -1) return nullptr;
return a[index]; return &a[index];
}
bool FastLocals::contains(StrName name){
return varnames_inv->contains(name);
}
void FastLocals::erase(StrName name){
int index = varnames_inv->try_get(name);
if(index == -1) FATAL_ERROR();
a[index] = nullptr;
}
bool FastLocals::try_set(StrName name, PyObject* value){
int index = varnames_inv->try_get(name);
if(index == -1) return false;
a[index] = value;
return true;
} }
NameDict_ FastLocals::to_namedict(){ NameDict_ FastLocals::to_namedict(){

View File

@ -398,7 +398,11 @@ PyObject* VM::format(Str spec, PyObject* obj){
int width, precision; int width, precision;
try{ try{
if(dot >= 0){ if(dot >= 0){
width = Number::stoi(spec.substr(0, dot).str()); if(dot == 0){
width = -1;
}else{
width = Number::stoi(spec.substr(0, dot).str());
}
precision = Number::stoi(spec.substr(dot+1).str()); precision = Number::stoi(spec.substr(dot+1).str());
}else{ }else{
width = Number::stoi(spec.str()); width = Number::stoi(spec.str());
@ -424,7 +428,7 @@ PyObject* VM::format(Str spec, PyObject* obj){
}else{ }else{
ret = CAST(Str&, py_str(obj)); ret = CAST(Str&, py_str(obj));
} }
if(width > ret.length()){ if(width != -1 && width > ret.length()){
int pad = width - ret.length(); int pad = width - ret.length();
std::string padding(pad, pad_c); std::string padding(pad, pad_c);
if(align == '>') ret = padding.c_str() + ret; if(align == '>') ret = padding.c_str() + ret;
@ -446,7 +450,7 @@ PyObject* VM::new_module(StrName name) {
static std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){ static std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){
std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg); std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
switch(byte.op){ switch(byte.op){
case OP_LOAD_CONST: case OP_LOAD_CONST: case OP_FORMAT_STRING:
if(vm != nullptr){ if(vm != nullptr){
argStr += fmt(" (", CAST(Str, vm->py_repr(co->consts[byte.arg])), ")"); argStr += fmt(" (", CAST(Str, vm->py_repr(co->consts[byte.arg])), ")");
} }

View File

@ -42,6 +42,8 @@ assert f'{a:010}' == '0000000010'
assert f'{a:010d}' == '0000000010' assert f'{a:010d}' == '0000000010'
assert f'{a:010f}' == '010.000000' assert f'{a:010f}' == '010.000000'
assert f'{a:010.2f}' == '0000010.00' assert f'{a:010.2f}' == '0000010.00'
assert f'{a:.2f}' == '10.00'
assert f'{a:.5f}' == '10.00000'
b = '123' b = '123'
assert f'{b:10}' == '123 ' assert f'{b:10}' == '123 '

View File

@ -56,4 +56,19 @@ def f():
f() f()
# class A: a=b=1 # class A: a=b=1
# class A: a, b = 1, 2 # class A: a, b = 1, 2
bmi = 0.0
def test(a):
if a:
bmi = 1.4
return f'{bmi:.2f}'
assert test(1) == '1.40'
try:
assert test(0) == '0.00'
exit(1)
except UnboundLocalError:
pass