]> hydra-www.ietfng.org Git - dyna2/commitdiff
several tweaks.
authorTim Vieira <tim.f.vieira@gmail.com>
Wed, 14 Aug 2013 19:49:59 +0000 (15:49 -0400)
committerTim Vieira <tim.f.vieira@gmail.com>
Wed, 14 Aug 2013 19:49:59 +0000 (15:49 -0400)
dyna-doctest [deleted file]
run-doctests.py
src/Dyna/Backend/Python/chart.py
src/Dyna/Backend/Python/interpreter.py
src/Dyna/Backend/Python/term.py

diff --git a/dyna-doctest b/dyna-doctest
deleted file mode 100755 (executable)
index c28b23d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env bash
-
-exec python ${DYNAHOME:-.}/src/Dyna/Backend/Python/dyna_doctest.py "$@"
index ee8d18d11f354b7aa8719002e44d1c68f4bbcabe..57d6d3b0345697d6c14c18350da3e40082345a62 100755 (executable)
@@ -2,6 +2,7 @@
 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'
@@ -14,70 +15,87 @@ if not path(src).exists():
 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()
index 16047471a9bbfbe301daf4127a7288e5edfdfe77..7cc610a147c34b62288e91e3636948f253e9e1bb 100644 (file)
@@ -17,6 +17,12 @@ class Chart(object):
         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.
index 944fcfbe60f56630842305dfc34ab47d20a48198..31abf1f10bfa3c1a42d3fbcf7f6a84ffd8f2fac3 100644 (file)
@@ -51,19 +51,11 @@ class Rule(object):
         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])
@@ -89,7 +81,7 @@ class Interpreter(object):
         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
@@ -106,16 +98,9 @@ class Interpreter(object):
     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
@@ -127,10 +112,6 @@ class Interpreter(object):
             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):
@@ -569,7 +550,8 @@ class Interpreter(object):
 
         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():
index f2b238758ac85f66d2282039a6c2afbe4a296812..126a1b9c9e7f71aa65d84cccf4f662cd906ec35b 100644 (file)
@@ -16,14 +16,19 @@ class Term(object):
 #        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):
@@ -34,13 +39,13 @@ class Term(object):
         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))