from joy.parser import text_to_expression, Symbol from joy.utils.stack import iter_stack, list_to_stack from joy.library import SimpleFunctionWrapper def import_yin(): from joy.utils.generated_library import * return locals() D = { name: SimpleFunctionWrapper(func) for name, func in import_yin().iteritems() } def _names(): n = 0 while True: yield Symbol('a' + str(n)) n += 1 class InfiniteStack(tuple): names = _names().next def __init__(self, code): self.code = code def __iter__(self): if not self: new_var = self.names() self.code.append(('pop', new_var)) return iter((new_var, self)) class Foo(object): def __init__(self, name): self.name = name def __call__(self, stack, expression, code): in1, (in0, stack) = stack out = InfiniteStack.names() code.append(('call', out, self.name, (in0, in1))) return (out, stack), expression, code def I(expression): code = [] stack = InfiniteStack(code) while expression: term, expression = expression if isinstance(term, Symbol): func = D[term] stack, expression, _ = func(stack, expression, code) else: stack = term, stack s = list(iter_stack(stack)) if s: code.append(tuple(['ret'] + s)) return code strtup = lambda a, b: '(%s, %s)' % (b, a) strstk = lambda rest: reduce(strtup, rest, 'stack') def code_gen(code): coalesce_pops(code) lines = [] emit = lines.append for t in code: tag, rest = t[0], t[1:] if tag == 'pop': emit(strstk(rest) + ' = stack') elif tag == 'call': emit('%s = %s%s' % rest) elif tag == 'ret': emit('return ' + strstk(rest)) else: raise ValueError(tag) return '\n'.join(' ' + line for line in lines) def coalesce_pops(code): code.sort(key=lambda p: p[0] != 'pop') # All pops to the front. index = (i for i, t in enumerate(code) if t[0] != 'pop').next() code[:index] = [tuple(['pop'] + [t for _, t in code[:index][::-1]])] def compile_yinyang(name, text): return ''' def %s(stack): %s ''' % (name, code_gen(I(text_to_expression(text)))) D['mul'] = Foo('mul') D['sub'] = Foo('sub') ##print compile_yinyang('mul_', 'mul') ##print compile_yinyang('sqr', 'dup mul') ##print compile_yinyang('foo', 'dup 23 sub mul') ##print compile_yinyang('bar', 'mul mul mul mul') ##print compile_yinyang('baz', 'mul dup sub dup') ##print compile_yinyang('to_the_fifth_power', 'dup dup mul dup mul mul') ##print compile_yinyang('hey', 'dup dup dup') print compile_yinyang('hey', 'first_two')