87 lines
2.3 KiB
Python
87 lines
2.3 KiB
Python
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 __bool__(self):
|
|
return bool(self.current or self.stack)
|
|
|
|
def __str__(self):
|
|
return ' '.join(
|
|
map(
|
|
_s,
|
|
chain.from_iterable(
|
|
map(
|
|
iter_stack,
|
|
reversed(self.stack + [self.current])
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
class E(Expression):
|
|
|
|
def __iter__(self):
|
|
return iter((self.__next__(), self))
|
|
|
|
|
|
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'))
|
|
print('-'*20)
|
|
e = E(j('23 18'))
|
|
e.prepend(j('88 19'))
|
|
e.prepend(j('foo fie feum'))
|
|
print(e)
|
|
while e:
|
|
i, e = 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'))
|
|
|