diff --git a/docs/sphinx_docs/_build/html/_modules/joy/joy.html b/docs/sphinx_docs/_build/html/_modules/joy/joy.html new file mode 100644 index 0000000..6032ecf --- /dev/null +++ b/docs/sphinx_docs/_build/html/_modules/joy/joy.html @@ -0,0 +1,183 @@ + + + + + + + + joy.joy — Thun 0.1.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for joy.joy

+# -*- coding: utf-8 -*-
+#
+#    Copyright © 2014, 2015, 2017, 2018 Simon Forman
+#
+#    This file is part of Thun
+#
+#    Thun 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.
+#
+#    Thun 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 Thun.  If not see <http://www.gnu.org/licenses/>.
+#
+'''
+This module implements an interpreter for a dialect of Joy that
+attempts to stay very close to the spirit of Joy but does not precisely
+match the behaviour of the original version(s) written in C.
+
+'''
+from __future__ import print_function
+try:
+  input = raw_input
+except NameError:
+  pass
+from traceback import print_exc, format_exc
+from .parser import text_to_expression, ParseError, Symbol
+from .utils.stack import stack_to_string
+from .utils.pretty_print import TracePrinter
+
+
+
[docs]def joy(stack, expression, dictionary, viewer=None): + '''Evaluate the Joy expression on the stack. + + The basic joy() function is quite straightforward. It iterates through a + sequence of terms which are either literals (strings, numbers, sequences) + 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 function viewer: Optional viewer function. + + ''' + while expression: + + if viewer: viewer(stack, expression) + + term, expression = expression + if isinstance(term, Symbol): + term = dictionary[term] + stack, expression, dictionary = term(stack, expression, dictionary) + else: + stack = term, stack + + if viewer: viewer(stack, expression) + return stack, expression, dictionary
+ + +
[docs]def run(text, stack, dictionary, viewer=None): + ''' + Return the stack resulting from running the Joy code text on the stack. + ''' + expression = text_to_expression(text) + return joy(stack, expression, dictionary, viewer)
+ + +
[docs]def repl(stack=(), dictionary=None): + ''' + Read-Evaluate-Print Loop + + Accept input and run it on the stack, loop. + ''' + if dictionary is None: + dictionary = {} + try: + while True: + print() + print(stack_to_string(stack), '<-top') + print() + try: + text = input('joy? ') + except (EOFError, KeyboardInterrupt): + break + viewer = TracePrinter() + try: + stack, _, dictionary = run(text, stack, dictionary, viewer.viewer) + except: + exc = format_exc() # Capture the exception. + viewer.print_() # Print the Joy trace. + print('-' * 73) + print(exc) # Print the original exception. + else: + viewer.print_() + except: + print_exc() + print() + return stack
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/library.html b/docs/sphinx_docs/_build/html/_modules/joy/library.html new file mode 100644 index 0000000..c337ac9 --- /dev/null +++ b/docs/sphinx_docs/_build/html/_modules/joy/library.html @@ -0,0 +1,1515 @@ + + + + + + + + joy.library — Thun 0.1.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for joy.library

