Switch back to spaces for indentation.
For better or worse, Python 3 won. No need to be shitty about it, eh?
This commit is contained in:
parent
6fc77a9a4a
commit
65b2b4a7e3
|
|
@ -26,10 +26,10 @@ from .utils.pretty_print import trace
|
||||||
inscribe(trace)
|
inscribe(trace)
|
||||||
|
|
||||||
if '-q' in sys.argv:
|
if '-q' in sys.argv:
|
||||||
j = interp
|
j = interp
|
||||||
else:
|
else:
|
||||||
j = repl
|
j = repl
|
||||||
print('''\
|
print('''\
|
||||||
Thun - Copyright © 2017 Simon Forman
|
Thun - Copyright © 2017 Simon Forman
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type "warranty".
|
This program comes with ABSOLUTELY NO WARRANTY; for details type "warranty".
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
|
|
|
||||||
163
joy/joy.py
163
joy/joy.py
|
|
@ -27,113 +27,118 @@ from builtins import input
|
||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
from .parser import text_to_expression, ParseError, Symbol
|
from .parser import text_to_expression, ParseError, Symbol
|
||||||
from .utils.stack import stack_to_string
|
from .utils.stack import stack_to_string
|
||||||
|
from .library import NotAnIntError, StackUnderflowError
|
||||||
|
|
||||||
|
|
||||||
class UnknownSymbolError(KeyError): pass
|
class UnknownSymbolError(KeyError): pass
|
||||||
|
|
||||||
|
|
||||||
def joy(stack, expression, dictionary, viewer=None):
|
def joy(stack, expression, dictionary, viewer=None):
|
||||||
'''Evaluate a Joy expression on a stack.
|
'''Evaluate a Joy expression on a stack.
|
||||||
|
|
||||||
This function iterates through a sequence of terms which are either
|
This function iterates through a sequence of terms which are either
|
||||||
literals (strings, numbers, sequences of terms) or function symbols.
|
literals (strings, numbers, sequences of terms) or function symbols.
|
||||||
Literals are put onto the stack and functions are looked up in the
|
Literals are put onto the stack and functions are looked up in the
|
||||||
dictionary and executed.
|
dictionary and executed.
|
||||||
|
|
||||||
The viewer is a function that is called with the stack and expression
|
The viewer is a function that is called with the stack and expression
|
||||||
on every iteration, its return value is ignored.
|
on every iteration, its return value is ignored.
|
||||||
|
|
||||||
:param stack stack: The stack.
|
:param stack stack: The stack.
|
||||||
:param stack expression: The expression to evaluate.
|
:param stack expression: The expression to evaluate.
|
||||||
:param dict dictionary: A ``dict`` mapping names to Joy functions.
|
:param dict dictionary: A ``dict`` mapping names to Joy functions.
|
||||||
:param function viewer: Optional viewer function.
|
:param function viewer: Optional viewer function.
|
||||||
:rtype: (stack, (), dictionary)
|
:rtype: (stack, (), dictionary)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
while expression:
|
while expression:
|
||||||
|
|
||||||
if viewer: viewer(stack, expression)
|
if viewer: viewer(stack, expression)
|
||||||
|
|
||||||
term, expression = expression
|
term, expression = expression
|
||||||
if isinstance(term, Symbol):
|
if isinstance(term, Symbol):
|
||||||
try:
|
try:
|
||||||
term = dictionary[term]
|
term = dictionary[term]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise UnknownSymbolError(term)
|
raise UnknownSymbolError(term)
|
||||||
stack, expression, dictionary = term(stack, expression, dictionary)
|
stack, expression, dictionary = term(stack, expression, dictionary)
|
||||||
else:
|
else:
|
||||||
stack = term, stack
|
stack = term, stack
|
||||||
|
|
||||||
if viewer: viewer(stack, expression)
|
if viewer: viewer(stack, expression)
|
||||||
return stack, expression, dictionary
|
return stack, expression, dictionary
|
||||||
|
|
||||||
|
|
||||||
def run(text, stack, dictionary, viewer=None):
|
def run(text, stack, dictionary, viewer=None):
|
||||||
'''
|
'''
|
||||||
Return the stack resulting from running the Joy code text on the stack.
|
Return the stack resulting from running the Joy code text on the stack.
|
||||||
|
|
||||||
:param str text: Joy code.
|
:param str text: Joy code.
|
||||||
:param stack stack: The stack.
|
:param stack stack: The stack.
|
||||||
:param dict dictionary: A ``dict`` mapping names to Joy functions.
|
:param dict dictionary: A ``dict`` mapping names to Joy functions.
|
||||||
:param function viewer: Optional viewer function.
|
:param function viewer: Optional viewer function.
|
||||||
:rtype: (stack, (), dictionary)
|
:rtype: (stack, (), dictionary)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
expression = text_to_expression(text)
|
expression = text_to_expression(text)
|
||||||
return joy(stack, expression, dictionary, viewer)
|
return joy(stack, expression, dictionary, viewer)
|
||||||
|
|
||||||
|
|
||||||
def repl(stack=(), dictionary=None):
|
def repl(stack=(), dictionary=None):
|
||||||
'''
|
'''
|
||||||
Read-Evaluate-Print Loop
|
Read-Evaluate-Print Loop
|
||||||
|
|
||||||
Accept input and run it on the stack, loop.
|
Accept input and run it on the stack, loop.
|
||||||
|
|
||||||
:param stack stack: The stack.
|
:param stack stack: The stack.
|
||||||
:param dict dictionary: A ``dict`` mapping names to Joy functions.
|
:param dict dictionary: A ``dict`` mapping names to Joy functions.
|
||||||
:rtype: stack
|
:rtype: stack
|
||||||
|
|
||||||
'''
|
'''
|
||||||
if dictionary is None:
|
if dictionary is None:
|
||||||
dictionary = {}
|
dictionary = {}
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
print()
|
print()
|
||||||
print(stack_to_string(stack), '<-top')
|
print(stack_to_string(stack), '<-top')
|
||||||
print()
|
print()
|
||||||
try:
|
try:
|
||||||
text = input('joy? ')
|
text = input('joy? ')
|
||||||
except (EOFError, KeyboardInterrupt):
|
except (EOFError, KeyboardInterrupt):
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
stack, _, dictionary = run(text, stack, dictionary)
|
stack, _, dictionary = run(text, stack, dictionary)
|
||||||
except:
|
except:
|
||||||
print_exc()
|
print_exc()
|
||||||
except:
|
except:
|
||||||
print_exc()
|
print_exc()
|
||||||
print()
|
print()
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
|
|
||||||
def interp(stack=(), dictionary=None):
|
def interp(stack=(), dictionary=None):
|
||||||
'''
|
'''
|
||||||
Simple REPL with no extra output, suitable for use in scripts.
|
Simple REPL with no extra output, suitable for use in scripts.
|
||||||
'''
|
'''
|
||||||
if dictionary is None:
|
if dictionary is None:
|
||||||
dictionary = {}
|
dictionary = {}
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
text = input()
|
text = input()
|
||||||
except (EOFError, KeyboardInterrupt):
|
except (EOFError, KeyboardInterrupt):
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
stack, _, dictionary = run(text, stack, dictionary)
|
stack, _, dictionary = run(text, stack, dictionary)
|
||||||
except UnknownSymbolError as sym:
|
except UnknownSymbolError as sym:
|
||||||
print('Unknown:', sym)
|
print('Unknown:', sym)
|
||||||
except:
|
except StackUnderflowError:
|
||||||
print_exc()
|
print('Not enough values on stack.')
|
||||||
print(stack_to_string(stack))
|
except NotAnIntError:
|
||||||
except:
|
print('Not an integer.')
|
||||||
print_exc()
|
except:
|
||||||
return stack
|
print_exc()
|
||||||
|
print(stack_to_string(stack))
|
||||||
|
except:
|
||||||
|
print_exc()
|
||||||
|
return stack
|
||||||
|
|
|
||||||
1529
joy/library.py
1529
joy/library.py
File diff suppressed because it is too large
Load Diff
104
joy/parser.py
104
joy/parser.py
|
|
@ -53,71 +53,71 @@ token_scanner = Scanner([
|
||||||
|
|
||||||
|
|
||||||
class Symbol(str):
|
class Symbol(str):
|
||||||
'''A string class that represents Joy function names.'''
|
'''A string class that represents Joy function names.'''
|
||||||
__repr__ = str.__str__
|
__repr__ = str.__str__
|
||||||
|
|
||||||
|
|
||||||
def text_to_expression(text):
|
def text_to_expression(text):
|
||||||
'''Convert a string to a Joy expression.
|
'''Convert a string to a Joy expression.
|
||||||
|
|
||||||
When supplied with a string this function returns a Python datastructure
|
When supplied with a string this function returns a Python datastructure
|
||||||
that represents the Joy datastructure described by the text expression.
|
that represents the Joy datastructure described by the text expression.
|
||||||
Any unbalanced square brackets will raise a ParseError.
|
Any unbalanced square brackets will raise a ParseError.
|
||||||
|
|
||||||
:param str text: Text to convert.
|
:param str text: Text to convert.
|
||||||
:rtype: stack
|
:rtype: stack
|
||||||
:raises ParseError: if the parse fails.
|
:raises ParseError: if the parse fails.
|
||||||
'''
|
'''
|
||||||
return _parse(_tokenize(text))
|
return _parse(_tokenize(text))
|
||||||
|
|
||||||
|
|
||||||
class ParseError(ValueError):
|
class ParseError(ValueError):
|
||||||
'''Raised when there is a error while parsing text.'''
|
'''Raised when there is a error while parsing text.'''
|
||||||
|
|
||||||
|
|
||||||
def _tokenize(text):
|
def _tokenize(text):
|
||||||
'''Convert a text into a stream of tokens.
|
'''Convert a text into a stream of tokens.
|
||||||
|
|
||||||
Converts function names to Symbols.
|
Converts function names to Symbols.
|
||||||
|
|
||||||
Raise ParseError (with some of the failing text) if the scan fails.
|
Raise ParseError (with some of the failing text) if the scan fails.
|
||||||
'''
|
'''
|
||||||
tokens, rest = token_scanner.scan(text)
|
tokens, rest = token_scanner.scan(text)
|
||||||
if rest:
|
if rest:
|
||||||
raise ParseError(
|
raise ParseError(
|
||||||
'Scan failed at position %i, %r'
|
'Scan failed at position %i, %r'
|
||||||
% (len(text) - len(rest), rest[:10])
|
% (len(text) - len(rest), rest[:10])
|
||||||
)
|
)
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
def _parse(tokens):
|
def _parse(tokens):
|
||||||
'''
|
'''
|
||||||
Return a stack/list expression of the tokens.
|
Return a stack/list expression of the tokens.
|
||||||
'''
|
'''
|
||||||
frame = []
|
frame = []
|
||||||
stack = []
|
stack = []
|
||||||
for tok in tokens:
|
for tok in tokens:
|
||||||
if tok == '[':
|
if tok == '[':
|
||||||
stack.append(frame)
|
stack.append(frame)
|
||||||
frame = []
|
frame = []
|
||||||
stack[-1].append(frame)
|
stack[-1].append(frame)
|
||||||
elif tok == ']':
|
elif tok == ']':
|
||||||
try:
|
try:
|
||||||
frame = stack.pop()
|
frame = stack.pop()
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise ParseError('Extra closing bracket.')
|
raise ParseError('Extra closing bracket.')
|
||||||
frame[-1] = list_to_stack(frame[-1])
|
frame[-1] = list_to_stack(frame[-1])
|
||||||
elif tok == 'true':
|
elif tok == 'true':
|
||||||
frame.append(True)
|
frame.append(True)
|
||||||
elif tok == 'false':
|
elif tok == 'false':
|
||||||
frame.append(False)
|
frame.append(False)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
thing = int(tok)
|
thing = int(tok)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
thing = Symbol(tok)
|
thing = Symbol(tok)
|
||||||
frame.append(thing)
|
frame.append(thing)
|
||||||
if stack:
|
if stack:
|
||||||
raise ParseError('Unclosed bracket.')
|
raise ParseError('Unclosed bracket.')
|
||||||
return list_to_stack(frame)
|
return list_to_stack(frame)
|
||||||
|
|
|
||||||
|
|
@ -46,79 +46,79 @@ from ..library import FunctionWrapper
|
||||||
|
|
||||||
@FunctionWrapper
|
@FunctionWrapper
|
||||||
def trace(stack, expression, dictionary):
|
def trace(stack, expression, dictionary):
|
||||||
'''Evaluate a Joy expression on a stack and print a trace.
|
'''Evaluate a Joy expression on a stack and print a trace.
|
||||||
|
|
||||||
This function is just like the `i` combinator but it also prints a
|
This function is just like the `i` combinator but it also prints a
|
||||||
trace of the evaluation
|
trace of the evaluation
|
||||||
|
|
||||||
:param stack stack: The stack.
|
:param stack stack: The stack.
|
||||||
:param stack expression: The expression to evaluate.
|
:param stack expression: The expression to evaluate.
|
||||||
:param dict dictionary: A ``dict`` mapping names to Joy functions.
|
:param dict dictionary: A ``dict`` mapping names to Joy functions.
|
||||||
:rtype: (stack, (), dictionary)
|
:rtype: (stack, (), dictionary)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
tp = TracePrinter()
|
tp = TracePrinter()
|
||||||
quote, stack = stack
|
quote, stack = stack
|
||||||
try:
|
try:
|
||||||
s, _, d = joy(stack, quote, dictionary, tp.viewer)
|
s, _, d = joy(stack, quote, dictionary, tp.viewer)
|
||||||
except:
|
except:
|
||||||
tp.print_()
|
tp.print_()
|
||||||
print('-' * 73)
|
print('-' * 73)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
tp.print_()
|
tp.print_()
|
||||||
return s, expression, d
|
return s, expression, d
|
||||||
|
|
||||||
|
|
||||||
class TracePrinter(object):
|
class TracePrinter(object):
|
||||||
'''
|
'''
|
||||||
This is what does the formatting. You instantiate it and pass the ``viewer()``
|
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
|
method to the :py:func:`joy.joy.joy` function, then print it to see the
|
||||||
trace.
|
trace.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.history = []
|
self.history = []
|
||||||
|
|
||||||
def viewer(self, stack, expression):
|
def viewer(self, stack, expression):
|
||||||
'''
|
'''
|
||||||
Record the current stack and expression in the TracePrinter's history.
|
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.
|
Pass this method as the ``viewer`` argument to the :py:func:`joy.joy.joy` function.
|
||||||
|
|
||||||
:param stack quote: A stack.
|
:param stack quote: A stack.
|
||||||
:param stack expression: A stack.
|
:param stack expression: A stack.
|
||||||
'''
|
'''
|
||||||
self.history.append((stack, expression))
|
self.history.append((stack, expression))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '\n'.join(self.go())
|
return '\n'.join(self.go())
|
||||||
|
|
||||||
def go(self):
|
def go(self):
|
||||||
'''
|
'''
|
||||||
Return a list of strings, one for each entry in the history, prefixed
|
Return a list of strings, one for each entry in the history, prefixed
|
||||||
with enough spaces to align all the interpreter dots.
|
with enough spaces to align all the interpreter dots.
|
||||||
|
|
||||||
This method is called internally by the ``__str__()`` method.
|
This method is called internally by the ``__str__()`` method.
|
||||||
|
|
||||||
:rtype: list(str)
|
:rtype: list(str)
|
||||||
'''
|
'''
|
||||||
max_stack_length = 0
|
max_stack_length = 0
|
||||||
lines = []
|
lines = []
|
||||||
for stack, expression in self.history:
|
for stack, expression in self.history:
|
||||||
stack = stack_to_string(stack)
|
stack = stack_to_string(stack)
|
||||||
expression = expression_to_string(expression)
|
expression = expression_to_string(expression)
|
||||||
n = len(stack)
|
n = len(stack)
|
||||||
if n > max_stack_length:
|
if n > max_stack_length:
|
||||||
max_stack_length = n
|
max_stack_length = n
|
||||||
lines.append((n, '%s • %s' % (stack, expression)))
|
lines.append((n, '%s • %s' % (stack, expression)))
|
||||||
for i in range(len(lines)): # Prefix spaces to line up '•'s.
|
for i in range(len(lines)): # Prefix spaces to line up '•'s.
|
||||||
length, line = lines[i]
|
length, line = lines[i]
|
||||||
lines[i] = (' ' * (max_stack_length - length) + line)
|
lines[i] = (' ' * (max_stack_length - length) + line)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def print_(self):
|
def print_(self):
|
||||||
try:
|
try:
|
||||||
print(self)
|
print(self)
|
||||||
except:
|
except:
|
||||||
print_exc()
|
print_exc()
|
||||||
print('Exception while printing viewer.')
|
print('Exception while printing viewer.')
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ means we can directly "unpack" the expected arguments to a Joy function.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
def dup((head, tail)):
|
def dup((head, tail)):
|
||||||
return head, (head, tail)
|
return head, (head, tail)
|
||||||
|
|
||||||
We replace the argument "stack" by the expected structure of the stack,
|
We replace the argument "stack" by the expected structure of the stack,
|
||||||
in this case "(head, tail)", and Python takes care of unpacking the
|
in this case "(head, tail)", and Python takes care of unpacking the
|
||||||
|
|
@ -56,9 +56,9 @@ Unfortunately, the Sphinx documentation generator, which is used to generate thi
|
||||||
web page, doesn't handle tuples in the function parameters. And in Python 3, 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::
|
syntax was removed entirely. Instead you would have to write::
|
||||||
|
|
||||||
def dup(stack):
|
def dup(stack):
|
||||||
head, tail = stack
|
head, tail = stack
|
||||||
return head, (head, tail)
|
return head, (head, tail)
|
||||||
|
|
||||||
|
|
||||||
We have two very simple functions, one to build up a stack from a Python
|
We have two very simple functions, one to build up a stack from a Python
|
||||||
|
|
@ -73,59 +73,59 @@ printed left-to-right. These functions are written to support :doc:`../pretty`.
|
||||||
|
|
||||||
|
|
||||||
def list_to_stack(el, stack=()):
|
def list_to_stack(el, stack=()):
|
||||||
'''Convert a Python list (or other sequence) to a Joy stack::
|
'''Convert a Python list (or other sequence) to a Joy stack::
|
||||||
|
|
||||||
[1, 2, 3] -> (1, (2, (3, ())))
|
[1, 2, 3] -> (1, (2, (3, ())))
|
||||||
|
|
||||||
:param list el: A Python list or other sequence (iterators and generators
|
:param list el: A Python list or other sequence (iterators and generators
|
||||||
won't work because ``reverse()`` is called on ``el``.)
|
won't work because ``reverse()`` is called on ``el``.)
|
||||||
:param stack stack: A stack, optional, defaults to the empty stack.
|
:param stack stack: A stack, optional, defaults to the empty stack.
|
||||||
:rtype: stack
|
:rtype: stack
|
||||||
|
|
||||||
'''
|
'''
|
||||||
for item in reversed(el):
|
for item in reversed(el):
|
||||||
stack = item, stack
|
stack = item, stack
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
|
|
||||||
def iter_stack(stack):
|
def iter_stack(stack):
|
||||||
'''Iterate through the items on the stack.
|
'''Iterate through the items on the stack.
|
||||||
|
|
||||||
:param stack stack: A stack.
|
:param stack stack: A stack.
|
||||||
:rtype: iterator
|
:rtype: iterator
|
||||||
'''
|
'''
|
||||||
while stack:
|
while stack:
|
||||||
item, stack = stack
|
item, stack = stack
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
|
|
||||||
def stack_to_string(stack):
|
def stack_to_string(stack):
|
||||||
'''
|
'''
|
||||||
Return a "pretty print" string for a stack.
|
Return a "pretty print" string for a stack.
|
||||||
|
|
||||||
The items are written right-to-left::
|
The items are written right-to-left::
|
||||||
|
|
||||||
(top, (second, ...)) -> '... second top'
|
(top, (second, ...)) -> '... second top'
|
||||||
|
|
||||||
:param stack stack: A stack.
|
:param stack stack: A stack.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
'''
|
'''
|
||||||
f = lambda stack: reversed(list(iter_stack(stack)))
|
f = lambda stack: reversed(list(iter_stack(stack)))
|
||||||
return _to_string(stack, f)
|
return _to_string(stack, f)
|
||||||
|
|
||||||
|
|
||||||
def expression_to_string(expression):
|
def expression_to_string(expression):
|
||||||
'''
|
'''
|
||||||
Return a "pretty print" string for a expression.
|
Return a "pretty print" string for a expression.
|
||||||
|
|
||||||
The items are written left-to-right::
|
The items are written left-to-right::
|
||||||
|
|
||||||
(top, (second, ...)) -> 'top second ...'
|
(top, (second, ...)) -> 'top second ...'
|
||||||
|
|
||||||
:param stack expression: A stack.
|
:param stack expression: A stack.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
'''
|
'''
|
||||||
return _to_string(expression, iter_stack)
|
return _to_string(expression, iter_stack)
|
||||||
|
|
||||||
|
|
||||||
_JOY_BOOL_LITS = 'false', 'true'
|
_JOY_BOOL_LITS = 'false', 'true'
|
||||||
|
|
@ -138,40 +138,40 @@ def _joy_repr(thing):
|
||||||
|
|
||||||
|
|
||||||
def _to_string(stack, f):
|
def _to_string(stack, f):
|
||||||
if not isinstance(stack, tuple): return _joy_repr(stack)
|
if not isinstance(stack, tuple): return _joy_repr(stack)
|
||||||
if not stack: return '' # shortcut
|
if not stack: return '' # shortcut
|
||||||
return ' '.join(map(_s, f(stack)))
|
return ' '.join(map(_s, f(stack)))
|
||||||
|
|
||||||
|
|
||||||
_s = lambda s: (
|
_s = lambda s: (
|
||||||
'[%s]' % expression_to_string(s)
|
'[%s]' % expression_to_string(s)
|
||||||
if isinstance(s, tuple)
|
if isinstance(s, tuple)
|
||||||
else _joy_repr(s)
|
else _joy_repr(s)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def concat(quote, expression):
|
def concat(quote, expression):
|
||||||
'''Concatinate quote onto expression.
|
'''Concatinate quote onto expression.
|
||||||
|
|
||||||
In joy [1 2] [3 4] would become [1 2 3 4].
|
In joy [1 2] [3 4] would become [1 2 3 4].
|
||||||
|
|
||||||
:param stack quote: A stack.
|
:param stack quote: A stack.
|
||||||
:param stack expression: A stack.
|
:param stack expression: A stack.
|
||||||
:raises RuntimeError: if quote is larger than sys.getrecursionlimit().
|
:raises RuntimeError: if quote is larger than sys.getrecursionlimit().
|
||||||
:rtype: stack
|
:rtype: stack
|
||||||
'''
|
'''
|
||||||
# This is the fastest implementation, but will trigger
|
# This is the fastest implementation, but will trigger
|
||||||
# RuntimeError: maximum recursion depth exceeded
|
# RuntimeError: maximum recursion depth exceeded
|
||||||
# on quotes longer than sys.getrecursionlimit().
|
# on quotes longer than sys.getrecursionlimit().
|
||||||
|
|
||||||
return (quote[0], concat(quote[1], expression)) if quote else expression
|
return (quote[0], concat(quote[1], expression)) if quote else expression
|
||||||
|
|
||||||
# Original implementation.
|
# Original implementation.
|
||||||
|
|
||||||
## return list_to_stack(list(iter_stack(quote)), expression)
|
## return list_to_stack(list(iter_stack(quote)), expression)
|
||||||
|
|
||||||
# In-lining is slightly faster (and won't break the
|
# In-lining is slightly faster (and won't break the
|
||||||
# recursion limit on long quotes.)
|
# recursion limit on long quotes.)
|
||||||
|
|
||||||
## temp = []
|
## temp = []
|
||||||
## while quote:
|
## while quote:
|
||||||
|
|
@ -184,67 +184,67 @@ def concat(quote, expression):
|
||||||
|
|
||||||
|
|
||||||
def dnd(stack, from_index, to_index):
|
def dnd(stack, from_index, to_index):
|
||||||
'''
|
'''
|
||||||
Given a stack and two indices return a rearranged stack.
|
Given a stack and two indices return a rearranged stack.
|
||||||
First remove the item at from_index and then insert it at to_index,
|
First remove the item at from_index and then insert it at to_index,
|
||||||
the second index is relative to the stack after removal of the item
|
the second index is relative to the stack after removal of the item
|
||||||
at from_index.
|
at from_index.
|
||||||
|
|
||||||
This function reuses all of the items and as much of the stack as it
|
This function reuses all of the items and as much of the stack as it
|
||||||
can. It's meant to be used by remote clients to support drag-n-drop
|
can. It's meant to be used by remote clients to support drag-n-drop
|
||||||
rearranging of the stack from e.g. the StackListbox.
|
rearranging of the stack from e.g. the StackListbox.
|
||||||
'''
|
'''
|
||||||
assert 0 <= from_index
|
assert 0 <= from_index
|
||||||
assert 0 <= to_index
|
assert 0 <= to_index
|
||||||
if from_index == to_index:
|
if from_index == to_index:
|
||||||
return stack
|
return stack
|
||||||
head, n = [], from_index
|
head, n = [], from_index
|
||||||
while True:
|
while True:
|
||||||
item, stack = stack
|
item, stack = stack
|
||||||
n -= 1
|
n -= 1
|
||||||
if n < 0:
|
if n < 0:
|
||||||
break
|
break
|
||||||
head.append(item)
|
head.append(item)
|
||||||
assert len(head) == from_index
|
assert len(head) == from_index
|
||||||
# now we have two cases:
|
# now we have two cases:
|
||||||
diff = from_index - to_index
|
diff = from_index - to_index
|
||||||
if diff < 0:
|
if diff < 0:
|
||||||
# from < to
|
# from < to
|
||||||
# so the destination index is still in the stack
|
# so the destination index is still in the stack
|
||||||
while diff:
|
while diff:
|
||||||
h, stack = stack
|
h, stack = stack
|
||||||
head.append(h)
|
head.append(h)
|
||||||
diff += 1
|
diff += 1
|
||||||
else:
|
else:
|
||||||
# from > to
|
# from > to
|
||||||
# so the destination is in the head list
|
# so the destination is in the head list
|
||||||
while diff:
|
while diff:
|
||||||
stack = head.pop(), stack
|
stack = head.pop(), stack
|
||||||
diff -= 1
|
diff -= 1
|
||||||
stack = item, stack
|
stack = item, stack
|
||||||
while head:
|
while head:
|
||||||
stack = head.pop(), stack
|
stack = head.pop(), stack
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
|
|
||||||
def pick(stack, n):
|
def pick(stack, n):
|
||||||
'''
|
'''
|
||||||
Return the nth item on the stack.
|
Return the nth item on the stack.
|
||||||
|
|
||||||
:param stack stack: A stack.
|
:param stack stack: A stack.
|
||||||
:param int n: An index into the stack.
|
:param int n: An index into the stack.
|
||||||
:raises ValueError: if ``n`` is less than zero.
|
:raises ValueError: if ``n`` is less than zero.
|
||||||
:raises IndexError: if ``n`` is equal to or greater than the length of ``stack``.
|
:raises IndexError: if ``n`` is equal to or greater than the length of ``stack``.
|
||||||
:rtype: whatever
|
:rtype: whatever
|
||||||
'''
|
'''
|
||||||
if n < 0:
|
if n < 0:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
item, stack = stack
|
item, stack = stack
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise IndexError
|
raise IndexError
|
||||||
n -= 1
|
n -= 1
|
||||||
if n < 0:
|
if n < 0:
|
||||||
break
|
break
|
||||||
return item
|
return item
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue