Update build.py

up

up
This commit is contained in:
blueloveTH 2023-03-05 01:54:34 +08:00
parent 2f0aa7c89c
commit 3b13b1a988
17 changed files with 513 additions and 444 deletions

View File

@ -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
.gitignore vendored
View File

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

View File

@ -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
build.py Normal file
View File

@ -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()

View File

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

View File

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

View File

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

View File

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

36
preprocess.py Normal file
View File

@ -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())

View File

@ -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
python/builtins.py Normal file
View File

@ -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
python/dict.py Normal file
View File

@ -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
python/functools.py Normal file
View File

@ -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
python/random.py Normal file
View File

@ -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
python/set.py Normal file
View File

@ -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()

View File

@ -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
)";

View File

@ -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);
}