def step(self): while self.intentions and not self.intentions[0]: self.intentions.popleft() for intention_stack in self.intentions: intention = intention_stack[-1] # Wait until. if intention.wait_until: if intention.wait_until < self.env.time(): intention.wait_until = None else: continue break else: return False instr = intention.instr if not instr: intention_stack.pop() if not intention_stack: self.intentions.remove(intention_stack) elif intention.calling_term: frozen = intention.head_term.freeze(intention.scope, {}) calling_intention = intention_stack[-1] if not pyson.unify(intention.calling_term, frozen, calling_intention.scope, calling_intention.stack): raise RuntimeError("back unification failed") return True try: if instr.f(self, intention): intention.instr = instr.success else: intention.instr = instr.failure if not intention.instr: raise PysonError("plan failure") except PysonError as err: log = pyson.Log(LOGGER) raise log.error("%s @ %s", err, instr.f, loc=instr.loc, extra_locs=instr.extra_locs) except: log = pyson.Log(LOGGER) raise log.exception("python exception @ %s", instr.f, loc=instr.loc, extra_locs=instr.extra_locs) return True
def repl(hook): lineno = 0 tokens = [] while True: try: log = pyson.Log(pyson.get_logger(__name__), 3) if not tokens: line = pyson.util.prompt("pyson.parser >>> ") else: line = pyson.util.prompt("pyson.parser ... ") lineno += 1 tokens.extend(pyson.lexer.tokenize(pyson.StringSource("<stdin>", line), log, lineno)) while tokens: token_stream = iter(tokens) try: agent = parse_agent("<stdin>", token_stream, log, frozenset()) except StopIteration: log.throw() break else: log.throw() hook(agent) tokens = list(token_stream) except pyson.AggregatedError as error: print(str(error), file=sys.stderr) tokens = [] except KeyboardInterrupt: print() sys.exit(0)
def test_unexpected_eof(self): src = pyson.StringSource("<test>", "a") log = pyson.Log(pyson.get_logger(__name__), 3) tokens = pyson.lexer.TokenStream(src, log) with self.assertRaises(pyson.AggregatedError): pyson.parser.parse(tokens, log, frozenset())
def main(source, lineno=1): log = pyson.Log(pyson.get_logger(__name__), 3) for tok in tokenize(source, log, lineno): log.info("%s", tok.lexeme, loc=tok.loc) log.throw()
def step(self): while self.intentions and not self.intentions[0]: self.intentions.popleft() for intention_stack in self.intentions: intention = intention_stack[-1] # Suspended / waiting. if intention.waiter is not None: if intention.waiter.poll(self.env): intention.waiter = None else: continue break else: return False instr = intention.instr if not instr: intention_stack.pop() if not intention_stack: self.intentions.remove(intention_stack) elif intention.calling_term: frozen = intention.head_term.freeze(intention.scope, {}) calling_intention = intention_stack[-1] if not pyson.unify(intention.calling_term, frozen, calling_intention.scope, calling_intention.stack): raise RuntimeError("back unification failed") return True try: if instr.f(self, intention): intention.instr = instr.success else: intention.instr = instr.failure if not intention.instr: raise PysonError("plan failure") except PysonError as err: log = pyson.Log(LOGGER) raise log.error("%s", err, loc=instr.loc, extra_locs=instr.extra_locs) except Exception as err: log = pyson.Log(LOGGER) raise log.exception("agent %r raised python exception: %r", self.name, err, loc=instr.loc, extra_locs=instr.extra_locs) return True
def test_unify_return_value(self): src = pyson.StringSource("<test>", "+!p <- (X = 2) + 1 > 0.") log = pyson.Log(pyson.get_logger(__name__), 3) tokens = pyson.lexer.TokenStream(src, log) with self.assertRaises(pyson.AggregatedError): pyson.parser.parse(tokens, log, frozenset()) log.throw()
def test_rule_head_not_unifiable(self): src = pyson.StringSource("<test>", "rule(X + 1) :- true.") log = pyson.Log(pyson.get_logger(__name__), 3) tokens = pyson.lexer.TokenStream(src, log) pyson.parser.parse(tokens, log, frozenset()) with self.assertRaises(pyson.AggregatedError): log.throw()
def test_formula_type(self): src = pyson.StringSource("<test>", "+!plan <- ?true.") log = pyson.Log(pyson.get_logger(__name__), 3) tokens = pyson.lexer.TokenStream(src, log) pyson.parser.parse(tokens, log, frozenset()) with self.assertRaises(pyson.AggregatedError): log.throw()
def _build_agent(self, source, actions, agent_cls=Agent, name=None): # Parse source. log = pyson.Log(LOGGER, 3) tokens = pyson.lexer.TokenStream(source, log) ast_agent = pyson.parser.parse(tokens, log, frozenset(source.name)) log.throw() return self.build_agent_from_ast(source, ast_agent, actions, agent_cls, name)
def main(source, hook): log = pyson.Log(pyson.get_logger(__name__), 3) tokens = pyson.lexer.TokenStream(source, log, 1) agent = parse(source.name, tokens, log) log.throw() hook(agent)
def repl(agent, env, actions): lineno = 0 tokens = [] env = Environment() variables = {} intention = Intention() while True: try: log = pyson.Log(LOGGER, 3) try: if not tokens: line = pyson.util.prompt("%s >>> " % agent.name) else: line = pyson.util.prompt("%s ... " % agent.name) except KeyboardInterrupt: print() sys.exit(0) lineno += 1 tokens.extend( pyson.lexer.tokenize(pyson.StringSource("<stdin>", line), log, lineno)) while tokens: token_stream = iter(tokens) try: tok = next(token_stream) tok, body = pyson.parser.parse_plan_body( tok, token_stream, log) except StopIteration: log.throw() break else: log.throw() tokens = list(token_stream) intention.instr = Instruction(noop) body.accept( BuildInstructionsVisitor(variables, actions, intention.instr, log)) log.throw() agent.intentions.append(collections.deque([intention])) env.run_agent(agent) dump_variables(variables, intention.scope) except pyson.AggregatedError as error: print(str(error), file=sys.stderr) tokens = [] except pyson.PysonError as error: LOGGER.error("%s", error) tokens = []
def build_agent_from_ast(self, source, ast_agent, actions, agent_cls=Agent, name=None): # This function is also called by the optimizer. log = pyson.Log(LOGGER, 3) agent = agent_cls(self, self._make_name(name or source.name)) # Add rules to agent prototype. for ast_rule in ast_agent.rules: variables = {} head = ast_rule.head.accept(BuildTermVisitor(variables)) consequence = ast_rule.consequence.accept(BuildQueryVisitor(variables, actions, log)) agent.add_rule(Rule(head, consequence)) # Add plans to agent prototype. for ast_plan in ast_agent.plans: variables = {} head = ast_plan.head.accept(BuildTermVisitor(variables)) if ast_plan.context: context = ast_plan.context.accept(BuildQueryVisitor(variables, actions, log)) else: context = TrueQuery() body = Instruction(noop) body.f = noop if ast_plan.body: ast_plan.body.accept(BuildInstructionsVisitor(variables, actions, body, log)) plan = Plan(ast_plan.trigger, ast_plan.goal_type, head, context, body) agent.add_plan(plan) # Add beliefs to agent prototype. for ast_belief in ast_agent.beliefs: belief = ast_belief.accept(BuildTermVisitor({})) agent.call(pyson.Trigger.addition, pyson.GoalType.belief, belief, Intention(), delayed=True) # Call initial goals on agent prototype. for ast_goal in ast_agent.goals: term = ast_goal.atom.accept(BuildTermVisitor({})) agent.call(pyson.Trigger.addition, pyson.GoalType.achievement, term, Intention(), delayed=True) # Report errors. log.throw() self.agents[agent.name] = agent return ast_agent, agent
def _wait(agent, term, intention): # Handle optional arguments. args = [pyson.grounded(arg, intention.scope) for arg in term.args] if len(args) == 2: event, millis = args else: if pyson.is_number(args[0]): millis = args[0] event = None else: millis = None event = args[0] # Type checks. if not (millis is None or pyson.is_number(millis)): raise pyson.PysonError("expected timeout for .wait to be numeric") if not (event is None or pyson.is_string(event)): raise pyson.PysonError("expected event for .wait to be a string") # Event. if event is not None: # Parse event. if not event.endswith("."): event += "." log = pyson.Log(LOGGER, 1) tokens = pyson.lexer.TokenStream(pyson.StringSource("<.wait>", event), log) tok, ast_event = pyson.parser.parse_event(tokens.next(), tokens, log) if tok.lexeme != ".": raise log.error( "expected no further tokens after event for .wait, got: '%s'", tok.lexeme, loc=tok.loc) # Build term. event = ast_event.accept(pyson.runtime.BuildEventVisitor(log)) # Timeout. if millis is None: until = None else: until = agent.env.time() + millis / 1000 # Create waiter. intention.waiter = pyson.runtime.Waiter(event=event, until=until) yield