blueloveTH hace 3 años
padre
commit
d70d2c6995
Se han modificado 12 ficheros con 85 adiciones y 130 borrados
  1. 1 0
      .github/workflows/main.yml
  2. 7 7
      benchmarks/primes.py
  3. 4 4
      benchmarks/sort.py
  4. 1 8
      scripts/run_tests.py
  5. 13 73
      src/builtins.h
  6. 1 0
      src/common.h
  7. 2 19
      src/compiler.h
  8. 0 2
      src/opcodes.h
  9. 2 2
      src/parser.h
  10. 35 8
      src/pocketpy.h
  11. 14 7
      src/vm.h
  12. 5 0
      tests/_random.py

+ 1 - 0
.github/workflows/main.yml

@@ -42,6 +42,7 @@ jobs:
         build_dir: web
         build_dir: web
       env:
       env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      if: github.event_name == 'push'
     - uses: actions/upload-artifact@v3
     - uses: actions/upload-artifact@v3
       with:
       with:
         path: output
         path: output

+ 7 - 7
benchmarks/primes.py

@@ -1,3 +1,5 @@
+# BUG!! There is a memory leak in this code
+
 UPPER_BOUND = 5000000
 UPPER_BOUND = 5000000
 PREFIX = 32338
 PREFIX = 32338
 
 
@@ -29,7 +31,7 @@ class Sieve:
                 while i < self.limit:
                 while i < self.limit:
                     self.prime[i] = False
                     self.prime[i] = False
                     i = i + r * r
                     i = i + r * r
-            r = r + 1
+            r += 1
         return self
         return self
 
 
     def step1(self, x, y):
     def step1(self, x, y):
@@ -53,13 +55,13 @@ class Sieve:
             self.step1(x, y)
             self.step1(x, y)
             self.step2(x, y)
             self.step2(x, y)
             self.step3(x, y)
             self.step3(x, y)
-            y = y + 1
+            y += 1
 
 
     def loop_x(self):
     def loop_x(self):
         x = 1
         x = 1
         while x * x < self.limit:
         while x * x < self.limit:
             self.loop_y(x)
             self.loop_y(x)
-            x = x + 1
+            x += 1
 
 
     def calc(self):
     def calc(self):
         self.loop_x()
         self.loop_x()
@@ -83,10 +85,8 @@ def find(upper_bound, prefix):
     str_prefix = str(prefix)
     str_prefix = str(prefix)
     head = generate_trie(primes.to_list())
     head = generate_trie(primes.to_list())
     for ch in str_prefix:
     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
             return None
 
 
     queue, result = [(head, str_prefix)], []
     queue, result = [(head, str_prefix)], []

+ 4 - 4
benchmarks/sort.py

@@ -11,15 +11,15 @@ def __qsort(a: list, i: int, j: int):
     u = a[i];
     u = a[i];
     while i<j:
     while i<j:
         while i<j and a[j]>u:
         while i<j and a[j]>u:
-            j--
+            j -= 1
         if i<j:
         if i<j:
             a[i] = a[j]
             a[i] = a[j]
-            i++
+            i += 1
         while i<j and a[i]<u:
         while i<j and a[i]<u:
-            i++
+            i += 1
         if i<j:
         if i<j:
             a[j] = a[i]
             a[j] = a[i]
-            j--
+            j -= 1
     a[i] = u;
     a[i] = u;
     __qsort(a, d1, i-1)
     __qsort(a, d1, i-1)
     __qsort(a, i+1, d2)
     __qsort(a, i+1, d2)

+ 1 - 8
scripts/run_tests.py

@@ -4,14 +4,7 @@ import time
 
 
 def test_file(filepath, cpython=False):
 def test_file(filepath, cpython=False):
     if cpython:
     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':
     if sys.platform == 'win32':
         return os.system("pocketpy.exe " + filepath) == 0
         return os.system("pocketpy.exe " + filepath) == 0
     else:
     else:

+ 13 - 73
src/builtins.h

@@ -121,7 +121,7 @@ def __qsort(a: list, i: int, j: int):
     mid = (i+j) // 2
     mid = (i+j) // 2
     a[mid], a[i] = a[i], a[mid]
     a[mid], a[i] = a[i], a[mid]
     u = a[i];
     u = a[i];
