OSDN Git Service

Working on compiler.
authorSimon Forman <sforman@hushmail.com>
Wed, 1 Aug 2018 17:59:07 +0000 (10:59 -0700)
committerSimon Forman <sforman@hushmail.com>
Wed, 1 Aug 2018 17:59:07 +0000 (10:59 -0700)
I have a simple dataflow thingy for some Yin and Yang functions.

joy/utils/compiler.py [new file with mode: 0644]

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