jaclang 0.7.1__py3-none-any.whl → 0.7.7__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.

Files changed (106) hide show
  1. jaclang/cli/cli.py +2 -2
  2. jaclang/compiler/absyntree.py +539 -297
  3. jaclang/compiler/codeloc.py +2 -2
  4. jaclang/compiler/constant.py +100 -2
  5. jaclang/compiler/jac.lark +27 -19
  6. jaclang/compiler/parser.py +119 -92
  7. jaclang/compiler/passes/main/access_modifier_pass.py +20 -12
  8. jaclang/compiler/passes/main/def_impl_match_pass.py +32 -12
  9. jaclang/compiler/passes/main/def_use_pass.py +59 -40
  10. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +71 -30
  11. jaclang/compiler/passes/main/import_pass.py +12 -7
  12. jaclang/compiler/passes/main/pyast_gen_pass.py +110 -47
  13. jaclang/compiler/passes/main/pyast_load_pass.py +49 -13
  14. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +25 -11
  15. jaclang/compiler/passes/main/pyout_pass.py +3 -1
  16. jaclang/compiler/passes/main/registry_pass.py +6 -6
  17. jaclang/compiler/passes/main/sub_node_tab_pass.py +0 -5
  18. jaclang/compiler/passes/main/sym_tab_build_pass.py +43 -235
  19. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +21 -4
  20. jaclang/compiler/passes/main/tests/test_def_use_pass.py +5 -10
  21. jaclang/compiler/passes/main/tests/test_import_pass.py +8 -0
  22. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  23. jaclang/compiler/passes/main/type_check_pass.py +2 -1
  24. jaclang/compiler/passes/tool/jac_formatter_pass.py +44 -11
  25. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +16 -0
  26. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +16 -0
  27. jaclang/compiler/passes/tool/tests/fixtures/doc_string.jac +15 -0
  28. jaclang/compiler/passes/tool/tests/fixtures/genai/essay_review.jac +1 -1
  29. jaclang/compiler/passes/tool/tests/fixtures/genai/expert_answer.jac +1 -1
  30. jaclang/compiler/passes/tool/tests/fixtures/genai/joke_gen.jac +1 -1
  31. jaclang/compiler/passes/tool/tests/fixtures/genai/odd_word_out.jac +1 -1
  32. jaclang/compiler/passes/tool/tests/fixtures/genai/personality_finder.jac +1 -1
  33. jaclang/compiler/passes/tool/tests/fixtures/genai/text_to_type.jac +1 -1
  34. jaclang/compiler/passes/tool/tests/fixtures/genai/translator.jac +1 -1
  35. jaclang/compiler/passes/tool/tests/fixtures/genai/wikipedia.jac +1 -1
  36. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +7 -5
  37. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
  38. jaclang/compiler/passes/transform.py +2 -4
  39. jaclang/{core/registry.py → compiler/semtable.py} +1 -3
  40. jaclang/compiler/symtable.py +150 -89
  41. jaclang/compiler/tests/test_parser.py +2 -2
  42. jaclang/core/aott.py +118 -18
  43. jaclang/core/{construct.py → architype.py} +44 -93
  44. jaclang/core/constructs.py +44 -0
  45. jaclang/core/context.py +157 -0
  46. jaclang/core/importer.py +18 -9
  47. jaclang/core/memory.py +53 -2
  48. jaclang/core/test.py +90 -0
  49. jaclang/core/utils.py +2 -2
  50. jaclang/langserve/engine.py +199 -138
  51. jaclang/langserve/server.py +48 -53
  52. jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -0
  53. jaclang/langserve/tests/fixtures/circle.jac +16 -12
  54. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  55. jaclang/langserve/tests/fixtures/circle_pure.impl.jac +8 -4
  56. jaclang/langserve/tests/fixtures/circle_pure.jac +2 -2
  57. jaclang/langserve/tests/fixtures/circle_pure.test.jac +15 -0
  58. jaclang/langserve/tests/fixtures/import_include_statements.jac +6 -0
  59. jaclang/langserve/tests/fixtures/py_import.py +26 -0
  60. jaclang/langserve/tests/test_server.py +200 -2
  61. jaclang/langserve/utils.py +214 -10
  62. jaclang/plugin/builtin.py +1 -1
  63. jaclang/plugin/default.py +48 -92
  64. jaclang/plugin/feature.py +33 -17
  65. jaclang/plugin/spec.py +18 -20
  66. jaclang/plugin/tests/test_features.py +0 -33
  67. jaclang/settings.py +4 -0
  68. jaclang/tests/fixtures/abc.jac +16 -12
  69. jaclang/tests/fixtures/aott_raise.jac +1 -1
  70. jaclang/tests/fixtures/byllmissue.jac +12 -0
  71. jaclang/tests/fixtures/edgetypeissue.jac +10 -0
  72. jaclang/tests/fixtures/hash_init_check.jac +17 -0
  73. jaclang/tests/fixtures/hello.jac +1 -1
  74. jaclang/tests/fixtures/impl_match_confused.impl.jac +1 -0
  75. jaclang/tests/fixtures/impl_match_confused.jac +5 -0
  76. jaclang/tests/fixtures/math_question.jpg +0 -0
  77. jaclang/tests/fixtures/maxfail_run_test.jac +17 -5
  78. jaclang/tests/fixtures/nosigself.jac +19 -0
  79. jaclang/tests/fixtures/run_test.jac +17 -5
  80. jaclang/tests/fixtures/walker_override.jac +21 -0
  81. jaclang/tests/fixtures/with_llm_function.jac +1 -1
  82. jaclang/tests/fixtures/with_llm_lower.jac +1 -1
  83. jaclang/tests/fixtures/with_llm_method.jac +1 -1
  84. jaclang/tests/fixtures/with_llm_type.jac +1 -1
  85. jaclang/tests/fixtures/with_llm_vision.jac +25 -0
  86. jaclang/tests/test_bugs.py +19 -0
  87. jaclang/tests/test_cli.py +1 -1
  88. jaclang/tests/test_language.py +197 -82
  89. jaclang/tests/test_reference.py +1 -1
  90. jaclang/utils/lang_tools.py +5 -4
  91. jaclang/utils/test.py +2 -1
  92. jaclang/utils/treeprinter.py +35 -4
  93. {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/METADATA +3 -2
  94. {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/RECORD +96 -88
  95. jaclang/core/llms/__init__.py +0 -20
  96. jaclang/core/llms/anthropic.py +0 -61
  97. jaclang/core/llms/base.py +0 -206
  98. jaclang/core/llms/groq.py +0 -67
  99. jaclang/core/llms/huggingface.py +0 -73
  100. jaclang/core/llms/ollama.py +0 -78
  101. jaclang/core/llms/openai.py +0 -61
  102. jaclang/core/llms/togetherai.py +0 -60
  103. jaclang/core/llms/utils.py +0 -9
  104. jaclang/core/shelve_storage.py +0 -55
  105. {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/WHEEL +0 -0
  106. {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/entry_points.txt +0 -0
@@ -1,12 +1,19 @@
1
1
  """Utility functions for the language server."""
2
2
 
3
3
  import asyncio
4
+ import builtins
5
+ import importlib.util
6
+ import os
7
+ import sys
4
8
  from functools import wraps
5
9
  from typing import Any, Awaitable, Callable, Coroutine, Optional, ParamSpec, TypeVar
6
10
 
7
11
  import jaclang.compiler.absyntree as ast
8
- from jaclang.compiler.symtable import SymbolTable
12
+ from jaclang.compiler.codeloc import CodeLocInfo
13
+ from jaclang.compiler.symtable import Symbol, SymbolTable
14
+ from jaclang.utils.helpers import import_target_to_relative_path
9
15
 
16
+ import lsprotocol.types as lspt
10
17
 
11
18
  T = TypeVar("T", bound=Callable[..., Coroutine[Any, Any, Any]])
12
19
  P = ParamSpec("P")
@@ -55,17 +62,23 @@ def sym_tab_list(sym_tab: SymbolTable, file_path: str) -> list[SymbolTable]:
55
62
  return sym_tabs
56
63
 
57
64
 
58
- def find_deepest_node_at_pos(
65
+ def find_deepest_symbol_node_at_pos(
59
66
  node: ast.AstNode, line: int, character: int
60
- ) -> Optional[ast.AstNode]:
61
- """Return the deepest node that contains the given position."""
67
+ ) -> Optional[ast.AstSymbolNode]:
68
+ """Return the deepest symbol node that contains the given position."""
69
+ last_symbol_node = None
70
+
62
71
  if position_within_node(node, line, character):
63
- for i in node.kid:
64
- if position_within_node(i, line, character):
65
- return find_deepest_node_at_pos(i, line, character)
66
- return node
67
- else:
68
- return None
72
+ if isinstance(node, ast.AstSymbolNode):
73
+ last_symbol_node = node
74
+
75
+ for child in [i for i in node.kid if i.loc.mod_path == node.loc.mod_path]:
76
+ if position_within_node(child, line, character):
77
+ deeper_node = find_deepest_symbol_node_at_pos(child, line, character)
78
+ if deeper_node is not None:
79
+ last_symbol_node = deeper_node
80
+
81
+ return last_symbol_node
69
82
 
70
83
 
71
84
  def position_within_node(node: ast.AstNode, line: int, character: int) -> bool:
@@ -88,3 +101,194 @@ def position_within_node(node: ast.AstNode, line: int, character: int) -> bool:
88
101
  ):
89
102
  return True
90
103
  return False
104
+
105
+
106
+ def collect_symbols(node: SymbolTable) -> list[lspt.DocumentSymbol]:
107
+ """Recursively collect symbols from the AST."""
108
+ symbols = []
109
+ if node is None:
110
+ return symbols
111
+
112
+ for key, item in node.tab.items():
113
+ if (
114
+ key in dir(builtins)
115
+ or item in [owner_sym(tab) for tab in node.kid]
116
+ or item.decl.loc.mod_path != node.owner.loc.mod_path
117
+ ):
118
+ continue
119
+ else:
120
+
121
+ pos = create_range(item.decl.loc)
122
+ symbol = lspt.DocumentSymbol(
123
+ name=key,
124
+ kind=kind_map(item.decl),
125
+ range=pos,
126
+ selection_range=pos,
127
+ children=[],
128
+ )
129
+ symbols.append(symbol)
130
+
131
+ for sub_tab in [
132
+ i for i in node.kid if i.owner.loc.mod_path == node.owner.loc.mod_path
133
+ ]:
134
+ sub_symbols = collect_symbols(sub_tab)
135
+
136
+ if isinstance(
137
+ sub_tab.owner,
138
+ (ast.IfStmt, ast.ElseStmt, ast.WhileStmt, ast.IterForStmt, ast.InForStmt),
139
+ ):
140
+ symbols.extend(sub_symbols)
141
+ else:
142
+ sub_pos = create_range(sub_tab.owner.loc)
143
+ symbol = lspt.DocumentSymbol(
144
+ name=sub_tab.name,
145
+ kind=kind_map(sub_tab.owner),
146
+ range=sub_pos,
147
+ selection_range=sub_pos,
148
+ children=sub_symbols,
149
+ )
150
+ symbols.append(symbol)
151
+
152
+ return symbols
153
+
154
+
155
+ def owner_sym(table: SymbolTable) -> Optional[Symbol]:
156
+ """Get owner sym."""
157
+ if table.parent and isinstance(table.owner, ast.AstSymbolNode):
158
+ return table.parent.lookup(table.owner.sym_name)
159
+ return None
160
+
161
+
162
+ def create_range(loc: CodeLocInfo) -> lspt.Range:
163
+ """Create an lspt.Range from a location object."""
164
+ return lspt.Range(
165
+ start=lspt.Position(
166
+ line=loc.first_line - 1 if loc.first_line > 0 else 0,
167
+ character=loc.col_start - 1 if loc.col_start > 0 else 0,
168
+ ),
169
+ end=lspt.Position(
170
+ line=loc.last_line - 1 if loc.last_line > 0 else 0,
171
+ character=loc.col_end - 1 if loc.col_end > 0 else 0,
172
+ ),
173
+ )
174
+
175
+
176
+ def kind_map(sub_tab: ast.AstNode) -> lspt.SymbolKind:
177
+ """Map the symbol node to an lspt.SymbolKind."""
178
+ return (
179
+ lspt.SymbolKind.Function
180
+ if isinstance(sub_tab, (ast.Ability, ast.AbilityDef))
181
+ else (
182
+ lspt.SymbolKind.Class
183
+ if isinstance(sub_tab, (ast.Architype, ast.ArchDef))
184
+ else (
185
+ lspt.SymbolKind.Module
186
+ if isinstance(sub_tab, ast.Module)
187
+ else (
188
+ lspt.SymbolKind.Enum
189
+ if isinstance(sub_tab, (ast.Enum, ast.EnumDef))
190
+ else lspt.SymbolKind.Variable
191
+ )
192
+ )
193
+ )
194
+ )
195
+
196
+
197
+ def get_mod_path(mod_path: ast.ModulePath, name_node: ast.Name) -> str | None:
198
+ """Get path for a module import name."""
199
+ ret_target = None
200
+ module_location_path = mod_path.loc.mod_path
201
+ if mod_path.parent and (
202
+ (
203
+ isinstance(mod_path.parent.parent, ast.Import)
204
+ and mod_path.parent.parent.hint.tag.value == "py"
205
+ )
206
+ or (
207
+ isinstance(mod_path.parent, ast.Import)
208
+ and mod_path.parent.from_loc
209
+ and mod_path.parent.hint.tag.value == "py"
210
+ )
211
+ ):
212
+ if mod_path.path and name_node in mod_path.path:
213
+ temporary_path_str = ("." * mod_path.level) + ".".join(
214
+ [p.value for p in mod_path.path[: mod_path.path.index(name_node) + 1]]
215
+ if mod_path.path
216
+ else ""
217
+ )
218
+ else:
219
+ temporary_path_str = mod_path.path_str
220
+ sys.path.append(os.path.dirname(module_location_path))
221
+ spec = importlib.util.find_spec(temporary_path_str)
222
+ sys.path.remove(os.path.dirname(module_location_path))
223
+ if spec and spec.origin and spec.origin.endswith(".py"):
224
+ ret_target = spec.origin
225
+ elif mod_path.parent and (
226
+ (
227
+ isinstance(mod_path.parent.parent, ast.Import)
228
+ and mod_path.parent.parent.hint.tag.value == "jac"
229
+ )
230
+ or (
231
+ isinstance(mod_path.parent, ast.Import)
232
+ and mod_path.parent.from_loc
233
+ and mod_path.parent.hint.tag.value == "jac"
234
+ )
235
+ ):
236
+ ret_target = import_target_to_relative_path(
237
+ level=mod_path.level,
238
+ target=mod_path.path_str,
239
+ base_path=os.path.dirname(module_location_path),
240
+ )
241
+ return ret_target
242
+
243
+
244
+ def get_item_path(mod_item: ast.ModuleItem) -> tuple[str, tuple[int, int]] | None:
245
+ """Get path."""
246
+ item_name = mod_item.name.value
247
+ if mod_item.from_parent.hint.tag.value == "py" and mod_item.from_parent.from_loc:
248
+ path = get_mod_path(mod_item.from_parent.from_loc, mod_item.name)
249
+ if path:
250
+ return get_definition_range(path, item_name)
251
+ elif mod_item.from_parent.hint.tag.value == "jac":
252
+ mod_node = mod_item.from_mod_path
253
+ if mod_node.sub_module and mod_node.sub_module._sym_tab:
254
+ for symbol_name, symbol in mod_node.sub_module._sym_tab.tab.items():
255
+ if symbol_name == item_name:
256
+ return symbol.decl.loc.mod_path, (
257
+ symbol.decl.loc.first_line - 1,
258
+ symbol.decl.loc.last_line - 1,
259
+ )
260
+ return None
261
+
262
+
263
+ def get_definition_range(
264
+ filename: str, name: str
265
+ ) -> tuple[str, tuple[int, int]] | None:
266
+ """Get the start and end line of a function or class definition in a file."""
267
+ import ast
268
+
269
+ with open(filename, "r") as file:
270
+ source = file.read()
271
+
272
+ tree = ast.parse(source)
273
+
274
+ for node in ast.walk(tree):
275
+ if isinstance(node, (ast.FunctionDef, ast.ClassDef)) and node.name == name:
276
+ start_line = node.lineno
277
+ end_line = (
278
+ node.body[-1].end_lineno
279
+ if hasattr(node.body[-1], "end_lineno")
280
+ else node.body[-1].lineno
281
+ )
282
+ if start_line and end_line:
283
+ return filename, (start_line - 1, end_line - 1)
284
+ elif isinstance(node, ast.Assign):
285
+ for target in node.targets:
286
+ if isinstance(target, ast.Name) and target.id == name:
287
+ start_line = node.lineno
288
+ end_line = (
289
+ node.end_lineno if hasattr(node, "end_lineno") else node.lineno
290
+ )
291
+ if start_line and end_line:
292
+ return filename, (start_line - 1, end_line - 1)
293
+
294
+ return None
jaclang/plugin/builtin.py CHANGED
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from typing import Optional
9
- from jaclang.core.construct import NodeArchitype
9
+ from jaclang.core.constructs import NodeArchitype
10
10
 
11
11
 
12
12
  def dotgen(
jaclang/plugin/default.py CHANGED
@@ -7,40 +7,39 @@ import html
7
7
  import os
8
8
  import pickle
9
9
  import types
10
- from contextvars import ContextVar
10
+ from collections import OrderedDict
11
11
  from dataclasses import field
12
12
  from functools import wraps
13
13
  from typing import Any, Callable, Optional, Type, Union
14
- from uuid import UUID
15
14
 
16
15
  from jaclang.compiler.absyntree import Module
17
16
  from jaclang.compiler.constant import EdgeDir, colors
17
+ from jaclang.compiler.semtable import SemInfo, SemRegistry, SemScope
18
18
  from jaclang.core.aott import (
19
19
  aott_raise,
20
20
  extract_non_primary_type,
21
21
  get_all_type_explanations,
22
22
  get_info_types,
23
- get_object_string,
24
- get_type_annotation,
23
+ get_input_information,
25
24
  )
26
- from jaclang.core.construct import (
25
+ from jaclang.core.constructs import (
27
26
  Architype,
28
27
  DSFunc,
29
28
  EdgeAnchor,
30
29
  EdgeArchitype,
30
+ ExecutionContext,
31
31
  GenericEdge,
32
32
  JacTestCheck,
33
+ Memory,
33
34
  NodeAnchor,
34
35
  NodeArchitype,
35
36
  ObjectAnchor,
36
37
  Root,
37
38
  WalkerAnchor,
38
39
  WalkerArchitype,
40
+ exec_context,
39
41
  )
40
42
  from jaclang.core.importer import jac_importer
41
- from jaclang.core.memory import Memory
42
- from jaclang.core.registry import SemInfo, SemRegistry, SemScope
43
- from jaclang.core.shelve_storage import ShelveStorage
44
43
  from jaclang.core.utils import traverse_graph
45
44
  from jaclang.plugin.feature import JacFeature as Jac
46
45
  from jaclang.plugin.spec import T
@@ -70,65 +69,6 @@ __all__ = [
70
69
  hookimpl = pluggy.HookimplMarker("jac")
71
70
 
72
71
 
73
- class ExecutionContext:
74
- """Default Execution Context implementation."""
75
-
76
- mem: Optional[Memory]
77
- root: Optional[Root]
78
-
79
- def __init__(self) -> None:
80
- super().__init__()
81
- self.mem = ShelveStorage()
82
- self.root = None
83
-
84
- def init_memory(self, session: str = "") -> None:
85
- if session:
86
- self.mem = ShelveStorage(session)
87
- else:
88
- self.mem = Memory()
89
-
90
- def get_root(self) -> Root:
91
- if self.mem is None:
92
- raise ValueError("Memory not initialized")
93
-
94
- if not self.root:
95
- root = self.mem.get_obj(UUID(int=0))
96
- if root is None:
97
- self.root = Root()
98
- self.mem.save_obj(self.root, persistent=self.root._jac_.persistent)
99
- elif not isinstance(root, Root):
100
- raise ValueError(f"Invalid root object: {root}")
101
- else:
102
- self.root = root
103
- return self.root
104
-
105
- def get_obj(self, obj_id: UUID) -> Architype | None:
106
- """Get object from memory."""
107
- if self.mem is None:
108
- raise ValueError("Memory not initialized")
109
-
110
- return self.mem.get_obj(obj_id)
111
-
112
- def save_obj(self, item: Architype, persistent: bool) -> None:
113
- """Save object to memory."""
114
- if self.mem is None:
115
- raise ValueError("Memory not initialized")
116
-
117
- self.mem.save_obj(item, persistent)
118
-
119
- def reset(self) -> None:
120
- """Reset the execution context."""
121
- if self.mem:
122
- self.mem.close()
123
- self.mem = None
124
- self.root = None
125
-
126
-
127
- ExecContext: ContextVar[ExecutionContext | None] = ContextVar(
128
- "ExecutionContext", default=None
129
- )
130
-
131
-
132
72
  class JacFeatureDefaults:
133
73
  """Jac Feature."""
134
74
 
@@ -138,20 +78,20 @@ class JacFeatureDefaults:
138
78
  @hookimpl
139
79
  def context(session: str = "") -> ExecutionContext:
140
80
  """Get the execution context."""
141
- ctx = ExecContext.get()
81
+ ctx = exec_context.get()
142
82
  if ctx is None:
143
83
  ctx = ExecutionContext()
144
- ExecContext.set(ctx)
84
+ exec_context.set(ctx)
145
85
  return ctx
146
86
 
147
87
  @staticmethod
148
88
  @hookimpl
149
89
  def reset_context() -> None:
150
90
  """Reset the execution context."""
151
- ctx = ExecContext.get()
91
+ ctx = exec_context.get()
152
92
  if ctx:
153
93
  ctx.reset()
154
- ExecContext.set(None)
94
+ exec_context.set(None)
155
95
 
156
96
  @staticmethod
157
97
  @hookimpl
@@ -170,7 +110,9 @@ class JacFeatureDefaults:
170
110
  """Create a new architype."""
171
111
  for i in on_entry + on_exit:
172
112
  i.resolve(cls)
173
- if not issubclass(cls, arch_base):
113
+ if not hasattr(cls, "_jac_entry_funcs_") or not hasattr(
114
+ cls, "_jac_exit_funcs_"
115
+ ):
174
116
  # Saving the module path and reassign it after creating cls
175
117
  # So the jac modules are part of the correct module
176
118
  cur_module = cls.__module__
@@ -179,12 +121,20 @@ class JacFeatureDefaults:
179
121
  cls._jac_entry_funcs_ = on_entry # type: ignore
180
122
  cls._jac_exit_funcs_ = on_exit # type: ignore
181
123
  else:
182
- cls._jac_entry_funcs_ = cls._jac_entry_funcs_ + [
183
- x for x in on_entry if x not in cls._jac_entry_funcs_
184
- ]
185
- cls._jac_exit_funcs_ = cls._jac_exit_funcs_ + [
186
- x for x in on_exit if x not in cls._jac_exit_funcs_
187
- ]
124
+ new_entry_funcs = OrderedDict(zip([i.name for i in on_entry], on_entry))
125
+ entry_funcs = OrderedDict(
126
+ zip([i.name for i in cls._jac_entry_funcs_], cls._jac_entry_funcs_)
127
+ )
128
+ entry_funcs.update(new_entry_funcs)
129
+ cls._jac_entry_funcs_ = list(entry_funcs.values())
130
+
131
+ new_exit_funcs = OrderedDict(zip([i.name for i in on_exit], on_exit))
132
+ exit_funcs = OrderedDict(
133
+ zip([i.name for i in cls._jac_exit_funcs_], cls._jac_exit_funcs_)
134
+ )
135
+ exit_funcs.update(new_exit_funcs)
136
+ cls._jac_exit_funcs_ = list(exit_funcs.values())
137
+
188
138
  inner_init = cls.__init__ # type: ignore
189
139
 
190
140
  @wraps(inner_init)
@@ -268,7 +218,7 @@ class JacFeatureDefaults:
268
218
  cachable: bool,
269
219
  mdl_alias: Optional[str],
270
220
  override_name: Optional[str],
271
- mod_bundle: Optional[Module],
221
+ mod_bundle: Optional[Module | str],
272
222
  lng: Optional[str],
273
223
  items: Optional[dict[str, Union[str, bool]]],
274
224
  ) -> Optional[types.ModuleType]:
@@ -387,7 +337,13 @@ class JacFeatureDefaults:
387
337
  @hookimpl
388
338
  def ignore(
389
339
  walker: WalkerArchitype,
390
- expr: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
340
+ expr: (
341
+ list[NodeArchitype | EdgeArchitype]
342
+ | list[NodeArchitype]
343
+ | list[EdgeArchitype]
344
+ | NodeArchitype
345
+ | EdgeArchitype
346
+ ),
391
347
  ) -> bool:
392
348
  """Jac's ignore stmt feature."""
393
349
  return walker._jac_.ignore_node(expr)
@@ -396,7 +352,13 @@ class JacFeatureDefaults:
396
352
  @hookimpl
397
353
  def visit_node(
398
354
  walker: WalkerArchitype,
399
- expr: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
355
+ expr: (
356
+ list[NodeArchitype | EdgeArchitype]
357
+ | list[NodeArchitype]
358
+ | list[EdgeArchitype]
359
+ | NodeArchitype
360
+ | EdgeArchitype
361
+ ),
400
362
  ) -> bool:
401
363
  """Jac's visit stmt feature."""
402
364
  if isinstance(walker, WalkerArchitype):
@@ -533,14 +495,14 @@ class JacFeatureDefaults:
533
495
  @hookimpl
534
496
  def build_edge(
535
497
  is_undirected: bool,
536
- conn_type: Optional[Type[EdgeArchitype]],
498
+ conn_type: Optional[Type[EdgeArchitype] | EdgeArchitype],
537
499
  conn_assign: Optional[tuple[tuple, tuple]],
538
500
  ) -> Callable[[], EdgeArchitype]:
539
501
  """Jac's root getter."""
540
502
  conn_type = conn_type if conn_type else GenericEdge
541
503
 
542
504
  def builder() -> EdgeArchitype:
543
- edge = conn_type()
505
+ edge = conn_type() if isinstance(conn_type, type) else conn_type
544
506
  edge._jac_.is_undirected = is_undirected
545
507
  if conn_assign:
546
508
  for fld, val in zip(conn_assign[0], conn_assign[1]):
@@ -698,16 +660,10 @@ class JacFeatureDefaults:
698
660
  incl_info = [x for x in incl_info if not isinstance(x[1], type)]
699
661
  information, collected_types = get_info_types(_scope, mod_registry, incl_info)
700
662
  type_collector.extend(collected_types)
701
- inputs_information_list = []
702
- for i in inputs:
703
- typ_anno = get_type_annotation(i[3])
704
- type_collector.extend(extract_non_primary_type(typ_anno))
705
- inputs_information_list.append(
706
- f"{i[0]} ({i[2]}) ({typ_anno}) = {get_object_string(i[3])}"
707
- )
708
- inputs_information = "\n".join(inputs_information_list)
709
663
 
710
- output_information = f"{outputs[0]} ({outputs[1]})"
664
+ inputs_information = get_input_information(inputs, type_collector)
665
+
666
+ output_information = f"{outputs[0]} ({outputs[1]})".strip()
711
667
  type_collector.extend(extract_non_primary_type(outputs[1]))
712
668
  output_type_explanations = "\n".join(
713
669
  list(
jaclang/plugin/feature.py CHANGED
@@ -3,22 +3,20 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import types
6
- from typing import Any, Callable, Optional, TYPE_CHECKING, Type, Union
6
+ from typing import Any, Callable, Optional, Type, TypeAlias, Union
7
7
 
8
8
  from jaclang.compiler.absyntree import Module
9
+ from jaclang.core.constructs import (
10
+ Architype,
11
+ EdgeArchitype,
12
+ Memory,
13
+ NodeArchitype,
14
+ Root,
15
+ WalkerArchitype,
16
+ )
17
+ from jaclang.plugin.default import ExecutionContext
9
18
  from jaclang.plugin.spec import JacBuiltin, JacCmdSpec, JacFeatureSpec, T
10
19
 
11
- if TYPE_CHECKING:
12
- from jaclang.core.construct import (
13
- Architype,
14
- EdgeArchitype,
15
- NodeArchitype,
16
- WalkerArchitype,
17
- Root,
18
- )
19
- from jaclang.plugin.default import ExecutionContext
20
- from jaclang.core.memory import Memory
21
-
22
20
 
23
21
  import pluggy
24
22
 
@@ -33,7 +31,13 @@ class JacFeature:
33
31
 
34
32
  import abc
35
33
  from jaclang.compiler.constant import EdgeDir
36
- from jaclang.plugin.spec import DSFunc
34
+ from jaclang.core.constructs import DSFunc
35
+
36
+ RootType: TypeAlias = Root
37
+ Obj: TypeAlias = Architype
38
+ Node: TypeAlias = NodeArchitype
39
+ Edge: TypeAlias = EdgeArchitype
40
+ Walker: TypeAlias = WalkerArchitype
37
41
 
38
42
  @staticmethod
39
43
  def context(session: str = "") -> ExecutionContext:
@@ -98,7 +102,7 @@ class JacFeature:
98
102
  cachable: bool = True,
99
103
  mdl_alias: Optional[str] = None,
100
104
  override_name: Optional[str] = None,
101
- mod_bundle: Optional[Module] = None,
105
+ mod_bundle: Optional[Module | str] = None,
102
106
  lng: Optional[str] = "jac",
103
107
  items: Optional[dict[str, Union[str, bool]]] = None,
104
108
  ) -> Optional[types.ModuleType]:
@@ -162,7 +166,13 @@ class JacFeature:
162
166
  @staticmethod
163
167
  def ignore(
164
168
  walker: WalkerArchitype,
165
- expr: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
169
+ expr: (
170
+ list[NodeArchitype | EdgeArchitype]
171
+ | list[NodeArchitype]
172
+ | list[EdgeArchitype]
173
+ | NodeArchitype
174
+ | EdgeArchitype
175
+ ),
166
176
  ) -> bool: # noqa: ANN401
167
177
  """Jac's ignore stmt feature."""
168
178
  return pm.hook.ignore(walker=walker, expr=expr)
@@ -170,7 +180,13 @@ class JacFeature:
170
180
  @staticmethod
171
181
  def visit_node(
172
182
  walker: WalkerArchitype,
173
- expr: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
183
+ expr: (
184
+ list[NodeArchitype | EdgeArchitype]
185
+ | list[NodeArchitype]
186
+ | list[EdgeArchitype]
187
+ | NodeArchitype
188
+ | EdgeArchitype
189
+ ),
174
190
  ) -> bool: # noqa: ANN401
175
191
  """Jac's visit stmt feature."""
176
192
  return pm.hook.visit_node(walker=walker, expr=expr)
@@ -247,7 +263,7 @@ class JacFeature:
247
263
  @staticmethod
248
264
  def build_edge(
249
265
  is_undirected: bool,
250
- conn_type: Optional[Type[EdgeArchitype]],
266
+ conn_type: Optional[Type[EdgeArchitype] | EdgeArchitype],
251
267
  conn_assign: Optional[tuple[tuple, tuple]],
252
268
  ) -> Callable[[], EdgeArchitype]:
253
269
  """Jac's root getter."""
jaclang/plugin/spec.py CHANGED
@@ -3,19 +3,19 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import types
6
- from dataclasses import dataclass
7
6
  from typing import Any, Callable, Optional, TYPE_CHECKING, Type, TypeVar, Union
8
7
 
9
8
  from jaclang.compiler.absyntree import Module
10
9
 
11
10
  if TYPE_CHECKING:
12
- from jaclang.core.construct import EdgeArchitype, NodeArchitype
11
+ from jaclang.core.constructs import EdgeArchitype, NodeArchitype
13
12
  from jaclang.plugin.default import (
14
13
  Architype,
15
14
  EdgeDir,
16
15
  ExecutionContext,
17
16
  WalkerArchitype,
18
17
  Root,
18
+ DSFunc,
19
19
  )
20
20
  from jaclang.core.memory import Memory
21
21
 
@@ -26,20 +26,6 @@ hookspec = pluggy.HookspecMarker("jac")
26
26
  T = TypeVar("T")
27
27
 
28
28
 
29
- # TODO: DSFunc should be moved into jaclang/core
30
- @dataclass(eq=False)
31
- class DSFunc:
32
- """Data Spatial Function."""
33
-
34
- name: str
35
- trigger: type | types.UnionType | tuple[type | types.UnionType, ...] | None
36
- func: Callable[[Any, Any], Any] | None = None
37
-
38
- def resolve(self, cls: type) -> None:
39
- """Resolve the function."""
40
- self.func = getattr(cls, self.name)
41
-
42
-
43
29
  class JacFeatureSpec:
44
30
  """Jac Feature."""
45
31
 
@@ -113,7 +99,7 @@ class JacFeatureSpec:
113
99
  cachable: bool,
114
100
  mdl_alias: Optional[str],
115
101
  override_name: Optional[str],
116
- mod_bundle: Optional[Module],
102
+ mod_bundle: Optional[Module | str],
117
103
  lng: Optional[str],
118
104
  items: Optional[dict[str, Union[str, bool]]],
119
105
  ) -> Optional[types.ModuleType]:
@@ -167,7 +153,13 @@ class JacFeatureSpec:
167
153
  @hookspec(firstresult=True)
168
154
  def ignore(
169
155
  walker: WalkerArchitype,
170
- expr: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
156
+ expr: (
157
+ list[NodeArchitype | EdgeArchitype]
158
+ | list[NodeArchitype]
159
+ | list[EdgeArchitype]
160
+ | NodeArchitype
161
+ | EdgeArchitype
162
+ ),
171
163
  ) -> bool:
172
164
  """Jac's ignore stmt feature."""
173
165
  raise NotImplementedError
@@ -176,7 +168,13 @@ class JacFeatureSpec:
176
168
  @hookspec(firstresult=True)
177
169
  def visit_node(
178
170
  walker: WalkerArchitype,
179
- expr: list[NodeArchitype | EdgeArchitype] | NodeArchitype | EdgeArchitype,
171
+ expr: (
172
+ list[NodeArchitype | EdgeArchitype]
173
+ | list[NodeArchitype]
174
+ | list[EdgeArchitype]
175
+ | NodeArchitype
176
+ | EdgeArchitype
177
+ ),
180
178
  ) -> bool: # noqa: ANN401
181
179
  """Jac's visit stmt feature."""
182
180
  raise NotImplementedError
@@ -248,7 +246,7 @@ class JacFeatureSpec:
248
246
  @hookspec(firstresult=True)
249
247
  def build_edge(
250
248
  is_undirected: bool,
251
- conn_type: Optional[Type[EdgeArchitype]],
249
+ conn_type: Optional[Type[EdgeArchitype] | EdgeArchitype],
252
250
  conn_assign: Optional[tuple[tuple, tuple]],
253
251
  ) -> Callable[[], EdgeArchitype]:
254
252
  """Jac's root getter."""