-    while i < j:
+    while i<j:
         while i<j and a[j]>u:
         while i<j and a[j]>u:
             j -= 1
             j -= 1
         if i<j:
         if i<j:
@@ -279,6 +279,12 @@ class dict:
             if kv is not None:
             if kv is not None:
                 self[kv[0]] = kv[1]
                 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):
     def keys(self):
         return [kv[0] for kv in self._a if kv is not None]
         return [kv[0] for kv in self._a if kv is not None]
 
 
@@ -416,77 +422,11 @@ class set:
 )";
 )";
 
 
 const char* kRandomCode = R"(
 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)]
 )";
 )";

+ 1 - 0
src/common.h

@@ -11,6 +11,7 @@
 #include <regex>
 #include <regex>
 #include <stack>
 #include <stack>
 #include <cmath>
 #include <cmath>
+#include <cstdlib>
 #include <stdexcept>
 #include <stdexcept>
 #include <vector>
 #include <vector>
 #include <string>
 #include <string>

+ 2 - 19
src/compiler.h

@@ -73,8 +73,6 @@ public:
         rules[TK("@num")] =     { METHOD(exprLiteral),   NO_INFIX };
         rules[TK("@num")] =     { METHOD(exprLiteral),   NO_INFIX };
         rules[TK("@str")] =     { METHOD(exprLiteral),   NO_INFIX };
         rules[TK("@str")] =     { METHOD(exprLiteral),   NO_INFIX };
         rules[TK("@fstr")] =    { METHOD(exprFString),   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(exprTernary),        PREC_TERNARY };
         rules[TK("=")] =        { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
         rules[TK("=")] =        { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
         rules[TK("+=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
         rules[TK("+=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
@@ -227,12 +225,7 @@ private:
                     return;
                     return;
                 }
                 }
                 case '=': parser->set_next_token_2('=', TK("="), 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("+="));
-                    else parser->set_next_token(TK("+"));
-                    return;
-                }
+                case '+': parser->set_next_token_2('=', TK("+"), TK("+=")); return;
                 case '>': {
                 case '>': {
                     if(parser->matchchar('=')) parser->set_next_token(TK(">="));
                     if(parser->matchchar('=')) parser->set_next_token(TK(">="));
                     else 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);
         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() {
     void exprBinaryOp() {
         TokenIndex op = parser->prev.type;
         TokenIndex op = parser->prev.type;
         parse_expression((Precedence)(rules[op].precedence + 1));
         parse_expression((Precedence)(rules[op].precedence + 1));
@@ -943,7 +926,7 @@ __LISTCOMP:
             consume_end_stmt();
             consume_end_stmt();
             // If last op is not an assignment, pop the result.
             // If last op is not an assignment, pop the result.
             uint8_t last_op = co()->codes.back().op;
             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);
                 if(mode()==REPL_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR, -1, true);
                 emit(OP_POP_TOP, -1, true);
                 emit(OP_POP_TOP, -1, true);
             }
             }

+ 0 - 2
src/opcodes.h

@@ -68,8 +68,6 @@ OPCODE(DELETE_REF)
 OPCODE(TRY_BLOCK_ENTER)
 OPCODE(TRY_BLOCK_ENTER)
 OPCODE(TRY_BLOCK_EXIT)
 OPCODE(TRY_BLOCK_EXIT)
 
 
-OPCODE(STORE_INCREMENT)
-
 //OPCODE(FAST_INDEX_0)      // a[0]
 //OPCODE(FAST_INDEX_0)      // a[0]
 //OPCODE(FAST_INDEX_1)      // a[i]
 //OPCODE(FAST_INDEX_1)      // a[i]
 
 

+ 2 - 2
src/parser.h

@@ -10,7 +10,7 @@ constexpr const char* kTokens[] = {
     "+", "-", "*", "/", "//", "**", "=", ">", "<", "...", "->",
     "+", "-", "*", "/", "//", "**", "=", ">", "<", "...", "->",
     "<<", ">>", "&", "|", "^", "?",
     "<<", ">>", "&", "|", "^", "?",
     "==", "!=", ">=", "<=",
     "==", "!=", ">=", "<=",
-    "+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=", "++", "--",
+    "+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=",
     /** KW_BEGIN **/
     /** KW_BEGIN **/
     "class", "import", "as", "def", "lambda", "pass", "del", "from", "with",
     "class", "import", "as", "def", "lambda", "pass", "del", "from", "with",
     "None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
     "None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
@@ -144,7 +144,7 @@ struct Parser {
         if(brackets_level > 0) return true;
         if(brackets_level > 0) return true;
         int spaces = eat_spaces();
         int spaces = eat_spaces();
         if(peekchar() == '#') skip_line_comment();
         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
         // https://docs.python.org/3/reference/lexical_analysis.html#indentation
         if(spaces > indents.top()){
         if(spaces > indents.top()){
             indents.push(spaces);
             indents.push(spaces);

+ 35 - 8
src/pocketpy.h

@@ -569,12 +569,12 @@ void add_module_math(VM* vm){
     vm->setattr(mod, "pi", vm->PyFloat(3.1415926535897932384));
     vm->setattr(mod, "pi", vm->PyFloat(3.1415926535897932384));
     vm->setattr(mod, "e" , vm->PyFloat(2.7182818284590452354));
     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, "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, "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])))));
     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{
 class _PkExported{
 public:
 public:
     virtual ~_PkExported() = default;
     virtual ~_PkExported() = default;
@@ -781,11 +809,10 @@ extern "C" {
         add_module_math(vm);
         add_module_math(vm);
         add_module_re(vm);
         add_module_re(vm);
         add_module_dis(vm);
         add_module_dis(vm);
+        add_module_random(vm);
 
 
         CodeObject_ code = vm->compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
         CodeObject_ code = vm->compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
         vm->_exec(code, vm->builtins, pkpy::make_shared<pkpy::NameDict>());
         vm->_exec(code, vm->builtins, pkpy::make_shared<pkpy::NameDict>());
-
-        pkpy_vm_add_module(vm, "random", kRandomCode);
         return vm;
         return vm;
     }
     }
 
 

+ 14 - 7
src/vm.h

@@ -16,6 +16,7 @@
 class VM {
 class VM {
     std::stack< std::unique_ptr<Frame> > callstack;
     std::stack< std::unique_ptr<Frame> > callstack;
     PyVar _py_op_call;
     PyVar _py_op_call;
+    PyVar _ascii_str_pool[128];
 
 
     PyVar run_frame(Frame* frame){
     PyVar run_frame(Frame* frame){
         while(frame->has_next_bytecode()){
         while(frame->has_next_bytecode()){
@@ -27,12 +28,6 @@ class VM {
             {
             {
             case OP_NO_OP: break;       // do nothing
             case OP_NO_OP: break;       // do nothing
             case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); break;
             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: {
             case OP_LOAD_LAMBDA: {
                 PyVar obj = frame->co->consts[byte.arg];
                 PyVar obj = frame->co->consts[byte.arg];
                 setattr(obj, __module__, frame->_module);
                 setattr(obj, __module__, frame->_module);
@@ -367,6 +362,7 @@ public:
         }
         }
 
 
         init_builtin_types();
         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){
     PyVar asStr(const PyVar& obj){
@@ -816,9 +812,20 @@ public:
         return (const BaseRef*)(obj->value());
         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(Int, i64, tp_int)
     DEF_NATIVE(Float, f64, tp_float)
     DEF_NATIVE(Float, f64, tp_float)
-    DEF_NATIVE(Str, Str, tp_str)
     DEF_NATIVE(List, pkpy::List, tp_list)
     DEF_NATIVE(List, pkpy::List, tp_list)
     DEF_NATIVE(Tuple, pkpy::Tuple, tp_tuple)
     DEF_NATIVE(Tuple, pkpy::Tuple, tp_tuple)
     DEF_NATIVE(Function, pkpy::Function_, tp_function)
     DEF_NATIVE(Function, pkpy::Function_, tp_function)

+ 5 - 0
tests/_random.py

@@ -5,6 +5,11 @@ for _ in range(100):
     assert i <= 10
     assert i <= 10
     assert i >= 1
     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
 from sys import version as v