Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

run_step_by_step in runner #469

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions python/hyperon/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ def __init__(self, metta, program):
# until the RunnerState is done with it.
self.parser = parser
self.cstate = hp.runner_state_new_with_parser(metta.cmetta, parser.cparser)
self.cmetta = metta.cmetta

def __del__(self):
"""Frees a RunnerState and all associated resources."""
hp.runner_state_free(self.cstate)

def __str__(self):
return self.cstate.__str__()

def run_step(self):
"""
Executes the next step in the interpretation plan, or begins interpretation of the next atom in the stream of MeTTa code.
Expand All @@ -44,6 +48,11 @@ def current_results(self, flat=False):
Returns the current in-progress results from an in-flight program evaluation
"""
results = hp.runner_state_current_results(self.cstate)

err_str = hp.metta_err_str(self.cmetta)
if (err_str is not None):
raise RuntimeError(err_str)

if flat:
return [Atom._from_catom(catom) for result in results for catom in result]
else:
Expand Down Expand Up @@ -199,6 +208,9 @@ def run(self, program, flat=False):
"""Runs the MeTTa code from the program string containing S-Expression MeTTa syntax"""
parser = SExprParser(program)
results = hp.metta_run(self.cmetta, parser.cparser)
return self.process_results(results, flat=flat)

def process_results(self, results, flat=False):
err_str = hp.metta_err_str(self.cmetta)
if (err_str is not None):
raise RuntimeError(err_str)
Expand All @@ -207,6 +219,14 @@ def run(self, program, flat=False):
else:
return [[Atom._from_catom(catom) for catom in result] for result in results]

def run_step_by_step(self, program):
"""Runs program step by step, yielding state"""
state = RunnerState(self, program)
while not state.is_complete():
state.run_step()
yield state


class Environment:
"""This class contains the API for configuring the host platform interface used by MeTTa"""

Expand Down
24 changes: 24 additions & 0 deletions python/tests/test_run_metta.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import unittest
from hyperon import MeTTa, Environment, E
from test_common import HyperonTestCase

Expand Down Expand Up @@ -68,8 +69,31 @@ def test_comments(self):
result = MeTTa(env_builder=Environment.test_env()).run(program)
self.assertEqual('[[1]]', repr(result))

def test_run_step_by_step(self):
program = '''
(= (TupleCount $tuple) (if (== $tuple ()) 0 (+ 1 (TupleCount (cdr-atom $tuple)))))
(= tup (1 2))
(= tup (3 4 5))
!(match &self (= tup $t) (TupleCount $t))
'''
runner = MeTTa(env_builder=Environment.test_env())
i = 0
for state in runner.run_step_by_step(program):
pass
i += 1
print('number of steps ' + str(i))
self.assertLess(i, 600)
results = state.current_results()
self.assertEqual(len(results[0]), 2)

def process_exceptions(self, results):
for result in results:
self.assertEqual(result, [E()])


def test_scripts(self):


#LP-TODO-Next: I'd like to remove the working directory for this runner, and instead try
# to import child modules relative to their parents using `self:` paths. See comments around
# `relative_submodule_import_test`
Expand Down
Loading