mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
some update
This commit is contained in:
parent
817f7c3583
commit
d70d2c6995
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
@ -42,6 +42,7 @@ jobs:
|
||||
build_dir: web
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: github.event_name == 'push'
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
|
@ -1,3 +1,5 @@
|
||||
# BUG!! There is a memory leak in this code
|
||||
|
||||
UPPER_BOUND = 5000000
|
||||
PREFIX = 32338
|
||||
|
||||
@ -29,7 +31,7 @@ class Sieve:
|
||||
while i < self.limit:
|
||||
self.prime[i] = False
|
||||
i = i + r * r
|
||||
r = r + 1
|
||||
r += 1
|
||||
return self
|
||||
|
||||
def step1(self, x, y):
|
||||
@ -53,13 +55,13 @@ class Sieve:
|
||||
self.step1(x, y)
|
||||
self.step2(x, y)
|
||||
self.step3(x, y)
|
||||
y = y + 1
|
||||
y += 1
|
||||
|
||||
def loop_x(self):
|
||||
x = 1
|
||||
while x * x < self.limit:
|
||||
self.loop_y(x)
|
||||
x = x + 1
|
||||
x += 1
|
||||
|
||||
def calc(self):
|
||||
self.loop_x()
|
||||
@ -83,10 +85,8 @@ def find(upper_bound, prefix):
|
||||
str_prefix = str(prefix)
|
||||
head = generate_trie(primes.to_list())
|
||||
for ch in str_prefix:
|
||||
if ch not in head.children:
|
||||
return None
|
||||
head = head.children[ch]
|
||||
if head is None:
|
||||
head = head.children.get(ch)
|
||||
if head is None: # either ch does not exist or the value is None
|
||||
return None
|
||||
|
||||
queue, result = [(head, str_prefix)], []
|
||||
|
@ -11,15 +11,15 @@ def __qsort(a: list, i: int, j: int):
|
||||
u = a[i];
|
||||
while i<j:
|
||||
while i<j and a[j]>u:
|
||||
j--
|
||||
j -= 1
|
||||
if i<j:
|
||||
a[i] = a[j]
|
||||
i++
|
||||
i += 1
|
||||
while i<j and a[i]<u:
|
||||
i++
|
||||
i += 1
|
||||
if i<j:
|
||||
a[j] = a[i]
|
||||
j--
|
||||
j -= 1
|
||||
a[i] = u;
|
||||
__qsort(a, d1, i-1)
|
||||
__qsort(a, i+1, d2)
|
||||
|
@ -4,14 +4,7 @@ import time
|
||||
|
||||
def test_file(filepath, cpython=False):
|
||||
if cpython:
|
||||
with open(filepath, 'rt') as f:
|
||||
text = f.read().replace('++', '+=1').replace('--', '-=1')
|
||||
with open("tmp.py", 'wt') as f:
|
||||
f.write(text)
|
||||
x = os.system("python3 tmp.py") == 0
|
||||
os.remove("tmp.py")
|
||||
return x
|
||||
|
||||
return os.system("python3 " + filepath) == 0
|
||||
if sys.platform == 'win32':
|
||||
return os.system("pocketpy.exe " + filepath) == 0
|
||||
else:
|
||||
|
@ -121,7 +121,7 @@ def __qsort(a: list, i: int, j: int):
|
||||
mid = (i+j) // 2
|
||||
a[mid], a[i] = a[i], a[mid]
|
||||
u = a[i];
|
||||
while i < j:
|
||||
while i<j:
|
||||
while i<j and a[j]>u:
|
||||
j -= 1
|
||||
if i<j:
|
||||
@ -279,6 +279,12 @@ class dict:
|
||||
if kv is not None:
|
||||
self[kv[0]] = kv[1]
|
||||
|
||||
def get(self, key, default=None):
|
||||
ok, i = self.__probe(key)
|
||||
if ok:
|
||||
return self._a[i][1]
|
||||
return default
|
||||
|
||||
def keys(self):
|
||||
return [kv[0] for kv in self._a if kv is not None]
|
||||
|
||||
@ -416,77 +422,11 @@ class set:
|
||||
)";
|
||||
|
||||
const char* kRandomCode = R"(
|
||||
import time as _time
|
||||
|
||||
__all__ = ['Random', 'seed', 'random', 'randint', 'uniform']
|
||||
|
||||
def _int32(x):
|
||||
return int(0xffffffff & x)
|
||||
|
||||
class Random:
|
||||
def __init__(self, seed=None):
|
||||
if seed is None:
|
||||
seed = int(_time.time() * 1000000)
|
||||
seed = _int32(seed)
|
||||
self.mt = [0] * 624
|
||||
self.mt[0] = seed
|
||||
self.mti = 0
|
||||
for i in range(1, 624):
|
||||
self.mt[i] = _int32(1812433253 * (self.mt[i - 1] ^ self.mt[i - 1] >> 30) + i)
|
||||
|
||||
def extract_number(self):
|
||||
if self.mti == 0:
|
||||
self.twist()
|
||||
y = self.mt[self.mti]
|
||||
y = y ^ y >> 11
|
||||
y = y ^ y << 7 & 2636928640
|
||||
y = y ^ y << 15 & 4022730752
|
||||
y = y ^ y >> 18
|
||||
self.mti = (self.mti + 1) % 624
|
||||
return _int32(y)
|
||||
|
||||
def twist(self):
|
||||
for i in range(0, 624):
|
||||
y = _int32((self.mt[i] & 0x80000000) + (self.mt[(i + 1) % 624] & 0x7fffffff))
|
||||
self.mt[i] = (y >> 1) ^ self.mt[(i + 397) % 624]
|
||||
|
||||
if y % 2 != 0:
|
||||
self.mt[i] = self.mt[i] ^ 0x9908b0df
|
||||
|
||||
def seed(self, x):
|
||||
assert type(x) is int
|
||||
self.mt = [0] * 624
|
||||
self.mt[0] = _int32(x)
|
||||
self.mti = 0
|
||||
for i in range(1, 624):
|
||||
self.mt[i] = _int32(1812433253 * (self.mt[i - 1] ^ self.mt[i - 1] >> 30) + i)
|
||||
|
||||
def random(self):
|
||||
return self.extract_number() / 2 ** 32
|
||||
|
||||
def randint(self, a, b):
|
||||
assert a <= b
|
||||
return int(self.random() * (b - a + 1)) + a
|
||||
|
||||
def uniform(self, a, b):
|
||||
if a > b:
|
||||
a, b = b, a
|
||||
return self.random() * (b - a) + a
|
||||
|
||||
def shuffle(self, L):
|
||||
for i in range(len(L)):
|
||||
j = self.randint(i, len(L) - 1)
|
||||
L[i], L[j] = L[j], L[i]
|
||||
|
||||
def choice(self, L):
|
||||
return L[self.randint(0, len(L) - 1)]
|
||||
|
||||
_inst = Random()
|
||||
seed = _inst.seed
|
||||
random = _inst.random
|
||||
randint = _inst.randint
|
||||
uniform = _inst.uniform
|
||||
shuffle = _inst.shuffle
|
||||
choice = _inst.choice
|
||||
def shuffle(L):
|
||||
for i in range(len(L)):
|
||||
j = randint(i, len(L) - 1)
|
||||
L[i], L[j] = L[j], L[i]
|
||||
|
||||
def choice(L):
|
||||
return L[randint(0, len(L) - 1)]
|
||||
)";
|
@ -11,6 +11,7 @@
|
||||
#include <regex>
|
||||
#include <stack>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
@ -73,8 +73,6 @@ public:
|
||||
rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX };
|
||||
rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX };
|
||||
rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX };
|
||||
rules[TK("++")] = { nullptr, METHOD(exprSelfInc), PREC_UNARY };
|
||||
rules[TK("--")] = { nullptr, METHOD(exprSelfDec), PREC_UNARY };
|
||||
rules[TK("?")] = { nullptr, METHOD(exprTernary), PREC_TERNARY };
|
||||
rules[TK("=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
|
||||
rules[TK("+=")] = { nullptr, METHOD(exprAssign), PREC_ASSIGNMENT };
|
||||
@ -227,12 +225,7 @@ private:
|
||||
return;
|
||||
}
|
||||
case '=': parser->set_next_token_2('=', TK("="), TK("==")); return;
|
||||
case '+': {
|
||||
if(parser->matchchar('+')) parser->set_next_token(TK("++"));
|
||||
else if(parser->matchchar('=')) parser->set_next_token(TK("+="));
|
||||
else parser->set_next_token(TK("+"));
|
||||
return;
|
||||
}
|
||||
case '+': parser->set_next_token_2('=', TK("+"), TK("+=")); return;
|
||||
case '>': {
|
||||
if(parser->matchchar('=')) parser->set_next_token(TK(">="));
|
||||
else if(parser->matchchar('>')) parser->set_next_token(TK(">>"));
|
||||
@ -464,16 +457,6 @@ private:
|
||||
patch_jump(patch2);
|
||||
}
|
||||
|
||||
void exprSelfInc() {
|
||||
emit(OP_STORE_INCREMENT, 1);
|
||||
consume_end_stmt();
|
||||
}
|
||||
|
||||
void exprSelfDec() {
|
||||
emit(OP_STORE_INCREMENT, -1);
|
||||
consume_end_stmt();
|
||||
}
|
||||
|
||||
void exprBinaryOp() {
|
||||
TokenIndex op = parser->prev.type;
|
||||
parse_expression((Precedence)(rules[op].precedence + 1));
|
||||
@ -943,7 +926,7 @@ __LISTCOMP:
|
||||
consume_end_stmt();
|
||||
// If last op is not an assignment, pop the result.
|
||||
uint8_t last_op = co()->codes.back().op;
|
||||
if( last_op!=OP_STORE_NAME && last_op!=OP_STORE_REF && last_op!=OP_STORE_INCREMENT){
|
||||
if( last_op!=OP_STORE_NAME && last_op!=OP_STORE_REF){
|
||||
if(mode()==REPL_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR, -1, true);
|
||||
emit(OP_POP_TOP, -1, true);
|
||||
}
|
||||
|
@ -68,8 +68,6 @@ OPCODE(DELETE_REF)
|
||||
OPCODE(TRY_BLOCK_ENTER)
|
||||
OPCODE(TRY_BLOCK_EXIT)
|
||||
|
||||
OPCODE(STORE_INCREMENT)
|
||||
|
||||
//OPCODE(FAST_INDEX_0) // a[0]
|
||||
//OPCODE(FAST_INDEX_1) // a[i]
|
||||
|
||||
|
@ -10,7 +10,7 @@ constexpr const char* kTokens[] = {
|
||||
"+", "-", "*", "/", "//", "**", "=", ">", "<", "...", "->",
|
||||
"<<", ">>", "&", "|", "^", "?",
|
||||
"==", "!=", ">=", "<=",
|
||||
"+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=", "++", "--",
|
||||
"+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=",
|
||||
/** KW_BEGIN **/
|
||||
"class", "import", "as", "def", "lambda", "pass", "del", "from", "with",
|
||||
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
|
||||
@ -144,7 +144,7 @@ struct Parser {
|
||||
if(brackets_level > 0) return true;
|
||||
int spaces = eat_spaces();
|
||||
if(peekchar() == '#') skip_line_comment();
|
||||
if(peekchar() == '\0' || peekchar() == '\n') return true;
|
||||
if(peekchar() == '\0' || peekchar() == '\n' || peekchar() == '\r') return true;
|
||||
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
|
||||
if(spaces > indents.top()){
|
||||
indents.push(spaces);
|
||||
|
@ -569,12 +569,12 @@ void add_module_math(VM* vm){
|
||||
vm->setattr(mod, "pi", vm->PyFloat(3.1415926535897932384));
|
||||
vm->setattr(mod, "e" , vm->PyFloat(2.7182818284590452354));
|
||||
|
||||
vm->bind_func<1>(mod, "log", CPP_LAMBDA(vm->PyFloat(log(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "log10", CPP_LAMBDA(vm->PyFloat(log10(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "log2", CPP_LAMBDA(vm->PyFloat(log2(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "sin", CPP_LAMBDA(vm->PyFloat(sin(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "cos", CPP_LAMBDA(vm->PyFloat(cos(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "tan", CPP_LAMBDA(vm->PyFloat(tan(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "log", CPP_LAMBDA(vm->PyFloat(std::log(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "log10", CPP_LAMBDA(vm->PyFloat(std::log10(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "log2", CPP_LAMBDA(vm->PyFloat(std::log2(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "sin", CPP_LAMBDA(vm->PyFloat(std::sin(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "cos", CPP_LAMBDA(vm->PyFloat(std::cos(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "tan", CPP_LAMBDA(vm->PyFloat(std::tan(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "isnan", CPP_LAMBDA(vm->PyBool(std::isnan(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "isinf", CPP_LAMBDA(vm->PyBool(std::isinf(vm->num_to_float(args[0])))));
|
||||
vm->bind_func<1>(mod, "fabs", CPP_LAMBDA(vm->PyFloat(std::fabs(vm->num_to_float(args[0])))));
|
||||
@ -669,6 +669,34 @@ void add_module_re(VM* vm){
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_random(VM* vm){
|
||||
PyVar mod = vm->new_module("random");
|
||||
std::srand(std::time(nullptr));
|
||||
vm->bind_func<1>(mod, "seed", [](VM* vm, const pkpy::Args& args) {
|
||||
std::srand((unsigned int)vm->PyInt_AS_C(args[0]));
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func<0>(mod, "random", CPP_LAMBDA(vm->PyFloat((f64)std::rand() / RAND_MAX)));
|
||||
vm->bind_func<2>(mod, "randint", [](VM* vm, const pkpy::Args& args) {
|
||||
i64 a = vm->PyInt_AS_C(args[0]);
|
||||
i64 b = vm->PyInt_AS_C(args[1]);
|
||||
if(a > b) std::swap(a, b);
|
||||
return vm->PyInt(a + std::rand() % (b - a + 1));
|
||||
});
|
||||
|
||||
vm->bind_func<2>(mod, "uniform", [](VM* vm, const pkpy::Args& args) {
|
||||
f64 a = vm->PyFloat_AS_C(args[0]);
|
||||
f64 b = vm->PyFloat_AS_C(args[1]);
|
||||
if(a > b) std::swap(a, b);
|
||||
return vm->PyFloat(a + (b - a) * std::rand() / RAND_MAX);
|
||||
});
|
||||
|
||||
CodeObject_ code = vm->compile(kRandomCode, "random.py", EXEC_MODE);
|
||||
vm->_exec(code, mod, pkpy::make_shared<pkpy::NameDict>());
|
||||
}
|
||||
|
||||
|
||||
class _PkExported{
|
||||
public:
|
||||
virtual ~_PkExported() = default;
|
||||
@ -781,11 +809,10 @@ extern "C" {
|
||||
add_module_math(vm);
|
||||
add_module_re(vm);
|
||||
add_module_dis(vm);
|
||||
add_module_random(vm);
|
||||
|
||||
CodeObject_ code = vm->compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
|
||||
vm->_exec(code, vm->builtins, pkpy::make_shared<pkpy::NameDict>());
|
||||
|
||||
pkpy_vm_add_module(vm, "random", kRandomCode);
|
||||
return vm;
|
||||
}
|
||||
|
||||
|
21
src/vm.h
21
src/vm.h
@ -16,6 +16,7 @@
|
||||
class VM {
|
||||
std::stack< std::unique_ptr<Frame> > callstack;
|
||||
PyVar _py_op_call;
|
||||
PyVar _ascii_str_pool[128];
|
||||
|
||||
PyVar run_frame(Frame* frame){
|
||||
while(frame->has_next_bytecode()){
|
||||
@ -27,12 +28,6 @@ class VM {
|
||||
{
|
||||
case OP_NO_OP: break; // do nothing
|
||||
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); break;
|
||||
case OP_STORE_INCREMENT:{
|
||||
const BaseRef* r = PyRef_AS_C(frame->top());
|
||||
i64 val = PyInt_AS_C(r->get(this, frame));
|
||||
r->set(this, frame, PyInt(val+byte.arg));
|
||||
frame->_pop();
|
||||
} break;
|
||||
case OP_LOAD_LAMBDA: {
|
||||
PyVar obj = frame->co->consts[byte.arg];
|
||||
setattr(obj, __module__, frame->_module);
|
||||
@ -367,6 +362,7 @@ public:
|
||||
}
|
||||
|
||||
init_builtin_types();
|
||||
for(int i=0; i<128; i++) _ascii_str_pool[i] = new_object(tp_str, std::string(1, (char)i));
|
||||
}
|
||||
|
||||
PyVar asStr(const PyVar& obj){
|
||||
@ -816,9 +812,20 @@ public:
|
||||
return (const BaseRef*)(obj->value());
|
||||
}
|
||||
|
||||
inline const Str& PyStr_AS_C(const PyVar& obj) {
|
||||
check_type(obj, tp_str);
|
||||
return OBJ_GET(Str, obj);
|
||||
}
|
||||
inline PyVar PyStr(const Str& value) {
|
||||
if(value.size() == 1){
|
||||
char c = value.c_str()[0];
|
||||
if(c > 0) return _ascii_str_pool[(int)c];
|
||||
}
|
||||
return new_object(tp_str, value);
|
||||
}
|
||||
|
||||
DEF_NATIVE(Int, i64, tp_int)
|
||||
DEF_NATIVE(Float, f64, tp_float)
|
||||
DEF_NATIVE(Str, Str, tp_str)
|
||||
DEF_NATIVE(List, pkpy::List, tp_list)
|
||||
DEF_NATIVE(Tuple, pkpy::Tuple, tp_tuple)
|
||||
DEF_NATIVE(Function, pkpy::Function_, tp_function)
|
||||
|
@ -5,6 +5,11 @@ for _ in range(100):
|
||||
assert i <= 10
|
||||
assert i >= 1
|
||||
|
||||
a = [1, 2, 3, 4]
|
||||
b = (1, 2, 3)
|
||||
r.shuffle(a)
|
||||
r.choice(a)
|
||||
r.choice(b)
|
||||
|
||||
from sys import version as v
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user