Initial move of code from git repo.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright © 2016 Simon Forman
|
||||
#
|
||||
# This file is part of Joypy.
|
||||
#
|
||||
# Joypy is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Joypy is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Joypy. If not see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
'''
|
||||
Pretty printing support.
|
||||
|
||||
This is what does the formatting, e.g.:
|
||||
|
||||
. 23 18 mul 99 add
|
||||
23 . 18 mul 99 add
|
||||
23 18 . mul 99 add
|
||||
414 . 99 add
|
||||
414 99 . add
|
||||
513 .
|
||||
|
||||
'''
|
||||
# (Kinda clunky and hacky. This should be swapped out in favor of much
|
||||
# smarter stuff.)
|
||||
from __future__ import print_function
|
||||
from traceback import print_exc
|
||||
from .stack import expression_to_string, stack_to_string
|
||||
|
||||
|
||||
class TracePrinter(object):
|
||||
|
||||
def __init__(self):
|
||||
self.history = []
|
||||
|
||||
def viewer(self, stack, expression):
|
||||
'''Pass this method as the viewer to joy() function.'''
|
||||
self.history.append((stack, expression))
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(self.go())
|
||||
|
||||
def go(self):
|
||||
max_stack_length = 0
|
||||
lines = []
|
||||
for stack, expression in self.history:
|
||||
stack = stack_to_string(stack)
|
||||
expression = expression_to_string(expression)
|
||||
n = len(stack)
|
||||
if n > max_stack_length:
|
||||
max_stack_length = n
|
||||
lines.append((n, '%s . %s' % (stack, expression)))
|
||||
return [ # Prefix spaces to line up '.'s.
|
||||
(' ' * (max_stack_length - length) + line)
|
||||
for length, line in lines
|
||||
]
|
||||
|
||||
def print_(self):
|
||||
try:
|
||||
print(self)
|
||||
except:
|
||||
print_exc()
|
||||
print('Exception while printing viewer.')
|
||||
@@ -0,0 +1,154 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright © 2014, 2015, 2017 Simon Forman
|
||||
#
|
||||
# This file is part of joy.py
|
||||
#
|
||||
# joy.py is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# joy.py is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with joy.py. If not see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
'''
|
||||
|
||||
|
||||
§ Stack
|
||||
|
||||
|
||||
When talking about Joy we use the terms "stack", "list", "sequence" and
|
||||
"aggregate" to mean the same thing: a simple datatype that permits
|
||||
certain operations such as iterating and pushing and popping values from
|
||||
(at least) one end.
|
||||
|
||||
We use the venerable two-tuple recursive form of sequences where the
|
||||
empty tuple () is the empty stack and (head, rest) gives the recursive
|
||||
form of a stack with one or more items on it.
|
||||
|
||||
()
|
||||
(1, ())
|
||||
(2, (1, ()))
|
||||
(3, (2, (1, ())))
|
||||
...
|
||||
|
||||
And so on.
|
||||
|
||||
|
||||
We have two very simple functions to build up a stack from a Python
|
||||
iterable and also to iterate through a stack and yield its items
|
||||
one-by-one in order, and two functions to generate string representations
|
||||
of stacks:
|
||||
|
||||
list_to_stack()
|
||||
|
||||
iter_stack()
|
||||
|
||||
expression_to_string() (prints left-to-right)
|
||||
|
||||
stack_to_string() (prints right-to-left)
|
||||
|
||||
|
||||
A word about the stack data structure.
|
||||
|
||||
Python has very nice "tuple packing and unpacking" in its syntax which
|
||||
means we can directly "unpack" the expected arguments to a Joy function.
|
||||
|
||||
For example:
|
||||
|
||||
def dup(stack):
|
||||
head, tail = stack
|
||||
return head, (head, tail)
|
||||
|
||||
We replace the argument "stack" by the expected structure of the stack,
|
||||
in this case "(head, tail)", and Python takes care of de-structuring the
|
||||
incoming argument and assigning values to the names. Note that Python
|
||||
syntax doesn't require parentheses around tuples used in expressions
|
||||
where they would be redundant.
|
||||
'''
|
||||
|
||||
|
||||
def list_to_stack(el, stack=()):
|
||||
'''Convert a list (or other sequence) to a stack.
|
||||
|
||||
[1, 2, 3] -> (1, (2, (3, ())))
|
||||
|
||||
'''
|
||||
for item in reversed(el):
|
||||
stack = item, stack
|
||||
return stack
|
||||
|
||||
|
||||
def iter_stack(stack):
|
||||
'''Iterate through the items on the stack.'''
|
||||
while stack:
|
||||
item, stack = stack
|
||||
yield item
|
||||
|
||||
|
||||
def stack_to_string(stack):
|
||||
'''
|
||||
Return a "pretty print" string for a stack.
|
||||
|
||||
The items are written right-to-left:
|
||||
|
||||
(top, (second, ...)) -> '... second top'
|
||||
'''
|
||||
f = lambda stack: reversed(list(iter_stack(stack)))
|
||||
return _to_string(stack, f)
|
||||
|
||||
|
||||
def expression_to_string(expression):
|
||||
'''
|
||||
Return a "pretty print" string for a expression.
|
||||
|
||||
The items are written left-to-right:
|
||||
|
||||
(top, (second, ...)) -> 'top second ...'
|
||||
'''
|
||||
return _to_string(expression, iter_stack)
|
||||
|
||||
|
||||
def _to_string(stack, f):
|
||||
if isinstance(stack, long): return str(stack).rstrip('L')
|
||||
if not isinstance(stack, tuple): return repr(stack)
|
||||
if not stack: return '' # shortcut
|
||||
return ' '.join(map(_s, f(stack)))
|
||||
|
||||
|
||||
_s = lambda s: (
|
||||
'[%s]' % expression_to_string(s) if isinstance(s, tuple)
|
||||
else str(s).rstrip('L') if isinstance(s, long)
|
||||
else repr(s)
|
||||
)
|
||||
|
||||
|
||||
def pushback(quote, expression):
|
||||
'''Concatinate quote onto expression.
|
||||
|
||||
In joy [1 2] [3 4] would become [1 2 3 4].
|
||||
'''
|
||||
return list_to_stack(list(iter_stack(quote)), expression)
|
||||
|
||||
|
||||
def pick(s, n):
|
||||
'''
|
||||
Find the nth item on the stack. (Pick with zero is the same as "dup".)
|
||||
'''
|
||||
if n < 0:
|
||||
raise ValueError
|
||||
while True:
|
||||
try:
|
||||
item, s = s
|
||||
except ValueError:
|
||||
raise IndexError
|
||||
n -= 1
|
||||
if n < 0:
|
||||
break
|
||||
return item
|
||||
Reference in New Issue
Block a user