Skip to content

Commit

Permalink
Update after jason review:
Browse files Browse the repository at this point in the history
- List changed to JacList
- All architype share the same meta class, support for cross inheritance
- Types annotation were added to root node so type check pass tests
  are passing.
  • Loading branch information
ThakeeNathees committed Jan 25, 2025
1 parent 4788666 commit 3aea9f3
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 104 deletions.
12 changes: 6 additions & 6 deletions jac/examples/reference/architypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

def print_base_classes(cls: type) -> type:
print(
f"Base classes of {cls.__name__}: {List([c.__name__ for c in cls.__bases__])}"
f"Base classes of {cls.__name__}: {JacList([c.__name__ for c in cls.__bases__])}"
)
return cls


class Animal(Obj):
class Animal:
pass


Expand All @@ -18,18 +18,18 @@ class Domesticated(Obj):


@print_base_classes
class Pet(Animal, Domesticated, Obj):
class Pet(Animal, Domesticated, Node):
pass


class Person(Animal, Obj):
class Person(Animal, Walker):
pass


class Feeder(Person, Obj):
class Feeder(Person, Walker):
pass


@print_base_classes
class Zoologist(Feeder, Obj):
class Zoologist(Feeder, Walker):
pass
4 changes: 2 additions & 2 deletions jac/examples/reference/builtin_types.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from jaclang import List
from jaclang import JacList

a = 9.2
b = 44
c = List([2, 4, 6, 10])
c = JacList([2, 4, 6, 10])
d = {"name": "john", "age": 28}
e = ("jaseci", 5, 4, 14)
f = True
Expand Down
104 changes: 38 additions & 66 deletions jac/jaclang/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
Generic,
Tuple,
Type,
TypeGuard,
TypeVar,
override,
cast,
)

from jaclang.plugin.builtin import dotgen, jid, jobj # noqa: F401
Expand All @@ -30,7 +32,7 @@
"Walker",
"Node",
"Edge",
"List",
"JacList",
"EdgeDir",
"Root",
# Decorators.
Expand Down Expand Up @@ -60,6 +62,7 @@
plugin_manager.load_setuptools_entrypoints("jac")

T = TypeVar("T")
S = TypeVar("S") # S is a subtype of T.

# ----------------------------------------------------------------------------
# Meta classes.
Expand All @@ -74,19 +77,20 @@
# Reference: https://stackoverflow.com/a/9639512/10846399
#
class _ArchiTypeBase:
pass

def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
"""Initialize Jac architype base."""

class MetaCommon(ABCMeta):

class JacMeta(ABCMeta):
"""Common metaclass for Jac types."""

def __new__( # noqa: D102
cls,
name: str,
bases: Tuple[Type, ...],
dct: Dict[str, Any],
make_func: Callable[[list, list], Callable[[type], type]],
) -> "MetaCommon":
) -> "JacMeta":

