Bladeren bron

test `++`/`--`

BLUELOVETH 3 jaren geleden
bovenliggende
commit
f076bf4310
8 gewijzigde bestanden met toevoegingen van 91 en 19 verwijderingen
  1. 2 0
      benchmarks/primes.py
  2. 27 1
      benchmarks/sort.py
  3. 10 3
      scripts/run_tests.py
  4. 25 5
      src/compiler.h
  5. 1 1
      src/obj.h
  6. 7 2
      src/opcodes.h
  7. 1 1
      src/parser.h
  8. 18 6
      src/vm.h

+ 2 - 0
benchmarks/primes.py

@@ -1,6 +1,8 @@
 UPPER_BOUND = 5000000
 PREFIX = 32338
 
+exit(0)
+
 class Node:
     def __init__(self):
         self.children = {}

+ 27 - 1
benchmarks/sort.py

@@ -1,4 +1,30 @@
 import random
 
 a = [random.randint(-100000, 100000) for i in range(100000)]
-a = sorted(a)
+
+def __qsort(a: list, i: int, j: int):
+    if i>=j:
+        return
+    d1, d2 = i, j
+    mid = (i+j) // 2
+    a[mid], a[i] = a[i], a[mid]
+    u = a[i];
+    while i<j:
+        while i<j and a[j]>u:
+            j--
+        if i<j:
+            a[i] = a[j]
+            i++
+        while i<j and a[i]<u:
+            i++
+        if i<j:
+            a[j] = a[i]
+            j--
+    a[i] = u;
+    __qsort(a, d1, i-1)
+    __qsort(a, i+1, d2)
+
+from dis import dis
+dis(__qsort)
+
+__qsort(a, 0, len(a)-1)

+ 10 - 3
scripts/run_tests.py

@@ -4,7 +4,14 @@ import time
 
 def test_file(filepath, cpython=False):
     if cpython:
-        return os.system("python3 " + filepath) == 0
+        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
+            
     if sys.platform == 'win32':
         return os.system("pocketpy.exe " + filepath) == 0
     else:
@@ -16,7 +23,7 @@ def test_dir(path):
         if not filename.endswith('.py'):
             continue
         filepath = os.path.join(path, filename)
-        print("> " + filepath)
+        print("> " + filepath, flush=True)
 
         if path == 'benchmarks/':
             _0 = time.time()
@@ -30,7 +37,7 @@ def test_dir(path):
             if not test_file(filepath): exit(1)
 
 if len(sys.argv) == 2:
-    assert sys.argv[1] == 'benchmark'
+    assert 'benchmark' in sys.argv[1]
     d = 'benchmarks/'
 else:
     d = 'tests/'

+ 25 - 5
src/compiler.h

@@ -73,6 +73,8 @@ 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 };
@@ -225,7 +227,12 @@ private:
                     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 '>': {
                     if(parser->matchchar('=')) parser->set_next_token(TK(">="));
                     else if(parser->matchchar('>')) parser->set_next_token(TK(">>"));
@@ -241,6 +248,7 @@ private:
                 case '-': {
                     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("--"));
                     else parser->set_next_token(TK("-"));
                     return;
                 }
@@ -456,6 +464,16 @@ 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));
@@ -626,7 +644,8 @@ __LISTCOMP:
         consume(TK("@id"));
         const Str& name = parser->prev.str();
         int index = co()->add_name(name, NAME_ATTR);
-        emit(OP_BUILD_ATTR_REF, index);
+        index = (index<<1) + (int)co()->_rvalue;
+        emit(OP_BUILD_ATTR, index);
     }
 
     // [:], [:b]
@@ -655,7 +674,8 @@ __LISTCOMP:
                 consume(TK("]"));
             }
         }
-        emit(OP_BUILD_INDEX_REF);
+
+        emit(OP_BUILD_INDEX, (int)co()->_rvalue);
     }
 
     void exprValue() {
@@ -730,7 +750,7 @@ __LISTCOMP:
             consume(TK("@id"));
             Token tkname = parser->prev;
             int index = co()->add_name(tkname.str(), NAME_ATTR);
-            emit(OP_BUILD_ATTR_REF, index);
+            emit(OP_BUILD_ATTR, (index<<1)+1);
             if (match(TK("as"))) {
                 consume(TK("@id"));
                 tkname = parser->prev;
@@ -923,7 +943,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){
+            if( last_op!=OP_STORE_NAME && last_op!=OP_STORE_REF && last_op!=OP_STORE_INCREMENT){
                 if(mode()==REPL_MODE && parser->indents.top()==0) emit(OP_PRINT_EXPR, -1, true);
                 emit(OP_POP_TOP, -1, true);
             }

+ 1 - 1
src/obj.h

@@ -113,7 +113,7 @@ namespace pkpy {
         inline static void call(int* counter) {
             PyObject* obj = (PyObject*)(counter + 1);
             std::vector<int*>& pool = _obj_pool[obj->_tid];
-            if(obj->_tid==tid<Dummy>() || pool.size() > 60){
+            if(obj->_tid==tid<Dummy>() || pool.size() > 32){
                 obj->~PyObject();
                 free(counter);
             }else{

+ 7 - 2
src/opcodes.h

@@ -58,8 +58,8 @@ OPCODE(EXCEPTION_MATCH)
 OPCODE(RAISE)
 OPCODE(RE_RAISE)
 
-OPCODE(BUILD_INDEX_REF)
-OPCODE(BUILD_ATTR_REF)
+OPCODE(BUILD_INDEX)
+OPCODE(BUILD_ATTR)
 OPCODE(STORE_NAME)
 OPCODE(STORE_FUNCTION)
 OPCODE(STORE_REF)
@@ -68,4 +68,9 @@ 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]
+
 #endif

+ 1 - 1
src/parser.h

@@ -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",

+ 18 - 6
src/vm.h

@@ -27,6 +27,12 @@ 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);
@@ -42,14 +48,20 @@ class VM {
                 auto& p = frame->co->names[byte.arg];
                 NameRef(p).set(this, frame, frame->pop_value(this));
             } break;
-            case OP_BUILD_ATTR_REF: {
-                auto& attr = frame->co->names[byte.arg];
+            case OP_BUILD_ATTR: {
+                int name = byte.arg >> 1;
+                bool _rvalue = byte.arg % 2 == 1;
+                auto& attr = frame->co->names[name];
                 PyVar obj = frame->pop_value(this);
-                frame->push(PyRef(AttrRef(obj, NameRef(attr))));
+                AttrRef ref = AttrRef(obj, NameRef(attr));
+                if(_rvalue) frame->push(ref.get(this, frame));
+                else frame->push(PyRef(ref));
             } break;
-            case OP_BUILD_INDEX_REF: {
+            case OP_BUILD_INDEX: {
                 PyVar index = frame->pop_value(this);
-                frame->push(PyRef(IndexRef(frame->pop_value(this), index)));
+                auto ref = IndexRef(frame->pop_value(this), index);
+                if(byte.arg == 0) frame->push(PyRef(ref));
+                else frame->push(ref.get(this, frame));
             } break;
             case OP_STORE_REF: {
                 PyVar obj = frame->pop_value(this);
@@ -794,7 +806,7 @@ public:
 
     template<typename P>
     inline PyVarRef PyRef(P&& value) {
-        static_assert(std::is_base_of<BaseRef, P>::value, "P should derive from BaseRef");
+        static_assert(std::is_base_of<BaseRef, std::remove_reference_t<P>>::value, "P should derive from BaseRef");
         return new_object(tp_ref, std::forward<P>(value));
     }