blueloveTH 3 jaren geleden
bovenliggende
commit
43f99dde5d
23 gewijzigde bestanden met toevoegingen van 132 en 193 verwijderingen
  1. 9 1
      .github/workflows/main.yml
  2. 1 1
      README.md
  3. 6 6
      scripts/run_tests.py
  4. 47 0
      src/builtins.h
  5. 5 1
      src/compiler.h
  6. 1 1
      src/main.cpp
  7. 2 1
      src/obj.h
  8. 9 1
      src/pocketpy.h
  9. 2 2
      src/vm.h
  10. 0 15
      tests/2.py
  11. 0 7
      tests/4.py
  12. 0 9
      tests/5.py
  13. 0 16
      tests/6.py
  14. 1 3
      tests/basic.py
  15. 21 14
      tests/builtin_ty.py
  16. 0 0
      tests/controlflow.py
  17. 0 0
      tests/functions.py
  18. 19 0
      tests/goto.py
  19. 0 0
      tests/hidden/3.py
  20. 8 0
      tests/listcomp.py
  21. 0 39
      tests/mixedtype/basic.py
  22. 1 1
      tests/prime.py
  23. 0 75
      tests/singletype/basic.py

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

@@ -31,4 +31,12 @@ jobs:
         target_branch: gh-pages
         build_dir: web
       env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  build_test_linux:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+    - name: Compiling
+      run: |
+        bash build_cpp.sh
+        python3 scripts/run_tests.py

+ 1 - 1
README.md

@@ -30,7 +30,7 @@ It will generate `pocketpy.h` and `main.cpp` in `amalgamated/` directory. You ca
 **If you want to do development:**
 
 ```bash
-g++ -o pocketpy src/main.cpp --std=c++17 -O1
+g++ -o pocketpy src/main.cpp --std=c++17 -O1 -pthread
 ```
 ## Flutter Plugin
 

+ 6 - 6
scripts/run_tests.py

@@ -1,23 +1,23 @@
 import os
 
-singletypepath = 'tests/singletype'
-mixedtypepath = 'tests/mixedtype'
-
 def test_file(filepath):
     return os.system("./pocketpy " + filepath) == 0
     #return os.system("python3 " + filepath) == 0
 
 def test_dir(path):
-    print("=" * 50)
+    has_error = False
     for filename in os.listdir(path):
         if filename.endswith('.py'):
             filepath = os.path.join(path, filename)
             code = test_file(filepath)
             if not code:
                 print("[x] " + filepath)
+                has_error = True
             else:
                 print("[√] " + filepath)
+    return not has_error
 
 if __name__ == '__main__':
-    test_dir(singletypepath)
-    test_dir(mixedtypepath)
+    ok = test_dir('./tests')
+    if not ok:
+        exit(1)

+ 47 - 0
src/builtins.h

@@ -42,6 +42,23 @@ def __list4extend(self, other):
 list.extend = __list4extend
 del __list4extend
 
+def __list4remove(self, value):
+    for i in range(len(self)):
+        if self[i] == value:
+            del self[i]
+            return True
+    return False
+list.remove = __list4remove
+del __list4remove
+
+def __list4index(self, value):
+    for i in range(len(self)):
+        if self[i] == value:
+            return i
+    return -1
+list.index = __list4index
+del __list4index
+
 def __list4__mul__(self, n):
     a = []
     for i in range(n):
@@ -61,6 +78,16 @@ list.__eq__ = __iterable4__eq__
 tuple.__eq__ = __iterable4__eq__
 del __iterable4__eq__
 
+def __iterable4count(self, x):
+    res = 0
+    for i in self:
+        if i == x:
+            res += 1
+    return res
+list.count = __iterable4count
+tuple.count = __iterable4count
+del __iterable4count
+
 def __iterable4__contains__(self, item):
     for i in self:
         if i == item:
@@ -135,6 +162,14 @@ class dict:
     def items(self):
         return [kv for kv in self._a if kv is not None]
 
+    def clear(self):
+        self._a = [None] * self._capacity
+        self._len = 0
+
+    def update(self, other):
+        for k, v in other.items():
+            self[k] = v
+
     def copy(self):
         d = dict()
         for kv in self._a:
@@ -181,6 +216,18 @@ def map(f, iterable):
 
 def zip(a, b):
     return [(a[i], b[i]) for i in range(min(len(a), len(b)))]