# We have added this "__init__" to the jac base class just to make the type checkers happy.
# Actually the dataclass decorator will create an __init__ function and assign it here bellow.
Expand All @@ -102,55 +106,25 @@ def __new__( # noqa: D102

inst = super().__new__(cls, name, bases, dct)
inst = dataclass(eq=False)(inst) # type: ignore [arg-type, assignment]
inst = make_func(on_entry, on_exit)(inst) # type: ignore [assignment]
inst = inst._MAKE_FN(on_entry, on_exit)(inst) # type: ignore [assignment, attr-defined]
return inst


class MetaObj(MetaCommon): # noqa: D101
def __new__( # noqa: D102
cls, name: str, bases: Tuple[Type, ...], dct: Dict[str, Any]
) -> "MetaCommon":
return super().__new__(cls, name, bases, dct, Jac.make_obj)


class MetaWalker(MetaCommon): # noqa: D101
def __new__( # noqa: D102
cls, name: str, bases: Tuple[Type, ...], dct: Dict[str, Any]
) -> "MetaCommon":
return super().__new__(cls, name, bases, dct, Jac.make_walker)


class MetaNode(MetaCommon): # noqa: D101
def __new__( # noqa: D102
cls, name: str, bases: Tuple[Type, ...], dct: Dict[str, Any]
) -> "MetaCommon":
return super().__new__(cls, name, bases, dct, Jac.make_node)


class MetaEdge(MetaCommon): # noqa: D101
def __new__( # noqa: D102
cls, name: str, bases: Tuple[Type, ...], dct: Dict[str, Any]
) -> "MetaCommon":
return super().__new__(cls, name, bases, dct, Jac.make_edge)


# ----------------------------------------------------------------------------
# Base classes.
# ----------------------------------------------------------------------------


class Obj(_ArchiTypeBase, metaclass=MetaObj):
class Obj(_ArchiTypeBase, metaclass=JacMeta):
"""Base class for all the jac object types."""

def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
"""Initialize Jac architype base."""
_MAKE_FN = Jac.make_obj


class Walker(_ArchiTypeBase, metaclass=MetaWalker):
class Walker(_ArchiTypeBase, metaclass=JacMeta):
"""Base class for all the jac walker types."""

def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
"""Initialize Jac architype base."""
_MAKE_FN = Jac.make_walker

def spawn(self, node: "_ArchiTypeBase | Root") -> "Walker":
"""Spawn a new node from the walker."""
Expand All @@ -163,7 +137,7 @@ def ignore(
| Node
| Edge
| list[Node | Root | Edge]
| List[Node | Root | Edge]
| JacList[Node | Root | Edge]
)""",
) -> bool:
"""Ignore statement."""
Expand All @@ -176,7 +150,7 @@ def visit(
| Node
| Edge
| list[Node | Root | Edge]
| List[Node | Root | Edge]
| JacList[Node | Root | Edge]
)""",
) -> bool:
"""Visit statement."""
Expand All @@ -187,24 +161,23 @@ def disengage(self) -> None:
Jac.disengage(self) # type: ignore [arg-type]


class Node(_ArchiTypeBase, metaclass=MetaNode):
class Node(_ArchiTypeBase, metaclass=JacMeta):
"""Base class for all the jac node types."""

def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
"""Initialize Jac architype base."""
_MAKE_FN = Jac.make_node

def spawn(self, archi: _ArchiTypeBase) -> "Walker":
"""Spawn a new node from the walker."""
return Jac.spawn_call(self, archi) # type: ignore [arg-type, return-value]

def connect(
self,
node: "Node | Root | List[Node | Root]",
node: "Node | Root | JacList[Node | Root]",
edge: "type[Edge] | Edge | None" = None,
unidir: bool = False,
conn_assign: tuple[tuple, tuple] | None = None,
edges_only: bool = False,
) -> "List[Node | Root| Edge]":
) -> "JacList[Node | Root| Edge]":
"""Connect the current node to another node."""
# TODO: The above edge type should be reviewed, as the bellow can also take None, Edge, type[Edge].
ret = Jac.connect(
Expand All @@ -215,11 +188,11 @@ def connect(
),
edges_only=edges_only,
)
return List(ret) # type: ignore [arg-type]
return JacList(ret) # type: ignore [arg-type]

