From 997f9af4fa07e9679d4bea962a21673be79c6701 Mon Sep 17 00:00:00 2001 From: Tim Vieira Date: Tue, 2 Jul 2013 00:14:51 -0400 Subject: [PATCH] tweaks to trace to print lists nicely, and infix 'in' Simplify error message pertaining to retracting a rule and when a query or trace fails. --- src/Dyna/Backend/Python/post/trace.py | 29 +++++++++++++++++++++++---- src/Dyna/Backend/Python/repl.py | 13 +++++++++--- src/Dyna/Backend/Python/stdlib.py | 9 +++++++-- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/Dyna/Backend/Python/post/trace.py b/src/Dyna/Backend/Python/post/trace.py index dbdb5bc..a01d601 100644 --- a/src/Dyna/Backend/Python/post/trace.py +++ b/src/Dyna/Backend/Python/post/trace.py @@ -56,12 +56,14 @@ def dig(head, visited, tail, groups, interp): if head in tail: return ['%s = %s' % (yellow % head, head.value)] \ + ['|'] \ - + branch([[red % 'continue as before (cyclic structure, will continue forever)']]) + + branch([[red % 'continue as before (cyclic structure, will continue forever)']]) \ + + [''] if head in visited: return ['%s = %s' % (yellow % head, head.value)] \ + ['|'] \ - + branch([[red % 'continue as before (shared structure)']]) + + branch([[red % 'continue as before (shared structure)']]) \ + + [''] if head not in groups: return [] @@ -83,7 +85,8 @@ def dig(head, visited, tail, groups, interp): return ['%s = %s' % (yellow % head, cyan % _repr(head.value))] \ + ['|'] \ - + branch(contribs) + [''] + + branch(contribs) #\ +# + [''] def branch(xs): @@ -171,12 +174,16 @@ class Crux(object): return label fn_args = [self.get_function(y) for y in x.body] - if not label.isalpha() and not label.startswith('&') and len(fn_args) == 2: # infix + + # infix + if (not label.isalpha() and not label.startswith('&') and len(fn_args) == 2) \ + or label in ('in', 'and', 'or'): [a,b] = fn_args return '(%s %s %s)' % (a, label, b) return '%s(%s)' % (label, ', '.join(fn_args)) else: + if not g.incoming[x]: # input if re.match('u[A-Z].*', x): # user variable return x[1:] + (cyan % '=%s' % self.values(x)) @@ -184,11 +191,25 @@ class Crux(object): if len(g.incoming[x]) > 1: return ' = '.join('(%s%s)' % (self.get_function(e), (cyan % '=%s' % self.values(e.head))) for e in g.incoming[x]) + [e] = g.incoming[x] if e.label == '=': return self.get_function(e) + # handle lists + if e.label == '& cons': + _e = e + a = [] + while e.label == '& cons': + x, xs = e.body + [e] = g.incoming[xs] + a.append(self.get_function(x)) + if e.label == '& nil': + return '[%s]' % ', '.join(a) + else: + return self.get_function(_e) # malformed list. + if e.label.startswith('&'): return self.get_function(e) diff --git a/src/Dyna/Backend/Python/repl.py b/src/Dyna/Backend/Python/repl.py index d88525f..e0dfc04 100644 --- a/src/Dyna/Backend/Python/repl.py +++ b/src/Dyna/Backend/Python/repl.py @@ -171,18 +171,22 @@ class REPL(cmd.Cmd, object): try: query = "$query dict= %s." % q + self.default(query, show_changed=False) + try: [(_, _, results)] = self.interp.chart['$query/0'][:,] return results except ValueError: return [] + finally: # cleanup: # retract newly added rules. for r in self.interp.new_rules: - self.interp.retract_rule(r) + if r in self.interp.rules: + self.interp.retract_rule(r) try: # drop $out chart @@ -203,7 +207,7 @@ class REPL(cmd.Cmd, object): if len(results) == 0: print 'No results.' return - for val, bindings in results: + for val, bindings in sorted(results): print _repr(val), 'where', drepr(dict(bindings)) print @@ -541,7 +545,9 @@ class REPL(cmd.Cmd, object): try: query = "$trace dict= _ is %s, &(%s)." % (q,q) + self.default(query, show_changed=False) + try: [(_, _, results)] = self.interp.chart['$trace/0'][:,] except ValueError: @@ -558,7 +564,8 @@ class REPL(cmd.Cmd, object): # cleanup: # retract newly added rules. for r in self.interp.new_rules: - self.interp.retract_rule(r) + if r in self.interp.rules: + self.interp.retract_rule(r) try: # drop $out chart diff --git a/src/Dyna/Backend/Python/stdlib.py b/src/Dyna/Backend/Python/stdlib.py index 7b1d8da..006c4bf 100644 --- a/src/Dyna/Backend/Python/stdlib.py +++ b/src/Dyna/Backend/Python/stdlib.py @@ -13,6 +13,11 @@ except ImportError: # XXX: should probably issue a warning def split(s, delim='\s+'): return todynalist(re.split(delim, s)) +def crash(): + class Crasher(Exception): + pass + raise Crasher('Hey, you asked for it!') + def pycall(name, *args): """ Temporary foreign function interface - call Python functions from dyna! @@ -22,12 +27,12 @@ def pycall(name, *args): return todyna(x) def todyna(x): - if isinstance(x, (list, tuple)): + if isinstance(x, (set, list, tuple)): return todynalist(x) return x def topython(x): - if isinstance(x, (Cons, Nil)): + if isinstance(x, Cons) or x is Nil: return x.aslist return x -- 2.50.1