0,0 → 1,699 |
import tokenize |
from tokenize import Token |
if '.' in str(1.0): |
from boot import * |
|
EOF,ADD,SUB,MUL,DIV,POW,AND,OR,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 = 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 |
|
class DState: |
def __init__(self,code,fname): |
self.code, self.fname = code,fname |
self.lines = self.code.split('\n') |
|
self.stack,self.out,self._scopei,self.tstack,self._tagi,self.data = [],[('tag','EOF')],0,[],0,{} |
self.error = False |
def begin(self,gbl=False): |
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.cregs,self.tmpc)) |
else: self.stack.append(None) |
self.vars,self.r2n,self.n2r,self._tmpi,self.mreg,self.snum,self._globals,self.lineno,self.globals,self.cregs,self.tmpc = [],{},{},0,0,str(self._scopei),gbl,-1,[],['regs'],0 |
self._scopei += 1 |
insert(self.cregs) |
def end(self): |
self.cregs.append(self.mreg) |
code(EOF) |
|
# This next line forces the encoder to |
# throw an exception if any tmp regs |
# were leaked within the frame |
assert(self.tmpc == 0) #REG |
|
if len(self.stack) > 1: |
self.vars,self.r2n,self.n2r,self._tmpi,self.mreg,self.snum,self._globals,self.lineno,self.globals,self.cregs,self.tmpc = self.stack.pop() |
else: self.stack.pop() |
|
|
def insert(v): D.out.append(v) |
def write(v): |
if istype(v,'list'): |
insert(v) |
return |
for n in range(0,len(v),4): |
insert(('data',v[n:n+4])) |
def setpos(v): |
if '-nopos' in ARGV: return |
line,x = v |
if line == D.lineno: return |
text = D.lines[line-1] |
D.lineno = line |
val = text + "\0"*(4-len(text)%4) |
code_16(POS,len(val)/4,line) |
write(val) |
def code(i,a=0,b=0,c=0): |
if not istype(i,'number'): raise |
if not istype(a,'number'): raise |
if not istype(b,'number'): raise |
if not istype(c,'number'): raise |
write(('code',i,a,b,c)) |
def code_16(i,a,b): |
if b < 0: b += 0x8000 |
code(i,a,(b&0xff00)>>8,(b&0xff)>>0) |
def get_code16(i,a,b): |
return ('code',i,a,(b&0xff00)>>8,(b&0xff)>>0) |
|
def _do_string(v,r=None): |
r = get_tmp(r) |
val = v + "\0"*(4-len(v)%4) |
code_16(STRING,r,len(v)) |
write(val) |
return r |
def do_string(t,r=None): |
return _do_string(t.val,r) |
|
def _do_number(v,r=None): |
r = get_tmp(r) |
code(NUMBER,r,0,0) |
write(fpack(number(v))) |
return r |
def do_number(t,r=None): |
return _do_number(t.val,r) |
|
def get_tag(): |
k = str(D._tagi) |
D._tagi += 1 |
return k |
def stack_tag(): |
k = get_tag() |
D.tstack.append(k) |
return k |
def pop_tag(): |
D.tstack.pop() |
|
def tag(*t): |
t = D.snum+':'+':'.join([str(v) for v in t]) |
insert(('tag',t)) |
def jump(*t): |
t = D.snum+':'+':'.join([str(v) for v in t]) |
insert(('jump',t)) |
def setjmp(*t): |
t = D.snum+':'+':'.join([str(v) for v in t]) |
insert(('setjmp',t)) |
def fnc(*t): |
t = D.snum+':'+':'.join([str(v) for v in t]) |
r = get_reg(t) |
insert(('fnc',r,t)) |
return r |
|
def map_tags(): |
tags = {} |
out = [] |
n = 0 |
for item in D.out: |
if item[0] == 'tag': |
tags[item[1]] = n |
continue |
if item[0] == 'regs': |
out.append(get_code16(REGS,item[1],0)) |
n += 1 |
continue |
out.append(item) |
n += 1 |
for n in range(0,len(out)): |
item = out[n] |
if item[0] == 'jump': |
out[n] = get_code16(JUMP,0,tags[item[1]]-n) |
elif item[0] == 'setjmp': |
out[n] = get_code16(SETJMP,0,tags[item[1]]-n) |
elif item[0] == 'fnc': |
out[n] = get_code16(DEF,item[1],tags[item[2]]-n) |
for n in range(0,len(out)): |
item = out[n] |
if item[0] == 'data': |
out[n] = item[1] |
elif item[0] == 'code': |
i,a,b,c = item[1:] |
out[n] = chr(i)+chr(a)+chr(b)+chr(c) |
else: |
raise str(('huh?',item)) |
if len(out[n]) != 4: |
raise ('code '+str(n)+' is wrong length '+str(len(out[n]))) |
D.out = out |
|
def get_tmp(r=None): |
if r != None: return r |
return get_tmps(1)[0] |
def get_tmps(t): |
rs = alloc(t) |
regs = range(rs,rs+t) |
for r in regs: |
set_reg(r,"$"+str(D._tmpi)) |
D._tmpi += 1 |
D.tmpc += t #REG |
return regs |
def alloc(t): |
s = ''.join(["01"[r in D.r2n] for r in range(0,min(256,D.mreg+t))]) |
return s.index('0'*t) |
def is_tmp(r): |
if r is None: return False |
return (D.r2n[r][0] == '$') |
def un_tmp(r): |
n = D.r2n[r] |
free_reg(r) |
set_reg(r,'*'+n) |
def free_tmp(r): |
if is_tmp(r): free_reg(r) |
return r |
def free_tmps(r): |
for k in r: free_tmp(k) |
def get_reg(n): |
if n not in D.n2r: |
set_reg(alloc(1),n) |
return D.n2r[n] |
#def get_clean_reg(n): |
#if n in D.n2r: raise |
#set_reg(D.mreg,n) |
#return D.n2r[n] |
def set_reg(r,n): |
D.n2r[n] = r; D.r2n[r] = n |
D.mreg = max(D.mreg,r+1) |
def free_reg(r): |
if is_tmp(r): D.tmpc -= 1 |
n = D.r2n[r]; del D.r2n[r]; del D.n2r[n] |
|
def imanage(orig,fnc): |
items = orig.items |
orig.val = orig.val[:-1] |
t = Token(orig.pos,'symbol','=',[items[0],orig]) |
return fnc(t) |
|
def infix(i,tb,tc,r=None): |
r = get_tmp(r) |
b,c = do(tb,r),do(tc) |
code(i,r,b,c) |
if r != b: free_tmp(b) |
free_tmp(c) |
return r |
def ss_infix(ss,i,tb,tc,r=None): |
r = get_tmp(r) |
r2 = get_tmp() |
ss = _do_number(ss) |
t = get_tag() |
r = do(tb,r) |
code(EQ,r2,r,ss) |
code(IF,r2) |
jump(t,'else') |
jump(t,'end') |
tag(t,'else') |
r = do(tc,r) |
tag(t,'end') |
free_tmp(r2) #REG |
free_tmp(ss) #REG |
return r |
|
def _do_none(r=None): |
r = get_tmp(r) |
code(NONE,r) |
return r |
|
def do_symbol(t,r=None): |
sets = ['='] |
isets = ['+=','-=','*=','/='] |
cmps = ['<','>','<=','>=','==','!='] |
metas = { |
'+':ADD,'*':MUL,'/':DIV,'**':POW, |
'-':SUB,'and':AND,'or':OR, |
'%':MOD,'>>':RSH,'<<':LSH, |
'&':AND,'|':OR, |
} |
if t.val == 'None': return _do_none(r) |
if t.val == 'True': |
return _do_number('1',r) |
if t.val == 'False': |
return _do_number('0',r) |
items = t.items |
|
if t.val in ['and','or']: |
ss = int(t.val == 'or') |
return ss_infix(ss,metas[t.val],items[0],items[1],r) |
if t.val in isets: |
return imanage(t,do_symbol) |
if t.val == 'is': |
return infix(EQ,items[0],items[1],r) |
if t.val == 'isnot': |
return infix(CMP,items[0],items[1],r) |
if t.val == 'not': |
return infix(EQ,Token(t.pos,'number',0),items[0],r) |
if t.val == 'in': |
return infix(HAS,items[1],items[0],r) |
if t.val == 'notin': |
r = infix(HAS,items[1],items[0],r) |
zero = _do_number('0') |
code(EQ,r,r,free_tmp(zero)) |
return r |
if t.val in sets: |
return do_set_ctx(items[0],items[1]); |
elif t.val in cmps: |
b,c = items[0],items[1] |
v = t.val |
if v[0] in ('>','>='): |
b,c,v = c,b,'<'+v[1:] |
cd = EQ |
if v == '<': cd = LT |
if v == '<=': cd = LE |
if v == '!=': cd = NE |
return infix(cd,b,c,r) |
else: |
return infix(metas[t.val],items[0],items[1],r) |
|
def do_set_ctx(k,v): |
if k.type == 'name': |
if (D._globals and k.val not in D.vars) or (k.val in D.globals): |
c = do_string(k) |
b = do(v) |
code(GSET,c,b) |
free_tmp(c) |
free_tmp(b) |
return |
a = do_local(k) |
b = do(v) |
code(MOVE,a,b) |
free_tmp(b) |
return a |
elif k.type in ('tuple','list'): |
if v.type in ('tuple','list'): |
n,tmps = 0,[] |
for kk in k.items: |
vv = v.items[n] |
tmp = get_tmp(); tmps.append(tmp) |
r = do(vv) |
code(MOVE,tmp,r) |
free_tmp(r) #REG |
n+=1 |
n = 0 |
for kk in k.items: |
vv = v.items[n] |
tmp = tmps[n] |
free_tmp(do_set_ctx(kk,Token(vv.pos,'reg',tmp))) #REG |
n += 1 |
return |
|
r = do(v); un_tmp(r) |
n, tmp = 0, Token(v.pos,'reg',r) |
for tt in k.items: |
free_tmp(do_set_ctx(tt,Token(tmp.pos,'get',None,[tmp,Token(tmp.pos,'number',str(n))]))) #REG |
n += 1 |
free_reg(r) |
return |
r = do(k.items[0]) |
rr = do(v) |
tmp = do(k.items[1]) |
code(SET,r,tmp,rr) |
free_tmp(r) #REG |
free_tmp(tmp) #REG |
return rr |
|
def manage_seq(i,a,items,sav=0): |
l = max(sav,len(items)) |
n,tmps = 0,get_tmps(l) |
for tt in items: |
r = tmps[n] |
b = do(tt,r) |
if r != b: |
code(MOVE,r,b) |
free_tmp(b) |
n +=1 |
if not len(tmps): |
code(i,a,0,0) |
return 0 |
code(i,a,tmps[0],len(items)) |
free_tmps(tmps[sav:]) |
return tmps[0] |
|
def p_filter(items): |
a,b,c,d = [],[],None,None |
for t in items: |
if t.type == 'symbol' and t.val == '=': b.append(t) |
elif t.type == 'args': c = t |
elif t.type == 'nargs': d = t |
else: a.append(t) |
return a,b,c,d |
|
def do_import(t): |
for mod in t.items: |
mod.type = 'string' |
v = do_call(Token(t.pos,'call',None,[ |
Token(t.pos,'name','import'), |
mod])) |
mod.type = 'name' |
do_set_ctx(mod,Token(t.pos,'reg',v)) |
def do_from(t): |
mod = t.items[0] |
mod.type = 'string' |
v = do(Token(t.pos,'call',None,[ |
Token(t.pos,'name','import'), |
mod])) |
item = t.items[1] |
if item.val == '*': |
free_tmp(do(Token(t.pos,'call',None,[ |
Token(t.pos,'name','merge'), |
Token(t.pos,'name','__dict__'), |
Token(t.pos,'reg',v)]))) #REG |
else: |
item.type = 'string' |
free_tmp(do_set_ctx( |
Token(t.pos,'get',None,[ Token(t.pos,'name','__dict__'),item]), |
Token(t.pos,'get',None,[ Token(t.pos,'reg',v),item]) |
)) #REG |
|
|
def do_globals(t): |
for t in t.items: |
if t.val not in D.globals: |
D.globals.append(t.val) |
def do_del(tt): |
for t in tt.items: |
r = do(t.items[0]) |
r2 = do(t.items[1]) |
code(DEL,r,r2) |
free_tmp(r); free_tmp(r2) #REG |
|
def do_call(t,r=None): |
r = get_tmp(r) |
items = t.items |
fnc = do(items[0]) |
a,b,c,d = p_filter(t.items[1:]) |
e = None |
if len(b) != 0 or d != None: |
e = do(Token(t.pos,'dict',None,[])); un_tmp(e); |
for p in b: |
p.items[0].type = 'string' |
t1,t2 = do(p.items[0]),do(p.items[1]) |
code(SET,e,t1,t2) |
free_tmp(t1); free_tmp(t2) #REG |
if d: free_tmp(do(Token(t.pos,'call',None,[Token(t.pos,'name','merge'),Token(t.pos,'reg',e),d.items[0]]))) #REG |
manage_seq(PARAMS,r,a) |
if c != None: |
t1,t2 = _do_string('*'),do(c.items[0]) |
code(SET,r,t1,t2) |
free_tmp(t1); free_tmp(t2) #REG |
if e != None: |
t1 = _do_none() |
code(SET,r,t1,e) |
free_tmp(t1) #REG |
code(CALL,r,fnc,r) |
free_tmp(fnc) #REG |
return r |
|
def do_name(t,r=None): |
if t.val in D.vars: |
return do_local(t,r) |
r = get_tmp(r) |
c = do_string(t) |
code(GGET,r,c) |
free_tmp(c) |
return r |
|
def do_local(t,r=None): |
if t.val not in D.vars: |
D.vars.append(t.val) |
return get_reg(t.val) |
|
def do_def(tok,kls=None): |
items = tok.items |
|
t = get_tag() |
rf = fnc(t,'end') |
|
D.begin() |
setpos(tok.pos) |
r = do_local(Token(tok.pos,'name','__params')) |
do_info(items[0].val) |
a,b,c,d = p_filter(items[1].items) |
for p in a: |
v = do_local(p) |
tmp = _do_none() |
code(GET,v,r,tmp) |
free_tmp(tmp) #REG |
for p in b: |
v = do_local(p.items[0]) |
do(p.items[1],v) |
tmp = _do_none() |
code(IGET,v,r,tmp) |
free_tmp(tmp) #REG |
if c != None: |
v = do_local(c.items[0]) |
tmp = _do_string('*') |
code(GET,v,r,tmp) |
free_tmp(tmp) #REG |
if d != None: |
e = do_local(d.items[0]) |
code(DICT,e,0,0) |
tmp = _do_none() |
code(IGET,e,r,tmp) |
free_tmp(tmp) #REG |
free_tmp(do(items[2])) #REG |
D.end() |
|
tag(t,'end') |
|
if kls == None: |
if D._globals: do_globals(Token(tok.pos,0,0,[items[0]])) |
r = do_set_ctx(items[0],Token(tok.pos,'reg',rf)) |
else: |
rn = do_string(items[0]) |
code(SET,kls,rn,rf) |
free_tmp(rn) |
|
free_tmp(rf) |
|
def do_class(t): |
tok = t |
items = t.items |
parent = None |
if items[0].type == 'name': |
name = items[0].val |
else: |
name = items[0].items[0].val |
parent = items[0].items[1].val |
|
kls = do(Token(t.pos,'dict',0,[])) |
ts = _do_string(name) |
code(GSET,ts,kls) |
free_tmp(ts) #REG |
|
init,_new = False,[] |
if parent: |
_new.append(Token(t.pos,'call',None,[ |
Token(t.pos,'get',None,[ |
Token(t.pos,'name',parent), |
Token(t.pos,'string','__new__'), |
]), |
Token(t.pos,'name','self'), |
])) |
|
for fc in items[1].items: |
if fc.type != 'def': continue |
fn = fc.items[0].val |
if fn == '__init__': init = True |
do_def(fc,kls) |
_new.append(Token(fc.pos,'symbol','=',[ |
Token(fc.pos,'get',None,[ |
Token(fc.pos,'name','self'), |
Token(fc.pos,'string',fn)]), |
Token(fc.pos,'call',None,[ |
Token(fc.pos,'name','bind'), |
Token(fc.pos,'get',None,[ |
Token(fc.pos,'name',name), |
Token(fc.pos,'string',fn)]), |
Token(fc.pos,'name','self')]) |
])) |
|
do_def(Token(t.pos,'def',None,[ |
Token(t.pos,'name','__new__'), |
Token(t.pos,'list',None,[Token(t.pos,'name','self')]), |
Token(t.pos,'statements',None,_new)]),kls) |
|
t = get_tag() |
rf = fnc(t,'end') |
D.begin() |
params = do_local(Token(tok.pos,'name','__params')) |
|
slf = do_local(Token(tok.pos,'name','self')) |
code(DICT,slf,0,0) |
|
free_tmp(do(Token(tok.pos,'call',None,[ |
Token(tok.pos,'get',None,[ |
Token(tok.pos,'name',name), |
Token(tok.pos,'string','__new__')]), |
Token(tok.pos,'name','self')]))) #REG |
|
if init: |
tmp = get_tmp() |
t3 = _do_string('__init__') |
code(GET,tmp,slf,t3) |
t4 = get_tmp() |
code(CALL,t4,tmp,params) |
free_tmp(tmp) #REG |
free_tmp(t3) #REG |
free_tmp(t4) #REG |
code(RETURN,slf) |
|
D.end() |
tag(t,'end') |
ts = _do_string('__call__') |
code(SET,kls,ts,rf) |
free_tmp(kls) #REG |
free_tmp(ts) #REG |
|
|
|
|
def do_while(t): |
items = t.items |
t = stack_tag() |
tag(t,'begin') |
tag(t,'continue') |
r = do(items[0]) |
code(IF,r) |
free_tmp(r) #REG |
jump(t,'end') |
free_tmp(do(items[1])) #REG |
jump(t,'begin') |
tag(t,'break') |
tag(t,'end') |
pop_tag() |
|
def do_for(tok): |
items = tok.items |
|
reg = do_local(items[0]) |
itr = do(items[1]) |
i = _do_number('0') |
|
t = stack_tag(); tag(t,'loop'); tag(t,'continue') |
code(ITER,reg,itr,i); jump(t,'end') |
free_tmp(do(items[2])) #REG |
jump(t,'loop') |
tag(t,'break'); tag(t,'end'); pop_tag() |
|
free_tmp(itr) #REG |
free_tmp(i) |
|
def do_comp(t,r=None): |
name = 'comp:'+get_tag() |
r = do_local(Token(t.pos,'name',name)) |
code(LIST,r,0,0) |
key = Token(t.pos,'get',None,[ |
Token(t.pos,'reg',r), |
Token(t.pos,'symbol','None')]) |
ap = Token(t.pos,'symbol','=',[key,t.items[0]]) |
do(Token(t.pos,'for',None,[t.items[1],t.items[2],ap])) |
return r |
|
def do_if(t): |
items = t.items |
t = get_tag() |
n = 0 |
for tt in items: |
tag(t,n) |
if tt.type == 'elif': |
a = do(tt.items[0]); code(IF,a); free_tmp(a); |
jump(t,n+1) |
free_tmp(do(tt.items[1])) #REG |
elif tt.type == 'else': |
free_tmp(do(tt.items[0])) #REG |
else: |
raise |
jump(t,'end') |
n += 1 |
tag(t,n) |
tag(t,'end') |
|
def do_try(t): |
items = t.items |
t = get_tag() |
setjmp(t,'except') |
free_tmp(do(items[0])) #REG |
jump(t,'end') |
tag(t,'except') |
free_tmp(do(items[1].items[1])) #REG |
tag(t,'end') |
|
def do_return(t): |
if t.items: r = do(t.items[0]) |
else: r = _do_none() |
code(RETURN,r) |
free_tmp(r) |
return |
def do_raise(t): |
if t.items: r = do(t.items[0]) |
else: r = _do_none() |
code(RAISE,r) |
free_tmp(r) |
return |
|
def do_statements(t): |
for tt in t.items: free_tmp(do(tt)) |
|
def do_list(t,r=None): |
r = get_tmp(r) |
manage_seq(LIST,r,t.items) |
return r |
|
def do_dict(t,r=None): |
r = get_tmp(r) |
manage_seq(DICT,r,t.items) |
return r |
|
def do_get(t,r=None): |
items = t.items |
return infix(GET,items[0],items[1],r) |
|
def do_break(t): jump(D.tstack[-1],'break') |
def do_continue(t): jump(D.tstack[-1],'continue') |
def do_pass(t): code(PASS) |
|
def do_info(name='?'): |
if '-nopos' in ARGV: return |
code(FILE,free_tmp(_do_string(D.fname))) |
code(NAME,free_tmp(_do_string(name))) |
def do_module(t): |
do_info() |
free_tmp(do(t.items[0])) #REG |
def do_reg(t,r=None): return t.val |
|
fmap = { |
'module':do_module,'statements':do_statements,'def':do_def, |
'return':do_return,'while':do_while,'if':do_if, |
'break':do_break,'pass':do_pass,'continue':do_continue,'for':do_for, |
'class':do_class,'raise':do_raise,'try':do_try,'import':do_import, |
'globals':do_globals,'del':do_del,'from':do_from, |
} |
rmap = { |
'list':do_list, 'tuple':do_list, 'dict':do_dict, 'slice':do_list, |
'comp':do_comp, 'name':do_name,'symbol':do_symbol,'number':do_number, |
'string':do_string,'get':do_get, 'call':do_call, 'reg':do_reg, |
} |
|
def do(t,r=None): |
if t.pos: setpos(t.pos) |
try: |
if t.type in rmap: |
return rmap[t.type](t,r) |
return fmap[t.type](t) |
except: |
if D.error: raise |
D.error = True |
tokenize.u_error('encode',D.code,t.pos) |
|
def encode(fname,s,t): |
t = Token((1,1),'module','module',[t]) |
global D |
s = tokenize.clean(s) |
D = DState(s,fname) |
D.begin(True) |
do(t) |
D.end() |
map_tags() |
out = D.out; D = None |
return ''.join(out) |
|