From: Tim Vieira Date: Thu, 1 Aug 2013 17:09:18 +0000 (-0400) Subject: Many small tweaks. X-Git-Url: https://hydra-www.ietfng.org/gitweb/?a=commitdiff_plain;h=568afa096244da3f0aa6346c5e934de112b9b74d;p=dyna2 Many small tweaks. - fixed argument disposition of tupling operators: `->` and `:`. - Compare rules by their index (i.e. equality, hash,q and sort order). - Recompilation works like rule initialization --- diff --git a/src/Dyna/Backend/Python/dyna_doctest.py b/src/Dyna/Backend/Python/dyna_doctest.py index b7a44e7..a32ebc7 100644 --- a/src/Dyna/Backend/Python/dyna_doctest.py +++ b/src/Dyna/Backend/Python/dyna_doctest.py @@ -9,8 +9,10 @@ from utils import bold, red, green, yellow, strip_comments def diff(expect, got): with file('/tmp/expect','wb') as A: A.write(expect) + A.write('\n') with file('/tmp/got','wb') as B: B.write(got) + B.write('\n') from subprocess import Popen, PIPE p = Popen(['colordiff', A.name, B.name], stdout=PIPE, stderr=PIPE) return p.communicate()[0] @@ -18,11 +20,7 @@ def diff(expect, got): def extract(code): for block in re.compile('^> ', re.MULTILINE).split(code): - cmd = [] - expect = [] - - reading = True - + cmd, expect, reading = [], [], True for i, line in enumerate(block.split('\n')): if (line.startswith('|') or i == 0) and reading: if line.startswith('|'): @@ -31,7 +29,6 @@ def extract(code): else: reading = False expect.append(line) - yield '\n'.join(cmd).strip(), '\n'.join(expect).strip() diff --git a/src/Dyna/Backend/Python/interpreter.py b/src/Dyna/Backend/Python/interpreter.py index fad8b7d..cfc5cce 100644 --- a/src/Dyna/Backend/Python/interpreter.py +++ b/src/Dyna/Backend/Python/interpreter.py @@ -8,7 +8,7 @@ from path import path from term import Term, Cons, Nil, MapsTo, Error from chart import Chart from utils import red, parse_attrs, ddict, dynac, read_anf, strip_comments, \ - _repr, hide_ugly_filename, true, false, parse_parser_state + _repr, hide_ugly_filename, true, false, parse_parser_state, magenta, indent from prioritydict import prioritydict from config import dotdynadir @@ -32,6 +32,18 @@ class Rule(object): self.anf = None self.head_fn = None + def __eq__(self, other): + return self.index == other.index + + def hash(self): + return self.index + + def __cmp__(self, other): + try: + return cmp(self.index, other.index) + except AttributeError: + return 1 + def __repr__(self): return 'Rule(%s, %r)' % (self.index, self.src) @@ -93,7 +105,7 @@ class Interpreter(object): for fn in bc: if fn not in self._gbc: # new backchain declaration for r in self.rule_by_head[fn]: - self.recompile.add(r) + self.needs_recompile(r) def __init__(self): # declarations @@ -180,7 +192,7 @@ class Interpreter(object): while agenda: item = self.agenda.pop_smallest() self.pop(item) - # after draining the agenda, try to initialize pending rules. + self.run_recompile() self.run_uninitialized() if self.agenda: self._agenda() @@ -272,14 +284,9 @@ class Interpreter(object): self.emit(*e) def gbc(self, fn, args): - item = self.build(fn, *args) - - # TODO: we will need to distinguish `unknown` from `null` when we move - # to mixed chaining. if item.value is not None: return item.value - return self.force_gbc(item) def force_gbc(self, item): @@ -315,7 +322,7 @@ class Interpreter(object): return self.pop(item) - def load_plan(self, filename, recurse=True): + def load_plan(self, filename): """ Compile, load, and execute new dyna rules. @@ -358,11 +365,6 @@ class Interpreter(object): for fn, r, h in env.updaters: self.new_updater(fn, r, h) - if recurse: - self.run_recompile() - - # we we don't accumulate all changed rules, new_rules return will be new - # rules of top-level call. return new_rules def recompile_rule(self, r): @@ -378,34 +380,29 @@ class Interpreter(object): f.write(code) return self.dynac(dyna) + def needs_recompile(self, r): + self.retract_rule(r.index) # clears errors + self.recompile.add(r) + def run_recompile(self): - # TODO: it's a bit strange to ignore the error and just print - # it. However, since the rules in the recompile list are - # syntactically valid (well, they at least they were valid) -- this - # means that errors must be planning errors... probably all to do - # with missing BC declarations. - # - # TODO: we probably have to worry about infinite loops -- at the - # moment this results in an interpreter crash due to max recursion - # limit - # - # TODO: maybe we should handle recompilation more like we do - # uninitialized rules. # run to fixed point. while self.recompile: + success = set() failed = set() for r in list(self.recompile): try: - plan = self.recompile_rule(r) + r.plan = self.recompile_rule(r) except DynaCompilerError as e: failed.add(r) self.set_error(r, e) else: - self.retract_rule(r.index) - self.load_plan(plan, recurse=False) - if failed == self.recompile: # no progress - break + success.add(r) + self.clear_error(r) self.recompile = failed + if not success: + break + for r in success: + self.load_plan(r.plan) def run_uninitialized(self): q = set(self.uninitialized_rules) @@ -487,7 +484,7 @@ class Interpreter(object): # now backchained. for d in self.rule_dep[head_fn]: if rule != d and d.head_fn not in self._gbc: - self.recompile.add(d) + self.needs_recompile(d) self._gbc[head_fn].append(query) @@ -597,8 +594,8 @@ class Interpreter(object): visited = set() if fn not in self._gbc or fn in visited: - # don't refresh non-BC computation be careful not to get stuck in an - # infinite loop if there is a cycle in the dep graph + # don't refresh non-BC computation. Also, be careful not to get + # stuck in an infinite loop if there is a cycle in the dep graph return visited.add(fn) @@ -740,6 +737,9 @@ class Interpreter(object): else: print >> out, ' %s' % (e) + #print >> out + #print >> out, magenta % indent(e.traceback.rstrip(), indent=' ') + print >> out print >> out, r.render_ctx(e.exception_frame, indent=' ') print >> out diff --git a/src/Dyna/Backend/Python/post/trace.py b/src/Dyna/Backend/Python/post/trace.py index 046135c..9444553 100644 --- a/src/Dyna/Backend/Python/post/trace.py +++ b/src/Dyna/Backend/Python/post/trace.py @@ -196,7 +196,11 @@ class Crux(object): # infix if (not label[0].isalpha() and label[0] not in ('$','&') and len(fn_args) == 2) \ - or label in ('in', 'and', 'or', 'with_key', '->', 'is'): + or label in ('in', 'with_key', '&with_key', '->', '&->', 'is'): + + if label in {'&with_key', '->', '&->'}: + label = label[1:] + [a,b] = fn_args return '(%s %s %s)' % (a, label, b) return '%s(%s)' % (label, ', '.join(fn_args)) @@ -225,24 +229,12 @@ class Crux(object): _e = e a = [] while e.label == '& cons': - - # TODO: crashlogs/abarany:2013-07-24:11:47:31:17823.log - x, xs = e.body # e = _a3 = & cons(uV, uX) - - # g.incoming = { - # '_a5': [_a5 = edge@1(uX, uU, uV)], - # '_a4': [_a4 = pathto@0(uU)], - # '_a3': [_a3 = & cons(uV, uX)], - # '_a2': [_a2 = +@2(_a4, _a5)], - # 'uU': [], - # '_t1': [_t1 = & with_key(_a2, _a3)], - # 'uV': [], - # '_t0': [_t0 = & pathto(uV)], 'uX': [] - # } - # xs = 'uX' - - [e] = g.incoming[xs] + x, xs = e.body a.append(self._get_function(x)) + if not g.incoming[xs]: + a.append(self._get_function(xs)) + break + [e] = g.incoming[xs] if e.label == '& nil': return '[%s]' % ', '.join(a) diff --git a/src/Dyna/Backend/Python/repl.py b/src/Dyna/Backend/Python/repl.py index 3ee0e63..7c30108 100644 --- a/src/Dyna/Backend/Python/repl.py +++ b/src/Dyna/Backend/Python/repl.py @@ -11,9 +11,8 @@ import re, os, cmd, readline from utils import ip, lexer, subst, drepr, _repr, get_module, yellow, \ green, bold from stdlib import topython, todyna -from errors import DynaCompilerError +from errors import DynaCompilerError, show_traceback from config import dotdynadir -from errors import show_traceback import load, post from interpreter import Rule @@ -277,6 +276,7 @@ class REPL(cmd.Cmd, object): errors_before = self.interp.error.copy() yield if errors_before.items() != self.interp.error.items(): + e = set(errors_before) | set(self.interp.error) new_errors = 0 cleared_errors = 0 @@ -295,7 +295,7 @@ class REPL(cmd.Cmd, object): #print 'cleared error at `%s`.' % k cleared_errors += 1 elif not was and now: -# print 'new error at `%s`.' % k, es + #print 'new error at `%s`.' % k, es new_errors += 1 if new_errors and cleared_errors: print yellow % '>>>', '%s new errors, %s errors cleared. Type `sol` for details.\n' \ diff --git a/src/Dyna/Backend/Python/stdlib.py b/src/Dyna/Backend/Python/stdlib.py index 69d6ab9..94f3916 100644 --- a/src/Dyna/Backend/Python/stdlib.py +++ b/src/Dyna/Backend/Python/stdlib.py @@ -20,6 +20,10 @@ from glob import glob # return todyna([x+a for a in self.aslist]) +def lookup(k, alist): + a = dict(alist) + return a.get(k) + def or_(x, y): if not (isbool(x) and isbool(y)): raise TypeError('`|` expected Boolean arguments, got `%s` and `%s`' \ diff --git a/src/Dyna/Backend/Python/term.py b/src/Dyna/Backend/Python/term.py index c158cff..b89ca7e 100644 --- a/src/Dyna/Backend/Python/term.py +++ b/src/Dyna/Backend/Python/term.py @@ -98,4 +98,4 @@ class MapsTo(NoIntern, Term): def __init__(self, k, v): super(MapsTo, self).__init__('->/2', (k, v)) def __repr__(self): - return '%s -> %s' % self.args + return '%s -> %s' % tuple(map(_repr, self.args)) diff --git a/src/Dyna/Backend/Python/utils.py b/src/Dyna/Backend/Python/utils.py index 1a29933..1559f56 100644 --- a/src/Dyna/Backend/Python/utils.py +++ b/src/Dyna/Backend/Python/utils.py @@ -28,6 +28,12 @@ def parse_parser_state(parser_state): return backchain, ruleix, iaggr, other +def indent(x, indent=''): + if isinstance(x, basestring): + return re.compile('^(.*)$', flags=re.MULTILINE).sub(indent + r'\1', x) + else: + return [indent + y for y in x] + class _true(object): def __nonzero__(self): diff --git a/src/Dyna/Term/SurfaceSyntax.hs b/src/Dyna/Term/SurfaceSyntax.hs index db11ffe..f1f6f1c 100644 --- a/src/Dyna/Term/SurfaceSyntax.hs +++ b/src/Dyna/Term/SurfaceSyntax.hs @@ -178,12 +178,12 @@ disposTab_prologish t = DisposTab s a , (("false",0),(SDQuote,[])) -- key , (("$key" ,1),(SDEval,[ADQuote])) - , (("with_key",2),(SDQuote,[ADEval, ADEval])) + , (("with_key",2),(SDQuote,[ADEval,ADEval])) -- lists , (("nil", 0),(SDQuote,[])) , (("cons", 2),(SDQuote,[ADEval,ADEval])) - , (("->",2),(SDQuote,[ADQuote, ADQuote])) - , ((":",2),(SDQuote,[ADQuote, ADQuote])) + , (("->", 2),(SDQuote,[ADEval,ADEval])) + , ((":", 2),(SDQuote,[ADEval,ADEval])) ] -- | Make the default surface syntax more functional. Here, all functors @@ -214,9 +214,9 @@ disposTab_dyna t = DisposTab s a -- key , (("$key" ,1),(SDEval,[ADQuote])) , (("with_key",2),(SDQuote,[ADEval, ADEval])) - , (("->",2),(SDQuote,[ADQuote, ADQuote])) - , ((":",2),(SDQuote,[ADQuote, ADQuote])) - + -- tuples + , (("->", 2),(SDQuote,[ADEval,ADEval])) + , ((":", 2),(SDQuote,[ADEval,ADEval])) ] ------------------------------------------------------------------------}}} diff --git a/test/repl/late-bc.dynadoc b/test/repl/late-bc.dynadoc index 620cb75..7423159 100644 --- a/test/repl/late-bc.dynadoc +++ b/test/repl/late-bc.dynadoc @@ -70,3 +70,14 @@ Failed to recompile rule: > query foo(3) foo(3) = 12. + +> sol + +Solution +======== +a/1 +=== +a(1) = 1. +a(2) = 2. +a(3) = 3. +a(4) = 4.