+
+def sorted(iterable, key=None, reverse=False):
+    if key is None:
+        key = lambda x: x
+    a = [key(i) for i in iterable]
+    b = list(iterable)
+    for i in range(len(a)):
+        for j in range(i+1, len(a)):
+            if (a[i] > a[j]) ^ reverse:
+                a[i], a[j] = a[j], a[i]
+                b[i], b[j] = b[j], b[i]
+    return b
 )";
 
 const char* __RANDOM_CODE = R"(

+ 5 - 1
src/compiler.h

@@ -833,7 +833,11 @@ __LISTCOMP:
             {
                 case 0: func->args.push_back(name); break;
                 case 1: func->starredArg = name; state+=1; break;
-                case 2: consume(TK("=")); func->kwArgs[name] = consumeLiteral(); break;
+                case 2:
+                    consume(TK("="));
+                    func->kwArgs[name] = consumeLiteral();
+                    func->kwArgsOrder.push_back(name);
+                    break;
                 case 3: syntaxError("**kwargs is not supported yet"); break;
             }
         } while (match(TK(",")));

+ 1 - 1
src/main.cpp

@@ -2,7 +2,7 @@
 
 #include "pocketpy.h"
 
-#define PK_DEBUG_TIME
+//#define PK_DEBUG_TIME
 
 struct Timer{
     const char* title;

+ 2 - 1
src/obj.h

@@ -10,7 +10,7 @@ const _Int _Int_MAX_NEG = -9223372036854775807LL;
 const _Float _FLOAT_INF_POS = INFINITY;
 const _Float _FLOAT_INF_NEG = -INFINITY;
 
-#define PK_VERSION "0.2.6"
+#define PK_VERSION "0.2.9"
 
 class CodeObject;
 class BasePointer;
@@ -27,6 +27,7 @@ struct Function {
     std::vector<_Str> args;
     _Str starredArg;        // empty if no *arg
     PyVarDict kwArgs;       // empty if no k=v
+    std::vector<_Str> kwArgsOrder;
 
     bool hasName(const _Str& val) const {
         bool _0 = std::find(args.begin(), args.end(), val) != args.end();

+ 9 - 1
src/pocketpy.h

@@ -424,7 +424,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
         vm->__checkArgSize(args, 3, true);
         PyVarList& _self = vm->PyList_AS_C(args[0]);
         int _index = vm->PyInt_AS_C(args[1]);
-        _index = vm->normalizedIndex(_index, _self.size());
+        if(_index < 0) _index += _self.size();
+        if(_index < 0) _index = 0;
+        if(_index > _self.size()) _index = _self.size();
         _self.insert(_self.begin() + _index, args[2]);
         return vm->None;
     });
@@ -534,6 +536,12 @@ void __initializeBuiltinFunctions(VM* _vm) {
     _vm->bindMethod("bool", "__eq__", [](VM* vm, PyVarList args) {
         return vm->PyBool(args[0] == args[1]);
     });
+
+    _vm->bindMethod("bool", "__xor__", [](VM* vm, PyVarList args) {
+        bool _self = vm->PyBool_AS_C(args[0]);
+        bool _obj = vm->PyBool_AS_C(args[1]);
+        return vm->PyBool(_self ^ _obj);
+    });
 }
 
 #include "builtins.h"

+ 2 - 2
src/vm.h

@@ -439,11 +439,11 @@ public:
                 locals[fn->starredArg] = PyTuple(vargs);
             }
             // handle keyword arguments
