jaclang 0.7.30__py3-none-any.whl → 0.7.31__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jaclang might be problematic. Click here for more details.

jaclang/__init__.py CHANGED
@@ -1,12 +1,428 @@
1
1
  """The Jac Programming Language."""
2
2
 
3
+ import inspect
4
+ import os
5
+ from abc import ABCMeta, abstractmethod as abstract
6
+ from dataclasses import dataclass, field as dc_field
7
+ from types import ModuleType
8
+ from typing import (
9
+ Any,
10
+ Callable,
11
+ ClassVar,
12
+ Dict,
13
+ Generic,
14
+ Tuple,
15
+ Type,
16
+ TypeGuard,
17
+ TypeVar,
18
+ cast,
19
+ override,
20
+ )
21
+
22
+ from jaclang.plugin.builtin import dotgen, jid, jobj # noqa: F401
3
23
  from jaclang.plugin.default import JacFeatureImpl
4
- from jaclang.plugin.feature import JacFeature, plugin_manager
24
+ from jaclang.plugin.feature import JacFeature as Jac, plugin_manager
25
+ from jaclang.plugin.spec import EdgeDir
26
+ from jaclang.runtimelib.context import ExecutionContext
27
+
28
+ __all__ = [
29
+ # Jac types.
30
+ "Obj",
31
+ "Walker",
32
+ "Node",
33
+ "Edge",
34
+ "JacList",
35
+ "EdgeDir",
36
+ "Root",
37
+ # Decorators.
38
+ "with_entry",
39
+ "with_exit",
40
+ "jac_test",
41
+ "abstract",
42
+ "override",
43
+ # Functions.
44
+ "jac_import",
45
+ "field",
46
+ # Builtin.
47
+ "Jac",
48
+ "root",
49
+ "static",
50
+ "dotgen",
51
+ "jid",
52
+ "jobj",
53
+ ]
5
54
 
6
- jac_import = JacFeature.jac_import
7
55
 
56
+ # ----------------------------------------------------------------------------
57
+ # Plugin Initialization.
58
+ # ----------------------------------------------------------------------------
8
59
 
9
60
  plugin_manager.register(JacFeatureImpl)
10
61
  plugin_manager.load_setuptools_entrypoints("jac")
11
62
 