def disconnect(
self,
node: "Node | Root | List[Node | Root]",
node: "Node | Root | JacList[Node | Root]",
edge: "type[Edge] | None" = None,
dir: EdgeDir = EdgeDir.OUT,
) -> bool:
Expand All @@ -235,10 +208,10 @@ def refs(
self,
edge: "type[Edge] | None" = None,
cond: "Callable[[Edge], bool] | None" = None,
target: "Node | Root | List[Node|Root] | None" = None,
target: "Node | Root | JacList[Node|Root] | None" = None,
dir: EdgeDir = EdgeDir.OUT,
edges_only: bool = False,
) -> "List[Node | Root | Edge]":
) -> "JacList[Node | Root | Edge]":
"""Return all the connected nodes / edges."""
filter_func = (
(
Expand All @@ -256,21 +229,20 @@ def refs(
filter_func=filter_func,
edges_only=edges_only,
)
return List(ret)
return JacList(ret)


class Edge(_ArchiTypeBase, metaclass=MetaEdge):
class Edge(_ArchiTypeBase, metaclass=JacMeta):
"""Base class for all the jac edge types."""

def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
"""Initialize Jac architype base."""
_MAKE_FN = Jac.make_edge

def spawn(self, archi: _ArchiTypeBase) -> "Walker":
"""Spawn a new node from the walker."""
return Jac.spawn_call(self, archi) # type: ignore [arg-type, return-value]


class List(Generic[T], list[T]):
class JacList(Generic[T], list[T]):
"""List with jac methods."""

# Reuse the methods.
Expand All @@ -279,22 +251,22 @@ class List(Generic[T], list[T]):
refs = Node.refs

def filter(
self, ty: type[T] | None = None, fn: Callable[[T], bool] | None = None
) -> "List[T]":
self,
ty: Type[S] | None = None,
fn: Callable[[T | S], TypeGuard[S]] | None = None,
) -> "JacList[S]":
"""Filter comprehension."""
if ty and fn:
return List(
list(filter(lambda item: isinstance(item, ty) and fn(item), self))
)
return JacList([item for item in self if isinstance(item, ty) and fn(item)])
if ty:
return List(list(filter(lambda item: isinstance(item, ty), self)))
return JacList([item for item in self if isinstance(item, ty)])
if fn:
return List(list(filter(fn, self)))
return self
return JacList(list(filter(fn, self)))
return cast(JacList[S], self)

def assign(self, attrs: tuple[str], values: tuple[Any]) -> "List[T]":
def assign(self, attrs: tuple[str], values: tuple[Any]) -> "JacList[T]":
"""Assign Comprehension."""
return List(Jac.assign_compr(self, (attrs, values)))
return JacList(Jac.assign_compr(self, (attrs, values)))


# ----------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions jac/jaclang/compiler/passes/main/pyast_gen_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -2537,7 +2537,7 @@ def exit_list_val(self, node: ast.ListVal) -> None:
node.gen.py_ast = [
self.sync(
ast3.Call(
func=self.jaclib_obj("List"),
func=self.jaclib_obj("JacList"),
args=[
self.sync(
ast3.List(
Expand Down Expand Up @@ -2659,7 +2659,7 @@ def exit_list_compr(self, node: ast.ListCompr) -> None:
node.gen.py_ast = [
self.sync(
ast3.Call(
func=self.jaclib_obj("List"),
func=self.jaclib_obj("JacList"),
args=[
self.sync(
ast3.ListComp(
Expand Down
33 changes: 15 additions & 18 deletions jac/jaclang/compiler/passes/main/tests/test_type_check_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,20 @@ def test_data_spatial_type_info(self) -> None:
out,
r"129:24 - 129:28.*SpecialVarRef - Jac.get_root\(\) \- Type\: jaclang.runtimelib.architype.Root",
)
# (thakee) Jac.node_dot ???
#
# self.assertRegex(out, r"129:11 - 129:29.*FuncCall \- Type\: builtins\.str")
# self.assertRegex(
# out,
# r"129:15 - 129:23.*Name \- node_dot \- Type\: builtins.str, SymbolTable\: str",
# )

# (thakee) Root methods doesn't have type info, what to do?
#
# self.assertRegex(
# out,
# r"128:5 - 128:25.*BinaryExpr \- Type\: jaclang.runtimelib.architype.WalkerArchitype",
# )
# self.assertRegex(
# out,
# r"48:11 - 48:28.*EdgeRefTrailer \- Type\: builtins.list\[data_spatial_types.A\]",
# )

self.assertRegex(out, r"129:11 - 129:29.*FuncCall \- Type\: builtins\.str")
self.assertRegex(
out,
r"129:15 - 129:23.*Name \- node_dot \- Type\: builtins.str, SymbolTable\: str",
)

self.assertRegex(
out,
r"128:5 - 128:25.*BinaryExpr \- Type\: jaclang.Walker",
)
self.assertRegex(
out,
r"48:11 - 48:28.*EdgeRefTrailer \- Type\: jaclang.JacList\[data_spatial_types.A\]",
)

self.assertRegex(out, r"24:5 - 24:25.*BinaryExpr \- Type\: builtins.bool", out)
Loading

0 comments on commit 3aea9f3

Please sign in to comment.