Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

Commit

Permalink
[REFACTOR]: Execution Context
Browse files Browse the repository at this point in the history
  • Loading branch information
amadolid committed Aug 28, 2024
1 parent 39cc924 commit 38227e2
Show file tree
Hide file tree
Showing 11 changed files with 204 additions and 210 deletions.
92 changes: 56 additions & 36 deletions jaclang/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
from jaclang.plugin.builtin import dotgen
from jaclang.plugin.feature import JacCmd as Cmd
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.runtimelib.constructs import Anchor, Architype
from jaclang.runtimelib.machine import JacProgram
from jaclang.runtimelib.constructs import Architype, WalkerArchitype
from jaclang.runtimelib.context import ExecutionContext
from jaclang.runtimelib.machine import JacMachine, JacProgram
from jaclang.utils.helpers import debugger as db
from jaclang.utils.lang_tools import AstTool

Expand Down Expand Up @@ -90,7 +91,9 @@ def run(
base, mod = os.path.split(filename)
base = base if base else "./"
mod = mod[:-4]
Jac.context().init_memory(base_path=base, session=session)

jctx = ExecutionContext.create(session=session)

if filename.endswith(".jac"):
ret_module = jac_import(
target=mod,
Expand All @@ -104,14 +107,12 @@ def run(
(loaded_mod,) = ret_module
elif filename.endswith(".jir"):
with open(filename, "rb") as f:
ir = pickle.load(f)
jac_program = JacProgram(mod_bundle=ir, bytecode=None)
Jac.context().jac_machine.attach_program(jac_program)
ret_module = jac_import(
target=mod,
base_path=base,
cachable=cache,
override_name="__main__" if main else None,
jac_program=JacProgram(mod_bundle=pickle.load(f), bytecode=None),
)
if ret_module is None:
loaded_mod = None
Expand All @@ -122,13 +123,13 @@ def run(
return

if not node or node == "root":
entrypoint: Architype = Jac.get_root()
else:
obj = Jac.context().mem.find_by_id(UUID(node))
if not isinstance(obj, Anchor) or obj.architype is None:
print(f"Entrypoint {node} not found.")
return
entrypoint: Architype = jctx.root.architype
elif obj := jctx.datasource.find_by_id(UUID(node)):
entrypoint = obj.architype
else:
print(f"Entrypoint {node} not found.")
jctx.close()
return

# TODO: handle no override name
if walker:
Expand All @@ -138,7 +139,7 @@ def run(
else:
print(f"Walker {walker} not found.")

Jac.reset_context()
jctx.close()


@cmd_registry.register
Expand All @@ -147,21 +148,18 @@ def get_object(id: str, session: str = "") -> dict:
if session == "":
session = cmd_registry.args.session if "session" in cmd_registry.args else ""

Jac.context().init_memory(session=session)
jctx = ExecutionContext.create(session=session)

data = {}
if id == "root":
id_uuid = UUID(int=0)
data = jctx.root.__getstate__()
elif obj := jctx.datasource.find_by_id(UUID(id)):
data = obj.__getstate__()
else:
id_uuid = UUID(id)

obj = Jac.context().mem.find_by_id(id_uuid)
if obj is None:
print(f"Object with id {id} not found.")
Jac.reset_context()
return {}
else:
Jac.reset_context()
return obj.__getstate__()

jctx.close()
return data


@cmd_registry.register
Expand Down Expand Up @@ -211,26 +209,43 @@ def lsp() -> None:


@cmd_registry.register
def enter(filename: str, entrypoint: str, args: list) -> None:
"""Run the specified entrypoint function in the given .jac file.
def enter(
filename: str,
entrypoint: str,
args: list,
session: str = "",
root: str = "",
node: str = "",
) -> None:
"""
Run the specified entrypoint function in the given .jac file.
:param filename: The path to the .jac file.
:param entrypoint: The name of the entrypoint function.
:param args: Arguments to pass to the entrypoint function.
:param session: shelve.Shelf file path.
:param root: root executor.
:param node: starting node.
"""
jctx = ExecutionContext.create(session=session, root=root, entry=node)

if filename.endswith(".jac"):
base, mod_name = os.path.split(filename)
base = base if base else "./"
mod_name = mod_name[:-4]
(mod,) = jac_import(target=mod_name, base_path=base)
if not mod:
print("Errors occurred while importing the module.")
return
else:
getattr(mod, entrypoint)(*args)
architype = getattr(mod, entrypoint)(*args)
if isinstance(architype, WalkerArchitype):
Jac.spawn_call(jctx.entry.architype, architype)

else:
print("Not a .jac file.")

jctx.close()


@cmd_registry.register
def test(
Expand All @@ -252,6 +267,8 @@ def test(
jac test => jac test -d .
"""
jctx = ExecutionContext.create()

failcount = Jac.run_test(
filepath=filepath,
filter=filter,
Expand All @@ -260,6 +277,9 @@ def test(
directory=directory,
verbose=verbose,
)

jctx.close()

if failcount:
raise SystemExit(f"Tests failed: {failcount}")

Expand Down Expand Up @@ -361,13 +381,13 @@ def dot(
base, mod = os.path.split(filename)
base = base if base else "./"
mod = mod[:-4]
Jac.context().init_memory(base_path=base, session=session)

jctx = ExecutionContext.create(session=session)

if filename.endswith(".jac"):
jac_import(
target=mod,
base_path=base,
)
module = Jac.context().jac_machine.loaded_modules.get(mod)
jac_machine = JacMachine(base)
jac_import(target=mod, base_path=base, jac_machine=jac_machine)
module = jac_machine.loaded_modules.get(mod)
globals().update(vars(module))
try:
node = globals().get(initial, eval(initial)) if initial else None
Expand All @@ -385,7 +405,7 @@ def dot(
import traceback

traceback.print_exc()
Jac.reset_context()
jctx.close()
return
file_name = saveto if saveto else f"{mod}.dot"
with open(file_name, "w") as file:
Expand All @@ -394,7 +414,7 @@ def dot(
else:
print("Not a .jac file.")

Jac.reset_context()
jctx.close()


@cmd_registry.register
Expand Down
15 changes: 5 additions & 10 deletions jaclang/compiler/tests/test_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,29 @@

from jaclang import jac_import
from jaclang.cli import cli
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.runtimelib.machine import JacMachine
from jaclang.utils.test import TestCase


class TestLoader(TestCase):
"""Test Jac self.prse."""

def setUp(self) -> None:
"""Set up test."""
return super().setUp()

def test_import_basic_python(self) -> None:
"""Test basic self loading."""
Jac.context().init_memory(base_path=self.fixture_abs_path(__file__))
(h,) = jac_import("fixtures.hello_world", base_path=__file__)
self.assertEqual(h.hello(), "Hello World!") # type: ignore

def test_modules_correct(self) -> None:
"""Test basic self loading."""
Jac.context().init_memory(base_path=self.fixture_abs_path(__file__))
jac_import("fixtures.hello_world", base_path=__file__)
jac_machine = JacMachine(__file__)
jac_import("fixtures.hello_world", base_path=__file__, jac_machine=jac_machine)
self.assertIn(
"module 'fixtures.hello_world'",
str(Jac.context().jac_machine.loaded_modules),
str(jac_machine.loaded_modules),
)
self.assertIn(
"/tests/fixtures/hello_world.jac",
str(Jac.context().jac_machine.loaded_modules),
str(jac_machine.loaded_modules),
)

def test_jac_py_import(self) -> None:
Expand Down
45 changes: 18 additions & 27 deletions jaclang/plugin/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
Root,
WalkerAnchor,
WalkerArchitype,
exec_context,
)
from jaclang.runtimelib.importer import ImportPathSpec, JacImporter, PythonImporter
from jaclang.runtimelib.machine import JacMachine, JacProgram
from jaclang.runtimelib.utils import traverse_graph
from jaclang.plugin.feature import JacFeature as Jac # noqa: I100
from jaclang.plugin.spec import P, T
Expand Down Expand Up @@ -69,28 +69,15 @@ class JacFeatureDefaults:

@staticmethod
@hookimpl
def context(session: str = "") -> ExecutionContext:
"""Get the execution context."""
ctx = exec_context.get()
if ctx is None:
ctx = ExecutionContext()
exec_context.set(ctx)
return ctx
def get_context() -> ExecutionContext:
"""Get current execution context."""
return ExecutionContext.get()

@staticmethod
@hookimpl
def reset_context() -> None:
"""Reset the execution context."""
ctx = exec_context.get()
if ctx:
ctx.reset()
exec_context.set(None)

@staticmethod
@hookimpl
def memory_hook() -> Memory | None:
"""Return the memory hook."""
return Jac.context().mem
def get_datasource() -> Memory:
"""Get current execution context."""
return ExecutionContext.get().datasource

@staticmethod
@hookimpl
Expand Down Expand Up @@ -251,6 +238,8 @@ def jac_import(
lng: Optional[str],
items: Optional[dict[str, Union[str, Optional[str]]]],
reload_module: Optional[bool],
jac_machine: Optional[JacMachine],
jac_program: Optional[JacProgram],
) -> tuple[types.ModuleType, ...]:
"""Core Import Process."""
spec = ImportPathSpec(
Expand All @@ -263,12 +252,14 @@ def jac_import(
lng,
items,
)
jac_machine = jac_machine or JacMachine(base_path)
jac_machine.attach_program(
jac_program or JacProgram(mod_bundle=None, bytecode=None)
)
if lng == "py":
import_result = PythonImporter(Jac.context().jac_machine).run_import(spec)
import_result = PythonImporter(jac_machine).run_import(spec)
else:
import_result = JacImporter(Jac.context().jac_machine).run_import(
spec, reload_module
)
import_result = JacImporter(jac_machine).run_import(spec, reload_module)
return (
(import_result.ret_mod,)
if absorb or not items
Expand Down Expand Up @@ -503,14 +494,14 @@ def disconnect(
and node == source
and target.architype in right
):
anchor.destroy()
anchor.destroy() if anchor.persistent else anchor.detach()
disconnect_occurred = True
if (
dir in [EdgeDir.IN, EdgeDir.ANY]
and node == target
and source.architype in right
):
anchor.destroy()
anchor.destroy() if anchor.persistent else anchor.detach()
disconnect_occurred = True

return disconnect_occurred
Expand All @@ -531,7 +522,7 @@ def assign_compr(
@hookimpl
def get_root() -> Root:
"""Jac's assign comprehension feature."""
return Jac.context().get_root()
return ExecutionContext.get_root()

@staticmethod
@hookimpl
Expand Down
Loading

0 comments on commit 38227e2

Please sign in to comment.