+# -*- coding: utf-8 -*-
+#
+#    Copyright © 2014, 2015, 2017, 2018 Simon Forman
+#
+#    This file is part of Thun
+#
+#    Thun 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.
+#
+#    Thun 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 Thun.  If not see <http://www.gnu.org/licenses/>. 
+#
+'''
+This module contains the Joy function infrastructure and a library of
+functions.  Its main export is a Python function initialize() that
+returns a dictionary of Joy functions suitable for use with the joy()
+function.
+'''
+from inspect import getdoc
+from functools import wraps
+import operator, math
+
+from .parser import text_to_expression, Symbol
+from .utils.stack import list_to_stack, iter_stack, pick, pushback
+from .utils.brutal_hackery import rename_code_object
+
+
+_dictionary = {}
+
+
+
[docs]def inscribe(function): + '''A decorator to inscribe functions into the default dictionary.''' + _dictionary[function.name] = function + return function
+ + +
[docs]def initialize(): + '''Return a dictionary of Joy functions for use with joy().''' + return _dictionary.copy()
+ + +ALIASES = ( + ('add', ['+']), + ('and', ['&']), + ('bool', ['truthy']), + ('mul', ['*']), + ('truediv', ['/']), + ('mod', ['%', 'rem', 'remainder', 'modulus']), + ('eq', ['=']), + ('ge', ['>=']), + ('getitem', ['pick', 'at']), + ('gt', ['>']), + ('le', ['<=']), + ('lshift', ['<<']), + ('lt', ['<']), + ('ne', ['<>', '!=']), + ('rshift', ['>>']), + ('sub', ['-']), + ('xor', ['^']), + ('succ', ['++']), + ('pred', ['--']), + ('rolldown', ['roll<']), + ('rollup', ['roll>']), + ('id', ['•']), + ) + + +
[docs]def add_aliases(D, A): + ''' + Given a dict and a iterable of (name, [alias, ...]) pairs, create + additional entries in the dict mapping each alias to the named function + if it's in the dict. Aliases for functions not in the dict are ignored. + ''' + for name, aliases in A: + try: + F = D[name] + except KeyError: + continue + for alias in aliases: + D[alias] = F
+ + +definitions = ('''\ +second == rest first +third == rest rest first +of == swap at +product == 1 swap [*] step +swons == swap cons +swoncat == swap concat +flatten == [] swap [concat] step +unit == [] cons +quoted == [unit] dip +unquoted == [i] dip +enstacken == stack [clear] dip +disenstacken == ? [uncons ?] loop pop +? == dup truthy +dinfrirst == dip infra first +nullary == [stack] dinfrirst +unary == [stack [pop] dip] dinfrirst +binary == [stack [popop] dip] dinfrirst +ternary == [stack [popop pop] dip] dinfrirst +pam == [i] map +run == [] swap infra +sqr == dup mul +size == 0 swap [pop ++] step +cleave == [i] app2 [popd] dip +average == [sum 1.0 *] [size] cleave / +gcd == 1 [tuck modulus dup 0 >] loop pop +least_fraction == dup [gcd] infra [div] concat map +*fraction == [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons +*fraction0 == concat [[swap] dip * [*] dip] infra +down_to_zero == [0 >] [dup --] while +range_to_zero == unit [down_to_zero] infra +anamorphism == [pop []] swap [dip swons] genrec +range == [0 <=] [1 - dup] anamorphism +while == swap [nullary] cons dup dipd concat loop +dudipd == dup dipd +primrec == [i] genrec +step_zero == 0 roll> step +''' + +##Zipper +##z-down == [] swap uncons swap +##z-up == swons swap shunt +##z-right == [swons] cons dip uncons swap +##z-left == swons [uncons swap] dip swap + +##Quadratic Formula +##divisor == popop 2 * +##minusb == pop neg +##radical == swap dup * rollup * 4 * - sqrt +##root1 == + swap / +##root2 == - swap / +##q0 == [[divisor] [minusb] [radical]] pam +##q1 == [[root1] [root2]] pam +##quadratic == [q0] ternary i [q1] ternary + +# Project Euler +##'''\ +##PE1.1 == + dup [+] dip +##PE1.2 == dup [3 & PE1.1] dip 2 >> +##PE1.3 == 14811 swap [PE1.2] times pop +##PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop +##''' +#PE1.2 == [PE1.1] step +#PE1 == 0 0 66 [[3 2 1 3 1 2 3] PE1.2] times [3 2 1 3] PE1.2 pop +) + + +
[docs]def FunctionWrapper(f): + '''Set name attribute.''' + if not f.__doc__: + raise ValueError('Function %s must have doc string.' % f.__name__) + f.name = f.__name__.rstrip('_') # Don't shadow builtins. + return f
+ + +
[docs]def SimpleFunctionWrapper(f): + ''' + Wrap functions that take and return just a stack. + ''' + @FunctionWrapper + @wraps(f) + @rename_code_object(f.__name__) + def inner(stack, expression, dictionary): + return f(stack), expression, dictionary + return inner
+ + +
[docs]def BinaryBuiltinWrapper(f): + ''' + Wrap functions that take two arguments and return a single result. + ''' + @FunctionWrapper + @wraps(f) + @rename_code_object(f.__name__) + def inner(stack, expression, dictionary): + (a, (b, stack)) = stack + result = f(b, a) + return (result, stack), expression, dictionary + return inner
+ + +
[docs]def UnaryBuiltinWrapper(f): + ''' + Wrap functions that take one argument and return a single result. + ''' + @FunctionWrapper + @wraps(f) + @rename_code_object(f.__name__) + def inner(stack, expression, dictionary): + (a, stack) = stack + result = f(a) + return (result, stack), expression, dictionary + return inner
+ + +
[docs]class DefinitionWrapper(object): + ''' + Provide implementation of defined functions, and some helper methods. + ''' + + def __init__(self, name, body_text, doc=None): + self.name = self.__name__ = name + self.body = text_to_expression(body_text) + self._body = tuple(iter_stack(self.body)) + self.__doc__ = doc or body_text + + def __call__(self, stack, expression, dictionary): + expression = list_to_stack(self._body, expression) + return stack, expression, dictionary + +
[docs] @classmethod + def parse_definition(class_, defi): + ''' + Given some text describing a Joy function definition parse it and + return a DefinitionWrapper. + ''' + name, proper, body_text = (n.strip() for n in defi.partition('==')) + if not proper: + raise ValueError('Definition %r failed' % (defi,)) + return class_(name, body_text)
+ +
[docs] @classmethod + def add_definitions(class_, defs, dictionary): + ''' + Scan multi-line string defs for definitions and add them to the + dictionary. + ''' + for definition in _text_to_defs(defs): + class_.add_def(definition, dictionary)
+ +
[docs] @classmethod + def add_def(class_, definition, dictionary): + ''' + Add the definition to the dictionary. + ''' + F = class_.parse_definition(definition) + dictionary[F.name] = F
+ + +def _text_to_defs(text): + return (line.strip() for line in text.splitlines() if '==' in line) + + +# +# Functions +# + + +
[docs]@inscribe +@SimpleFunctionWrapper +def parse(stack): + '''Parse the string on the stack to a Joy expression.''' + text, stack = stack + expression = text_to_expression(text) + return expression, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def first(stack): + ''' + :: + + first == uncons pop + + ''' + ((head, tail), stack) = stack + return head, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def rest(stack): + ''' + :: + + rest == uncons popd + + ''' + ((head, tail), stack) = stack + return tail, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def getitem(stack): + ''' + :: + + getitem == drop first + + Expects an integer and a quote on the stack and returns the item at the + nth position in the quote counting from 0. + :: + + [a b c d] 0 getitem + ------------------------- + a + + ''' + n, (Q, stack) = stack + return pick(Q, n), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def drop(stack): + ''' + :: + + drop == [rest] times + + Expects an integer and a quote on the stack and returns the quote with + n items removed off the top. + :: + + [a b c d] 2 drop + ---------------------- + [c d] + + ''' + n, (Q, stack) = stack + while n > 0: + try: + _, Q = Q + except ValueError: + raise IndexError + n -= 1 + return Q, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def take(stack): + ''' + Expects an integer and a quote on the stack and returns the quote with + just the top n items in reverse order (because that's easier and you can + use reverse if needed.) + :: + + [a b c d] 2 take + ---------------------- + [b a] + + ''' + n, (Q, stack) = stack + x = () + while n > 0: + try: + item, Q = Q + except ValueError: + raise IndexError + x = item, x + n -= 1 + return x, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def choice(stack): + ''' + Use a Boolean value to select one of two items. + :: + + A B False choice + ---------------------- + A + + + A B True choice + --------------------- + B + + Currently Python semantics are used to evaluate the "truthiness" of the + Boolean value (so empty string, zero, etc. are counted as false, etc.) + ''' + (if_, (then, (else_, stack))) = stack + return then if if_ else else_, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def select(stack): + ''' + Use a Boolean value to select one of two items from a sequence. + :: + + [A B] False select + ------------------------ + A + + + [A B] True select + ----------------------- + B + + The sequence can contain more than two items but not fewer. + Currently Python semantics are used to evaluate the "truthiness" of the + Boolean value (so empty string, zero, etc. are counted as false, etc.) + ''' + (flag, (choices, stack)) = stack + (else_, (then, _)) = choices + return then if flag else else_, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def max_(S): + '''Given a list find the maximum.''' + tos, stack = S + return max(iter_stack(tos)), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def min_(S): + '''Given a list find the minimum.''' + tos, stack = S + return min(iter_stack(tos)), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def sum_(S): + '''Given a quoted sequence of numbers return the sum. + + sum == 0 swap [+] step + ''' + tos, stack = S + return sum(iter_stack(tos)), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def remove(S): + ''' + Expects an item on the stack and a quote under it and removes that item + from the the quote. The item is only removed once. + :: + + [1 2 3 1] 1 remove + ------------------------ + [2 3 1] + + ''' + (tos, (second, stack)) = S + l = list(iter_stack(second)) + l.remove(tos) + return list_to_stack(l), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def unique(S): + '''Given a list remove duplicate items.''' + tos, stack = S + I = list(iter_stack(tos)) + list_to_stack(sorted(set(I), key=I.index)) + return list_to_stack(sorted(set(I), key=I.index)), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def sort_(S): + '''Given a list return it sorted.''' + tos, stack = S + return list_to_stack(sorted(iter_stack(tos))), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def cons(S): + ''' + The cons operator expects a list on top of the stack and the potential + member below. The effect is to add the potential member into the + aggregate. + ''' + (tos, (second, stack)) = S + return (second, tos), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def uncons(S): + ''' + Inverse of cons, removes an item from the top of the list on the stack + and places it under the remaining list. + ''' + (tos, stack) = S + item, tos = tos + return tos, (item, stack)
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def clear(stack): + '''Clear everything from the stack. + :: + + ... clear + --------------- + + ''' + return ()
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def dup(S): + '''Duplicate the top item on the stack.''' + (tos, stack) = S + return tos, (tos, stack)
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def over(S): + ''' + Copy the second item down on the stack to the top of the stack. + :: + + a b over + -------------- + a b a + + ''' + second = S[1][0] + return second, S
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def tuck(S): + ''' + Copy the item at TOS under the second item of the stack. + :: + + a b tuck + -------------- + b a b + + ''' + (tos, (second, stack)) = S + return tos, (second, (tos, stack))
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def swap(S): + '''Swap the top two items on stack.''' + (tos, (second, stack)) = S + return second, (tos, stack)
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def swaack(stack): + '''swap stack''' + old_stack, stack = stack + return stack, old_stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def stack_(stack): + ''' + The stack operator pushes onto the stack a list containing all the + elements of the stack. + ''' + return stack, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def unstack(stack): + ''' + The unstack operator expects a list on top of the stack and makes that + the stack discarding the rest of the stack. + ''' + return stack[0]
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def pop(stack): + '''Pop and discard the top item from the stack.''' + return stack[1]
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def popd(stack): + '''Pop and discard the second item from the stack.''' + (tos, (_, stack)) = stack + return tos, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def popdd(stack): + '''Pop and discard the third item from the stack.''' + (tos, (second, (_, stack))) = stack + return tos, (second, stack)
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def popop(stack): + '''Pop and discard the first and second items from the stack.''' + return stack[1][1]
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def dupd(S): + '''Duplicate the second item on the stack.''' + (tos, (second, stack)) = S + return tos, (second, (second, stack))
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def reverse(S): + '''Reverse the list on the top of the stack. + :: + + reverse == [] swap shunt + ''' + (tos, stack) = S + res = () + for term in iter_stack(tos): + res = term, res + return res, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def concat(S): + '''Concatinate the two lists on the top of the stack.''' + (tos, (second, stack)) = S + for term in reversed(list(iter_stack(second))): + tos = term, tos + return tos, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def shunt(stack): + '''Like concat but reverses the top list into the second. + :: + + shunt == [swons] step + + ''' + (tos, (second, stack)) = stack + while tos: + term, tos = tos + second = term, second + return second, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def zip_(S): + ''' + Replace the two lists on the top of the stack with a list of the pairs + from each list. The smallest list sets the length of the result list. + ''' + (tos, (second, stack)) = S + accumulator = [ + (a, (b, ())) + for a, b in zip(iter_stack(tos), iter_stack(second)) + ] + return list_to_stack(accumulator), stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def succ(S): + '''Increment TOS.''' + (tos, stack) = S + return tos + 1, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def pred(S): + '''Decrement TOS.''' + (tos, stack) = S + return tos - 1, stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def pm(stack): + ''' + Plus or minus + :: + + a b pm + ------------- + a+b a-b + + ''' + a, (b, stack) = stack + p, m, = b + a, b - a + return m, (p, stack)
+ + +
[docs]def floor(n): + return int(math.floor(n))
+ +floor.__doc__ = math.floor.__doc__ + + +
[docs]@inscribe +@SimpleFunctionWrapper +def divmod_(S): + ''' + divmod(x, y) -> (quotient, remainder) + + Return the tuple (x//y, x%y). Invariant: div*y + mod == x. + ''' + a, (b, stack) = S + d, m = divmod(a, b) + return d, (m, stack)
+ + +
[docs]def sqrt(a): + ''' + Return the square root of the number a. + Negative numbers return complex roots. + ''' + try: + r = math.sqrt(a) + except ValueError: + assert a < 0, repr(a) + r = math.sqrt(-a) * 1j + return r
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def rollup(S): + ''' + :: + + a b c + ----------- + b c a + + ''' + (a, (b, (c, stack))) = S + return b, (c, (a, stack))
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def rolldown(S): + ''' + :: + + a b c + ----------- + c a b + + ''' + (a, (b, (c, stack))) = S + return c, (a, (b, stack))
+ + +#def execute(S): +# (text, stack) = S +# if isinstance(text, str): +# return run(text, stack) +# return stack + + +
[docs]@inscribe +@SimpleFunctionWrapper +def id_(stack): + '''The identity function.''' + return stack
+ + +
[docs]@inscribe +@SimpleFunctionWrapper +def void(stack): + '''True if the form on TOS is void otherwise False.''' + form, stack = stack + return _void(form), stack
+ + +def _void(form): + return any(not _void(i) for i in iter_stack(form)) + + + +## transpose +## sign +## take + + +
[docs]@inscribe +@FunctionWrapper +def words(stack, expression, dictionary): + '''Print all the words in alphabetical order.''' + print(' '.join(sorted(dictionary))) + return stack, expression, dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def sharing(stack, expression, dictionary): + '''Print redistribution information.''' + print("You may convey verbatim copies of the Program's source code as" + ' you receive it, in any medium, provided that you conspicuously' + ' and appropriately publish on each copy an appropriate copyright' + ' notice; keep intact all notices stating that this License and' + ' any non-permissive terms added in accord with section 7 apply' + ' to the code; keep intact all notices of the absence of any' + ' warranty; and give all recipients a copy of this License along' + ' with the Program.' + ' You should have received a copy of the GNU General Public License' + ' along with Thun. If not see <http://www.gnu.org/licenses/>.') + return stack, expression, dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def warranty(stack, expression, dictionary): + '''Print warranty information.''' + print('THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY' + ' APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE' + ' COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM' + ' "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR' + ' IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES' + ' OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE' + ' ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS' + ' WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE' + ' COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.') + return stack, expression, dictionary
+ + +# def simple_manual(stack): +# ''' +# Print words and help for each word. +# ''' +# for name, f in sorted(FUNCTIONS.items()): +# d = getdoc(f) +# boxline = '+%s+' % ('-' * (len(name) + 2)) +# print('\n'.join(( +# boxline, +# '| %s |' % (name,), +# boxline, +# d if d else ' ...', +# '', +# '--' * 40, +# '', +# ))) +# return stack + + +
[docs]@inscribe +@FunctionWrapper +def help_(S, expression, dictionary): + '''Accepts a quoted symbol on the top of the stack and prints its docs.''' + ((symbol, _), stack) = S + word = dictionary[symbol] + print(getdoc(word)) + return stack, expression, dictionary
+ + +# +# § Combinators +# + + +# Several combinators depend on other words in their definitions, +# we use symbols to prevent hard-coding these, so in theory, you +# could change the word in the dictionary to use different semantics. +S_choice = Symbol('choice') +S_first = Symbol('first') +S_getitem = Symbol('getitem') +S_genrec = Symbol('genrec') +S_loop = Symbol('loop') +S_i = Symbol('i') +S_ifte = Symbol('ifte') +S_infra = Symbol('infra') +S_step = Symbol('step') +S_times = Symbol('times') +S_swaack = Symbol('swaack') +S_truthy = Symbol('truthy') + + +
[docs]@inscribe +@FunctionWrapper +def i(stack, expression, dictionary): + ''' + The i combinator expects a quoted program on the stack and unpacks it + onto the pending expression for evaluation. + :: + + [Q] i + ----------- + Q + + ''' + quote, stack = stack + return stack, pushback(quote, expression), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def x(stack, expression, dictionary): + ''' + :: + + x == dup i + + ... [Q] x = ... [Q] dup i + ... [Q] x = ... [Q] [Q] i + ... [Q] x = ... [Q] Q + + ''' + quote, _ = stack + return stack, pushback(quote, expression), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def b(stack, expression, dictionary): + ''' + :: + + b == [i] dip i + + ... [P] [Q] b == ... [P] i [Q] i + ... [P] [Q] b == ... P Q + + ''' + q, (p, (stack)) = stack + return stack, pushback(p, pushback(q, expression)), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def dupdip(stack, expression, dictionary): + ''' + :: + + [F] dupdip == dup [F] dip + + ... a [F] dupdip + ... a dup [F] dip + ... a a [F] dip + ... a F a + + ''' + F, stack = stack + a = stack[0] + return stack, pushback(F, (a, expression)), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def infra(stack, expression, dictionary): + ''' + Accept a quoted program and a list on the stack and run the program + with the list as its stack. + :: + + ... [a b c] [Q] . infra + ----------------------------- + c b a . Q [...] swaack + + ''' + (quote, (aggregate, stack)) = stack + return aggregate, pushback(quote, (stack, (S_swaack, expression))), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def genrec(stack, expression, dictionary): + ''' + General Recursion Combinator. + :: + + [if] [then] [rec1] [rec2] genrec + --------------------------------------------------------------------- + [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte + + From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun: + "The genrec combinator takes four program parameters in addition to + whatever data parameters it needs. Fourth from the top is an if-part, + followed by a then-part. If the if-part yields true, then the then-part + is executed and the combinator terminates. The other two parameters are + the rec1-part and the rec2-part. If the if-part yields false, the + rec1-part is executed. Following that the four program parameters and + the combinator are again pushed onto the stack bundled up in a quoted + form. Then the rec2-part is executed, where it will find the bundled + form. Typically it will then execute the bundled form, either with i or + with app2, or some other combinator." + + The way to design one of these is to fix your base case [then] and the + test [if], and then treat rec1 and rec2 as an else-part "sandwiching" + a quotation of the whole function. + + For example, given a (general recursive) function 'F': + :: + + F == [I] [T] [R1] [R2] genrec + + If the [I] if-part fails you must derive R1 and R2 from: + :: + + ... R1 [F] R2 + + Just set the stack arguments in front, and figure out what R1 and R2 + have to do to apply the quoted [F] in the proper way. In effect, the + genrec combinator turns into an ifte combinator with a quoted copy of + the original definition in the else-part: + :: + + F == [I] [T] [R1] [R2] genrec + == [I] [T] [R1 [F] R2] ifte + + Primitive recursive functions are those where R2 == i. + :: + + P == [I] [T] [R] primrec + == [I] [T] [R [P] i] ifte + == [I] [T] [R P] ifte + + ''' + (rec2, (rec1, stack)) = stack + (then, (if_, _)) = stack + F = (if_, (then, (rec1, (rec2, (S_genrec, ()))))) + else_ = pushback(rec1, (F, rec2)) + return (else_, stack), (S_ifte, expression), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def map_(S, expression, dictionary): + ''' + Run the quoted program on TOS on the items in the list under it, push a + new list with the results (in place of the program and original list. + ''' +# (quote, (aggregate, stack)) = S +# results = list_to_stack([ +# joy((term, stack), quote, dictionary)[0][0] +# for term in iter_stack(aggregate) +# ]) +# return (results, stack), expression, dictionary + (quote, (aggregate, stack)) = S + if not aggregate: + return (aggregate, stack), expression, dictionary + batch = () + for term in iter_stack(aggregate): + s = term, stack + batch = (s, (quote, (S_infra, (S_first, batch)))) + stack = (batch, ((), stack)) + return stack, (S_infra, expression), dictionary
+ + +#def cleave(S, expression, dictionary): +# ''' +# The cleave combinator expects two quotations, and below that an item X. +# It first executes [P], with X on top, and saves the top result element. +# Then it executes [Q], again with X, and saves the top result. +# Finally it restores the stack to what it was below X and pushes the two +# results P(X) and Q(X). +# ''' +# (Q, (P, (x, stack))) = S +# p = joy((x, stack), P, dictionary)[0][0] +# q = joy((x, stack), Q, dictionary)[0][0] +# return (q, (p, stack)), expression, dictionary + + +
[docs]@inscribe +@FunctionWrapper +def branch(stack, expression, dictionary): + ''' + Use a Boolean value to select one of two quoted programs to run. + + :: + + branch == roll< choice i + + :: + + False [F] [T] branch + -------------------------- + F + + True [F] [T] branch + ------------------------- + T + + ''' + (then, (else_, (flag, stack))) = stack + return stack, pushback(then if flag else else_, expression), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def ifte(stack, expression, dictionary): + ''' + If-Then-Else Combinator + :: + + ... [if] [then] [else] ifte + --------------------------------------------------- + ... [[else] [then]] [...] [if] infra select i + + + + + ... [if] [then] [else] ifte + ------------------------------------------------------- + ... [else] [then] [...] [if] infra first choice i + + + Has the effect of grabbing a copy of the stack on which to run the + if-part using infra. + ''' + (else_, (then, (if_, stack))) = stack + expression = (S_infra, (S_first, (S_choice, (S_i, expression)))) + stack = (if_, (stack, (then, (else_, stack)))) + return stack, expression, dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def dip(stack, expression, dictionary): + ''' + The dip combinator expects a quoted program on the stack and below it + some item, it hoists the item into the expression and runs the program + on the rest of the stack. + :: + + ... x [Q] dip + ------------------- + ... Q x + + ''' + (quote, (x, stack)) = stack + expression = (x, expression) + return stack, pushback(quote, expression), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def dipd(S, expression, dictionary): + ''' + Like dip but expects two items. + :: + + ... y x [Q] dip + --------------------- + ... Q y x + + ''' + (quote, (x, (y, stack))) = S + expression = (y, (x, expression)) + return stack, pushback(quote, expression), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def dipdd(S, expression, dictionary): + ''' + Like dip but expects three items. + :: + + ... z y x [Q] dip + ----------------------- + ... Q z y x + + ''' + (quote, (x, (y, (z, stack)))) = S + expression = (z, (y, (x, expression))) + return stack, pushback(quote, expression), dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def app1(S, expression, dictionary): + ''' + Given a quoted program on TOS and anything as the second stack item run + the program and replace the two args with the first result of the + program. + :: + + ... x [Q] . app1 + ----------------------------------- + ... [x ...] [Q] . infra first + ''' + (quote, (x, stack)) = S + stack = (quote, ((x, stack), stack)) + expression = (S_infra, (S_first, expression)) + return stack, expression, dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def app2(S, expression, dictionary): + '''Like app1 with two items. + :: + + ... y x [Q] . app2 + ----------------------------------- + ... [y ...] [Q] . infra first + [x ...] [Q] infra first + + ''' + (quote, (x, (y, stack))) = S + expression = (S_infra, (S_first, + ((x, stack), (quote, (S_infra, (S_first, + expression)))))) + stack = (quote, ((y, stack), stack)) + return stack, expression, dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def app3(S, expression, dictionary): + '''Like app1 with three items. + :: + + ... z y x [Q] . app3 + ----------------------------------- + ... [z ...] [Q] . infra first + [y ...] [Q] infra first + [x ...] [Q] infra first + + ''' + (quote, (x, (y, (z, stack)))) = S + expression = (S_infra, (S_first, + ((y, stack), (quote, (S_infra, (S_first, + ((x, stack), (quote, (S_infra, (S_first, + expression)))))))))) + stack = (quote, ((z, stack), stack)) + return stack, expression, dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def step(S, expression, dictionary): + ''' + Run a quoted program on each item in a sequence. + :: + + ... [] [Q] . step + ----------------------- + ... . + + + ... [a] [Q] . step + ------------------------ + ... a . Q + + + ... [a b c] [Q] . step + ---------------------------------------- + ... a . Q [b c] [Q] step + + The step combinator executes the quotation on each member of the list + on top of the stack. + ''' + (quote, (aggregate, stack)) = S + if not aggregate: + return stack, expression, dictionary + head, tail = aggregate + stack = quote, (head, stack) + if tail: + expression = tail, (quote, (S_step, expression)) + expression = S_i, expression + return stack, expression, dictionary
+ + +
[docs]@inscribe +@FunctionWrapper +def times(stack, expression, dictionary): + ''' + times == [-- dip] cons [swap] infra [0 >] swap while pop + :: + + ... n [Q] . times + --------------------- w/ n <= 0 + ... . + + + ... 1 [Q] . times + --------------------------------- + ... . Q + + + ... n [Q] . times + --------------------------------- w/ n > 1 + ... . Q (n - 1) [Q] times + + ''' + # times == [-- dip] cons [swap] infra [0 >] swap while pop + (quote, (n, stack)) = stack + if n <= 0: + return stack, expression, dictionary + n -= 1 + if n: + expression = n, (quote, (S_times, expression)) + expression = pushback(quote, expression) + return stack, expression, dictionary
+ + +# The current definition above works like this: + +# [P] [Q] while +# -------------------------------------- +# [P] nullary [Q [P] nullary] loop + +# while == [pop i not] [popop] [dudipd] primrec + +#def while_(S, expression, dictionary): +# '''[if] [body] while''' +# (body, (if_, stack)) = S +# while joy(stack, if_, dictionary)[0][0]: +# stack = joy(stack, body, dictionary)[0] +# return stack, expression, dictionary + + +
[docs]@inscribe +@FunctionWrapper +def loop(stack, expression, dictionary): + ''' + Basic loop combinator. + :: + + ... True [Q] loop + ----------------------- + ... Q [Q] loop + + ... False [Q] loop + ------------------------ + ... + + ''' + quote, (flag, stack) = stack + if flag: + expression = pushback(quote, (quote, (S_loop, expression))) + return stack, expression, dictionary
+ + +#def nullary(S, expression, dictionary): +# ''' +# Run the program on TOS and return its first result without consuming +# any of the stack (except the program on TOS.) +# ''' +# (quote, stack) = S +# result = joy(stack, quote, dictionary) +# return (result[0][0], stack), expression, dictionary +# +# +#def unary(S, expression, dictionary): +# (quote, stack) = S +# _, return_stack = stack +# result = joy(stack, quote, dictionary)[0] +# return (result[0], return_stack), expression, dictionary +# +# +#def binary(S, expression, dictionary): +# (quote, stack) = S +# _, (_, return_stack) = stack +# result = joy(stack, quote, dictionary)[0] +# return (result[0], return_stack), expression, dictionary +# +# +#def ternary(S, expression, dictionary): +# (quote, stack) = S +# _, (_, (_, return_stack)) = stack +# result = joy(stack, quote, dictionary)[0] +# return (result[0], return_stack), expression, dictionary + + +# FunctionWrapper(binary), +# FunctionWrapper(cleave), +# FunctionWrapper(nullary), +# FunctionWrapper(ternary), +# FunctionWrapper(unary), +# FunctionWrapper(while_), + + +for F in ( + BinaryBuiltinWrapper(operator.add), + BinaryBuiltinWrapper(operator.and_), + BinaryBuiltinWrapper(operator.div), + BinaryBuiltinWrapper(operator.eq), + BinaryBuiltinWrapper(operator.floordiv), + BinaryBuiltinWrapper(operator.ge), + BinaryBuiltinWrapper(operator.gt), + BinaryBuiltinWrapper(operator.le), + BinaryBuiltinWrapper(operator.lshift), + BinaryBuiltinWrapper(operator.lt), + BinaryBuiltinWrapper(operator.mod), + BinaryBuiltinWrapper(operator.mul), + BinaryBuiltinWrapper(operator.ne), + BinaryBuiltinWrapper(operator.or_), + BinaryBuiltinWrapper(operator.pow), + BinaryBuiltinWrapper(operator.rshift), + BinaryBuiltinWrapper(operator.sub), + BinaryBuiltinWrapper(operator.truediv), + BinaryBuiltinWrapper(operator.xor), + + UnaryBuiltinWrapper(abs), + UnaryBuiltinWrapper(bool), + UnaryBuiltinWrapper(floor), + UnaryBuiltinWrapper(operator.neg), + UnaryBuiltinWrapper(operator.not_), + UnaryBuiltinWrapper(sqrt), + ): + inscribe(F) +del F # Otherwise Sphinx autodoc will pick it up. + + +add_aliases(_dictionary, ALIASES) + + +DefinitionWrapper.add_definitions(definitions, _dictionary) +
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/parser.html b/docs/sphinx_docs/_build/html/_modules/joy/parser.html new file mode 100644 index 0000000..9de971c --- /dev/null +++ b/docs/sphinx_docs/_build/html/_modules/joy/parser.html @@ -0,0 +1,190 @@ + + + + + + + + joy.parser — Thun 0.1.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for joy.parser

+# -*- coding: utf-8 -*-
+#
+#    Copyright © 2014, 2015, 2016, 2017 Simon Forman
+#
+#    This file is part of Thun.
+#
+#    Thun 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.
+#
+#    Thun 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 Thun.  If not see <http://www.gnu.org/licenses/>.
+#
+'''
+This module exports a single function for converting text to a joy
+expression as well as a single Symbol class and a single Exception type.
+
+The Symbol string class is used by the interpreter to recognize literals
+by the fact that they are not Symbol objects.
+
+A crude grammar::
+
+  joy = term*
+  term = int | float | string | '[' joy ']' | function
+
+A Joy expression is a sequence of zero or more terms
+
+
+'''
+#TODO: explain the details of float lits and strings.
+from re import Scanner
+from .utils.stack import list_to_stack
+
+
+
[docs]class Symbol(str): + '''A string class that represents Joy function names.''' + __repr__ = str.__str__
+ + +
[docs]def text_to_expression(text): + '''Convert a string to a Joy expression. + + When supplied with a string this function returns a Python datastructure + that represents the Joy datastructure described by the text expression. + Any unbalanced square brackets will raise a ParseError. + + :param str text: Text to convert. + :rtype: quote + :raises ParseError: if the parse fails. + ''' + return _parse(_tokenize(text))
+ + +
[docs]class ParseError(ValueError): + '''Raised when there is a error while parsing text.'''
+ + +def _tokenize(text): + '''Convert a text into a stream of tokens. + + Converts function names to Symbols. + + Raise ParseError (with some of the failing text) if the scan fails. + ''' + tokens, rest = _scanner.scan(text) + if rest: + raise ParseError( + 'Scan failed at position %i, %r' + % (len(text) - len(rest), rest[:10]) + ) + return tokens + + +def _parse(tokens): + ''' + Return a stack/list expression of the tokens. + ''' + frame = [] + stack = [] + for tok in tokens: + if tok == '[': + stack.append(frame) + frame = [] + stack[-1].append(frame) + elif tok == ']': + try: + frame = stack.pop() + except IndexError: + raise ParseError('Extra closing bracket.') + frame[-1] = list_to_stack(frame[-1]) + else: + frame.append(tok) + if stack: + raise ParseError('Unclosed bracket.') + return list_to_stack(frame) + + +_scanner = Scanner([ + (r'-?\d+\.\d*', lambda _, token: float(token)), + (r'-?\d+', lambda _, token: int(token)), + (r'[•\w!@$%^&*()_+<>?|\/;:`~,.=-]+', lambda _, token: Symbol(token)), + (r'\[|\]', lambda _, token: token), + (r'"(?:[^"\\]|\\.)*"', lambda _, token: token[1:-1].replace('\\"', '"')), + (r"'(?:[^'\\]|\\.)*'", lambda _, token: token[1:-1].replace("\\'", "'")), + (r'\s+', None), + ]) +
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/utils/pretty_print.html b/docs/sphinx_docs/_build/html/_modules/joy/utils/pretty_print.html new file mode 100644 index 0000000..9ca4dc8 --- /dev/null +++ b/docs/sphinx_docs/_build/html/_modules/joy/utils/pretty_print.html @@ -0,0 +1,152 @@ + + + + + + + + joy.utils.pretty_print — Thun 0.1.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for joy.utils.pretty_print

+# -*- coding: utf-8 -*-
+#
+#    Copyright © 2016 Simon Forman
+#
+#    This file is part of Thun.
+#
+#    Thun 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.
+#
+#    Thun 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 Thun.  If not see <http://www.gnu.org/licenses/>.
+#
+'''
+Pretty printing support.
+'''
+# (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
+
+
+
[docs]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 . + + ''' + + def __init__(self): + self.history = [] + +
[docs] 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.')
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/utils/stack.html b/docs/sphinx_docs/_build/html/_modules/joy/utils/stack.html new file mode 100644 index 0000000..346f111 --- /dev/null +++ b/docs/sphinx_docs/_build/html/_modules/joy/utils/stack.html @@ -0,0 +1,250 @@ + + + + + + + + joy.utils.stack — Thun 0.1.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for joy.utils.stack

+# -*- coding: utf-8 -*-
+#
+#    Copyright © 2014, 2015, 2017 Simon Forman
+#
+#    This file is part of Thun
+#
+#    Thun 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.
+#
+#    Thun 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 Thun.  If not see <http://www.gnu.org/licenses/>.
+#
+'''
+When talking about Joy we use the terms "stack", "list", "sequence",
+"quote" 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
+empty tuple ``()`` is the empty stack and ``(head, rest)`` gives the recursive
+form of a stack with one or more items on it::
+
+    stack := () | (item, stack)
+
+Putting some numbers onto a stack::
+
+    ()
+    (1, ())
+    (2, (1, ()))
+    (3, (2, (1, ())))
+    ...
+
+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((head, tail)):
+    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 unpacking the
+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.)
+
+.. _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.
+
+
+
+
[docs]def list_to_stack(el, stack=()): + '''Convert a Python list (or other sequence) to a Joy stack:: + + [1, 2, 3] -> (1, (2, (3, ()))) + + ''' + for item in reversed(el): + stack = item, stack + return stack
+ + +
[docs]def iter_stack(stack): + '''Iterate through the items on the stack.''' + while stack: + item, stack = stack + yield item
+ + +
[docs]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)
+ + +
[docs]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) + ) + + +
[docs]def pushback(quote, expression): + '''Concatinate quote onto expression. + + In joy [1 2] [3 4] would become [1 2 3 4]. + ''' + + # Original implementation. + +## return list_to_stack(list(iter_stack(quote)), expression) + + # In-lining is slightly faster (and won't break the + # recursion limit on long quotes.) + +## temp = [] +## while quote: +## item, quote = quote +## temp.append(item) +## for item in reversed(temp): +## 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
+ + +
[docs]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
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/sphinx_docs/index.rst b/docs/sphinx_docs/index.rst index d5453ea..c940180 100644 --- a/docs/sphinx_docs/index.rst +++ b/docs/sphinx_docs/index.rst @@ -6,7 +6,7 @@ Thun |release| Documentation ============================ -Thun is dialect of Joy written in Python. +Thun is dialect of Joy written in Python 2. `Joy`_ is a programming language created by Manfred von Thun that is easy to use and understand and has many other nice properties. This Python @@ -75,7 +75,7 @@ interesting aspects. It's quite a treasure trove. Documentation on Thun Dialect ----------------------------- -Thun is implemented in Python. The following is specific information for this dialect of Joy. +The following is specific information for this dialect of Joy. There are also some Jupyter notebooks. .. toctree::