+++ /dev/null
-#!/usr/bin/env bash
-
-exec python ${DYNAHOME:-.}/src/Dyna/Backend/Python/dyna_doctest.py "$@"
from path import path
from cStringIO import StringIO
from subprocess import Popen, PIPE
+from argparse import ArgumentParser
import re, sys
src = 'src/Dyna/Backend/Python'
from utils import red, green
from dyna_doctest import run
-failures = []
-print 'End-to-end'
-print '=========='
+def end_to_end(tests):
+ print 'End-to-end'
+ print '=========='
+ for x, z in tests:
+ print x,
+ sys.stdout.flush()
-for z in sorted(path('examples/expected').glob("*.py.out")):
+ y = x + '.py.out'
- x = re.sub('(examples/)expected/(.*).py.out', r'\1\2.dyna', z)
- y = x + '.py.out'
+ # run ./dyna
+ p = Popen(['./dyna', x, '-o', y], stdout=PIPE, stderr=PIPE)
+ (out, err) = p.communicate()
- print x,
- sys.stdout.flush()
+ assert not p.returncode, out + '\n' + err
- # run ./dyna
- p = Popen(['./dyna', x, '-o', y], stdout=PIPE, stderr=PIPE)
- (out, err) = p.communicate()
+ # look at diff
+ p = Popen(['diff', y, z], stdout=PIPE, stderr=PIPE)
+ (out, err) = p.communicate()
- assert not p.returncode, out + '\n' + err
+ if not p.returncode:
+ print green % 'pass'
+ else:
+ print red % 'fail'
+ yield [x, out + '\n' + err]
- # look at diff
- p = Popen(['diff', y, z], stdout=PIPE, stderr=PIPE)
- (out, err) = p.communicate()
- if not p.returncode:
- print green % 'pass'
- else:
- print red % 'fail'
- failures.append([x, out + '\n' + err])
+def run_doctests(files):
+ print
+ print 'Doctests'
+ print '========'
+ for x in files:
+ print x,
+ sys.stdout.flush()
+ with file(x) as f:
+ g = StringIO()
+ if run(f.read(), g):
+ yield [x, g.getvalue()]
+ print red % 'fail'
+ else:
+ print green % 'pass'
-print
-print 'Doctests'
-print '========'
-for x in sorted(path('test').glob("*/*.dynadoc")):
+def main():
- if '/ptb.dynadoc' in x:
- continue
+ parser = ArgumentParser()
+ parser.add_argument('files', nargs='*', type=path)
- if '/known-failures/' in x:
- continue
+ args = parser.parse_args()
- print x,
- sys.stdout.flush()
- with file(x) as f:
- g = StringIO()
- if run(f.read(), g):
- failures.append([x, g.getvalue()])
- print red % 'fail'
- else:
- print green % 'pass'
+ failures = []
+ # default set of doctests
+ if not args.files:
+ tests = [(re.sub('(examples/)expected/(.*).py.out', r'\1\2.dyna', z), z) \
+ for z in sorted(path('examples/expected').glob("*.py.out"))]
+ failures.extend(end_to_end(tests))
-for f, log in failures:
- print
- print '================================================'
- print f
- print '================================================'
- print log
+ args.files = [x for x in sorted(path('test').glob("*/*.dynadoc")) \
+ if '/ptb.dynadoc' not in x \
+ and '/known-failures/' not in x]
+ failures.extend(run_doctests(args.files))
-if failures:
- print '================================================'
- print 'FAILURES (%s)' % len(failures)
- print '================================================'
- for f, _ in failures:
+ # detailed failure reports
+ for f, log in failures:
+ print
+ print '================================================'
print f
- exit(1)
+ print '================================================'
+ print log
+
+ # failure summary
+ if failures:
+ print '================================================'
+ print 'FAILURES (%s)' % len(failures)
+ print '================================================'
+ for f, _ in failures:
+ print f
+ exit(1)
+
+
+if __name__ == '__main__':
+ main()
return aggregator(self.agg_name, term)
def set_aggregator(self, agg):
+ """
+ if we have a new aggregator and an existing chart, we need to shove a
+ bunch of aggregators into the interned nodes. This happens when a new
+ rule (e.g. from the repl) gives something a value, which didn't have a
+ value before.
+ """
self.agg_name = agg
for item in self.intern.values():
assert item.value is None, [item, item.value, item.aggregator] # shouldn't change aggregator when non-null.
c = Crux(head=None, rule=self, body=None, vs = ctx)
return '\n'.join(indent + line for line in c.format())
-# def debug(self):
-# import debug
-# with file(dotdynadir / 'tmp.dyna', 'wb') as f:
-# f.write(self.src)
-# debug.main(f.name)
-
-# TODO: yuck, hopefully temporary measure to support pickling the Interpreter's
-# state
-class foo(dict):
+class Charts(dict):
def __init__(self, agg_name):
self.agg_name = agg_name
- super(foo, self).__init__()
+ super(Charts, self).__init__()
def __missing__(self, fn):
arity = int(fn.split('/')[-1])
self[fn] = c = Chart(fn, arity, self.agg_name[fn])
self._gbc = defaultdict(list)
# data structures
self.agenda = prioritydict()
- self.chart = foo(self.agg_name)
+ self.chart = Charts(self.agg_name)
self.error = {}
self.changed = {}
# misc
def new_fn(self, fn, agg):
if self.agg_name[fn] is None:
self.agg_name[fn] = agg
- # if we have a new aggregator and an existing chart we need to shove
- # a bunch of aggregators into the interned nodes.
- #
- # This happens when a new rule (e.g. from the repl) gives something
- # a value, which didn't have a value before -- i.e. was only used as
- # structure.
- if fn in self.chart:
- self.chart[fn].set_aggregator(agg)
+ self.chart[fn].set_aggregator(agg)
# check for aggregator conflict.
- assert self.agg_name[fn] == agg, (fn, self.agg_name[fn], agg)
+ assert self.agg_name[fn] == agg
def build(self, fn, *args):
# handle a few special cases where the item doesn't have a chart
return MapsTo(*args)
if fn == '$key/1':
self.new_fn(fn, '=')
- # if we haven't seen this functor before, it probably doesn't have a
- # Chart, so lets go ahead and create one.
- if fn not in self.agg_name:
- self.new_fn(fn, None)
return self.chart[fn].insert(args)
def delete(self, item, val, ruleix, variables):
visited.add(fn)
- # YUCK: find some was to avoid this...
+ # YUCK: find some was to avoid this... alternatively, we can run
+ # deletes first.
self.was = {x: x.value for x in self.chart[fn].intern.values()}
for x in self.chart[fn].intern.values():
# return self is other
def __cmp__(self, other):
- if self is other:
- return 0
try:
- if self.fn == other.fn:
- return cmp(self.args, other.args)
- else:
- return cmp(self.fn, other.fn)
- except AttributeError:
+ if self is other:
+ return 0
+ try:
+ if self.fn == other.fn:
+ return cmp(self.args, other.args)
+ else:
+ return cmp(self.fn, other.fn)
+ except AttributeError:
+ return 1
+ except RuntimeError:
+ # HACK: sometimes we have a cyclic (or very deep) term and hit a
+ # recursion limit.
return 1
def __repr__(self):
return '%s(%s)' % (fn, ','.join(map(_repr, self.args)))
+# TODO: maybe the right way to do this is with a weak value dictionary
class NoIntern(Term):
"Mix-in which adds hash and equality method for terms which aren't interned."
+
def __eq__(self, other):
- try:
- return (self.fn, self.args) == (other.fn, other.args)
- except AttributeError:
- return False
+ return Term.__cmp__(self, other) == 0
+
def __hash__(self):
return hash((self.fn, self.args))