X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=joy%2Flibrary.py;h=800ff3b76fca339294dcdcdd2bc7a1ff3b616c29;hb=fcd4c613e4a049a21fe0ed5bed42770390bc1b80;hp=c2913737905a80686e0c1bf1886ff6d2d4f1799a;hpb=0bbe9c890e6a4801d6e58f8df618df578d941afd;p=joypy%2FThun.git diff --git a/joy/library.py b/joy/library.py index c291373..800ff3b 100644 --- a/joy/library.py +++ b/joy/library.py @@ -23,11 +23,14 @@ functions. Its main export is a Python function initialize() that returns a dictionary of Joy functions suitable for use with the joy() function. ''' +from pkg_resources import resource_stream +from io import TextIOWrapper from inspect import getdoc, getmembers, isfunction from functools import wraps from itertools import count import operator, math +from . import __name__ as _joy_package_name from .parser import text_to_expression, Symbol from .utils import generated_library as genlib from .utils.errors import ( @@ -44,6 +47,14 @@ from .utils.stack import ( ) +def default_defs(dictionary): + def_stream = TextIOWrapper( + resource_stream(_joy_package_name, 'defs.txt'), + encoding='UTF_8', + ) + Def.load_definitions(def_stream, dictionary) + + HELP_TEMPLATE = '''\ ==== Help on %s ==== @@ -58,9 +69,9 @@ HELP_TEMPLATE = '''\ _dictionary = {} -def inscribe(function): +def inscribe(function, d=_dictionary): '''A decorator to inscribe functions into the default dictionary.''' - _dictionary[function.name] = function + d[function.name] = function return function @@ -111,88 +122,6 @@ def add_aliases(D, A): D[alias] = F -definitions = ('''\ -? == dup truthy -*fraction == [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons -*fraction0 == concat [[swap] dip * [*] dip] infra -anamorphism == [pop []] swap [dip swons] genrec -average == [sum 1.0 *] [size] cleave / -binary == nullary [popop] dip -cleave == fork [popd] dip -codireco == cons dip rest cons -dinfrirst == dip infra first -unstack == ? [uncons ?] loop pop -down_to_zero == [0 >] [dup --] while -dupdipd == dup dipd -enstacken == stack [clear] dip -flatten == [] swap [concat] step -fork == [i] app2 -gcd == 1 [tuck modulus dup 0 >] loop pop -ifte == [nullary not] dipd branch -ii == [dip] dupdip i -least_fraction == dup [gcd] infra [div] concat map -make_generator == [codireco] ccons -nullary == [stack] dinfrirst -of == swap at -pam == [i] map -tailrec == [i] genrec -product == 1 swap [*] step -quoted == [unit] dip -range == [0 <=] [1 - dup] anamorphism -range_to_zero == unit [down_to_zero] infra -run == [] swap infra -size == 0 swap [pop ++] step -sqr == dup mul -step_zero == 0 roll> step -swoncat == swap concat -tailrec == [i] genrec -ternary == unary [popop] dip -unary == nullary popd -unquoted == [i] dip -while == swap [nullary] cons dup dipd concat loop -''' -# -# -# ifte == [nullary] dipd swap branch -# genrec == [[genrec] cons cons cons cons] nullary swons concat ifte - -# Another definition for while. FWIW -# while == over [[i] dip nullary] ccons [nullary] dip loop - -##ccons == cons cons -##unit == [] cons -##second == rest first -##third == rest rest first -##swons == swap cons - -##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 -) - - def FunctionWrapper(f): '''Set name attribute.''' if not f.__doc__: @@ -223,12 +152,13 @@ def BinaryBuiltinWrapper(f): (a, (b, stack)) = stack except ValueError: raise StackUnderflowError('Not enough values on stack.') - if ( not isinstance(a, int) - or not isinstance(b, int) - or isinstance(a, bool) # Because bools are ints in Python. - or isinstance(b, bool) - ): - raise NotAnIntError + # Boolean predicates like "or" fail here. :( +## if ( not isinstance(a, int) +## or not isinstance(b, int) +## or isinstance(a, bool) # Because bools are ints in Python. +## or isinstance(b, bool) +## ): +## raise NotAnIntError result = f(b, a) return (result, stack), expression, dictionary return inner @@ -247,16 +177,16 @@ def UnaryBuiltinWrapper(f): return inner -class DefinitionWrapper(object): +class Def(object): ''' - Provide implementation of defined functions, and some helper methods. + Definitions created by inscribe. ''' - 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 __init__(self, name, body): + self.name = name + self.body = body + self._body = tuple(iter_stack(body)) + self.__doc__ = expression_to_string(body) self._compiled = None def __call__(self, stack, expression, dictionary): @@ -266,58 +196,14 @@ class DefinitionWrapper(object): return stack, expression, dictionary @classmethod - def parse_definition(class_, defi): - ''' - Given some text describing a Joy function definition parse it and - return a DefinitionWrapper. - ''' - # At some point I decided that the definitions file should NOT - # use '==' to separate the name from the body. But somehow the - # xerblin\gui\default_joy_home\definitions.txt file didn't get - # the memo. Nor did the load_definitions() method. - # So I think the simplest way forward at the moment will be to - # edit this function to expect '=='. - - name, part, body = defi.partition('==') - if part: - return class_(name.strip(), body.strip()) - raise ValueError("No '==' in definition text %r" % (defi,)) - - # return class_(*(n.strip() for n in defi.split(None, 1))) - - @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) - - @classmethod - def add_def(class_, definition, dictionary, fail_fails=False): - ''' - Add the definition to the dictionary. - ''' - F = class_.parse_definition(definition) - dictionary[F.name] = F - - @classmethod - def load_definitions(class_, filename, dictionary): - with open(filename) as f: - lines = [line for line in f if '==' in line] - for line in lines: - class_.add_def(line, dictionary) - - -def _text_to_defs(text): - return ( - line.strip() - for line in text.splitlines() - if line - and not line.startswith('#') - and '==' in line - ) + def load_definitions(class_, stream, dictionary): + for line in stream: + if line.lstrip().startswith('#'): + continue + name, body = text_to_expression(line) + if name not in dictionary: + inscribe(class_(name, body), dictionary) +## inscribe(class_(name, body), dictionary) # @@ -330,16 +216,14 @@ def _text_to_defs(text): def inscribe_(stack, expression, dictionary): ''' Create a new Joy function definition in the Joy dictionary. A - definition is given as a string with a name followed by a double - equal sign then one or more Joy functions, the body. for example: + definition is given as a quote with a name followed by a Joy + expression. for example: - sqr == dup mul + [sqr dup mul] inscribe - If you want the definition to persist over restarts, enter it into - the definitions.txt resource. ''' - definition, stack = stack - DefinitionWrapper.add_def(definition, dictionary, fail_fails=True) + (name, body), stack = stack + inscribe(Def(name, body), dictionary) return stack, expression, dictionary @@ -437,6 +321,19 @@ def take(stack): @inscribe +@FunctionWrapper +def gcd2(stack, expression, dictionary): + '''Compiled GCD function.''' + (v1, (v2, stack)) = stack + tos = True + while tos: + v3 = v2 % v1 + tos = v3 > 0 + (v1, (v2, stack)) = (v3, (v1, stack)) + return (v2, stack), expression, dictionary + + +@inscribe @SimpleFunctionWrapper def choice(stack): ''' @@ -888,6 +785,22 @@ def b(stack, expression, dictionary): @inscribe @FunctionWrapper +def ii(stack, expression, dictionary): + ''' + :: + + ... a [Q] ii + ------------------ + ... Q a Q + + ''' + quote, (a, stack) = stack + expression = concat(quote, (a, concat(quote, expression))) + return stack, expression, dictionary + + +@inscribe +@FunctionWrapper def dupdip(stack, expression, dictionary): ''' :: @@ -1464,6 +1377,3 @@ for name, primitive in getmembers(genlib, isfunction): add_aliases(_dictionary, ALIASES) - - -DefinitionWrapper.add_definitions(definitions, _dictionary)