12
- __all__ = ["jac_import"]
63
+ T = TypeVar("T")
64
+ S = TypeVar("S") # S is a subtype of T.
65
+
66
+ # ----------------------------------------------------------------------------
67
+ # Meta classes.
68
+ # ----------------------------------------------------------------------------
69
+
70
+
71
+ # Since the meta class of the architypes are changine the base class to it's
72
+ # suitable archi type, If a class doesn't have a parent class (ie. by default
73
+ # inherit from object) __bases__ will be immutable. So we need to use a dummy
74
+ # parent class to make it mutable.
75
+ #
76
+ # Reference: https://stackoverflow.com/a/9639512/10846399
77
+ #
78
+ class _ArchiTypeBase:
79
+
80
+ def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
81
+ """Initialize Jac architype base."""
82
+
83
+
84
+ class JacMeta(ABCMeta):
85
+ """Common metaclass for Jac types."""
86
+
87
+ def __new__( # noqa: D102
88
+ cls,
89
+ name: str,
90
+ bases: Tuple[Type, ...],
91
+ dct: Dict[str, Any],
92
+ ) -> "JacMeta":
93
+
94
+ # We have added this "__init__" to the jac base class just to make the type checkers happy.
95
+ # Actually the dataclass decorator will create an __init__ function and assign it here bellow.
96
+ if bases == (_ArchiTypeBase,) and "__init__" in dct:
97
+ del dct["__init__"]
98
+
99
+ on_entry, on_exit = [], []
100
+ for func in dct.values():
101
+ if hasattr(func, "__jac_entry"):
102
+ on_entry.append(Jac.DSFunc(func.__name__, func))
103
+ if hasattr(func, "__jac_exit"):
104
+ on_exit.append(Jac.DSFunc(func.__name__, func))
105
+
106
+ inst = super().__new__(cls, name, bases, dct)
107
+ inst = dataclass(eq=False)(inst) # type: ignore [arg-type, assignment]
108
+ inst = inst._MAKE_FN(on_entry, on_exit)(inst) # type: ignore [assignment, attr-defined]
109
+ return inst
110
+
111
+
112
+ # ----------------------------------------------------------------------------
113
+ # Base classes.
114
+ # ----------------------------------------------------------------------------
115
+
116
+
117
+ class Obj(_ArchiTypeBase, metaclass=JacMeta):
118
+ """Base class for all the jac object types."""
119
+
120
+ _MAKE_FN = Jac.make_obj
121
+
122
+
123
+ class Walker(_ArchiTypeBase, metaclass=JacMeta):
124
+ """Base class for all the jac walker types."""
125
+
126
+ _MAKE_FN = Jac.make_walker
127
+
128
+ def spawn(self, node: "Node | Root") -> "Walker":
129
+ """Spawn a new node from the walker."""
130
+ return Jac.spawn_call(self, node) # type: ignore [arg-type, return-value]
131
+
132
+ def ignore(
133
+ self,
134
+ expr: """(
135
+ Root
136
+ | Node
137
+ | Edge
138
+ | list[Node | Root | Edge]
139
+ | JacList[Node | Root | Edge]
140
+ )""",
141
+ ) -> bool:
142
+ """Ignore statement."""
143
+ return Jac.ignore(self, expr) # type: ignore [arg-type]
144
+
145
+ def visit(
146
+ self,
147
+ expr: """(
148
+ Root
149
+ | Node
150
+ | Edge
151
+ | list[Node | Root | Edge]
152
+ | JacList[Node | Root | Edge]
153
+ )""",
154
+ ) -> bool:
155
+ """Visit statement."""
156
+ return Jac.visit_node(self, expr) # type: ignore [arg-type]
157
+
158
+ def disengage(self) -> None:
159
+ """Disengage statement."""
160
+ Jac.disengage(self) # type: ignore [arg-type]
161
+
162
+
163
+ class Node(_ArchiTypeBase, metaclass=JacMeta):
164
+ """Base class for all the jac node types."""
165
+
166
+ _MAKE_FN = Jac.make_node
167
+
168
+ def spawn(self, archi: Walker) -> "Walker":
169
+ """Spawn a new node from the walker."""
170
+ return Jac.spawn_call(self, archi) # type: ignore [arg-type, return-value]
171
+
172
+ def connect(
173
+ self,
174
+ node: "Node | Root | JacList[Node | Root]",
175
+ edge: "type[Edge] | Edge | None" = None,
176
+ unidir: bool = False,
177
+ conn_assign: tuple[tuple, tuple] | None = None,
178
+ edges_only: bool = False,
179
+ ) -> "JacList[Node | Root| Edge]":
180
+ """Connect the current node to another node."""
181
+ # TODO: The above edge type should be reviewed, as the bellow can also take None, Edge, type[Edge].
182
+ ret = Jac.connect(
183
+ left=self, # type: ignore [arg-type]
184
+ right=node, # type: ignore [arg-type]
185
+ edge_spec=Jac.build_edge(
186
+ is_undirected=unidir, conn_type=edge, conn_assign=conn_assign # type: ignore [arg-type]
187
+ ),
188
+ edges_only=edges_only,
189
+ )
190
+ return JacList(ret) # type: ignore [arg-type]
191
+
192
+ def disconnect(
193
+ self,
194
+ node: "Node | Root | JacList[Node | Root]",
195
+ edge: "type[Edge] | None" = None,
196
+ dir: EdgeDir = EdgeDir.OUT,
197
+ ) -> bool:
198
+ """Disconnect the current node from the graph."""
199
+ filter_func = None
200
+ if edge:
201
+ filter_func = lambda edges: [ # noqa: E731
202
+ ed for ed in edges if isinstance(ed, edge)
203
+ ]
204
+ return Jac.disconnect(self, node, dir=dir, filter_func=filter_func) # type: ignore [arg-type]
205
+
206
+ def refs(
207
+ self,
208
+ edge: "type[Edge] | None" = None,
209
+ cond: "Callable[[Edge], bool] | None" = None,
210
+ target: "Node | Root | JacList[Node|Root] | None" = None,
211
+ dir: EdgeDir = EdgeDir.OUT,
212
+ edges_only: bool = False,
213
+ ) -> "JacList[Node | Root | Edge]":
214
+ """Return all the connected nodes / edges."""
215
+ filter_func = (
216
+ (
217
+ lambda edges: ( # noqa: E731
218
+ [ed for ed in edges if isinstance(ed, edge) if not cond or cond(ed)]
219
+ )
220
+ )
221
+ if edge
222
+ else None
223
+ )
224
+ ret = plugin_manager.hook.edge_ref(
225
+ node_obj=self,
226
+ target_obj=target,
227
+ dir=dir,
228
+ filter_func=filter_func,
229
+ edges_only=edges_only,
230
+ )
231
+ return JacList(ret)
232
+
233
+
234
+ class Root(_ArchiTypeBase, metaclass=JacMeta):
235
+ """Base class for jac root type."""
236
+
237
+ _MAKE_FN = Jac.make_root
238
+
239
+ def spawn(self, archi: Walker) -> "Walker":
240
+ """Spawn a new node from the walker."""
241
+ return Jac.spawn_call(self, archi) # type: ignore [arg-type, return-value]
242
+
243
+ def connect(
244
+ self,
245
+ node: "Node | Root | JacList[Node | Root]",
246
+ edge: "type[Edge] | Edge | None" = None,
247
+ unidir: bool = False,
248
+ conn_assign: tuple[tuple, tuple] | None = None,
249
+ edges_only: bool = False,
250
+ ) -> "JacList[Node | Root| Edge]":
251
+ """Connect the current node to another node."""
252
+ # TODO: The above edge type should be reviewed, as the bellow can also take None, Edge, type[Edge].
253
+ ret = Jac.connect(
254
+ left=self, # type: ignore [arg-type]
255
+ right=node, # type: ignore [arg-type]
256
+ edge_spec=Jac.build_edge(
257
+ is_undirected=unidir, conn_type=edge, conn_assign=conn_assign # type: ignore [arg-type]
258
+ ),
259
+ edges_only=edges_only,
260
+ )
261
+ return JacList(ret) # type: ignore [arg-type]
262
+
263
+ def disconnect(
264
+ self,
265
+ node: "Node | Root | JacList[Node | Root]",
266
+ edge: "type[Edge] | None" = None,
267
+ dir: EdgeDir = EdgeDir.OUT,
268
+ ) -> bool:
269
+ """Disconnect the current node from the graph."""
270
+ filter_func = None
271
+ if edge:
272
+ filter_func = lambda edges: [ # noqa: E731
273
+ ed for ed in edges if isinstance(ed, edge)
274
+ ]
275
+ return Jac.disconnect(self, node, dir=dir, filter_func=filter_func) # type: ignore [arg-type]
276
+
277
+ def refs(
278
+ self,
279
+ edge: "type[Edge] | None" = None,
280
+ cond: "Callable[[Edge], bool] | None" = None,
281
+ target: "Node | Root | JacList[Node|Root] | None" = None,
282
+ dir: EdgeDir = EdgeDir.OUT,
283
+ edges_only: bool = False,
284
+ ) -> "JacList[Node | Root | Edge]":
285
+ """Return all the connected nodes / edges."""
286
+ filter_func = (
287
+ (
288
+ lambda edges: ( # noqa: E731
289
+ [ed for ed in edges if isinstance(ed, edge) if not cond or cond(ed)]
290
+ )
291
+ )
292
+ if edge
293
+ else None
294
+ )
295
+ ret = plugin_manager.hook.edge_ref(
296
+ node_obj=self,
297
+ target_obj=target,
298
+ dir=dir,
299
+ filter_func=filter_func,
300
+ edges_only=edges_only,
301
+ )
302
+ return JacList(ret)
303
+
304
+
305
+ class Edge(_ArchiTypeBase, metaclass=JacMeta):
306
+ """Base class for all the jac edge types."""
307
+
308
+ _MAKE_FN = Jac.make_edge
309
+
310
+ def spawn(self, archi: Walker) -> "Walker":
311
+ """Spawn a new node from the walker."""
312
+ return Jac.spawn_call(self, archi) # type: ignore [arg-type, return-value]
313
+
314
+
315
+ class GenericEdge(_ArchiTypeBase, metaclass=JacMeta):
316
+ """Base class for jac root type."""
317
+
318
+ _MAKE_FN = Jac.make_generic_edge
319
+
320
+ def spawn(self, archi: Walker) -> "Walker":
321
+ """Spawn a new node from the walker."""
322
+ return Jac.spawn_call(self, archi) # type: ignore [arg-type, return-value]
323
+
324
+
325
+ class JacList(Generic[T], list[T]):
326
+ """List with jac methods."""
327
+
328
+ # Reuse the methods.
329
+ connect = Node.connect
330
+ disconnect = Node.disconnect
331
+ refs = Node.refs
332
+
333
+ def filter(
334
+ self,
335
+ ty: Type[S] | None = None,
336
+ fn: Callable[[T | S], TypeGuard[S]] | None = None,
337
+ ) -> "JacList[S]":
338
+ """Filter comprehension."""
339
+ if ty and fn:
340
+ return JacList([item for item in self if isinstance(item, ty) and fn(item)])
341
+ if ty:
342
+ return JacList([item for item in self if isinstance(item, ty)])
343
+ if fn:
344
+ return JacList(list(filter(fn, self)))
345
+ return cast(JacList[S], self)
346
+
347
+ def assign(self, attrs: tuple[str], values: tuple[Any]) -> "JacList[T]":
348
+ """Assign Comprehension."""
349
+ return JacList(Jac.assign_compr(self, (attrs, values)))
350
+
351
+
352
+ # ----------------------------------------------------------------------------
353
+ # Decorators.
354
+ # ----------------------------------------------------------------------------
355
+
356
+
357
+ def with_entry(func: Callable) -> Callable:
358
+ """Mark a method as jac entry with this decorator."""
359
+ setattr(func, "__jac_entry", True) # noqa: B010
360
+ return func
361
+
362
+
363
+ def with_exit(func: Callable) -> Callable:
364
+ """Mark a method as jac exit with this decorator."""
365
+ setattr(func, "__jac_exit", True) # noqa: B010
366
+ return func
367
+
368
+
369
+ # ----------------------------------------------------------------------------
370
+ # Functions.
371
+ # ----------------------------------------------------------------------------
372
+
373
+
374
+ def jac_import(
375
+ target: str,
376
+ lng: str | None = "jac",
377
+ base_path: str | None = None,
378
+ absorb: bool = False,
379
+ cachable: bool = True,
380
+ alias: str | None = None,
381
+ override_name: str | None = None,
382
+ items: dict[str, str | None] | None = None,
383
+ reload_module: bool | None = False,
384
+ ) -> tuple[ModuleType, ...]:
385
+ """Import a module."""
386
+ base_path = base_path or os.path.dirname(inspect.stack()[1].filename)
387
+ return Jac.jac_import(
388
+ target=target,
389
+ lng=lng,
390
+ base_path=base_path,
391
+ absorb=absorb,
392
+ cachable=cachable,
393
+ mdl_alias=alias,
394
+ override_name=override_name,
395
+ items=items,
396
+ reload_module=reload_module,
397
+ )
398
+
399
+
400
+ def field(
401
+ value: T = None, # type: ignore [assignment]
402
+ gen: Callable[[], T] | None = None,
403
+ postinit: bool = False,
404
+ ) -> T:
405
+ """Set the default value to jac architype dataclass."""
406
+ if postinit:
407
+ return dc_field(init=False)
408
+ gen = gen or (lambda: value) # noqa: E731
409
+ return Jac.has_instance_default(gen_func=gen) # type: ignore
410
+
411
+
412
+ # ----------------------------------------------------------------------------
413
+ # Builtin.
414
+ # ----------------------------------------------------------------------------
415
+
416
+ jac_test = Jac.create_test
417
+ static = ClassVar
418
+
419
+ root = cast(Root, Jac.get_root())
420
+
421
+
422
+ # Listen to context change and update the above global root here.
423
+ def _update_root() -> None:
424
+ global root
425
+ root = cast(Root, ExecutionContext.get_root())
426
+
427
+
428
+ ExecutionContext.on_ctx_change.append(lambda ctx: _update_root())
@@ -462,7 +462,7 @@ class NameAtom(AtomExpr, EnumBlockStmt):
462
462
  self._sym: Optional[Symbol] = None
