1 # -*- coding: utf-8 -*-
3 # Copyright © 2014, 2015, 2017, 2018 Simon Forman
5 # This file is part of Joypy
7 # Joypy is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # Joypy is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Joypy. If not see <http://www.gnu.org/licenses/>.
21 This module contains the Joy function infrastructure and a library of
22 functions. Its main export is a Python function initialize() that
23 returns a dictionary of Joy functions suitable for use with the joy()
26 from inspect import getdoc
27 from functools import wraps
30 from .parser import text_to_expression, Symbol
31 from .utils.stack import list_to_stack, iter_stack, pick, pushback
37 def inscribe(function):
38 '''A decorator to inscribe functions into the default dictionary.'''
39 _dictionary[function.name] = function
44 '''Return a dictionary of Joy functions for use with joy().'''
45 return _dictionary.copy()
54 ('mod', ['%', 'rem', 'remainder', 'modulus']),
57 ('getitem', ['pick', 'at']),
68 ('rolldown', ['roll<']),
69 ('rollup', ['roll>']),
74 def add_aliases(D, A=ALIASES):
76 Given a dict and a iterable of (name, [alias, ...]) pairs, create
77 additional entries in the dict mapping each alias to the named function
78 if it's in the dict. Aliases for functions not in the dict are ignored.
80 for name, aliases in A:
91 third == rest rest first
93 product == 1 swap [*] step
95 swoncat == swap concat
96 flatten == [] swap [concat] step
100 enstacken == stack [clear] dip
101 disenstacken == ? [uncons ?] loop pop
103 dinfrirst == dip infra first
104 nullary == [stack] dinfrirst
105 unary == [stack [pop] dip] dinfrirst
106 binary == [stack [popop] dip] dinfrirst
107 ternary == [stack [popop pop] dip] dinfrirst
111 size == 0 swap [pop ++] step
112 cleave == [i] app2 [popd] dip
113 average == [sum 1.0 *] [size] cleave /
114 gcd == 1 [tuck modulus dup 0 >] loop pop
115 least_fraction == dup [gcd] infra [div] concat map
116 *fraction == [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons
117 *fraction0 == concat [[swap] dip * [*] dip] infra
118 down_to_zero == [0 >] [dup --] while
119 range_to_zero == unit [down_to_zero] infra
120 anamorphism == [pop []] swap [dip swons] genrec
121 range == [0 <=] [1 - dup] anamorphism
122 while == swap [nullary] cons dup dipd concat loop
124 primrec == [i] genrec
125 step_zero == 0 roll> step
129 ##z-down == [] swap uncons swap
130 ##z-up == swons swap shunt
131 ##z-right == [swons] cons dip uncons swap
132 ##z-left == swons [uncons swap] dip swap
135 ##divisor == popop 2 *
137 ##radical == swap dup * rollup * 4 * - sqrt
140 ##q0 == [[divisor] [minusb] [radical]] pam
141 ##q1 == [[root1] [root2]] pam
142 ##quadratic == [q0] ternary i [q1] ternary
146 ##PE1.1 == + dup [+] dip
147 ##PE1.2 == dup [3 & PE1.1] dip 2 >>
148 ##PE1.3 == 14811 swap [PE1.2] times pop
149 ##PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop
151 #PE1.2 == [PE1.1] step
152 #PE1 == 0 0 66 [[3 2 1 3 1 2 3] PE1.2] times [3 2 1 3] PE1.2 pop
156 def FunctionWrapper(f):
157 '''Set name attribute.'''
159 raise ValueError('Function %s must have doc string.' % f.__name__)
160 f.name = f.__name__.rstrip('_') # Don't shadow builtins.
164 def SimpleFunctionWrapper(f):
166 Wrap functions that take and return just a stack.
170 def inner(stack, expression, dictionary):
171 return f(stack), expression, dictionary
175 def BinaryBuiltinWrapper(f):
177 Wrap functions that take two arguments and return a single result.
181 def inner(stack, expression, dictionary):
182 (a, (b, stack)) = stack
184 return (result, stack), expression, dictionary
188 def UnaryBuiltinWrapper(f):
190 Wrap functions that take one argument and return a single result.
194 def inner(stack, expression, dictionary):
197 return (result, stack), expression, dictionary
201 class DefinitionWrapper(object):
203 Provide implementation of defined functions, and some helper methods.
206 def __init__(self, name, body_text, doc=None):
207 self.name = self.__name__ = name
208 self.body = text_to_expression(body_text)
209 self._body = tuple(iter_stack(self.body))
210 self.__doc__ = doc or body_text
212 def __call__(self, stack, expression, dictionary):
213 expression = list_to_stack(self._body, expression)
214 return stack, expression, dictionary
217 def parse_definition(class_, defi):
219 Given some text describing a Joy function definition parse it and
220 return a DefinitionWrapper.
222 name, proper, body_text = (n.strip() for n in defi.partition('=='))
224 raise ValueError('Definition %r failed' % (defi,))
225 return class_(name, body_text)
228 def add_definitions(class_, defs, dictionary):
229 for definition in _text_to_defs(defs):
230 class_.add_def(definition, dictionary)
233 def add_def(class_, definition, dictionary):
234 F = class_.parse_definition(definition)
235 dictionary[F.name] = F
238 def _text_to_defs(text):
239 return (line.strip() for line in text.splitlines() if '==' in line)
248 @SimpleFunctionWrapper
249 def parse((text, stack)):
250 '''Parse the string on the stack to a Joy expression.'''
251 expression = text_to_expression(text)
252 return expression, stack
256 @SimpleFunctionWrapper
257 def first(((head, tail), stack)):
258 '''first == uncons pop'''
263 @SimpleFunctionWrapper
264 def rest(((head, tail), stack)):
265 '''rest == uncons popd'''
270 @SimpleFunctionWrapper
273 getitem == drop first
275 Expects an integer and a quote on the stack and returns the item at the
276 nth position in the quote counting from 0.
279 -------------------------
283 n, (Q, stack) = stack
284 return pick(Q, n), stack
288 @SimpleFunctionWrapper
293 Expects an integer and a quote on the stack and returns the quote with
294 n items removed off the top.
297 ----------------------
301 n, (Q, stack) = stack
312 @SimpleFunctionWrapper
315 Expects an integer and a quote on the stack and returns the quote with
316 just the top n items in reverse order (because that's easier and you can
317 use reverse if needed.)
320 ----------------------
324 n, (Q, stack) = stack
337 @SimpleFunctionWrapper
340 Use a Boolean value to select one of two items.
343 ----------------------
348 ---------------------
351 Currently Python semantics are used to evaluate the "truthiness" of the
352 Boolean value (so empty string, zero, etc. are counted as false, etc.)
354 (if_, (then, (else_, stack))) = stack
355 return then if if_ else else_, stack
359 @SimpleFunctionWrapper
362 Use a Boolean value to select one of two items from a sequence.
365 ------------------------
370 -----------------------
373 The sequence can contain more than two items but not fewer.
374 Currently Python semantics are used to evaluate the "truthiness" of the
375 Boolean value (so empty string, zero, etc. are counted as false, etc.)
377 (flag, (choices, stack)) = stack
378 (else_, (then, _)) = choices
379 return then if flag else else_, stack
383 @SimpleFunctionWrapper
385 '''Given a list find the maximum.'''
387 return max(iter_stack(tos)), stack
391 @SimpleFunctionWrapper
393 '''Given a list find the minimum.'''
395 return min(iter_stack(tos)), stack
399 @SimpleFunctionWrapper
401 '''Given a quoted sequence of numbers return the sum.
403 sum == 0 swap [+] step
406 return sum(iter_stack(tos)), stack
410 @SimpleFunctionWrapper
413 Expects an item on the stack and a quote under it and removes that item
414 from the the quote. The item is only removed once.
417 ------------------------
421 (tos, (second, stack)) = S
422 l = list(iter_stack(second))
424 return list_to_stack(l), stack
428 @SimpleFunctionWrapper
430 '''Given a list remove duplicate items.'''
432 I = list(iter_stack(tos))
433 list_to_stack(sorted(set(I), key=I.index))
434 return list_to_stack(sorted(set(I), key=I.index)), stack
438 @SimpleFunctionWrapper
440 '''Given a list return it sorted.'''
442 return list_to_stack(sorted(iter_stack(tos))), stack
446 @SimpleFunctionWrapper
449 The cons operator expects a list on top of the stack and the potential
450 member below. The effect is to add the potential member into the
453 (tos, (second, stack)) = S
454 return (second, tos), stack
458 @SimpleFunctionWrapper
461 Inverse of cons, removes an item from the top of the list on the stack
462 and places it under the remaining list.
466 return tos, (item, stack)
470 @SimpleFunctionWrapper
472 '''Clear everything from the stack.
482 @SimpleFunctionWrapper
484 '''Duplicate the top item on the stack.'''
486 return tos, (tos, stack)
490 @SimpleFunctionWrapper
493 Copy the second item down on the stack to the top of the stack.
505 @SimpleFunctionWrapper
508 Copy the item at TOS under the second item of the stack.
515 (tos, (second, stack)) = S
516 return tos, (second, (tos, stack))
520 @SimpleFunctionWrapper
522 '''Swap the top two items on stack.'''
523 (tos, (second, stack)) = S
524 return second, (tos, stack)
528 @SimpleFunctionWrapper
531 old_stack, stack = stack
532 return stack, old_stack
536 @SimpleFunctionWrapper
539 The stack operator pushes onto the stack a list containing all the
540 elements of the stack.
546 @SimpleFunctionWrapper
549 The unstack operator expects a list on top of the stack and makes that
550 the stack discarding the rest of the stack.
556 @SimpleFunctionWrapper
558 '''Pop and discard the top item from the stack.'''
563 @SimpleFunctionWrapper
565 '''Pop and discard the second item from the stack.'''
566 (tos, (_, stack)) = stack
571 @SimpleFunctionWrapper
573 '''Pop and discard the third item from the stack.'''
574 (tos, (second, (_, stack))) = stack
575 return tos, (second, stack)
579 @SimpleFunctionWrapper
581 '''Pop and discard the first and second items from the stack.'''
586 @SimpleFunctionWrapper
588 '''Duplicate the second item on the stack.'''
589 (tos, (second, stack)) = S
590 return tos, (second, (second, stack))
594 @SimpleFunctionWrapper
596 '''Reverse the list on the top of the stack.
598 reverse == [] swap shunt
602 for term in iter_stack(tos):
608 @SimpleFunctionWrapper
610 '''Concatinate the two lists on the top of the stack.'''
611 (tos, (second, stack)) = S
612 for term in reversed(list(iter_stack(second))):
618 @SimpleFunctionWrapper
619 def shunt((tos, (second, stack))):
621 shunt == [swons] step
623 Like concat but reverses the top list into the second.
627 second = term, second
632 @SimpleFunctionWrapper
635 Replace the two lists on the top of the stack with a list of the pairs
636 from each list. The smallest list sets the length of the result list.
638 (tos, (second, stack)) = S
641 for a, b in zip(iter_stack(tos), iter_stack(second))
643 return list_to_stack(accumulator), stack
647 @SimpleFunctionWrapper
651 return tos + 1, stack
655 @SimpleFunctionWrapper
659 return tos - 1, stack
663 @SimpleFunctionWrapper
673 a, (b, stack) = stack
679 return int(math.floor(n))
681 floor.__doc__ = math.floor.__doc__
685 @SimpleFunctionWrapper
688 divmod(x, y) -> (quotient, remainder)
690 Return the tuple (x//y, x%y). Invariant: div*y + mod == x.
699 Return the square root of the number a.
700 Negative numbers return complex roots.
705 assert a < 0, repr(a)
706 r = math.sqrt(-a) * 1j
711 @SimpleFunctionWrapper
714 (a, (b, (c, stack))) = S
715 return b, (c, (a, stack))
719 @SimpleFunctionWrapper
722 (a, (b, (c, stack))) = S
723 return c, (a, (b, stack))
728 # if isinstance(text, str):
729 # return run(text, stack)
734 @SimpleFunctionWrapper
736 '''The identity function.'''
741 @SimpleFunctionWrapper
743 '''True if the form on TOS is void otherwise False.'''
745 return _void(form), stack
749 return any(not _void(i) for i in iter_stack(form))
760 def words(stack, expression, dictionary):
761 '''Print all the words in alphabetical order.'''
762 print(' '.join(sorted(dictionary)))
763 return stack, expression, dictionary
768 def sharing(stack, expression, dictionary):
769 '''Print redistribution information.'''
770 print("You may convey verbatim copies of the Program's source code as"
771 ' you receive it, in any medium, provided that you conspicuously'
772 ' and appropriately publish on each copy an appropriate copyright'
773 ' notice; keep intact all notices stating that this License and'
774 ' any non-permissive terms added in accord with section 7 apply'
775 ' to the code; keep intact all notices of the absence of any'
776 ' warranty; and give all recipients a copy of this License along'
778 ' You should have received a copy of the GNU General Public License'
779 ' along with Joypy. If not see <http://www.gnu.org/licenses/>.')
780 return stack, expression, dictionary
785 def warranty(stack, expression, dictionary):
786 '''Print warranty information.'''
787 print('THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY'
788 ' APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE'
789 ' COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM'
790 ' "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR'
791 ' IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES'
792 ' OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE'
793 ' ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS'
794 ' WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE'
795 ' COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.')
796 return stack, expression, dictionary
799 # def simple_manual(stack):
801 # Print words and help for each word.
803 # for name, f in sorted(FUNCTIONS.items()):
805 # boxline = '+%s+' % ('-' * (len(name) + 2))
808 # '| %s |' % (name,),
810 # d if d else ' ...',
820 def help_(S, expression, dictionary):
821 '''Accepts a quoted symbol on the top of the stack and prints its docs.'''
822 ((symbol, _), stack) = S
823 word = dictionary[symbol]
825 return stack, expression, dictionary
833 # Several combinators depend on other words in their definitions,
834 # we use symbols to prevent hard-coding these, so in theory, you
835 # could change the word in the dictionary to use different semantics.
836 S_choice = Symbol('choice')
837 S_first = Symbol('first')
838 S_getitem = Symbol('getitem')
839 S_genrec = Symbol('genrec')
840 S_loop = Symbol('loop')
842 S_ifte = Symbol('ifte')
843 S_infra = Symbol('infra')
844 S_step = Symbol('step')
845 S_times = Symbol('times')
846 S_swaack = Symbol('swaack')
847 S_truthy = Symbol('truthy')
852 def i(stack, expression, dictionary):
854 The i combinator expects a quoted program on the stack and unpacks it
855 onto the pending expression for evaluation.
863 return stack, pushback(quote, expression), dictionary
868 def x(stack, expression, dictionary):
872 ... [Q] x = ... [Q] dup i
873 ... [Q] x = ... [Q] [Q] i
874 ... [Q] x = ... [Q] Q
878 return stack, pushback(quote, expression), dictionary
883 def b(stack, expression, dictionary):
887 ... [P] [Q] b == ... [P] i [Q] i
888 ... [P] [Q] b == ... P Q
891 q, (p, (stack)) = stack
892 return stack, pushback(p, pushback(q, expression)), dictionary
897 def dupdip(stack, expression, dictionary):
899 [F] dupdip == dup [F] dip
909 return stack, pushback(F, (a, expression)), dictionary
914 def infra(stack, expression, dictionary):
916 Accept a quoted program and a list on the stack and run the program
917 with the list as its stack.
919 ... [a b c] [Q] . infra
920 -----------------------------
921 c b a . Q [...] swaack
924 (quote, (aggregate, stack)) = stack
925 return aggregate, pushback(quote, (stack, (S_swaack, expression))), dictionary
930 def genrec(stack, expression, dictionary):
932 General Recursion Combinator.
934 [if] [then] [rec1] [rec2] genrec
935 ---------------------------------------------------------------------
936 [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
938 From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
939 "The genrec combinator takes four program parameters in addition to
940 whatever data parameters it needs. Fourth from the top is an if-part,
941 followed by a then-part. If the if-part yields true, then the then-part
942 is executed and the combinator terminates. The other two parameters are
943 the rec1-part and the rec2-part. If the if-part yields false, the
944 rec1-part is executed. Following that the four program parameters and
945 the combinator are again pushed onto the stack bundled up in a quoted
946 form. Then the rec2-part is executed, where it will find the bundled
947 form. Typically it will then execute the bundled form, either with i or
948 with app2, or some other combinator."
950 The way to design one of these is to fix your base case [then] and the
951 test [if], and then treat rec1 and rec2 as an else-part "sandwiching"
952 a quotation of the whole function.
954 For example, given a (general recursive) function 'F':
956 F == [I] [T] [R1] [R2] genrec
958 If the [I] if-part fails you must derive R1 and R2 from:
962 Just set the stack arguments in front, and figure out what R1 and R2
963 have to do to apply the quoted [F] in the proper way. In effect, the
964 genrec combinator turns into an ifte combinator with a quoted copy of
965 the original definition in the else-part:
967 F == [I] [T] [R1] [R2] genrec
968 == [I] [T] [R1 [F] R2] ifte
970 (Primitive recursive functions are those where R2 == i.
972 P == [I] [T] [R] primrec
973 == [I] [T] [R [P] i] ifte
974 == [I] [T] [R P] ifte
977 (rec2, (rec1, stack)) = stack
978 (then, (if_, _)) = stack
979 F = (if_, (then, (rec1, (rec2, (S_genrec, ())))))
980 else_ = pushback(rec1, (F, rec2))
981 return (else_, stack), (S_ifte, expression), dictionary
986 def map_(S, expression, dictionary):
988 Run the quoted program on TOS on the items in the list under it, push a
989 new list with the results (in place of the program and original list.
991 # (quote, (aggregate, stack)) = S
992 # results = list_to_stack([
993 # joy((term, stack), quote, dictionary)[0][0]
994 # for term in iter_stack(aggregate)
996 # return (results, stack), expression, dictionary
997 (quote, (aggregate, stack)) = S
999 return (aggregate, stack), expression, dictionary
1001 for term in iter_stack(aggregate):
1003 batch = (s, (quote, (S_infra, (S_first, batch))))
1004 stack = (batch, ((), stack))
1005 return stack, (S_infra, expression), dictionary
1008 #def cleave(S, expression, dictionary):
1010 # The cleave combinator expects two quotations, and below that an item X.
1011 # It first executes [P], with X on top, and saves the top result element.
1012 # Then it executes [Q], again with X, and saves the top result.
1013 # Finally it restores the stack to what it was below X and pushes the two
1014 # results P(X) and Q(X).
1016 # (Q, (P, (x, stack))) = S
1017 # p = joy((x, stack), P, dictionary)[0][0]
1018 # q = joy((x, stack), Q, dictionary)[0][0]
1019 # return (q, (p, stack)), expression, dictionary
1024 def branch(stack, expression, dictionary):
1026 Use a Boolean value to select one of two quoted programs to run.
1028 branch == roll< choice i
1031 False [F] [T] branch
1032 --------------------------
1036 -------------------------
1040 (then, (else_, (flag, stack))) = stack
1041 return stack, pushback(then if flag else else_, expression), dictionary
1046 def ifte(stack, expression, dictionary):
1048 If-Then-Else Combinator
1050 ... [if] [then] [else] ifte
1051 ---------------------------------------------------
1052 ... [[else] [then]] [...] [if] infra select i
1057 ... [if] [then] [else] ifte
1058 -------------------------------------------------------
1059 ... [else] [then] [...] [if] infra first choice i
1062 Has the effect of grabbing a copy of the stack on which to run the
1063 if-part using infra.
1065 (else_, (then, (if_, stack))) = stack
1066 expression = (S_infra, (S_first, (S_choice, (S_i, expression))))
1067 stack = (if_, (stack, (then, (else_, stack))))
1068 return stack, expression, dictionary
1073 def dip(stack, expression, dictionary):
1075 The dip combinator expects a quoted program on the stack and below it
1076 some item, it hoists the item into the expression and runs the program
1077 on the rest of the stack.
1084 (quote, (x, stack)) = stack
1085 expression = (x, expression)
1086 return stack, pushback(quote, expression), dictionary
1091 def dipd(S, expression, dictionary):
1093 Like dip but expects two items.
1096 ---------------------
1100 (quote, (x, (y, stack))) = S
1101 expression = (y, (x, expression))
1102 return stack, pushback(quote, expression), dictionary
1107 def dipdd(S, expression, dictionary):
1109 Like dip but expects three items.
1112 -----------------------
1116 (quote, (x, (y, (z, stack)))) = S
1117 expression = (z, (y, (x, expression)))
1118 return stack, pushback(quote, expression), dictionary
1123 def app1(S, expression, dictionary):
1125 Given a quoted program on TOS and anything as the second stack item run
1126 the program and replace the two args with the first result of the
1130 -----------------------------------
1131 ... [x ...] [Q] . infra first
1133 (quote, (x, stack)) = S
1134 stack = (quote, ((x, stack), stack))
1135 expression = (S_infra, (S_first, expression))
1136 return stack, expression, dictionary
1141 def app2(S, expression, dictionary):
1142 '''Like app1 with two items.
1145 -----------------------------------
1146 ... [y ...] [Q] . infra first
1147 [x ...] [Q] infra first
1150 (quote, (x, (y, stack))) = S
1151 expression = (S_infra, (S_first,
1152 ((x, stack), (quote, (S_infra, (S_first,
1154 stack = (quote, ((y, stack), stack))
1155 return stack, expression, dictionary
1160 def app3(S, expression, dictionary):
1161 '''Like app1 with three items.
1163 ... z y x [Q] . app3
1164 -----------------------------------
1165 ... [z ...] [Q] . infra first
1166 [y ...] [Q] infra first
1167 [x ...] [Q] infra first
1170 (quote, (x, (y, (z, stack)))) = S
1171 expression = (S_infra, (S_first,
1172 ((y, stack), (quote, (S_infra, (S_first,
1173 ((x, stack), (quote, (S_infra, (S_first,
1174 expression))))))))))
1175 stack = (quote, ((z, stack), stack))
1176 return stack, expression, dictionary
1181 def step(S, expression, dictionary):
1183 Run a quoted program on each item in a sequence.
1186 -----------------------
1191 ------------------------
1195 ... [a b c] [Q] . step
1196 ----------------------------------------
1197 ... a . Q [b c] [Q] step
1199 The step combinator executes the quotation on each member of the list
1200 on top of the stack.
1202 (quote, (aggregate, stack)) = S
1204 return stack, expression, dictionary
1205 head, tail = aggregate
1206 stack = quote, (head, stack)
1208 expression = tail, (quote, (S_step, expression))
1209 expression = S_i, expression
1210 return stack, expression, dictionary
1215 def times(stack, expression, dictionary):
1217 times == [-- dip] cons [swap] infra [0 >] swap while pop
1220 --------------------- w/ n <= 0
1225 ---------------------------------
1230 --------------------------------- w/ n > 1
1231 ... . Q (n - 1) [Q] times
1234 # times == [-- dip] cons [swap] infra [0 >] swap while pop
1235 (quote, (n, stack)) = stack
1237 return stack, expression, dictionary
1240 expression = n, (quote, (S_times, expression))
1241 expression = pushback(quote, expression)
1242 return stack, expression, dictionary
1245 # The current definition above works like this:
1248 # --------------------------------------
1249 # [P] nullary [Q [P] nullary] loop
1251 # while == [pop i not] [popop] [dudipd] primrec
1253 #def while_(S, expression, dictionary):
1254 # '''[if] [body] while'''
1255 # (body, (if_, stack)) = S
1256 # while joy(stack, if_, dictionary)[0][0]:
1257 # stack = joy(stack, body, dictionary)[0]
1258 # return stack, expression, dictionary
1263 def loop(stack, expression, dictionary):
1265 Basic loop combinator.
1268 -----------------------
1272 ------------------------
1276 quote, (flag, stack) = stack
1278 expression = pushback(quote, (quote, (S_loop, expression)))
1279 return stack, expression, dictionary
1282 #def nullary(S, expression, dictionary):
1284 # Run the program on TOS and return its first result without consuming
1285 # any of the stack (except the program on TOS.)
1287 # (quote, stack) = S
1288 # result = joy(stack, quote, dictionary)
1289 # return (result[0][0], stack), expression, dictionary
1292 #def unary(S, expression, dictionary):
1293 # (quote, stack) = S
1294 # _, return_stack = stack
1295 # result = joy(stack, quote, dictionary)[0]
1296 # return (result[0], return_stack), expression, dictionary
1299 #def binary(S, expression, dictionary):
1300 # (quote, stack) = S
1301 # _, (_, return_stack) = stack
1302 # result = joy(stack, quote, dictionary)[0]
1303 # return (result[0], return_stack), expression, dictionary
1306 #def ternary(S, expression, dictionary):
1307 # (quote, stack) = S
1308 # _, (_, (_, return_stack)) = stack
1309 # result = joy(stack, quote, dictionary)[0]
1310 # return (result[0], return_stack), expression, dictionary
1313 # FunctionWrapper(binary),
1314 # FunctionWrapper(cleave),
1315 # FunctionWrapper(nullary),
1316 # FunctionWrapper(ternary),
1317 # FunctionWrapper(unary),
1318 # FunctionWrapper(while_),
1322 BinaryBuiltinWrapper(operator.add),
1323 BinaryBuiltinWrapper(operator.and_),
1324 BinaryBuiltinWrapper(operator.div),
1325 BinaryBuiltinWrapper(operator.eq),
1326 BinaryBuiltinWrapper(operator.floordiv),
1327 BinaryBuiltinWrapper(operator.ge),
1328 BinaryBuiltinWrapper(operator.gt),
1329 BinaryBuiltinWrapper(operator.le),
1330 BinaryBuiltinWrapper(operator.lshift),
1331 BinaryBuiltinWrapper(operator.lt),
1332 BinaryBuiltinWrapper(operator.mod),
1333 BinaryBuiltinWrapper(operator.mul),
1334 BinaryBuiltinWrapper(operator.ne),
1335 BinaryBuiltinWrapper(operator.or_),
1336 BinaryBuiltinWrapper(operator.pow),
1337 BinaryBuiltinWrapper(operator.rshift),
1338 BinaryBuiltinWrapper(operator.sub),
1339 BinaryBuiltinWrapper(operator.truediv),
1340 BinaryBuiltinWrapper(operator.xor),
1342 UnaryBuiltinWrapper(abs),
1343 UnaryBuiltinWrapper(bool),
1344 UnaryBuiltinWrapper(floor),
1345 UnaryBuiltinWrapper(operator.neg),
1346 UnaryBuiltinWrapper(operator.not_),
1347 UnaryBuiltinWrapper(sqrt),
1352 add_aliases(_dictionary)
1355 DefinitionWrapper.add_definitions(definitions, _dictionary)