So fra, so good...

This commit is contained in:
Simon Forman 2018-07-17 12:43:24 -07:00
parent 25b7871074
commit c2dd7cca0a
2 changed files with 144 additions and 124 deletions

View File

@ -34,6 +34,8 @@ from .utils.brutal_hackery import rename_code_object
from .utils import generated_library as genlib from .utils import generated_library as genlib
from .utils.types import ( from .utils.types import (
compose,
ef,
stack_effect, stack_effect,
AnyJoyType, AnyJoyType,
BooleanJoyType, BooleanJoyType,
@ -42,6 +44,7 @@ from .utils.types import (
FloatJoyType, FloatJoyType,
IntJoyType, IntJoyType,
TextJoyType, TextJoyType,
_functions,
) )
@ -55,6 +58,17 @@ I = i0, i1, i2, i3, i4, i5, i6, i7, i8, i9 = map(IntJoyType, _R)
T = t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 = map(TextJoyType, _R) T = t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 = map(TextJoyType, _R)
sec0 = stack_effect(t1)()
sec1 = stack_effect(s0, i1)(s1)
sec2 = stack_effect(s0, i1)(a1)
sec_binary_cmp = stack_effect(n1, n2)(b1)
sec_binary_ints = stack_effect(i1, i2)(i3)
sec_binary_logic = stack_effect(b1, b2)(b3)
sec_binary_math = stack_effect(n1, n2)(n3)
sec_unary_logic = stack_effect(a1)(b1)
sec_unary_math = stack_effect(n1)(n2)
_dictionary = {} _dictionary = {}
@ -74,6 +88,8 @@ ALIASES = (
('and', ['&']), ('and', ['&']),
('bool', ['truthy']), ('bool', ['truthy']),
('mul', ['*']), ('mul', ['*']),
('floordiv', ['/floor', '//']),
('floor', ['round']),
('truediv', ['/']), ('truediv', ['/']),
('mod', ['%', 'rem', 'remainder', 'modulus']), ('mod', ['%', 'rem', 'remainder', 'modulus']),
('eq', ['=']), ('eq', ['=']),
@ -111,6 +127,58 @@ def add_aliases(D, A):
D[alias] = F D[alias] = F
def yin_functions():
'''
Return a dict of named stack effects.
"Yin" functions are those that only rearrange items in stacks and
can be defined completely by their stack effects. This means they
can be auto-compiled.
'''
cons = ef(a1, s0)((a1, s0))
ccons = compose(cons, cons)
dup = ef(a1)(a1, a1)
dupd = ef(a2, a1)(a2, a2, a1)
dupdd = ef(a3, a2, a1)(a3, a3, a2, a1)
first = ef((a1, s1),)(a1,)
over = ef(a2, a1)(a2, a1, a2)
pop = ef(a1)()
popd = ef(a2, a1,)(a1)
popdd = ef(a3, a2, a1,)(a2, a1,)
popop = ef(a2, a1,)()
popopd = ef(a3, a2, a1,)(a1)
popopdd = ef(a4, a3, a2, a1,)(a2, a1)
rest = ef((a1, s0),)(s0,)
rolldown = ef(a1, a2, a3)(a2, a3, a1)
rollup = ef(a1, a2, a3)(a3, a1, a2)
rrest = compose(rest, rest)
second = compose(rest, first)
stack = s0, (s0, s0)
swaack = (s1, s0), (s0, s1)
swap = ef(a1, a2)(a2, a1)
swons = compose(swap, cons)
third = compose(rest, second)
tuck = ef(a2, a1)(a1, a2, a1)
uncons = ef((a1, s0),)(a1, s0)
unswons = compose(uncons, swap)
stuncons = compose(stack, uncons)
stununcons = compose(stack, uncons, uncons)
unit = ef(a1)((a1, ()))
first_two = compose(uncons, uncons, pop)
fourth = compose(rest, third)
_Tree_add_Ee = compose(pop, swap, rolldown, rrest, ccons)
_Tree_get_E = compose(popop, second)
_Tree_delete_clear_stuff = compose(rollup, popop, rest)
_Tree_delete_R0 = compose(over, first, swap, dup)
return {
name.rstrip('_'): stack_effect
for name, stack_effect in locals().iteritems()
}
definitions = ('''\ definitions = ('''\
of == swap at of == swap at
product == 1 swap [*] step product == 1 swap [*] step
@ -289,32 +357,40 @@ def _text_to_defs(text):
return (line.strip() for line in text.splitlines() if '==' in line) return (line.strip() for line in text.splitlines() if '==' in line)
## eh = compose(dup, bool_)
## sqr = compose(dup, mul)
## of = compose(swap, at)
# #
# Functions # Functions
# #
# Load the auto-generated primitives into the dictionary. # Load the auto-generated primitives into the dictionary.
_functions.update(yin_functions())
for name, primitive in getmembers(genlib, isfunction): for name, primitive in getmembers(genlib, isfunction):
inscribe(SimpleFunctionWrapper(primitive)) inscribe(SimpleFunctionWrapper(primitive))
@inscribe @inscribe
@sec0
@FunctionWrapper @FunctionWrapper
@stack_effect(t1)()
def inscribe_(stack, expression, dictionary): def inscribe_(stack, expression, dictionary):
''' '''
Create a new Joy function definition in the Joy dictionary. A Create a new Joy function definition in the Joy dictionary. A
definition is given as a string with a name followed by a double 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: equal sign then one or more Joy functions, the body. for example:
sqr == dup mul sqr == dup mul
If you want the definition to persist over restarts, enter it into If you want the definition to persist over restarts, enter it into
the definitions.txt resource. the definitions.txt resource.
''' '''
definition, stack = stack definition, stack = stack
DefinitionWrapper.add_def(definition, dictionary) DefinitionWrapper.add_def(definition, dictionary)
return stack, expression, dictionary return stack, expression, dictionary
@inscribe @inscribe
@ -327,6 +403,7 @@ def parse(stack):
@inscribe @inscribe
@sec2
@SimpleFunctionWrapper @SimpleFunctionWrapper
def getitem(stack): def getitem(stack):
''' '''
@ -348,6 +425,7 @@ def getitem(stack):
@inscribe @inscribe
@sec1
@SimpleFunctionWrapper @SimpleFunctionWrapper
def drop(stack): def drop(stack):
''' '''
@ -375,6 +453,7 @@ def drop(stack):
@inscribe @inscribe
@sec1
@SimpleFunctionWrapper @SimpleFunctionWrapper
def take(stack): def take(stack):
''' '''
@ -512,6 +591,7 @@ def sort_(S):
return list_to_stack(sorted(iter_stack(tos))), stack return list_to_stack(sorted(iter_stack(tos))), stack
_functions['clear'] = s0, s1
@inscribe @inscribe
@SimpleFunctionWrapper @SimpleFunctionWrapper
def clear(stack): def clear(stack):
@ -1319,32 +1399,39 @@ def cmp_(stack, expression, dictionary):
for F in ( for F in (
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), #divmod_ = pm = __(n2, n1), __(n4, n3)
UnaryBuiltinWrapper(bool),
UnaryBuiltinWrapper(floor), sec_binary_cmp(BinaryBuiltinWrapper(operator.eq)),
UnaryBuiltinWrapper(operator.neg), sec_binary_cmp(BinaryBuiltinWrapper(operator.ge)),
UnaryBuiltinWrapper(operator.not_), sec_binary_cmp(BinaryBuiltinWrapper(operator.gt)),
UnaryBuiltinWrapper(sqrt), sec_binary_cmp(BinaryBuiltinWrapper(operator.le)),
sec_binary_cmp(BinaryBuiltinWrapper(operator.lt)),
sec_binary_cmp(BinaryBuiltinWrapper(operator.ne)),
sec_binary_ints(BinaryBuiltinWrapper(operator.xor)),
sec_binary_ints(BinaryBuiltinWrapper(operator.lshift)),
sec_binary_ints(BinaryBuiltinWrapper(operator.rshift)),
sec_binary_logic(BinaryBuiltinWrapper(operator.and_)),
sec_binary_logic(BinaryBuiltinWrapper(operator.or_)),
sec_binary_math(BinaryBuiltinWrapper(operator.add)),
sec_binary_math(BinaryBuiltinWrapper(operator.floordiv)),
sec_binary_math(BinaryBuiltinWrapper(operator.mod)),
sec_binary_math(BinaryBuiltinWrapper(operator.mul)),
sec_binary_math(BinaryBuiltinWrapper(operator.pow)),
sec_binary_math(BinaryBuiltinWrapper(operator.sub)),
sec_binary_math(BinaryBuiltinWrapper(operator.truediv)),
sec_unary_logic(UnaryBuiltinWrapper(bool)),
sec_unary_logic(UnaryBuiltinWrapper(operator.not_)),
sec_unary_math(UnaryBuiltinWrapper(abs)),
sec_unary_math(UnaryBuiltinWrapper(operator.neg)),
sec_unary_math(UnaryBuiltinWrapper(sqrt)),
stack_effect(n1)(i1)(UnaryBuiltinWrapper(floor)),
): ):
inscribe(F) inscribe(F)
del F # Otherwise Sphinx autodoc will pick it up. del F # Otherwise Sphinx autodoc will pick it up.

View File

@ -275,108 +275,41 @@ def compile_(name, f, doc=None):
return %s''' % (name, doc, i, o) return %s''' % (name, doc, i, o)
_functions = {}
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 def _apply_to(function):
i, o = _functions[function.name] = __(*inputs), __(*outputs)
return _stack_effect function.__doc__ += (
'\nStack effect::\n\n ' # '::' for Sphinx docs.
+ doc_from_stack_effect(i, o)
)
return function
return _apply_to
return _stack_effect
def ef(*inputs):
_R = range(10) def _ef(*outputs):
A = a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = map(AnyJoyType, _R) return __(*inputs), __(*outputs)
B = b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = map(BooleanJoyType, _R) return _ef
N = n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 = map(NumberJoyType, _R)
S = s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 = map(StackJoyType, _R)
F = f0, f1, f2, f3, f4, f5, f6, f7, f8, f9 = map(FloatJoyType, _R)
I = i0, i1, i2, i3, i4, i5, i6, i7, i8, i9 = map(IntJoyType, _R)
T = t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 = map(TextJoyType, _R)
def defs(): def show(DEFS):
'''
Return a dict of named stack effects.
'''
at = __(s0, i1), __(a1)
drop = take = __(s0, i1), __(s1)
cons = __(a1, s0), __((a1, s0),)
ccons = compose(cons, cons)
dup = __(a1,), __(a1, a1)
dupd = __(a2, a1), __(a2, a2, a1)
dupdd = __(a3, a2, a1), __(a3, a3, a2, a1)
first = __((a1, s1),), __(a1,)
inscribe = __(t1), __()
over = __(a2, a1), __(a2, a1, a2)
pop = __(a1), __()
popd = __(a2, a1,), __(a1)
popdd = __(a3, a2, a1,), __(a2, a1,)
popop = __(a2, a1,), __()
popopd = __(a3, a2, a1,), __(a1)
popopdd = __(a4, a3, a2, a1,), __(a2, a1)
rest = __((a1, s0),), __(s0,)
rolldown = __(a1, a2, a3), __(a2, a3, a1)
rollup = __(a1, a2, a3), __(a3, a1, a2)
rrest = compose(rest, rest)
second = compose(rest, first)
stack = s0, (s0, s0)
swaack = (s1, s0), (s0, s1)
swap = __(a1, a2), __(a2, a1)
swons = compose(swap, cons)
third = compose(rest, second)
tuck = __(a2, a1), __(a1, a2, a1)
uncons = __((a1, s0),), __(a1, s0)
unswons = compose(uncons, swap)
stuncons = compose(stack, uncons)
stununcons = compose(stack, uncons, uncons)
unit = __(a1), __((a1, ()))
of = compose(swap, at)
clear = s0, s1
eq = ge = gt = le = lt = ne = __(n1, n2), __(b1)
and_ = __(b1, b2), __(b3)
bool_ = not_ = __(a1), __(b1)
eh = compose(dup, bool_)
add = div = floordiv = mod = mul = pow_ = sub = truediv = \
lshift = rshift = __(n1, n2), __(n3,)
sqr = compose(dup, mul)
abs_ = floor = sqrt = succ = pred = neg = __(n1,), __(n2,)
divmod_ = pm = __(n2, n1), __(n4, n3)
first_two = compose(uncons, uncons, pop)
fourth = compose(rest, third)
of = compose(swap, at)
_Tree_add_Ee = compose(pop, swap, rolldown, rrest, ccons)
_Tree_get_E = compose(popop, second)
_Tree_delete_clear_stuff = compose(rollup, popop, rest)
_Tree_delete_R0 = compose(over, first, swap, dup)
return {
name.rstrip('_'): stack_effect
for name, stack_effect in locals().iteritems()
}
DEFS = defs()
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(DEFS, f=None):
if f is None: if f is None:
import sys import sys
f = sys.stdout f = sys.stdout
@ -389,5 +322,5 @@ def generate_library_code(f=None):
print >> f print >> f
if __name__ == '__main__': ##if __name__ == '__main__':
show() ## show()