463
463
  self._sym_name: str = ""
464
464
  self._sym_category: SymbolType = SymbolType.UNKNOWN
465
- self._py_ctx_func: Type[ast3.AST] = ast3.Load
465
+ self._py_ctx_func: Type[ast3.expr_context] = ast3.Load
466
466
  AtomExpr.__init__(self)
467
467
 
468
468
  @property
@@ -492,12 +492,12 @@ class NameAtom(AtomExpr, EnumBlockStmt):
492
492
  return ret_type
493
493
 
494
494
  @property
495
- def py_ctx_func(self) -> Type[ast3.AST]:
495
+ def py_ctx_func(self) -> Type[ast3.expr_context]:
496
496
  """Get python context function."""
497
497
  return self._py_ctx_func
498
498
 
499
499
  @py_ctx_func.setter
500
- def py_ctx_func(self, py_ctx_func: Type[ast3.AST]) -> None:
500
+ def py_ctx_func(self, py_ctx_func: Type[ast3.expr_context]) -> None:
501
501
  """Set python context function."""
502
502
  self._py_ctx_func = py_ctx_func
503
503
 
@@ -91,8 +91,9 @@ class Constants(StrEnum):
91
91
  """Token constants for Jac."""
92
92
 
93
93
  JAC_LANG_IMP = "jac"
94
- HERE = "_jac_here_"
95
- JAC_FEATURE = "_Jac"
94
+ HERE = "here" # "_jac_here_"
95
+ JAC_CHECK = "_check"
96
+ JAC_FEATURE = "Jac" # "_Jac"
96
97
  ROOT = f"{JAC_FEATURE}.get_root()"
97
98
  EDGES_TO_NODE = "__jac__.edges_to_nodes"
98
99
  EDGE_REF = "__jac__.edge_ref"
@@ -152,7 +153,6 @@ class Tokens(str, Enum):
152
153
 
153
154
  FLOAT = "FLOAT"
154
155
  STRING = "STRING"
155
- DOC_STRING = "DOC_STRING"
156
156
  PYNLINE = "PYNLINE"
157
157
  BOOL = "BOOL"
158
158
  INT = "INT"
@@ -355,7 +355,7 @@ colors = [
355
355
  "#F0FFF0",
356
356
  "#F5E5FF",
357
357
  "#FFFFE0",
358
- "#D2FEFF ",
358
+ "#D2FEFF",
359
359
  "#E8FFD7",
360
360
  "#FFDEAD",
361
361
  "#FFF0F5",