From b1e073b8624cd6fcf232cf772b1c19625c455dbc Mon Sep 17 00:00:00 2001 From: "Alexie (Boyong) Madolid" Date: Wed, 25 Sep 2024 17:55:13 +0800 Subject: [PATCH] temporary --- jac/jaclang/cli/cli.py | 2 +- jac/jaclang/runtimelib/context.py | 15 +-- jac/jaclang/runtimelib/implementation.py | 3 +- jac/jaclang/runtimelib/interface.py | 127 ++++++++++++++++++++++- jac/jaclang/runtimelib/memory.py | 110 ++++++-------------- 5 files changed, 164 insertions(+), 93 deletions(-) diff --git a/jac/jaclang/cli/cli.py b/jac/jaclang/cli/cli.py index 294ca36d7c..3634449d9a 100644 --- a/jac/jaclang/cli/cli.py +++ b/jac/jaclang/cli/cli.py @@ -19,8 +19,8 @@ from jaclang.compiler.passes.tool.schedules import format_pass from jaclang.plugin.builtin import dotgen from jaclang.plugin.feature import JacFeature as Jac -from jaclang.runtimelib.constructs import WalkerArchitype from jaclang.runtimelib.context import ExecutionContext +from jaclang.runtimelib.implementation import WalkerArchitype from jaclang.runtimelib.machine import JacMachine, JacProgram from jaclang.utils.helpers import debugger as db from jaclang.utils.lang_tools import AstTool diff --git a/jac/jaclang/runtimelib/context.py b/jac/jaclang/runtimelib/context.py index d2badd6c2a..5df5becf4e 100644 --- a/jac/jaclang/runtimelib/context.py +++ b/jac/jaclang/runtimelib/context.py @@ -4,11 +4,12 @@ import unittest from contextvars import ContextVar -from typing import Any, Callable, Optional, cast +from typing import Callable, Optional, cast from uuid import UUID -from .interface import NodeAnchor, Root -from .memory import Memory, ShelfStorage +from .implementation import NodeAnchor, Root +from .interface import ExecutionContext as BaseExecutionContext +from .memory import ShelfStorage EXECUTION_CONTEXT = ContextVar[Optional["ExecutionContext"]]("ExecutionContext") @@ -21,15 +22,9 @@ SUPER_ROOT_ARCHITYPE.__jac__ = SUPER_ROOT_ANCHOR -class ExecutionContext: +class ExecutionContext(BaseExecutionContext): """Execution Context.""" - mem: Memory - reports: list[Any] - system_root: NodeAnchor - root: NodeAnchor - entry_node: NodeAnchor - def init_anchor( self, anchor_id: str | None, diff --git a/jac/jaclang/runtimelib/implementation.py b/jac/jaclang/runtimelib/implementation.py index 22ccdf944b..c5705f5f77 100644 --- a/jac/jaclang/runtimelib/implementation.py +++ b/jac/jaclang/runtimelib/implementation.py @@ -19,7 +19,8 @@ _ANCHOR, ) -ANCHOR_TYPES: TypeAlias = "NodeAnchor" | "EdgeAnchor" | "WalkerAnchor" +Anchor: TypeAlias = "NodeAnchor" | "EdgeAnchor" | "WalkerAnchor" +Architype: TypeAlias = "NodeArchitype" | "EdgeArchitype" | "WalkerArchitype" logger = getLogger(__name__) diff --git a/jac/jaclang/runtimelib/interface.py b/jac/jaclang/runtimelib/interface.py index 8ca75da385..89c46c31a5 100644 --- a/jac/jaclang/runtimelib/interface.py +++ b/jac/jaclang/runtimelib/interface.py @@ -1,10 +1,12 @@ """Jaclang Runtimelib interfaces.""" +from __future__ import annotations + from abc import ABC, abstractmethod from dataclasses import dataclass, field from enum import IntEnum from types import UnionType -from typing import Any, Callable, ClassVar, Generic, Iterable, Type, TypeVar +from typing import Any, Callable, ClassVar, Generator, Generic, Iterable, Type, TypeVar _ID = TypeVar("_ID") @@ -14,6 +16,11 @@ _DESERIALIZE = TypeVar("_DESERIALIZE") +######################################################################################### +# ID / ACCESS # +######################################################################################### + + @dataclass(kw_only=True) class JID(Generic[_ID, _ANCHOR], ABC): """Jaclang ID Interface.""" @@ -62,6 +69,11 @@ class Permission: roots: Access = field(default_factory=Access) +######################################################################################### +# ANCHORS # +######################################################################################### + + @dataclass(kw_only=True) class Anchor(Generic[_SERIALIZE], ABC): """Anchor Interface.""" @@ -105,6 +117,11 @@ class WalkerAnchor(Anchor[_SERIALIZE]): architype: "WalkerArchitype" +######################################################################################### +# ARCHITYPES # +######################################################################################### + + class Architype(Generic[_SERIALIZE], ABC): """Architype Interface.""" @@ -159,3 +176,111 @@ class DSFunc: def resolve(self, cls: type) -> None: """Resolve the function.""" self.func = getattr(cls, self.name) + + +######################################################################################### +# MEMORY INTERFACES # +######################################################################################### + + +@dataclass +class Memory(Generic[_ID, _ANCHOR]): + """Generic Memory Handler.""" + + __mem__: dict[_ID, _ANCHOR] = field(default_factory=dict) + __gc__: set[_ID] = field(default_factory=set) + + def close(self) -> None: + """Close memory handler.""" + self.__mem__.clear() + self.__gc__.clear() + + def find( + self, + ids: _ID | Iterable[_ID], + filter: Callable[[_ANCHOR], _ANCHOR] | None = None, + ) -> Generator[_ANCHOR, None, None]: + """Find anchors from memory by ids with filter.""" + if not isinstance(ids, Iterable): + ids = [ids] + + return ( + anchor + for id in ids + if (anchor := self.__mem__.get(id)) and (not filter or filter(anchor)) + ) + + def find_one( + self, + ids: _ID | Iterable[_ID], + filter: Callable[[_ANCHOR], _ANCHOR] | None = None, + ) -> _ANCHOR | None: + """Find one anchor from memory by ids with filter.""" + return next(self.find(ids, filter), None) + + def find_by_id(self, id: _ID) -> _ANCHOR | None: + """Find one by id.""" + return self.__mem__.get(id) + + def set(self, id: _ID, data: _ANCHOR) -> None: + """Save anchor to memory.""" + self.__mem__[id] = data + + def remove(self, ids: _ID | Iterable[_ID]) -> None: + """Remove anchor/s from memory.""" + if not isinstance(ids, Iterable): + ids = [ids] + + for id in ids: + if self.__mem__.pop(id, None): + self.__gc__.add(id) + + +######################################################################################### +# CONTEXT # +######################################################################################### + + +class ExecutionContext(ABC): + """Execution Context.""" + + mem: Memory + reports: list[Any] + system_root: NodeAnchor + root: NodeAnchor + entry_node: NodeAnchor + + @abstractmethod + def init_anchor( + self, + anchor_id: str | None, + default: NodeAnchor, + ) -> NodeAnchor: + """Load initial anchors.""" + + def set_entry_node(self, entry_node: str | None) -> None: + """Override entry.""" + self.entry_node = self.init_anchor(entry_node, self.root) + + @abstractmethod + def close(self) -> None: + """Close current ExecutionContext.""" + + @staticmethod + @abstractmethod + def create( + session: str | None = None, + root: str | None = None, + auto_close: bool = True, + ) -> ExecutionContext: + """Create ExecutionContext.""" + + @staticmethod + @abstractmethod + def get() -> ExecutionContext: + """Get current ExecutionContext.""" + + @staticmethod + @abstractmethod + def get_root() -> Root: + """Get current root.""" diff --git a/jac/jaclang/runtimelib/memory.py b/jac/jaclang/runtimelib/memory.py index 051165e5ee..3f42707472 100644 --- a/jac/jaclang/runtimelib/memory.py +++ b/jac/jaclang/runtimelib/memory.py @@ -2,72 +2,20 @@ from __future__ import annotations -from dataclasses import dataclass, field +from dataclasses import dataclass from pickle import dumps from shelve import Shelf, open -from typing import Callable, Generator, Generic, Iterable, TypeVar +from typing import Callable, Generator, Iterable, TypeVar from uuid import UUID -from .architype import Anchor, NodeAnchor, Root, TANCH +from .implementation import Anchor, JID, NodeAnchor, Root +from .interface import Memory ID = TypeVar("ID") @dataclass -class Memory(Generic[ID, TANCH]): - """Generic Memory Handler.""" - - __mem__: dict[ID, TANCH] = field(default_factory=dict) - __gc__: set[TANCH] = field(default_factory=set) - - def close(self) -> None: - """Close memory handler.""" - self.__mem__.clear() - self.__gc__.clear() - - def find( - self, - ids: ID | Iterable[ID], - filter: Callable[[TANCH], TANCH] | None = None, - ) -> Generator[TANCH, None, None]: - """Find anchors from memory by ids with filter.""" - if not isinstance(ids, Iterable): - ids = [ids] - - return ( - anchor - for id in ids - if (anchor := self.__mem__.get(id)) and (not filter or filter(anchor)) - ) - - def find_one( - self, - ids: ID | Iterable[ID], - filter: Callable[[TANCH], TANCH] | None = None, - ) -> TANCH | None: - """Find one anchor from memory by ids with filter.""" - return next(self.find(ids, filter), None) - - def find_by_id(self, id: ID) -> TANCH | None: - """Find one by id.""" - return self.__mem__.get(id) - - def set(self, id: ID, data: TANCH) -> None: - """Save anchor to memory.""" - self.__mem__[id] = data - - def remove(self, ids: ID | Iterable[ID]) -> None: - """Remove anchor/s from memory.""" - if not isinstance(ids, Iterable): - ids = [ids] - - for id in ids: - if anchor := self.__mem__.pop(id, None): - self.__gc__.add(anchor) - - -@dataclass -class ShelfStorage(Memory[UUID, Anchor]): +class ShelfStorage(Memory[JID[Anchor], Anchor]): """Shelf Handler.""" __shelf__: Shelf[Anchor] | None = None @@ -82,38 +30,40 @@ def close(self) -> None: if isinstance(self.__shelf__, Shelf): from jaclang.plugin.feature import JacFeature as Jac - for anchor in self.__gc__: - self.__shelf__.pop(str(anchor.id), None) - self.__mem__.pop(anchor.id, None) + for jid in self.__gc__: + self.__shelf__.pop(str(jid), None) + self.__mem__.pop(jid, None) - for d in self.__mem__.values(): - if d.persistent and d.hash != hash(dumps(d)): - _id = str(d.id) - if p_d := self.__shelf__.get(_id): + for jid, anchor in self.__mem__.items(): + if anchor.persistent and anchor.hash != hash(dumps(anchor)): + _jid = str(jid) + if p_d := self.__shelf__.get(_jid): if ( isinstance(p_d, NodeAnchor) - and isinstance(d, NodeAnchor) - and p_d.edges != d.edges - and Jac.check_connect_access(d) + and isinstance(anchor, NodeAnchor) + and p_d.edge_ids != anchor.edge_ids + and Jac.check_connect_access(anchor) ): - if not d.edges: - self.__shelf__.pop(_id, None) + if not anchor.edge_ids: + self.__shelf__.pop(_jid, None) continue - p_d.edges = d.edges + p_d.edge_ids = anchor.edge_ids - if Jac.check_write_access(d): - if hash(dumps(p_d.access)) != hash(dumps(d.access)): - p_d.access = d.access - if hash(dumps(d.architype)) != hash(dumps(d.architype)): - p_d.architype = d.architype + if Jac.check_write_access(anchor): + if hash(dumps(p_d.access)) != hash(dumps(anchor.access)): + p_d.access = anchor.access + if hash(dumps(anchor.architype)) != hash( + dumps(anchor.architype) + ): + p_d.architype = anchor.architype - self.__shelf__[_id] = p_d + self.__shelf__[_jid] = p_d elif not ( - isinstance(d, NodeAnchor) - and not isinstance(d.architype, Root) - and not d.edges + isinstance(anchor, NodeAnchor) + and not isinstance(anchor.architype, Root) + and not anchor.edge_ids ): - self.__shelf__[_id] = d + self.__shelf__[_jid] = anchor self.__shelf__.close() super().close()