diff --git a/joy/joy.py b/joy/joy.py index 901b159..07ed9a6 100644 --- a/joy/joy.py +++ b/joy/joy.py @@ -42,11 +42,11 @@ def joy(stack, expression, dictionary, viewer=None): or functions. Literals are put onto the stack and functions are executed. - - :param quote stack: The stack. - :param quote expression: The expression to evaluate. - :param dict dictionary: A `dict` mapping names to Joy functions. + :param stack stack: The stack. + :param stack expression: The expression to evaluate. + :param dict dictionary: A ``dict`` mapping names to Joy functions. :param function viewer: Optional viewer function. + :rtype: (stack, (), dictionary) ''' while expression: @@ -67,6 +67,13 @@ def joy(stack, expression, dictionary, viewer=None): def run(text, stack, dictionary, viewer=None): ''' Return the stack resulting from running the Joy code text on the stack. + + :param str text: Joy code. + :param stack stack: The stack. + :param dict dictionary: A ``dict`` mapping names to Joy functions. + :param function viewer: Optional viewer function. + :rtype: (stack, (), dictionary) + ''' expression = text_to_expression(text) return joy(stack, expression, dictionary, viewer) @@ -77,6 +84,11 @@ def repl(stack=(), dictionary=None): Read-Evaluate-Print Loop Accept input and run it on the stack, loop. + + :param stack stack: The stack. + :param dict dictionary: A ``dict`` mapping names to Joy functions. + :rtype: stack + ''' if dictionary is None: dictionary = {} diff --git a/joy/parser.py b/joy/parser.py index e0dd9fc..350bc9c 100644 --- a/joy/parser.py +++ b/joy/parser.py @@ -51,7 +51,7 @@ def text_to_expression(text): Any unbalanced square brackets will raise a ParseError. :param str text: Text to convert. - :rtype: quote + :rtype: stack :raises ParseError: if the parse fails. ''' return _parse(_tokenize(text)) diff --git a/joy/utils/pretty_print.py b/joy/utils/pretty_print.py index 5f71c01..5151ae1 100644 --- a/joy/utils/pretty_print.py +++ b/joy/utils/pretty_print.py @@ -18,7 +18,24 @@ # along with Thun. If not see . # ''' -Pretty printing support. +Pretty printing support, e.g.:: + + Joy? 23 18 * 99 + + . 23 18 mul 99 add + 23 . 18 mul 99 add + 23 18 . mul 99 add + 414 . 99 add + 414 99 . add + 513 . + + 513 <-top + + joy? + +On each line the stack is printed with the top to the right, then a ``.`` to +represent the current locus of processing, then the pending expression to the +left. + ''' # (Kinda clunky and hacky. This should be swapped out in favor of much # smarter stuff.) @@ -29,29 +46,36 @@ from .stack import expression_to_string, stack_to_string class TracePrinter(object): ''' - This is what does the formatting, e.g.:: - - Joy? 23 18 * 99 + - . 23 18 mul 99 add - 23 . 18 mul 99 add - 23 18 . mul 99 add - 414 . 99 add - 414 99 . add - 513 . - + This is what does the formatting. You instantiate it and pass the ``viewer()`` + method to the :py:func:`joy.joy.joy` function, then print it to see the + trace. ''' def __init__(self): self.history = [] def viewer(self, stack, expression): - '''Pass this method as the viewer to joy() function.''' + ''' + Record the current stack and expression in the TracePrinter's history. + Pass this method as the ``viewer`` argument to the :py:func:`joy.joy.joy` function. + + :param stack quote: A stack. + :param stack expression: A stack. + ''' self.history.append((stack, expression)) def __str__(self): return '\n'.join(self.go()) def go(self): + ''' + Return a list of strings, one for each entry in the history, prefixed + with enough spaces to align all the interpreter dots. + + This method is called internally by the ``__str__()`` method. + + :rtype: list(str) + ''' max_stack_length = 0 lines = [] for stack, expression in self.history: diff --git a/joy/utils/stack.py b/joy/utils/stack.py index 478521d..6bcc5b4 100644 --- a/joy/utils/stack.py +++ b/joy/utils/stack.py @@ -18,12 +18,13 @@ # along with Thun. If not see . # ''' -When talking about Joy we use the terms "stack", "list", "sequence", -"quote" and others to mean the same thing: a simple linear datatype that +When talking about Joy we use the terms "stack", "quote", "sequence", +"list", and others to mean the same thing: a simple linear datatype that permits certain operations such as iterating and pushing and popping values from (at least) one end. -We use the `cons list`_, a venerable two-tuple recursive sequence datastructure, where the +There is no "Stack" Python class, instead we use the `cons list`_, a +venerable two-tuple recursive sequence datastructure, 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:: @@ -51,33 +52,36 @@ incoming tuple and assigning values to the names. (Note that Python syntax doesn't require parentheses around tuples used in expressions where they would be redundant.) +Unfortunately, the Sphinx documentation generator, which is used to generate this +web page, doesn't handle tuples in the function parameters. And in Python 3, this +syntax was removed entirely. Instead you would have to write:: + + def dup(stack): + head, tail = stack + return head, (head, tail) + + +We have two very simple functions, one to build up a stack from a Python +iterable and another to iterate through a stack and yield its items +one-by-one in order. There are also two functions to generate string representations +of stacks. They only differ in that one prints the terms in stack from left-to-right while the other prints from right-to-left. In both functions *internal stacks* are +printed left-to-right. These functions are written to support :doc:`../pretty`. + .. _cons list: https://en.wikipedia.org/wiki/Cons#Lists ''' -##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. - - def list_to_stack(el, stack=()): '''Convert a Python list (or other sequence) to a Joy stack:: [1, 2, 3] -> (1, (2, (3, ()))) + :param list el: A Python list or other sequence (iterators and generators + won't work because ``reverse()`` is called on ``el``.) + :param stack stack: A stack, optional, defaults to the empty stack. + :rtype: stack + ''' for item in reversed(el): stack = item, stack @@ -85,7 +89,11 @@ def list_to_stack(el, stack=()): def iter_stack(stack): - '''Iterate through the items on the stack.''' + '''Iterate through the items on the stack. + + :param stack stack: A stack. + :rtype: iterator + ''' while stack: item, stack = stack yield item @@ -98,6 +106,9 @@ def stack_to_string(stack): The items are written right-to-left:: (top, (second, ...)) -> '... second top' + + :param stack stack: A stack. + :rtype: str ''' f = lambda stack: reversed(list(iter_stack(stack))) return _to_string(stack, f) @@ -110,6 +121,9 @@ def expression_to_string(expression): The items are written left-to-right:: (top, (second, ...)) -> 'top second ...' + + :param stack expression: A stack. + :rtype: str ''' return _to_string(expression, iter_stack) @@ -132,7 +146,16 @@ def pushback(quote, expression): '''Concatinate quote onto expression. In joy [1 2] [3 4] would become [1 2 3 4]. + + :param stack quote: A stack. + :param stack expression: A stack. + :raises RuntimeError: if quote is larger than sys.getrecursionlimit(). + :rtype: stack ''' + # This is the fastest implementation, but will trigger + # RuntimeError: maximum recursion depth exceeded + # on quotes longer than sys.getrecursionlimit(). + return (quote[0], pushback(quote[1], expression)) if quote else expression # Original implementation. @@ -149,15 +172,17 @@ def pushback(quote, expression): ## expression = item, expression ## return expression - # This is the fastest, but will trigger - # RuntimeError: maximum recursion depth exceeded - # on quotes longer than sys.getrecursionlimit(). - return (quote[0], pushback(quote[1], expression)) if quote else expression def pick(s, n): ''' - Find the nth item on the stack. (Pick with zero is the same as "dup".) + Return the nth item on the stack. + + :param stack s: A stack. + :param int n: An index into the stack. + :raises ValueError: if ``n`` is less than zero. + :raises IndexError: if ``n`` is equal to or greater than the length of ``s``. + :rtype: whatever ''' if n < 0: raise ValueError