- TODO: create an Interpreter object to hold state.
- - TODO: sorted order of Chart seems to have changed. Check that this changed order
- makes sense
-
- timv: look at the diff--what were we doing before?
-
- TODO: deleting a rule: (1) remove update handlers (2) run initializers in
delete mode (3) remove initializers.
- TODO: Term's should only be aggregated with ``=`` or ``:=``. We should
disallow ``a += &b.``
- equals (=) aggregation (only one value allowed, multiplicity >0 on only one value)
+ Equals aggregation only one value allowed, mult. >0 on single value. The
+ following program has one FP of `c` end `e` are mutually exclusive.
- a = b for c
- a = d for e
+ a = b for c
+ a = d for e
- c and e might be mutually exclusive in all FP, but not during computation
- -- this is the same as the error problem (e.g. division problem)
+ This might not be the case during computation -- this is the same as the
+ error problem.
- TODO: doc tests for Dyna code!
- TODO: repl needs to pass parser a rule index pragma to start from.
+ blocked: nwf will tell me what bits of parser state to send back to him.
+
- TODO: build hypergraph from unrolled circuit. This requires a little bit of
thinking because we don't yet know what things in the chart have been
touched.
-
-Use ruleix to make := work at the REPL
-
-:- ruleix 100
-
+ - TODO: transactions for errors.
-NOTES
-=====
- - "initializers" aren't just initializers, they are the fully-naive bottom-up
- inference rules.
-
PARSER
======
- - TODO: Singled quoted strings:
-
- x += f('result = 5').
-
-
- TODO: Nested expressions:
out(0) dict= _VALUE is (rewrite(X,Y) + rewrite(X,Y,Z)), _VALUE.
timv: This isn't sufficiently motivating because we can just leave `a` as
`null` until we pass the divide by zero error.
+
+
+
"""
from __future__ import division
import os, sys
from collections import defaultdict, namedtuple
+from functools import partial
from argparse import ArgumentParser
from utils import ip, red, green, blue, magenta, yellow, dynahome, \
def insert(self, args, val):
# debugging check: row is not already in chart.
- assert self.lookup(args) is None, '%r already in chart with value %r' % (args, val)
+ assert self.lookup(args) is None, \
+ '%r already in chart with value %r' % (args, val)
self.intern[args] = term = Term(self.name, args)
term.value = val
register.handlers = defaultdict(list)
+# - "initializers" aren't just initializers -- They are fully-naive bottom-up
+# inference routines. At the moment we only use them to initialize the chart.
+
def initializer(_):
- "Same idea as register"
+ "Implementation idea is very similar to register."
def wrap(handler):
initializer.handlers.append(handler)
if val is None:
return
for handler in register.handlers[item.fn]:
+
+ emittiers = []
+ _emit = lambda item, val, ruleix, variables: \
+ emittiers.append(lambda: emit(item, val, ruleix, variables, delete=delete))
+
try:
- handler(item, val, delete=delete)
+ handler(item, val, emit=_emit)
except (TypeError, ZeroDivisionError) as e:
if error_suppression:
#print >> trace,
print '%s on update %s = %s' % (e, item, val)
else:
raise e
+ else:
+ # no exception, accept emissions.
+ for e in emittiers:
+ e()
def peel(fn, item):
print >> trace, (red % 'delete' if delete else green % 'update'), \
'%s (val %s; curr: %s)' % (item, val, item.value)
- assert not isinstance(val, tuple) or isinstance(val, Term)
-
if delete:
item.aggregator.dec(val, ruleix, variables)
else:
item.aggregator.inc(val, ruleix, variables)
- agenda[item] = 0
+ agenda[item] = 0 # everything is high priority
changed = {}
print >> trace, '(was: %s,' % (was,),
now = item.aggregator.fold()
- print >> trace, 'now:', str(now) + ')'
+ print >> trace, 'now: %s)' % (now,)
if was == now:
print >> trace, yellow % 'unchanged'
continue
+ # TODO: handle was and now at the same time to avoid the two passes.
if was is not None:
update_dispatcher(item, was, delete=True)
print >> trace, yellow % h.read()
# load generated code.
- execfile(f, globals())
+ execfile(f, globals()) # if we want to isolate side-effects of new code
+ # we can pass in something insead of globals()
def dump(code, filename='/tmp/tmp.dyna'):
load(filename)
for init in initializer.handlers: # assumes we have cleared
+
+ _emit = partial(emit, delete=False)
+
try:
- init(delete=False)
+ init(emit=_emit)
except (TypeError, ZeroDivisionError) as e:
if error_suppression:
#print >> trace,
-import cmd
-import readline
+import cmd, readline
class REPL(cmd.Cmd, object):
def __init__(self, hist):
cmd.Cmd.__init__(self)
- #self.prompt = ":- "
self.hist = hist
if not os.path.exists(hist):
+ readline.clear_history()
with file(hist, 'wb') as f:
f.write('')
readline.read_history_file(hist)
def do_changed(self, _):
if not changed:
- #print 'nothing changed.'
- #print
return
print '============='
for x, v in sorted(changed.items()):
print '%s := %r' % (x, v)
print
- def do_dump(self, _):
- print '============='
- for fn in sorted(chart):
- c = chart[fn]
- for i, r in sorted(c.data.items(), key=lambda x: x[1]): # sort by Term's arguments
- val = r[-1]
- if val is not None:
- print '%-30s := %r' % (Term(fn, i), val)
- print
-
def do_chart(self, args):
if not args:
dump_charts()
print "Queries don't end with a dot."
return
- query = 'out(%s) dict= _VALUE is %s, _VALUE.' % (self.lineno, line)
+ query = 'out(%s) dict= _VALUE is (%s), _VALUE.' % (self.lineno, line)
print blue % query
except KeyboardInterrupt:
print '^C'
self.cmdloop()
+ except Exception as e:
+ readline.write_history_file(self.hist)
+ raise e
def repl(hist):