def render_rule_context(rule, ctx, indent=''):
- # TODO: include an undefined or unknown marker
- # TODO: can highlight the expression which raise the error.
+ # TODO: highlight expression which caused the error.
from post.trace import Crux
c = Crux(head=None, rule=rule, body=None, vs = ctx)
- return ''.join(indent + line for line in c.format())
+ return '\n'.join(indent + line for line in c.format())
class Rule(object):
self.init = None
self.updaters = []
self.query = None
-
self._span = None
self._src = None
+ self.initialized = False
+
@property
def span(self):
if self._span is None:
print '^C'
self.dump_charts()
- def _go(self):
+ def _go(self, changed=None):
"the main loop"
- changed = {}
+ if changed is None:
+ changed = {}
agenda = self.agenda
error = self.error
while agenda:
if was == now:
continue
- was_error = False
- if item in error: # clear error
- was_error = True
- del error[item]
-
# TODO: handle `was` and `now` at the same time to avoid the two passes.
# TODO: will need to propagate was=None when we have question mark
- if was is not None and not was_error:
+ if was is not None: # and item not in error:
# if `was` is marked as an error we know it didn't propagate.
# Thus, we can skip the delete-updates.
self.update_dispatcher(item, was, delete=True)
- assert now is not True or now is not False # invalid dyna types.
+ if item in error: # only care about errors at new value.
+ del error[item]
item.value = now
changed[item] = now
+ if self.uninitialized_rules:
+ self.run_uninitialized()
+
+ if self.agenda:
+ self._go(changed)
+
return changed
def update_dispatcher(self, item, val, delete):
error = []
for handler in self.updaters[item.fn]:
+
+ if not handler.rule.initialized:
+ continue
+
try:
handler(item, val, emit=t_emit)
except (TypeError, ZeroDivisionError, KeyboardInterrupt, OverflowError) as e:
def run_uninitialized(self):
q = list(self.uninitialized_rules)
+ failed = []
+
self.uninitialized_rules = []
+
while q:
(_, r) = q.pop()
try:
+
+ rule = self.rules[r]
+ assert not rule.initialized
+
emits = []
def _emit(*args):
emits.append(args)
- self.rules[r].init(emit=_emit)
+ rule.init(emit=_emit)
except (TypeError, ZeroDivisionError) as e:
e.exception_frame = rule_error_context()
- self.uninitialized_rules.append((e, r))
+ failed.append((e, r))
else:
+ rule.initialized = True
# process emits
for e in emits:
self.emit(*e, delete=False)
+ self.uninitialized_rules = failed
def dynac(self, filename):
filename = path(filename)