OSDN Git Service

Minor cleanup.
[joypy/Thun.git] / joy / utils / pretty_print.py
1 # -*- coding: utf-8 -*-
2 #
3 #    Copyright © 2016 Simon Forman
4 #
5 #    This file is part of Thun.
6 #
7 #    Thun is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU General Public License as published by
9 #    the Free Software Foundation, either version 3 of the License, or
10 #    (at your option) any later version.
11 #
12 #    Thun is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU General Public License for more details.
16 #
17 #    You should have received a copy of the GNU General Public License
18 #    along with Thun.  If not see <http://www.gnu.org/licenses/>.
19 #
20 '''
21 Pretty printing support, e.g.::
22
23     Joy? [23 18 * 99 +] trace
24            • 23 18 mul 99 add
25         23 • 18 mul 99 add
26      23 18 • mul 99 add
27        414 • 99 add
28     414 99 • add
29        513 • 
30
31     513 <-top
32
33     joy? 
34
35 On each line the stack is printed with the top to the left, then a
36 bullet symbol,``•``, to represent the current locus of processing, then
37 the pending expression to the right.
38 '''
39 # (Kinda clunky and hacky.  This should be swapped out in favor of much
40 # smarter stuff.)
41 from __future__ import print_function
42 from builtins import object
43 from traceback import print_exc
44 from .stack import expression_to_string, stack_to_string
45 from ..joy import joy
46 from ..library import inscribe, FunctionWrapper
47
48
49 @inscribe
50 @FunctionWrapper
51 def trace(stack, expression, dictionary):
52         '''Evaluate a Joy expression on a stack and print a trace.
53
54         This function is just like the `i` combinator but it also prints a
55         trace of the evaluation
56
57         :param stack stack: The stack.
58         :param stack expression: The expression to evaluate.
59         :param dict dictionary: A ``dict`` mapping names to Joy functions.
60         :rtype: (stack, (), dictionary)
61
62         '''
63         tp = TracePrinter()
64         quote, stack = stack
65         try:
66                 s, _, d = joy(stack, quote, dictionary, tp.viewer)
67         except:
68                 tp.print_()
69                 print('-' * 73)
70                 raise
71         else:
72                 tp.print_()
73         return s, expression, d
74
75
76 class TracePrinter(object):
77         '''
78         This is what does the formatting.  You instantiate it and pass the ``viewer()``
79         method to the :py:func:`joy.joy.joy` function, then print it to see the
80         trace.
81         '''
82
83         def __init__(self):
84                 self.history = []
85
86         def viewer(self, stack, expression):
87                 '''
88                 Record the current stack and expression in the TracePrinter's history.
89                 Pass this method as the ``viewer`` argument to the :py:func:`joy.joy.joy` function.
90
91                 :param stack quote: A stack.
92                 :param stack expression: A stack.
93                 '''
94                 self.history.append((stack, expression))
95
96         def __str__(self):
97                 return '\n'.join(self.go())
98
99         def go(self):
100                 '''
101                 Return a list of strings, one for each entry in the history, prefixed
102                 with enough spaces to align all the interpreter dots.
103
104                 This method is called internally by the ``__str__()`` method.
105
106                 :rtype: list(str)
107                 '''
108                 max_stack_length = 0
109                 lines = []
110                 for stack, expression in self.history:
111                         stack = stack_to_string(stack)
112                         expression = expression_to_string(expression)
113                         n = len(stack)
114                         if n > max_stack_length:
115                                 max_stack_length = n
116                         lines.append((n, '%s • %s' % (stack, expression)))
117                 return [  # Prefix spaces to line up '•'s.
118                         (' ' * (max_stack_length - length) + line)
119                         for length, line in lines
120                         ]
121
122         def print_(self):
123                 try:
124                         print(self)
125                 except:
126                         print_exc()
127                         print('Exception while printing viewer.')