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
+ _repr, hide_ugly_filename, true, false, parse_parser_state
from prioritydict import prioritydict
from config import dotdynadir
class Interpreter(object):
+ @property
+ def parser_state(self):
+ # TODO: this is pretty hacky. XREF:parser-state
+ bc, rix, agg, other = self.pstate
+ lines = [':-ruleix %d.' % rix]
+ for fn in bc:
+ [(fn, arity)] = re.findall('(.*)/(\d+)', fn)
+ lines.append(":-backchain '%s'/%s." % (fn, arity))
+ for fn, agg in agg.items():
+ [(fn, arity)] = re.findall('(.*)/(\d+)', fn)
+ lines.append(":-iaggr '%s'/%s %s." % (fn, arity, agg))
+ lines.extend(':-%s %s.' % (k,v) for k,v in other)
+ return '\n'.join(lines)
+
def __init__(self):
# declarations
self.agg_name = defaultdict(none)
- self.parser_state = ''
+ self.pstate = (set(), 0, {}, [])
self.files = []
# rules
self.rules = {}
return Error()
else:
- # no exceptions, accept emissions.
for e in emits:
# an error could happen here, but we assume (by contract) that this
# is not possible.
for x in read_anf(contents):
anf[x.ruleix] = x
- # accept the new parser state
- self.parser_state = env.parser_state
+ # update parser state
+ self.pstate = parse_parser_state(env.parser_state)
+
for k, v in env.agg_decl.items():
self.new_fn(k, v)
try:
plan = self.dynac_code('\n'.join(r.src for r in sorted(self.recompile, key=lambda r: r.index)))
except DynaCompilerError as e:
- # TODO: it's a bit strange to ignore the error and simply print
- # the error. However, since the rules in the recompile list are
+ # 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.
self.recompute_coarse()
+ # if now there are no more rules defining a functor
+ if not self.rule_by_head[rule.head_fn]:
+ del self.chart[rule.head_fn] # delete the chart.
+ del self.agg_name[rule.head_fn]
+ del self.pstate[2][rule.head_fn] # remove fn aggr def from parser state
+
self._agenda()
return self.changed
from cStringIO import StringIO
+# TODO: This is pretty hacking we should have the codegen produce something
+# easier to serialize/modify/unserialize. XREF:parser-state
+def parse_parser_state(parser_state):
+ backchain = set()
+ ruleix = None
+ iaggr = {}
+ other = []
+ for k, v in re.findall('^:-\s*(\S+) (.*?)\s*\.$', parser_state, re.MULTILINE):
+ if k == 'backchain':
+ [(fn, arity)] = re.findall("'(.*?)'/(\d+)", v)
+ backchain.add('%s/%s' % (fn, arity))
+ elif k == 'iaggr':
+ [(fn, arity, agg)] = re.findall("'(.*?)'/(\d+)\s*(.*)", v)
+ iaggr['%s/%s' % (fn, arity)] = agg
+ elif k == 'ruleix':
+ ruleix = int(v)
+ else:
+ other.append((k,v))
+ return backchain, ruleix, iaggr, other
+
+
class _true(object):
def __nonzero__(self):
--- /dev/null
+% After retracting all rules defining a functor/arity user should be allowed to
+% change it's aggregator; Issue #61: can't retract wrong aggregator.
+
+> :- backchain f/1.
+> f(X) = 1.
+
+> retract_rule 0
+
+% now, make it's aggregator '+=' instead of '='
+> f(X) += 1.
+> f(X) += 2.
+
+> query f(1)
+
+f(1) = 3.
+
+% will still be one rule defining f/1
+> retract_rule 1
+
+
+% FIXME, empty changes...
+Changes
+=======
+
+
+% try to change to `:=`
+> f(X) := 100.
+
+DynaCompilerError:
+Encountered error in input program:
+ Conflicting aggregators; rule
+ f(X) := 100.
+ uses ':=' for f/1 but I had been lead to expect '+='.
+Everything was syntactically valid, but we could not
+see it through.
+new rule(s) were not added to program.