-            for(const auto& [name, value] : fn->kwArgs){
+            for(const _Str& name : fn->kwArgsOrder){
                 if(i < args.size()) {
                     locals[name] = args[i++];
                 }else{
-                    locals[name] = value;
+                    locals[name] = fn->kwArgs[name];
                 }
             }
 

+ 0 - 15
tests/2.py

@@ -1,15 +0,0 @@
-def test(n):
-  k = 0
-  for x in range(n):
-    if x<2:
-      continue
-    flag = True
-    for i in range(2,x):
-      if x%i == 0:
-        flag = False
-        break
-    if flag:
-      k += 1
-  return k
-
-print(test(10000))

+ 0 - 7
tests/4.py

@@ -1,7 +0,0 @@
-for i in range(100):
-    for j in range(100):
-        print(i, j)
-        goto .end
-
-label .end
-print("END")

+ 0 - 9
tests/5.py

@@ -1,9 +0,0 @@
-for i in range(10):
-    for j in range(10):
-        goto .test 
-        print(2)
-    label .test
-    print(i)
-
-# 15, 23
-# 5, 28

+ 0 - 16
tests/6.py

@@ -1,16 +0,0 @@
-[
-    1,2,3
-]
-
-import ink
-
-print('Once upon a time...')
-
-index, val = ink.choice(
-  'There were two choices.',
-  'There were four lines of content.'
-)
-
-print(f'You selected {index}')
-
-print('They lived happily ever after.')

+ 1 - 3
tests/basic.py

@@ -89,6 +89,4 @@ assert [1, 2, 3] != [1, 2, 4]
 
 # test + *=
 assert [1, 2, 3] + [4, 5, 6] == [1, 2, 3, 4, 5, 6]          
-assert [1, 2, 3] * 3 == [1, 2, 3, 1, 2, 3, 1, 2, 3]
-
-print("ALL TESTS PASSED")
+assert [1, 2, 3] * 3 == [1, 2, 3, 1, 2, 3, 1, 2, 3]

+ 21 - 14
tests/singletype/builtin_ty.py → tests/builtin_ty.py

@@ -67,7 +67,7 @@ assert l[-1:-3] == []
 assert l[-3:-1] == [2,3]
 
 
-l1 = [1];l2 = l1;l1 += [2];l3 = [1,1,2]
+l1 = [1];l2 = l1;l1.append(2);l3 = [1,1,2]
 assert l2[1] == 2
 assert l1 == l2
 assert l1*3 == [1,2,1,2,1,2]
@@ -104,19 +104,20 @@ l.insert(0, 'h')
 l.insert(3, 'o')
 l.insert(1, 'e')
 assert l == ['h', 'e', 'l', 'l', 'o']
-assert l.pop(-2) == 'l'
+assert l[-2] == 'l'
 
 ##############################################
 ##tuple
 ##############################################
 
-# tup = ('Google', 'Runoob', 'Taobao', 'Wiki', 'Weibo','Weixin')
-# assert tup[1] == 'Runoob';assert tup[-2] == 'Weibo'
-# assert tup[1:] == ('Runoob', 'Taobao', 'Wiki', 'Weibo', 'Weixin')
-# assert tup[2:4] == ('Taobao', 'Wiki')
-# assert len(tup) == 6
-
-
+tup = ('Google', 'Runoob', 'Taobao', 'Wiki', 'Weibo','Weixin')
+a,b = 1,2
+assert a == 1
+assert b == 2
+a,b = b,a
+assert a == 2
+assert b == 1
+assert len(tup) == 6
 
 ##############################################
 ##dict
@@ -134,19 +135,21 @@ assert len(tinydict) == 0
 
 dict1 = {'user':'circle','num':[1,2,3]}
 dict2 = dict1.copy()
-assert dict2 == {'user':'circle','num':[1,2,3]}
-dict1['user'] = 'root'
-assert dict1 == {'user': 'root', 'num': [1, 2, 3]};assert dict2 == {'user':'circle','num':[1,2,3]}
+for k,v in dict1.items():
+    assert dict2[k] == v
 
 tinydict = {'Name': 'circle', 'Age': 7}
 tinydict2 = {'Sex': 'female' }
 tinydict.update(tinydict2)
-assert tinydict == {'Name': 'circle', 'Age': 7, 'Sex': 'female'}
+updated_dict = {'Name': 'circle', 'Age': 7, 'Sex': 'female'}
+for k,v in tinydict.items():
+    assert updated_dict[k] == v
 
 dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
 keys = dishes.keys()
 values = dishes.values()
-assert list(keys) == ['eggs', 'sausage', 'bacon', 'spam'];assert list(values) == [2, 1, 1, 500]
+assert sorted(keys) == sorted(['eggs', 'sausage', 'bacon', 'spam'])
+assert sorted(values) == sorted([2, 1, 1, 500])
 
 d={1:"a",2:"b",3:"c"}
 result=[]
@@ -156,3 +159,7 @@ for kv in d.items():
     result.append(v)
 assert result == [1, 'a', 2, 'b', 3, 'c']
 
+a = [1,2,3,-1]
+assert sorted(a) == [-1,1,2,3]
+assert sorted(a, lambda x:-x) == [3,2,1,-1]
+assert sorted(a, None, True) == [3,2,1,-1]

+ 0 - 0
tests/singletype/controlflow.py → tests/controlflow.py


+ 0 - 0
tests/singletype/functions.py → tests/functions.py


+ 19 - 0
tests/goto.py

@@ -0,0 +1,19 @@
+a = []
+
+for i in range(10):
+    for j in range(10):
+        goto .test 
+        print(2)
+    label .test
+    a.append(i)
+
+assert a == list(range(10))
+
+b = False
+
+for i in range(10):
+    for j in range(10):
+        goto .out
+        b = True
+label .out
+assert not b

+ 0 - 0
tests/3.py → tests/hidden/3.py


+ 8 - 0
tests/listcomp.py

@@ -0,0 +1,8 @@
+a = [i for i in range(10)]
+assert a == list(range(10))
+
+a = [i for i in range(10) if i % 2 == 0]
+assert a == [0, 2, 4, 6, 8]
+
+a = [i**3 for i in range(10) if i % 2 == 0]
+assert a == [0, 8, 64, 216, 512]

+ 0 - 39
tests/mixedtype/basic.py

@@ -1,39 +0,0 @@
-def compare(a,b):
-    d = a-b
-    if d > -0.0001 and d < 0.0001:
-        return 1
-    return 0
-
-
-assert compare(32 + 32.0,64) == 1
-assert compare(8855 / 3.2,2767.1875) == 1
-#assert 6412//6.5 == 986.0  #TypeError: unsupported operand type(s) for //
-assert compare(1054.5*7985,8420182.5) == 1
-#assert 4 % 2.0 == 0.0  #TypeError: unsupported operand type(s) for %
-l = [3.2,5,10,8.9]
-assert 2.3 + l[0] == 5.5
-assert 3 + l[1] == 8
-assert compare(3/l[2],0.3) == 1
-assert 3 // l[1] == 0
-assert l[2] % 3 == 1
-assert compare(3*l[3],26.7) == 1
-assert 'a' * l[1] == 'aaaaa'
-
-assert compare(2.9**2,8.41) == 1
-assert compare(2.5**(-1),0.4) == 1 
-
-assert 2.5 > 2
-assert 1.6 < 100
-assert 1.0 == 1
-x = 2.6
-y = 5
-l = [5.4,8,'40',3.14]
-assert x <= y
-assert y >= x
-assert x != y
-assert y < l[0]
-
-str = ['s','bb']
-s = 'jack' + str[0]
-assert s == 'jacks'
-assert str[1] * 3 == 'bbbbbb' 

+ 1 - 1
tests/1.py → tests/prime.py

@@ -13,4 +13,4 @@ def test(n):
       k += 1
   return k
 
-print(test(10000))
+assert test(100) == 25

+ 0 - 75
tests/singletype/basic.py

@@ -1,75 +0,0 @@
-
-def compare(a,b):
-    d = a-b
-    if d > -0.0001 and d < 0.0001:
-        return 1
-    return 0
-
-s = 'foo'; s += 'bar'
-assert s == 'foobar'
-assert 1 + 2 * 3 == 7
-assert (1 + 2)* 3 == 9
-assert compare(1.2*3.5 , 4.2) == 1
-assert compare(9.8*(2.5 - 3),-4.9) == 1
-assert compare(2.4*8.6,20.64) == 1
-
-assert compare(1.5 + 3,4.5) == 1
-assert compare(1.5 + 3.9,5.4) == 1
-assert 2 - 1 == 1
-assert compare(5.3 - 2.5,2.8) == 1
-assert 42 % 40 == 2
-assert -15 % 6 == -3     # in python -15 % 6 == 3
-assert 2/1 == 2
-assert 3//2 == 1
-assert 1 - 9 == -8
-
-a = 1
-assert -a == -1
-assert 'testing'== 'test' + 'ing'
-
-x = 42 
-assert x%3 == 0
-x = 27 
-assert x%8 == 3
-
-
-assert 2**3 == 8 
-assert -2**2 == 4 
-assert (-2)**2 == 4
-assert compare(0.2**2,0.04) == 1    
-x = 4
-assert x**4 == 256
-assert compare(x**0.5,2) == 1
-assert compare(4**(-1.0),0.25) == 1
-
-assert 'abc' * 3 == 'abcabcabc'
-assert '' * 1000 == ''
-assert 'foo' * 0 == ''
-
-
-assert 1 < 2
-assert 3 > 1
-x = 1
-y = 8
-assert x <= y
-assert y >= x
-assert x != y
-
-assert 42 in [12, 42, 3.14]
-assert 'key' in {'key':'value'}
-assert 'a' in 'abc'
-assert 'd' not in 'abc'
-
-x = 1
-y = 0
-assert not x == False
-assert not y == True
-
-a = 1
-b = 1
-c = 0.1
-assert (a==b) and (a is not b)       # small int cache
-assert a is not c
-
-
-