Parcourir la source

up

Update build.py

up

up
blueloveTH il y a 3 ans
Parent
commit
3b13b1a988
17 fichiers modifiés avec 513 ajouts et 444 suppressions
  1. 5 6
      .github/workflows/main.yml
  2. 2 0
      .gitignore
  3. 6 2
      amalgamate.py
  4. 50 0
      build.py
  5. 0 1
      build_cpp.sh
  6. 0 3
      build_linux.sh
  7. 0 3
      build_wasm.sh
  8. 2 1
      compile_flags.txt
  9. 36 0
      preprocess.py
  10. 0 7
      profile.sh
  11. 190 0
      python/builtins.py
  12. 100 0
      python/dict.py
  13. 9 0
      python/functools.py
  14. 7 0
      python/random.py
  15. 98 0
      python/set.py
  16. 0 416
      src/builtins.h
  17. 8 5
      src/pocketpy.h

+ 5 - 6
.github/workflows/main.yml

@@ -13,9 +13,8 @@ jobs:
     - name: Compiling
       shell: bash
       run: |
-        clang-cl.exe -std:c++17 -GR- -EHsc -O2 -Wno-deprecated-declarations -Fe:pocketpy src/main.cpp
-        echo '#include "pocketpy.h"' > src/tmp.cpp
-        clang-cl.exe -std:c++17 -GR- -EHsc -O2 -Wno-deprecated-declarations -LD -Fe:pocketpy src/tmp.cpp
+        python3 build.py windows
+        python3 build.py windows -lib
         python3 scripts/run_tests.py
         python3 scripts/run_tests.py benchmark
         mkdir -p output/windows/x86_64
@@ -38,7 +37,7 @@ jobs:
     - name: Compiling
       run: |
         mkdir -p output/web/lib
