1 # -*- coding: utf-8 -*-
3 # Copyright © 2014-2020 Simon Forman
5 # This file is part of Thun
7 # Thun 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 # Thun 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 Thun. 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, getmembers, isfunction
27 from functools import wraps
28 from itertools import count
31 from .parser import text_to_expression, Symbol
32 from .utils import generated_library as genlib
33 from .utils.errors import (
38 from .utils.stack import (
57 # This is the main dict we're building.
61 def inscribe(function, d=_dictionary):
62 '''A decorator to inscribe functions into the default dictionary.'''
63 d[function.name] = function
68 '''Return a dictionary of Joy functions for use with joy().'''
69 return _dictionary.copy()
77 ('floordiv', ['/floor', '//', '/', 'div']),
78 ('mod', ['%', 'rem', 'remainder', 'modulus']),
81 ('getitem', ['pick', 'at']),
92 ('rolldown', ['roll<']),
93 ('rollup', ['roll>']),
99 def add_aliases(D, A):
101 Given a dict and a iterable of (name, [alias, ...]) pairs, create
102 additional entries in the dict mapping each alias to the named function
103 if it's in the dict. Aliases for functions not in the dict are ignored.
105 for name, aliases in A:
110 for alias in aliases:
114 def FunctionWrapper(f):
115 '''Set name attribute.'''
117 raise ValueError('Function %s must have doc string.' % f.__name__)
118 f.name = f.__name__.rstrip('_') # Don't shadow builtins.
122 def SimpleFunctionWrapper(f):
124 Wrap functions that take and return just a stack.
128 def inner(stack, expression, dictionary):
129 return f(stack), expression, dictionary
133 def BinaryBuiltinWrapper(f):
135 Wrap functions that take two arguments and return a single result.
139 def inner(stack, expression, dictionary):
141 (a, (b, stack)) = stack
143 raise StackUnderflowError('Not enough values on stack.')
144 # Boolean predicates like "or" fail here. :(
145 ## if ( not isinstance(a, int)
146 ## or not isinstance(b, int)
147 ## or isinstance(a, bool) # Because bools are ints in Python.
148 ## or isinstance(b, bool)
150 ## raise NotAnIntError
152 return (result, stack), expression, dictionary
156 def UnaryBuiltinWrapper(f):
158 Wrap functions that take one argument and return a single result.
162 def inner(stack, expression, dictionary):
165 return (result, stack), expression, dictionary
171 Definitions created by inscribe.
174 def __init__(self, name, body):
177 self._body = tuple(iter_stack(body))
178 self.__doc__ = expression_to_string(body)
179 self._compiled = None
181 def __call__(self, stack, expression, dictionary):
183 return self._compiled(stack, expression, dictionary) # pylint: disable=E1102
184 expression = list_to_stack(self._body, expression)
185 return stack, expression, dictionary
188 def load_definitions(class_, stream, dictionary):
190 if line.lstrip().startswith('#'):
192 name, body = text_to_expression(line)
193 inscribe(class_(name, body), dictionary)
203 def inscribe_(stack, expression, dictionary):
205 Create a new Joy function definition in the Joy dictionary. A
206 definition is given as a quote with a name followed by a Joy
207 expression. for example:
209 [sqr dup mul] inscribe
212 (name, body), stack = stack
213 inscribe(Def(name, body), dictionary)
214 return stack, expression, dictionary
218 @SimpleFunctionWrapper
220 '''Parse the string on the stack to a Joy expression.'''
222 expression = text_to_expression(text)
223 return expression, stack
227 # @SimpleFunctionWrapper
229 # '''Attempt to infer the stack effect of a Joy expression.'''
231 # effects = infer_expression(E)
232 # e = list_to_stack([(fi, (fo, ())) for fi, fo in effects])
237 @SimpleFunctionWrapper
242 getitem == drop first
244 Expects an integer and a quote on the stack and returns the item at the
245 nth position in the quote counting from 0.
249 -------------------------
253 n, (Q, stack) = stack
254 return pick(Q, n), stack
258 @SimpleFunctionWrapper
265 Expects an integer and a quote on the stack and returns the quote with
266 n items removed off the top.
270 ----------------------
274 n, (Q, stack) = stack
285 @SimpleFunctionWrapper
288 Expects an integer and a quote on the stack and returns the quote with
289 just the top n items in reverse order (because that's easier and you can
290 use reverse if needed.)
294 ----------------------
298 n, (Q, stack) = stack
312 def gcd2(stack, expression, dictionary):
313 '''Compiled GCD function.'''
314 (v1, (v2, stack)) = stack
319 (v1, (v2, stack)) = (v3, (v1, stack))
320 return (v2, stack), expression, dictionary
324 @SimpleFunctionWrapper
327 Use a Boolean value to select one of two items.
331 ----------------------
336 ---------------------
339 Currently Python semantics are used to evaluate the "truthiness" of the
340 Boolean value (so empty string, zero, etc. are counted as false, etc.)
342 (if_, (then, (else_, stack))) = stack
343 return then if if_ else else_, stack
347 @SimpleFunctionWrapper
350 Use a Boolean value to select one of two items from a sequence.
354 ------------------------
359 -----------------------
362 The sequence can contain more than two items but not fewer.
363 Currently Python semantics are used to evaluate the "truthiness" of the
364 Boolean value (so empty string, zero, etc. are counted as false, etc.)
366 (flag, (choices, stack)) = stack
367 (else_, (then, _)) = choices
368 return then if flag else else_, stack
372 @SimpleFunctionWrapper
374 '''Given a list find the maximum.'''
376 return max(iter_stack(tos)), stack
380 @SimpleFunctionWrapper
382 '''Given a list find the minimum.'''
384 return min(iter_stack(tos)), stack
388 @SimpleFunctionWrapper
391 Given a quoted sequence of numbers return the sum.
394 sum == 0 swap [+] step
398 return sum(iter_stack(tos)), stack
402 @SimpleFunctionWrapper
405 Expects an item on the stack and a quote under it and removes that item
406 from the the quote. The item is only removed once.
410 ------------------------
414 (tos, (second, stack)) = S
415 l = list(iter_stack(second))
417 return list_to_stack(l), stack
421 @SimpleFunctionWrapper
423 '''Given a list remove duplicate items.'''
425 I = list(iter_stack(tos))
426 return list_to_stack(sorted(set(I), key=I.index)), stack
430 @SimpleFunctionWrapper
432 '''Given a list return it sorted.'''
434 return list_to_stack(sorted(iter_stack(tos))), stack
438 @SimpleFunctionWrapper
440 '''Clear everything from the stack.
443 clear == stack [pop stack] loop
453 @SimpleFunctionWrapper
454 def disenstacken(stack):
456 The disenstacken operator expects a list on top of the stack and makes that
457 the stack discarding the rest of the stack.
463 @SimpleFunctionWrapper
466 Reverse the list on the top of the stack.
469 reverse == [] swap shunt
473 for term in iter_stack(tos):
479 @SimpleFunctionWrapper
482 Concatinate the two lists on the top of the stack.
485 [a b c] [d e f] concat
486 ----------------------------
490 (tos, (second, stack)) = S
491 return concat(second, tos), stack
495 @SimpleFunctionWrapper
498 Like concat but reverses the top list into the second.
501 shunt == [swons] step == reverse swap concat
503 [a b c] [d e f] shunt
504 ---------------------------
508 (tos, (second, stack)) = stack
511 second = term, second
516 @SimpleFunctionWrapper
519 Replace the two lists on the top of the stack with a list of the pairs
520 from each list. The smallest list sets the length of the result list.
522 (tos, (second, stack)) = S
525 for a, b in zip(iter_stack(tos), iter_stack(second))
527 return list_to_stack(accumulator), stack
531 @SimpleFunctionWrapper
535 return tos + 1, stack
539 @SimpleFunctionWrapper
543 return tos - 1, stack
547 @SimpleFunctionWrapper
558 a, (b, stack) = stack
564 return int(math.floor(n))
566 floor.__doc__ = math.floor.__doc__
570 @SimpleFunctionWrapper
573 divmod(x, y) -> (quotient, remainder)
575 Return the tuple (x//y, x%y). Invariant: q * y + r == x.
584 Return the square root of the number a.
585 Negative numbers return complex roots.
590 assert a < 0, repr(a)
591 r = math.sqrt(-a) * 1j
597 # if isinstance(text, str):
598 # return run(text, stack)
603 @SimpleFunctionWrapper
605 '''The identity function.'''
610 @SimpleFunctionWrapper
612 '''True if the form on TOS is void otherwise False.'''
614 return _void(form), stack
618 return any(not _void(i) for i in iter_stack(form))
629 def words(stack, expression, dictionary):
630 '''Print all the words in alphabetical order.'''
631 print(' '.join(sorted(dictionary)))
632 return stack, expression, dictionary
637 def sharing(stack, expression, dictionary):
638 '''Print redistribution information.'''
639 print("You may convey verbatim copies of the Program's source code as"
640 ' you receive it, in any medium, provided that you conspicuously'
641 ' and appropriately publish on each copy an appropriate copyright'
642 ' notice; keep intact all notices stating that this License and'
643 ' any non-permissive terms added in accord with section 7 apply'
644 ' to the code; keep intact all notices of the absence of any'
645 ' warranty; and give all recipients a copy of this License along'
647 ' You should have received a copy of the GNU General Public License'
648 ' along with Thun. If not see <http://www.gnu.org/licenses/>.')
649 return stack, expression, dictionary
654 def warranty(stack, expression, dictionary):
655 '''Print warranty information.'''
656 print('THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY'
657 ' APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE'
658 ' COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM'
659 ' "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR'
660 ' IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES'
661 ' OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE'
662 ' ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS'
663 ' WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE'
664 ' COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.')
665 return stack, expression, dictionary
668 # def simple_manual(stack):
670 # Print words and help for each word.
672 # for name, f in sorted(FUNCTIONS.items()):
674 # boxline = '+%s+' % ('-' * (len(name) + 2))
677 # '| %s |' % (name,),
679 # d if d else ' ...',
689 def help_(S, expression, dictionary):
690 '''Accepts a quoted symbol on the top of the stack and prints its docs.'''
691 ((symbol, _), stack) = S
692 word = dictionary[symbol]
693 print(HELP_TEMPLATE % (symbol, getdoc(word), symbol))
694 return stack, expression, dictionary
702 # Several combinators depend on other words in their definitions,
703 # we use symbols to prevent hard-coding these, so in theory, you
704 # could change the word in the dictionary to use different semantics.
705 S_choice = Symbol('choice')
706 S_first = Symbol('first')
707 S_genrec = Symbol('genrec')
708 S_getitem = Symbol('getitem')
710 S_ifte = Symbol('ifte')
711 S_infra = Symbol('infra')
712 S_loop = Symbol('loop')
713 S_pop = Symbol('pop')
714 S_primrec = Symbol('primrec')
715 S_step = Symbol('step')
716 S_swaack = Symbol('swaack')
717 S_times = Symbol('times')
722 def i(stack, expression, dictionary):
724 The i combinator expects a quoted program on the stack and unpacks it
725 onto the pending expression for evaluation.
736 raise StackUnderflowError('Not enough values on stack.')
737 return stack, concat(quote, expression), dictionary
742 def x(stack, expression, dictionary):
748 ... [Q] x = ... [Q] dup i
749 ... [Q] x = ... [Q] [Q] i
750 ... [Q] x = ... [Q] Q
754 return stack, concat(quote, expression), dictionary
759 def b(stack, expression, dictionary):
765 ... [P] [Q] b == ... [P] i [Q] i
766 ... [P] [Q] b == ... P Q
769 q, (p, (stack)) = stack
770 return stack, concat(p, concat(q, expression)), dictionary
775 def dupdip(stack, expression, dictionary):
779 [F] dupdip == dup [F] dip
789 return stack, concat(F, (a, expression)), dictionary
794 def infra(stack, expression, dictionary):
796 Accept a quoted program and a list on the stack and run the program
797 with the list as its stack. Does not affect the rest of the stack.
800 ... [a b c] [Q] . infra
801 -----------------------------
802 c b a . Q [...] swaack
805 (quote, (aggregate, stack)) = stack
806 return aggregate, concat(quote, (stack, (S_swaack, expression))), dictionary
811 def genrec(stack, expression, dictionary):
813 General Recursion Combinator.
816 [if] [then] [rec1] [rec2] genrec
817 ---------------------------------------------------------------------
818 [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
820 From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
821 "The genrec combinator takes four program parameters in addition to
822 whatever data parameters it needs. Fourth from the top is an if-part,
823 followed by a then-part. If the if-part yields true, then the then-part
824 is executed and the combinator terminates. The other two parameters are
825 the rec1-part and the rec2-part. If the if-part yields false, the
826 rec1-part is executed. Following that the four program parameters and
827 the combinator are again pushed onto the stack bundled up in a quoted
828 form. Then the rec2-part is executed, where it will find the bundled
829 form. Typically it will then execute the bundled form, either with i or
830 with app2, or some other combinator."
832 The way to design one of these is to fix your base case [then] and the
833 test [if], and then treat rec1 and rec2 as an else-part "sandwiching"
834 a quotation of the whole function.
836 For example, given a (general recursive) function 'F':
839 F == [I] [T] [R1] [R2] genrec
841 If the [I] if-part fails you must derive R1 and R2 from:
846 Just set the stack arguments in front, and figure out what R1 and R2
847 have to do to apply the quoted [F] in the proper way. In effect, the
848 genrec combinator turns into an ifte combinator with a quoted copy of
849 the original definition in the else-part:
852 F == [I] [T] [R1] [R2] genrec
853 == [I] [T] [R1 [F] R2] ifte
855 Primitive recursive functions are those where R2 == i.
858 P == [I] [T] [R] tailrec
859 == [I] [T] [R [P] i] ifte
860 == [I] [T] [R P] ifte
863 (rec2, (rec1, stack)) = stack
864 (then, (if_, _)) = stack
865 F = (if_, (then, (rec1, (rec2, (S_genrec, ())))))
866 else_ = concat(rec1, (F, rec2))
867 return (else_, stack), (S_ifte, expression), dictionary
872 def map_(S, expression, dictionary):
874 Run the quoted program on TOS on the items in the list under it, push a
875 new list with the results in place of the program and original list.
877 # (quote, (aggregate, stack)) = S
878 # results = list_to_stack([
879 # joy((term, stack), quote, dictionary)[0][0]
880 # for term in iter_stack(aggregate)
882 # return (results, stack), expression, dictionary
883 (quote, (aggregate, stack)) = S
885 return (aggregate, stack), expression, dictionary
887 for term in iter_stack(aggregate):
889 batch = (s, (quote, (S_infra, (S_first, batch))))
890 stack = (batch, ((), stack))
891 return stack, (S_infra, expression), dictionary
896 def primrec(stack, expression, dictionary):
898 From the "Overview of the language JOY":
900 > The primrec combinator expects two quoted programs in addition to a
901 data parameter. For an integer data parameter it works like this: If
902 the data parameter is zero, then the first quotation has to produce
903 the value to be returned. If the data parameter is positive then the
904 second has to combine the data parameter with the result of applying
905 the function to its predecessor.::
909 > Then primrec tests whether the top element on the stack (initially
910 the 5) is equal to zero. If it is, it pops it off and executes one of
911 the quotations, the [1] which leaves 1 on the stack as the result.
912 Otherwise it pushes a decremented copy of the top element and
913 recurses. On the way back from the recursion it uses the other
914 quotation, [*], to multiply what is now a factorial on top of the
915 stack by the second element on the stack.::
917 n [Base] [Recur] primrec
919 0 [Base] [Recur] primrec
920 ------------------------------
923 n [Base] [Recur] primrec
924 ------------------------------------------ n > 0
925 n (n-1) [Base] [Recur] primrec Recur
928 recur, (base, (n, stack)) = stack
930 expression = concat(base, expression)
932 expression = S_primrec, concat(recur, expression)
933 stack = recur, (base, (n - 1, (n, stack)))
934 return stack, expression, dictionary
937 #def cleave(S, expression, dictionary):
939 # The cleave combinator expects two quotations, and below that an item X.
940 # It first executes [P], with X on top, and saves the top result element.
941 # Then it executes [Q], again with X, and saves the top result.
942 # Finally it restores the stack to what it was below X and pushes the two
943 # results P(X) and Q(X).
945 # (Q, (P, (x, stack))) = S
946 # p = joy((x, stack), P, dictionary)[0][0]
947 # q = joy((x, stack), Q, dictionary)[0][0]
948 # return (q, (p, stack)), expression, dictionary
953 def branch(stack, expression, dictionary):
955 Use a Boolean value to select one of two quoted programs to run.
959 branch == roll< choice i
964 --------------------------
968 -------------------------
972 (then, (else_, (flag, stack))) = stack
973 return stack, concat(then if flag else else_, expression), dictionary
978 ##def ifte(stack, expression, dictionary):
980 ## If-Then-Else Combinator
983 ## ... [if] [then] [else] ifte
984 ## ---------------------------------------------------
985 ## ... [[else] [then]] [...] [if] infra select i
990 ## ... [if] [then] [else] ifte
991 ## -------------------------------------------------------
992 ## ... [else] [then] [...] [if] infra first choice i
995 ## Has the effect of grabbing a copy of the stack on which to run the
996 ## if-part using infra.
998 ## (else_, (then, (if_, stack))) = stack
999 ## expression = (S_infra, (S_first, (S_choice, (S_i, expression))))
1000 ## stack = (if_, (stack, (then, (else_, stack))))
1001 ## return stack, expression, dictionary
1006 def cond(stack, expression, dictionary):
1008 This combinator works like a case statement. It expects a single quote
1009 on the stack that must contain zero or more condition quotes and a
1010 default quote. Each condition clause should contain a quoted predicate
1011 followed by the function expression to run if that predicate returns
1012 true. If no predicates return true the default function runs.
1014 It works by rewriting into a chain of nested `ifte` expressions, e.g.::
1016 [[[B0] T0] [[B1] T1] [D]] cond
1017 -----------------------------------------
1018 [B0] [T0] [[B1] [T1] [D] ifte] ifte
1021 conditions, stack = stack
1023 expression = _cond(conditions, expression)
1025 # Attempt to preload the args to first ifte.
1026 (P, (T, (E, expression))) = expression
1028 # If, for any reason, the argument to cond should happen to contain
1029 # only the default clause then this optimization will fail.
1032 stack = (E, (T, (P, stack)))
1033 return stack, expression, dictionary
1036 def _cond(conditions, expression):
1037 (clause, rest) = conditions
1038 if not rest: # clause is [D]
1041 return (P, (T, (_cond(rest, ()), (S_ifte, expression))))
1046 def dip(stack, expression, dictionary):
1048 The dip combinator expects a quoted program on the stack and below it
1049 some item, it hoists the item into the expression and runs the program
1050 on the rest of the stack.
1059 (quote, (x, stack)) = stack
1061 raise StackUnderflowError('Not enough values on stack.')
1062 expression = (x, expression)
1063 return stack, concat(quote, expression), dictionary
1068 def dipd(S, expression, dictionary):
1070 Like dip but expects two items.
1074 ---------------------
1078 (quote, (x, (y, stack))) = S
1079 expression = (y, (x, expression))
1080 return stack, concat(quote, expression), dictionary
1085 def dipdd(S, expression, dictionary):
1087 Like dip but expects three items.
1091 -----------------------
1095 (quote, (x, (y, (z, stack)))) = S
1096 expression = (z, (y, (x, expression)))
1097 return stack, concat(quote, expression), dictionary
1102 def app1(S, expression, dictionary):
1104 Given a quoted program on TOS and anything as the second stack item run
1105 the program and replace the two args with the first result of the
1110 -----------------------------------
1111 ... [x ...] [Q] . infra first
1114 (quote, (x, stack)) = S
1115 stack = (quote, ((x, stack), stack))
1116 expression = (S_infra, (S_first, expression))
1117 return stack, expression, dictionary
1122 def app2(S, expression, dictionary):
1123 '''Like app1 with two items.
1127 -----------------------------------
1128 ... [y ...] [Q] . infra first
1129 [x ...] [Q] infra first
1132 (quote, (x, (y, stack))) = S
1133 expression = (S_infra, (S_first,
1134 ((x, stack), (quote, (S_infra, (S_first,
1136 stack = (quote, ((y, stack), stack))
1137 return stack, expression, dictionary
1142 def app3(S, expression, dictionary):
1143 '''Like app1 with three items.
1146 ... z y x [Q] . app3
1147 -----------------------------------
1148 ... [z ...] [Q] . infra first
1149 [y ...] [Q] infra first
1150 [x ...] [Q] infra first
1153 (quote, (x, (y, (z, stack)))) = S
1154 expression = (S_infra, (S_first,
1155 ((y, stack), (quote, (S_infra, (S_first,
1156 ((x, stack), (quote, (S_infra, (S_first,
1157 expression))))))))))
1158 stack = (quote, ((z, stack), stack))
1159 return stack, expression, dictionary
1164 def step(S, expression, dictionary):
1166 Run a quoted program on each item in a sequence.
1170 -----------------------
1175 ------------------------
1179 ... [a b c] [Q] . step
1180 ----------------------------------------
1181 ... a . Q [b c] [Q] step
1183 The step combinator executes the quotation on each member of the list
1184 on top of the stack.
1186 (quote, (aggregate, stack)) = S
1188 return stack, expression, dictionary
1189 head, tail = aggregate
1190 stack = quote, (head, stack)
1192 expression = tail, (quote, (S_step, expression))
1193 expression = S_i, expression
1194 return stack, expression, dictionary
1199 def times(stack, expression, dictionary):
1201 times == [-- dip] cons [swap] infra [0 >] swap while pop
1205 --------------------- w/ n <= 0
1210 -----------------------
1215 ------------------------------------- w/ n > 1
1216 ... . Q (n - 1) [Q] times
1219 # times == [-- dip] cons [swap] infra [0 >] swap while pop
1220 (quote, (n, stack)) = stack
1222 return stack, expression, dictionary
1225 expression = n, (quote, (S_times, expression))
1226 expression = concat(quote, expression)
1227 return stack, expression, dictionary
1230 # The current definition above works like this:
1233 # --------------------------------------
1234 # [P] nullary [Q [P] nullary] loop
1236 # while == [pop i not] [popop] [dudipd] tailrec
1238 #def while_(S, expression, dictionary):
1239 # '''[if] [body] while'''
1240 # (body, (if_, stack)) = S
1241 # while joy(stack, if_, dictionary)[0][0]:
1242 # stack = joy(stack, body, dictionary)[0]
1243 # return stack, expression, dictionary
1248 def loop(stack, expression, dictionary):
1250 Basic loop combinator.
1254 -----------------------
1258 ------------------------
1263 quote, stack = stack
1265 raise StackUnderflowError('Not enough values on stack.')
1266 if not isinstance(quote, tuple):
1267 raise NotAListError('Loop body not a list.')
1269 (flag, stack) = stack
1271 raise StackUnderflowError('Not enough values on stack.')
1273 expression = concat(quote, (quote, (S_loop, expression)))
1274 return stack, expression, dictionary
1279 def cmp_(stack, expression, dictionary):
1281 cmp takes two values and three quoted programs on the stack and runs
1282 one of the three depending on the results of comparing the two values:
1286 ------------------------- a > b
1290 ------------------------- a = b
1294 ------------------------- a < b
1297 L, (E, (G, (b, (a, stack)))) = stack
1298 expression = concat(G if a > b else L if a < b else E, expression)
1299 return stack, expression, dictionary
1302 # FunctionWrapper(cleave),
1303 # FunctionWrapper(while_),
1308 #divmod_ = pm = __(n2, n1), __(n4, n3)
1310 BinaryBuiltinWrapper(operator.eq),
1311 BinaryBuiltinWrapper(operator.ge),
1312 BinaryBuiltinWrapper(operator.gt),
1313 BinaryBuiltinWrapper(operator.le),
1314 BinaryBuiltinWrapper(operator.lt),
1315 BinaryBuiltinWrapper(operator.ne),
1317 BinaryBuiltinWrapper(operator.xor),
1318 BinaryBuiltinWrapper(operator.lshift),
1319 BinaryBuiltinWrapper(operator.rshift),
1321 BinaryBuiltinWrapper(operator.and_),
1322 BinaryBuiltinWrapper(operator.or_),
1324 BinaryBuiltinWrapper(operator.add),
1325 BinaryBuiltinWrapper(operator.floordiv),
1326 BinaryBuiltinWrapper(operator.mod),
1327 BinaryBuiltinWrapper(operator.mul),
1328 BinaryBuiltinWrapper(operator.pow),
1329 BinaryBuiltinWrapper(operator.sub),
1330 ## BinaryBuiltinWrapper(operator.truediv),
1332 UnaryBuiltinWrapper(bool),
1333 UnaryBuiltinWrapper(operator.not_),
1335 UnaryBuiltinWrapper(abs),
1336 UnaryBuiltinWrapper(operator.neg),
1337 UnaryBuiltinWrapper(sqrt),
1339 UnaryBuiltinWrapper(floor),
1340 UnaryBuiltinWrapper(round),
1343 del F # Otherwise Sphinx autodoc will pick it up.
1346 for name, primitive in getmembers(genlib, isfunction):
1347 inscribe(SimpleFunctionWrapper(primitive))
1350 add_aliases(_dictionary, ALIASES)