diff --git a/build/lib/joy/__init__.py b/build/lib/joy/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/lib/joy/__main__.py b/build/lib/joy/__main__.py deleted file mode 100644 index 1b436bc..0000000 --- a/build/lib/joy/__main__.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- 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 . -# -from .library import initialize -from .joy import repl - -print '''\ -Joypy - Copyright © 2017 Simon Forman -This program comes with ABSOLUTELY NO WARRANTY; for details type "warranty". -This is free software, and you are welcome to redistribute it -under certain conditions; type "sharing" for details. -Type "words" to see a list of all words, and "[] help" to print the -docs for a word. -''' -stack = repl(dictionary=initialize()) diff --git a/build/lib/joy/joy.py b/build/lib/joy/joy.py deleted file mode 100644 index aa04505..0000000 --- a/build/lib/joy/joy.py +++ /dev/null @@ -1,125 +0,0 @@ -# -*- coding: utf-8 -*- -''' - - -A dialect of Joy in Python. - - -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 script -is 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. A Tkinter GUI is provided as well. - - - Copyright © 2014, 2016, 2017 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 . - - -§ joy() - -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. - -Every Joy function is an unary mapping from stacks to stacks. Even -literals are considered to be functions that accept a stack and return a -new stack with the literal value on top. - -Exports: - - joy(stack, expression, dictionary, viewer=None) - - run(text, stack, dictionary, viewer=None) - - repl(stack=(), dictionary=()) - -''' -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 - - -def joy(stack, expression, dictionary, viewer=None): - ''' - Evaluate the Joy expression on the stack. - ''' - 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 - - -def run(text, stack, dictionary, viewer=None): - ''' - Return the stack resulting from running the Joy code text on the stack. - ''' - try: - expression = text_to_expression(text) - except ParseError as err: - print('Err:', err.message) - return stack, (), dictionary - return joy(stack, expression, dictionary, viewer) - - -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 diff --git a/build/lib/joy/library.py b/build/lib/joy/library.py deleted file mode 100644 index 416a3e3..0000000 --- a/build/lib/joy/library.py +++ /dev/null @@ -1,1295 +0,0 @@ -# -*- 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 . -# -from inspect import getdoc -import operator, math - -from .parser import text_to_expression, Symbol -from .utils.stack import list_to_stack, iter_stack, pick, pushback - - -ALIASES = ( - ('add', ['+']), - ('and', ['&']), - ('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', ['•']), - ) - - -def add_aliases(D, A=ALIASES): - ''' - 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 -) - - -class FunctionWrapper(object): - ''' - Allow functions to have a nice repr(). - - At some point it's likely this class and its subclasses would gain - machinery to support type checking and inference. - ''' - - def __init__(self, f): - self.f = f - self.name = f.__name__.rstrip('_') # Don't shadow builtins. - self.__doc__ = f.__doc__ or str(f) - - def __call__(self, stack, expression, dictionary): - ''' - Functions in general receive and return all three. - ''' - return self.f(stack, expression, dictionary) - - def __repr__(self): - return self.name - - -class SimpleFunctionWrapper(FunctionWrapper): - ''' - Wrap functions that take and return just a stack. - ''' - - def __call__(self, stack, expression, dictionary): - return self.f(stack), expression, dictionary - - -class BinaryBuiltinWrapper(FunctionWrapper): - ''' - Wrap functions that take two arguments and return a single result. - ''' - - def __call__(self, stack, expression, dictionary): - (a, (b, stack)) = stack - result = self.f(b, a) - return (result, stack), expression, dictionary - - -class UnaryBuiltinWrapper(FunctionWrapper): - ''' - Wrap functions that take one argument and return a single result. - ''' - - def __call__(self, stack, expression, dictionary): - (a, stack) = stack - result = self.f(a) - return (result, stack), expression, dictionary - - -class DefinitionWrapper(FunctionWrapper): - ''' - 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 - - @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) - - @classmethod - def add_definitions(class_, defs, dictionary): - for definition in _text_to_defs(defs): - class_.add_def(definition, dictionary) - - @classmethod - def add_def(class_, definition, dictionary): - F = class_.parse_definition(definition) - dictionary[F.name] = F - - -def _text_to_defs(text): - return filter(None, (line.strip() for line in text.splitlines())) - - -# -# Functions -# - - -def parse((text, stack)): - '''Parse the string on the stack to a Joy expression.''' - expression = text_to_expression(text) - return expression, stack - - -def first(((head, tail), stack)): - '''first == uncons pop''' - return head, stack - - -def rest(((head, tail), stack)): - '''rest == uncons popd''' - return tail, stack - - -def truthy(stack): - '''Coerce the item on the top of the stack to its Boolean value.''' - n, stack = stack - return bool(n), stack - - -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 - - -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 - - -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 - - -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 - - -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 - - -def max_(S): - '''Given a list find the maximum.''' - tos, stack = S - return max(iter_stack(tos)), stack - - -def min_(S): - '''Given a list find the minimum.''' - tos, stack = S - return min(iter_stack(tos)), stack - - -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 - - -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 - - -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 - - -def sort_(S): - '''Given a list return it sorted.''' - tos, stack = S - return list_to_stack(sorted(iter_stack(tos))), stack - - -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 - - -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) - - -def clear(stack): - '''Clear everything from the stack. - - ... clear - --------------- - - ''' - return () - - -def dup(S): - '''Duplicate the top item on the stack.''' - (tos, stack) = S - return tos, (tos, stack) - - -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 - - -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)) - - -def swap(S): - '''Swap the top two items on stack.''' - (tos, (second, stack)) = S - return second, (tos, stack) - - -def swaack(stack): - '''swap stack''' - old_stack, stack = stack - return stack, old_stack - - -def stack_(stack): - ''' - The stack operator pushes onto the stack a list containing all the - elements of the stack. - ''' - return stack, stack - - -def unstack(S): - ''' - The unstack operator expects a list on top of the stack and makes that - the stack discarding the rest of the stack. - ''' - (tos, stack) = S - return tos - - -def pop(S): - '''Pop and discard the top item from the stack.''' - (tos, stack) = S - return stack - - -def popd(S): - '''Pop and discard the second item from the stack.''' - (tos, (second, stack)) = S - return tos, stack - - -def popdd(S): - '''Pop and discard the third item from the stack.''' - (tos, (second, (third, stack))) = S - return tos, (second, stack) - - -def popop(S): - '''Pop and discard the first and second items from the stack.''' - (tos, (second, stack)) = S - return stack - - -def dupd(S): - '''Duplicate the second item on the stack.''' - (tos, (second, stack)) = S - return tos, (second, (second, stack)) - - -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 - - -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 - - -def shunt((tos, (second, stack))): - ''' - shunt == [swons] step - - Like concat but reverses the top list into the second. - ''' - while tos: - term, tos = tos - second = term, second - return second, stack - - -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 - - -def succ(S): - '''Increment TOS.''' - (tos, stack) = S - return tos + 1, stack - - -def pred(S): - '''Decrement TOS.''' - (tos, stack) = S - return tos - 1, stack - - -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) - - -def floor(n): - return int(math.floor(n)) - -floor.__doc__ = math.floor.__doc__ - - -def divmod_(S): - a, (b, stack) = S - d, m = divmod(a, b) - return d, (m, stack) - -divmod_.__doc__ = divmod.__doc__ - - -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 - - -def rollup(S): - '''a b c -> b c a''' - (a, (b, (c, stack))) = S - return b, (c, (a, stack)) - - -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 - - -def id_(stack): - return stack - - -def void(stack): - form, stack = stack - return _void(form), stack - - -def _void(form): - return any(not _void(i) for i in iter_stack(form)) - - - -## transpose -## sign -## take - - -def words(stack, expression, dictionary): - '''Print all the words in alphabetical order.''' - print(' '.join(sorted(dictionary))) - return stack, expression, dictionary - - -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 Joypy. If not see .') - return stack, expression, dictionary - - -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 - - -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') - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -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 - - -builtins = ( - 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(floor), - UnaryBuiltinWrapper(operator.neg), - UnaryBuiltinWrapper(operator.not_), - UnaryBuiltinWrapper(sqrt), - ) - - -combinators = ( - FunctionWrapper(app1), - FunctionWrapper(app2), - FunctionWrapper(app3), - FunctionWrapper(b), - FunctionWrapper(branch), -# FunctionWrapper(binary), -# FunctionWrapper(cleave), - FunctionWrapper(dip), - FunctionWrapper(dipd), - FunctionWrapper(dipdd), - FunctionWrapper(dupdip), - FunctionWrapper(genrec), - FunctionWrapper(help_), - FunctionWrapper(i), - FunctionWrapper(ifte), - FunctionWrapper(infra), - FunctionWrapper(loop), - FunctionWrapper(map_), -# FunctionWrapper(nullary), - FunctionWrapper(step), - FunctionWrapper(times), -# FunctionWrapper(ternary), -# FunctionWrapper(unary), -# FunctionWrapper(while_), - FunctionWrapper(words), - FunctionWrapper(x), - ) - - -primitives = ( - SimpleFunctionWrapper(choice), - SimpleFunctionWrapper(clear), - SimpleFunctionWrapper(concat), - SimpleFunctionWrapper(cons), - SimpleFunctionWrapper(divmod_), - SimpleFunctionWrapper(drop), - SimpleFunctionWrapper(dup), - SimpleFunctionWrapper(dupd), - SimpleFunctionWrapper(first), - SimpleFunctionWrapper(getitem), - SimpleFunctionWrapper(id_), - SimpleFunctionWrapper(max_), - SimpleFunctionWrapper(min_), - SimpleFunctionWrapper(over), - SimpleFunctionWrapper(parse), - SimpleFunctionWrapper(pm), - SimpleFunctionWrapper(pop), - SimpleFunctionWrapper(popd), - SimpleFunctionWrapper(popdd), - SimpleFunctionWrapper(popop), - SimpleFunctionWrapper(pred), - SimpleFunctionWrapper(remove), - SimpleFunctionWrapper(rest), - SimpleFunctionWrapper(reverse), - SimpleFunctionWrapper(rolldown), - SimpleFunctionWrapper(rollup), - SimpleFunctionWrapper(select), - SimpleFunctionWrapper(shunt), - SimpleFunctionWrapper(sort_), - SimpleFunctionWrapper(stack_), - SimpleFunctionWrapper(succ), - SimpleFunctionWrapper(sum_), - SimpleFunctionWrapper(swaack), - SimpleFunctionWrapper(swap), - SimpleFunctionWrapper(take), - SimpleFunctionWrapper(truthy), - SimpleFunctionWrapper(tuck), - SimpleFunctionWrapper(uncons), - SimpleFunctionWrapper(unique), - SimpleFunctionWrapper(unstack), - SimpleFunctionWrapper(unstack), - SimpleFunctionWrapper(void), - SimpleFunctionWrapper(zip_), - - FunctionWrapper(sharing), - FunctionWrapper(warranty), - ) - - -def initialize(dictionary=None): - if dictionary is None: - dictionary = {} - dictionary.update((F.name, F) for F in builtins) - dictionary.update((F.name, F) for F in combinators) - dictionary.update((F.name, F) for F in primitives) - add_aliases(dictionary) - DefinitionWrapper.add_definitions(definitions, dictionary) - return dictionary diff --git a/build/lib/joy/parser.py b/build/lib/joy/parser.py deleted file mode 100644 index dc6411f..0000000 --- a/build/lib/joy/parser.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2014, 2015, 2016, 2017 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 . -# -''' - - -§ Converting text to a joy expression. - -This module exports a single function: - - text_to_expression(text) - -As well as a single Symbol class and a single Exception type: - - ParseError - -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. -''' -from re import Scanner -from .utils.stack import list_to_stack - - -class Symbol(str): - __repr__ = str.__str__ - - -def text_to_expression(text): - ''' - Convert a text to a Joy expression. - ''' - return _parse(_tokenize(text)) - - -class ParseError(ValueError): pass - - -def _tokenize(text): - ''' - Convert a text into a stream of tokens, converting symbols using - symbol(token). Raise ValueError (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('One or more extra closing brackets.') - frame[-1] = list_to_stack(frame[-1]) - else: - frame.append(tok) - if stack: - raise ParseError('One or more unclosed brackets.') - return list_to_stack(frame) - - -def _scan_identifier(scanner, token): return Symbol(token) -def _scan_bracket(scanner, token): return token -def _scan_float(scanner, token): return float(token) -def _scan_int(scanner, token): return int(token) -def _scan_dstr(scanner, token): return token[1:-1].replace('\\"', '"') -def _scan_sstr(scanner, token): return token[1:-1].replace("\\'", "'") - - -_scanner = Scanner([ - (r'-?\d+\.\d*', _scan_float), - (r'-?\d+', _scan_int), - (r'[•\w!@$%^&*()_+<>?|\/;:`~,.=-]+', _scan_identifier), - (r'\[|\]', _scan_bracket), - (r'"(?:[^"\\]|\\.)*"', _scan_dstr), - (r"'(?:[^'\\]|\\.)*'", _scan_sstr), - (r'\s+', None), - ]) diff --git a/build/lib/joy/utils/__init__.py b/build/lib/joy/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/lib/joy/utils/pretty_print.py b/build/lib/joy/utils/pretty_print.py deleted file mode 100644 index 98b12e6..0000000 --- a/build/lib/joy/utils/pretty_print.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- 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 . -# -''' -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.') diff --git a/build/lib/joy/utils/stack.py b/build/lib/joy/utils/stack.py deleted file mode 100644 index e3f8dd9..0000000 --- a/build/lib/joy/utils/stack.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- 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 . -# -''' - - -§ 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