-        bash build_wasm.sh
+        python3 build.py web
         cp web/lib/* output/web/lib
     - uses: crazy-max/ghaction-github-pages@v3
       with:
@@ -62,8 +61,8 @@ jobs:
     - name: Compiling
       run: |
         sudo apt install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15
-        bash build_cpp.sh
-        bash build_linux.sh
+        python3 build.py linux
+        python3 build.py linux -lib
         python3 scripts/run_tests.py
         python3 scripts/run_tests.py benchmark
         mkdir -p output/linux/x86_64

+ 2 - 0
.gitignore

@@ -20,3 +20,5 @@ plugins/flutter/src/pocketpy.h
 plugins/macos/pocketpy/pocketpy.h
 plugins/godot/godot-cpp/
 123.txt
+src/_generated.h
+profile.sh

+ 6 - 2
amalgamate.py

@@ -1,11 +1,15 @@
+import os
+
+os.system("python3 preprocess.py")
+
 with open("src/opcodes.h", "rt", encoding='utf-8') as f:
 	OPCODES_TEXT = f.read()
 
 pipeline = [
-	["common.h", "memory.h", "str.h", "tuplelist.h", "namedict.h", "builtins.h", "error.h"],
+	["common.h", "memory.h", "str.h", "tuplelist.h", "namedict.h", "error.h"],
 	["obj.h", "parser.h", "codeobject.h", "frame.h"],
 	["vm.h", "ref.h", "ceval.h", "compiler.h", "repl.h"],
-	["iter.h", "cffi.h", "pocketpy.h"]
+	["iter.h", "cffi.h", "_generated.h", "pocketpy.h"]
 ]
 
 copied = set()

+ 50 - 0
build.py

@@ -0,0 +1,50 @@
+import os
+import sys
+
+assert __name__ == "__main__"
+
+os.system("python3 preprocess.py")
+
+def DONE(code=0):
+    exit(code)
+
+linux_common = "-Wfatal-errors --std=c++17 -O2 -Wall -Wno-sign-compare -Wno-unused-variable -fno-rtti -stdlib=libc++"
+linux_cmd = "clang++ -o pocketpy src/main.cpp " + linux_common
+linux_lib_cmd = "clang++ -fPIC -shared -o pocketpy.so src/tmp.cpp " + linux_common
+
+lib_pre_cmd = r'''echo "#include \"pocketpy.h\"" > src/tmp.cpp'''
+lib_post_cmd = r'''rm src/tmp.cpp'''
+
+windows_common = "clang-cl.exe -std:c++17 -GR- -EHsc -O2 -Wno-deprecated-declarations"
+windows_cmd = windows_common + " -Fe:pocketpy src/main.cpp"
+windows_lib_cmd = windows_common + " -LD -Fe:pocketpy src/tmp.cpp"
+
+if sys.argv.__len__() == 1:
+    os.system(linux_cmd)
+    DONE()
+
+if "windows" in sys.argv:
+    if "-lib" in sys.argv:
+        os.system(lib_pre_cmd)
+        os.system(windows_lib_cmd)
+        os.system(lib_post_cmd)
+    else:
+        os.system(windows_cmd)
+    DONE()
+
+if "linux" in sys.argv:
+    if "-lib" in sys.argv:
+        os.system(lib_pre_cmd)
+        os.system(linux_lib_cmd)
+        os.system(lib_post_cmd)
+    else:
+        os.system(linux_cmd)
+    DONE()
+
+if "web" in sys.argv:
+    os.system(r'''
+rm -rf web/lib/
+mkdir -p web/lib/
+em++ src/main.cpp -fno-rtti -fexceptions -O3 -sEXPORTED_FUNCTIONS=_pkpy_delete,_pkpy_setup_callbacks,_pkpy_new_repl,_pkpy_repl_input,_pkpy_new_vm,_pkpy_vm_add_module,_pkpy_vm_bind,_pkpy_vm_eval,_pkpy_vm_exec,_pkpy_vm_get_global,_pkpy_vm_read_output -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js
+''')
+    DONE()

+ 0 - 1
build_cpp.sh

@@ -1 +0,0 @@
-clang++ -o pocketpy src/main.cpp -Wfatal-errors --std=c++17 -O2 -Wall -Wno-sign-compare -Wno-unused-variable -fno-rtti -stdlib=libc++ -v

+ 0 - 3
build_linux.sh

@@ -1,3 +0,0 @@
-echo '#include "pocketpy.h"' > src/tmp.cpp
-clang++ -fPIC -shared -o pocketpy.so src/tmp.cpp --std=c++17 -O2 -Wall -Wno-sign-compare -Wno-unused-variable -fno-rtti -stdlib=libc++
-rm src/tmp.cpp

+ 0 - 3
build_wasm.sh

@@ -1,3 +0,0 @@
-rm -rf web/lib/
-mkdir -p web/lib/
-em++ src/main.cpp -fno-rtti -fexceptions -O3 -sEXPORTED_FUNCTIONS=_pkpy_delete,_pkpy_setup_callbacks,_pkpy_new_repl,_pkpy_repl_input,_pkpy_new_vm,_pkpy_vm_add_module,_pkpy_vm_bind,_pkpy_vm_eval,_pkpy_vm_exec,_pkpy_vm_get_global,_pkpy_vm_read_output -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js

+ 2 - 1
compile_flags.txt

@@ -1,4 +1,5 @@
 -xc++
 -Wall
 -W*
--std=c++17
+-std=c++17
+-stdlib=libc++

+ 36 - 0
preprocess.py

@@ -0,0 +1,36 @@
+import os
+from datetime import datetime
+
+def generate_python_sources():
+    sources = {}
+    for file in os.listdir("python"):
+        assert file.endswith(".py")
+        key = file.split(".")[0]
+        with open("python/" + file) as f:
+            value = f.read()
+            value = value.encode('utf-8').hex(':')
+            value = '\\x' + value.replace(':', '\\x')
+        sources[key] = value
+
+    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+
+    header = '''#pragma once
+// generated on ''' + timestamp + '''
+#include <map>
+#include <string>
+
+namespace pkpy{
+    std::map<std::string, std::string> kPythonLibs = {
+'''
+    for key, value in sources.items():
+        header += ' '*8 + '{"' + key + '", "' + value + '"},'
+        header += '\n'
+
+    header += '''
+    };
+}   // namespace pkpy
+'''
+    return header
+
+with open("src/_generated.h", "w", encoding='utf-8') as f:
+    f.write(generate_python_sources())

+ 0 - 7
profile.sh

@@ -1,7 +0,0 @@
-g++ -o pocketpy src/main.cpp --std=c++17 -pg -O2 -fno-rtti
-
-./pocketpy benchmarks/primes.py
-
-gprof pocketpy gmon.out > gprof.txt
-
-rm gmon.out

+ 190 - 0
python/builtins.py

@@ -0,0 +1,190 @@
+def print(*args, sep=' ', end='\n'):
+    s = sep.join([str(i) for i in args])
+    __sys_stdout_write(s + end)
+
+def round(x, ndigits=0):
+    assert ndigits >= 0
+    if ndigits == 0:
+        return x >= 0 ? int(x + 0.5) : int(x - 0.5)
+    if x >= 0:
+        return int(x * 10**ndigits + 0.5) / 10**ndigits
+    else:
+        return int(x * 10**ndigits - 0.5) / 10**ndigits
+
+def isinstance(obj, cls):
+    assert type(cls) is type
+    obj_t = type(obj)
+    while obj_t is not None:
+        if obj_t is cls:
+            return True
+        obj_t = obj_t.__base__
+    return False
+
+def abs(x):
+    return x < 0 ? -x : x
+
+def max(a, b):
+    return a > b ? a : b
+
+def min(a, b):
+    return a < b ? a : b
+
+def all(iterable):
+    for i in iterable:
+        if not i:
+            return False
+    return True
+
+def any(iterable):
+    for i in iterable:
+        if i:
+            return True
+    return False
+
+def enumerate(iterable, start=0):
+    n = start
+    for elem in iterable:
+        yield n, elem
+        n += 1
+
+def sum(iterable):
+    res = 0
+    for i in iterable:
+        res += i
+    return res
+
+def map(f, iterable):
+    for i in iterable:
+        yield f(i)
+
+def zip(a, b):
+    for i in range(min(len(a), len(b))):
+        yield (a[i], b[i])
+
+def reversed(iterable):
+    a = list(iterable)
+    a.reverse()
+    return a
+
+def sorted(iterable, reverse=False):
+    a = list(iterable)
+    a.sort(reverse=reverse)
+    return a
+
+##### str #####
+
+str.__mul__ = lambda self, n: ''.join([self for _ in range(n)])
+
+def str::split(self, sep):
+    if sep == "":
+        return list(self)
+    res = []
+    i = 0
+    while i < len(self):
+        if self[i:i+len(sep)] == sep:
+            res.append(self[:i])
+            self = self[i+len(sep):]
+            i = 0
+        else:
+            i += 1
+    res.append(self)
+    return res
+
+def str::index(self, sub):
+    for i in range(len(self)):
+        if self[i:i+len(sub)] == sub:
+            return i
+    return -1
+
+def str::strip(self, chars=None):
+    chars = chars or ' \t\n\r'
+    i = 0
+    while i < len(self) and self[i] in chars:
+        i += 1
+    j = len(self) - 1
+    while j >= 0 and self[j] in chars:
+        j -= 1
+    return self[i:j+1]
+
+##### list #####
+
+list.__new__ = lambda obj: [i for i in obj]
+list.__repr__ = lambda self: '[' + ', '.join([repr(i) for i in self]) + ']'
+tuple.__repr__ = lambda self: '(' + ', '.join([repr(i) for i in self]) + ')'
+list.__json__ = lambda self: '[' + ', '.join([i.__json__() for i in self]) + ']'
+tuple.__json__ = lambda self: '[' + ', '.join([i.__json__() for i in self]) + ']'
+
+def __qsort(a: list, L: int, R: int):
+    if L >= R: return;
+    mid = a[(R+L)//2];
+    i, j = L, R
+    while i<=j:
+        while a[i]<mid: i+=1
+        while a[j]>mid: j-=1
+        if i<=j:
+            a[i], a[j] = a[j], a[i]
+            i+=1
+            j-=1
+    __qsort(a, L, j)
+    __qsort(a, i, R)
+
+def list::sort(self, reverse=False):
+    __qsort(self, 0, len(self)-1)
+    if reverse:
+        self.reverse()
+
+def list::extend(self, other):
+    for i in other:
+        self.append(i)
+
+def list::remove(self, value):
+    for i in range(len(self)):
+        if self[i] == value:
+            del self[i]
+            return True
+    return False
+
+def list::index(self, value):
+    for i in range(len(self)):
+        if self[i] == value:
+            return i
+    return -1
+
+def list::pop(self, i=-1):
+    res = self[i]
+    del self[i]
+    return res
+
+def list::__eq__(self, other):
+    if len(self) != len(other):
+        return False
+    for i in range(len(self)):
+        if self[i] != other[i]:
+            return False
+    return True
+tuple.__eq__ = list.__eq__
+list.__ne__ = lambda self, other: not self.__eq__(other)
+tuple.__ne__ = lambda self, other: not self.__eq__(other)
+
+def list::count(self, x):
+    res = 0
+    for i in self:
+        if i == x:
+            res += 1
+    return res
+tuple.count = list.count
+
+def list::__contains__(self, item):
+    for i in self:
+        if i == item:
+            return True
+    return False
+tuple.__contains__ = list.__contains__
+
+
+class property:
+    def __init__(self, fget):
+        self.fget = fget
+
+    def __get__(self, obj):
+        return self.fget(obj)

+ 100 - 0
python/dict.py

@@ -0,0 +1,100 @@
+class dict:
+    def __init__(self, capacity=13):
+        self._capacity = capacity
+        self._a = [None] * self._capacity
+        self._len = 0
+        
+    def __len__(self):
+        return self._len
+
+    def __probe(self, key):
+        i = hash(key) % self._capacity
+        while self._a[i] is not None:
+            if self._a[i][0] == key:
+                return True, i
+            i = (i + 1) % self._capacity
+        return False, i
+
+    def __getitem__(self, key):
+        ok, i = self.__probe(key)
+        if not ok:
+            raise KeyError(repr(key))
+        return self._a[i][1]
+
+    def __contains__(self, key):
+        ok, i = self.__probe(key)
+        return ok
+
+    def __setitem__(self, key, value):
+        ok, i = self.__probe(key)
+        if ok:
+            self._a[i][1] = value
+        else:
+            self._a[i] = [key, value]
+            self._len += 1
+            if self._len > self._capacity * 0.67:
+                self._capacity *= 2
+                self.__rehash()
+
+    def __delitem__(self, key):
+        ok, i = self.__probe(key)
+        if not ok:
+            raise KeyError(repr(key))
+        self._a[i] = None
+        self._len -= 1
+
+    def __rehash(self):
+        old_a = self._a
+        self._a = [None] * self._capacity
+        self._len = 0
+        for kv in old_a:
+            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):
+        for kv in self._a:
+            if kv is not None:
+                yield kv[0]
+
+    def values(self):
+        for kv in self._a:
+            if kv is not None:
+                yield kv[1]
+
+    def items(self):
+        for kv in self._a:
+            if kv is not None:
+                yield kv
+
+    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:
+            if kv is not None:
+                d[kv[0]] = kv[1]
+        return d
+
+    def __repr__(self):
+        a = [repr(k)+': '+repr(v) for k,v in self.items()]
+        return '{'+ ', '.join(a) + '}'
+
+    def __json__(self):
+        a = []
+        for k,v in self.items():
+            if type(k) is not str:
+                raise TypeError('json keys must be strings, got ' + repr(k) )
+            a.append(k.__json__()+': '+v.__json__())
+        return '{'+ ', '.join(a) + '}'

+ 9 - 0
python/functools.py

@@ -0,0 +1,9 @@
+def cache(f):
+    def wrapper(*args):
+        if not hasattr(f, 'cache'):
+            f.cache = {}
+        key = args
+        if key not in f.cache:
+            f.cache[key] = f(*args)
+        return f.cache[key]
+    return wrapper

+ 7 - 0
python/random.py

@@ -0,0 +1,7 @@
+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)]

+ 98 - 0
python/set.py

@@ -0,0 +1,98 @@
+class set:
+    def __init__(self, iterable=None):
+        iterable = iterable or []
+        self._a = {}
+        for item in iterable:
+            self.add(item)
+
+    def add(self, elem):
+        self._a[elem] = None
+        
+    def discard(self, elem):
+        if elem in self._a:
+            del self._a[elem]
+
+    def remove(self, elem):
+        del self._a[elem]
+        
+    def clear(self):
+        self._a.clear()
+
+    def update(self,other):
+        for elem in other:
+            self.add(elem)
+        return self
+
+    def __len__(self):
+        return len(self._a)
+    
+    def copy(self):
+        return set(self._a.keys())
+    
+    def __and__(self, other):
+        ret = set()
+        for elem in self:
+            if elem in other:
+                ret.add(elem)
+        return ret
+    
+    def __or__(self, other):
+        ret = self.copy()
+        for elem in other:
+            ret.add(elem)
+        return ret
+
+    def __sub__(self, other):
+        ret = set() 
+        for elem in self:
+            if elem not in other: 
+                ret.add(elem) 
+        return ret
+    
+    def __xor__(self, other): 
+        ret = set() 
+        for elem in self: 
+            if elem not in other: 
+                ret.add(elem) 
+        for elem in other: 
+            if elem not in self: 
+                ret.add(elem) 
+        return ret
+
+    def union(self, other):
+        return self | other
+
+    def intersection(self, other):
+        return self & other
+
+    def difference(self, other):
+        return self - other
+
+    def symmetric_difference(self, other):      
+        return self ^ other
+    
+    def __eq__(self, other):
+        return self.__xor__(other).__len__() == 0
+
+    def __ne__(self, other):
+        return self.__xor__(other).__len__() != 0
+    
+    def isdisjoint(self, other):
+        return self.__and__(other).__len__() == 0
+    
+    def issubset(self, other):
+        return self.__sub__(other).__len__() == 0
+    
+    def issuperset(self, other):
+        return other.__sub__(self).__len__() == 0
+
+    def __contains__(self, elem):
+        return elem in self._a
+    
+    def __repr__(self):
+        if len(self) == 0:
+            return 'set()'
+        return '{'+ ', '.join([repr(i) for i in self._a.keys()]) + '}'
+    
+    def __iter__(self):
+        return self._a.keys()

+ 0 - 416
src/builtins.h

@@ -1,416 +0,0 @@
-#pragma once
-
-const char* kBuiltinsCode = R"(
-def print(*args, sep=' ', end='\n'):
-    s = sep.join([str(i) for i in args])
-    __sys_stdout_write(s + end)
-
-def round(x, ndigits=0):
-    assert ndigits >= 0
-    if ndigits == 0:
-        return x >= 0 ? int(x + 0.5) : int(x - 0.5)
-    if x >= 0:
-        return int(x * 10**ndigits + 0.5) / 10**ndigits
-    else:
-        return int(x * 10**ndigits - 0.5) / 10**ndigits
-
-def isinstance(obj, cls):
-    assert type(cls) is type
-    obj_t = type(obj)
-    while obj_t is not None:
-        if obj_t is cls:
-            return True
-        obj_t = obj_t.__base__
-    return False
-
-def abs(x):
-    return x < 0 ? -x : x
-
-def max(a, b):
-    return a > b ? a : b
-
-def min(a, b):
-    return a < b ? a : b
-
-def all(iterable):
-    for i in iterable:
-        if not i:
-            return False
-    return True
-
-def any(iterable):
-    for i in iterable:
-        if i:
-            return True
-    return False
-
-def enumerate(iterable, start=0):
-    n = start
-    for elem in iterable:
-        yield n, elem
-        n += 1
-
-def sum(iterable):
-    res = 0
-    for i in iterable:
-        res += i
-    return res
-
-def map(f, iterable):
-    for i in iterable:
-        yield f(i)
-
-def zip(a, b):
-    for i in range(min(len(a), len(b))):
-        yield (a[i], b[i])
-
-def reversed(iterable):
-    a = list(iterable)
-    a.reverse()
-    return a
-
-def sorted(iterable, reverse=False):
-    a = list(iterable)
-    a.sort(reverse=reverse)
-    return a
-
-##### str #####
-
-str.__mul__ = lambda self, n: ''.join([self for _ in range(n)])
-
-def str::split(self, sep):
-    if sep == "":
-        return list(self)
-    res = []
-    i = 0
-    while i < len(self):
-        if self[i:i+len(sep)] == sep:
-            res.append(self[:i])
-            self = self[i+len(sep):]
-            i = 0
-        else:
-            i += 1
-    res.append(self)
-    return res
-
-def str::index(self, sub):
-    for i in range(len(self)):
-        if self[i:i+len(sub)] == sub:
-            return i
-    return -1
-
-def str::strip(self, chars=None):
-    chars = chars or ' \t\n\r'
-    i = 0
-    while i < len(self) and self[i] in chars:
-        i += 1
-    j = len(self) - 1
-    while j >= 0 and self[j] in chars:
-        j -= 1
-    return self[i:j+1]
-
-##### list #####
-
-list.__repr__ = lambda self: '[' + ', '.join([repr(i) for i in self]) + ']'
-tuple.__repr__ = lambda self: '(' + ', '.join([repr(i) for i in self]) + ')'
-list.__json__ = lambda self: '[' + ', '.join([i.__json__() for i in self]) + ']'
-tuple.__json__ = lambda self: '[' + ', '.join([i.__json__() for i in self]) + ']'
-
-def __qsort(a: list, L: int, R: int):
-    if L >= R: return;
-    mid = a[(R+L)//2];
-    i, j = L, R
-    while i<=j:
-        while a[i]<mid: i+=1
-        while a[j]>mid: j-=1
-        if i<=j:
-            a[i], a[j] = a[j], a[i]
-            i+=1
-            j-=1
-    __qsort(a, L, j)
-    __qsort(a, i, R)
-
-def list::sort(self, reverse=False):
-    __qsort(self, 0, len(self)-1)
-    if reverse:
-        self.reverse()
-
-def list::extend(self, other):
-    for i in other:
-        self.append(i)
-
-def list::remove(self, value):
-    for i in range(len(self)):
-        if self[i] == value:
-            del self[i]
-            return True
-    return False
-
-def list::index(self, value):
-    for i in range(len(self)):
-        if self[i] == value:
-            return i
-    return -1
-
-def list::pop(self, i=-1):
-    res = self[i]
-    del self[i]
-    return res
-
-def list::__eq__(self, other):
-    if len(self) != len(other):
-        return False
-    for i in range(len(self)):
-        if self[i] != other[i]:
-            return False
-    return True
-tuple.__eq__ = list.__eq__
-list.__ne__ = lambda self, other: not self.__eq__(other)
-tuple.__ne__ = lambda self, other: not self.__eq__(other)
-
-def list::count(self, x):
-    res = 0
-    for i in self:
-        if i == x:
-            res += 1
-    return res
-tuple.count = list.count
-
-def list::__contains__(self, item):
-    for i in self:
-        if i == item:
-            return True
-    return False
-
-tuple.__contains__ = list.__contains__
-list.__new__ = lambda obj: [i for i in obj]
-
-class dict:
-    def __init__(self, capacity=13):
-        self._capacity = capacity
-        self._a = [None] * self._capacity
-        self._len = 0
-        
-    def __len__(self):
-        return self._len
-
-    def __probe(self, key):
-        i = hash(key) % self._capacity
-        while self._a[i] is not None:
-            if self._a[i][0] == key:
-                return True, i
-            i = (i + 1) % self._capacity
-        return False, i
-
-    def __getitem__(self, key):
-        ok, i = self.__probe(key)
-        if not ok:
-            raise KeyError(repr(key))
-        return self._a[i][1]
-
-    def __contains__(self, key):
-        ok, i = self.__probe(key)
-        return ok
-
-    def __setitem__(self, key, value):
-        ok, i = self.__probe(key)
-        if ok:
-            self._a[i][1] = value
-        else:
-            self._a[i] = [key, value]
-            self._len += 1
-            if self._len > self._capacity * 0.67:
-                self._capacity *= 2
-                self.__rehash()
-
-    def __delitem__(self, key):
-        ok, i = self.__probe(key)
-        if not ok:
-            raise KeyError(repr(key))
-        self._a[i] = None
-        self._len -= 1
-
-    def __rehash(self):
-        old_a = self._a
-        self._a = [None] * self._capacity
-        self._len = 0
-        for kv in old_a:
-            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):
-        for kv in self._a:
-            if kv is not None:
-                yield kv[0]
-
-    def values(self):
-        for kv in self._a:
-            if kv is not None:
-                yield kv[1]
-
-    def items(self):
-        for kv in self._a:
-            if kv is not None:
-                yield kv
-
-    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:
-            if kv is not None:
-                d[kv[0]] = kv[1]
-        return d
-
-    def __repr__(self):
-        a = [repr(k)+': '+repr(v) for k,v in self.items()]
-        return '{'+ ', '.join(a) + '}'
-
-    def __json__(self):
-        a = []
-        for k,v in self.items():
-            if type(k) is not str:
-                raise TypeError('json keys must be strings, got ' + repr(k) )
-            a.append(k.__json__()+': '+v.__json__())
-        return '{'+ ', '.join(a) + '}'
-
-class set:
-    def __init__(self, iterable=None):
-        iterable = iterable or []
-        self._a = dict()
-        for item in iterable:
-            self.add(item)
-
-    def add(self, elem):
-        self._a[elem] = None
-        
-    def discard(self, elem):
-        if elem in self._a:
-            del self._a[elem]
-
-    def remove(self, elem):
-        del self._a[elem]
-        
-    def clear(self):
-        self._a.clear()
-
-    def update(self,other):
-        for elem in other:
-            self.add(elem)
-        return self
-
-    def __len__(self):
-        return len(self._a)
-    
-    def copy(self):
-        return set(self._a.keys())
-    
-    def __and__(self, other):
-        ret = set()
-        for elem in self:
-            if elem in other:
-                ret.add(elem)
-        return ret
-    
-    def __or__(self, other):
-        ret = self.copy()
-        for elem in other:
-            ret.add(elem)
-        return ret
-
-    def __sub__(self, other):
-        ret = set() 
-        for elem in self:
-            if elem not in other: 
-                ret.add(elem) 
-        return ret
-    
-    def __xor__(self, other): 
-        ret = set() 
-        for elem in self: 
-            if elem not in other: 
-                ret.add(elem) 
-        for elem in other: 
-            if elem not in self: 
-                ret.add(elem) 
-        return ret
-
-    def union(self, other):
-        return self | other
-
-    def intersection(self, other):
-        return self & other
-
-    def difference(self, other):
-        return self - other
-
-    def symmetric_difference(self, other):      
-        return self ^ other
-    
-    def __eq__(self, other):
-        return self.__xor__(other).__len__() == 0
-
-    def __ne__(self, other):
-        return self.__xor__(other).__len__() != 0
-    
-    def isdisjoint(self, other):
-        return self.__and__(other).__len__() == 0
-    
-    def issubset(self, other):
-        return self.__sub__(other).__len__() == 0
-    
-    def issuperset(self, other):
-        return other.__sub__(self).__len__() == 0
-
-    def __contains__(self, elem):
-        return elem in self._a
-    
-    def __repr__(self):
-        if len(self) == 0:
-            return 'set()'
-        return '{'+ ', '.join([repr(i) for i in self._a.keys()]) + '}'
-    
-    def __iter__(self):
-        return self._a.keys()
-
-class property:
-    def __init__(self, fget):
-        self.fget = fget
-
-    def __get__(self, obj):
-        return self.fget(obj)
-)";
-
-const char* kRandomCode = R"(
-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)]
-)";
-
-const char* kFuncToolsCode = R"(
-def cache(f):
-    def wrapper(*args):
-        if not hasattr(f, 'cache'):
-            f.cache = {}
-        key = args
-        if key not in f.cache:
-            f.cache[key] = f(*args)
-        return f.cache[key]
-    return wrapper
-)";

+ 8 - 5
src/pocketpy.h

@@ -5,6 +5,7 @@
 #include "repl.h"
 #include "iter.h"
 #include "cffi.h"
+#include "_generated.h"
 
 namespace pkpy {
 
@@ -534,8 +535,6 @@ void init_builtins(VM* _vm) {
     _vm->bind_method<0>("ellipsis", "__repr__", CPP_LAMBDA(VAR("Ellipsis")));
 }
 
-#include "builtins.h"
-
 #ifdef _WIN32
 #define __EXPORT __declspec(dllexport)
 #elif __APPLE__
@@ -773,13 +772,13 @@ void add_module_random(VM* vm){
         return VAR(a + (b - a) * std::rand() / (f64)RAND_MAX);
     });
 
-    CodeObject_ code = vm->compile(kRandomCode, "random.py", EXEC_MODE);
+    CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE);
     vm->_exec(code, mod);
 }
 
 void add_module_functools(VM* vm){
     PyVar mod = vm->new_module("functools");
-    CodeObject_ code = vm->compile(kFuncToolsCode, "functools.py", EXEC_MODE);
+    CodeObject_ code = vm->compile(kPythonLibs["functools"], "functools.py", EXEC_MODE);
     vm->_exec(code, mod);
 }
 
@@ -797,7 +796,11 @@ void VM::post_init(){
     add_module_functools(this);
     add_module_c(this);
 
-    CodeObject_ code = compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
+    CodeObject_ code = compile(kPythonLibs["builtins"], "<builtins>", EXEC_MODE);
+    this->_exec(code, this->builtins);
+    code = compile(kPythonLibs["dict"], "<builtins>", EXEC_MODE);
+    this->_exec(code, this->builtins);
+    code = compile(kPythonLibs["set"], "<builtins>", EXEC_MODE);
     this->_exec(code, this->builtins);
 }