├── examples ├── basic.py ├── julia.py ├── asteroid.py └── vines.py ├── .gitignore ├── tinypy ├── vmmain.c ├── tpmain.c ├── mymain.c ├── tp.c ├── boot.py ├── py2bc.py ├── mymain.d ├── asm.py ├── disasm.py ├── sandbox.c ├── gc.c ├── list.c ├── misc.c ├── tokenize.py ├── string.c ├── dict.c ├── builtins.c ├── tp.h ├── parse.py ├── ops.c └── encode.py ├── Makefile ├── ROADMAP.txt ├── CHANGES.txt ├── README.txt ├── modules ├── random │ ├── init.c │ └── tests.py ├── math │ ├── init.c │ ├── tests.py │ └── math.c ├── pygame │ └── init.c └── re │ └── testsuite.py ├── LICENSE.txt ├── cpython └── cpython.c ├── doc └── A Brief description of re module of tinypy.tex └── setup.py /examples/basic.py: -------------------------------------------------------------------------------- 1 | if __name__ == '__main__': 2 | print("#OK") -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tinypy-panda.* 2 | tinypy/*_auto.h 3 | *.tpc 4 | *.o 5 | *.pyc 6 | tinypy/tmp.txt 7 | tinypy/tmp1.py 8 | tinypy/tmp2.py 9 | Makefile.bak 10 | Makefile-tinypy-harryr.mk 11 | .dep.inc 12 | *.d 13 | .bzr 14 | nbproject 15 | build/ 16 | -------------------------------------------------------------------------------- /tinypy/vmmain.c: -------------------------------------------------------------------------------- 1 | #define TP_COMPILER 0 2 | #include "tp.c" 3 | 4 | int main(int argc, char *argv[]) { 5 | tp_vm *tp = tp_init(argc,argv); 6 | tp_import(tp,argv[1],"__main__",0,0); 7 | tp_deinit(tp); 8 | return(0); 9 | } 10 | -------------------------------------------------------------------------------- /tinypy/tpmain.c: -------------------------------------------------------------------------------- 1 | #include "tp.c" 2 | /* INCLUDE */ 3 | 4 | int main(int argc, char *argv[]) { 5 | tp_vm *tp = tp_init(argc,argv); 6 | /* INIT */ 7 | tp_ez_call(tp,"py2bc","tinypy",tp_None); 8 | tp_deinit(tp); 9 | return(0); 10 | } 11 | 12 | /**/ 13 | -------------------------------------------------------------------------------- /tinypy/mymain.c: -------------------------------------------------------------------------------- 1 | #include "tp.c" 2 | 3 | 4 | int main(int argc, char *argv[]) { 5 | tp_vm *tp = tp_init(argc,argv); 6 | /* 7 | printf("sizeof(tp_vm) = %lu bytes\ntp->mem_used = %.2f KiB\nsizeof(tp_obj) = %lu\n", sizeof(tp_vm), tp->mem_used / 1024.0f, sizeof(tp_obj)); 8 | printf("sizeof(tp_frame_) = %lu\n", sizeof(tp_frame_)); 9 | */ 10 | tp_ez_call(tp,"py2bc","tinypy",tp_None); 11 | tp_deinit(tp); 12 | return(0); 13 | } 14 | 15 | /**/ 16 | -------------------------------------------------------------------------------- /tinypy/tp.c: -------------------------------------------------------------------------------- 1 | #ifndef TP_COMPILER 2 | #define TP_COMPILER 1 3 | #endif 4 | 5 | #ifndef TP_NORMALMAKE 6 | # include "tp.h" 7 | # include "list.c" 8 | # include "dict.c" 9 | # include "misc.c" 10 | # include "string.c" 11 | # include "builtins.c" 12 | # include "gc.c" 13 | # include "ops.c" 14 | # ifdef TP_SANDBOX 15 | # include "sandbox.c" 16 | # endif 17 | void tp_compiler(TP); 18 | # include "vm.c" 19 | #else 20 | # include "tp.h" 21 | # include "vm_auto.h" 22 | #endif 23 | 24 | tp_obj tp_None = {TP_NONE}; 25 | 26 | #if TP_COMPILER 27 | #include "bc.c" 28 | void tp_compiler(TP) { 29 | tp_import(tp,0,"tokenize",tp_tokenize,sizeof(tp_tokenize)); 30 | tp_import(tp,0,"parse",tp_parse,sizeof(tp_parse)); 31 | tp_import(tp,0,"encode",tp_encode,sizeof(tp_encode)); 32 | tp_import(tp,0,"py2bc",tp_py2bc,sizeof(tp_py2bc)); 33 | tp_ez_call(tp,"py2bc","_init",tp_None); 34 | } 35 | #else 36 | void tp_compiler(TP) { } 37 | #endif 38 | 39 | /**/ 40 | -------------------------------------------------------------------------------- /tinypy/boot.py: -------------------------------------------------------------------------------- 1 | def _boot_init(): 2 | global FTYPE 3 | f = open('tp.h','r').read() 4 | FTYPE = 'f' 5 | if 'double tp_num' in f: FTYPE = 'd' 6 | import sys 7 | global ARGV 8 | ARGV = sys.argv 9 | _boot_init() 10 | 11 | def merge(a,b): 12 | if isinstance(a,dict): 13 | for k in b: a[k] = b[k] 14 | else: 15 | for k in b: setattr(a,k,b[k]) 16 | 17 | def number(v): 18 | if type(v) is str and v[0:2] == '0x': 19 | v = int(v[2:],16) 20 | return float(v) 21 | 22 | def istype(v,t): 23 | if t == 'string': return isinstance(v,str) 24 | elif t == 'list': return (isinstance(v,list) or isinstance(v,tuple)) 25 | elif t == 'dict': return isinstance(v,dict) 26 | elif t == 'number': return (isinstance(v,float) or isinstance(v,int)) 27 | raise '?' 28 | 29 | def fpack(v): 30 | import struct 31 | return struct.pack(FTYPE,v) 32 | 33 | def system(cmd): 34 | import os 35 | return os.system(cmd) 36 | 37 | def load(fname): 38 | f = open(fname,'rb') 39 | r = f.read() 40 | f.close() 41 | return r 42 | 43 | def save(fname,v): 44 | f = open(fname,'wb') 45 | f.write(v) 46 | f.close() 47 | -------------------------------------------------------------------------------- /examples/julia.py: -------------------------------------------------------------------------------- 1 | # center: 10043 2 | import pygame, sys 3 | if not "tinypy" in sys.version: 4 | import pygame.locals 5 | 6 | SW,SH = 120,120 7 | 8 | def julia(s,ca,cb): 9 | pal = [((min(255,v)),(min(255,v*3/2)),(min(255,v*2))) for v in range(0,256)] 10 | for y in range(0,SH): 11 | for x in range(0,SW): 12 | i=0 13 | a=((float(x)/SW) * 4.0 - 2.0) 14 | b=((float(y)/SH) * 4.0 - 2.0) 15 | while i < 15 and (a*a)+(b*b)<4.0: 16 | na=(a*a)-(b*b)+ca 17 | nb=(2.0*a*b)+cb 18 | a=na 19 | b=nb 20 | i = i +1 21 | s.set_at((x,y),pal[i*16]) 22 | 23 | def main(): 24 | pygame.init() 25 | s = pygame.display.set_mode((SW,SH),0,32) 26 | _quit = False 27 | while not _quit: 28 | for e in pygame.event.get(): 29 | if e.type in (pygame.locals.QUIT,pygame.locals.KEYDOWN): 30 | _quit = True 31 | 32 | x,y = pygame.mouse.get_pos() 33 | ca=((float(x)/SW) * 2.0 - 1.0) 34 | cb=((float(y)/SH) * 2.0 - 1.0) 35 | ticks = pygame.time.get_ticks() 36 | julia(s,ca,cb) 37 | print(pygame.time.get_ticks()-ticks) 38 | pygame.display.flip() 39 | 40 | 41 | if __name__ == '__main__': 42 | main() 43 | -------------------------------------------------------------------------------- /tinypy/py2bc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | if not "tinypy" in sys.version: 3 | from boot import * 4 | 5 | import tokenize,parse,encode 6 | 7 | def _compile(s,fname): 8 | tokens = tokenize.tokenize(s) 9 | t = parse.parse(s,tokens) 10 | r = encode.encode(fname,s,t) 11 | return r 12 | 13 | def _import(name): 14 | if name in MODULES: 15 | return MODULES[name] 16 | py = name+".py" 17 | tpc = name+".tpc" 18 | if exists(py): 19 | if not exists(tpc) or mtime(py) > mtime(tpc): 20 | s = load(py) 21 | code = _compile(s,py) 22 | save(tpc,code) 23 | if not exists(tpc): raise 24 | code = load(tpc) 25 | g = {'__name__':name,'__code__':code} 26 | g['__dict__'] = g 27 | MODULES[name] = g 28 | exec(code,g) 29 | return g 30 | 31 | 32 | def _init(): 33 | BUILTINS['compile'] = _compile 34 | BUILTINS['import'] = _import 35 | 36 | def import_fname(fname,name): 37 | g = {} 38 | g['__name__'] = name 39 | MODULES[name] = g 40 | s = load(fname) 41 | code = _compile(s,fname) 42 | g['__code__'] = code 43 | exec(code,g) 44 | return g 45 | 46 | def tinypy(): 47 | return import_fname(ARGV[0],'__main__') 48 | 49 | def main(src,dest): 50 | s = load(src) 51 | r = _compile(s,src) 52 | save(dest,r) 53 | 54 | if __name__ == '__main__': 55 | main(ARGV[1],ARGV[2]) 56 | main(ARGV[1],ARGV[2]) 57 | main(ARGV[1],ARGV[2]) 58 | main(ARGV[1],ARGV[2]) 59 | main(ARGV[1],ARGV[2]) 60 | main(ARGV[1],ARGV[2]) 61 | main(ARGV[1],ARGV[2]) 62 | main(ARGV[1],ARGV[2]) 63 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | RM=rm -f 3 | CFLAGS=-ggdb -O0 4 | CPPFLAGS=-DTP_NORMALMAKE -DTP_SANDBOX 5 | WFLAGS=-std=c89 -Wall 6 | 7 | PY2BC_OBJ=tinypy/tokenize.tpc tinypy/parse.tpc tinypy/encode.tpc tinypy/py2bc.tpc 8 | TINYPY_OBJ=tinypy/mymain.o 9 | VM_OBJ=tinypy/vmmain.o 10 | CORE_SRC=$(addprefix tinypy/,builtins.c dict.c gc.c list.c misc.c ops.c sandbox.c string.c vm.c) 11 | CORE_OBJ=$(CORE_SRC:.c=.o) 12 | AUTOHEADERS=$(addsuffix _auto.h,$(basename $(CORE_SRC:.c=.h))) 13 | AUTODEPS=$(CORE_OBJ:.o=.d) 14 | 15 | all: build/tinypy build/vm $(PY2BC_OBJ) 16 | 17 | -include $(AUTODEPS) 18 | 19 | build: 20 | @mkdir -p build 21 | 22 | build/tinypy: build $(TINYPY_OBJ) $(CORE_OBJ) 23 | $(CC) $(WFLAGS) $(CFLAGS) -o $@ $(TINYPY_OBJ) $(CORE_OBJ) 24 | 25 | build/vm: build $(VM_OBJ) $(CORE_OBJ) 26 | $(CC) $(WFLAGS) $(CFLAGS) -o $@ $(VM_OBJ) $(CORE_OBJ) 27 | 28 | $(AUTODEPS): $(AUTOHEADERS) 29 | 30 | clean: 31 | -$(RM) -rf build/ 32 | -$(RM) tinypy/*.o 33 | -$(RM) tinypy/*.tpc 34 | -$(RM) tinypy/*.pyc 35 | -$(RM) $(AUTODEPS) 36 | -$(RM) $(AUTOHEADERS) 37 | 38 | %.tpc: %.py 39 | cd tinypy && python py2bc.py ../$< ../$@ 40 | 41 | $(addsuffix _auto.h,$(basename %.h)): %.c 42 | @echo "#ifndef HEADER_$(subst .h,_H,$(subst /,_,$(addsuffix _auto.h,$(basename $@))))" > $@ 43 | @echo "#define HEADER_$(subst .h,_H,$(subst /,_,$(addsuffix _auto.h,$(basename $@))))" >> $@ 44 | @echo "#include \"tp.h\"" >> $@ 45 | @grep -E '^[a-zA-Z0-9_]+ \*?[a-zA-Z0-9_]+\([^)]+\)' $< | sed -e 's/[ \t]*{[ \t]*/;/' >> $@ 46 | @echo "#endif" >> $@ 47 | 48 | %.o: %.c 49 | $(CC) $(WFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< 50 | 51 | %.d: %.c 52 | @/usr/X11/bin/makedepend $(CPPFLAGS) -f - $< | sed 's,\($*\.o\)[ :]*,\1 $@ : ,g' > $@ 53 | -------------------------------------------------------------------------------- /ROADMAP.txt: -------------------------------------------------------------------------------- 1 | tinypy is a minimalist implementation of python in 64k of code 2 | 3 | "batteries not included (yet)" 4 | "lua for people who like python" 5 | 6 | what tinypy is: 7 | * parser and bytecode compiler written in tinypy 8 | * fully bootstrapped 9 | * luaesque virtual machine with garbage collection written in C 10 | it's "stackless" sans any "stackless" features 11 | * cross-platform :) it runs under windows / linux / macosx 12 | * a fairly decent subset of python 13 | o classes and single inheritance 14 | o functions with variable or keyword arguments 15 | o strings, lists, dicts, numbers 16 | o modules, list comprehensions 17 | o exceptions with full traceback 18 | o some builtins 19 | - an easy C-API for building modules 20 | - 64k of code (for at least some definition of 64k) 21 | - interesting, educational, nifty, and useful 22 | - well tested 23 | - easy to read, maintain, and use 24 | - fun fun fun!!! 25 | - you can static compile it and its modules (MIT license, so "it's all good!") 26 | 27 | what tinypy will be: 28 | - sandboxed 29 | - a Cpython module (setup.py install) 30 | - including some batteries (math, random, re, marshal, pygame?!) 31 | - Visual Studio compatible 32 | - documented 33 | 34 | what tinypy might be: 35 | - as fast as python (maybe faster?) 36 | - including a JIT module 37 | - C89 compatible 38 | - C++ compatible (like lua) 39 | - a shed-skin module 40 | - including a dynamic loading module 41 | 42 | what tinypy won't be: 43 | - a full implementation of python 44 | - totally compatible with python 45 | 46 | alternatives to tinypy: 47 | - lua 48 | - shed-skin 49 | - pymite 50 | - pyvm 51 | - cython 52 | - pypy 53 | - jython 54 | - ironpython 55 | - python 56 | -------------------------------------------------------------------------------- /tinypy/mymain.d: -------------------------------------------------------------------------------- 1 | # DO NOT DELETE 2 | 3 | tinypy/mymain.o tinypy/mymain.d : tinypy/tp.c tinypy/tp.h /usr/include/setjmp.h 4 | tinypy/mymain.o tinypy/mymain.d : /usr/include/machine/setjmp.h /usr/include/i386/setjmp.h 5 | tinypy/mymain.o tinypy/mymain.d : /usr/include/sys/cdefs.h /usr/include/sys/stat.h 6 | tinypy/mymain.o tinypy/mymain.d : /usr/include/sys/_types.h /usr/include/machine/_types.h 7 | tinypy/mymain.o tinypy/mymain.d : /usr/include/i386/_types.h /usr/include/sys/_structs.h 8 | tinypy/mymain.o tinypy/mymain.d : /usr/include/stdio.h /usr/include/_types.h 9 | tinypy/mymain.o tinypy/mymain.d : /usr/include/stdlib.h /usr/include/available.h 10 | tinypy/mymain.o tinypy/mymain.d : /usr/include/sys/wait.h /usr/include/sys/signal.h 11 | tinypy/mymain.o tinypy/mymain.d : /usr/include/sys/appleapiopts.h 12 | tinypy/mymain.o tinypy/mymain.d : /usr/include/machine/signal.h /usr/include/i386/signal.h 13 | tinypy/mymain.o tinypy/mymain.d : /usr/include/i386/_structs.h /usr/include/sys/resource.h 14 | tinypy/mymain.o tinypy/mymain.d : /usr/include/machine/endian.h /usr/include/i386/endian.h 15 | tinypy/mymain.o tinypy/mymain.d : /usr/include/sys/_endian.h 16 | tinypy/mymain.o tinypy/mymain.d : /usr/include/libkern/_OSByteOrder.h 17 | tinypy/mymain.o tinypy/mymain.d : /usr/include/libkern/i386/_OSByteOrder.h 18 | tinypy/mymain.o tinypy/mymain.d : /usr/include/alloca.h /usr/include/machine/types.h 19 | tinypy/mymain.o tinypy/mymain.d : /usr/include/i386/types.h /usr/include/string.h 20 | tinypy/mymain.o tinypy/mymain.d : /usr/include/stdarg.h /usr/include/math.h 21 | tinypy/mymain.o tinypy/mymain.d : /usr/include/architecture/i386/math.h /usr/include/time.h 22 | tinypy/mymain.o tinypy/mymain.d : /usr/include/_structs.h tinypy/list.c tinypy/dict.c 23 | tinypy/mymain.o tinypy/mymain.d : tinypy/misc.c tinypy/string.c tinypy/builtins.c 24 | tinypy/mymain.o tinypy/mymain.d : tinypy/builtins_auto.h tinypy/gc.c tinypy/ops.c tinypy/vm.c 25 | tinypy/mymain.o tinypy/mymain.d : tinypy/bc.c 26 | -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- 1 | * added support for meta-methods (lua style): __get__, __set__, __call__ 2 | setmeta(dict,meta) getmeta(dict) getraw(dict) -> a dict that won't check 3 | its meta-methods 4 | * added some API testing to tests.py 5 | * applied OSX setup.py patch by Atul Varma 6 | * fixed to issue #14 by Dean 7 | * updated meta-method patch to be more pythonic 8 | * resolved Issue 19-Multiplying a string with a negative value crashes tinypy 9 | by Denis 10 | 11 | == 1.1 ========================================================================= 12 | * applied patch by Dean Hall to fix several range() bugs 13 | * applied patch by Krzysztof Kowalczyk to add VS 2005, 2008 compatibility. 14 | * reorganized the source so that contributed modules can go into contrib 15 | * reorganized the reorganization so that modules go into modules 16 | since that seems less confusing somehow 17 | * added a crude pygame module - to see it in action: 18 | $ python setup.py linux pygame 19 | $ ./build/tinypy examples/julia.py 20 | * added support for 21 | from x import * 22 | from x import y 23 | * trimmed off 1064 bytes by changing all the tokens from dicts to 24 | a Token class in tokenize, parse, encode modules 25 | * applied patch by Seth Lemons to support /* */ comment stripping in 26 | setup.py and get tinypy up to -std=c89 spec 27 | * cleaned up encode.py so that registers are no longer leaked 28 | added assert after each frame to check that this is the case 29 | * applied patch by KK to improve tinypy/tests.py feedback 30 | * applied patch by allefant to finish namespacing tinypy 31 | * applied patch by allefant to keep blob->tinypy.h from having warnings 32 | * added math module from Rockins Chen 33 | * fixed precedent of ** 34 | * removed unused tp_data meta methods 35 | * made tp_data API "safer" by requiring the magic type 36 | * improved setup.py to handle the clean argument 37 | * renamed some internal fnc names for no good reason 38 | * added boot option to setup.py so that full boostrapping 39 | isn't always required 40 | * applied const correctness patch from allefant 41 | * fixed memory leak in list & dict copy functions 42 | * improved kwargs support 43 | * got it compiling with -Wc++-compat 44 | * applied ord patch from allefant 45 | * fixed mingw build -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 64k tinypy 2 | "batteries not (yet) included" 3 | Copyright (c) 2008 Phil Hassey 4 | 5 | Check it out: 6 | 7 | $ python setup.py linux pygame 8 | $ ./build/tinypy examples/julia.py 9 | $ ./build/tinypy your-program-goes-here.py 10 | 11 | Depends on: 12 | - python (only for bootstrapping) 13 | - sdl (for the pygame module) 14 | - gcc 15 | 16 | Credits: 17 | - math module - Rockins Chen 18 | - VS support - Krzysztof Kowalczyk 19 | - bug fixin' - Dean Hall & Allefant 20 | 21 | Thanks to allefant and the python community for all the tips and feedback! 22 | Thanks to John M. for a python 2.5 compat. patch. 23 | And to illume and the rest of #ludumdare for morale support. 24 | Also thanks to python.org, lua.org, valgrind.org, nekovm.org, pypy.org 25 | http://javascript.crockford.com/tdop/tdop.html 26 | http://www.memorymanagement.org/articles/recycle.html 27 | http://shed-skin.blogspot.com/ 28 | 29 | Other "tiny" python implementations: 30 | http://pymite.python-hosting.com/ 31 | http://students.ceid.upatras.gr/~sxanth/pyvm/ 32 | 33 | F.A.Q.s: 34 | 35 | Q. If I run boot.py it says you've got like 80k of code! That's TOTALLY 36 | not 64k! I want my money back. 37 | A. Err... that's true. But 64k sounds *SO* much better than 80k. 38 | If you *really* want it to be 64k, just run: 39 | $ python mk64k.py 40 | This does the following things: 41 | - changes 4 spaces into tabs and removes blank lines 42 | - removes comments 43 | - removes the "namespacing" i.e. "tp_print" becomes "print" 44 | 45 | Q. The binary is bigger than 64k. I hate big binaries. 46 | A. I don't really care, but if you run "upx tinypy" it makes the tinypy 47 | binary smaller than 64k. 48 | 49 | Q. No matter how you spin this, it's just plain NOT 64k. 50 | A. Let the buyer beware? I dunno, it's close enough. Let's call it a rounding 51 | error, shall we? 52 | 53 | Q. How come some oddball combinations of variable and named arguments don't work? 54 | A. Ask me some other time. Short answer: I do it like lua does it. Only calls 55 | like this make sense: 56 | call_with_var_args(a,b,c,*d) 57 | call_with_named_args(a=b,**c) 58 | mixes of both just don't work, sorry! 59 | 60 | Q. At the end of build.py tinypy doesn't work! 61 | A. This is probably because of my use of -O3 in the final step. Run the command 62 | again without -O3. Some versions of GCC are buggy and don't do well with it. -------------------------------------------------------------------------------- /tinypy/asm.py: -------------------------------------------------------------------------------- 1 | def get_ops(): 2 | """ Builds an opcode name <-> value dictionary """ 3 | li = ["EOF","ADD","SUB","MUL","DIV","POW","BITAND","BITOR","CMP","GET", \ 4 | "SET","NUMBER","STRING","GGET","GSET","MOVE","DEF","PASS", \ 5 | "JUMP","CALL","RETURN","IF","DEBUG","EQ","LE","LT","DICT", \ 6 | "LIST","NONE","LEN","LINE","PARAMS","IGET","FILE","NAME", \ 7 | "NE","HAS","RAISE","SETJMP","MOD","LSH","RSH","ITER","DEL", \ 8 | "REGS","BITXOR", "IFN", "NOT", "BITNOT"] 9 | dic = {} 10 | for i in li: 11 | dic[i] = li.index(i) 12 | return dic 13 | 14 | def prepare(x): 15 | """ Prepares the line for processing by breaking it into tokens, 16 | removing empty tokens and stripping whitespace """ 17 | try: 18 | ind = x.index('"') 19 | except: 20 | ind = -1 21 | if ind != -1: 22 | d = x[ind:] 23 | x = x[:ind] 24 | x = x.split(' ') 25 | tmp = [] 26 | final = [] 27 | for i in x: 28 | if i: 29 | if i[0] != ':': 30 | tmp.append(i) 31 | for i in tmp[:4]: 32 | final.append(i) 33 | if not d: 34 | d = "".join(tmp[4:]) 35 | final.append(d.strip()) 36 | return final 37 | 38 | def dequote(x): 39 | """ Removes outermost quotes from a string, if they exist """ 40 | if x[0] == '"' and x[len(x)-1] == '"': 41 | return x[1:len(x)-1] 42 | return x 43 | 44 | def assemble(asmc): 45 | asmc = asmc.strip() 46 | asmc = asmc.split('\n') 47 | bc = [] 48 | ops = get_ops() 49 | for line in asmc: 50 | current = prepare(line) 51 | i,a,b,c,d = current 52 | a = int(a) 53 | b = int(b) 54 | c = int(c) 55 | bc.append(chr(ops[i])) 56 | bc.append(chr(a)) 57 | bc.append(chr(b)) 58 | bc.append(chr(c)) 59 | if i == "LINE": 60 | n = a * 4 61 | d = dequote(d) 62 | text = d 63 | text += chr(0) * (n - len(d)) 64 | bc.append(text) 65 | if i == "STRING": 66 | d = dequote(d) 67 | text = d + "\0"*(4-len(d)%4) 68 | bc.append(text) 69 | elif i == "NUMBER": 70 | d = int(d) 71 | bc.append(fpack(d)) 72 | bc = "".join(bc) 73 | return bc 74 | 75 | if __name__ == '__main__': 76 | asmc = load(ARGV[1]) 77 | bc = assemble(asmc) 78 | save(ARGV[2], bc) 79 | -------------------------------------------------------------------------------- /modules/random/init.c: -------------------------------------------------------------------------------- 1 | #include "random.c" 2 | 3 | /* 4 | * random_mod_init() 5 | * 6 | * random module initialization function 7 | */ 8 | void random_init(TP) 9 | { 10 | /* 11 | * module dict for random 12 | */ 13 | tp_obj random_mod = tp_dict(tp); 14 | 15 | /* 16 | * bind functions to random module 17 | */ 18 | tp_set(tp, random_mod, tp_string("seed"), tp_fnc(tp, random_seed)); 19 | tp_set(tp, random_mod, tp_string("getstate"), tp_fnc(tp, random_getstate)); 20 | tp_set(tp, random_mod, tp_string("setstate"), tp_fnc(tp, random_setstate)); 21 | tp_set(tp, random_mod, tp_string("jumpahead"), tp_fnc(tp, random_jumpahead)); 22 | tp_set(tp, random_mod, tp_string("random"), tp_fnc(tp, random_random)); 23 | 24 | /* 25 | * bind usual distribution random variable generator 26 | */ 27 | tp_set(tp, random_mod, tp_string("uniform"), tp_fnc(tp, random_uniform)); 28 | tp_set(tp, random_mod, tp_string("normalvariate"), tp_fnc(tp, random_normalvariate)); 29 | tp_set(tp, random_mod, tp_string("lognormvariate"), tp_fnc(tp, random_lognormvariate)); 30 | tp_set(tp, random_mod, tp_string("expovariate"), tp_fnc(tp, random_expovariate)); 31 | tp_set(tp, random_mod, tp_string("vonmisesvariate"), tp_fnc(tp, random_vonmisesvariate)); 32 | tp_set(tp, random_mod, tp_string("gammavariate"), tp_fnc(tp, random_gammavariate)); 33 | tp_set(tp, random_mod, tp_string("betavariate"), tp_fnc(tp, random_betavariate)); 34 | tp_set(tp, random_mod, tp_string("paretovariate"), tp_fnc(tp, random_paretovariate)); 35 | tp_set(tp, random_mod, tp_string("weibullvariate"), tp_fnc(tp, random_weibullvariate)); 36 | tp_set(tp, random_mod, tp_string("randrange"), tp_fnc(tp, random_randrange)); 37 | tp_set(tp, random_mod, tp_string("randint"), tp_fnc(tp, random_randint)); 38 | tp_set(tp, random_mod, tp_string("choice"), tp_fnc(tp, random_choice)); 39 | tp_set(tp, random_mod, tp_string("shuffle"), tp_fnc(tp, random_shuffle)); 40 | 41 | /* 42 | * bind special attributes to random module 43 | */ 44 | tp_set(tp, random_mod, tp_string("__doc__"), tp_string("Random variable generators.")); 45 | tp_set(tp, random_mod, tp_string("__name__"), tp_string("random")); 46 | tp_set(tp, random_mod, tp_string("__file__"), tp_string(__FILE__)); 47 | 48 | /* 49 | * bind random module to tinypy modules[] 50 | */ 51 | tp_set(tp, tp->modules, tp_string("random"), random_mod); 52 | } 53 | -------------------------------------------------------------------------------- /modules/math/init.c: -------------------------------------------------------------------------------- 1 | #include "math.c" 2 | 3 | /* 4 | * init math module, namely, set its dictionary 5 | */ 6 | void math_init(TP) 7 | { 8 | /* 9 | * new a module dict for math 10 | */ 11 | tp_obj math_mod = tp_dict(tp); 12 | 13 | /* 14 | * initialize pi and e 15 | */ 16 | math_pi = tp_number(M_PI); 17 | math_e = tp_number(M_E); 18 | 19 | /* 20 | * bind math functions to math module 21 | */ 22 | tp_set(tp, math_mod, tp_string("pi"), math_pi); 23 | tp_set(tp, math_mod, tp_string("e"), math_e); 24 | tp_set(tp, math_mod, tp_string("acos"), tp_fnc(tp, math_acos)); 25 | tp_set(tp, math_mod, tp_string("asin"), tp_fnc(tp, math_asin)); 26 | tp_set(tp, math_mod, tp_string("atan"), tp_fnc(tp, math_atan)); 27 | tp_set(tp, math_mod, tp_string("atan2"), tp_fnc(tp, math_atan2)); 28 | tp_set(tp, math_mod, tp_string("ceil"), tp_fnc(tp, math_ceil)); 29 | tp_set(tp, math_mod, tp_string("cos"), tp_fnc(tp, math_cos)); 30 | tp_set(tp, math_mod, tp_string("cosh"), tp_fnc(tp, math_cosh)); 31 | tp_set(tp, math_mod, tp_string("degrees"), tp_fnc(tp, math_degrees)); 32 | tp_set(tp, math_mod, tp_string("exp"), tp_fnc(tp, math_exp)); 33 | tp_set(tp, math_mod, tp_string("fabs"), tp_fnc(tp, math_fabs)); 34 | tp_set(tp, math_mod, tp_string("floor"), tp_fnc(tp, math_floor)); 35 | tp_set(tp, math_mod, tp_string("fmod"), tp_fnc(tp, math_fmod)); 36 | tp_set(tp, math_mod, tp_string("frexp"), tp_fnc(tp, math_frexp)); 37 | tp_set(tp, math_mod, tp_string("hypot"), tp_fnc(tp, math_hypot)); 38 | tp_set(tp, math_mod, tp_string("ldexp"), tp_fnc(tp, math_ldexp)); 39 | tp_set(tp, math_mod, tp_string("log"), tp_fnc(tp, math_log)); 40 | tp_set(tp, math_mod, tp_string("log10"), tp_fnc(tp, math_log10)); 41 | tp_set(tp, math_mod, tp_string("modf"), tp_fnc(tp, math_modf)); 42 | tp_set(tp, math_mod, tp_string("pow"), tp_fnc(tp, math_pow)); 43 | tp_set(tp, math_mod, tp_string("radians"), tp_fnc(tp, math_radians)); 44 | tp_set(tp, math_mod, tp_string("sin"), tp_fnc(tp, math_sin)); 45 | tp_set(tp, math_mod, tp_string("sinh"), tp_fnc(tp, math_sinh)); 46 | tp_set(tp, math_mod, tp_string("sqrt"), tp_fnc(tp, math_sqrt)); 47 | tp_set(tp, math_mod, tp_string("tan"), tp_fnc(tp, math_tan)); 48 | tp_set(tp, math_mod, tp_string("tanh"), tp_fnc(tp, math_tanh)); 49 | 50 | /* 51 | * bind special attributes to math module 52 | */ 53 | tp_set(tp, math_mod, tp_string("__doc__"), 54 | tp_string( 55 | "This module is always available. It provides access to the\n" 56 | "mathematical functions defined by the C standard.")); 57 | tp_set(tp, math_mod, tp_string("__name__"), tp_string("math")); 58 | tp_set(tp, math_mod, tp_string("__file__"), tp_string(__FILE__)); 59 | 60 | /* 61 | * bind to tiny modules[] 62 | */ 63 | tp_set(tp, tp->modules, tp_string("math"), math_mod); 64 | } 65 | 66 | -------------------------------------------------------------------------------- /tinypy/disasm.py: -------------------------------------------------------------------------------- 1 | import sys 2 | __tinypy__ = "tinypy" in sys.version 3 | if not __tinypy__: 4 | from boot import * 5 | __tinypy__ = False 6 | else: 7 | __tinypy__ = True 8 | 9 | def get_ops(): 10 | """ Builds an value <-> opcode name dictionary """ 11 | li = ["EOF","ADD","SUB","MUL","DIV","POW","BITAND","BITOR","CMP","GET", \ 12 | "SET","NUMBER","STRING","GGET","GSET","MOVE","DEF","PASS", \ 13 | "JUMP","CALL","RETURN","IF","DEBUG","EQ","LE","LT","DICT", \ 14 | "LIST","NONE","LEN","LINE","PARAMS","IGET","FILE","NAME", \ 15 | "NE","HAS","RAISE","SETJMP","MOD","LSH","RSH","ITER","DEL", \ 16 | "REGS","BITXOR", "IFN", "NOT", "BITNOT"] 17 | dic = {} 18 | for i in li: 19 | dic[li.index(i)] = i 20 | return dic 21 | 22 | def isupper(x): 23 | return ord(x) >= ord("A") and ord(x) <= ord("Z") 24 | 25 | def pad(s, n): 26 | p = "" 27 | if n < 0: 28 | m = -n - len(s) 29 | if m > 0: p = " " * m 30 | return p + s 31 | m = n - len(s) 32 | if m > 0: p = " " * m 33 | return s + p 34 | 35 | def funpack(bytes): 36 | if not __tinypy__: 37 | import struct 38 | return struct.unpack("d", bytes)[0] 39 | def eat(x, bit): 40 | y = int(x / 2 ** bit) 41 | x -= y * 2 ** bit 42 | return x, y 43 | x = 0 44 | for i in range(8): 45 | x += ord(bytes[i]) * 2 ** (i * 8) 46 | x, sign = eat(x, 63) 47 | x, exponent = eat(x, 52) 48 | x, mantissa1 = eat(x, 31) 49 | x, mantissa2 = eat(x, 0) 50 | mantissa = mantissa1 * 2 ** 31 + mantissa2 51 | sign = sign * -2 + 1 52 | x = sign * 2 ** (exponent - 1023) * (1 + mantissa / 2 ** 52) 53 | return x 54 | 55 | def text(x, ip, bc): 56 | return "".join([chr(c) for c in bc[ip:ip+x]]) 57 | 58 | def trim(x): 59 | txt = [] 60 | for c in x: 61 | if ord(c): 62 | txt.append(c) 63 | return "".join(txt) 64 | 65 | def disassemble(bc): 66 | bc = [ord(x) for x in bc] 67 | asmc = [] 68 | ip = 0 69 | names = get_ops() 70 | while ip < len(bc): 71 | i, a, b, c = bc[ip:ip + 4] 72 | line = "" 73 | line += pad(names[i], 10) + ":" 74 | line += " " + pad(str(a), -3) 75 | line += " " + pad(str(b), -3) 76 | line += " " + pad(str(c), -3) 77 | ip += 4 78 | if names[i] == "LINE": 79 | n = a * 4 80 | line += " \"" + text(n,ip,bc) + "\"" 81 | line = trim(line) 82 | ip += n 83 | elif names[i] == "STRING": 84 | n = b * 256 + c 85 | line += " \"" + text(n,ip,bc) + "\"" 86 | line = trim(line) 87 | derp = n / 4 88 | derp = int(derp) 89 | ip += (derp + 1) * 4 90 | elif names[i] == "NUMBER": 91 | f = funpack(text(8,ip,bc)) 92 | line += " " + str(f) 93 | ip += 8 94 | asmc.append(line) 95 | asmc = "\n".join(asmc) 96 | return asmc 97 | 98 | if __name__ == "__main__": 99 | bc = load(ARGV[1]) 100 | asmc = disassemble(bc) 101 | print(asmc) 102 | -------------------------------------------------------------------------------- /tinypy/sandbox.c: -------------------------------------------------------------------------------- 1 | 2 | #ifdef TP_NORMALMAKE 3 | #include "tp.h" 4 | #include "builtins_auto.h" 5 | #include "dict_auto.h" 6 | #include "list_auto.h" 7 | #include "misc_auto.h" 8 | #include "string_auto.h" 9 | #endif 10 | 11 | void tp_sandbox(TP, double time_limit, unsigned long mem_limit) { 12 | tp->time_limit = time_limit; 13 | tp->mem_limit = mem_limit; 14 | } 15 | 16 | void tp_mem_update(TP) { 17 | /* static long maxmem = 0; 18 | if (tp->mem_used/1024 > maxmem) { 19 | maxmem = tp->mem_used/1024; 20 | fprintf(stderr,"%ld k\n",maxmem); 21 | }*/ 22 | if((!tp->mem_exceeded) && 23 | (tp->mem_used > tp->mem_limit) && 24 | (tp->mem_limit != TP_NO_LIMIT)) { 25 | tp->mem_exceeded = 1; 26 | tp_raise(,tp_string("(tp_mem_update) SandboxError: memory limit exceeded")); 27 | } 28 | } 29 | 30 | void tp_time_update(TP) { 31 | clock_t tmp = tp->clocks; 32 | if(tp->time_limit != TP_NO_LIMIT) 33 | { 34 | tp->clocks = clock(); 35 | tp->time_elapsed += ((double) (tp->clocks - tmp) / CLOCKS_PER_SEC) * 1000.0; 36 | if(tp->time_elapsed >= tp->time_limit) 37 | tp_raise(,tp_string("(tp_time_update) SandboxError: time limit exceeded")); 38 | } 39 | } 40 | 41 | #ifdef TP_SANDBOX 42 | 43 | void *tp_malloc(TP, unsigned long bytes) { 44 | unsigned long *ptr = (unsigned long *) calloc(bytes + sizeof(unsigned long), 1); 45 | if(ptr) { 46 | *ptr = bytes; 47 | tp->mem_used += bytes + sizeof(unsigned long); 48 | } 49 | tp_mem_update(tp); 50 | return ptr+1; 51 | } 52 | 53 | void tp_free(TP, void *ptr) { 54 | unsigned long *temp = (unsigned long *) ptr; 55 | if(temp) { 56 | --temp; 57 | tp->mem_used -= (*temp + sizeof(unsigned long)); 58 | free(temp); 59 | } 60 | tp_mem_update(tp); 61 | } 62 | 63 | void *tp_realloc(TP, void *ptr, unsigned long bytes) { 64 | unsigned long *temp = (unsigned long *) ptr; 65 | int diff; 66 | if(temp && bytes) { 67 | --temp; 68 | diff = bytes - *temp; 69 | *temp = bytes; 70 | tp->mem_used += diff; 71 | temp = (unsigned long *) realloc(temp, bytes+sizeof(unsigned long)); 72 | return temp+1; 73 | } 74 | else if(temp && !bytes) { 75 | tp_free(tp, temp); 76 | return NULL; 77 | } 78 | else if(!temp && bytes) { 79 | return tp_malloc(tp, bytes); 80 | } 81 | else { 82 | return NULL; 83 | } 84 | } 85 | 86 | #endif 87 | 88 | tp_obj tp_sandbox_(TP) { 89 | tp_num time = TP_NUM(); 90 | tp_num mem = TP_NUM(); 91 | tp_sandbox(tp, time, mem); 92 | tp_del(tp, tp->builtins, tp_string("sandbox")); 93 | tp_del(tp, tp->builtins, tp_string("mtime")); 94 | tp_del(tp, tp->builtins, tp_string("load")); 95 | tp_del(tp, tp->builtins, tp_string("save")); 96 | tp_del(tp, tp->builtins, tp_string("system")); 97 | return tp_None; 98 | } 99 | 100 | void tp_bounds(TP, tp_code *cur, int n) { 101 | char *s = (char *)(cur + n); 102 | tp_frame_ *frame = tp_frame_current(tp); 103 | if( frame ) { 104 | tp_obj code = frame->code; 105 | if (s < code.string.val || s > (code.string.val+code.string.len)) { 106 | tp_raise(,tp_string("(tp_bounds) SandboxError: bytecode bounds reached")); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tinypy/gc.c: -------------------------------------------------------------------------------- 1 | /* tp_obj tp_track(TP,tp_obj v) { return v; } 2 | void tp_grey(TP,tp_obj v) { } 3 | void tp_full(TP) { } 4 | void tp_gc_init(TP) { } 5 | void tp_gc_deinit(TP) { } 6 | void tp_delete(TP,tp_obj v) { }*/ 7 | 8 | #ifdef TP_NORMALMAKE 9 | #include "tp.h" 10 | #include "list_auto.h" 11 | #include "dict_auto.h" 12 | #endif 13 | 14 | void tp_grey(TP,tp_obj v) { 15 | if (v.type < TP_STRING || (!v.gci.data) || *v.gci.data) { return; } 16 | *v.gci.data = 1; 17 | if (v.type == TP_STRING || v.type == TP_DATA) { 18 | _tp_list_appendx(tp,tp->black,v); 19 | return; 20 | } 21 | _tp_list_appendx(tp,tp->grey,v); 22 | } 23 | 24 | void tp_follow(TP,tp_obj v) { 25 | int type = v.type; 26 | if (type == TP_LIST) { 27 | int n; 28 | for (n=0; nlen; n++) { 29 | tp_grey(tp,v.list.val->items[n]); 30 | } 31 | } 32 | if (type == TP_DICT) { 33 | int i; 34 | for (i=0; ilen; i++) { 35 | int n = _tp_dict_next(tp,v.dict.val); 36 | tp_grey(tp,v.dict.val->items[n].key); 37 | tp_grey(tp,v.dict.val->items[n].val); 38 | } 39 | tp_grey(tp,v.dict.val->meta); 40 | } 41 | if (type == TP_FNC) { 42 | tp_grey(tp,v.fnc.info->self); 43 | tp_grey(tp,v.fnc.info->globals); 44 | tp_grey(tp,v.fnc.info->code); 45 | } 46 | } 47 | 48 | void tp_reset(TP) { 49 | int n; 50 | _tp_list *tmp; 51 | for (n=0; nblack->len; n++) { 52 | *tp->black->items[n].gci.data = 0; 53 | } 54 | tmp = tp->white; 55 | tp->white = tp->black; 56 | tp->black = tmp; 57 | } 58 | 59 | void tp_gc_init(TP) { 60 | tp->white = _tp_list_new(tp); 61 | tp->grey = _tp_list_new(tp); 62 | tp->black = _tp_list_new(tp); 63 | tp->steps = 0; 64 | } 65 | 66 | void tp_gc_deinit(TP) { 67 | _tp_list_free(tp, tp->white); 68 | _tp_list_free(tp, tp->grey); 69 | _tp_list_free(tp, tp->black); 70 | } 71 | 72 | void tp_delete(TP,tp_obj v) { 73 | int type = v.type; 74 | if (type == TP_LIST) { 75 | _tp_list_free(tp, v.list.val); 76 | return; 77 | } else if (type == TP_DICT) { 78 | _tp_dict_free(tp, v.dict.val); 79 | return; 80 | } else if (type == TP_STRING) { 81 | tp_free(tp, v.string.info); 82 | return; 83 | } else if (type == TP_DATA) { 84 | if (v.data.info->free) { 85 | v.data.info->free(tp,v); 86 | } 87 | tp_free(tp, v.data.info); 88 | return; 89 | } else if (type == TP_FNC) { 90 | tp_free(tp, v.fnc.info); 91 | return; 92 | } 93 | else if( type == TP_FRAME ) { 94 | tp_frame_ *f = v.frame.val; 95 | tp_free(tp, f); 96 | return; 97 | } 98 | tp_raise(,tp_string("(tp_delete) TypeError: ?")); 99 | } 100 | 101 | void tp_collect(TP) { 102 | int n; 103 | for (n=0; nwhite->len; n++) { 104 | tp_obj r = tp->white->items[n]; 105 | if (*r.gci.data) { continue; } 106 | tp_delete(tp,r); 107 | } 108 | tp->white->len = 0; 109 | tp_reset(tp); 110 | } 111 | 112 | void _tp_gcinc(TP) { 113 | tp_obj v; 114 | if (!tp->grey->len) { 115 | return; 116 | } 117 | v = _tp_list_pop(tp,tp->grey,tp->grey->len-1,"_tp_gcinc"); 118 | tp_follow(tp,v); 119 | _tp_list_appendx(tp,tp->black,v); 120 | } 121 | 122 | void tp_full(TP) { 123 | while (tp->grey->len) { 124 | _tp_gcinc(tp); 125 | } 126 | tp_collect(tp); 127 | tp_follow(tp,tp->root); 128 | } 129 | 130 | void tp_gcinc(TP) { 131 | tp->steps += 1; 132 | if (tp->steps < TP_GCMAX || tp->grey->len > 0) { 133 | _tp_gcinc(tp); _tp_gcinc(tp); 134 | } 135 | if (tp->steps < TP_GCMAX || tp->grey->len > 0) { return; } 136 | tp->steps = 0; 137 | tp_full(tp); 138 | return; 139 | } 140 | 141 | tp_obj tp_track(TP,tp_obj v) { 142 | tp_gcinc(tp); 143 | tp_grey(tp,v); 144 | return v; 145 | } 146 | 147 | /**/ 148 | 149 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | 3 | tinypy contains tinypy code licensed in a MIT format license. It also 4 | contains some goodies grabbed from Python, so that license is included 5 | as well. 6 | 7 | ================================================================================ 8 | 9 | The tinypy License 10 | 11 | Copyright (c) 2008 Phil Hassey 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in 21 | all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | 31 | ================================================================================ 32 | 33 | PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 34 | -------------------------------------------- 35 | 36 | 1. This LICENSE AGREEMENT is between the Python Software Foundation 37 | ("PSF"), and the Individual or Organization ("Licensee") accessing and 38 | otherwise using this software ("Python") in source or binary form and 39 | its associated documentation. 40 | 41 | 2. Subject to the terms and conditions of this License Agreement, PSF 42 | hereby grants Licensee a nonexclusive, royalty-free, world-wide 43 | license to reproduce, analyze, test, perform and/or display publicly, 44 | prepare derivative works, distribute, and otherwise use Python 45 | alone or in any derivative version, provided, however, that PSF's 46 | License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 47 | 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation; 48 | All Rights Reserved" are retained in Python alone or in any derivative 49 | version prepared by Licensee. 50 | 51 | 3. In the event Licensee prepares a derivative work that is based on 52 | or incorporates Python or any part thereof, and wants to make 53 | the derivative work available to others as provided herein, then 54 | Licensee hereby agrees to include in any such work a brief summary of 55 | the changes made to Python. 56 | 57 | 4. PSF is making Python available to Licensee on an "AS IS" 58 | basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR 59 | IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND 60 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS 61 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT 62 | INFRINGE ANY THIRD PARTY RIGHTS. 63 | 64 | 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 65 | FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS 66 | A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, 67 | OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 68 | 69 | 6. This License Agreement will automatically terminate upon a material 70 | breach of its terms and conditions. 71 | 72 | 7. Nothing in this License Agreement shall be deemed to create any 73 | relationship of agency, partnership, or joint venture between PSF and 74 | Licensee. This License Agreement does not grant permission to use PSF 75 | trademarks or trade name in a trademark sense to endorse or promote 76 | products or services of Licensee, or any third party. 77 | 78 | 8. By copying, installing or otherwise using Python, Licensee 79 | agrees to be bound by the terms and conditions of this License 80 | Agreement. 81 | 82 | ================================================================================ 83 | -------------------------------------------------------------------------------- /examples/asteroid.py: -------------------------------------------------------------------------------- 1 | """ 2 | a simple diversing asteroids simulation 3 | """ 4 | 5 | import sys 6 | import math 7 | import random 8 | import pygame 9 | if "tinypy" not in sys.version: # not tinypy 10 | import pygame.locals 11 | 12 | SCR_WIDTH = 600 13 | SCR_HEIGHT = 600 14 | NASTEROIDS = 320 # number of asteroids 15 | INIT_NASTEROIDS = 80 # initial number of asteroids 16 | OFFSET = 20 # max initial offset 17 | DIV_FACTOR = 1.1 # diverse factor 18 | 19 | class Center(object): 20 | x = SCR_WIDTH / 2 21 | y = SCR_HEIGHT / 2 22 | 23 | class Graphics(object): 24 | x = 0 25 | y = 0 26 | w = SCR_WIDTH 27 | h = SCR_HEIGHT 28 | center = Center() 29 | BACKGROUND = (0, 0, 0) # black background 30 | 31 | def __init__(self): 32 | pygame.init() 33 | self.screen = pygame.display.set_mode((SCR_WIDTH, SCR_HEIGHT)) 34 | self.clearScreen() 35 | def drawRect(self, sx, sy, w, h, color): 36 | sx = int(sx) 37 | sy = int(sy) 38 | dx = int(sx + w) 39 | dy = int(sy + h) 40 | for x in range(sx, dx): 41 | for y in range(sy, dy): 42 | self.screen.set_at((x, y), color) 43 | def clearScreen(self): 44 | for x in range(SCR_WIDTH): 45 | for y in range(SCR_HEIGHT): 46 | self.screen.set_at((x, y), self.BACKGROUND) 47 | def flipDisplay(self): 48 | pygame.display.flip() 49 | 50 | class Asteroid(object): 51 | graphics = Graphics() 52 | def __init__(self): 53 | self.x = 0 # x and y, set to invalid position 54 | self.y = 0 55 | self.size = 1 56 | self.color = [0, 0, 0] 57 | def show(self): 58 | self.graphics.drawRect(self.x, self.y, self.size, self.size, self.color) 59 | def hide(self): 60 | self.graphics.drawRect(self.x, self.y, self.size, self.size, self.graphics.BACKGROUND) 61 | def update(self): 62 | # update asteroids[i]'s position 63 | if (self.x <= self.graphics.x or self.x >= self.graphics.w or 64 | self.y <= self.graphics.y or self.y >= self.graphics.h): 65 | self.x = self.graphics.center.x - OFFSET + OFFSET * 2 * random.random() 66 | self.y = self.graphics.center.y - OFFSET + OFFSET * 2 * random.random() 67 | self.color[0] = random.randint(20, 255) 68 | self.color[1] = random.randint(20, 255) 69 | self.color[2] = random.randint(20, 255) 70 | else: 71 | gx = self.graphics.center.x + (self.x - self.graphics.center.x) * DIV_FACTOR 72 | if (math.fabs(self.x - self.graphics.center.x) < 1e-6): 73 | gy = self.graphics.center.y + (self.y - self.graphics.center.y) * DIV_FACTOR 74 | else: 75 | k = (gx - self.graphics.center.x) / (self.x - self.graphics.center.x) 76 | gy = self.graphics.center.y + (self.y - self.graphics.center.y) * k 77 | self.x = gx 78 | self.y = gy 79 | 80 | # update self's size 81 | self.size = int(5 * ((math.fabs(self.x - self.graphics.center.x) * 2) / self.graphics.w)) 82 | if self.size <= 1: 83 | self.size = 1 84 | 85 | def main(): 86 | asteroids = [] 87 | for i in range(INIT_NASTEROIDS): 88 | asteroid = Asteroid() 89 | asteroid.update() 90 | asteroids.append(asteroid) 91 | 92 | _quit = False 93 | while not _quit: 94 | for e in pygame.event.get(): 95 | if e.type in (pygame.locals.QUIT, pygame.locals.KEYDOWN): 96 | _quit = True 97 | 98 | if (len(asteroids) < NASTEROIDS): 99 | asteroid = Asteroid() 100 | asteroid.update() 101 | asteroids.append(asteroid) 102 | 103 | for i in range(len(asteroids)): 104 | # hide asteroids[i] 105 | asteroids[i].hide() 106 | 107 | # update asteroids[i] 108 | asteroids[i].update() 109 | 110 | # show asteroids[i] 111 | asteroids[i].show() 112 | 113 | # swap display content actually 114 | Asteroid.graphics.flipDisplay() 115 | 116 | if __name__ == '__main__': 117 | main() 118 | print("#OK") 119 | -------------------------------------------------------------------------------- /tinypy/list.c: -------------------------------------------------------------------------------- 1 | #ifdef TP_NORMALMAKE 2 | #include "tp.h" 3 | #include "list_auto.h" 4 | #endif 5 | 6 | void _tp_list_realloc(TP, _tp_list *self,int len) { 7 | if (!len) { len=1; } 8 | self->items = (tp_obj*)tp_realloc(tp, self->items,len*sizeof(tp_obj)); 9 | self->alloc = len; 10 | } 11 | 12 | void _tp_list_set(TP,_tp_list *self,int k, tp_obj v, const char *error) { 13 | if (k >= self->len) { 14 | tp_raise(,tp_string("(_tp_list_set) KeyError")); 15 | } 16 | self->items[k] = v; 17 | tp_grey(tp,v); 18 | } 19 | void _tp_list_free(TP, _tp_list *self) { 20 | tp_free(tp, self->items); 21 | tp_free(tp, self); 22 | } 23 | 24 | tp_obj _tp_list_get(TP,_tp_list *self,int k,const char *error) { 25 | if (k >= self->len) { 26 | tp_raise(tp_None,tp_string("(_tp_list_get) KeyError")); 27 | } 28 | return self->items[k]; 29 | } 30 | void _tp_list_insertx(TP,_tp_list *self, int n, tp_obj v) { 31 | if (self->len >= self->alloc) { 32 | _tp_list_realloc(tp, self,self->alloc*2); 33 | } 34 | if (n < self->len) { memmove(&self->items[n+1],&self->items[n],sizeof(tp_obj)*(self->len-n)); } 35 | self->items[n] = v; 36 | self->len += 1; 37 | } 38 | void _tp_list_appendx(TP,_tp_list *self, tp_obj v) { 39 | _tp_list_insertx(tp,self,self->len,v); 40 | } 41 | void _tp_list_insert(TP,_tp_list *self, int n, tp_obj v) { 42 | _tp_list_insertx(tp,self,n,v); 43 | tp_grey(tp,v); 44 | } 45 | void _tp_list_append(TP,_tp_list *self, tp_obj v) { 46 | _tp_list_insert(tp,self,self->len,v); 47 | } 48 | tp_obj _tp_list_pop(TP,_tp_list *self, int n, const char *error) { 49 | tp_obj r = _tp_list_get(tp,self,n,error); 50 | if (n != self->len-1) { memmove(&self->items[n],&self->items[n+1],sizeof(tp_obj)*(self->len-(n+1))); } 51 | self->len -= 1; 52 | return r; 53 | } 54 | 55 | int _tp_list_find(TP,_tp_list *self, tp_obj v) { 56 | int n; 57 | for (n=0; nlen; n++) { 58 | if (tp_cmp(tp,v,self->items[n]) == 0) { 59 | return n; 60 | } 61 | } 62 | return -1; 63 | } 64 | 65 | tp_obj tp_index(TP) { 66 | tp_obj self = TP_OBJ(); 67 | tp_obj v = TP_OBJ(); 68 | int i = _tp_list_find(tp,self.list.val,v); 69 | if (i < 0) { 70 | tp_raise(tp_None,tp_string("(tp_index) ValueError: list.index(x): x not in list")); 71 | } 72 | return tp_number(i); 73 | } 74 | 75 | _tp_list *_tp_list_new(TP) { 76 | return (_tp_list*)tp_malloc(tp, sizeof(_tp_list)); 77 | } 78 | 79 | tp_obj _tp_list_copy(TP, tp_obj rr) { 80 | tp_obj val = {TP_LIST}; 81 | _tp_list *o = rr.list.val; 82 | _tp_list *r = _tp_list_new(tp); 83 | *r = *o; r->gci = 0; 84 | r->items = (tp_obj*)tp_malloc(tp, sizeof(tp_obj)*o->len); 85 | memcpy(r->items,o->items,sizeof(tp_obj)*o->len); 86 | val.list.val = r; 87 | return tp_track(tp,val); 88 | } 89 | 90 | tp_obj tp_append(TP) { 91 | tp_obj self = TP_OBJ(); 92 | tp_obj v = TP_OBJ(); 93 | _tp_list_append(tp,self.list.val,v); 94 | return tp_None; 95 | } 96 | 97 | tp_obj tp_pop(TP) { 98 | tp_obj self = TP_OBJ(); 99 | return _tp_list_pop(tp,self.list.val,self.list.val->len-1,"pop"); 100 | } 101 | 102 | tp_obj tp_insert(TP) { 103 | tp_obj self = TP_OBJ(); 104 | int n = TP_NUM(); 105 | tp_obj v = TP_OBJ(); 106 | _tp_list_insert(tp,self.list.val,n,v); 107 | return tp_None; 108 | } 109 | 110 | tp_obj tp_extend(TP) { 111 | tp_obj self = TP_OBJ(); 112 | tp_obj v = TP_OBJ(); 113 | int i; 114 | for (i=0; ilen; i++) { 115 | _tp_list_append(tp,self.list.val,v.list.val->items[i]); 116 | } 117 | return tp_None; 118 | } 119 | 120 | tp_obj tp_list_nt(TP) { 121 | tp_obj r = {TP_LIST}; 122 | r.list.val = _tp_list_new(tp); 123 | return r; 124 | } 125 | 126 | tp_obj tp_list(TP) { 127 | tp_obj r = {TP_LIST}; 128 | r.list.val = _tp_list_new(tp); 129 | return tp_track(tp,r); 130 | } 131 | 132 | tp_obj tp_list_n(TP,int n,tp_obj *argv) { 133 | int i; 134 | tp_obj r = tp_list(tp); _tp_list_realloc(tp, r.list.val,n); 135 | for (i=0; iitems, self.list.val->len, sizeof(tp_obj), (int(*)(const void*,const void*))_tp_sort_cmp); 148 | return tp_None; 149 | } 150 | 151 | -------------------------------------------------------------------------------- /tinypy/misc.c: -------------------------------------------------------------------------------- 1 | /* File: Miscellaneous 2 | * Various functions to help interface tinypy. 3 | */ 4 | #ifdef TP_NORMALMAKE 5 | #include "tp.h" 6 | #include "list_auto.h" 7 | #endif 8 | 9 | tp_obj _tp_dcall(TP,tp_obj fnc(TP)) { 10 | return fnc(tp); 11 | } 12 | tp_obj _tp_tcall(TP,tp_obj fnc) { 13 | if (fnc.fnc.ftype&2) { 14 | _tp_list_insert(tp,tp->params.list.val,0,fnc.fnc.info->self); 15 | } 16 | return _tp_dcall(tp,(tp_obj (*)(tp_vm *))fnc.fnc.cfnc); 17 | } 18 | 19 | tp_obj tp_fnc_new(TP,int t, void *v, tp_obj c,tp_obj s, tp_obj g) { 20 | tp_obj r = {TP_FNC}; 21 | _tp_fnc *info = (_tp_fnc*)tp_malloc(tp, sizeof(_tp_fnc)); 22 | info->code = c; 23 | info->self = s; 24 | info->globals = g; 25 | r.fnc.ftype = t; 26 | r.fnc.info = info; 27 | r.fnc.cfnc = v; 28 | return tp_track(tp,r); 29 | } 30 | 31 | tp_obj tp_def(TP,tp_obj code, tp_obj g) { 32 | tp_obj r = tp_fnc_new(tp,1,0,code,tp_None,g); 33 | return r; 34 | } 35 | 36 | /* Function: tp_fnc 37 | * Creates a new tinypy function object. 38 | * 39 | * This is how you can create a tinypy function object which, when called in 40 | * the script, calls the provided C function. 41 | */ 42 | tp_obj tp_fnc(TP,tp_obj v(TP)) { 43 | return tp_fnc_new(tp,0,v,tp_None,tp_None,tp_None); 44 | } 45 | 46 | tp_obj tp_method(TP,tp_obj self,tp_obj v(TP)) { 47 | return tp_fnc_new(tp,2,v,tp_None,self,tp_None); 48 | } 49 | 50 | /* Function: tp_data 51 | * Creates a new data object. 52 | * 53 | * Parameters: 54 | * magic - An integer number associated with the data type. This can be used 55 | * to check the type of data objects. 56 | * v - A pointer to user data. Only the pointer is stored in the object, 57 | * you keep all responsibility for the data it points to. 58 | * 59 | * 60 | * Returns: 61 | * The new data object. 62 | * 63 | * Public fields: 64 | * The following fields can be access in a data object: 65 | * 66 | * magic - An integer number stored in the object. 67 | * val - The data pointer of the object. 68 | * info->free - If not NULL, a callback function called when the object gets 69 | * destroyed. 70 | * 71 | * Example: 72 | * > void *__free__(TP, tp_obj self) 73 | * > { 74 | * > free(self.data.val); 75 | * > } 76 | * > 77 | * > tp_obj my_obj = tp_data(TP, 0, my_ptr); 78 | * > my_obj.data.info->free = __free__; 79 | */ 80 | tp_obj tp_data(TP,int magic,void *v) { 81 | tp_obj r = {TP_DATA}; 82 | r.data.info = (_tp_data*)tp_malloc(tp, sizeof(_tp_data)); 83 | r.data.val = v; 84 | r.data.magic = magic; 85 | return tp_track(tp,r); 86 | } 87 | 88 | /* Function: tp_params 89 | * Initialize the tinypy parameters. 90 | * 91 | * When you are calling a tinypy function, you can use this to initialize the 92 | * list of parameters getting passed to it. Usually, you may want to use 93 | * or . 94 | */ 95 | tp_obj tp_params(TP) { 96 | tp_frame_ *frame = tp_frame_current(tp); 97 | tp->params = frame->params; 98 | tp->params.list.val->len = 0; 99 | return tp->params; 100 | } 101 | 102 | /* Function: tp_params_n 103 | * Specify a list of objects as function call parameters. 104 | * 105 | * See also: , 106 | * 107 | * Parameters: 108 | * n - The number of parameters. 109 | * argv - A list of n tinypy objects, which will be passed as parameters. 110 | * 111 | * Returns: 112 | * The parameters list. You may modify it before performing the function call. 113 | */ 114 | tp_obj tp_params_n(TP,int n, tp_obj argv[]) { 115 | tp_obj r = tp_params(tp); 116 | int i; for (i=0; i>', 21 | '-=','+=','*=','/=','=','==','!=','<','>', '|=', '&=', '^=', 22 | '<=','>=','[',']','{','}','(',')','.',':',',',';','&','|','!', '^' 23 | ] 24 | B_BEGIN,B_END = ['[','(','{'],[']',')','}'] 25 | 26 | class TData: 27 | def __init__(self): 28 | self.y,self.yi,self.nl = 1,0,True 29 | self.res,self.indent,self.braces = [],[0],0 30 | def add(self,t,v): self.res.append(Token(self.f,t,v)) 31 | 32 | def clean(s): 33 | s = s.replace('\r\n','\n') 34 | s = s.replace('\r','\n') 35 | return s 36 | 37 | def tokenize(s): 38 | global T 39 | s = clean(s) 40 | T,i,l = TData(),0,len(s) 41 | try: return do_tokenize(s,i,l) 42 | except: u_error('tokenize',s,T.f) 43 | 44 | def do_tokenize(s,i,l): 45 | global T 46 | T.f = (T.y,i-T.yi+1) 47 | while i < l: 48 | c = s[i]; T.f = (T.y,i-T.yi+1) 49 | if T.nl: T.nl = False; i = do_indent(s,i,l) 50 | elif c == '\n': i = do_nl(s,i,l) 51 | elif c in ISYMBOLS: i = do_symbol(s,i,l) 52 | elif c >= '0' and c <= '9': i = do_number(s,i,l) 53 | elif (c >= 'a' and c <= 'z') or \ 54 | (c >= 'A' and c <= 'Z') or c == '_': i = do_name(s,i,l) 55 | elif c=='"' or c=="'": i = do_string(s,i,l) 56 | elif c=='#': i = do_comment(s,i,l) 57 | elif c == '\\' and s[i+1] == '\n': 58 | i += 2; T.y,T.yi = T.y+1,i 59 | elif c == ' ' or c == '\t': i += 1 60 | else: u_error('tokenize',s,T.f) 61 | indent(0) 62 | r = T.res; T = None 63 | #for t in r: 64 | #print (t.pos,t.type,t.val) 65 | return r 66 | 67 | def do_nl(s,i,l): 68 | if not T.braces: 69 | T.add('nl',None) 70 | i,T.nl = i+1,True 71 | T.y,T.yi = T.y+1,i 72 | return i 73 | 74 | def do_indent(s,i,l): 75 | v = 0 76 | while i T.indent[-1]: 86 | T.indent.append(v) 87 | T.add('indent',v) 88 | elif v < T.indent[-1]: 89 | n = T.indent.index(v) 90 | while len(T.indent) > n+1: 91 | v = T.indent.pop() 92 | T.add('dedent',v) 93 | 94 | def do_symbol(s,i,l): 95 | symbols = [] 96 | v,f,i = s[i],i,i+1 97 | if v in SYMBOLS: symbols.append(v) 98 | while i '9') and (c < 'a' or c > 'f') and c != 'x': break 114 | v,i = v+c,i+1 115 | if c == '.': 116 | v,i = v+c,i+1 117 | while i '9': break 120 | v,i = v+c,i+1 121 | T.add('number',v) 122 | return i 123 | 124 | def do_name(s,i,l): 125 | v,i =s[i],i+1 126 | while i 'z') and (c < 'A' or c > 'Z') and (c < '0' or c > '9') and c != '_': break 129 | v,i = v+c,i+1 130 | if v in SYMBOLS: T.add('symbol',v) 131 | else: T.add('name',v) 132 | return i 133 | 134 | def do_string(s,i,l): 135 | v,q,i = '',s[i],i+1 136 | if (l-i) >= 5 and s[i] == q and s[i+1] == q: # """ 137 | i += 2 138 | while i len(state1) / 2): 33 | print("rep = ", rep, "len(state1) = ", len(state1)) 34 | raise "state1 and state2 should be different" 35 | 36 | # for the same seeds, state1 and state2 should be the same 37 | random.seed(100) 38 | state1 = random.getstate() 39 | random.seed(100) 40 | state2 = random.getstate() 41 | rep = 0 42 | for ind in range(len(state1)): 43 | elem1 = state1[ind] 44 | elem2 = state2[ind] 45 | if (elem1 == elem2): rep += 1 46 | if (rep != len(state1)): 47 | raise "state1 and state2 should be the same" 48 | 49 | def test_jumpahead(): 50 | """jumpahead will change the pseudo-number generator's internal state 51 | """ 52 | random.seed() 53 | state1 = random.getstate() 54 | random.jumpahead(20) 55 | state2 = random.getstate() 56 | rep = 0 57 | for ind in range(len(state1)): 58 | elem1 = state1[ind] 59 | elem2 = state2[ind] 60 | if (elem1 == elem2): rep += 1 61 | if (rep > len(state1) / 2): 62 | raise "state1 and state2 can't be the same" 63 | 64 | def test_setstate(): 65 | """ 66 | """ 67 | random.seed() 68 | oldState = random.getstate() 69 | oldRandSeq = [random.random() for i in range(10)] 70 | random.setstate(oldState) 71 | newRandSeq = [random.random() for i in range(10)] 72 | rep = 0 73 | for ind in range(len(oldRandSeq)): 74 | elem1 = oldRandSeq[ind] 75 | elem2 = newRandSeq[ind] 76 | if (elem1 == elem2): rep += 1 77 | if (rep != len(oldRandSeq)): 78 | raise "oldRandSeq and newRandSeq should be the same" 79 | 80 | def test_random(): 81 | """generate a random number list 82 | """ 83 | x = [random.random() for i in range(100)] 84 | 85 | def test_distribution(): 86 | """these lines are borrowed from python, they shouldn't 87 | cause any exception. 88 | """ 89 | g = random 90 | g.uniform(1,10) 91 | g.paretovariate(1.0) 92 | g.expovariate(1.0) 93 | g.weibullvariate(1.0, 1.0) 94 | g.normalvariate(0.0, 1.0) 95 | g.lognormvariate(0.0, 1.0) 96 | g.vonmisesvariate(0.0, 1.0) 97 | g.gammavariate(0.01, 1.0) 98 | g.gammavariate(1.0, 1.0) 99 | g.gammavariate(200.0, 1.0) 100 | g.betavariate(3.0, 3.0) 101 | 102 | def test_randrange(): 103 | """these input to randrange() shouldn't cause any exception. 104 | """ 105 | random.randrange(100000) 106 | random.randrange(-100000) 107 | random.randrange(0) 108 | random.randrange(-10.2) 109 | 110 | random.randrange(-10, 10) 111 | random.randrange(2, 1000) 112 | random.randrange(0, 1) 113 | random.randrange(-1, 0) 114 | 115 | random.randrange(10, 2000, 2) 116 | random.randrange(-2000, 100, 5) 117 | random.randrange(-1000.3, 1000.7, 2) 118 | 119 | def test_randint(): 120 | """for any valid pair (a, b), randint(a, b) should lay between [a, b] 121 | """ 122 | for i in range(1000): 123 | r = random.randint(-10000, 10000) 124 | if (-10000 <= r <= 10000): continue 125 | else: raise "error: random.randint()" 126 | 127 | def test_choice(): 128 | """random.choice() should be able to deal with string, list. 129 | """ 130 | S = "abcdefg123*@#$%)(" 131 | L = [1, 2, 3, -1, 0.2, -0.1, -10000, "cyc"] 132 | 133 | if random.choice(S) not in S: 134 | raise "error: random.choice(S)" 135 | 136 | if random.choice(L) not in L: 137 | raise "error: random.choice(L)" 138 | 139 | def test_shuffle(): 140 | """test random.shuffle() on list. since string is not writable in-place, 141 | random.shuffle() can not be applied on string. 142 | Note: to copy items from a list to a new list, must use syntax like: 143 | newList = oldList[:] 144 | if use syntax like: newList = oldList, newList is just an alias of oldList. 145 | """ 146 | oldL = [1, 2, 3, -1, 0.2, -0.1, -10000, "cyc"] 147 | newL = oldL[:] 148 | 149 | random.shuffle(newL) 150 | 151 | rep = 0 152 | for ind in range(len(oldL)): 153 | elem1 = oldL[ind] 154 | elem2 = newL[ind] 155 | if (elem1 == elem2): rep += 1 156 | if (rep > len(oldL) / 2): 157 | raise "oldL and newL shouldn't be the same" 158 | 159 | def test_53_bits_per_float(): 160 | pass 161 | 162 | def main(): 163 | test_seed_state() 164 | test_jumpahead() 165 | test_setstate() 166 | test_random() 167 | test_distribution() 168 | test_randrange() 169 | test_randint() 170 | test_choice() 171 | test_shuffle() 172 | test_53_bits_per_float() 173 | print("#OK") 174 | 175 | if __name__ == '__main__': 176 | main() 177 | -------------------------------------------------------------------------------- /tinypy/string.c: -------------------------------------------------------------------------------- 1 | /* File: String 2 | * String handling functions. 3 | */ 4 | 5 | #ifdef TP_NORMALMAKE 6 | #include "tp.h" 7 | #include "list_auto.h" 8 | #endif 9 | 10 | /* 11 | * Create a new empty string of a certain size. 12 | * Does not put it in for GC tracking, since contents should be 13 | * filled after returning. 14 | */ 15 | tp_obj tp_string_t(TP, int n) { 16 | tp_obj r = tp_string_n(0,n); 17 | r.string.info = (_tp_string*)tp_malloc(tp, sizeof(_tp_string)+n); 18 | r.string.info->len = n; 19 | r.string.val = r.string.info->s; 20 | return r; 21 | } 22 | 23 | /* 24 | * Create a new string which is a copy of some memory. 25 | * This is put into GC tracking for you. 26 | */ 27 | tp_obj tp_string_copy(TP, const char *s, int n) { 28 | tp_obj r = tp_string_t(tp,n); 29 | memcpy(r.string.info->s,s,n); 30 | return tp_track(tp,r); 31 | } 32 | 33 | /* 34 | * Create a new string which is a substring slice of another STRING. 35 | * Does not need to be put into GC tracking, as its parent is 36 | * already being tracked (supposedly). 37 | */ 38 | tp_obj tp_string_sub(TP, tp_obj s, int a, int b) { 39 | int l = s.string.len; 40 | a = _tp_max(0,(a<0?l+a:a)); b = _tp_min(l,(b<0?l+b:b)); 41 | tp_obj r = s; 42 | r.string.val += a; 43 | r.string.len = b-a; 44 | return r; 45 | } 46 | 47 | tp_obj tp_printf(TP, char const *fmt,...) { 48 | int l; 49 | tp_obj r; 50 | char *s; 51 | va_list arg; 52 | va_start(arg, fmt); 53 | l = vsnprintf(NULL, 0, fmt,arg); 54 | r = tp_string_t(tp,l); 55 | s = r.string.info->s; 56 | va_end(arg); 57 | va_start(arg, fmt); 58 | vsprintf(s,fmt,arg); 59 | va_end(arg); 60 | return tp_track(tp,r); 61 | } 62 | 63 | int _tp_str_index(tp_obj s, tp_obj k) { 64 | int i=0; 65 | while ((s.string.len - i) >= k.string.len) { 66 | if (memcmp(s.string.val+i,k.string.val,k.string.len) == 0) { 67 | return i; 68 | } 69 | i += 1; 70 | } 71 | return -1; 72 | } 73 | 74 | tp_obj tp_join(TP) { 75 | tp_obj delim = TP_OBJ(); 76 | tp_obj val = TP_OBJ(); 77 | int l=0,i; 78 | tp_obj r; 79 | char *s; 80 | for (i=0; ilen; i++) { 81 | if (i!=0) { l += delim.string.len; } 82 | l += tp_str(tp,val.list.val->items[i]).string.len; 83 | } 84 | r = tp_string_t(tp,l); 85 | s = r.string.info->s; 86 | l = 0; 87 | for (i=0; ilen; i++) { 88 | tp_obj e; 89 | if (i!=0) { 90 | memcpy(s+l,delim.string.val,delim.string.len); l += delim.string.len; 91 | } 92 | e = tp_str(tp,val.list.val->items[i]); 93 | memcpy(s+l,e.string.val,e.string.len); l += e.string.len; 94 | } 95 | return tp_track(tp,r); 96 | } 97 | 98 | tp_obj tp_split(TP) { 99 | tp_obj v = TP_OBJ(); 100 | tp_obj d = TP_OBJ(); 101 | tp_obj r = tp_list(tp); 102 | 103 | int i; 104 | while ((i=_tp_str_index(v,d))!=-1) { 105 | _tp_list_append(tp,r.list.val,tp_string_sub(tp,v,0,i)); 106 | v.string.val += i + d.string.len; v.string.len -= i + d.string.len; 107 | } 108 | _tp_list_append(tp,r.list.val,tp_string_sub(tp,v,0,v.string.len)); 109 | return r; 110 | } 111 | 112 | 113 | tp_obj tp_find(TP) { 114 | tp_obj s = TP_OBJ(); 115 | tp_obj v = TP_OBJ(); 116 | return tp_number(_tp_str_index(s,v)); 117 | } 118 | 119 | tp_obj tp_str_index(TP) { 120 | tp_obj s = TP_OBJ(); 121 | tp_obj v = TP_OBJ(); 122 | int n = _tp_str_index(s,v); 123 | if (n >= 0) { return tp_number(n); } 124 | tp_raise(tp_None,tp_string("(tp_str_index) ValueError: substring not found")); 125 | } 126 | 127 | tp_obj tp_str2(TP) { 128 | tp_obj v = TP_OBJ(); 129 | return tp_str(tp,v); 130 | } 131 | 132 | tp_obj tp_chr(TP) { 133 | int v = TP_NUM(); 134 | char tmp = (unsigned char)v; 135 | /*return tp_string_n(tp->chars[(unsigned char)v],1);*/ 136 | return tp_string_copy(tp, &tmp, 1); 137 | } 138 | tp_obj tp_ord(TP) { 139 | tp_obj s = TP_STR(); 140 | if (s.string.len != 1) { 141 | tp_raise(tp_None,tp_string("(tp_ord) TypeError: ord() expected a character")); 142 | } 143 | return tp_number((unsigned char)s.string.val[0]); 144 | } 145 | 146 | tp_obj tp_strip(TP) { 147 | tp_obj o = TP_TYPE(TP_STRING); 148 | char const *v = o.string.val; int l = o.string.len; 149 | int i; int a = l, b = 0; 150 | tp_obj r; 151 | char *s; 152 | for (i=0; is; 160 | memcpy(s,v+a,b-a); 161 | return tp_track(tp,r); 162 | } 163 | 164 | tp_obj tp_replace(TP) { 165 | tp_obj s = TP_OBJ(); 166 | tp_obj k = TP_OBJ(); 167 | tp_obj v = TP_OBJ(); 168 | tp_obj p = s; 169 | int i,n = 0; 170 | int c; 171 | int l; 172 | tp_obj rr; 173 | char *r; 174 | char *d; 175 | tp_obj z; 176 | while ((i = _tp_str_index(p,k)) != -1) { 177 | n += 1; 178 | p.string.val += i + k.string.len; p.string.len -= i + k.string.len; 179 | } 180 | /* fprintf(stderr,"ns: %d\n",n); */ 181 | l = s.string.len + n * (v.string.len-k.string.len); 182 | rr = tp_string_t(tp,l); 183 | r = rr.string.info->s; 184 | d = r; 185 | z = p = s; 186 | while ((i = _tp_str_index(p,k)) != -1) { 187 | p.string.val += i; p.string.len -= i; 188 | memcpy(d,z.string.val,c=(p.string.val-z.string.val)); d += c; 189 | p.string.val += k.string.len; p.string.len -= k.string.len; 190 | memcpy(d,v.string.val,v.string.len); d += v.string.len; 191 | z = p; 192 | } 193 | memcpy(d,z.string.val,(s.string.val + s.string.len) - z.string.val); 194 | 195 | return tp_track(tp,rr); 196 | } 197 | 198 | -------------------------------------------------------------------------------- /cpython/cpython.c: -------------------------------------------------------------------------------- 1 | #include "../build/tinypy.c" 2 | #include 3 | #include "structmember.h" 4 | 5 | typedef struct { 6 | PyObject_HEAD 7 | tp_vm *vm; 8 | } TinypyObject; 9 | 10 | static PyObject * 11 | Tinypy_ConvertObj(tp_obj obj) 12 | { 13 | PyObject *TinypyError, *TinypyModule; 14 | 15 | if(!(TinypyModule = PyImport_ImportModule("tinypy"))) { 16 | return NULL; 17 | } 18 | if(!(TinypyError = PyObject_GetAttrString(TinypyModule, "error"))) { 19 | return NULL; 20 | } 21 | if(obj.type == TP_NUMBER) { 22 | tp_num v = obj.number.val; 23 | if ((fabs(v)-fabs((long)v)) < 0.000001) { 24 | return Py_BuildValue("i", (int) v); 25 | } 26 | else { 27 | return Py_BuildValue("d", v); 28 | } 29 | } 30 | else if(obj.type == TP_STRING) { 31 | return Py_BuildValue("s#", obj.string.val, obj.string.len); 32 | } 33 | else if(obj.type == TP_NONE) { 34 | Py_INCREF(Py_None); 35 | return Py_None; 36 | } 37 | else { 38 | PyErr_SetString(TinypyError, "can only return strings, numbers and None"); 39 | return NULL; 40 | } 41 | } 42 | 43 | static int 44 | Tinypy_init(TinypyObject *self, PyObject *args, PyObject *kwds) 45 | { 46 | self->vm = tp_init(0, NULL); 47 | double time = 5*1000; /* 5 seconds default */ 48 | unsigned long mem = 16*1024*1024; /* 16 megabytes default */ 49 | static char *kwlist[] = { "time", "mem", 0 }; 50 | 51 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|dk", 52 | kwlist, &time, &mem)) { 53 | return -1; 54 | } 55 | tp_sandbox(self->vm, time, mem); 56 | 57 | return 0; 58 | } 59 | 60 | static void 61 | Tinypy_destruct(PyObject *self) 62 | { 63 | tp_deinit(((TinypyObject *) self)->vm); 64 | self->ob_type->tp_free(self); 65 | } 66 | 67 | static PyObject * 68 | Tinypy_exec(TinypyObject *self, PyObject *args, PyObject *kwds) 69 | { 70 | tp_obj obj; 71 | tp_vm *tp = self->vm; 72 | PyObject *ret, *TinypyError, *TinypyModule; 73 | static char *kwlist[] = { "code", "time", 0 }; 74 | const char *code; 75 | 76 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|d", 77 | kwlist, &code, &tp->time_limit)) { 78 | return NULL; 79 | } 80 | 81 | tp->time_elapsed = 0; 82 | tp->mem_exceeded = 0; 83 | if(!(TinypyModule = PyImport_ImportModule("tinypy"))) { 84 | return NULL; 85 | } 86 | if(!(TinypyError = PyObject_GetAttrString(TinypyModule, "error"))) { 87 | return NULL; 88 | } 89 | if(setjmp(tp->nextexpr)) { 90 | --(tp->cur); 91 | PyErr_SetObject(TinypyError, Tinypy_ConvertObj(tp->ex)); 92 | return NULL; 93 | } 94 | tp->clocks = clock(); 95 | obj = tp_eval(tp, code, tp->builtins); 96 | ret = Tinypy_ConvertObj(obj); 97 | return ret; 98 | } 99 | 100 | static PyMethodDef Tinypy_methods[] = { 101 | {"execute", (PyCFunction)Tinypy_exec, METH_VARARGS | METH_KEYWORDS, 102 | "Execute code supplied as the argument on the tinypy interpreter" 103 | }, 104 | {NULL} /* Sentinel */ 105 | }; 106 | 107 | static PyMethodDef tinypy_methods[] = { 108 | {NULL} /* Sentinel */ 109 | }; 110 | 111 | static PyTypeObject TinypyType = { 112 | PyObject_HEAD_INIT(NULL) 113 | 0, /*ob_size*/ 114 | "tinypy.Tinypy", /*tp_name*/ 115 | sizeof(TinypyObject), /*tp_basicsize*/ 116 | 0, /*tp_itemsize*/ 117 | Tinypy_destruct, /*tp_dealloc*/ 118 | 0, /*tp_print*/ 119 | 0, /*tp_getattr*/ 120 | 0, /*tp_setattr*/ 121 | 0, /*tp_compare*/ 122 | 0, /*tp_repr*/ 123 | 0, /*tp_as_number*/ 124 | 0, /*tp_as_sequence*/ 125 | 0, /*tp_as_mapping*/ 126 | 0, /*tp_hash */ 127 | 0, /*tp_call*/ 128 | 0, /*tp_str*/ 129 | 0, /*tp_getattro*/ 130 | 0, /*tp_setattro*/ 131 | 0, /*tp_as_buffer*/ 132 | Py_TPFLAGS_DEFAULT, /*tp_flags*/ 133 | "Tinypy VM instance", /* tp_doc */ 134 | 0, /* tp_traverse */ 135 | 0, /* tp_clear */ 136 | 0, /* tp_richcompare */ 137 | 0, /* tp_weaklistoffset */ 138 | 0, /* tp_iter */ 139 | 0, /* tp_iternext */ 140 | Tinypy_methods, /* tp_methods */ 141 | 0, /* tp_members */ 142 | 0, /* tp_getset */ 143 | 0, /* tp_base */ 144 | 0, /* tp_dict */ 145 | 0, /* tp_descr_get */ 146 | 0, /* tp_descr_set */ 147 | 0, /* tp_dictoffset */ 148 | (initproc)Tinypy_init, /* tp_init */ 149 | }; 150 | 151 | PyMODINIT_FUNC 152 | inittinypy(void) 153 | { 154 | PyObject *m; 155 | PyObject *TinypyError; 156 | 157 | TinypyType.tp_new = PyType_GenericNew; 158 | if (PyType_Ready(&TinypyType) < 0) { 159 | return; 160 | } 161 | 162 | m = Py_InitModule3("tinypy", tinypy_methods, 163 | "tinypy - a small Python subset interpreter"); 164 | if (m == NULL) { 165 | return; 166 | } 167 | 168 | Py_INCREF(&TinypyType); 169 | if(PyModule_AddObject(m, "Tinypy", (PyObject *)&TinypyType) < 0) { 170 | return; 171 | } 172 | TinypyError = PyErr_NewException("tinypy.error", NULL, NULL); 173 | Py_INCREF(TinypyError); 174 | if(PyModule_AddObject(m, "error", TinypyError) < 0) { 175 | return; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /modules/math/tests.py: -------------------------------------------------------------------------------- 1 | ### This file is grabbed from Python's Lib/test/test_math.py 2 | ###--------------------------------------------------------- 3 | # Python test set -- math module 4 | # XXXX Should not do tests around zero only 5 | 6 | eps = 0.00001 7 | #print('math module, testing with eps ', eps) 8 | import math 9 | 10 | def testit(name, value, expected): 11 | if abs(value-expected) > eps: 12 | msg = name + " returned " + str(value) + " expected " + str(expected) 13 | raise msg 14 | 15 | #print 'constants' 16 | testit('pi', math.pi, 3.1415926) 17 | testit('e', math.e, 2.7182818) 18 | 19 | #print 'acos' 20 | testit('acos(-1)', math.acos(-1), math.pi) 21 | testit('acos(0)', math.acos(0), math.pi/2) 22 | testit('acos(1)', math.acos(1), 0) 23 | 24 | #print 'asin' 25 | testit('asin(-1)', math.asin(-1), -math.pi/2) 26 | testit('asin(0)', math.asin(0), 0) 27 | testit('asin(1)', math.asin(1), math.pi/2) 28 | 29 | #print 'atan' 30 | testit('atan(-1)', math.atan(-1), -math.pi/4) 31 | testit('atan(0)', math.atan(0), 0) 32 | testit('atan(1)', math.atan(1), math.pi/4) 33 | 34 | #print 'atan2' 35 | testit('atan2(-1, 0)', math.atan2(-1, 0), -math.pi/2) 36 | testit('atan2(-1, 1)', math.atan2(-1, 1), -math.pi/4) 37 | testit('atan2(0, 1)', math.atan2(0, 1), 0) 38 | testit('atan2(1, 1)', math.atan2(1, 1), math.pi/4) 39 | testit('atan2(1, 0)', math.atan2(1, 0), math.pi/2) 40 | 41 | #print 'ceil' 42 | testit('ceil(0.5)', math.ceil(0.5), 1) 43 | testit('ceil(1.0)', math.ceil(1.0), 1) 44 | testit('ceil(1.5)', math.ceil(1.5), 2) 45 | testit('ceil(-0.5)', math.ceil(-0.5), 0) 46 | testit('ceil(-1.0)', math.ceil(-1.0), -1) 47 | testit('ceil(-1.5)', math.ceil(-1.5), -1) 48 | 49 | #print 'cos' 50 | testit('cos(-pi/2)', math.cos(-math.pi/2), 0) 51 | testit('cos(0)', math.cos(0), 1) 52 | testit('cos(pi/2)', math.cos(math.pi/2), 0) 53 | testit('cos(pi)', math.cos(math.pi), -1) 54 | 55 | #print 'cosh' 56 | testit('cosh(0)', math.cosh(0), 1) 57 | testit('cosh(2)-2*(cosh(1)**2)', math.cosh(2)-2*(math.cosh(1)**2), -1) # Thanks to Lambert 58 | 59 | #print 'degrees' 60 | testit('degrees(pi)', math.degrees(math.pi), 180.0) 61 | testit('degrees(pi/2)', math.degrees(math.pi/2), 90.0) 62 | testit('degrees(-pi/4)', math.degrees(-math.pi/4), -45.0) 63 | 64 | #print 'exp' 65 | testit('exp(-1)', math.exp(-1), 1/math.e) 66 | testit('exp(0)', math.exp(0), 1) 67 | testit('exp(1)', math.exp(1), math.e) 68 | 69 | #print 'fabs' 70 | testit('fabs(-1)', math.fabs(-1), 1) 71 | testit('fabs(0)', math.fabs(0), 0) 72 | testit('fabs(1)', math.fabs(1), 1) 73 | 74 | #print 'floor' 75 | testit('floor(0.5)', math.floor(0.5), 0) 76 | testit('floor(1.0)', math.floor(1.0), 1) 77 | testit('floor(1.5)', math.floor(1.5), 1) 78 | testit('floor(-0.5)', math.floor(-0.5), -1) 79 | testit('floor(-1.0)', math.floor(-1.0), -1) 80 | testit('floor(-1.5)', math.floor(-1.5), -2) 81 | 82 | #print 'fmod' 83 | testit('fmod(10,1)', math.fmod(10,1), 0) 84 | testit('fmod(10,0.5)', math.fmod(10,0.5), 0) 85 | testit('fmod(10,1.5)', math.fmod(10,1.5), 1) 86 | testit('fmod(-10,1)', math.fmod(-10,1), 0) 87 | testit('fmod(-10,0.5)', math.fmod(-10,0.5), 0) 88 | testit('fmod(-10,1.5)', math.fmod(-10,1.5), -1) 89 | 90 | #print 'frexp' 91 | def testfrexp(name, value, expected): 92 | mant = value[0] 93 | exp = value[1] 94 | emant = expected[0] 95 | eexp = expected[1] 96 | if abs(mant-emant) > eps or exp != eexp: 97 | raise '%s returned (%f, %f), expected (%f, %f)'%\ 98 | (name, mant, exp, emant,eexp) 99 | 100 | testfrexp('frexp(-1)', math.frexp(-1), (-0.5, 1)) 101 | testfrexp('frexp(0)', math.frexp(0), (0, 0)) 102 | testfrexp('frexp(1)', math.frexp(1), (0.5, 1)) 103 | testfrexp('frexp(2)', math.frexp(2), (0.5, 2)) 104 | 105 | #print 'hypot' 106 | testit('hypot(0,0)', math.hypot(0,0), 0) 107 | testit('hypot(3,4)', math.hypot(3,4), 5) 108 | 109 | #print 'ldexp' 110 | testit('ldexp(0,1)', math.ldexp(0,1), 0) 111 | testit('ldexp(1,1)', math.ldexp(1,1), 2) 112 | testit('ldexp(1,-1)', math.ldexp(1,-1), 0.5) 113 | testit('ldexp(-1,1)', math.ldexp(-1,1), -2) 114 | 115 | #print 'log' 116 | testit('log(1/e)', math.log(1/math.e), -1) 117 | testit('log(1)', math.log(1), 0) 118 | testit('log(e)', math.log(math.e), 1) 119 | testit('log(32,2)', math.log(32,2), 5) 120 | testit('log(10**40, 10)', math.log(10**40, 10), 40) 121 | testit('log(10**40, 10**20)', math.log(10**40, 10**20), 2) 122 | 123 | #print 'log10' 124 | testit('log10(0.1)', math.log10(0.1), -1) 125 | testit('log10(1)', math.log10(1), 0) 126 | testit('log10(10)', math.log10(10), 1) 127 | 128 | #print 'modf' 129 | def testmodf(name, value, expected): 130 | v1 = value[0] 131 | v2 = value[1] 132 | e1 = expected[0] 133 | e2 = expected[1] 134 | if abs(v1-e1) > eps or abs(v2-e2): 135 | raise '%s returned (%f, %f), expected (%f, %f)'%\ 136 | (name, v1,v2, e1,e2) 137 | 138 | testmodf('modf(1.5)', math.modf(1.5), (0.5, 1.0)) 139 | testmodf('modf(-1.5)', math.modf(-1.5), (-0.5, -1.0)) 140 | 141 | #print 'pow' 142 | testit('pow(0,1)', math.pow(0,1), 0) 143 | testit('pow(1,0)', math.pow(1,0), 1) 144 | testit('pow(2,1)', math.pow(2,1), 2) 145 | testit('pow(2,-1)', math.pow(2,-1), 0.5) 146 | 147 | #print 'radians' 148 | testit('radians(180)', math.radians(180), math.pi) 149 | testit('radians(90)', math.radians(90), math.pi/2) 150 | testit('radians(-45)', math.radians(-45), -math.pi/4) 151 | 152 | #print 'sin' 153 | testit('sin(0)', math.sin(0), 0) 154 | testit('sin(pi/2)', math.sin(math.pi/2), 1) 155 | testit('sin(-pi/2)', math.sin(-math.pi/2), -1) 156 | 157 | #print 'sinh' 158 | testit('sinh(0)', math.sinh(0), 0) 159 | testit('sinh(1)**2-cosh(1)**2', math.sinh(1)**2-math.cosh(1)**2, -1) 160 | testit('sinh(1)+sinh(-1)', math.sinh(1)+math.sinh(-1), 0) 161 | 162 | #print 'sqrt' 163 | testit('sqrt(0)', math.sqrt(0), 0) 164 | testit('sqrt(1)', math.sqrt(1), 1) 165 | testit('sqrt(4)', math.sqrt(4), 2) 166 | 167 | #print 'tan' 168 | testit('tan(0)', math.tan(0), 0) 169 | testit('tan(pi/4)', math.tan(math.pi/4), 1) 170 | testit('tan(-pi/4)', math.tan(-math.pi/4), -1) 171 | 172 | #print 'tanh' 173 | testit('tanh(0)', math.tanh(0), 0) 174 | testit('tanh(1)+tanh(-1)', math.tanh(1)+math.tanh(-1), 0) 175 | 176 | #print("OK: math module test pass") 177 | -------------------------------------------------------------------------------- /modules/pygame/init.c: -------------------------------------------------------------------------------- 1 | #include "SDL.h" 2 | 3 | /* utility functions */ 4 | Uint32 pygame_list_to_color(TP,tp_obj clr,SDL_Surface *s) { 5 | int r,g,b; 6 | r = tp_get(tp,clr,tp_number(0)).number.val; 7 | g = tp_get(tp,clr,tp_number(1)).number.val; 8 | b = tp_get(tp,clr,tp_number(2)).number.val; 9 | return SDL_MapRGB(s->format,r,g,b); 10 | } 11 | 12 | /* surface */ 13 | 14 | #define PYGAME_TYPE_SURF 0x1001 15 | 16 | void pygame_surf_free(TP,tp_obj d) { 17 | if (d.data.magic != PYGAME_TYPE_SURF) { tp_raise(,tp_printf(tp, "%s","not a surface")); } 18 | SDL_FreeSurface((SDL_Surface*)d.data.val); 19 | } 20 | 21 | SDL_Surface *pygame_obj_to_surf(TP,tp_obj self) { 22 | tp_obj d = tp_get(tp,self,tp_string("__surf")); 23 | if (d.data.magic != PYGAME_TYPE_SURF) { tp_raise(0,tp_printf(tp, "%s","not a surface")); } 24 | return (SDL_Surface*)d.data.val; 25 | } 26 | 27 | 28 | tp_obj pygame_surface_set_at(TP) { 29 | tp_obj self = TP_OBJ(); 30 | tp_obj pos = TP_TYPE(TP_LIST); 31 | tp_obj clr = TP_TYPE(TP_LIST); 32 | SDL_Rect r; 33 | r.x = tp_get(tp,pos,tp_number(0)).number.val; 34 | r.y = tp_get(tp,pos,tp_number(1)).number.val; 35 | r.w = 1; r.h = 1; 36 | SDL_Surface *s =pygame_obj_to_surf(tp,self); 37 | Uint32 c = pygame_list_to_color(tp,clr,s); 38 | SDL_FillRect(s, &r, c); 39 | return tp_None; 40 | } 41 | 42 | 43 | tp_obj pygame_surf_to_obj(TP,SDL_Surface *s) { 44 | tp_obj self = tp_dict(tp); 45 | 46 | tp_obj d = tp_data(tp,PYGAME_TYPE_SURF,s); 47 | d.data.info->free = pygame_surf_free; 48 | 49 | tp_set(tp,self,tp_string("__surf"),d); 50 | tp_set(tp,self,tp_string("set_at"),tp_method(tp,self,pygame_surface_set_at)); 51 | return self; 52 | } 53 | 54 | 55 | 56 | 57 | /* display module */ 58 | 59 | tp_obj pygame_display_set_mode(TP) { 60 | tp_obj sz = TP_TYPE(TP_LIST); 61 | int w = tp_get(tp,sz,tp_number(0)).number.val; 62 | int h = tp_get(tp,sz,tp_number(1)).number.val; 63 | SDL_Surface *s = SDL_SetVideoMode(w, h, 0, 0); 64 | return pygame_surf_to_obj(tp,s); 65 | } 66 | 67 | tp_obj pygame_display_flip(TP) { 68 | SDL_Flip(SDL_GetVideoSurface()); 69 | return tp_None; 70 | } 71 | 72 | SDL_Rect pygame_list_to_rect(TP,tp_obj o) { 73 | SDL_Rect r; 74 | r.x = tp_get(tp,o,tp_number(0)).number.val; 75 | r.y = tp_get(tp,o,tp_number(1)).number.val; 76 | r.w = tp_get(tp,o,tp_number(2)).number.val; 77 | r.h = tp_get(tp,o,tp_number(3)).number.val; 78 | return r; 79 | } 80 | 81 | tp_obj pygame_display_update(TP) { 82 | SDL_Rect r = pygame_list_to_rect(tp,TP_TYPE(TP_LIST)); 83 | SDL_UpdateRects(SDL_GetVideoSurface(), 1, &r); 84 | return tp_None; 85 | } 86 | 87 | /* event module */ 88 | tp_obj pygame_event_get(TP) { 89 | SDL_Event e; 90 | tp_obj r = tp_list(tp); 91 | while (SDL_PollEvent(&e)) { 92 | tp_obj d = tp_dict(tp); 93 | tp_set(tp,d,tp_string("type"),tp_number(e.type)); 94 | switch (e.type) { 95 | case SDL_KEYDOWN: 96 | case SDL_KEYUP: 97 | tp_set(tp,d,tp_string("key"),tp_number(e.key.keysym.sym)); 98 | tp_set(tp,d,tp_string("mod"),tp_number(e.key.keysym.mod)); 99 | break; 100 | case SDL_MOUSEMOTION: 101 | tp_set(tp,d,tp_string("pos"),tp_list_n(tp,2,(tp_obj[]){tp_number(e.motion.x),tp_number(e.motion.y)})); 102 | tp_set(tp,d,tp_string("rel"),tp_list_n(tp,2,(tp_obj[]){tp_number(e.motion.xrel),tp_number(e.motion.yrel)})); 103 | tp_set(tp,d,tp_string("state"),tp_number(e.motion.state)); 104 | break; 105 | case SDL_MOUSEBUTTONDOWN: 106 | case SDL_MOUSEBUTTONUP: 107 | tp_set(tp,d,tp_string("pos"),tp_list_n(tp,2,(tp_obj[]){tp_number(e.button.x),tp_number(e.button.y)})); 108 | tp_set(tp,d,tp_string("button"),tp_number(e.button.button)); 109 | break; 110 | } 111 | tp_set(tp,r,tp_None,d); 112 | } 113 | return r; 114 | } 115 | 116 | /* mouse */ 117 | tp_obj pygame_mouse_get_pos(TP) { 118 | int x,y; 119 | SDL_GetMouseState(&x,&y); 120 | tp_obj r = tp_list_n(tp,2,(tp_obj[]){tp_number(x),tp_number(y)}); 121 | return r; 122 | } 123 | 124 | /* time */ 125 | tp_obj pygame_time_get_ticks(TP) { 126 | return tp_number(SDL_GetTicks()); 127 | } 128 | 129 | 130 | /* pygame */ 131 | #define PYGAME_LOCALS(a,b) tp_set(tp,m,tp_string(a),tp_number(b)); 132 | 133 | tp_obj _pygame_init(TP) { 134 | SDL_Init(SDL_INIT_VIDEO); 135 | return tp_None; 136 | } 137 | 138 | 139 | void pygame_init(TP) { 140 | tp_obj g,m; 141 | g = tp_dict(tp); 142 | tp_set(tp,tp->modules,tp_string("pygame"),g); 143 | tp_set(tp,g,tp_string("init"),tp_fnc(tp,_pygame_init)); 144 | 145 | /* display */ 146 | m = tp_dict(tp); tp_set(tp,g,tp_string("display"),m); 147 | tp_set(tp,m,tp_string("set_mode"),tp_fnc(tp,pygame_display_set_mode)); 148 | tp_set(tp,m,tp_string("flip"),tp_fnc(tp,pygame_display_flip)); 149 | tp_set(tp,m,tp_string("update"),tp_fnc(tp,pygame_display_update)); 150 | 151 | /* event */ 152 | m = tp_dict(tp); tp_set(tp,g,tp_string("event"),m); 153 | tp_set(tp,m,tp_string("get"),tp_fnc(tp,pygame_event_get)); 154 | 155 | /* locals */ 156 | m = tp_dict(tp); tp_set(tp,g,tp_string("locals"),m); 157 | PYGAME_LOCALS("QUIT",SDL_QUIT); 158 | PYGAME_LOCALS("KEYDOWN",SDL_KEYDOWN); 159 | PYGAME_LOCALS("KEYUP",SDL_KEYUP); 160 | PYGAME_LOCALS("MOUSEBUTTONDOWN",SDL_MOUSEBUTTONDOWN); 161 | PYGAME_LOCALS("MOUSEBUTTONUP",SDL_MOUSEBUTTONUP); 162 | PYGAME_LOCALS("MOUSEMOTION",SDL_MOUSEMOTION); 163 | PYGAME_LOCALS("K_UP",SDLK_UP); 164 | PYGAME_LOCALS("K_DOWN",SDLK_DOWN); 165 | PYGAME_LOCALS("K_LEFT",SDLK_LEFT); 166 | PYGAME_LOCALS("K_RIGHT",SDLK_RIGHT); 167 | PYGAME_LOCALS("K_ESCAPE",SDLK_ESCAPE); 168 | PYGAME_LOCALS("K_SPACE",SDLK_SPACE); 169 | PYGAME_LOCALS("K_RETURN",SDLK_RETURN); 170 | 171 | /* mouse */ 172 | m = tp_dict(tp); tp_set(tp,g,tp_string("mouse"),m); 173 | tp_set(tp,m,tp_string("get_pos"),tp_fnc(tp,pygame_mouse_get_pos)); 174 | 175 | /* time */ 176 | m = tp_dict(tp); tp_set(tp,g,tp_string("time"),m); 177 | tp_set(tp,m,tp_string("get_ticks"),tp_fnc(tp,pygame_time_get_ticks)); 178 | 179 | 180 | } 181 | 182 | /**/ 183 | -------------------------------------------------------------------------------- /examples/vines.py: -------------------------------------------------------------------------------- 1 | #!/bin/env python 2 | # 3 | # vines borrowed from xscreensaver 4 | # 5 | """ 6 | /*- 7 | * Copyright (c) 1997 by Tracy Camp campt@hurrah.com 8 | * 9 | * Permission to use, copy, modify, and distribute this software and its 10 | * documentation for any purpose and without fee is hereby granted, 11 | * provided that the above copyright notice appear in all copies and that 12 | * both that copyright notice and this permission notice appear in 13 | * supporting documentation. 14 | * 15 | * This file is provided AS IS with no warranties of any kind. The author 16 | * shall have no liability with respect to the infringement of copyrights, 17 | * trade secrets or any patents by this file or any part thereof. In no 18 | * event will the author be liable for any lost revenue or profits or 19 | * other special, indirect and consequential damages. 20 | * 21 | * If you make a modification I would of course appreciate a copy. 22 | * 23 | * Revision History: 24 | * 01-Nov-2000: Allocation checks 25 | * 11-Jul-1997: David Hansen 26 | * Changed names to vines and modified draw loop 27 | * to honor batchcount so vines can be grown or plotted. 28 | * 10-May-1997: Compatible with xscreensaver 29 | * 21-Mar-1997: David Hansen 30 | * Updated mode to draw complete patterns on every 31 | * iteration instead of growing the vine. Also made 32 | * adjustments to randomization and changed variable 33 | * names to make logic easier to follow. 34 | */ 35 | 36 | /*- 37 | * This was modifed from a 'screen saver' that a friend and I 38 | * wrote on our TI-8x calculators in high school physics one day 39 | * Basically another geometric pattern generator, this ones claim 40 | * to fame is a pseudo-fractal looking vine like pattern that creates 41 | * nifty whorls and loops. 42 | */ 43 | """ 44 | 45 | import sys 46 | import math 47 | import random 48 | import pygame 49 | if "tinypy" not in sys.version: # not tinypy 50 | import pygame.locals 51 | 52 | SCR_WIDTH = 800 53 | SCR_HEIGHT = 600 54 | 55 | class VineStruct(object): 56 | a = 0 57 | x1 = 0 58 | y1 = 0 59 | x2 = 0 60 | y2 = 0 61 | i = 0 62 | length = 0 63 | iterations = 0 64 | constant = 0 65 | ang = 0 66 | centerx = 0 67 | centery = 0 68 | 69 | class Vines(object): 70 | def __init__(self): 71 | self.fp = VineStruct() 72 | self.fp.i = 0 73 | self.fp.length = 0 74 | self.fp.iterations = 30 + random.randint(0, 100) 75 | 76 | pygame.init() 77 | self.screen = pygame.display.set_mode((SCR_WIDTH, SCR_HEIGHT)) 78 | 79 | def __drawLine__(self, x1, y1, x2, y2, color): 80 | 81 | # validate the bounds 82 | if x1 < 0: x1 = 0 83 | if x1 > SCR_WIDTH: x1 = SCR_WIDTH 84 | if x2 < 0: x2 = 0 85 | if x2 > SCR_WIDTH: x2 = SCR_WIDTH 86 | if y1 < 0: y1 = 0 87 | if y1 > SCR_HEIGHT: y1 = SCR_HEIGHT 88 | if y2 < 0: y2 = 0 89 | if y2 > SCR_HEIGHT: y2 = SCR_HEIGHT 90 | 91 | if x1 <= x2: 92 | sx, sy = x1, y1 93 | dx, dy = x2, y2 94 | else: 95 | sx, sy = x2, y2 96 | dx, dy = x1, y1 97 | 98 | if (abs(x1 - x2) < 1e-4): 99 | x = sx 100 | if sy > dy: 101 | sy, dy = dy, sy 102 | y = sy 103 | while (y < dy): 104 | self.screen.set_at((x, y), color) 105 | y += 1 106 | else: 107 | k = (dy - sy) / (dx - sx) 108 | x = sx 109 | while (x < dx): 110 | y = sy + k * (x - sx) 111 | self.screen.set_at((x, y), color) 112 | x += 1 113 | 114 | pygame.display.flip() 115 | 116 | def draw(self): 117 | red = random.randint(0, 255) 118 | green = random.randint(0, 255) 119 | blue = random.randint(0, 255) 120 | if (self.fp.i >= self.fp.length): 121 | self.fp.iterations -= 1 122 | if (self.fp.iterations == 0): 123 | self.__init__(self) 124 | self.fp.centerx = random.randint(0, SCR_WIDTH); 125 | self.fp.centery = random.randint(0, SCR_HEIGHT); 126 | 127 | self.fp.ang = 60 + random.randint(0, 720); 128 | self.fp.length = 100 + random.randint(0, 3000); 129 | self.fp.constant= self.fp.length * (10 + random.randint(0, 10)) 130 | 131 | self.fp.i = 0; 132 | self.fp.a = 0; 133 | self.fp.x1 = 0; 134 | self.fp.y1 = 0; 135 | self.fp.x2 = 1; 136 | self.fp.y2 = 0; 137 | 138 | count = self.fp.i + random.randint(10, 100) 139 | if (count > self.fp.length): 140 | count = self.fp.length 141 | 142 | while (self.fp.i < count): 143 | x1 = self.fp.centerx + (self.fp.x1 / self.fp.constant) 144 | y1 = self.fp.centery - (self.fp.y1 / self.fp.constant) 145 | x2 = self.fp.centerx + (self.fp.x2 / self.fp.constant) 146 | y2 = self.fp.centery - (self.fp.y2 / self.fp.constant) 147 | 148 | color = (red, green, blue) 149 | self.__drawLine__(x1, y1, x2, y2, color) 150 | 151 | self.fp.a += (self.fp.ang * self.fp.i) 152 | self.fp.x1 = self.fp.x2 153 | self.fp.y1 = self.fp.y2 154 | 155 | self.fp.x2 += int((self.fp.i * (math.cos(self.fp.a) * 360.0)) / (2.0 * math.pi)) 156 | self.fp.y2 += int((self.fp.i * (math.sin(self.fp.a) * 360.0)) / (2.0 * math.pi)) 157 | self.fp.i += 1 158 | 159 | def main(): 160 | myVine = Vines() 161 | _quit = False 162 | while not _quit: 163 | for e in pygame.event.get(): 164 | if e.type in (pygame.locals.QUIT,pygame.locals.KEYDOWN): 165 | _quit = True 166 | myVine.draw() 167 | 168 | if __name__ == '__main__': 169 | main() 170 | print("#OK") -------------------------------------------------------------------------------- /tinypy/dict.c: -------------------------------------------------------------------------------- 1 | /* File: Dict 2 | * Functions for dealing with dictionaries. 3 | */ 4 | 5 | #ifdef TP_NORMALMAKE 6 | #include "tp.h" 7 | #include "dict_auto.h" 8 | #endif 9 | 10 | int tp_lua_hash(void const *v,int l) { 11 | int i,step = (l>>5)+1; 12 | int h = l + (l >= 4?*(int*)v:0); 13 | for (i=l; i>=step; i-=step) { 14 | h = h^((h<<5)+(h>>2)+((unsigned char *)v)[i-1]); 15 | } 16 | return h; 17 | } 18 | void _tp_dict_free(TP, _tp_dict *self) { 19 | tp_free(tp, self->items); 20 | tp_free(tp, self); 21 | } 22 | 23 | /* void _tp_dict_reset(_tp_dict *self) { 24 | memset(self->items,0,self->alloc*sizeof(tp_item)); 25 | self->len = 0; 26 | self->used = 0; 27 | self->cur = 0; 28 | }*/ 29 | 30 | int tp_hash(TP,tp_obj v) { 31 | switch (v.type) { 32 | case TP_NONE: return 0; 33 | case TP_NUMBER: return tp_lua_hash(&v.number.val,sizeof(tp_num)); 34 | case TP_STRING: return tp_lua_hash(v.string.val,v.string.len); 35 | case TP_DICT: return tp_lua_hash(&v.dict.val,sizeof(void*)); 36 | case TP_LIST: { 37 | int r = v.list.val->len; int n; for(n=0; nlen; n++) { 38 | tp_obj vv = v.list.val->items[n]; r += vv.type != TP_LIST?tp_hash(tp,v.list.val->items[n]):tp_lua_hash(&vv.list.val,sizeof(void*)); } return r; 39 | } 40 | case TP_FNC: return tp_lua_hash(&v.fnc.info,sizeof(void*)); 41 | case TP_DATA: return tp_lua_hash(&v.data.val,sizeof(void*)); 42 | } 43 | tp_raise(0,tp_string("(tp_hash) TypeError: value unhashable")); 44 | } 45 | 46 | void _tp_dict_hash_set(TP,_tp_dict *self, int hash, tp_obj k, tp_obj v) { 47 | tp_item item; 48 | int i,idx = hash&self->mask; 49 | for (i=idx; ialloc; i++) { 50 | int n = i&self->mask; 51 | if (self->items[n].used > 0) { continue; } 52 | if (self->items[n].used == 0) { self->used += 1; } 53 | item.used = 1; 54 | item.hash = hash; 55 | item.key = k; 56 | item.val = v; 57 | self->items[n] = item; 58 | self->len += 1; 59 | return; 60 | } 61 | tp_raise(,tp_string("(_tp_dict_hash_set) RuntimeError: ?")); 62 | } 63 | 64 | void _tp_dict_tp_realloc(TP,_tp_dict *self,int len) { 65 | tp_item *items = self->items; 66 | int i,alloc = self->alloc; 67 | len = _tp_max(8,len); 68 | 69 | self->items = (tp_item*)tp_malloc(tp, len*sizeof(tp_item)); 70 | self->alloc = len; self->mask = len-1; 71 | self->len = 0; self->used = 0; 72 | 73 | for (i=0; imask; 82 | for (i=idx; ialloc; i++) { 83 | int n = i&self->mask; 84 | if (self->items[n].used == 0) { break; } 85 | if (self->items[n].used < 0) { continue; } 86 | if (self->items[n].hash != hash) { continue; } 87 | if (tp_cmp(tp,self->items[n].key,k) != 0) { continue; } 88 | return n; 89 | } 90 | return -1; 91 | } 92 | int _tp_dict_find(TP,_tp_dict *self,tp_obj k) { 93 | return _tp_dict_hash_find(tp,self,tp_hash(tp,k),k); 94 | } 95 | 96 | void _tp_dict_setx(TP,_tp_dict *self,tp_obj k, tp_obj v) { 97 | int hash = tp_hash(tp,k); int n = _tp_dict_hash_find(tp,self,hash,k); 98 | if (n == -1) { 99 | if (self->len >= (self->alloc/2)) { 100 | _tp_dict_tp_realloc(tp,self,self->alloc*2); 101 | } else if (self->used >= (self->alloc*3/4)) { 102 | _tp_dict_tp_realloc(tp,self,self->alloc); 103 | } 104 | _tp_dict_hash_set(tp,self,hash,k,v); 105 | } else { 106 | self->items[n].val = v; 107 | } 108 | } 109 | 110 | void _tp_dict_set(TP,_tp_dict *self,tp_obj k, tp_obj v) { 111 | _tp_dict_setx(tp,self,k,v); 112 | tp_grey(tp,k); tp_grey(tp,v); 113 | } 114 | 115 | tp_obj _tp_dict_get(TP,_tp_dict *self,tp_obj k, const char *error) { 116 | int n = _tp_dict_find(tp,self,k); 117 | if (n < 0) { 118 | tp_raise(tp_None,tp_add(tp,tp_string("(_tp_dict_get) KeyError: "),tp_str(tp,k))); 119 | } 120 | return self->items[n].val; 121 | } 122 | 123 | void _tp_dict_del(TP,_tp_dict *self,tp_obj k, const char *error) { 124 | int n = _tp_dict_find(tp,self,k); 125 | if (n < 0) { 126 | tp_raise(,tp_add(tp,tp_string("(_tp_dict_del) KeyError: "),tp_str(tp,k))); 127 | } 128 | self->items[n].used = -1; 129 | self->len -= 1; 130 | } 131 | 132 | _tp_dict *_tp_dict_new(TP) { 133 | _tp_dict *self = (_tp_dict*)tp_malloc(tp, sizeof(_tp_dict)); 134 | return self; 135 | } 136 | tp_obj _tp_dict_copy(TP,tp_obj rr) { 137 | tp_obj obj = {TP_DICT}; 138 | _tp_dict *o = rr.dict.val; 139 | _tp_dict *r = _tp_dict_new(tp); 140 | *r = *o; r->gci = 0; 141 | r->items = (tp_item*)tp_malloc(tp, sizeof(tp_item)*o->alloc); 142 | memcpy(r->items,o->items,sizeof(tp_item)*o->alloc); 143 | obj.dict.val = r; 144 | obj.dict.dtype = 1; 145 | return tp_track(tp,obj); 146 | } 147 | 148 | int _tp_dict_next(TP,_tp_dict *self) { 149 | if (!self->len) { 150 | tp_raise(0,tp_string("(_tp_dict_next) RuntimeError")); 151 | } 152 | while (1) { 153 | self->cur = ((self->cur + 1) & self->mask); 154 | if (self->items[self->cur].used > 0) { 155 | return self->cur; 156 | } 157 | } 158 | } 159 | 160 | tp_obj tp_merge(TP) { 161 | tp_obj self = TP_OBJ(); 162 | tp_obj v = TP_OBJ(); 163 | int i; for (i=0; ilen; i++) { 164 | int n = _tp_dict_next(tp,v.dict.val); 165 | _tp_dict_set(tp,self.dict.val, 166 | v.dict.val->items[n].key,v.dict.val->items[n].val); 167 | } 168 | return tp_None; 169 | } 170 | 171 | /* Function: tp_dict 172 | * 173 | * Creates a new dictionary object. 174 | * 175 | * *Note* If you use on the dictionary, you have to use to 176 | * access the "raw" dictionary again. 177 | * 178 | * Returns: 179 | * The newly created dictionary. 180 | */ 181 | tp_obj tp_dict(TP) { 182 | tp_obj r = {TP_DICT}; 183 | r.dict.val = _tp_dict_new(tp); 184 | r.dict.dtype = 1; 185 | return tp ? tp_track(tp,r) : r; 186 | } 187 | 188 | tp_obj tp_dict_n(TP,int n, tp_obj* argv) { 189 | tp_obj r = tp_dict(tp); 190 | int i; for (i=0; i 2 | #ifndef M_E 3 | #define M_E 2.7182818284590452354 4 | #endif 5 | #ifndef M_PI 6 | #define M_PI 3.14159265358979323846 7 | #endif 8 | 9 | #include 10 | 11 | /* 12 | * template for tinypy math functions 13 | * with one parameter. 14 | * 15 | * @cfunc is the coresponding function name in C 16 | * math library. 17 | */ 18 | #define TP_MATH_FUNC1(cfunc) \ 19 | static tp_obj math_##cfunc(TP) { \ 20 | double x = TP_NUM(); \ 21 | double r = 0.0; \ 22 | \ 23 | errno = 0; \ 24 | r = cfunc(x); \ 25 | if (errno == EDOM || errno == ERANGE) { \ 26 | tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f " \ 27 | "out of range", __func__, x)); \ 28 | } \ 29 | \ 30 | return (tp_number(r)); \ 31 | } 32 | 33 | /* 34 | * template for tinypy math functions 35 | * with two parameters. 36 | * 37 | * @cfunc is the coresponding function name in C 38 | * math library. 39 | */ 40 | #define TP_MATH_FUNC2(cfunc) \ 41 | static tp_obj math_##cfunc(TP) { \ 42 | double x = TP_NUM(); \ 43 | double y = TP_NUM(); \ 44 | double r = 0.0; \ 45 | \ 46 | errno = 0; \ 47 | r = cfunc(x, y); \ 48 | if (errno == EDOM || errno == ERANGE) { \ 49 | tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f " \ 50 | "out of range", __func__, x, y)); \ 51 | } \ 52 | \ 53 | return (tp_number(r)); \ 54 | } 55 | 56 | 57 | /* 58 | * PI definition: 3.1415926535897931 59 | */ 60 | static tp_obj math_pi; 61 | 62 | /* 63 | * E definition: 2.7182818284590451 64 | */ 65 | static tp_obj math_e; 66 | 67 | /* 68 | * acos(x) 69 | * 70 | * return arc cosine of x, return value is measured in radians. 71 | * if x falls out -1 to 1, raise out-of-range exception. 72 | */ 73 | TP_MATH_FUNC1(acos) 74 | 75 | /* 76 | * asin(x) 77 | * 78 | * return arc sine of x, measured in radians, actually [-PI/2, PI/2] 79 | * if x falls out of -1 to 1, raise out-of-range exception 80 | */ 81 | TP_MATH_FUNC1(asin) 82 | 83 | /* 84 | * atan(x) 85 | * 86 | * return arc tangent of x, measured in radians, 87 | */ 88 | TP_MATH_FUNC1(atan) 89 | 90 | /* 91 | * atan2(x, y) 92 | * 93 | * return arc tangent of x/y, measured in radians. 94 | * unlike atan(x/y), both the signs of x and y 95 | * are considered to determine the quaderant of 96 | * the result. 97 | */ 98 | TP_MATH_FUNC2(atan2) 99 | 100 | /* 101 | * ceil(x) 102 | * 103 | * return the ceiling of x, i.e, the smallest 104 | * integer >= x. 105 | */ 106 | TP_MATH_FUNC1(ceil) 107 | 108 | /* 109 | * cos(x) 110 | * 111 | * return cosine of x. x is measured in radians. 112 | */ 113 | TP_MATH_FUNC1(cos) 114 | 115 | /* 116 | * cosh(x) 117 | * 118 | * return hyperbolic cosine of x. 119 | */ 120 | TP_MATH_FUNC1(cosh) 121 | 122 | /* 123 | * degrees(x) 124 | * 125 | * converts angle x from radians to degrees. 126 | * NOTE: this function is introduced by python, 127 | * so we cannot wrap it directly in TP_MATH_FUNC1(), 128 | * here the solution is defining a new 129 | * C function - degrees(). 130 | */ 131 | static const double degToRad = 132 | 3.141592653589793238462643383 / 180.0; 133 | static double degrees(double x) 134 | { 135 | return (x / degToRad); 136 | } 137 | 138 | TP_MATH_FUNC1(degrees) 139 | 140 | /* 141 | * exp(x) 142 | * 143 | * return the value e raised to power of x. 144 | * e is the base of natural logarithms. 145 | */ 146 | TP_MATH_FUNC1(exp) 147 | 148 | /* 149 | * fabs(x) 150 | * 151 | * return the absolute value of x. 152 | */ 153 | TP_MATH_FUNC1(fabs) 154 | 155 | /* 156 | * floor(x) 157 | * 158 | * return the floor of x, i.e, the largest integer <= x 159 | */ 160 | TP_MATH_FUNC1(floor) 161 | 162 | /* 163 | * fmod(x, y) 164 | * 165 | * return the remainder of dividing x by y. that is, 166 | * return x - n * y, where n is the quotient of x/y. 167 | * NOTE: this function relies on the underlying platform. 168 | */ 169 | TP_MATH_FUNC2(fmod) 170 | 171 | /* 172 | * frexp(x) 173 | * 174 | * return a pair (r, y), which satisfies: 175 | * x = r * (2 ** y), and r is normalized fraction 176 | * which is laid between 1/2 <= abs(r) < 1. 177 | * if x = 0, the (r, y) = (0, 0). 178 | */ 179 | static tp_obj math_frexp(TP) { 180 | double x = TP_NUM(); 181 | int y = 0; 182 | double r = 0.0; 183 | tp_obj rList = tp_list(tp); 184 | 185 | errno = 0; 186 | r = frexp(x, &y); 187 | if (errno == EDOM || errno == ERANGE) { 188 | tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f, " 189 | "out of range", __func__, x)); 190 | } 191 | 192 | _tp_list_append(tp, rList.list.val, tp_number(r)); 193 | _tp_list_append(tp, rList.list.val, tp_number((tp_num)y)); 194 | return (rList); 195 | } 196 | 197 | 198 | /* 199 | * hypot(x, y) 200 | * 201 | * return Euclidean distance, namely, 202 | * sqrt(x*x + y*y) 203 | */ 204 | TP_MATH_FUNC2(hypot) 205 | 206 | 207 | /* 208 | * ldexp(x, y) 209 | * 210 | * return the result of multiplying x by 2 211 | * raised to y. 212 | */ 213 | TP_MATH_FUNC2(ldexp) 214 | 215 | /* 216 | * log(x, [base]) 217 | * 218 | * return logarithm of x to given base. If base is 219 | * not given, return the natural logarithm of x. 220 | * Note: common logarithm(log10) is used to compute 221 | * the denominator and numerator. based on fomula: 222 | * log(x, base) = log10(x) / log10(base). 223 | */ 224 | static tp_obj math_log(TP) { 225 | double x = TP_NUM(); 226 | tp_obj b = TP_DEFAULT(tp_None); 227 | double y = 0.0; 228 | double den = 0.0; /* denominator */ 229 | double num = 0.0; /* numinator */ 230 | double r = 0.0; /* result */ 231 | 232 | if (b.type == TP_NONE) 233 | y = M_E; 234 | else if (b.type == TP_NUMBER) 235 | y = (double)b.number.val; 236 | else 237 | tp_raise(tp_None, tp_printf(tp, "%s(x, [base]): base invalid", __func__)); 238 | 239 | errno = 0; 240 | num = log10(x); 241 | if (errno == EDOM || errno == ERANGE) 242 | goto excep; 243 | 244 | errno = 0; 245 | den = log10(y); 246 | if (errno == EDOM || errno == ERANGE) 247 | goto excep; 248 | 249 | r = num / den; 250 | 251 | return (tp_number(r)); 252 | 253 | excep: 254 | tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f " 255 | "out of range", __func__, x, y)); 256 | } 257 | 258 | /* 259 | * log10(x) 260 | * 261 | * return 10-based logarithm of x. 262 | */ 263 | TP_MATH_FUNC1(log10) 264 | 265 | /* 266 | * modf(x) 267 | * 268 | * return a pair (r, y). r is the integral part of 269 | * x and y is the fractional part of x, both holds 270 | * the same sign as x. 271 | */ 272 | static tp_obj math_modf(TP) { 273 | double x = TP_NUM(); 274 | double y = 0.0; 275 | double r = 0.0; 276 | tp_obj rList = tp_list(tp); 277 | 278 | errno = 0; 279 | r = modf(x, &y); 280 | if (errno == EDOM || errno == ERANGE) { 281 | tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f, " 282 | "out of range", __func__, x)); 283 | } 284 | 285 | _tp_list_append(tp, rList.list.val, tp_number(r)); 286 | _tp_list_append(tp, rList.list.val, tp_number(y)); 287 | return (rList); 288 | } 289 | 290 | /* 291 | * pow(x, y) 292 | * 293 | * return value of x raised to y. equivalence of x ** y. 294 | * NOTE: conventionally, tp_pow() is the implementation 295 | * of builtin function pow(); whilst, math_pow() is an 296 | * alternative in math module. 297 | */ 298 | static tp_obj math_pow(TP) { 299 | double x = TP_NUM(); 300 | double y = TP_NUM(); 301 | double r = 0.0; 302 | 303 | errno = 0; 304 | r = pow(x, y); 305 | if (errno == EDOM || errno == ERANGE) { 306 | tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f " 307 | "out of range", __func__, x, y)); 308 | } 309 | 310 | return (tp_number(r)); 311 | } 312 | 313 | 314 | /* 315 | * radians(x) 316 | * 317 | * converts angle x from degrees to radians. 318 | * NOTE: this function is introduced by python, 319 | * adopt same solution as degrees(x). 320 | */ 321 | static double radians(double x) 322 | { 323 | return (x * degToRad); 324 | } 325 | 326 | TP_MATH_FUNC1(radians) 327 | 328 | /* 329 | * sin(x) 330 | * 331 | * return sine of x, x is measured in radians. 332 | */ 333 | TP_MATH_FUNC1(sin) 334 | 335 | /* 336 | * sinh(x) 337 | * 338 | * return hyperbolic sine of x. 339 | * mathematically, sinh(x) = (exp(x) - exp(-x)) / 2. 340 | */ 341 | TP_MATH_FUNC1(sinh) 342 | 343 | /* 344 | * sqrt(x) 345 | * 346 | * return square root of x. 347 | * if x is negtive, raise out-of-range exception. 348 | */ 349 | TP_MATH_FUNC1(sqrt) 350 | 351 | /* 352 | * tan(x) 353 | * 354 | * return tangent of x, x is measured in radians. 355 | */ 356 | TP_MATH_FUNC1(tan) 357 | 358 | /* 359 | * tanh(x) 360 | * 361 | * return hyperbolic tangent of x. 362 | * mathematically, tanh(x) = sinh(x) / cosh(x). 363 | */ 364 | TP_MATH_FUNC1(tanh) 365 | -------------------------------------------------------------------------------- /tinypy/builtins.c: -------------------------------------------------------------------------------- 1 | /* File: Builtins 2 | * Builtin tinypy functions. 3 | */ 4 | 5 | #ifdef TP_NORMALMAKE 6 | #include "tp.h" 7 | #include "builtins_auto.h" 8 | #include "dict_auto.h" 9 | #include "list_auto.h" 10 | #include "misc_auto.h" 11 | #include "string_auto.h" 12 | #endif 13 | 14 | tp_obj tp_print(TP) { 15 | int n = 0; 16 | tp_obj e; 17 | TP_LOOP(e) 18 | if (n) { printf(" "); } 19 | tp_echo(tp,e); 20 | n += 1; 21 | TP_END; 22 | printf("\n"); 23 | return tp_None; 24 | } 25 | 26 | tp_obj tp_bind(TP) { 27 | tp_obj r = TP_TYPE(TP_FNC); 28 | tp_obj self = TP_OBJ(); 29 | return tp_fnc_new(tp, 30 | r.fnc.ftype|2,r.fnc.cfnc,r.fnc.info->code, 31 | self,r.fnc.info->globals); 32 | } 33 | 34 | tp_obj tp_min(TP) { 35 | tp_obj r = TP_OBJ(); 36 | tp_obj e; 37 | TP_LOOP(e) 38 | if (tp_cmp(tp,r,e) > 0) { r = e; } 39 | TP_END; 40 | return r; 41 | } 42 | 43 | tp_obj tp_max(TP) { 44 | tp_obj r = TP_OBJ(); 45 | tp_obj e; 46 | TP_LOOP(e) 47 | if (tp_cmp(tp,r,e) < 0) { r = e; } 48 | TP_END; 49 | return r; 50 | } 51 | 52 | tp_obj tp_copy(TP) { 53 | tp_obj r = TP_OBJ(); 54 | int type = r.type; 55 | if (type == TP_LIST) { 56 | return _tp_list_copy(tp,r); 57 | } else if (type == TP_DICT) { 58 | return _tp_dict_copy(tp,r); 59 | } 60 | tp_raise(tp_None,tp_string("(tp_copy) TypeError: ?")); 61 | } 62 | 63 | 64 | tp_obj tp_len_(TP) { 65 | tp_obj e = TP_OBJ(); 66 | return tp_len(tp,e); 67 | } 68 | 69 | tp_obj tp_assert(TP) { 70 | int a = TP_NUM(); 71 | if (a) { return tp_None; } 72 | tp_raise(tp_None,tp_string("(tp_assert) AssertionError")); 73 | } 74 | 75 | tp_obj tp_range(TP) { 76 | int a,b,c,i; 77 | tp_obj r = tp_list(tp); 78 | switch (tp->params.list.val->len) { 79 | case 1: a = 0; b = TP_NUM(); c = 1; break; 80 | case 2: 81 | case 3: a = TP_NUM(); b = TP_NUM(); c = TP_DEFAULT(tp_number(1)).number.val; break; 82 | default: return r; 83 | } 84 | if (c != 0) { 85 | for (i=a; (c>0) ? ib; i+=c) { 86 | _tp_list_append(tp,r.list.val,tp_number(i)); 87 | } 88 | } 89 | return r; 90 | } 91 | 92 | /* Function: tp_system 93 | * 94 | * The system builtin. A grave security flaw. If your version of tinypy 95 | * enables this, you better remove it before deploying your app :P 96 | */ 97 | tp_obj tp_system(TP) { 98 | char s[TP_CSTR_LEN]; tp_cstr(tp,TP_STR(),s,TP_CSTR_LEN); 99 | int r = system(s); 100 | return tp_number(r); 101 | } 102 | 103 | tp_obj tp_istype(TP) { 104 | tp_obj v = TP_OBJ(); 105 | tp_obj t = TP_STR(); 106 | if (tp_cmp(tp,t,tp_string("string")) == 0) { return tp_number(v.type == TP_STRING); } 107 | if (tp_cmp(tp,t,tp_string("list")) == 0) { return tp_number(v.type == TP_LIST); } 108 | if (tp_cmp(tp,t,tp_string("dict")) == 0) { return tp_number(v.type == TP_DICT); } 109 | if (tp_cmp(tp,t,tp_string("number")) == 0) { return tp_number(v.type == TP_NUMBER); } 110 | if (tp_cmp(tp,t,tp_string("fnc")) == 0) { return tp_number(v.type == TP_FNC && (v.fnc.ftype&2) == 0); } 111 | if (tp_cmp(tp,t,tp_string("method")) == 0) { return tp_number(v.type == TP_FNC && (v.fnc.ftype&2) != 0); } 112 | tp_raise(tp_None,tp_string("(is_type) TypeError: ?")); 113 | } 114 | 115 | 116 | tp_obj tp_float(TP) { 117 | tp_obj v = TP_OBJ(); 118 | int ord = TP_DEFAULT(tp_number(0)).number.val; 119 | int type = v.type; 120 | if (type == TP_NUMBER) { return v; } 121 | if (type == TP_STRING && v.string.len < 32) { 122 | char s[32]; memset(s,0,v.string.len+1); 123 | memcpy(s,v.string.val,v.string.len); 124 | if (strchr(s,'.')) { return tp_number(atof(s)); } 125 | return(tp_number(strtol(s,0,ord))); 126 | } 127 | tp_raise(tp_None,tp_string("(tp_float) TypeError: ?")); 128 | } 129 | 130 | 131 | tp_obj tp_save(TP) { 132 | char fname[256]; tp_cstr(tp,TP_STR(),fname,256); 133 | tp_obj v = TP_OBJ(); 134 | FILE *f; 135 | f = fopen(fname,"wb"); 136 | if (!f) { tp_raise(tp_None,tp_string("(tp_save) IOError: ?")); } 137 | fwrite(v.string.val,v.string.len,1,f); 138 | fclose(f); 139 | return tp_None; 140 | } 141 | 142 | tp_obj tp_load(TP) { 143 | FILE *f; 144 | long l; 145 | tp_obj r; 146 | char *s; 147 | char fname[256]; tp_cstr(tp,TP_STR(),fname,256); 148 | struct stat stbuf; 149 | stat(fname, &stbuf); 150 | l = stbuf.st_size; 151 | f = fopen(fname,"rb"); 152 | if (!f) { 153 | tp_raise(tp_None,tp_string("(tp_load) IOError: ?")); 154 | } 155 | r = tp_string_t(tp,l); 156 | s = r.string.info->s; 157 | fread(s,1,l,f); 158 | /* if (rr !=l) { printf("hmmn: %d %d\n",rr,(int)l); }*/ 159 | fclose(f); 160 | return tp_track(tp,r); 161 | } 162 | 163 | 164 | tp_obj tp_fpack(TP) { 165 | tp_num v = TP_NUM(); 166 | tp_obj r = tp_string_t(tp,sizeof(tp_num)); 167 | *(tp_num*)r.string.val = v; 168 | return tp_track(tp,r); 169 | } 170 | 171 | tp_obj tp_abs(TP) { 172 | return tp_number(fabs(tp_float(tp).number.val)); 173 | } 174 | tp_obj tp_int(TP) { 175 | return tp_number((long)tp_float(tp).number.val); 176 | } 177 | tp_num _roundf(tp_num v) { 178 | tp_num av = fabs(v); tp_num iv = (long)av; 179 | av = (av-iv < 0.5?iv:iv+1); 180 | return (v<0?-av:av); 181 | } 182 | tp_obj tp_round(TP) { 183 | return tp_number(_roundf(tp_float(tp).number.val)); 184 | } 185 | 186 | tp_obj tp_exists(TP) { 187 | char fname[TP_CSTR_LEN]; tp_cstr(tp,TP_STR(),fname,TP_CSTR_LEN); 188 | struct stat stbuf; 189 | return tp_number(!stat(fname,&stbuf)); 190 | } 191 | tp_obj tp_mtime(TP) { 192 | char fname[TP_CSTR_LEN]; tp_cstr(tp,TP_STR(),fname,TP_CSTR_LEN); 193 | struct stat stbuf; 194 | if (!stat(fname,&stbuf)) { return tp_number(stbuf.st_mtime); } 195 | tp_raise(tp_None,tp_string("(tp_mtime) IOError: ?")); 196 | } 197 | 198 | int _tp_lookup_(TP,tp_obj self, tp_obj k, tp_obj *meta, int depth) { 199 | int n = _tp_dict_find(tp,self.dict.val,k); 200 | if (n != -1) { 201 | *meta = self.dict.val->items[n].val; 202 | return 1; 203 | } 204 | depth--; if (!depth) { tp_raise(0,tp_string("(tp_lookup) RuntimeError: maximum lookup depth exceeded")); } 205 | if (self.dict.dtype && self.dict.val->meta.type == TP_DICT && _tp_lookup_(tp,self.dict.val->meta,k,meta,depth)) { 206 | if (self.dict.dtype == 2 && meta->type == TP_FNC) { 207 | *meta = tp_fnc_new(tp,meta->fnc.ftype|2, 208 | meta->fnc.cfnc,meta->fnc.info->code, 209 | self,meta->fnc.info->globals); 210 | } 211 | return 1; 212 | } 213 | return 0; 214 | } 215 | 216 | int _tp_lookup(TP,tp_obj self, tp_obj k, tp_obj *meta) { 217 | return _tp_lookup_(tp,self,k,meta,8); 218 | } 219 | 220 | /* Function: tp_setmeta 221 | * Set a "dict's meta". 222 | * 223 | * This is a builtin function, so you need to use to provide the 224 | * parameters. 225 | * 226 | * In tinypy, each dictionary can have a so-called "meta" dictionary attached 227 | * to it. When dictionary attributes are accessed, but not present in the 228 | * dictionary, they instead are looked up in the meta dictionary. To get the 229 | * raw dictionary, you can use . 230 | * 231 | * This function is particulary useful for objects and classes, which are just 232 | * special dictionaries created with and . There you can 233 | * use tp_setmeta to change the class of the object or parent class of a class. 234 | * 235 | * Parameters: 236 | * self - The dictionary for which to set a meta. 237 | * meta - The meta dictionary. 238 | * 239 | * Returns: 240 | * None 241 | */ 242 | tp_obj tp_setmeta(TP) { 243 | tp_obj self = TP_TYPE(TP_DICT); 244 | tp_obj meta = TP_TYPE(TP_DICT); 245 | self.dict.val->meta = meta; 246 | return tp_None; 247 | } 248 | 249 | tp_obj tp_getmeta(TP) { 250 | tp_obj self = TP_TYPE(TP_DICT); 251 | return self.dict.val->meta; 252 | } 253 | 254 | /* Function: tp_object 255 | * Creates a new object. 256 | * 257 | * Returns: 258 | * The newly created object. The object initially has no parent class, use 259 | * to set a class. Also see . 260 | */ 261 | tp_obj tp_object(TP) { 262 | tp_obj self = tp_dict(tp); 263 | self.dict.dtype = 2; 264 | return self; 265 | } 266 | 267 | tp_obj tp_object_new(TP) { 268 | tp_obj klass = TP_TYPE(TP_DICT); 269 | tp_obj self = tp_object(tp); 270 | self.dict.val->meta = klass; 271 | TP_META_BEGIN(self,"__init__"); 272 | tp_call(tp,meta,tp->params); 273 | TP_META_END; 274 | return self; 275 | } 276 | 277 | tp_obj tp_object_call(TP) { 278 | tp_obj self; 279 | if (tp->params.list.val->len) { 280 | self = TP_TYPE(TP_DICT); 281 | self.dict.dtype = 2; 282 | } else { 283 | self = tp_object(tp); 284 | } 285 | return self; 286 | } 287 | 288 | /* Function: tp_getraw 289 | * Retrieve the raw dict of a dict. 290 | * 291 | * This builtin retrieves one dict parameter from tinypy, and returns its raw 292 | * dict. This is very useful when implementing your own __get__ and __set__ 293 | * functions, as it allows you to directly access the attributes stored in the 294 | * dict. 295 | */ 296 | tp_obj tp_getraw(TP) { 297 | tp_obj self = TP_TYPE(TP_DICT); 298 | self.dict.dtype = 0; 299 | return self; 300 | } 301 | 302 | /* Function: tp_class 303 | * Creates a new base class. 304 | * 305 | * Parameters: 306 | * none 307 | * 308 | * Returns: 309 | * A new, empty class (derived from tinypy's builtin "object" class). 310 | */ 311 | tp_obj tp_class(TP) { 312 | tp_obj klass = tp_dict(tp); 313 | klass.dict.val->meta = tp_get(tp,tp->builtins,tp_string("object")); 314 | return klass; 315 | } 316 | 317 | /* Function: tp_builtins_bool 318 | * Coerces any value to a boolean. 319 | */ 320 | tp_obj tp_builtins_bool(TP) { 321 | tp_obj v = TP_OBJ(); 322 | return (tp_number(tp_bool(tp, v))); 323 | } 324 | -------------------------------------------------------------------------------- /tinypy/tp.h: -------------------------------------------------------------------------------- 1 | /* File: General 2 | * Things defined in tp.h. 3 | */ 4 | #ifndef TP_H 5 | #define TP_H 6 | 7 | #include 8 | #include 9 | #ifndef __USE_ISOC99 10 | #define __USE_ISOC99 11 | #endif 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef __GNUC__ 20 | #define tp_inline __inline__ 21 | #endif 22 | 23 | #ifdef _MSC_VER 24 | #ifdef NDEBUG 25 | #define tp_inline __inline 26 | #else 27 | /* don't inline in debug builds (for easier debugging) */ 28 | #define tp_inline 29 | #endif 30 | #endif 31 | 32 | #ifndef tp_inline 33 | #error "Unsuported compiler" 34 | #endif 35 | 36 | /* #define tp_malloc(x) calloc((x),1) 37 | #define tp_realloc(x,y) realloc(x,y) 38 | #define tp_free(x) free(x) */ 39 | 40 | /* #include 41 | #define tp_malloc(x) GC_MALLOC(x) 42 | #define tp_realloc(x,y) GC_REALLOC(x,y) 43 | #define tp_free(x)*/ 44 | 45 | enum { 46 | TP_NONE = 0, 47 | TP_NUMBER = 1, 48 | TP_STRING = 2, 49 | TP_DICT = 3, 50 | TP_LIST = 4, 51 | TP_FNC = 5, 52 | TP_DATA = 6, 53 | TP_FRAME = 7 54 | }; 55 | 56 | typedef double tp_num; 57 | 58 | typedef struct tp_number_ { 59 | int type; 60 | tp_num val; 61 | } tp_number_; 62 | typedef struct tp_string_ { 63 | int type; 64 | struct _tp_string *info; 65 | char const *val; 66 | int len; 67 | } tp_string_; 68 | typedef struct tp_list_ { 69 | int type; 70 | struct _tp_list *val; 71 | } tp_list_; 72 | typedef struct tp_dict_ { 73 | int type; 74 | struct _tp_dict *val; 75 | int dtype; 76 | } tp_dict_; 77 | typedef struct tp_fnc_ { 78 | int type; 79 | struct _tp_fnc *info; 80 | int ftype; 81 | void *cfnc; 82 | } tp_fnc_; 83 | typedef struct tp_data_ { 84 | int type; 85 | struct _tp_data *info; 86 | void *val; 87 | int magic; 88 | } tp_data_; 89 | typedef struct tp_frameptr_ { 90 | int type; 91 | void *val; 92 | } tp_frameptr_; 93 | 94 | /* Type: tp_obj 95 | * Tinypy's object representation. 96 | * 97 | * Every object in tinypy is of this type in the C API. 98 | * 99 | * Fields: 100 | * type - This determines what kind of objects it is. It is either TP_NONE, in 101 | * which case this is the none type and no other fields can be accessed. 102 | * Or it has one of the values listed below, and the corresponding 103 | * fields can be accessed. 104 | * number - TP_NUMBER 105 | * number.val - A double value with the numeric value. 106 | * string - TP_STRING 107 | * string.val - A pointer to the string data. 108 | * string.len - Length in bytes of the string data. 109 | * dict - TP_DICT 110 | * list - TP_LIST 111 | * fnc - TP_FNC 112 | * data - TP_DATA 113 | * data.val - The user-provided data pointer. 114 | * data.magic - The user-provided magic number for identifying the data type. 115 | */ 116 | typedef union tp_obj { 117 | int type; 118 | tp_number_ number; 119 | struct { int type; int *data; } gci; 120 | tp_string_ string; 121 | tp_dict_ dict; 122 | tp_list_ list; 123 | tp_fnc_ fnc; 124 | tp_data_ data; 125 | tp_frameptr_ frame; 126 | } tp_obj; 127 | 128 | typedef struct _tp_string { 129 | int gci; 130 | int len; 131 | char s[1]; 132 | } _tp_string; 133 | typedef struct _tp_list { 134 | int gci; 135 | tp_obj *items; 136 | int len; 137 | int alloc; 138 | } _tp_list; 139 | typedef struct tp_item { 140 | int used; 141 | int hash; 142 | tp_obj key; 143 | tp_obj val; 144 | } tp_item; 145 | typedef struct _tp_dict { 146 | int gci; 147 | tp_item *items; 148 | int len; 149 | int alloc; 150 | int cur; 151 | int mask; 152 | int used; 153 | tp_obj meta; 154 | } _tp_dict; 155 | typedef struct _tp_fnc { 156 | int gci; 157 | tp_obj self; 158 | tp_obj globals; 159 | tp_obj code; 160 | } _tp_fnc; 161 | 162 | 163 | typedef union tp_code { 164 | unsigned char i; 165 | struct { unsigned char i,a,b,c; } regs; 166 | struct { char val[4]; } string; 167 | struct { float val; } number; 168 | } tp_code; 169 | 170 | typedef struct tp_frame_ { 171 | /* tp_code *codes; */ 172 | tp_obj code; 173 | tp_code *cur; 174 | tp_code *jmp; 175 | tp_obj *regs; 176 | tp_obj *ret_dest; 177 | tp_obj fname; 178 | tp_obj name; 179 | tp_obj line; 180 | tp_obj globals; 181 | tp_obj params; 182 | int lineno; 183 | int cregs; 184 | } tp_frame_; 185 | 186 | #define TP_GCMAX 4096 187 | #define TP_FRAMES 256 188 | #define TP_REGS_EXTRA 2 189 | /* #define TP_REGS_PER_FRAME 256*/ 190 | #define TP_REGS 1000 191 | 192 | /* Type: tp_vm 193 | * Representation of a tinypy virtual machine instance. 194 | * 195 | * A new tp_vm struct is created with , and will be passed to most 196 | * tinypy functions as first parameter. It contains all the data associated 197 | * with an instance of a tinypy virtual machine - so it is easy to have 198 | * multiple instances running at the same time. When you want to free up all 199 | * memory used by an instance, call . 200 | * 201 | * Fields: 202 | * These fields are currently documented: 203 | * 204 | * builtins - A dictionary containing all builtin objects. 205 | * modules - A dictionary with all loaded modules. 206 | * params - A list of parameters for the current function call. 207 | * frames - A list of all call frames. 208 | * cur - The index of the currently executing call frame. 209 | * frames[n].globals - A dictionary of global sybmols in callframe n. 210 | */ 211 | typedef struct tp_vm { 212 | tp_obj builtins; 213 | tp_obj modules; 214 | tp_obj _frames; 215 | tp_obj params; 216 | tp_obj _regs; 217 | tp_obj *regs; 218 | tp_obj root; 219 | jmp_buf buf; 220 | #ifdef CPYTHON_MOD 221 | jmp_buf nextexpr; 222 | #endif 223 | int jmp; 224 | tp_obj ex; 225 | /* char chars[256][2]; */ 226 | /* gc */ 227 | struct _tp_list *white; 228 | struct _tp_list *grey; 229 | struct _tp_list *black; 230 | int steps; 231 | /* sandbox */ 232 | clock_t clocks; 233 | double time_elapsed; 234 | double time_limit; 235 | unsigned long mem_limit; 236 | unsigned long mem_used; 237 | int mem_exceeded; 238 | } tp_vm; 239 | 240 | #define TP tp_vm *tp 241 | typedef struct _tp_data { 242 | int gci; 243 | void (*free)(TP,tp_obj); 244 | } _tp_data; 245 | 246 | #define tp_True tp_number(1) 247 | #define tp_False tp_number(0) 248 | 249 | extern tp_obj tp_None; 250 | 251 | #ifdef TP_SANDBOX 252 | void *tp_malloc(TP, unsigned long); 253 | void *tp_realloc(TP, void *, unsigned long); 254 | void tp_free(TP, void *); 255 | #else 256 | #define tp_malloc(TP,x) calloc((x),1) 257 | #define tp_realloc(TP,x,y) realloc(x,y) 258 | #define tp_free(TP,x) free(x) 259 | #endif 260 | 261 | void tp_sandbox(TP, double, unsigned long); 262 | void tp_time_update(TP); 263 | void tp_mem_update(TP); 264 | void tp_compiler(TP); 265 | void tp_run(TP,int cur); 266 | void tp_set(TP,tp_obj,tp_obj,tp_obj); 267 | tp_obj tp_get(TP,tp_obj,tp_obj); 268 | tp_obj tp_has(TP,tp_obj self, tp_obj k); 269 | tp_obj tp_len(TP,tp_obj); 270 | void tp_del(TP,tp_obj,tp_obj); 271 | tp_obj tp_str(TP,tp_obj); 272 | int tp_bool(TP,tp_obj); 273 | int tp_cmp(TP,tp_obj,tp_obj); 274 | void _tp_raise(TP,tp_obj); 275 | tp_obj tp_printf(TP,char const *fmt,...); 276 | tp_obj tp_track(TP,tp_obj); 277 | void tp_grey(TP,tp_obj); 278 | tp_obj tp_call(TP, tp_obj fnc, tp_obj params); 279 | tp_obj tp_add(TP,tp_obj a, tp_obj b) ; 280 | 281 | /* __func__ __VA_ARGS__ __FILE__ __LINE__ */ 282 | 283 | /* Function: tp_raise 284 | * Macro to raise an exception. 285 | * 286 | * This macro will return from the current function returning "r". The 287 | * remaining parameters are used to format the exception message. 288 | */ 289 | /* 290 | #define tp_raise(r,fmt,...) { \ 291 | _tp_raise(tp,tp_printf(tp,fmt,__VA_ARGS__)); \ 292 | return r; \ 293 | } 294 | */ 295 | #define tp_raise(r,v) { \ 296 | _tp_raise(tp,v); \ 297 | return r; \ 298 | } 299 | 300 | /* Function: tp_string 301 | * Creates a new string object from a C string. 302 | * 303 | * Given a pointer to a C string, creates a tinypy object representing the 304 | * same string. 305 | * 306 | * *Note* Only a reference to the string will be kept by tinypy, so make sure 307 | * it does not go out of scope, and don't de-allocate it. Also be aware that 308 | * tinypy will not delete the string for you. In many cases, it is best to 309 | * use or to create a string where tinypy 310 | * manages storage for you. 311 | */ 312 | tp_inline static tp_obj tp_string(char const *v) { 313 | tp_obj val; 314 | tp_string_ s = {TP_STRING, 0, v, 0}; 315 | s.len = strlen(v); 316 | val.string = s; 317 | return val; 318 | } 319 | 320 | #define TP_CSTR_LEN 256 321 | 322 | tp_inline static void tp_cstr(TP,tp_obj v, char *s, int l) { 323 | if (v.type != TP_STRING) { 324 | tp_raise(,tp_string("(tp_cstr) TypeError: value not a string")); 325 | } 326 | if (v.string.len >= l) { 327 | tp_raise(,tp_string("(tp_cstr) TypeError: value too long")); 328 | } 329 | memset(s,0,l); 330 | memcpy(s,v.string.val,v.string.len); 331 | } 332 | 333 | 334 | #define TP_OBJ() (tp_get(tp,tp->params,tp_None)) 335 | tp_obj tp_type(TP,int t,tp_obj v); 336 | 337 | 338 | 339 | #define TP_NO_LIMIT 0 340 | #define TP_TYPE(t) tp_type(tp,t,TP_OBJ()) 341 | #define TP_NUM() (TP_TYPE(TP_NUMBER).number.val) 342 | /* #define TP_STR() (TP_CSTR(TP_TYPE(TP_STRING))) */ 343 | #define TP_STR() (TP_TYPE(TP_STRING)) 344 | #define TP_DEFAULT(d) (tp->params.list.val->len?tp_get(tp,tp->params,tp_None):(d)) 345 | 346 | /* Macro: TP_LOOP 347 | * Macro to iterate over all remaining arguments. 348 | * 349 | * If you have a function which takes a variable number of arguments, you can 350 | * iterate through all remaining arguments for example like this: 351 | * 352 | * > tp_obj *my_func(tp_vm *tp) 353 | * > { 354 | * > // We retrieve the first argument like normal. 355 | * > tp_obj first = TP_OBJ(); 356 | * > // Then we iterate over the remaining arguments. 357 | * > tp_obj arg; 358 | * > TP_LOOP(arg) 359 | * > // do something with arg 360 | * > TP_END 361 | * > } 362 | */ 363 | #define TP_LOOP(e) \ 364 | int __l = tp->params.list.val->len; \ 365 | int __i; for (__i=0; __i<__l; __i++) { \ 366 | (e) = _tp_list_get(tp,tp->params.list.val,__i,"TP_LOOP"); 367 | #define TP_END \ 368 | } 369 | 370 | tp_inline static int _tp_min(int a, int b) { return (ab?a:b); } 372 | tp_inline static int _tp_sign(tp_num v) { return (v<0?-1:(v>0?1:0)); } 373 | 374 | tp_frame_* tp_frame_get(TP, int i); 375 | tp_frame_* tp_frame_current(TP); 376 | int tp_frame_count(TP); 377 | 378 | 379 | /* Function: tp_number 380 | * Creates a new numeric object. 381 | */ 382 | tp_inline static tp_obj tp_number(tp_num v) { 383 | tp_obj val = {TP_NUMBER}; 384 | val.number.val = v; 385 | return val; 386 | } 387 | 388 | tp_inline static void tp_echo(TP,tp_obj e) { 389 | e = tp_str(tp,e); 390 | fwrite(e.string.val,1,e.string.len,stdout); 391 | } 392 | 393 | /* Function: tp_string_n 394 | * Creates a new string object from a partial C string. 395 | * 396 | * Like , but you specify how many bytes of the given C string to 397 | * use for the string object. The *note* also applies for this function, as the 398 | * string reference and length are kept, but no actual substring is stored. 399 | */ 400 | tp_inline static tp_obj tp_string_n(char const *v,int n) { 401 | tp_obj val; 402 | tp_string_ s = {TP_STRING, 0,v,n}; 403 | val.string = s; 404 | return val; 405 | } 406 | 407 | #define TP_META_BEGIN(self,name) \ 408 | if (self.dict.dtype == 2) { \ 409 | tp_obj meta; if (_tp_lookup(tp,self,tp_string(name),&meta)) { 410 | 411 | #define TP_META_END \ 412 | } \ 413 | } 414 | 415 | #endif 416 | -------------------------------------------------------------------------------- /tinypy/parse.py: -------------------------------------------------------------------------------- 1 | import tokenize, sys 2 | from tokenize import Token 3 | if not "tinypy" in sys.version: 4 | from boot import * 5 | 6 | def check(t,*vs): 7 | if vs[0] == None: return True 8 | if t.type in vs: return True 9 | if t.type == 'symbol' and t.val in vs: return True 10 | return False 11 | 12 | def tweak(k,v): 13 | P.stack.append((k,dmap[k])) 14 | if v: dmap[k] = omap[k] 15 | else: dmap[k] = {'lbp':0,'nud':itself} 16 | def restore(): 17 | k,v = P.stack.pop() 18 | dmap[k] = v 19 | 20 | def cpy(d): 21 | r = {} 22 | for k in d: r[k] = d[k] 23 | return r 24 | 25 | class PData: 26 | def __init__(self,s,tokens): 27 | self.s = s 28 | self.tokens = tokens 29 | self.pos = 0 30 | self.token = None 31 | self.stack = [] 32 | self._terminal = 0 33 | def init(self): 34 | global omap,dmap 35 | omap = cpy(base_dmap) 36 | dmap = cpy(base_dmap) 37 | self.advance() 38 | def advance(self,val=None): 39 | if not check(self.token,val): 40 | error('expected '+val,self.token) 41 | if self.pos < len(self.tokens): 42 | t = self.tokens[self.pos] 43 | self.pos += 1 44 | else: 45 | t = Token((0,0),'eof','eof') 46 | self.token = do(t) 47 | 48 | self._terminal += 1 49 | if check(self.token,'nl','eof',';','dedent'): 50 | self._terminal = 0 51 | return t 52 | 53 | def terminal(self): 54 | if self._terminal > 1: 55 | error('invalid statement',self.token) 56 | 57 | def error(ctx,t): 58 | tokenize.u_error(ctx,P.s,t.pos) 59 | 60 | def nud(t): 61 | #if 'nud' not in t: 62 | #error('no nud',t) 63 | return t.nud(t) 64 | def led(t,left): 65 | #if 'led' not in t: 66 | #error('no led',t) 67 | return t.led(t,left) 68 | def get_lbp(t): 69 | #if 'lbp' not in t: 70 | #error('no lbp',t) 71 | return t.lbp 72 | def get_items(t): 73 | #if 'items' not in t: 74 | #error('no items',t) 75 | return t.items 76 | 77 | def expression(rbp): 78 | t = P.token 79 | advance() 80 | left = nud(t) 81 | while rbp < get_lbp(P.token): 82 | t = P.token 83 | advance() 84 | left = led(t,left) 85 | return left 86 | 87 | def infix_led(t,left): 88 | t.items = [left,expression(t.bp)] 89 | return t 90 | def infix_is(t,left): 91 | if check(P.token,'not'): 92 | t.val = 'isnot' 93 | advance('not') 94 | t.items = [left,expression(t.bp)] 95 | return t 96 | def infix_not(t,left): 97 | advance('in') 98 | t.val = 'notin' 99 | t.items = [left,expression(t.bp)] 100 | return t 101 | def infix_tuple(t,left): 102 | r = expression(t.bp) 103 | if left.val == ',': 104 | left.items.append(r) 105 | return left 106 | t.items = [left,r] 107 | t.type = 'tuple' 108 | return t 109 | def lst(t): 110 | if t == None: return [] 111 | if check(t,',','tuple','statements'): 112 | return get_items(t) 113 | return [t] 114 | def ilst(typ,t): 115 | return Token(t.pos,typ,typ,lst(t)) 116 | 117 | def call_led(t,left): 118 | r = Token(t.pos,'call','$',[left]) 119 | while not check(P.token,')'): 120 | tweak(',',0) 121 | r.items.append(expression(0)) 122 | if P.token.val == ',': advance(',') 123 | restore() 124 | advance(")") 125 | return r 126 | def get_led(t,left): 127 | r = Token(t.pos,'get','.',[left]) 128 | items = [left] 129 | more = False 130 | while not check(P.token,']'): 131 | more = False 132 | if check(P.token,':'): 133 | items.append(Token(P.token.pos,'symbol','None')) 134 | else: 135 | items.append(expression(0)) 136 | if check(P.token,':'): 137 | advance(':') 138 | more = True 139 | if more: 140 | items.append(Token(P.token.pos,'symbol','None')) 141 | if len(items) > 2: 142 | items = [left,Token(t.pos,'slice',':',items[1:])] 143 | r.items = items 144 | advance("]") 145 | return r 146 | def dot_led(t,left): 147 | r = expression(t.bp) 148 | r.type = 'string' 149 | t.items = [left,r] 150 | return t 151 | 152 | def itself(t): 153 | return t 154 | def paren_nud(t): 155 | tweak(',',1) 156 | r = expression(0) 157 | restore() 158 | advance(')') 159 | return r 160 | def list_nud(t): 161 | t.type = 'list' 162 | t.val = '[]' 163 | t.items = [] 164 | next = P.token 165 | tweak(',',0) 166 | while not check(P.token,'for',']'): 167 | r = expression(0) 168 | t.items.append(r) 169 | if P.token.val == ',': advance(',') 170 | if check(P.token,'for'): 171 | t.type = 'comp' 172 | advance('for') 173 | tweak('in',0) 174 | t.items.append(expression(0)) 175 | advance('in') 176 | t.items.append(expression(0)) 177 | restore() 178 | restore() 179 | advance(']') 180 | return t 181 | def dict_nud(t): 182 | t.type='dict' 183 | t.val = '{}' 184 | t.items = [] 185 | tweak(',',0) 186 | while not check(P.token,'}'): 187 | t.items.append(expression(0)) 188 | if check(P.token,':',','): advance() 189 | restore() 190 | advance('}') 191 | return t 192 | 193 | def advance(t=None): 194 | return P.advance(t) 195 | 196 | def iblock(items): 197 | while check(P.token,'nl',';'): advance() 198 | while True: 199 | items.append(expression(0)) 200 | P.terminal() 201 | while check(P.token,'nl',';'): advance() 202 | if check(P.token,'dedent','eof'): break 203 | 204 | def block(): 205 | items = [] 206 | tok = P.token 207 | 208 | if check(P.token,'nl'): 209 | while check(P.token,'nl'): advance() 210 | advance('indent') 211 | iblock(items) 212 | advance('dedent') 213 | else: 214 | items.append(expression(0)) 215 | while check(P.token,';'): 216 | advance(';') 217 | items.append(expression(0)) 218 | P.terminal() 219 | while check(P.token,'nl'): advance() 220 | 221 | if len(items) > 1: 222 | return Token(tok.pos,'statements',';',items) 223 | return items.pop() 224 | 225 | def def_nud(t): 226 | items = t.items = [] 227 | items.append(P.token); advance() 228 | advance('(') 229 | r = Token(t.pos,'symbol','():',[]) 230 | items.append(r) 231 | while not check(P.token,')'): 232 | tweak(',',0) 233 | r.items.append(expression(0)) 234 | if check(P.token,','): advance(',') 235 | restore() 236 | advance(')') 237 | advance(':') 238 | items.append(block()) 239 | return t 240 | 241 | 242 | def while_nud(t): 243 | items = t.items = [] 244 | items.append(expression(0)) 245 | advance(':') 246 | items.append(block()) 247 | return t 248 | def class_nud(t): 249 | items = t.items = [] 250 | items.append(expression(0)) 251 | advance(':') 252 | items.append(ilst('methods',block())) 253 | return t 254 | 255 | def from_nud(t): 256 | items = t.items = [] 257 | items.append(expression(0)) 258 | advance('import') 259 | items.append(expression(0)) 260 | return t 261 | 262 | def for_nud(t): 263 | items = t.items = [] 264 | tweak('in',0) 265 | items.append(expression(0)) 266 | advance('in') 267 | items.append(expression(0)) 268 | restore() 269 | advance(':') 270 | items.append(block()) 271 | return t 272 | def if_nud(t): 273 | items = t.items = [] 274 | a = expression(0) 275 | advance(':') 276 | b = block() 277 | items.append(Token(t.pos,'elif','elif',[a,b])) 278 | while check(P.token,'elif'): 279 | tok = P.token 280 | advance('elif') 281 | a = expression(0) 282 | advance(':') 283 | b = block() 284 | items.append(Token(tok.pos,'elif','elif',[a,b])) 285 | if check(P.token,'else'): 286 | tok = P.token 287 | advance('else') 288 | advance(':') 289 | b = block() 290 | items.append(Token(tok.pos,'else','else',[b])) 291 | return t 292 | def try_nud(t): 293 | items = t.items = [] 294 | advance(':') 295 | b = block() 296 | items.append(b) 297 | while check(P.token,'except'): 298 | tok = P.token 299 | advance('except') 300 | if not check(P.token,':'): a = expression(0) 301 | else: a = Token(tok.pos,'symbol','None') 302 | advance(':') 303 | b = block() 304 | items.append(Token(tok.pos,'except','except',[a,b])) 305 | #commenting this out, i don't think this next bit is valid syntax?? 306 | #if check(P.token,'else'): 307 | #tok = P.token 308 | #advance('else') 309 | #advance(':') 310 | #b = block() 311 | #items.append(Token(tok.pos,'else','else',[b])) 312 | return t 313 | def prefix_nud(t): 314 | #bp = 70 315 | #if 'bp' in t: bp = t['bp'] 316 | bp = t.bp 317 | t.items = [expression(bp)] 318 | return t 319 | def prefix_nud0(t): 320 | if check(P.token,'nl',';','eof','dedent'): return t 321 | return prefix_nud(t) 322 | def prefix_nuds(t): 323 | r = expression(0) 324 | return ilst(t.type,r) 325 | 326 | def prefix_neg(t): 327 | r = expression(50) 328 | if r.type == 'number': 329 | r.val = str(-float(r.val)) 330 | return r 331 | t.items = [Token(t.pos,'number','0'),r] 332 | return t 333 | def vargs_nud(t): 334 | r = prefix_nud(t) 335 | t.type = 'args' 336 | t.val = '*' 337 | return t 338 | def nargs_nud(t): 339 | r = prefix_nud(t) 340 | t.type = 'nargs' 341 | t.val = '**' 342 | return t 343 | 344 | 345 | base_dmap = { 346 | ',':{'lbp':20,'bp':20,'led':infix_tuple}, 347 | '+':{'lbp':50,'bp':50,'led':infix_led}, 348 | '-':{'lbp':50,'nud':prefix_neg, 349 | 'bp':50,'led':infix_led}, 350 | 'not':{'lbp':35,'nud':prefix_nud,'bp':35, 351 | 'bp':35,'led':infix_not }, 352 | '%':{'lbp':60,'bp':60,'led':infix_led}, 353 | '*':{'lbp':60,'nud':vargs_nud, 354 | 'bp':60,'led':infix_led,}, 355 | '**': {'lbp':65,'nud':nargs_nud, 356 | 'bp':65,'led':infix_led,}, 357 | '/':{'lbp':60,'bp':60,'led':infix_led}, 358 | '(':{'lbp':70,'nud':paren_nud, 359 | 'bp':80,'led':call_led,}, 360 | '[':{'lbp':70,'nud':list_nud, 361 | 'bp':80,'led':get_led,}, 362 | '{':{'lbp':0,'nud':dict_nud,}, 363 | '.':{'lbp':80,'bp':80,'led':dot_led,'type':'get',}, 364 | 'break':{'lbp':0,'nud':itself,'type':'break'}, 365 | 'pass':{'lbp':0,'nud':itself,'type':'pass'}, 366 | 'continue':{'lbp':0,'nud':itself,'type':'continue'}, 367 | 'eof':{'lbp':0,'type':'eof','val':'eof'}, 368 | 'def':{'lbp':0,'nud':def_nud,'type':'def',}, 369 | 'while':{'lbp':0,'nud':while_nud,'type':'while',}, 370 | 'for':{'lbp':0,'nud':for_nud,'type':'for',}, 371 | 'try':{'lbp':0,'nud':try_nud,'type':'try',}, 372 | 'if':{'lbp':0,'nud':if_nud,'type':'if',}, 373 | 'class':{'lbp':0,'nud':class_nud,'type':'class',}, 374 | 'raise':{'lbp':0,'nud':prefix_nud0,'type':'raise','bp':20,}, 375 | 'return':{'lbp':0,'nud':prefix_nud0,'type':'return','bp':10,}, 376 | 'import':{'lbp':0,'nud':prefix_nuds,'type':'import','bp':20,}, 377 | 'from':{'lbp':0,'nud':from_nud,'type':'from','bp':20,}, 378 | 'del':{'lbp':0,'nud':prefix_nuds,'type':'del','bp':10,}, 379 | 'global':{'lbp':0,'nud':prefix_nuds,'type':'globals','bp':20,}, 380 | 381 | '=':{ 382 | 'lbp':10,'bp':9,'led':infix_led, 383 | }, 384 | } 385 | 386 | def i_infix(bp,led,*vs): 387 | for v in vs: base_dmap[v] = {'lbp':bp,'bp':bp,'led':led} 388 | i_infix(40,infix_led,'<','>','<=','>=','!=','==') 389 | i_infix(40,infix_is,'is','in') 390 | i_infix(10,infix_led,'+=','-=','*=','/=', '&=', '|=', '^=') 391 | i_infix(32,infix_led,'and','&') 392 | i_infix(31,infix_led,'^') 393 | i_infix(30,infix_led,'or','|') 394 | i_infix(36,infix_led,'<<','>>') 395 | def i_terms(*vs): 396 | for v in vs: base_dmap[v] = {'lbp':0,'nud':itself} 397 | i_terms(')','}',']',';',':','nl','elif','else','True','False','None','name','string','number','indent','dedent','except') 398 | base_dmap['nl']['val'] = 'nl' 399 | 400 | def gmap(t,v): 401 | if v not in dmap: 402 | error('unknown "%s"'%v,t) 403 | return dmap[v] 404 | 405 | def do(t): 406 | if t.type == 'symbol': r = gmap(t,t.val) 407 | else: r = gmap(t,t.type) 408 | merge(t,r) 409 | return t 410 | def do_module(): 411 | tok = P.token 412 | items = [] 413 | iblock(items) 414 | advance('eof') 415 | if len(items) > 1: 416 | return Token(tok.pos,'statements',';',items) 417 | return items.pop() 418 | 419 | def parse(s,tokens,wrap=0): 420 | global P 421 | s = tokenize.clean(s) 422 | P=PData(s,tokens); P.init() 423 | r = do_module() 424 | P = None 425 | return r 426 | 427 | -------------------------------------------------------------------------------- /tinypy/ops.c: -------------------------------------------------------------------------------- 1 | /* File: Operations 2 | * Various tinypy operations. 3 | */ 4 | 5 | #ifdef TP_NORMALMAKE 6 | #include "tp.h" 7 | #include "list_auto.h" 8 | #include "dict_auto.h" 9 | #include "string_auto.h" 10 | #include "builtins_auto.h" 11 | #include "misc_auto.h" 12 | #endif 13 | 14 | /* Function: tp_str 15 | * String representation of an object. 16 | * 17 | * Returns a string object representating self. 18 | */ 19 | tp_obj tp_str(TP,tp_obj self) { 20 | int type = self.type; 21 | if (type == TP_STRING) { return self; } 22 | if (type == TP_NUMBER) { 23 | tp_num v = self.number.val; 24 | if ((fabs(v)-fabs((long)v)) < 0.000001) { return tp_printf(tp,"%ld",(long)v); } 25 | return tp_printf(tp,"%f",v); 26 | } else if(type == TP_DICT) { 27 | return tp_printf(tp,"",self.dict.val); 28 | } else if(type == TP_LIST) { 29 | return tp_printf(tp,"",self.list.val); 30 | } else if (type == TP_NONE) { 31 | return tp_string("None"); 32 | } else if (type == TP_DATA) { 33 | return tp_printf(tp,"",self.data.val); 34 | } else if (type == TP_FNC) { 35 | return tp_printf(tp,"",self.fnc.info); 36 | } 37 | return tp_string(""); 38 | } 39 | 40 | /* Function: tp_bool 41 | * Check the truth value of an object 42 | * 43 | * Returns false if v is a numeric object with a value of exactly 0, v is of 44 | * type None or v is a string list or dictionary with a length of 0. Else true 45 | * is returned. 46 | */ 47 | int tp_bool(TP,tp_obj v) { 48 | switch(v.type) { 49 | case TP_NUMBER: return v.number.val != 0; 50 | case TP_NONE: return 0; 51 | case TP_STRING: return v.string.len != 0; 52 | case TP_LIST: return v.list.val->len != 0; 53 | case TP_DICT: return v.dict.val->len != 0; 54 | } 55 | return 1; 56 | } 57 | 58 | 59 | /* Function: tp_has 60 | * Checks if an object contains a key. 61 | * 62 | * Returns tp_True if self[k] exists, tp_False otherwise. 63 | */ 64 | tp_obj tp_has(TP,tp_obj self, tp_obj k) { 65 | int type = self.type; 66 | if (type == TP_DICT) { 67 | if (_tp_dict_find(tp,self.dict.val,k) != -1) { return tp_True; } 68 | return tp_False; 69 | } else if (type == TP_STRING && k.type == TP_STRING) { 70 | return tp_number(_tp_str_index(self,k)!=-1); 71 | } else if (type == TP_LIST) { 72 | return tp_number(_tp_list_find(tp,self.list.val,k)!=-1); 73 | } 74 | tp_raise(tp_None,tp_string("(tp_has) TypeError: iterable argument required")); 75 | } 76 | 77 | /* Function: tp_del 78 | * Remove a dictionary entry. 79 | * 80 | * Removes the key k from self. Also works on classes and objects. 81 | * 82 | * Note that unlike with Python, you cannot use this to remove list items. 83 | */ 84 | void tp_del(TP,tp_obj self, tp_obj k) { 85 | int type = self.type; 86 | if (type == TP_DICT) { 87 | _tp_dict_del(tp,self.dict.val,k,"tp_del"); 88 | return; 89 | } 90 | tp_raise(,tp_string("(tp_del) TypeError: object does not support item deletion")); 91 | } 92 | 93 | 94 | /* Function: tp_iter 95 | * Iterate through a list or dict. 96 | * 97 | * If self is a list/string/dictionary, this will iterate over the 98 | * elements/characters/keys respectively, if k is an increasing index 99 | * starting with 0 up to the length of the object-1. 100 | * 101 | * In the case of a list of string, the returned items will correspond to the 102 | * item at index k. For a dictionary, no guarantees are made about the order. 103 | * You also cannot call the function with a specific k to get a specific 104 | * item -- it is only meant for iterating through all items, calling this 105 | * function len(self) times. Use to retrieve a specific item, and 106 | * to get the length. 107 | * 108 | * Parameters: 109 | * self - The object over which to iterate. 110 | * k - You must pass 0 on the first call, then increase it by 1 after each call, 111 | * and don't call the function with k >= len(self). 112 | * 113 | * Returns: 114 | * The first (k = 0) or next (k = 1 .. len(self)-1) item in the iteration. 115 | */ 116 | tp_obj tp_iter(TP,tp_obj self, tp_obj k) { 117 | int type = self.type; 118 | if (type == TP_LIST || type == TP_STRING) { return tp_get(tp,self,k); } 119 | if (type == TP_DICT && k.type == TP_NUMBER) { 120 | return self.dict.val->items[_tp_dict_next(tp,self.dict.val)].key; 121 | } 122 | tp_raise(tp_None,tp_string("(tp_iter) TypeError: iteration over non-sequence")); 123 | } 124 | 125 | 126 | /* Function: tp_get 127 | * Attribute lookup. 128 | * 129 | * This returns the result of using self[k] in actual code. It works for 130 | * dictionaries (including classes and instantiated objects), lists and strings. 131 | * 132 | * As a special case, if self is a list, self[None] will return the first 133 | * element in the list and subsequently remove it from the list. 134 | */ 135 | tp_obj tp_get(TP,tp_obj self, tp_obj k) { 136 | int type = self.type; 137 | tp_obj r; 138 | if (type == TP_DICT) { 139 | TP_META_BEGIN(self,"__get__"); 140 | return tp_call(tp,meta,tp_params_v(tp,1,k)); 141 | TP_META_END; 142 | if (self.dict.dtype && _tp_lookup(tp,self,k,&r)) { return r; } 143 | return _tp_dict_get(tp,self.dict.val,k,"tp_get"); 144 | } else if (type == TP_LIST) { 145 | if (k.type == TP_NUMBER) { 146 | int l = tp_len(tp,self).number.val; 147 | int n = k.number.val; 148 | n = (n<0?l+n:n); 149 | return _tp_list_get(tp,self.list.val,n,"tp_get"); 150 | } else if (k.type == TP_STRING) { 151 | if (tp_cmp(tp,tp_string("append"),k) == 0) { 152 | return tp_method(tp,self,tp_append); 153 | } else if (tp_cmp(tp,tp_string("pop"),k) == 0) { 154 | return tp_method(tp,self,tp_pop); 155 | } else if (tp_cmp(tp,tp_string("index"),k) == 0) { 156 | return tp_method(tp,self,tp_index); 157 | } else if (tp_cmp(tp,tp_string("sort"),k) == 0) { 158 | return tp_method(tp,self,tp_sort); 159 | } else if (tp_cmp(tp,tp_string("extend"),k) == 0) { 160 | return tp_method(tp,self,tp_extend); 161 | } else if (tp_cmp(tp,tp_string("*"),k) == 0) { 162 | tp_params_v(tp,1,self); 163 | r = tp_copy(tp); 164 | self.list.val->len=0; 165 | return r; 166 | } 167 | } else if (k.type == TP_NONE) { 168 | return _tp_list_pop(tp,self.list.val,0,"tp_get"); 169 | } 170 | } else if (type == TP_STRING) { 171 | if (k.type == TP_NUMBER) { 172 | int l = self.string.len; 173 | int n = k.number.val; 174 | n = (n<0?l+n:n); 175 | if (n >= 0 && n < l) { 176 | char tmp = (unsigned char)self.string.val[n]; 177 | /* return tp_string_n(tp->chars[(unsigned char)self.string.val[n]],1); */ 178 | return tp_string_copy(tp, &tmp, 1); 179 | } 180 | } else if (k.type == TP_STRING) { 181 | if (tp_cmp(tp,tp_string("join"),k) == 0) { 182 | return tp_method(tp,self,tp_join); 183 | } else if (tp_cmp(tp,tp_string("split"),k) == 0) { 184 | return tp_method(tp,self,tp_split); 185 | } else if (tp_cmp(tp,tp_string("index"),k) == 0) { 186 | return tp_method(tp,self,tp_str_index); 187 | } else if (tp_cmp(tp,tp_string("strip"),k) == 0) { 188 | return tp_method(tp,self,tp_strip); 189 | } else if (tp_cmp(tp,tp_string("replace"),k) == 0) { 190 | return tp_method(tp,self,tp_replace); 191 | } 192 | } 193 | } 194 | 195 | if (k.type == TP_LIST) { 196 | int a,b,l; 197 | tp_obj tmp; 198 | l = tp_len(tp,self).number.val; 199 | tmp = tp_get(tp,k,tp_number(0)); 200 | if (tmp.type == TP_NUMBER) { a = tmp.number.val; } 201 | else if(tmp.type == TP_NONE) { a = 0; } 202 | else { tp_raise(tp_None,tp_string("(tp_get) TypeError: indices must be numbers")); } 203 | tmp = tp_get(tp,k,tp_number(1)); 204 | if (tmp.type == TP_NUMBER) { b = tmp.number.val; } 205 | else if(tmp.type == TP_NONE) { b = l; } 206 | else { tp_raise(tp_None,tp_string("(tp_get) TypeError: indices must be numbers")); } 207 | a = _tp_max(0,(a<0?l+a:a)); b = _tp_min(l,(b<0?l+b:b)); 208 | if (type == TP_LIST) { 209 | return tp_list_n(tp,b-a,&self.list.val->items[a]); 210 | } else if (type == TP_STRING) { 211 | return tp_string_sub(tp,self,a,b); 212 | } 213 | } 214 | 215 | tp_raise(tp_None,tp_string("(tp_get) TypeError: ?")); 216 | } 217 | 218 | /* Function: tp_iget 219 | * Failsafe attribute lookup. 220 | * 221 | * This is like , except it will return false if the attribute lookup 222 | * failed. Otherwise, it will return true, and the object will be returned 223 | * over the reference parameter r. 224 | */ 225 | int tp_iget(TP,tp_obj *r, tp_obj self, tp_obj k) { 226 | if (self.type == TP_DICT) { 227 | int n = _tp_dict_find(tp,self.dict.val,k); 228 | if (n == -1) { return 0; } 229 | *r = self.dict.val->items[n].val; 230 | tp_grey(tp,*r); 231 | return 1; 232 | } 233 | if (self.type == TP_LIST && !self.list.val->len) { return 0; } 234 | *r = tp_get(tp,self,k); tp_grey(tp,*r); 235 | return 1; 236 | } 237 | 238 | /* Function: tp_set 239 | * Attribute modification. 240 | * 241 | * This is the counterpart of tp_get, it does the same as self[k] = v would do 242 | * in actual tinypy code. 243 | */ 244 | void tp_set(TP,tp_obj self, tp_obj k, tp_obj v) { 245 | int type = self.type; 246 | 247 | if (type == TP_DICT) { 248 | TP_META_BEGIN(self,"__set__"); 249 | tp_call(tp,meta,tp_params_v(tp,2,k,v)); 250 | return; 251 | TP_META_END; 252 | _tp_dict_set(tp,self.dict.val,k,v); 253 | return; 254 | } else if (type == TP_LIST) { 255 | if (k.type == TP_NUMBER) { 256 | _tp_list_set(tp,self.list.val,k.number.val,v,"tp_set"); 257 | return; 258 | } else if (k.type == TP_NONE) { 259 | _tp_list_append(tp,self.list.val,v); 260 | return; 261 | } else if (k.type == TP_STRING) { 262 | if (tp_cmp(tp,tp_string("*"),k) == 0) { 263 | tp_params_v(tp,2,self,v); tp_extend(tp); 264 | return; 265 | } 266 | } 267 | } 268 | tp_raise(,tp_string("(tp_set) TypeError: object does not support item assignment")); 269 | } 270 | 271 | tp_obj tp_add(TP,tp_obj a, tp_obj b) { 272 | if (a.type == TP_NUMBER && a.type == b.type) { 273 | return tp_number(a.number.val+b.number.val); 274 | } else if (a.type == TP_STRING && a.type == b.type) { 275 | int al = a.string.len, bl = b.string.len; 276 | tp_obj r = tp_string_t(tp,al+bl); 277 | char *s = r.string.info->s; 278 | memcpy(s,a.string.val,al); memcpy(s+al,b.string.val,bl); 279 | return tp_track(tp,r); 280 | } else if (a.type == TP_LIST && a.type == b.type) { 281 | tp_obj r; 282 | tp_params_v(tp,1,a); 283 | r = tp_copy(tp); 284 | tp_params_v(tp,2,r,b); 285 | tp_extend(tp); 286 | return r; 287 | } 288 | tp_raise(tp_None,tp_string("(tp_add) TypeError: ?")); 289 | } 290 | 291 | tp_obj tp_mul(TP,tp_obj a, tp_obj b) { 292 | if (a.type == TP_NUMBER && a.type == b.type) { 293 | return tp_number(a.number.val*b.number.val); 294 | } else if ((a.type == TP_STRING && b.type == TP_NUMBER) || 295 | (a.type == TP_NUMBER && b.type == TP_STRING)) { 296 | if(a.type == TP_NUMBER) { 297 | tp_obj c = a; a = b; b = c; 298 | } 299 | int al = a.string.len; int n = b.number.val; 300 | if(n <= 0) { 301 | tp_obj r = tp_string_t(tp,0); 302 | return tp_track(tp,r); 303 | } 304 | tp_obj r = tp_string_t(tp,al*n); 305 | char *s = r.string.info->s; 306 | int i; for (i=0; ilen); 323 | } else if (type == TP_LIST) { 324 | return tp_number(self.list.val->len); 325 | } 326 | 327 | tp_raise(tp_None,tp_string("(tp_len) TypeError: len() of unsized object")); 328 | } 329 | 330 | int tp_cmp(TP,tp_obj a, tp_obj b) { 331 | if (a.type != b.type) { return a.type-b.type; } 332 | switch(a.type) { 333 | case TP_NONE: return 0; 334 | case TP_NUMBER: return _tp_sign(a.number.val-b.number.val); 335 | case TP_STRING: { 336 | int l = _tp_min(a.string.len,b.string.len); 337 | int v = memcmp(a.string.val,b.string.val,l); 338 | if (v == 0) { 339 | v = a.string.len-b.string.len; 340 | } 341 | return v; 342 | } 343 | case TP_LIST: { 344 | int n,v; for(n=0;n<_tp_min(a.list.val->len,b.list.val->len);n++) { 345 | tp_obj aa = a.list.val->items[n]; tp_obj bb = b.list.val->items[n]; 346 | if (aa.type == TP_LIST && bb.type == TP_LIST) { v = aa.list.val-bb.list.val; } else { v = tp_cmp(tp,aa,bb); } 347 | if (v) { return v; } } 348 | return a.list.val->len-b.list.val->len; 349 | } 350 | case TP_DICT: return a.dict.val - b.dict.val; 351 | case TP_FNC: return a.fnc.info - b.fnc.info; 352 | case TP_DATA: return (char*)a.data.val - (char*)b.data.val; 353 | } 354 | tp_raise(0,tp_string("(tp_cmp) TypeError: ?")); 355 | } 356 | 357 | #define TP_OP(name,expr) \ 358 | tp_obj name(TP,tp_obj _a,tp_obj _b) { \ 359 | if (_a.type == TP_NUMBER && _a.type == _b.type) { \ 360 | tp_num a = _a.number.val; tp_num b = _b.number.val; \ 361 | return tp_number(expr); \ 362 | } \ 363 | tp_raise(tp_None,tp_string("(" #name ") TypeError: unsupported operand type(s)")); \ 364 | } 365 | 366 | TP_OP(tp_bitwise_and,((long)a)&((long)b)); 367 | TP_OP(tp_bitwise_or,((long)a)|((long)b)); 368 | TP_OP(tp_bitwise_xor,((long)a)^((long)b)); 369 | TP_OP(tp_mod,((long)a)%((long)b)); 370 | TP_OP(tp_lsh,((long)a)<<((long)b)); 371 | TP_OP(tp_rsh,((long)a)>>((long)b)); 372 | TP_OP(tp_sub,a-b); 373 | TP_OP(tp_div,a/b); 374 | TP_OP(tp_pow,pow(a,b)); 375 | 376 | tp_obj tp_bitwise_not(TP, tp_obj a) { 377 | if (a.type == TP_NUMBER) { 378 | return tp_number(~(long)a.number.val); 379 | } 380 | tp_raise(tp_None,tp_string("(tp_bitwise_not) TypeError: unsupported operand type")); 381 | } 382 | 383 | /**/ 384 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | VARS = {'$CPYTHON':''} 5 | TOPDIR = os.path.abspath(os.path.dirname(__file__)) 6 | TEST = False 7 | CLEAN = False 8 | BOOT = False 9 | DEBUG = False 10 | VALGRIND = False 11 | SANDBOX = False 12 | CORE = ['tokenize','parse','encode','py2bc'] 13 | MODULES = [] 14 | 15 | def main(): 16 | chksize() 17 | if len(sys.argv) < 2: 18 | print HELP 19 | return 20 | 21 | global TEST,CLEAN,BOOT,DEBUG,VALGRIND,SANDBOX 22 | TEST = 'test' in sys.argv 23 | CLEAN = 'clean' in sys.argv 24 | BOOT = 'boot' in sys.argv 25 | DEBUG = 'debug' in sys.argv 26 | VALGRIND = 'valgrind' in sys.argv 27 | SANDBOX = 'sandbox' in sys.argv 28 | CLEAN = CLEAN or BOOT 29 | TEST = TEST or BOOT 30 | 31 | get_libs() 32 | build_mymain() 33 | 34 | build = None 35 | 36 | if "linux" in sys.platform: 37 | vars_linux() 38 | build = build_gcc 39 | elif "darwin" in sys.platform: 40 | vars_osx() 41 | build = build_gcc 42 | elif "win" in sys.platform: 43 | build = build_vs 44 | 45 | #full list of compilers in distutils.ccompiler.show_compilers() 46 | if "-cunix" in sys.argv: 47 | build = build_gcc 48 | elif '-cmsvc' in sys.argv: 49 | build = build_vs 50 | elif '-cmingw32' in sys.argv: 51 | vars_windows() 52 | build = build_gcc 53 | 54 | if build == None: 55 | print "couldn't detect OS or incorrect compiler command. defaulting to GCC." 56 | build = build_gcc 57 | 58 | cmd = sys.argv[1] 59 | if cmd == "tinypy": 60 | build() 61 | elif cmd == '64k': 62 | build_64k() 63 | elif cmd == 'blob': 64 | build_blob() 65 | elif cmd == "build": 66 | build_blob() 67 | build_cpython() 68 | elif cmd == "install": 69 | install_cpython() 70 | else: 71 | print 'invalid command' 72 | 73 | HELP = """ 74 | python setup.py command [options] [modules] 75 | 76 | Commands: 77 | tinypy - build a vanilla tinypy interpreter binary 78 | 64k - generate a 64k version of the tinypy source 79 | blob - generate a single tinypy.c and tinypy.h 80 | 81 | build - build CPython module 82 | install - install CPython module 83 | 84 | Options: 85 | test - run tests during build 86 | clean - rebuild all .tpc during build 87 | boot - fully bootstrap and test tinypy 88 | debug - build with debug options on 89 | valgrind - run tests through valgrind 90 | -cCOMPILER - build for a specific platform (-cmingw32, -clinux, -cmsvc, -cunix) 91 | sandbox - enable sandbox 92 | 93 | Modules: 94 | math - build math module 95 | random - build random module * 96 | pygame - build pygame module ** 97 | marshal - build marshal module *** 98 | jit - build jit module *** 99 | re - build re module *** 100 | ??? - build other modules in the modules folder 101 | 102 | * coming soon!! 103 | ** proof-of-concept included 104 | *** vaporware 105 | """ 106 | 107 | def vars_osx(): 108 | VARS['$RM'] = 'rm -f' 109 | VARS['$VM'] = './vm' 110 | VARS['$TINYPY'] = './tinypy' 111 | VARS['$SYS'] = '-osx' 112 | VARS['$FLAGS'] = '' 113 | 114 | VARS['$WFLAGS'] = '-std=c89 -Wall' 115 | 116 | if 'pygame' in MODULES: 117 | VARS['$FLAGS'] += ' `sdl-config --cflags --libs` ' 118 | 119 | def vars_linux(): 120 | VARS['$RM'] = 'rm -f' 121 | VARS['$VM'] = './vm' 122 | VARS['$TINYPY'] = './tinypy' 123 | VARS['$SYS'] = '-linux' 124 | VARS['$FLAGS'] = '' 125 | 126 | VARS['$WFLAGS'] = '-std=c89 -Wall -Wc++-compat' 127 | #-Wwrite-strings - i think this is included in -Wc++-compat 128 | 129 | if 'pygame' in MODULES: 130 | VARS['$FLAGS'] += ' `sdl-config --cflags --libs` ' 131 | 132 | if SANDBOX: 133 | VARS['$SYS'] += " -sandbox " 134 | VARS['$FLAGS'] += " -DTP_SANDBOX " 135 | 136 | def vars_windows(): 137 | VARS['$RM'] = 'del' 138 | VARS['$VM'] = 'vm' 139 | VARS['$TINYPY'] = 'tinypy' 140 | VARS['$FLAGS'] = '-lmingw32' 141 | VARS['$WFLAGS'] = '-Wwrite-strings -Wall' 142 | VARS['$SYS'] = '-mingw32' 143 | VARS['$CPYTHON'] = "-c mingw32" 144 | 145 | if 'pygame' in MODULES: 146 | VARS['$FLAGS'] += ' -Ic:\\mingw\\include\\SDL -lSDLmain -lSDL ' 147 | 148 | def do_cmd(cmd): 149 | for k,v in VARS.items(): 150 | cmd = cmd.replace(k,v) 151 | if '$' in cmd: 152 | print 'vars_error',cmd 153 | sys.exit(-1) 154 | if VALGRIND and (cmd.startswith("./") or cmd.startswith("../")): 155 | cmd = "valgrind " + cmd 156 | 157 | print cmd 158 | r = os.system(cmd) 159 | if r: 160 | print 'exit_status',r 161 | sys.exit(r) 162 | 163 | def do_chdir(dest): 164 | print 'cd',dest 165 | os.chdir(dest) 166 | 167 | def build_bc(opt=False): 168 | out = [] 169 | for mod in CORE: 170 | out.append("""unsigned char tp_%s[] = {"""%mod) 171 | fname = mod+".tpc" 172 | data = open(fname,'rb').read() 173 | cols = 16 174 | for n in xrange(0,len(data),cols): 175 | out.append(",".join([str(ord(v)) for v in data[n:n+cols]])+',') 176 | out.append("""};""") 177 | out.append("") 178 | f = open('bc.c','wb') 179 | f.write('\n'.join(out)) 180 | f.close() 181 | 182 | def open_tinypy(fname,*args): 183 | return open(os.path.join(TOPDIR,'tinypy',fname),*args) 184 | 185 | def build_blob(): 186 | mods = CORE[:] 187 | do_chdir(os.path.join(TOPDIR,'tinypy')) 188 | for mod in mods: py2bc('python py2bc.py $SRC $DEST',mod) 189 | do_chdir(os.path.join(TOPDIR)) 190 | 191 | out = [] 192 | out.append("/*") 193 | out.extend([v.rstrip() for v in open(os.path.join(TOPDIR,'LICENSE.txt'),'r')]) 194 | out.append("*/") 195 | out.append("") 196 | 197 | out.append("#ifndef TINYPY_H") 198 | out.append("#define TINYPY_H") 199 | out.extend([v.rstrip() for v in open_tinypy('tp.h','r')]) 200 | for fname in ['list.c','dict.c','misc.c','string.c','builtins.c', 201 | 'gc.c','ops.c','vm.c','tp.c', 'sandbox.c']: 202 | for line in open_tinypy(fname,'r'): 203 | line = line.rstrip() 204 | if not len(line): continue 205 | if line[0] == '/': continue 206 | if line[0] == ' ': continue 207 | if line[0] == '\t': continue 208 | if line[-1] != '{': continue 209 | if 'enum' in line: continue 210 | if '=' in line: continue 211 | if '#' in line: continue 212 | line = line.replace('{',';') 213 | 214 | # Do not include prototypes already defined earlier, or gcc will 215 | # warn about doubled prototypes in user code. 216 | if '(' in line: 217 | line2 = line[:line.find('(') + 1] 218 | got_already = False 219 | for already in out: 220 | if already.startswith(line2): 221 | got_already = True 222 | break 223 | if got_already: continue 224 | out.append(line) 225 | out.append("#endif") 226 | out.append('') 227 | dest = os.path.join(TOPDIR,'build','tinypy.h') 228 | print 'writing %s'%dest 229 | f = open(dest,'w') 230 | f.write('\n'.join(out)) 231 | f.close() 232 | 233 | # we leave all the tinypy.h stuff at the top so that 234 | # if someone wants to include tinypy.c they don't have to have 235 | # tinypy.h cluttering up their folder 236 | 237 | if not os.path.exists(os.path.join(TOPDIR, 'tinypy', 'bc.c')): 238 | do_chdir(os.path.join(TOPDIR,'tinypy')) 239 | build_bc() 240 | do_chdir(os.path.join(TOPDIR)) 241 | 242 | for fname in ['list.c','dict.c','misc.c','string.c','builtins.c', 243 | 'gc.c','ops.c','vm.c','bc.c','tp.c','sandbox.c']: 244 | for line in open_tinypy(fname,'r'): 245 | line = line.rstrip() 246 | if line.find('#include "') != -1: continue 247 | out.append(line) 248 | out.append('') 249 | dest = os.path.join(TOPDIR,'build','tinypy.c') 250 | print 'writing %s'%dest 251 | f = open(dest,'w') 252 | f.write('\n'.join(out)) 253 | f.close() 254 | 255 | def py2bc(cmd,mod): 256 | src = '%s.py'%mod 257 | dest = '%s.tpc'%mod 258 | if CLEAN or not os.path.exists(dest) or os.stat(src).st_mtime > os.stat(dest).st_mtime: 259 | cmd = cmd.replace('$SRC',src) 260 | cmd = cmd.replace('$DEST',dest) 261 | do_cmd(cmd) 262 | else: 263 | print '#',dest,'is up to date' 264 | 265 | def build_gcc(): 266 | mods = CORE[:] 267 | do_chdir(os.path.join(TOPDIR,'tinypy')) 268 | nopos = ' -nopos ' 269 | if DEBUG: nopos = '' 270 | if TEST: 271 | mods.append('tests') 272 | mods.append('asm') 273 | mods.append('disasm') 274 | do_cmd("gcc $WFLAGS -g vmmain.c $FLAGS -lm -o vm") 275 | if BOOT: 276 | do_cmd('python tests.py $SYS') 277 | for mod in mods: 278 | py2bc('python py2bc.py $SRC $DEST',mod) 279 | else: 280 | for mod in mods: 281 | py2bc('python py2bc.py $SRC $DEST'+nopos,mod) 282 | if BOOT: 283 | do_cmd('$VM tests.tpc $SYS') 284 | for mod in mods: py2bc('$VM py2bc.tpc $SRC $DEST',mod) 285 | build_bc() 286 | do_cmd("gcc $WFLAGS -g tpmain.c $FLAGS -lm -o tinypy") 287 | #second pass - builts optimized binaries and stuff 288 | if BOOT: 289 | do_cmd('$TINYPY tests.py $SYS') 290 | for mod in mods: py2bc('$TINYPY py2bc.py $SRC $DEST'+nopos,mod) 291 | build_bc(True) 292 | if BOOT: 293 | do_cmd("gcc $WFLAGS -O2 tpmain.c $FLAGS -lm -o tinypy") 294 | do_cmd('$TINYPY tests.py $SYS') 295 | print("# OK - we'll try -O3 for extra speed ...") 296 | do_cmd("gcc $WFLAGS -O3 tpmain.c $FLAGS -lm -o tinypy") 297 | do_cmd('$TINYPY tests.py $SYS') 298 | if DEBUG: 299 | do_cmd("gcc $WFLAGS -g mymain.c $FLAGS -lm -o ../build/tinypy") 300 | else: 301 | do_cmd("gcc $WFLAGS -O3 mymain.c $FLAGS -lm -o ../build/tinypy") 302 | if TEST: 303 | do_cmd(os.path.join('..','build','tinypy')+' tests.py $SYS') 304 | test_mods(os.path.join('..','build','tinypy')+' $TESTS') 305 | 306 | do_chdir('..') 307 | print("# OK") 308 | 309 | def get_libs(): 310 | modules = os.listdir('modules') 311 | for m in modules[:]: 312 | if m not in sys.argv: modules.remove(m) 313 | global MODULES 314 | MODULES = modules 315 | 316 | def build_mymain(): 317 | src = os.path.join(TOPDIR,'tinypy','tpmain.c') 318 | out = open(src,'r').read() 319 | dest = os.path.join(TOPDIR,'tinypy','mymain.c') 320 | 321 | vs = [] 322 | for m in MODULES: 323 | vs.append('#include "../modules/%s/init.c"'%m) 324 | out = out.replace('/* INCLUDE */','\n'.join(vs)) 325 | 326 | vs = [] 327 | for m in MODULES: 328 | vs.append('%s_init(tp);'%m) 329 | out = out.replace('/* INIT */','\n'.join(vs)) 330 | 331 | f = open(dest,'w') 332 | f.write(out) 333 | f.close() 334 | return True 335 | 336 | def test_mods(cmd): 337 | for m in MODULES: 338 | tests = os.path.join('..','modules',m,'tests.py') 339 | if not os.path.exists(tests): continue 340 | cmd = cmd.replace('$TESTS',tests) 341 | do_cmd(cmd) 342 | 343 | def build_vs(): 344 | # How to compile on windows with Visual Studio: 345 | # Call the batch script that sets environement variables for Visual Studio and 346 | # then run this script. 347 | # For VS 2005 the script is: 348 | # "C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat" 349 | # For VS 2008: "C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat" 350 | # Doesn't compile with vc6 (no variadic macros) 351 | # Note: /MD option causes to dynamically link with msvcrt80.dll. This dramatically 352 | # reduces size (for vm.exe 159k => 49k). Downside is that msvcrt80.dll must be 353 | # present on the system (and not all windows machine have it). You can either re-distribute 354 | # msvcrt80.dll or statically link with C runtime by changing /MD to /MT. 355 | mods = CORE[:]; mods.append('tests') 356 | os.chdir(os.path.join(TOPDIR,'tinypy')) 357 | do_cmd('cl vmmain.c /Od /Zi /MD /Fdvm.pdb /Fmvm.map /Fevm.exe') 358 | do_cmd('python tests.py -win') 359 | for mod in mods: py2bc('python py2bc.py $SRC $DEST',mod) 360 | do_cmd('vm.exe tests.tpc -win') 361 | for mod in mods: py2bc('vm.exe py2bc.tpc $SRC $DEST',mod) 362 | build_bc() 363 | do_cmd('cl /Od tpmain.c /Zi /MD /Fdtinypy.pdb /Fmtinypy.map /Fetinypy.exe') 364 | #second pass - builts optimized binaries and stuff 365 | do_cmd('tinypy.exe tests.py -win') 366 | for mod in mods: py2bc('tinypy.exe py2bc.py $SRC $DEST'+nopos,mod) 367 | build_bc(True) 368 | do_cmd('cl /Os vmmain.c /D "NDEBUG" /Gy /GL /Zi /MD /Fdvm.pdb /Fmvm.map /Fevm.exe /link /opt:ref /opt:icf') 369 | do_cmd('cl /Os tpmain.c /D "NDEBUG" /Gy /GL /Zi /MD /Fdtinypy.pdb /Fmtinypy.map /Fetinypy.exe /link /opt:ref,icf /OPT:NOWIN98') 370 | do_cmd("tinypy.exe tests.py -win") 371 | do_cmd("dir *.exe") 372 | 373 | def shrink(fname): 374 | f = open(fname,'r'); lines = f.readlines(); f.close() 375 | out = [] 376 | fixes = [ 377 | 'vm','gc','params','STR', 378 | 'int','float','return','free','delete','init', 379 | 'abs','round','system','pow','div','raise','hash','index','printf','main'] 380 | passing = False 381 | for line in lines: 382 | #quit if we've already converted 383 | if '\t' in line: return ''.join(lines) 384 | 385 | #change " " into "\t" and remove blank lines 386 | if len(line.strip()) == 0: continue 387 | line = line.rstrip() 388 | l1,l2 = len(line),len(line.lstrip()) 389 | line = "\t"*((l1-l2)/4)+line.lstrip() 390 | 391 | #remove comments 392 | if '.c' in fname or '.h' in fname: 393 | #start block comment 394 | if line.strip()[:2] == '/*': 395 | passing = True; 396 | #end block comment 397 | if line.strip()[-2:] == '*/': 398 | passing = False; 399 | continue 400 | #skip lines inside block comments 401 | if passing: 402 | continue 403 | if '.py' in fname: 404 | if line.strip()[:1] == '#': continue 405 | 406 | #remove the "namespace penalty" from tinypy ... 407 | for name in fixes: 408 | line = line.replace('TP_'+name,'t'+name) 409 | line = line.replace('tp_'+name,'t'+name) 410 | line = line.replace('TP_','') 411 | line = line.replace('tp_','') 412 | 413 | out.append(line) 414 | return '\n'.join(out)+'\n' 415 | 416 | def chksize(): 417 | t1,t2 = 0,0 418 | for fname in [ 419 | 'tokenize.py','parse.py','encode.py','py2bc.py', 420 | 'tp.h','list.c','dict.c','misc.c','string.c','builtins.c', 421 | 'gc.c','ops.c','vm.c','tp.c','tpmain.c', 422 | ]: 423 | fname = os.path.join(TOPDIR,'tinypy',fname) 424 | f = open(fname,'r'); t1 += len(f.read()); f.close() 425 | txt = shrink(fname) 426 | t2 += len(txt) 427 | print "#",t1,t2,t2-65536 428 | return t2 429 | 430 | def build_64k(): 431 | for fname in [ 432 | 'tokenize.py','parse.py','encode.py','py2bc.py', 433 | 'tp.h','list.c','dict.c','misc.c','string.c','builtins.c', 434 | 'gc.c','ops.c','vm.c','tp.c','tpmain.c', 435 | ]: 436 | src = os.path.join(TOPDIR,'tinypy',fname) 437 | dest = os.path.join(TOPDIR,'build',fname) 438 | txt = shrink(src) 439 | f = open(dest,'w') 440 | f.write(txt) 441 | f.close() 442 | print '%s saved to %s'%(src,dest) 443 | 444 | def build_cpython(): 445 | try: from distutils.core import setup, Extension 446 | except: print "cannot import distutils" 447 | 448 | do_chdir(os.path.join(TOPDIR,'cpython')) 449 | setup(name = "tinypy", 450 | version = "0.8", 451 | description = "tinypy module for CPython", 452 | url = "http://www.tinypy.org/", 453 | ext_modules = [Extension("tinypy", ["cpython.c"], define_macros = [('CPYTHON_MOD', None)])]) 454 | 455 | def install_cpython(): 456 | try: from distutils.core import setup, Extension 457 | except: print "cannot import distutils" 458 | 459 | do_chdir(os.path.join(TOPDIR,'cpython')) 460 | setup(name = "tinypy", 461 | version = "0.8", 462 | description = "tinypy module for CPython", 463 | url = "http://www.tinypy.org/", 464 | ext_modules = [Extension("tinypy", ["cpython.c"], define_macros = [('CPYTHON_MOD', None)])]) 465 | 466 | if __name__ == '__main__': 467 | main() 468 | -------------------------------------------------------------------------------- /modules/re/testsuite.py: -------------------------------------------------------------------------------- 1 | # Test suite (for verifying correctness) 2 | # 3 | # The test suite is a list of 5- or 3-tuples. The 5 parts of a 4 | # complete tuple are: 5 | # element 0: a string containing the pattern 6 | # 1: the string to match against the pattern 7 | # 2: the expected result (0 - SUCCEED, 1 - FAIL, 2 - SYNTAX_ERROR) 8 | # 3: a string that will be eval()'ed to produce a test string. 9 | # This is an arbitrary Python expression; the available 10 | # variables are "found" (the whole match), and "g1", "g2", ... 11 | # up to "g10" contain the contents of each group, or the 12 | # string 'None' if the group wasn't given a value. 13 | # 4: The expected result of evaluating the expression. 14 | # If the two don't match, an error is reported. 15 | # 16 | # If the regex isn't expected to work, the latter two elements can be omitted. 17 | 18 | # test suite for search 19 | search_regex_tests=[ 20 | ['abc', 'abc', 0, 'found', 'abc'], 21 | ['abc', 'xbc', 1], 22 | ['abc', 'axc', 1], 23 | ['abc', 'abx', 1], 24 | ['abc', 'xabcy', 0, 'found', 'abc'], 25 | ['abc', 'ababc', 0, 'found', 'abc'], 26 | ['ab*c', 'abc', 0, 'found', 'abc'], 27 | ['ab*bc', 'abc', 0, 'found', 'abc'], 28 | ['ab*bc', 'abbc', 0, 'found', 'abbc'], 29 | ['ab*bc', 'abbbbc', 0, 'found', 'abbbbc'], 30 | ['ab+bc', 'abbc', 0, 'found', 'abbc'], 31 | ['ab+bc', 'abc', 1], 32 | ['ab+bc', 'abq', 1], 33 | ['ab+bc', 'abbbbc', 0, 'found', 'abbbbc'], 34 | ['ab?bc', 'abbc', 0, 'found', 'abbc'], 35 | ['ab?bc', 'abc', 0, 'found', 'abc'], 36 | ['ab?bc', 'abbbbc', 1], 37 | ['ab?c', 'abc', 0, 'found', 'abc'], 38 | ['^abc$', 'abc', 0, 'found', 'abc'], 39 | ['^abc$', 'abcc', 1], 40 | ['^abc', 'abcc', 0, 'found', 'abc'], 41 | ['^abc$', 'aabc', 1], 42 | ['abc$', 'aabc', 0, 'found', 'abc'], 43 | ['^', 'abc', 0, 'found+"-"', '-'], 44 | ['$', 'abc', 0, 'found+"-"', '-'], 45 | ['a.c', 'abc', 0, 'found', 'abc'], 46 | ['a.c', 'axc', 0, 'found', 'axc'], 47 | ['a.*c', 'axyzc', 0, 'found', 'axyzc'], 48 | ['a.*c', 'axyzd', 1], 49 | ['a[bc]d', 'abc', 1], 50 | ['a[bc]d', 'abd', 0, 'found', 'abd'], 51 | ['a[b-d]e', 'abd', 1], 52 | ['a[b-d]e', 'ace', 0, 'found', 'ace'], 53 | ['a[b-d]', 'aac', 0, 'found', 'ac'], 54 | ['a[-b]', 'a-', 0, 'found', 'a-'], 55 | ['a[b-]', 'a-', 0, 'found', 'a-'], 56 | ['a[]b', '-', 2], 57 | ['a[', '-', 2], 58 | ['a\\', '-', 2], 59 | ['abc\\)', '-', 2], 60 | ['\\(abc', '-', 2], 61 | ['a]', 'a]', 0, 'found', 'a]'], 62 | ['a[]]b', 'a]b', 0, 'found', 'a]b'], 63 | ['a[^bc]d', 'aed', 0, 'found', 'aed'], 64 | ['a[^bc]d', 'abd', 1], 65 | ['a[^-b]c', 'adc', 0, 'found', 'adc'], 66 | ['a[^-b]c', 'a-c', 1], 67 | ['a[^]b]c', 'a]c', 1], 68 | ['a[^]b]c', 'adc', 0, 'found', 'adc'], 69 | ['\\ba\\b', 'a-', 0, '"-"', '-'], 70 | ['\\ba\\b', '-a', 0, '"-"', '-'], 71 | ['\\ba\\b', '-a-', 0, '"-"', '-'], 72 | ['\\by\\b', 'xy', 1], 73 | ['\\by\\b', 'yz', 1], 74 | ['\\by\\b', 'xyz', 1], 75 | ['ab\\|cd', 'abc', 0, 'found', 'ab'], 76 | ['ab\\|cd', 'abcd', 0, 'found', 'ab'], 77 | ['\\(\\)ef', 'def', 0, 'found+"-"+g1', 'ef-'], 78 | ['$b', 'b', 1], 79 | ['a(b', 'a(b', 0, 'found+"-"+g1', 'a(b-None'], 80 | ['a(*b', 'ab', 0, 'found', 'ab'], 81 | ['a(*b', 'a((b', 0, 'found', 'a((b'], 82 | ['a\\\\b', 'a\\b', 0, 'found', 'a\\b'], 83 | ['\\(\\(a\\)\\)', 'abc', 0, 'found+"-"+g1+"-"+g2', 'a-a-a'], 84 | ['\\(a\\)b\\(c\\)', 'abc', 0, 'found+"-"+g1+"-"+g2', 'abc-a-c'], 85 | ['a+b+c', 'aabbabc', 0, 'found', 'abc'], 86 | ['\\(a+\\|b\\)*', 'ab', 0, 'found+"-"+g1', 'ab-b'], 87 | ['\\(a+\\|b\\)+', 'ab', 0, 'found+"-"+g1', 'ab-b'], 88 | ['\\(a+\\|b\\)?', 'ab', 0, 'found+"-"+g1', 'a-a'], 89 | ['\\)\\(', '-', 2], 90 | ['[^ab]*', 'cde', 0, 'found', 'cde'], 91 | ['abc', '', 1], 92 | ['a*', '', 0, 'found', ''], 93 | ['a\\|b\\|c\\|d\\|e', 'e', 0, 'found', 'e'], 94 | ['\\(a\\|b\\|c\\|d\\|e\\)f', 'ef', 0, 'found+"-"+g1', 'ef-e'], 95 | ['abcd*efg', 'abcdefg', 0, 'found', 'abcdefg'], 96 | ['ab*', 'xabyabbbz', 0, 'found', 'ab'], 97 | ['ab*', 'xayabbbz', 0, 'found', 'a'], 98 | ['\\(ab\\|cd\\)e', 'abcde', 0, 'found+"-"+g1', 'cde-cd'], 99 | ['[abhgefdc]ij', 'hij', 0, 'found', 'hij'], 100 | ['^\\(ab\\|cd\\)e', 'abcde', 1, 'xg1y', 'xy'], 101 | ['\\(abc\\|\\)ef', 'abcdef', 0, 'found+"-"+g1', 'ef-'], 102 | ['\\(a\\|b\\)c*d', 'abcd', 0, 'found+"-"+g1', 'bcd-b'], 103 | ['\\(ab\\|ab*\\)bc', 'abc', 0, 'found+"-"+g1', 'abc-a'], 104 | ['a\\([bc]*\\)c*', 'abc', 0, 'found+"-"+g1', 'abc-bc'], 105 | ['a\\([bc]*\\)\\(c*d\\)', 'abcd', 0, 'found+"-"+g1+"-"+g2', 'abcd-bc-d'], 106 | ['a\\([bc]+\\)\\(c*d\\)', 'abcd', 0, 'found+"-"+g1+"-"+g2', 'abcd-bc-d'], 107 | ['a\\([bc]*\\)\\(c+d\\)', 'abcd', 0, 'found+"-"+g1+"-"+g2', 'abcd-b-cd'], 108 | ['a[bcd]*dcdcde', 'adcdcde', 0, 'found', 'adcdcde'], 109 | ['a[bcd]+dcdcde', 'adcdcde', 1], 110 | ['\\(ab\\|a\\)b*c', 'abc', 0, 'found+"-"+g1', 'abc-ab'], 111 | ['\\(\\(a\\)\\(b\\)c\\)\\(d\\)', 'abcd', 0, 'g1+"-"+g2+"-"+g3+"-"+g4', 'abc-a-b-d'], 112 | ['[a-zA-Z_][a-zA-Z0-9_]*', 'alpha', 0, 'found', 'alpha'], 113 | ['^a\\(bc+\\|b[eh]\\)g\\|.h$', 'abh', 0, 'found+"-"+g1', 'bh-None'], 114 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'effgz', 0, 'found+"-"+g1+"-"+g2', 'effgz-effgz-None'], 115 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'ij', 0, 'found+"-"+g1+"-"+g2', 'ij-ij-j'], 116 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'effg', 1], 117 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'bcdd', 1], 118 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'reffgz', 0, 'found+"-"+g1+"-"+g2', 'effgz-effgz-None'], 119 | ['\\(\\(\\(\\(\\(\\(\\(\\(\\(a\\)\\)\\)\\)\\)\\)\\)\\)\\)', 'a', 0, 'found', 'a'], 120 | ['multiple words of text', 'uh-uh', 1], 121 | ['multiple words', 'multiple words, yeah', 0, 'found', 'multiple words'], 122 | ['\\(.*\\)c\\(.*\\)', 'abcde', 0, 'found+"-"+g1+"-"+g2', 'abcde-ab-de'], 123 | ['(\\(.*\\), \\(.*\\))', '(a, b)', 0, 'g2+"-"+g1', 'b-a'], 124 | ['[k]', 'ab', 1], 125 | ['a[-]?c', 'ac', 0, 'found', 'ac'], 126 | ['\\(abc\\)\\1', 'abcabc', 0, 'g1', 'abc'], 127 | ['\\([a-c]*\\)\\1', 'abcabc', 0, 'g1', 'abc'], 128 | ['^\\(.+\\)?B', 'AB', 0, 'g1', 'A'], 129 | ['\\(a+\\).\\1$', 'aaaaa', 0, 'found+"-"+g1', 'aaaaa-aa'], 130 | ['^\\(a+\\).\\1$', 'aaaa', 1], 131 | ['\\(abc\\)\\1', 'abcabc', 0, 'found+"-"+g1', 'abcabc-abc'], 132 | ['\\([a-c]+\\)\\1', 'abcabc', 0, 'found+"-"+g1', 'abcabc-abc'], 133 | ['\\(a\\)\\1', 'aa', 0, 'found+"-"+g1', 'aa-a'], 134 | ['\\(a+\\)\\1', 'aa', 0, 'found+"-"+g1', 'aa-a'], 135 | ['\\(a+\\)+\\1', 'aa', 0, 'found+"-"+g1', 'aa-a'], 136 | ['\\(a\\).+\\1', 'aba', 0, 'found+"-"+g1', 'aba-a'], 137 | ['\\(a\\)ba*\\1', 'aba', 0, 'found+"-"+g1', 'aba-a'], 138 | ['\\(aa\\|a\\)a\\1$', 'aaa', 0, 'found+"-"+g1', 'aaa-a'], 139 | ['\\(a\\|aa\\)a\\1$', 'aaa', 0, 'found+"-"+g1', 'aaa-a'], 140 | ['\\(a+\\)a\\1$', 'aaa', 0, 'found+"-"+g1', 'aaa-a'], 141 | ['\\([abc]*\\)\\1', 'abcabc', 0, 'found+"-"+g1', 'abcabc-abc'], 142 | ['\\(a\\)\\(b\\)c\\|ab', 'ab', 0, 'found+"-"+g1+"-"+g2', 'ab-None-None'], 143 | ['\\(a\\)+x', 'aaax', 0, 'found+"-"+g1', 'aaax-a'], 144 | ['\\([ac]\\)+x', 'aacx', 0, 'found+"-"+g1', 'aacx-c'], 145 | ['\\([^/]*/\\)*sub1/', 'd:msgs/tdir/sub1/trial/away.cpp', 0, 'found+"-"+g1', 'd:msgs/tdir/sub1/-tdir/'], 146 | ['\\([^.]*\\)\\.\\([^:]*\\):[T ]+\\(.*\\)', 'track1.title:TBlah blah blah', 0, 'found+"-"+g1+"-"+g2+"-"+g3', 'track1.title:TBlah blah blah-track1-title-Blah blah blah'], 147 | ['\\([^N]*N\\)+', 'abNNxyzN', 0, 'found+"-"+g1', 'abNNxyzN-xyzN'], 148 | ['\\([^N]*N\\)+', 'abNNxyz', 0, 'found+"-"+g1', 'abNN-N'], 149 | ['\\([abc]*\\)x', 'abcx', 0, 'found+"-"+g1', 'abcx-abc'], 150 | ['\\([abc]*\\)x', 'abc', 1], 151 | ['\\([xyz]*\\)x', 'abcx', 0, 'found+"-"+g1', 'x-'], 152 | ['\\(a\\)+b\\|aac', 'aac', 0, 'found+"-"+g1', 'aac-None'], 153 | ['\\', 'ab', 1], 157 | ['a\\>', 'a!', 0, 'found', 'a'], 158 | ['a\\>', 'a', 0, 'found', 'a'], 159 | ] 160 | 161 | 162 | # test suite for match 163 | match_regex_tests=[ 164 | ['abc', 'abc', 0, 'found', 'abc'], 165 | ['abc', 'xbc', 1], 166 | ['abc', 'axc', 1], 167 | ['abc', 'abx', 1], 168 | ['abc', 'xabcy', 1], 169 | ['abc', 'ababc', 1], 170 | ['ab*c', 'abc', 0, 'found', 'abc'], 171 | ['ab*bc', 'abc', 0, 'found', 'abc'], 172 | ['ab*bc', 'abbc', 0, 'found', 'abbc'], 173 | ['ab*bc', 'abbbbc', 0, 'found', 'abbbbc'], 174 | ['ab+bc', 'abbc', 0, 'found', 'abbc'], 175 | ['ab+bc', 'abc', 1], 176 | ['ab+bc', 'abq', 1], 177 | ['ab+bc', 'abbbbc', 0, 'found', 'abbbbc'], 178 | ['ab?bc', 'abbc', 0, 'found', 'abbc'], 179 | ['ab?bc', 'abc', 0, 'found', 'abc'], 180 | ['ab?bc', 'abbbbc', 1], 181 | ['ab?c', 'abc', 0, 'found', 'abc'], 182 | ['^abc$', 'abc', 0, 'found', 'abc'], 183 | ['^abc$', 'abcc', 1], 184 | ['^abc', 'abcc', 0, 'found', 'abc'], 185 | ['^abc$', 'aabc', 1], 186 | ['abc$', 'aabc', 1], 187 | ['^', 'abc', 0, 'found+"-"', '-'], 188 | ['$', 'abc', 1], 189 | ['a.c', 'abc', 0, 'found', 'abc'], 190 | ['a.c', 'axc', 0, 'found', 'axc'], 191 | ['a.*c', 'axyzc', 0, 'found', 'axyzc'], 192 | ['a.*c', 'axyzd', 1], 193 | ['a[bc]d', 'abc', 1], 194 | ['a[bc]d', 'abd', 0, 'found', 'abd'], 195 | ['a[b-d]e', 'abd', 1], 196 | ['a[b-d]e', 'ace', 0, 'found', 'ace'], 197 | ['a[b-d]', 'aac', 1], 198 | ['a[-b]', 'a-', 0, 'found', 'a-'], 199 | ['a[b-]', 'a-', 0, 'found', 'a-'], 200 | ['a[]b', '-', 2], 201 | ['a[', '-', 2], 202 | ['a\\', '-', 2], 203 | ['abc\\)', '-', 2], 204 | ['\\(abc', '-', 2], 205 | ['a]', 'a]', 0, 'found', 'a]'], 206 | ['a[]]b', 'a]b', 0, 'found', 'a]b'], 207 | ['a[^bc]d', 'aed', 0, 'found', 'aed'], 208 | ['a[^bc]d', 'abd', 1], 209 | ['a[^-b]c', 'adc', 0, 'found', 'adc'], 210 | ['a[^-b]c', 'a-c', 1], 211 | ['a[^]b]c', 'a]c', 1], 212 | ['a[^]b]c', 'adc', 0, 'found', 'adc'], 213 | ['\\ba\\b', 'a-', 0, '"-"', '-'], 214 | ['\\ba\\b', '-a', 1], 215 | ['\\ba\\b', '-a-', 1], 216 | ['\\by\\b', 'xy', 1], 217 | ['\\by\\b', 'yz', 1], 218 | ['\\by\\b', 'xyz', 1], 219 | ['ab\\|cd', 'abc', 0, 'found', 'ab'], 220 | ['ab\\|cd', 'abcd', 0, 'found', 'ab'], 221 | ['\\(\\)ef', 'def', 1], 222 | ['$b', 'b', 1], 223 | ['a(b', 'a(b', 0, 'found+"-"+g1', 'a(b-None'], 224 | ['a(*b', 'ab', 0, 'found', 'ab'], 225 | ['a(*b', 'a((b', 0, 'found', 'a((b'], 226 | ['a\\\\b', 'a\\b', 0, 'found', 'a\\b'], 227 | ['\\(\\(a\\)\\)', 'abc', 0, 'found+"-"+g1+"-"+g2', 'a-a-a'], 228 | ['\\(a\\)b\\(c\\)', 'abc', 0, 'found+"-"+g1+"-"+g2', 'abc-a-c'], 229 | ['a+b+c', 'aabbabc', 1], 230 | ['\\(a+\\|b\\)*', 'ab', 0, 'found+"-"+g1', 'ab-b'], 231 | ['\\(a+\\|b\\)+', 'ab', 0, 'found+"-"+g1', 'ab-b'], 232 | ['\\(a+\\|b\\)?', 'ab', 0, 'found+"-"+g1', 'a-a'], 233 | ['\\)\\(', '-', 2], 234 | ['[^ab]*', 'cde', 0, 'found', 'cde'], 235 | ['abc', '', 1], 236 | ['a*', '', 0, 'found', ''], 237 | ['a\\|b\\|c\\|d\\|e', 'e', 0, 'found', 'e'], 238 | ['\\(a\\|b\\|c\\|d\\|e\\)f', 'ef', 0, 'found+"-"+g1', 'ef-e'], 239 | ['abcd*efg', 'abcdefg', 0, 'found', 'abcdefg'], 240 | ['ab*', 'xabyabbbz', 1], 241 | ['ab*', 'xayabbbz', 1], 242 | ['\\(ab\\|cd\\)e', 'abcde', 1], 243 | ['[abhgefdc]ij', 'hij', 0, 'found', 'hij'], 244 | ['^\\(ab\\|cd\\)e', 'abcde', 1, 'xg1y', 'xy'], 245 | ['\\(abc\\|\\)ef', 'abcdef', 1], 246 | ['\\(a\\|b\\)c*d', 'abcd', 1], 247 | ['\\(ab\\|ab*\\)bc', 'abc', 0, 'found+"-"+g1', 'abc-a'], 248 | ['a\\([bc]*\\)c*', 'abc', 0, 'found+"-"+g1', 'abc-bc'], 249 | ['a\\([bc]*\\)\\(c*d\\)', 'abcd', 0, 'found+"-"+g1+"-"+g2', 'abcd-bc-d'], 250 | ['a\\([bc]+\\)\\(c*d\\)', 'abcd', 0, 'found+"-"+g1+"-"+g2', 'abcd-bc-d'], 251 | ['a\\([bc]*\\)\\(c+d\\)', 'abcd', 0, 'found+"-"+g1+"-"+g2', 'abcd-b-cd'], 252 | ['a[bcd]*dcdcde', 'adcdcde', 0, 'found', 'adcdcde'], 253 | ['a[bcd]+dcdcde', 'adcdcde', 1], 254 | ['\\(ab\\|a\\)b*c', 'abc', 0, 'found+"-"+g1', 'abc-ab'], 255 | ['\\(\\(a\\)\\(b\\)c\\)\\(d\\)', 'abcd', 0, 'g1+"-"+g2+"-"+g3+"-"+g4', 'abc-a-b-d'], 256 | ['[a-zA-Z_][a-zA-Z0-9_]*', 'alpha', 0, 'found', 'alpha'], 257 | ['^a\\(bc+\\|b[eh]\\)g\\|.h$', 'abh', 1], 258 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'effgz', 0, 'found+"-"+g1+"-"+g2', 'effgz-effgz-None'], 259 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'ij', 0, 'found+"-"+g1+"-"+g2', 'ij-ij-j'], 260 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'effg', 1], 261 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'bcdd', 1], 262 | ['\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'reffgz', 1], 263 | ['\\(\\(\\(\\(\\(\\(\\(\\(\\(a\\)\\)\\)\\)\\)\\)\\)\\)\\)', 'a', 0, 'found', 'a'], 264 | ['multiple words of text', 'uh-uh', 1], 265 | ['multiple words', 'multiple words, yeah', 0, 'found', 'multiple words'], 266 | ['\\(.*\\)c\\(.*\\)', 'abcde', 0, 'found+"-"+g1+"-"+g2', 'abcde-ab-de'], 267 | ['(\\(.*\\), \\(.*\\))', '(a, b)', 0, 'g2+"-"+g1', 'b-a'], 268 | ['[k]', 'ab', 1], 269 | ['a[-]?c', 'ac', 0, 'found', 'ac'], 270 | ['\\(abc\\)\\1', 'abcabc', 0, 'g1', 'abc'], 271 | ['\\([a-c]*\\)\\1', 'abcabc', 0, 'g1', 'abc'], 272 | ['^\\(.+\\)?B', 'AB', 0, 'g1', 'A'], 273 | ['\\(a+\\).\\1$', 'aaaaa', 0, 'found+"-"+g1', 'aaaaa-aa'], 274 | ['^\\(a+\\).\\1$', 'aaaa', 1], 275 | ['\\(abc\\)\\1', 'abcabc', 0, 'found+"-"+g1', 'abcabc-abc'], 276 | ['\\([a-c]+\\)\\1', 'abcabc', 0, 'found+"-"+g1', 'abcabc-abc'], 277 | ['\\(a\\)\\1', 'aa', 0, 'found+"-"+g1', 'aa-a'], 278 | ['\\(a+\\)\\1', 'aa', 0, 'found+"-"+g1', 'aa-a'], 279 | ['\\(a+\\)+\\1', 'aa', 0, 'found+"-"+g1', 'aa-a'], 280 | ['\\(a\\).+\\1', 'aba', 0, 'found+"-"+g1', 'aba-a'], 281 | ['\\(a\\)ba*\\1', 'aba', 0, 'found+"-"+g1', 'aba-a'], 282 | ['\\(aa\\|a\\)a\\1$', 'aaa', 0, 'found+"-"+g1', 'aaa-a'], 283 | ['\\(a\\|aa\\)a\\1$', 'aaa', 0, 'found+"-"+g1', 'aaa-a'], 284 | ['\\(a+\\)a\\1$', 'aaa', 0, 'found+"-"+g1', 'aaa-a'], 285 | ['\\([abc]*\\)\\1', 'abcabc', 0, 'found+"-"+g1', 'abcabc-abc'], 286 | ['\\(a\\)\\(b\\)c\\|ab', 'ab', 0, 'found+"-"+g1+"-"+g2', 'ab-None-None'], 287 | ['\\(a\\)+x', 'aaax', 0, 'found+"-"+g1', 'aaax-a'], 288 | ['\\([ac]\\)+x', 'aacx', 0, 'found+"-"+g1', 'aacx-c'], 289 | ['\\([^/]*/\\)*sub1/', 'd:msgs/tdir/sub1/trial/away.cpp', 0, 'found+"-"+g1', 'd:msgs/tdir/sub1/-tdir/'], 290 | ['\\([^.]*\\)\\.\\([^:]*\\):[T ]+\\(.*\\)', 'track1.title:TBlah blah blah', 0, 'found+"-"+g1+"-"+g2+"-"+g3', 'track1.title:TBlah blah blah-track1-title-Blah blah blah'], 291 | ['\\([^N]*N\\)+', 'abNNxyzN', 0, 'found+"-"+g1', 'abNNxyzN-xyzN'], 292 | ['\\([^N]*N\\)+', 'abNNxyz', 0, 'found+"-"+g1', 'abNN-N'], 293 | ['\\([abc]*\\)x', 'abcx', 0, 'found+"-"+g1', 'abcx-abc'], 294 | ['\\([abc]*\\)x', 'abc', 1], 295 | ['\\([xyz]*\\)x', 'abcx', 1], 296 | ['\\(a\\)+b\\|aac', 'aac', 0, 'found+"-"+g1', 'aac-None'], 297 | ['\\', 'ab', 1], 301 | ['a\\>', 'a!', 0, 'found', 'a'], 302 | ['a\\>', 'a', 0, 'found', 'a'], 303 | ] 304 | 305 | # test suite for split() 306 | # element 0: pattern 307 | # 1: string to split 308 | # 3: compile result 309 | # 4: maxsplit 310 | # 5: splitted fields list 311 | split_regex_tests = [ 312 | ["[ |,]", "with you, nothing, and me", 0, 0, ["with","you","nothing","and","me"]], 313 | ["[ |,]", "with you, nothing, and me", 0, 1, ["with", "you, nothing, and me"]], 314 | ["\\ ", "send email to apply", 0, 0, ["send", "email", "to", "apply"]], 315 | ["\\ ", "send email to apply", 0, 2, ["send", "email", "to apply"]], 316 | ["[+ | -]", "+86-028-83201034", 0, 0, ["86", "028", "83201034"]], 317 | ["[+ | -]", "+86-028-83201034", 0, 1, ["86", "028-83201034"]], 318 | ["[*|#]", "slide show", 0, 0, ["slide show"]], 319 | ["(", "whats ever", 0, 1, ["whats ever"]], 320 | ["@#!~$%^&*()<>\n", "who knows", 0, 1, ["who knows"]], 321 | ] 322 | 323 | # test suite for findall() 324 | # element 0: pattern 325 | # 1: string to match 326 | # 3: compile result 327 | # 4: starting position 328 | # 5: grouped fields list 329 | 330 | # reobj.find() 331 | findall_regex_tests = [ 332 | ["\\ ", "send email to apply", 0, 0, [" ", " ", " "]], 333 | ["\\ ", "send email to apply", 0, 5, [" ", " "]], 334 | ["[+ | -]", "+86-028-83201034", 0, 0, ["+", "-", "-"]], 335 | ["[+ | -]", "+86-028-83201034", 0, 1, ["-", "-"]], 336 | ["sl.*e\\|#", "slide show at Room #3", 0, 0, ["slide", "#"]], 337 | ["w.+s\\|e.*r", "whats ever", 0, 0, ["whats", "ever"]], 338 | ["Euler\\|Gauss", "Both Euler and Gauss are great mathematicians", 0, 0, ["Euler", "Gauss"]], 339 | ] 340 | 341 | # module re.findall() 342 | mod_findall_regex_tests = [ 343 | ["\\ ", "send email to apply", 0, 0, [" ", " ", " "]], 344 | ["\\ ", "send email to apply", 0, 0, [" ", " ", " "]], 345 | ["[+ | -]", "+86-028-83201034", 0, 0, ["+", "-", "-"]], 346 | ["[+ | -]", "+86-028-83201034", 0, 0, ["+", "-", "-"]], 347 | ["sl.*e\\|#", "slide show at Room #3", 0, 0, ["slide", "#"]], 348 | ["w.+s\\|e.*r", "whats ever", 0, 0, ["whats", "ever"]], 349 | ["Euler\\|Gauss", "Both Euler and Gauss are great mathematicians", 0, 0, ["Euler", "Gauss"]], 350 | ] 351 | 352 | # test for match object's groups() method 353 | # element 0: pattern 354 | # 1: string 355 | # 2: compile result 356 | # 3: matched fields, for groups() 357 | # 4: group index, valid when > 0, for start(), end(), and span() 358 | # 5: pattern's starting index in string, for start() and span() 359 | # 6: pattern's ending index in string, for end() and span 360 | matobj_groups_regex_tests = [ 361 | ["\\(abc\\(.*xyz\\)\\(.*31415926\\)\\)", "where is abc and flurry xyz, which is pi 31415926, derived from ms", 0, ["abc and flurry xyz, which is pi 31415926"," and flurry xyz",", which is pi 31415926"], 2, 12, 27], 362 | 363 | ["[a\\|b]\\(.+\\)shoe\\([t]+\\)d", "bbbshoetttdxrznmlkjp", 0, ["bb", "ttt"], 1, 1, 3], 364 | 365 | ["abcdef", "xyah2oewoyqe030uabcdefwhalsdewnkhgiohyczb", 0, [], -1, 0, 0], 366 | ] 367 | 368 | -------------------------------------------------------------------------------- /tinypy/encode.py: -------------------------------------------------------------------------------- 1 | import tokenize, sys 2 | from tokenize import Token 3 | if not "tinypy" in sys.version: 4 | from boot import * 5 | 6 | EOF,ADD,SUB,MUL,DIV,POW,BITAND,BITOR,CMP,GET,SET,NUMBER,STRING,GGET,GSET,MOVE,DEF,PASS,JUMP,CALL,RETURN,IF,DEBUG,EQ,LE,LT,DICT,LIST,NONE,LEN,POS,PARAMS,IGET,FILE,NAME,NE,HAS,RAISE,SETJMP,MOD,LSH,RSH,ITER,DEL,REGS,BITXOR,IFN,NOT,BITNOT = 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48 7 | 8 | class DState: 9 | def __init__(self,code,fname): 10 | self.code, self.fname = code,fname 11 | self.lines = self.code.split('\n') 12 | 13 | self.stack,self.out,self._scopei,self.tstack,self._tagi,self.data = [],[('tag','EOF')],0,[],0,{} 14 | self.error = False 15 | def begin(self,gbl=False): 16 | if len(self.stack): self.stack.append((self.vars,self.r2n,self.n2r,self._tmpi,self.mreg,self.snum,self._globals,self.lineno,self.globals,self.rglobals,self.cregs,self.tmpc)) 17 | else: self.stack.append(None) 18 | self.vars,self.r2n,self.n2r,self._tmpi,self.mreg,self.snum,self._globals,self.lineno,self.globals,self.rglobals,self.cregs,self.tmpc = [],{},{},0,0,str(self._scopei),gbl,-1,[],[],['regs'],0 19 | self._scopei += 1 20 | insert(self.cregs) 21 | def end(self): 22 | self.cregs.append(self.mreg) 23 | code(EOF) 24 | 25 | # This next line forces the encoder to 26 | # throw an exception if any tmp regs 27 | # were leaked within the frame 28 | # assert(self.tmpc == 0) #REG 29 | if self.tmpc != 0: 30 | print("Warning:\nencode.py contains a register leak\n") 31 | 32 | if len(self.stack) > 1: 33 | self.vars,self.r2n,self.n2r,self._tmpi,self.mreg,self.snum,self._globals,self.lineno,self.globals,self.rglobals,self.cregs,self.tmpc = self.stack.pop() 34 | else: self.stack.pop() 35 | 36 | 37 | def insert(v): D.out.append(v) 38 | def write(v): 39 | if istype(v,'list'): 40 | insert(v) 41 | return 42 | for n in range(0,len(v),4): 43 | insert(('data',v[n:n+4])) 44 | def setpos(v): 45 | if '-nopos' in ARGV: return 46 | line,x = v 47 | if line == D.lineno: return 48 | text = D.lines[line-1] 49 | D.lineno = line 50 | val = text + "\0"*(4-len(text)%4) 51 | code_16(POS,len(val)/4,line) 52 | write(val) 53 | def code(i,a=0,b=0,c=0): 54 | if not istype(i,'number'): raise 55 | if not istype(a,'number'): raise 56 | if not istype(b,'number'): raise 57 | if not istype(c,'number'): raise 58 | write(('code',i,a,b,c)) 59 | def code_16(i,a,b): 60 | if b < 0: b += 0x8000 61 | code(i,a,(b&0xff00)>>8,(b&0xff)>>0) 62 | def get_code16(i,a,b): 63 | return ('code',i,a,(b&0xff00)>>8,(b&0xff)>>0) 64 | 65 | def _do_string(v,r=None): 66 | r = get_tmp(r) 67 | val = v + "\0"*(4-len(v)%4) 68 | code_16(STRING,r,len(v)) 69 | write(val) 70 | return r 71 | def do_string(t,r=None): 72 | return _do_string(t.val,r) 73 | 74 | def _do_number(v,r=None): 75 | r = get_tmp(r) 76 | code(NUMBER,r,0,0) 77 | write(fpack(number(v))) 78 | return r 79 | def do_number(t,r=None): 80 | return _do_number(t.val,r) 81 | 82 | def get_tag(): 83 | k = str(D._tagi) 84 | D._tagi += 1 85 | return k 86 | def stack_tag(): 87 | k = get_tag() 88 | D.tstack.append(k) 89 | return k 90 | def pop_tag(): 91 | D.tstack.pop() 92 | 93 | def tag(*t): 94 | t = D.snum+':'+':'.join([str(v) for v in t]) 95 | insert(('tag',t)) 96 | def jump(*t): 97 | t = D.snum+':'+':'.join([str(v) for v in t]) 98 | insert(('jump',t)) 99 | def setjmp(*t): 100 | t = D.snum+':'+':'.join([str(v) for v in t]) 101 | insert(('setjmp',t)) 102 | def fnc(*t): 103 | t = D.snum+':'+':'.join([str(v) for v in t]) 104 | r = get_reg(t) 105 | insert(('fnc',r,t)) 106 | return r 107 | 108 | def map_tags(): 109 | tags = {} 110 | out = [] 111 | n = 0 112 | for item in D.out: 113 | if item[0] == 'tag': 114 | tags[item[1]] = n 115 | continue 116 | if item[0] == 'regs': 117 | out.append(get_code16(REGS,item[1],0)) 118 | n += 1 119 | continue 120 | out.append(item) 121 | n += 1 122 | for n in range(0,len(out)): 123 | item = out[n] 124 | if item[0] == 'jump': 125 | out[n] = get_code16(JUMP,0,tags[item[1]]-n) 126 | elif item[0] == 'setjmp': 127 | out[n] = get_code16(SETJMP,0,tags[item[1]]-n) 128 | elif item[0] == 'fnc': 129 | out[n] = get_code16(DEF,item[1],tags[item[2]]-n) 130 | for n in range(0,len(out)): 131 | item = out[n] 132 | if item[0] == 'data': 133 | out[n] = item[1] 134 | elif item[0] == 'code': 135 | i,a,b,c = item[1:] 136 | out[n] = chr(i)+chr(a)+chr(b)+chr(c) 137 | else: 138 | raise str(('huh?',item)) 139 | if len(out[n]) != 4: 140 | raise ('code '+str(n)+' is wrong length '+str(len(out[n]))) 141 | D.out = out 142 | 143 | def get_tmp(r=None): 144 | if r != None: return r 145 | return get_tmps(1)[0] 146 | def get_tmps(t): 147 | rs = alloc(t) 148 | regs = range(rs,rs+t) 149 | for r in regs: 150 | set_reg(r,"$"+str(D._tmpi)) 151 | D._tmpi += 1 152 | D.tmpc += t #REG 153 | return regs 154 | def alloc(t): 155 | s = ''.join(["01"[r in D.r2n] for r in range(0,min(256,D.mreg+t))]) 156 | return s.index('0'*t) 157 | def is_tmp(r): 158 | if r is None: return False 159 | return (D.r2n[r][0] == '$') 160 | def un_tmp(r): 161 | n = D.r2n[r] 162 | free_reg(r) 163 | set_reg(r,'*'+n) 164 | def free_tmp(r): 165 | if is_tmp(r): free_reg(r) 166 | return r 167 | def free_tmps(r): 168 | for k in r: free_tmp(k) 169 | def get_reg(n): 170 | if n not in D.n2r: 171 | set_reg(alloc(1),n) 172 | return D.n2r[n] 173 | #def get_clean_reg(n): 174 | #if n in D.n2r: raise 175 | #set_reg(D.mreg,n) 176 | #return D.n2r[n] 177 | def set_reg(r,n): 178 | D.n2r[n] = r; D.r2n[r] = n 179 | D.mreg = max(D.mreg,r+1) 180 | def free_reg(r): 181 | if is_tmp(r): D.tmpc -= 1 182 | n = D.r2n[r]; del D.r2n[r]; del D.n2r[n] 183 | 184 | def imanage(orig,fnc): 185 | items = orig.items 186 | orig.val = orig.val[:-1] 187 | t = Token(orig.pos,'symbol','=',[items[0],orig]) 188 | return fnc(t) 189 | 190 | def unary(i,tb,r=None): 191 | r = get_tmp(r) 192 | b = do(tb) 193 | code(i,r,b) 194 | if r != b: free_tmp(b) 195 | return r 196 | def infix(i,tb,tc,r=None): 197 | r = get_tmp(r) 198 | b,c = do(tb,r),do(tc) 199 | code(i,r,b,c) 200 | if r != b: free_tmp(b) 201 | free_tmp(c) 202 | return r 203 | def logic_infix(op, tb, tc, _r=None): 204 | t = get_tag() 205 | r = do(tb, _r) 206 | if _r != r: free_tmp(_r) #REG 207 | if op == 'and': code(IF, r) 208 | elif op == 'or': code(IFN, r) 209 | jump(t, 'end') 210 | _r = r 211 | r = do(tc, _r) 212 | if _r != r: free_tmp(_r) #REG 213 | tag(t, 'end') 214 | return r 215 | 216 | def _do_none(r=None): 217 | r = get_tmp(r) 218 | code(NONE,r) 219 | return r 220 | 221 | def do_symbol(t,r=None): 222 | sets = ['='] 223 | isets = ['+=','-=','*=','/=', '|=', '&=', '^='] 224 | cmps = ['<','>','<=','>=','==','!='] 225 | metas = { 226 | '+':ADD,'*':MUL,'/':DIV,'**':POW, 227 | '-':SUB, 228 | '%':MOD,'>>':RSH,'<<':LSH, 229 | '&':BITAND,'|':BITOR,'^':BITXOR, 230 | } 231 | if t.val == 'None': return _do_none(r) 232 | if t.val == 'True': 233 | return _do_number('1',r) 234 | if t.val == 'False': 235 | return _do_number('0',r) 236 | items = t.items 237 | 238 | if t.val in ['and','or']: 239 | return logic_infix(t.val, items[0], items[1], r) 240 | if t.val in isets: 241 | return imanage(t,do_symbol) 242 | if t.val == 'is': 243 | return infix(EQ,items[0],items[1],r) 244 | if t.val == 'isnot': 245 | return infix(CMP,items[0],items[1],r) 246 | if t.val == 'not': 247 | return unary(NOT, items[0], r) 248 | if t.val == 'in': 249 | return infix(HAS,items[1],items[0],r) 250 | if t.val == 'notin': 251 | r = infix(HAS,items[1],items[0],r) 252 | zero = _do_number('0') 253 | code(EQ,r,r,free_tmp(zero)) 254 | return r 255 | if t.val in sets: 256 | return do_set_ctx(items[0],items[1]); 257 | elif t.val in cmps: 258 | b,c = items[0],items[1] 259 | v = t.val 260 | if v[0] in ('>','>='): 261 | b,c,v = c,b,'<'+v[1:] 262 | cd = EQ 263 | if v == '<': cd = LT 264 | if v == '<=': cd = LE 265 | if v == '!=': cd = NE 266 | return infix(cd,b,c,r) 267 | else: 268 | return infix(metas[t.val],items[0],items[1],r) 269 | 270 | def do_set_ctx(k,v): 271 | if k.type == 'name': 272 | if (D._globals and k.val not in D.vars) or (k.val in D.globals): 273 | c = do_string(k) 274 | b = do(v) 275 | code(GSET,c,b) 276 | free_tmp(c) 277 | free_tmp(b) 278 | return 279 | a = do_local(k) 280 | b = do(v) 281 | code(MOVE,a,b) 282 | free_tmp(b) 283 | return a 284 | elif k.type in ('tuple','list'): 285 | if v.type in ('tuple','list'): 286 | n,tmps = 0,[] 287 | for kk in k.items: 288 | vv = v.items[n] 289 | tmp = get_tmp(); tmps.append(tmp) 290 | r = do(vv) 291 | code(MOVE,tmp,r) 292 | free_tmp(r) #REG 293 | n+=1 294 | n = 0 295 | for kk in k.items: 296 | vv = v.items[n] 297 | tmp = tmps[n] 298 | free_tmp(do_set_ctx(kk,Token(vv.pos,'reg',tmp))) #REG 299 | n += 1 300 | return 301 | 302 | r = do(v); un_tmp(r) 303 | n, tmp = 0, Token(v.pos,'reg',r) 304 | for tt in k.items: 305 | free_tmp(do_set_ctx(tt,Token(tmp.pos,'get',None,[tmp,Token(tmp.pos,'number',str(n))]))) #REG 306 | n += 1 307 | free_reg(r) 308 | return 309 | r = do(k.items[0]) 310 | rr = do(v) 311 | tmp = do(k.items[1]) 312 | code(SET,r,tmp,rr) 313 | free_tmp(r) #REG 314 | free_tmp(tmp) #REG 315 | return rr 316 | 317 | def manage_seq(i,a,items,sav=0): 318 | l = max(sav,len(items)) 319 | n,tmps = 0,get_tmps(l) 320 | for tt in items: 321 | r = tmps[n] 322 | b = do(tt,r) 323 | if r != b: 324 | code(MOVE,r,b) 325 | free_tmp(b) 326 | n +=1 327 | if not len(tmps): 328 | code(i,a,0,0) 329 | return 0 330 | code(i,a,tmps[0],len(items)) 331 | free_tmps(tmps[sav:]) 332 | return tmps[0] 333 | 334 | def p_filter(items): 335 | a,b,c,d = [],[],None,None 336 | for t in items: 337 | if t.type == 'symbol' and t.val == '=': b.append(t) 338 | elif t.type == 'args': c = t 339 | elif t.type == 'nargs': d = t 340 | else: a.append(t) 341 | return a,b,c,d 342 | 343 | def do_import(t): 344 | for mod in t.items: 345 | mod.type = 'string' 346 | v = do_call(Token(t.pos,'call',None,[ 347 | Token(t.pos,'name','import'), 348 | mod])) 349 | mod.type = 'name' 350 | do_set_ctx(mod,Token(t.pos,'reg',v)) 351 | def do_from(t): 352 | mod = t.items[0] 353 | mod.type = 'string' 354 | v = do(Token(t.pos,'call',None,[ 355 | Token(t.pos,'name','import'), 356 | mod])) 357 | item = t.items[1] 358 | if item.val == '*': 359 | free_tmp(do(Token(t.pos,'call',None,[ 360 | Token(t.pos,'name','merge'), 361 | Token(t.pos,'name','__dict__'), 362 | Token(t.pos,'reg',v)]))) #REG 363 | else: 364 | item.type = 'string' 365 | free_tmp(do_set_ctx( 366 | Token(t.pos,'get',None,[ Token(t.pos,'name','__dict__'),item]), 367 | Token(t.pos,'get',None,[ Token(t.pos,'reg',v),item]) 368 | )) #REG 369 | 370 | 371 | def do_globals(t): 372 | for t in t.items: 373 | if t.val not in D.globals: 374 | D.globals.append(t.val) 375 | def do_del(tt): 376 | for t in tt.items: 377 | r = do(t.items[0]) 378 | r2 = do(t.items[1]) 379 | code(DEL,r,r2) 380 | free_tmp(r); free_tmp(r2) #REG 381 | 382 | def do_call(t,r=None): 383 | r = get_tmp(r) 384 | items = t.items 385 | fnc = do(items[0]) 386 | a,b,c,d = p_filter(t.items[1:]) 387 | e = None 388 | if len(b) != 0 or d != None: 389 | e = do(Token(t.pos,'dict',None,[])); un_tmp(e); 390 | for p in b: 391 | p.items[0].type = 'string' 392 | t1,t2 = do(p.items[0]),do(p.items[1]) 393 | code(SET,e,t1,t2) 394 | free_tmp(t1); free_tmp(t2) #REG 395 | if d: free_tmp(do(Token(t.pos,'call',None,[Token(t.pos,'name','merge'),Token(t.pos,'reg',e),d.items[0]]))) #REG 396 | manage_seq(PARAMS,r,a) 397 | if c != None: 398 | t1,t2 = _do_string('*'),do(c.items[0]) 399 | code(SET,r,t1,t2) 400 | free_tmp(t1); free_tmp(t2) #REG 401 | if e != None: 402 | t1 = _do_none() 403 | code(SET,r,t1,e) 404 | free_tmp(t1) #REG 405 | code(CALL,r,fnc,r) 406 | free_tmp(fnc) #REG 407 | return r 408 | 409 | def do_name(t,r=None): 410 | if t.val in D.vars: 411 | return do_local(t,r) 412 | if t.val not in D.rglobals: 413 | D.rglobals.append(t.val) 414 | r = get_tmp(r) 415 | c = do_string(t) 416 | code(GGET,r,c) 417 | free_tmp(c) 418 | return r 419 | 420 | def do_local(t,r=None): 421 | if t.val in D.rglobals: 422 | D.error = True 423 | tokenize.u_error('UnboundLocalError',D.code,t.pos) 424 | if t.val not in D.vars: 425 | D.vars.append(t.val) 426 | return get_reg(t.val) 427 | 428 | def do_def(tok,kls=None): 429 | items = tok.items 430 | 431 | t = get_tag() 432 | rf = fnc(t,'end') 433 | 434 | D.begin() 435 | setpos(tok.pos) 436 | r = do_local(Token(tok.pos,'name','__params')) 437 | do_info(items[0].val) 438 | a,b,c,d = p_filter(items[1].items) 439 | for p in a: 440 | v = do_local(p) 441 | tmp = _do_none() 442 | code(GET,v,r,tmp) 443 | free_tmp(tmp) #REG 444 | for p in b: 445 | v = do_local(p.items[0]) 446 | do(p.items[1],v) 447 | tmp = _do_none() 448 | code(IGET,v,r,tmp) 449 | free_tmp(tmp) #REG 450 | if c != None: 451 | v = do_local(c.items[0]) 452 | tmp = _do_string('*') 453 | code(GET,v,r,tmp) 454 | free_tmp(tmp) #REG 455 | if d != None: 456 | e = do_local(d.items[0]) 457 | code(DICT,e,0,0) 458 | tmp = _do_none() 459 | code(IGET,e,r,tmp) 460 | free_tmp(tmp) #REG 461 | free_tmp(do(items[2])) #REG 462 | D.end() 463 | 464 | tag(t,'end') 465 | 466 | if kls == None: 467 | if D._globals: do_globals(Token(tok.pos,0,0,[items[0]])) 468 | r = do_set_ctx(items[0],Token(tok.pos,'reg',rf)) 469 | else: 470 | rn = do_string(items[0]) 471 | code(SET,kls,rn,rf) 472 | free_tmp(rn) 473 | 474 | free_tmp(rf) 475 | 476 | def do_class(t): 477 | tok = t 478 | items = t.items 479 | parent = None 480 | if items[0].type == 'name': 481 | name = items[0].val 482 | parent = Token(tok.pos,'name','object') 483 | else: 484 | name = items[0].items[0].val 485 | parent = items[0].items[1] 486 | 487 | kls = do(Token(t.pos,'dict',0,[])) 488 | un_tmp(kls) 489 | ts = _do_string(name) 490 | code(GSET,ts,kls) 491 | free_tmp(ts) #REG 492 | 493 | free_tmp(do(Token(tok.pos,'call',None,[ 494 | Token(tok.pos,'name','setmeta'), 495 | Token(tok.pos,'reg',kls), 496 | parent]))) 497 | 498 | for member in items[1].items: 499 | if member.type == 'def': do_def(member,kls) 500 | elif member.type == 'symbol' and member.val == '=': do_classvar(member,kls) 501 | else: continue 502 | 503 | free_reg(kls) #REG 504 | 505 | def do_classvar(t,r): 506 | var = do_string(t.items[0]) 507 | val = do(t.items[1]) 508 | code(SET,r,var,val) 509 | free_reg(var) 510 | free_reg(val) 511 | 512 | def do_while(t): 513 | items = t.items 514 | t = stack_tag() 515 | tag(t,'begin') 516 | tag(t,'continue') 517 | r = do(items[0]) 518 | code(IF,r) 519 | free_tmp(r) #REG 520 | jump(t,'end') 521 | free_tmp(do(items[1])) #REG 522 | jump(t,'begin') 523 | tag(t,'break') 524 | tag(t,'end') 525 | pop_tag() 526 | 527 | def do_for(tok): 528 | items = tok.items 529 | 530 | reg = do_local(items[0]) 531 | itr = do(items[1]) 532 | i = _do_number('0') 533 | 534 | t = stack_tag(); tag(t,'loop'); tag(t,'continue') 535 | code(ITER,reg,itr,i); jump(t,'end') 536 | free_tmp(do(items[2])) #REG 537 | jump(t,'loop') 538 | tag(t,'break'); tag(t,'end'); pop_tag() 539 | 540 | free_tmp(itr) #REG 541 | free_tmp(i) 542 | 543 | def do_comp(t,r=None): 544 | name = 'comp:'+get_tag() 545 | r = do_local(Token(t.pos,'name',name)) 546 | code(LIST,r,0,0) 547 | key = Token(t.pos,'get',None,[ 548 | Token(t.pos,'reg',r), 549 | Token(t.pos,'symbol','None')]) 550 | ap = Token(t.pos,'symbol','=',[key,t.items[0]]) 551 | do(Token(t.pos,'for',None,[t.items[1],t.items[2],ap])) 552 | return r 553 | 554 | def do_if(t): 555 | items = t.items 556 | t = get_tag() 557 | n = 0 558 | for tt in items: 559 | tag(t,n) 560 | if tt.type == 'elif': 561 | a = do(tt.items[0]); code(IF,a); free_tmp(a); 562 | jump(t,n+1) 563 | free_tmp(do(tt.items[1])) #REG 564 | elif tt.type == 'else': 565 | free_tmp(do(tt.items[0])) #REG 566 | else: 567 | raise 568 | jump(t,'end') 569 | n += 1 570 | tag(t,n) 571 | tag(t,'end') 572 | 573 | def do_try(t): 574 | items = t.items 575 | t = get_tag() 576 | setjmp(t,'except') 577 | free_tmp(do(items[0])) #REG 578 | code(SETJMP,0) 579 | jump(t,'end') 580 | tag(t,'except') 581 | free_tmp(do(items[1].items[1])) #REG 582 | tag(t,'end') 583 | 584 | def do_return(t): 585 | if t.items: r = do(t.items[0]) 586 | else: r = _do_none() 587 | code(RETURN,r) 588 | free_tmp(r) 589 | return 590 | def do_raise(t): 591 | if t.items: r = do(t.items[0]) 592 | else: r = _do_none() 593 | code(RAISE,r) 594 | free_tmp(r) 595 | return 596 | 597 | def do_statements(t): 598 | for tt in t.items: free_tmp(do(tt)) 599 | 600 | def do_list(t,r=None): 601 | r = get_tmp(r) 602 | manage_seq(LIST,r,t.items) 603 | return r 604 | 605 | def do_dict(t,r=None): 606 | r = get_tmp(r) 607 | manage_seq(DICT,r,t.items) 608 | return r 609 | 610 | def do_get(t,r=None): 611 | items = t.items 612 | return infix(GET,items[0],items[1],r) 613 | 614 | def do_break(t): jump(D.tstack[-1],'break') 615 | def do_continue(t): jump(D.tstack[-1],'continue') 616 | def do_pass(t): code(PASS) 617 | 618 | def do_info(name='?'): 619 | if '-nopos' in ARGV: return 620 | code(FILE,free_tmp(_do_string(D.fname))) 621 | code(NAME,free_tmp(_do_string(name))) 622 | def do_module(t): 623 | do_info() 624 | free_tmp(do(t.items[0])) #REG 625 | def do_reg(t,r=None): return t.val 626 | 627 | fmap = { 628 | 'module':do_module,'statements':do_statements,'def':do_def, 629 | 'return':do_return,'while':do_while,'if':do_if, 630 | 'break':do_break,'pass':do_pass,'continue':do_continue,'for':do_for, 631 | 'class':do_class,'raise':do_raise,'try':do_try,'import':do_import, 632 | 'globals':do_globals,'del':do_del,'from':do_from, 633 | } 634 | rmap = { 635 | 'list':do_list, 'tuple':do_list, 'dict':do_dict, 'slice':do_list, 636 | 'comp':do_comp, 'name':do_name,'symbol':do_symbol,'number':do_number, 637 | 'string':do_string,'get':do_get, 'call':do_call, 'reg':do_reg, 638 | } 639 | 640 | def do(t,r=None): 641 | if t.pos: setpos(t.pos) 642 | try: 643 | if t.type in rmap: 644 | return rmap[t.type](t,r) 645 | #if r != None: free_reg(r) #REG 646 | return fmap[t.type](t) 647 | except: 648 | if D.error: raise 649 | D.error = True 650 | tokenize.u_error('encode',D.code,t.pos) 651 | 652 | def encode(fname,s,t): 653 | t = Token((1,1),'module','module',[t]) 654 | global D 655 | s = tokenize.clean(s) 656 | D = DState(s,fname) 657 | D.begin(True) 658 | do(t) 659 | D.end() 660 | map_tags() 661 | out = D.out; D = None 662 | return ''.join(out) 663 | 664 | --------------------------------------------------------------------------------