i got used to it, but Jupyter likes 4

This commit is contained in:
Simon Forman 2018-07-17 10:49:09 -07:00
parent 14d67dd7c5
commit 25b7871074
1 changed files with 248 additions and 248 deletions

View File

@ -5,77 +5,77 @@ from joy.parser import Symbol
class AnyJoyType(object): class AnyJoyType(object):
''' '''
Joy type variable. Represents any Joy value. Joy type variable. Represents any Joy value.
''' '''
accept = tuple, int, float, long, complex, str, unicode, bool, Symbol accept = tuple, int, float, long, complex, str, unicode, bool, Symbol
prefix = 'a' prefix = 'a'
def __init__(self, number): def __init__(self, number):
self.number = number self.number = number
def __repr__(self): def __repr__(self):
return self.prefix + str(self.number) return self.prefix + str(self.number)
def __eq__(self, other): def __eq__(self, other):
return ( return (
isinstance(other, self.__class__) isinstance(other, self.__class__)
and other.prefix == self.prefix and other.prefix == self.prefix
and other.number == self.number and other.number == self.number
) )
def __ge__(self, other): def __ge__(self, other):
return ( return (
issubclass(other.__class__, self.__class__) issubclass(other.__class__, self.__class__)
or isinstance(other, self.accept) or isinstance(other, self.accept)
) )
def __le__(self, other): def __le__(self, other):
# 'a string' >= AnyJoyType() should be False. # 'a string' >= AnyJoyType() should be False.
return issubclass(self.__class__, other.__class__) return issubclass(self.__class__, other.__class__)
def __add__(self, other): def __add__(self, other):
return self.__class__(self.number + other) return self.__class__(self.number + other)
__radd__ = __add__ __radd__ = __add__
def __hash__(self): def __hash__(self):
return hash(repr(self)) return hash(repr(self))
class BooleanJoyType(AnyJoyType): class BooleanJoyType(AnyJoyType):
accept = bool accept = bool
prefix = 'b' prefix = 'b'
class NumberJoyType(AnyJoyType): class NumberJoyType(AnyJoyType):
accept = int, float, long, complex accept = int, float, long, complex
prefix = 'n' prefix = 'n'
class FloatJoyType(NumberJoyType): class FloatJoyType(NumberJoyType):
accept = float accept = float
prefix = 'f' prefix = 'f'
class IntJoyType(FloatJoyType): class IntJoyType(FloatJoyType):
accept = int accept = int
prefix = 'i' prefix = 'i'
class TextJoyType(FloatJoyType): class TextJoyType(FloatJoyType):
accept = basestring accept = basestring
prefix = 't' prefix = 't'
class StackJoyType(AnyJoyType): class StackJoyType(AnyJoyType):
accept = tuple accept = tuple
prefix = 's' prefix = 's'
def __nonzero__(self): def __nonzero__(self):
# Imitate () at the end of cons list. # Imitate () at the end of cons list.
return False return False
class JoyTypeError(Exception): pass class JoyTypeError(Exception): pass
@ -97,178 +97,178 @@ def reify(meaning, name, seen=None):
def relabel(left, right): def relabel(left, right):
''' '''
Re-number type variables to avoid collisions between stack effects. Re-number type variables to avoid collisions between stack effects.
''' '''
return left, _1000(right) return left, _1000(right)
def _1000(right): def _1000(right):
if not isinstance(right, tuple): if not isinstance(right, tuple):
return 1000 + right return 1000 + right
return tuple(_1000(n) for n in right) return tuple(_1000(n) for n in right)
def delabel(f, seen=None, c=None): def delabel(f, seen=None, c=None):
''' '''
Fix up type variable numbers after relabel(). Fix up type variable numbers after relabel().
''' '''
if seen is None: if seen is None:
assert c is None assert c is None
seen, c = {}, Counter() seen, c = {}, Counter()
try:
return seen[f]
except KeyError:
pass
if not isinstance(f, tuple):
try: try:
return seen[f] seen[f] = f.__class__(c[f.prefix] + 1)
except KeyError: except (TypeError, # FunctionJoyTypes break this.
pass AttributeError): # Symbol
seen[f] = f
else:
c[f.prefix] += 1
return seen[f]
if not isinstance(f, tuple): return tuple(delabel(inner, seen, c) for inner in f)
try:
seen[f] = f.__class__(c[f.prefix] + 1)
except (TypeError, # FunctionJoyTypes break this.
AttributeError): # Symbol
seen[f] = f
else:
c[f.prefix] += 1
return seen[f]
return tuple(delabel(inner, seen, c) for inner in f)
def unify(u, v, s=None): def unify(u, v, s=None):
''' '''
Return a substitution dict representing a unifier for u and v. Return a substitution dict representing a unifier for u and v.
''' '''
if s is None: if s is None:
s = {} s = {}
elif s: elif s:
u = reify(s, u) u = reify(s, u)
v = reify(s, v) v = reify(s, v)
if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
if u >= v:
s[u] = v
elif v >= u:
s[v] = u
else:
raise JoyTypeError('Cannot unify %r and %r.' % (u, v))
elif isinstance(u, tuple) and isinstance(v, tuple):
if len(u) != len(v) != 2:
raise ValueError(repr((u, v))) # Bad input.
(a, b), (c, d) = u, v
s = unify(b, d, unify(a, c, s))
elif isinstance(v, tuple):
if not _stacky(u):
raise JoyTypeError('Cannot unify %r and %r.' % (u, v))
s[u] = v
elif isinstance(u, tuple):
if not _stacky(v):
raise JoyTypeError('Cannot unify %r and %r.' % (v, u))
s[v] = u
if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
if u >= v:
s[u] = v
elif v >= u:
s[v] = u
else: else:
raise JoyTypeError('Cannot unify %r and %r.' % (u, v)) raise JoyTypeError('Cannot unify %r and %r.' % (u, v))
return s elif isinstance(u, tuple) and isinstance(v, tuple):
if len(u) != len(v) != 2:
raise ValueError(repr((u, v))) # Bad input.
(a, b), (c, d) = u, v
s = unify(b, d, unify(a, c, s))
elif isinstance(v, tuple):
if not _stacky(u):
raise JoyTypeError('Cannot unify %r and %r.' % (u, v))
s[u] = v
elif isinstance(u, tuple):
if not _stacky(v):
raise JoyTypeError('Cannot unify %r and %r.' % (v, u))
s[v] = u
else:
raise JoyTypeError('Cannot unify %r and %r.' % (u, v))
return s
def _stacky(thing): def _stacky(thing):
return thing.__class__ in {AnyJoyType, StackJoyType} return thing.__class__ in {AnyJoyType, StackJoyType}
def _compose(f, g): def _compose(f, g):
''' '''
Return the stack effect of the composition of two stack effects. Return the stack effect of the composition of two stack effects.
''' '''
# Relabel, unify, update, delabel. # Relabel, unify, update, delabel.
(f_in, f_out), (g_in, g_out) = relabel(f, g) (f_in, f_out), (g_in, g_out) = relabel(f, g)
fg = reify(unify(g_in, f_out), (f_in, g_out)) fg = reify(unify(g_in, f_out), (f_in, g_out))
return delabel(fg) return delabel(fg)
def compose(*functions): def compose(*functions):
''' '''
Return the stack effect of the composition of some of stack effects. Return the stack effect of the composition of some of stack effects.
''' '''
return reduce(_compose, functions) return reduce(_compose, functions)
def compilable(f): def compilable(f):
''' '''
Return True if a stack effect represents a function that can be Return True if a stack effect represents a function that can be
automatically compiled (to Python), False otherwise. automatically compiled (to Python), False otherwise.
''' '''
return isinstance(f, tuple) and all(imap(compilable, f)) or _stacky(f) return isinstance(f, tuple) and all(imap(compilable, f)) or _stacky(f)
def doc_from_stack_effect(inputs, outputs): def doc_from_stack_effect(inputs, outputs):
''' '''
Return a crude string representation of a stack effect. Return a crude string representation of a stack effect.
''' '''
switch = [False] # Do we need to display the '...' for the rest of the main stack? switch = [False] # Do we need to display the '...' for the rest of the main stack?
i, o = _f(inputs, switch), _f(outputs, switch) i, o = _f(inputs, switch), _f(outputs, switch)
if switch[0]: if switch[0]:
i.append('...') i.append('...')
o.append('...') o.append('...')
return '(%s--%s)' % ( return '(%s--%s)' % (
' '.join(reversed([''] + i)), ' '.join(reversed([''] + i)),
' '.join(reversed(o + [''])), ' '.join(reversed(o + [''])),
) )
def _f(term, switch): def _f(term, switch):
a = [] a = []
while term and isinstance(term, tuple): while term and isinstance(term, tuple):
item, term = term item, term = term
a.append(item) a.append(item)
assert isinstance(term, (tuple, StackJoyType)), repr(term) assert isinstance(term, (tuple, StackJoyType)), repr(term)
a = [_to_str(i, term, switch) for i in a] a = [_to_str(i, term, switch) for i in a]
return a return a
def _to_str(term, stack, switch): def _to_str(term, stack, switch):
if not isinstance(term, tuple): if not isinstance(term, tuple):
if term == stack:
switch[0] = True
return '[...]'
return (
'[...%i]' % term.number
if isinstance(term, StackJoyType)
else str(term)
)
a = []
while term and isinstance(term, tuple):
item, term = term
a.append(_to_str(item, stack, switch))
assert isinstance(term, (tuple, StackJoyType)), repr(term)
if term == stack: if term == stack:
switch[0] = True switch[0] = True
end = '' if term == () else '...' return '[...]'
#end = '...' return (
else: '[...%i]' % term.number
end = '' if term == () else '...%i' % term.number if isinstance(term, StackJoyType)
a.append(end) else str(term)
return '[%s]' % ' '.join(a) )
a = []
while term and isinstance(term, tuple):
item, term = term
a.append(_to_str(item, stack, switch))
assert isinstance(term, (tuple, StackJoyType)), repr(term)
if term == stack:
switch[0] = True
end = '' if term == () else '...'
#end = '...'
else:
end = '' if term == () else '...%i' % term.number
a.append(end)
return '[%s]' % ' '.join(a)
def compile_(name, f, doc=None): def compile_(name, f, doc=None):
''' '''
Return a string of Python code implementing the function described Return a string of Python code implementing the function described
by the stack effect. If no doc string is passed doc_from_stack_effect() by the stack effect. If no doc string is passed doc_from_stack_effect()
is used to generate one. is used to generate one.
''' '''
i, o = f i, o = f
if doc is None: if doc is None:
doc = doc_from_stack_effect(i, o) doc = doc_from_stack_effect(i, o)
return '''def %s(stack): return '''def %s(stack):
""" """
:: ::
%s %s
""" """
%s = stack %s = stack
@ -276,16 +276,16 @@ def compile_(name, f, doc=None):
def __(*seq): def __(*seq):
stack = StackJoyType(23) stack = StackJoyType(23)
for item in seq: stack = item, stack for item in seq: stack = item, stack
return stack return stack
def stack_effect(*inputs): def stack_effect(*inputs):
def _stack_effect(*outputs): def _stack_effect(*outputs):
pass pass
return _stack_effect return _stack_effect
@ -302,92 +302,92 @@ T = t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 = map(TextJoyType, _R)
def defs(): def defs():
''' '''
Return a dict of named stack effects. Return a dict of named stack effects.
''' '''
at = __(s0, i1), __(a1) at = __(s0, i1), __(a1)
drop = take = __(s0, i1), __(s1) drop = take = __(s0, i1), __(s1)
cons = __(a1, s0), __((a1, s0),) cons = __(a1, s0), __((a1, s0),)
ccons = compose(cons, cons) ccons = compose(cons, cons)
dup = __(a1,), __(a1, a1) dup = __(a1,), __(a1, a1)
dupd = __(a2, a1), __(a2, a2, a1) dupd = __(a2, a1), __(a2, a2, a1)
dupdd = __(a3, a2, a1), __(a3, a3, a2, a1) dupdd = __(a3, a2, a1), __(a3, a3, a2, a1)
first = __((a1, s1),), __(a1,) first = __((a1, s1),), __(a1,)
inscribe = __(t1), __() inscribe = __(t1), __()
over = __(a2, a1), __(a2, a1, a2) over = __(a2, a1), __(a2, a1, a2)
pop = __(a1), __() pop = __(a1), __()
popd = __(a2, a1,), __(a1) popd = __(a2, a1,), __(a1)
popdd = __(a3, a2, a1,), __(a2, a1,) popdd = __(a3, a2, a1,), __(a2, a1,)
popop = __(a2, a1,), __() popop = __(a2, a1,), __()
popopd = __(a3, a2, a1,), __(a1) popopd = __(a3, a2, a1,), __(a1)
popopdd = __(a4, a3, a2, a1,), __(a2, a1) popopdd = __(a4, a3, a2, a1,), __(a2, a1)
rest = __((a1, s0),), __(s0,) rest = __((a1, s0),), __(s0,)
rolldown = __(a1, a2, a3), __(a2, a3, a1) rolldown = __(a1, a2, a3), __(a2, a3, a1)
rollup = __(a1, a2, a3), __(a3, a1, a2) rollup = __(a1, a2, a3), __(a3, a1, a2)
rrest = compose(rest, rest) rrest = compose(rest, rest)
second = compose(rest, first) second = compose(rest, first)
stack = s0, (s0, s0) stack = s0, (s0, s0)
swaack = (s1, s0), (s0, s1) swaack = (s1, s0), (s0, s1)
swap = __(a1, a2), __(a2, a1) swap = __(a1, a2), __(a2, a1)
swons = compose(swap, cons) swons = compose(swap, cons)
third = compose(rest, second) third = compose(rest, second)
tuck = __(a2, a1), __(a1, a2, a1) tuck = __(a2, a1), __(a1, a2, a1)
uncons = __((a1, s0),), __(a1, s0) uncons = __((a1, s0),), __(a1, s0)
unswons = compose(uncons, swap) unswons = compose(uncons, swap)
stuncons = compose(stack, uncons) stuncons = compose(stack, uncons)
stununcons = compose(stack, uncons, uncons) stununcons = compose(stack, uncons, uncons)
unit = __(a1), __((a1, ())) unit = __(a1), __((a1, ()))
of = compose(swap, at) of = compose(swap, at)
clear = s0, s1 clear = s0, s1
eq = ge = gt = le = lt = ne = __(n1, n2), __(b1) eq = ge = gt = le = lt = ne = __(n1, n2), __(b1)
and_ = __(b1, b2), __(b3) and_ = __(b1, b2), __(b3)
bool_ = not_ = __(a1), __(b1) bool_ = not_ = __(a1), __(b1)
eh = compose(dup, bool_) eh = compose(dup, bool_)
add = div = floordiv = mod = mul = pow_ = sub = truediv = \ add = div = floordiv = mod = mul = pow_ = sub = truediv = \
lshift = rshift = __(n1, n2), __(n3,) lshift = rshift = __(n1, n2), __(n3,)
sqr = compose(dup, mul) sqr = compose(dup, mul)
abs_ = floor = sqrt = succ = pred = neg = __(n1,), __(n2,) abs_ = floor = sqrt = succ = pred = neg = __(n1,), __(n2,)
divmod_ = pm = __(n2, n1), __(n4, n3) divmod_ = pm = __(n2, n1), __(n4, n3)
first_two = compose(uncons, uncons, pop) first_two = compose(uncons, uncons, pop)
fourth = compose(rest, third) fourth = compose(rest, third)
of = compose(swap, at) of = compose(swap, at)
_Tree_add_Ee = compose(pop, swap, rolldown, rrest, ccons) _Tree_add_Ee = compose(pop, swap, rolldown, rrest, ccons)
_Tree_get_E = compose(popop, second) _Tree_get_E = compose(popop, second)
_Tree_delete_clear_stuff = compose(rollup, popop, rest) _Tree_delete_clear_stuff = compose(rollup, popop, rest)
_Tree_delete_R0 = compose(over, first, swap, dup) _Tree_delete_R0 = compose(over, first, swap, dup)
return { return {
name.rstrip('_'): stack_effect name.rstrip('_'): stack_effect
for name, stack_effect in locals().iteritems() for name, stack_effect in locals().iteritems()
} }
DEFS = defs() DEFS = defs()
def show(): def show():
for name, stack_effect_comment in sorted(DEFS.iteritems()): for name, stack_effect_comment in sorted(DEFS.iteritems()):
t = ' *'[compilable(stack_effect_comment)] t = ' *'[compilable(stack_effect_comment)]
print name, '=', doc_from_stack_effect(*stack_effect_comment), t print name, '=', doc_from_stack_effect(*stack_effect_comment), t
def generate_library_code(f=None): def generate_library_code(f=None):
if f is None: if f is None:
import sys import sys
f = sys.stdout f = sys.stdout
print >> f, '# GENERATED FILE. DO NOT EDIT.\n' print >> f, '# GENERATED FILE. DO NOT EDIT.\n'
for name, stack_effect_comment in sorted(DEFS.iteritems()): for name, stack_effect_comment in sorted(DEFS.iteritems()):
if not compilable(stack_effect_comment): if not compilable(stack_effect_comment):
continue continue
print >> f print >> f
print >> f, compile_(name, stack_effect_comment) print >> f, compile_(name, stack_effect_comment)
print >> f print >> f
if __name__ == '__main__': if __name__ == '__main__':
show() show()