diff --git a/joy/utils/compiler.py b/joy/utils/compiler.py new file mode 100644 index 0000000..0b2bc91 --- /dev/null +++ b/joy/utils/compiler.py @@ -0,0 +1,107 @@ +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')