OSDN Git Service

Expression?
authorSimon Forman <sforman@hushmail.com>
Mon, 4 Apr 2022 14:58:22 +0000 (07:58 -0700)
committerSimon Forman <sforman@hushmail.com>
Mon, 4 Apr 2022 14:58:22 +0000 (07:58 -0700)
implementations/Python/joy/expr.py [new file with mode: 0644]
implementations/expr.py [new file with mode: 0644]

diff --git a/implementations/Python/joy/expr.py b/implementations/Python/joy/expr.py
new file mode 100644 (file)
index 0000000..bf30811
--- /dev/null
@@ -0,0 +1,25 @@
+
+
+class Expression:
+
+    def __init__(self, initial_expression=()):
+        self.current = initial_expression
+        self.stack = []
+
+    def __next__(self):
+        if self.current:
+            item, self.current = self.current
+            return item
+        if self.stack:
+            self.current = self.stack.pop()
+            return self.__next__()
+        raise StopIteration
+
+    def prepend(self, quoted_program):
+        if self.current:
+            self.stack.append(self.current)
+        self.current = quoted_program
+
+
+from parser import text_to_expression as j
+e = Expression(j('23 18'))
diff --git a/implementations/expr.py b/implementations/expr.py
new file mode 100644 (file)
index 0000000..4ba0be5
--- /dev/null
@@ -0,0 +1,62 @@
+from itertools import chain
+from joy.utils.stack import _s, iter_stack
+
+
+class Expression:
+    '''
+    As elegant as it is to model the expression as a stack, it's not very
+    efficient, as concatenating definitions and other quoted programs to
+    the expression is a common and expensive operation.
+
+    Instead, let's keep a stack of sub-expressions, reading from them
+    one-by-one, and prepending new sub-expressions to the stack rather than
+    concatenating them.
+    '''
+
+    def __init__(self, initial_expression=()):
+        self.current = initial_expression
+        self.stack = []
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        if self.current: (item, self.current) = self.current
+        elif self.stack: (item, self.current) = self.stack.pop()
+        else: raise StopIteration
+        return item
+
+    def prepend(self, quoted_program):
+        if not quoted_program: return
+        if self.current: self.stack.append(self.current)
+        self.current = quoted_program
+
+    def __str__(self):
+        return ' '.join(
+            map(
+                _s,
+                chain.from_iterable(
+                    map(
+                        iter_stack,
+                        reversed(self.stack + [self.current])
+                        )
+                    )
+                )
+            )
+
+
+if __name__ == '__main__':
+    from joy.parser import text_to_expression as j
+
+    e = Expression(j('23 18'))
+    e.prepend(j('88 19'))
+    e.prepend(j('foo fie feum'))
+    print(e)
+    for i in e:
+        print(i, e.stack, e.current)
+        if i == 88:
+            print('prepending "hello world"')
+            e.prepend(j('hello world'))
+        if i == 19:
+            print('prepending "good bye"')
+            e.prepend(j('good bye'))