jaclang 0.2.5__py3-none-any.whl → 0.3.1__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 +3 -3
- jaclang/cli/__init__.py +0 -1
- jaclang/cli/__jac_gen__/cli.py +4 -4
- jaclang/cli/__jac_gen__/cmds.py +1 -1
- jaclang/cli/__jac_gen__/cmds_impl.py +1 -1
- jaclang/core/__init__.py +5 -11
- jaclang/core/__jac_gen__/corelib.py +289 -0
- jaclang/core/__jac_gen__/corelib_impl.py +220 -0
- jaclang/core/corelib.jac +21 -34
- jaclang/core/corelib_impl.jac +317 -0
- jaclang/jac/__init__.py +1 -0
- jaclang/jac/__jac_gen__/jac_parser.py +2 -2
- jaclang/jac/absyntree.py +28 -8
- jaclang/jac/constant.py +3 -7
- jaclang/jac/parser.py +13 -9
- jaclang/jac/passes/main/__init__.py +2 -0
- jaclang/jac/passes/main/def_use_pass.py +3 -2
- jaclang/jac/passes/main/pyast_gen_pass.py +99 -34
- jaclang/jac/passes/main/schedules.py +6 -0
- jaclang/jac/passes/main/sym_tab_build_pass.py +3 -5
- jaclang/jac/passes/main/tests/test_jac_format_pass.py +22 -4
- jaclang/jac/passes/main/tests/test_type_check_pass.py +42 -0
- jaclang/jac/passes/main/type_check_pass.py +103 -0
- jaclang/jac/passes/tool/fuse_comments_pass.py +57 -39
- jaclang/jac/passes/tool/jac_formatter_pass.py +419 -192
- jaclang/jac/passes/transform.py +0 -39
- jaclang/jac/passes/utils/__init__.py +1 -0
- jaclang/jac/passes/utils/mypy_ast_build.py +302 -0
- jaclang/jac/plugin/__init__.py +5 -2
- jaclang/jac/plugin/default.py +20 -4
- jaclang/jac/plugin/feature.py +15 -6
- jaclang/jac/plugin/spec.py +34 -6
- jaclang/jac/tests/test_workspace.py +45 -5
- jaclang/jac/transpiler.py +4 -9
- jaclang/utils/helpers.py +0 -33
- jaclang/utils/lang_tools.py +3 -0
- jaclang/utils/test.py +3 -1
- jaclang/vendor/lark/py.typed +0 -0
- jaclang/vendor/mypy/checker.py +19 -12
- jaclang/vendor/mypy/checkexpr.py +31 -10
- jaclang/vendor/mypy/constraints.py +56 -38
- jaclang/vendor/mypy/expandtype.py +1 -0
- jaclang/vendor/mypy/meet.py +10 -1
- jaclang/vendor/mypy/messages.py +16 -4
- jaclang/vendor/mypy/moduleinspect.py +10 -4
- jaclang/vendor/mypy/py.typed +1 -0
- jaclang/vendor/mypy/semanal.py +18 -17
- jaclang/vendor/mypy/semanal_enum.py +7 -4
- jaclang/vendor/mypy/semanal_namedtuple.py +11 -1
- jaclang/vendor/mypy/semanal_typeddict.py +25 -11
- jaclang/vendor/mypy/stubdoc.py +18 -4
- jaclang/vendor/mypy/stubgen.py +80 -1
- jaclang/vendor/mypy/stubgenc.py +47 -5
- jaclang/vendor/mypy/stubtest.py +53 -3
- jaclang/vendor/mypy/stubutil.py +9 -9
- jaclang/vendor/mypy/test/testipc.py +16 -7
- jaclang/vendor/mypy/test/teststubtest.py +20 -2
- jaclang/vendor/mypy/types.py +1 -1
- jaclang/vendor/mypyc/irbuild/prebuildvisitor.py +2 -1
- jaclang/vendor/mypyc/test/test_run.py +2 -4
- jaclang/vendor/pluggy/py.typed +0 -0
- {jaclang-0.2.5.dist-info → jaclang-0.3.1.dist-info}/METADATA +1 -1
- {jaclang-0.2.5.dist-info → jaclang-0.3.1.dist-info}/RECORD +67 -62
- {jaclang-0.2.5.dist-info → jaclang-0.3.1.dist-info}/WHEEL +1 -1
- {jaclang-0.2.5.dist-info → jaclang-0.3.1.dist-info}/entry_points.txt +3 -0
- jaclang/core/arch_impl.jac +0 -131
- jaclang/core/element_impl.jac +0 -109
- jaclang/core/exec_ctx_impl.jac +0 -14
- jaclang/core/memory_impl.jac +0 -57
- jaclang/jac/tests/fixtures/__jac_gen__/hello_world.py +0 -5
- /jaclang/{jac/tests/fixtures → core}/__jac_gen__/__init__.py +0 -0
- {jaclang-0.2.5.dist-info → jaclang-0.3.1.dist-info}/top_level.txt +0 -0
jaclang/jac/passes/transform.py
CHANGED
|
@@ -6,8 +6,6 @@ from typing import Optional
|
|
|
6
6
|
|
|
7
7
|
from jaclang.jac.absyntree import AstNode
|
|
8
8
|
from jaclang.jac.codeloc import CodeLocInfo
|
|
9
|
-
from jaclang.jac.constant import Constants as Con, Values as Val
|
|
10
|
-
from jaclang.utils.helpers import add_line_numbers, clip_code_section
|
|
11
9
|
from jaclang.utils.log import logging
|
|
12
10
|
|
|
13
11
|
|
|
@@ -31,37 +29,6 @@ class Alert:
|
|
|
31
29
|
return self.__str__()
|
|
32
30
|
|
|
33
31
|
|
|
34
|
-
class TransformError(Exception):
|
|
35
|
-
"""Error during transformation."""
|
|
36
|
-
|
|
37
|
-
def __init__(
|
|
38
|
-
self, message: str, errors: list[Alert], warnings: list[Alert]
|
|
39
|
-
) -> None:
|
|
40
|
-
"""Initialize error."""
|
|
41
|
-
self.errors = errors
|
|
42
|
-
self.warnings = warnings
|
|
43
|
-
if len(errors):
|
|
44
|
-
message += "\nErrors:"
|
|
45
|
-
for i in self.errors:
|
|
46
|
-
message += "\n" + str(i)
|
|
47
|
-
if len(warnings):
|
|
48
|
-
message += "\nWarnings:"
|
|
49
|
-
for i in self.warnings:
|
|
50
|
-
message += "\n" + str(i)
|
|
51
|
-
if len(errors) or len(warnings):
|
|
52
|
-
jac_err_line = (
|
|
53
|
-
errors[0].loc.first_line if len(errors) else warnings[0].loc.first_line
|
|
54
|
-
)
|
|
55
|
-
with open(errors[0].loc.mod_path, "r") as file:
|
|
56
|
-
jac_code_string = file.read()
|
|
57
|
-
message += f"\n{Con.JAC_ERROR_PREAMBLE}\n" + clip_code_section(
|
|
58
|
-
add_line_numbers(jac_code_string),
|
|
59
|
-
jac_err_line,
|
|
60
|
-
Val.JAC_ERROR_LINE_RANGE,
|
|
61
|
-
)
|
|
62
|
-
super().__init__(message)
|
|
63
|
-
|
|
64
|
-
|
|
65
32
|
class Transform(ABC):
|
|
66
33
|
"""Abstract class for IR passes."""
|
|
67
34
|
|
|
@@ -93,9 +60,3 @@ class Transform(ABC):
|
|
|
93
60
|
alrt = Alert(msg, self.cur_node.loc if not node_override else node_override.loc)
|
|
94
61
|
self.warnings_had.append(alrt)
|
|
95
62
|
self.logger.warning(str(alrt))
|
|
96
|
-
|
|
97
|
-
def gen_exception(
|
|
98
|
-
self, msg: str = "Error in code transform, see above for details."
|
|
99
|
-
) -> TransformError:
|
|
100
|
-
"""Raise error."""
|
|
101
|
-
return TransformError(msg, self.errors_had, self.warnings_had)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Utility packages for passes."""
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Overrides to mypy build manager for direct AST pass through."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import ast
|
|
5
|
+
|
|
6
|
+
import jaclang.vendor.mypy.build as myb
|
|
7
|
+
from jaclang.vendor.mypy.build import BuildSource
|
|
8
|
+
from jaclang.vendor.mypy.build import BuildSourceSet
|
|
9
|
+
from jaclang.vendor.mypy.build import FileSystemCache
|
|
10
|
+
from jaclang.vendor.mypy.build import compute_search_paths
|
|
11
|
+
from jaclang.vendor.mypy.build import load_graph
|
|
12
|
+
from jaclang.vendor.mypy.build import load_plugins
|
|
13
|
+
from jaclang.vendor.mypy.build import process_graph
|
|
14
|
+
from jaclang.vendor.mypy.errors import Errors
|
|
15
|
+
from jaclang.vendor.mypy.fastparse import ASTConverter
|
|
16
|
+
from jaclang.vendor.mypy.options import Options
|
|
17
|
+
from jaclang.vendor.mypy.semanal_main import semantic_analysis_for_scc
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BuildManager(myb.BuildManager):
|
|
21
|
+
"""Overrides to mypy build manager for direct AST pass through."""
|
|
22
|
+
|
|
23
|
+
def parse_file(
|
|
24
|
+
self,
|
|
25
|
+
id: str,
|
|
26
|
+
path: str,
|
|
27
|
+
source: str,
|
|
28
|
+
ignore_errors: bool,
|
|
29
|
+
options: myb.Options,
|
|
30
|
+
ast_override: ast.AST | None = None,
|
|
31
|
+
) -> myb.MypyFile:
|
|
32
|
+
"""Parse the source of a file with the given name.
|
|
33
|
+
|
|
34
|
+
Raise CompileError if there is a parse error.
|
|
35
|
+
"""
|
|
36
|
+
t0 = myb.time.time()
|
|
37
|
+
if ignore_errors:
|
|
38
|
+
self.errors.ignored_files.add(path)
|
|
39
|
+
tree = (
|
|
40
|
+
ast_override
|
|
41
|
+
if ast_override
|
|
42
|
+
else myb.parse(source, path, id, self.errors, options=options)
|
|
43
|
+
)
|
|
44
|
+
tree._fullname = id
|
|
45
|
+
self.add_stats(
|
|
46
|
+
files_parsed=1,
|
|
47
|
+
modules_parsed=int(not tree.is_stub),
|
|
48
|
+
stubs_parsed=int(tree.is_stub),
|
|
49
|
+
parse_time=myb.time.time() - t0,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if self.errors.is_blockers():
|
|
53
|
+
self.log("Bailing due to parse errors")
|
|
54
|
+
self.errors.raise_error()
|
|
55
|
+
|
|
56
|
+
self.errors.set_file_ignored_lines(path, tree.ignored_lines, ignore_errors)
|
|
57
|
+
return tree
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class State(myb.State):
|
|
61
|
+
"""Overrides to mypy state for direct AST pass through."""
|
|
62
|
+
|
|
63
|
+
manager: BuildManager
|
|
64
|
+
tree: myb.MypyFile | None = None
|
|
65
|
+
|
|
66
|
+
def __init__(
|
|
67
|
+
self,
|
|
68
|
+
id: str | None,
|
|
69
|
+
path: str | None,
|
|
70
|
+
source: str | None,
|
|
71
|
+
manager: BuildManager,
|
|
72
|
+
caller_state: myb.State | None = None,
|
|
73
|
+
caller_line: int = 0,
|
|
74
|
+
ancestor_for: myb.State | None = None,
|
|
75
|
+
root_source: bool = False,
|
|
76
|
+
# If `temporary` is True, this State is being created to just
|
|
77
|
+
# quickly parse/load the tree, without an intention to further
|
|
78
|
+
# process it. With this flag, any changes to external state as well
|
|
79
|
+
# as error reporting should be avoided.
|
|
80
|
+
temporary: bool = False,
|
|
81
|
+
ast_override: ast.AST | None = None,
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Override to mypy state for AST pass through."""
|
|
84
|
+
if not temporary:
|
|
85
|
+
assert id or path or source is not None, "Neither id, path nor source given"
|
|
86
|
+
self.manager = manager
|
|
87
|
+
State.order_counter += 1
|
|
88
|
+
self.order = State.order_counter
|
|
89
|
+
self.caller_state = caller_state
|
|
90
|
+
self.caller_line = caller_line
|
|
91
|
+
if caller_state:
|
|
92
|
+
self.import_context = caller_state.import_context.copy()
|
|
93
|
+
self.import_context.append((caller_state.xpath, caller_line))
|
|
94
|
+
else:
|
|
95
|
+
self.import_context = []
|
|
96
|
+
self.id = id or "__main__"
|
|
97
|
+
self.options = manager.options.clone_for_module(self.id)
|
|
98
|
+
self.early_errors: list[myb.ErrorInfo] = []
|
|
99
|
+
self._type_checker = None
|
|
100
|
+
if not path and source is None:
|
|
101
|
+
assert id is not None
|
|
102
|
+
try:
|
|
103
|
+
path, follow_imports = myb.find_module_and_diagnose(
|
|
104
|
+
manager,
|
|
105
|
+
id,
|
|
106
|
+
self.options,
|
|
107
|
+
caller_state,
|
|
108
|
+
caller_line,
|
|
109
|
+
ancestor_for,
|
|
110
|
+
root_source,
|
|
111
|
+
skip_diagnose=temporary,
|
|
112
|
+
)
|
|
113
|
+
except myb.ModuleNotFound:
|
|
114
|
+
if not temporary:
|
|
115
|
+
manager.missing_modules.add(id)
|
|
116
|
+
raise
|
|
117
|
+
if follow_imports == "silent":
|
|
118
|
+
self.ignore_all = True
|
|
119
|
+
elif path and myb.is_silent_import_module(manager, path) and not root_source:
|
|
120
|
+
self.ignore_all = True
|
|
121
|
+
self.path = path
|
|
122
|
+
if path:
|
|
123
|
+
self.abspath = myb.os.path.abspath(path)
|
|
124
|
+
self.xpath = path or "<string>"
|
|
125
|
+
if path and source is None and self.manager.cache_enabled:
|
|
126
|
+
self.meta = myb.find_cache_meta(self.id, path, manager)
|
|
127
|
+
# TODO: Get mtime if not cached.
|
|
128
|
+
if self.meta is not None:
|
|
129
|
+
self.interface_hash = self.meta.interface_hash
|
|
130
|
+
self.meta_source_hash = self.meta.hash
|
|
131
|
+
if path and source is None and self.manager.fscache.isdir(path):
|
|
132
|
+
source = ""
|
|
133
|
+
self.source = source
|
|
134
|
+
self.add_ancestors()
|
|
135
|
+
self.per_line_checking_time_ns = myb.collections.defaultdict(int)
|
|
136
|
+
t0 = myb.time.time()
|
|
137
|
+
self.meta = myb.validate_meta(
|
|
138
|
+
self.meta, self.id, self.path, self.ignore_all, manager
|
|
139
|
+
)
|
|
140
|
+
self.manager.add_stats(validate_meta_time=myb.time.time() - t0)
|
|
141
|
+
if self.meta:
|
|
142
|
+
# Make copies, since we may modify these and want to
|
|
143
|
+
# compare them to the originals later.
|
|
144
|
+
self.dependencies = list(self.meta.dependencies)
|
|
145
|
+
self.dependencies_set = set(self.dependencies)
|
|
146
|
+
self.suppressed = list(self.meta.suppressed)
|
|
147
|
+
self.suppressed_set = set(self.suppressed)
|
|
148
|
+
all_deps = self.dependencies + self.suppressed
|
|
149
|
+
assert len(all_deps) == len(self.meta.dep_prios)
|
|
150
|
+
self.priorities = dict(zip(all_deps, self.meta.dep_prios))
|
|
151
|
+
|
|
152
|
+
assert len(all_deps) == len(self.meta.dep_lines)
|
|
153
|
+
self.dep_line_map = dict(zip(all_deps, self.meta.dep_lines))
|
|
154
|
+
if temporary:
|
|
155
|
+
self.load_tree(temporary=True)
|
|
156
|
+
if not manager.use_fine_grained_cache() and myb.exist_added_packages(
|
|
157
|
+
self.suppressed, manager, self.options
|
|
158
|
+
):
|
|
159
|
+
# Special case: if there were a previously missing package imported here
|
|
160
|
+
# and it is not present, then we need to re-calculate dependencies.
|
|
161
|
+
# This is to support patterns like this:
|
|
162
|
+
# from missing_package import missing_module # type: ignore
|
|
163
|
+
# At first mypy doesn't know that `missing_module` is a module
|
|
164
|
+
# (it may be a variable, a class, or a function), so it is not added to
|
|
165
|
+
# suppressed dependencies. Therefore, when the package with module is added,
|
|
166
|
+
# we need to re-calculate dependencies.
|
|
167
|
+
# NOTE: see comment below for why we skip this in fine grained mode.
|
|
168
|
+
self.parse_file(
|
|
169
|
+
ast_override=ast_override
|
|
170
|
+
) # This is safe because the cache is anyway stale.
|
|
171
|
+
self.compute_dependencies()
|
|
172
|
+
else:
|
|
173
|
+
# When doing a fine-grained cache load, pretend we only
|
|
174
|
+
# know about modules that have cache information and defer
|
|
175
|
+
# handling new modules until the fine-grained update.
|
|
176
|
+
if manager.use_fine_grained_cache():
|
|
177
|
+
manager.log(f"Deferring module to fine-grained update {path} ({id})")
|
|
178
|
+
raise myb.ModuleNotFound
|
|
179
|
+
|
|
180
|
+
# Parse the file (and then some) to get the dependencies.
|
|
181
|
+
self.parse_file(temporary=temporary, ast_override=ast_override)
|
|
182
|
+
self.compute_dependencies()
|
|
183
|
+
|
|
184
|
+
def parse_file(
|
|
185
|
+
self, *, temporary: bool = False, ast_override: ast.AST | None = None
|
|
186
|
+
) -> None:
|
|
187
|
+
"""Parse file and run first pass of semantic analysis.
|
|
188
|
+
|
|
189
|
+
Everything done here is local to the file. Don't depend on imported
|
|
190
|
+
modules in any way. Also record module dependencies based on imports.
|
|
191
|
+
"""
|
|
192
|
+
if self.tree is not None:
|
|
193
|
+
# The file was already parsed (in __init__()).
|
|
194
|
+
return
|
|
195
|
+
|
|
196
|
+
manager = self.manager
|
|
197
|
+
|
|
198
|
+
# Can we reuse a previously parsed AST? This avoids redundant work in daemon.
|
|
199
|
+
cached = self.id in manager.ast_cache
|
|
200
|
+
modules = manager.modules
|
|
201
|
+
if not cached:
|
|
202
|
+
manager.log(f"Parsing {self.xpath} ({self.id})")
|
|
203
|
+
else:
|
|
204
|
+
manager.log(f"Using cached AST for {self.xpath} ({self.id})")
|
|
205
|
+
|
|
206
|
+
t0 = myb.time_ref()
|
|
207
|
+
|
|
208
|
+
with self.wrap_context():
|
|
209
|
+
source = self.source
|
|
210
|
+
self.source = None # We won't need it again.
|
|
211
|
+
if self.path and source is None:
|
|
212
|
+
try:
|
|
213
|
+
path = manager.maybe_swap_for_shadow_path(self.path)
|
|
214
|
+
source = myb.decode_python_encoding(manager.fscache.read(path))
|
|
215
|
+
self.source_hash = manager.fscache.hash_digest(path)
|
|
216
|
+
except OSError as ioerr:
|
|
217
|
+
# ioerr.strerror differs for os.stat failures between Windows and
|
|
218
|
+
# other systems, but os.strerror(ioerr.errno) does not, so we use that.
|
|
219
|
+
# (We want the error messages to be platform-independent so that the
|
|
220
|
+
# tests have predictable output.)
|
|
221
|
+
raise myb.CompileError(
|
|
222
|
+
[
|
|
223
|
+
"mypy: can't read file '{}': {}".format(
|
|
224
|
+
self.path, myb.os.strerror(ioerr.errno)
|
|
225
|
+
)
|
|
226
|
+
],
|
|
227
|
+
module_with_blocker=self.id,
|
|
228
|
+
) from ioerr
|
|
229
|
+
except (UnicodeDecodeError, myb.DecodeError) as decodeerr:
|
|
230
|
+
if self.path.endswith(".pyd"):
|
|
231
|
+
err = (
|
|
232
|
+
f"mypy: stubgen does not support .pyd files: '{self.path}'"
|
|
233
|
+
)
|
|
234
|
+
else:
|
|
235
|
+
err = f"mypy: can't decode file '{self.path}': {str(decodeerr)}"
|
|
236
|
+
raise myb.CompileError(
|
|
237
|
+
[err], module_with_blocker=self.id
|
|
238
|
+
) from decodeerr
|
|
239
|
+
elif self.path and self.manager.fscache.isdir(self.path):
|
|
240
|
+
source = ""
|
|
241
|
+
self.source_hash = ""
|
|
242
|
+
else:
|
|
243
|
+
assert source is not None
|
|
244
|
+
self.source_hash = myb.compute_hash(source)
|
|
245
|
+
|
|
246
|
+
self.parse_inline_configuration(source)
|
|
247
|
+
if not cached:
|
|
248
|
+
self.tree = manager.parse_file(
|
|
249
|
+
self.id,
|
|
250
|
+
self.xpath,
|
|
251
|
+
source,
|
|
252
|
+
self.ignore_all or self.options.ignore_errors,
|
|
253
|
+
self.options,
|
|
254
|
+
ast_override=ast_override,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
else:
|
|
258
|
+
# Reuse a cached AST
|
|
259
|
+
self.tree = manager.ast_cache[self.id][0]
|
|
260
|
+
manager.errors.set_file_ignored_lines(
|
|
261
|
+
self.xpath,
|
|
262
|
+
self.tree.ignored_lines,
|
|
263
|
+
self.ignore_all or self.options.ignore_errors,
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
self.time_spent_us += myb.time_spent_us(t0)
|
|
267
|
+
|
|
268
|
+
if not cached:
|
|
269
|
+
# Make a copy of any errors produced during parse time so that
|
|
270
|
+
# fine-grained mode can repeat them when the module is
|
|
271
|
+
# reprocessed.
|
|
272
|
+
self.early_errors = list(manager.errors.error_info_map.get(self.xpath, []))
|
|
273
|
+
else:
|
|
274
|
+
self.early_errors = manager.ast_cache[self.id][1]
|
|
275
|
+
|
|
276
|
+
if not temporary:
|
|
277
|
+
modules[self.id] = self.tree
|
|
278
|
+
|
|
279
|
+
if not cached:
|
|
280
|
+
self.semantic_analysis_pass1()
|
|
281
|
+
|
|
282
|
+
if not temporary:
|
|
283
|
+
self.check_blockers()
|
|
284
|
+
|
|
285
|
+
manager.ast_cache[self.id] = (self.tree, self.early_errors)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
__all__ = [
|
|
289
|
+
"BuildManager",
|
|
290
|
+
"State",
|
|
291
|
+
"BuildSource",
|
|
292
|
+
"BuildSourceSet",
|
|
293
|
+
"FileSystemCache",
|
|
294
|
+
"compute_search_paths",
|
|
295
|
+
"load_graph",
|
|
296
|
+
"load_plugins",
|
|
297
|
+
"process_graph",
|
|
298
|
+
"Errors",
|
|
299
|
+
"Options",
|
|
300
|
+
"ASTConverter",
|
|
301
|
+
"semantic_analysis_for_scc",
|
|
302
|
+
]
|
jaclang/jac/plugin/__init__.py
CHANGED
jaclang/jac/plugin/default.py
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
from typing import Any, Callable, Optional
|
|
5
|
+
from typing import Any, Callable, Optional, Type
|
|
6
6
|
|
|
7
7
|
from jaclang.jac.constant import EdgeDir
|
|
8
|
-
from jaclang.jac.plugin import
|
|
9
|
-
|
|
8
|
+
from jaclang.jac.plugin.spec import AT, Architype, T
|
|
9
|
+
|
|
10
|
+
import pluggy
|
|
11
|
+
|
|
12
|
+
hookimpl = pluggy.HookimplMarker("jac")
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
class JacFeatureDefaults:
|
|
@@ -14,9 +17,10 @@ class JacFeatureDefaults:
|
|
|
14
17
|
|
|
15
18
|
@staticmethod
|
|
16
19
|
@hookimpl
|
|
17
|
-
def bind_architype(arch: AT) ->
|
|
20
|
+
def bind_architype(arch: Type[AT], arch_type: str) -> bool:
|
|
18
21
|
"""Create a new architype."""
|
|
19
22
|
arch._jac_ = None
|
|
23
|
+
return True
|
|
20
24
|
|
|
21
25
|
@staticmethod
|
|
22
26
|
@hookimpl
|
|
@@ -44,6 +48,7 @@ class JacFeatureDefaults:
|
|
|
44
48
|
@hookimpl
|
|
45
49
|
def ignore(walker_obj: Any, expr: Any) -> bool: # noqa: ANN401
|
|
46
50
|
"""Jac's ignore stmt feature."""
|
|
51
|
+
return True
|
|
47
52
|
|
|
48
53
|
@staticmethod
|
|
49
54
|
@hookimpl
|
|
@@ -55,6 +60,7 @@ class JacFeatureDefaults:
|
|
|
55
60
|
@hookimpl
|
|
56
61
|
def disengage(walker_obj: Any) -> bool: # noqa: ANN401
|
|
57
62
|
"""Jac's disengage stmt feature."""
|
|
63
|
+
return True
|
|
58
64
|
|
|
59
65
|
@staticmethod
|
|
60
66
|
@hookimpl
|
|
@@ -88,3 +94,13 @@ class JacFeatureDefaults:
|
|
|
88
94
|
) -> list[T]:
|
|
89
95
|
"""Jac's assign comprehension feature."""
|
|
90
96
|
return target
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
@hookimpl
|
|
100
|
+
def get_root() -> Architype:
|
|
101
|
+
"""Jac's assign comprehension feature."""
|
|
102
|
+
|
|
103
|
+
class Blank(Architype):
|
|
104
|
+
_jac_: Any = None
|
|
105
|
+
|
|
106
|
+
return Blank()
|
jaclang/jac/plugin/feature.py
CHANGED
|
@@ -8,7 +8,7 @@ from typing import Any, Callable, Optional, Type
|
|
|
8
8
|
|
|
9
9
|
from jaclang.jac.constant import EdgeDir
|
|
10
10
|
from jaclang.jac.plugin.default import JacFeatureDefaults
|
|
11
|
-
from jaclang.jac.plugin.spec import AT, JacFeatureSpec, T
|
|
11
|
+
from jaclang.jac.plugin.spec import AT, AbsRootHook, Architype, JacFeatureSpec, T
|
|
12
12
|
|
|
13
13
|
import pluggy
|
|
14
14
|
|
|
@@ -18,9 +18,10 @@ class JacFeature:
|
|
|
18
18
|
|
|
19
19
|
pm = pluggy.PluginManager("jac")
|
|
20
20
|
pm.add_hookspecs(JacFeatureSpec)
|
|
21
|
-
pm.load_setuptools_entrypoints("jac")
|
|
22
21
|
pm.register(JacFeatureDefaults)
|
|
23
22
|
|
|
23
|
+
RootType: Type[AbsRootHook] = AbsRootHook
|
|
24
|
+
|
|
24
25
|
@staticmethod
|
|
25
26
|
def make_architype(arch_type: str) -> Callable[[type], type]:
|
|
26
27
|
"""Create a new architype."""
|
|
@@ -43,15 +44,18 @@ class JacFeature:
|
|
|
43
44
|
for k, v in cls_module_globals.items(): # Risky!
|
|
44
45
|
if k not in func_module_globals and not k.startswith("__"):
|
|
45
46
|
func_module_globals[k] = v
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
cls = dataclass(cls)
|
|
48
|
+
if not issubclass(cls, Architype):
|
|
49
|
+
cls = type(cls.__name__, (cls, Architype), {})
|
|
50
|
+
JacFeature.bind_architype(cls, arch_type)
|
|
51
|
+
return cls
|
|
48
52
|
|
|
49
53
|
return decorator
|
|
50
54
|
|
|
51
55
|
@staticmethod
|
|
52
|
-
def bind_architype(arch: AT) ->
|
|
56
|
+
def bind_architype(arch: Type[AT], arch_type: str) -> bool:
|
|
53
57
|
"""Create a new architype."""
|
|
54
|
-
return JacFeature.pm.hook.bind_architype(arch=arch)
|
|
58
|
+
return JacFeature.pm.hook.bind_architype(arch=arch, arch_type=arch_type)
|
|
55
59
|
|
|
56
60
|
@staticmethod
|
|
57
61
|
def make_ds_ability(event: str, trigger: Optional[type]) -> Callable[[type], type]:
|
|
@@ -113,3 +117,8 @@ class JacFeature:
|
|
|
113
117
|
) -> list[T]:
|
|
114
118
|
"""Jac's assign comprehension feature."""
|
|
115
119
|
return JacFeature.pm.hook.assign_compr(target=target, attr_val=attr_val)
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def get_root() -> Architype:
|
|
123
|
+
"""Jac's assign comprehension feature."""
|
|
124
|
+
return JacFeature.pm.hook.get_root()
|
jaclang/jac/plugin/spec.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Jac Language Features."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
from typing import Any, Callable, Optional, Protocol, TypeVar
|
|
4
|
+
from typing import Any, Callable, Optional, Protocol, Type, TypeVar
|
|
5
5
|
|
|
6
6
|
from jaclang.jac.constant import EdgeDir
|
|
7
7
|
|
|
@@ -10,14 +10,26 @@ import pluggy
|
|
|
10
10
|
hookspec = pluggy.HookspecMarker("jac")
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class
|
|
13
|
+
class Architype:
|
|
14
14
|
"""Architype Protocol."""
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
class ArchitypeProtocol(Protocol):
|
|
17
|
+
"""Architype Protocol."""
|
|
18
|
+
|
|
19
|
+
_jac_: ArchitypeProtocol
|
|
20
|
+
|
|
21
|
+
def __call__(self, target: Architype) -> None:
|
|
22
|
+
"""Call the architype's data spatial behavior."""
|
|
23
|
+
if callable(self._jac_):
|
|
24
|
+
return self._jac_(target)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AbsRootHook:
|
|
28
|
+
"""Abstract Root Node."""
|
|
17
29
|
|
|
18
30
|
|
|
19
31
|
T = TypeVar("T")
|
|
20
|
-
AT = TypeVar("AT", bound=
|
|
32
|
+
AT = TypeVar("AT", bound=Architype)
|
|
21
33
|
|
|
22
34
|
|
|
23
35
|
class JacFeatureSpec:
|
|
@@ -25,39 +37,45 @@ class JacFeatureSpec:
|
|
|
25
37
|
|
|
26
38
|
@staticmethod
|
|
27
39
|
@hookspec(firstresult=True)
|
|
28
|
-
def bind_architype(arch: AT) ->
|
|
40
|
+
def bind_architype(arch: Type[AT], arch_type: str) -> bool:
|
|
29
41
|
"""Create a new architype."""
|
|
42
|
+
raise NotImplementedError
|
|
30
43
|
|
|
31
44
|
@staticmethod
|
|
32
45
|
@hookspec(firstresult=True)
|
|
33
46
|
def make_ds_ability(event: str, trigger: Optional[type]) -> Callable[[type], type]:
|
|
34
47
|
"""Create a new architype."""
|
|
48
|
+
raise NotImplementedError
|
|
35
49
|
|
|
36
50
|
@staticmethod
|
|
37
51
|
@hookspec(firstresult=True)
|
|
38
52
|
def elvis(op1: Optional[T], op2: T) -> T: # noqa: ANN401
|
|
39
53
|
"""Jac's elvis operator feature."""
|
|
54
|
+
raise NotImplementedError
|
|
40
55
|
|
|
41
56
|
@staticmethod
|
|
42
57
|
@hookspec(firstresult=True)
|
|
43
58
|
def report(expr: Any) -> Any: # noqa: ANN401
|
|
44
59
|
"""Jac's report stmt feature."""
|
|
60
|
+
raise NotImplementedError
|
|
45
61
|
|
|
46
62
|
@staticmethod
|
|
47
63
|
@hookspec(firstresult=True)
|
|
48
64
|
def ignore(walker_obj: Any, expr: Any) -> bool: # noqa: ANN401
|
|
49
65
|
"""Jac's ignore stmt feature."""
|
|
66
|
+
raise NotImplementedError
|
|
50
67
|
|
|
51
68
|
@staticmethod
|
|
52
69
|
@hookspec(firstresult=True)
|
|
53
70
|
def visit(walker_obj: Any, expr: Any) -> bool: # noqa: ANN401
|
|
54
71
|
"""Jac's visit stmt feature."""
|
|
55
|
-
|
|
72
|
+
raise NotImplementedError
|
|
56
73
|
|
|
57
74
|
@staticmethod
|
|
58
75
|
@hookspec(firstresult=True)
|
|
59
76
|
def disengage(walker_obj: Any) -> bool: # noqa: ANN401
|
|
60
77
|
"""Jac's disengage stmt feature."""
|
|
78
|
+
raise NotImplementedError
|
|
61
79
|
|
|
62
80
|
@staticmethod
|
|
63
81
|
@hookspec(firstresult=True)
|
|
@@ -65,6 +83,7 @@ class JacFeatureSpec:
|
|
|
65
83
|
node_obj: Any, dir: EdgeDir, filter_type: Optional[type] # noqa: ANN401
|
|
66
84
|
) -> list[Any]:
|
|
67
85
|
"""Jac's apply_dir stmt feature."""
|
|
86
|
+
raise NotImplementedError
|
|
68
87
|
|
|
69
88
|
@staticmethod
|
|
70
89
|
@hookspec(firstresult=True)
|
|
@@ -73,11 +92,13 @@ class JacFeatureSpec:
|
|
|
73
92
|
|
|
74
93
|
Note: connect needs to call assign compr with tuple in op
|
|
75
94
|
"""
|
|
95
|
+
raise NotImplementedError
|
|
76
96
|
|
|
77
97
|
@staticmethod
|
|
78
98
|
@hookspec(firstresult=True)
|
|
79
99
|
def disconnect(op1: Optional[T], op2: T, op: Any) -> T: # noqa: ANN401
|
|
80
100
|
"""Jac's connect operator feature."""
|
|
101
|
+
raise NotImplementedError
|
|
81
102
|
|
|
82
103
|
@staticmethod
|
|
83
104
|
@hookspec(firstresult=True)
|
|
@@ -85,3 +106,10 @@ class JacFeatureSpec:
|
|
|
85
106
|
target: list[T], attr_val: tuple[tuple[str], tuple[Any]]
|
|
86
107
|
) -> list[T]:
|
|
87
108
|
"""Jac's assign comprehension feature."""
|
|
109
|
+
raise NotImplementedError
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
@hookspec(firstresult=True)
|
|
113
|
+
def get_root() -> Architype:
|
|
114
|
+
"""Jac's root getter."""
|
|
115
|
+
raise NotImplementedError
|
|
@@ -40,13 +40,53 @@ class TestWorkspace(TestCase):
|
|
|
40
40
|
def test_man_code_dir(self) -> None:
|
|
41
41
|
"""Test of circle workspace."""
|
|
42
42
|
loc = os.path.join(os.path.dirname(__file__))
|
|
43
|
-
# print(loc)
|
|
44
43
|
ws = Workspace(path=loc + "/../../../examples/manual_code")
|
|
45
44
|
key = [i for i in ws.modules.keys() if "circle.jac" in i][0]
|
|
46
45
|
# print(ws.modules[key].ir.sym_tab.pp())
|
|
47
46
|
# for i in ws.get_symbols(key):
|
|
48
47
|
# print(i.decl.pp(depth=2))
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
out = ""
|
|
49
|
+
for i in ws.get_uses(key):
|
|
50
|
+
# print(i.pp(depth=2).strip())
|
|
51
|
+
out += i.pp(depth=2)
|
|
52
|
+
for i in [
|
|
53
|
+
"math",
|
|
54
|
+
"calculate_area",
|
|
55
|
+
"RAD",
|
|
56
|
+
"expected_area",
|
|
57
|
+
"Circle",
|
|
58
|
+
"c",
|
|
59
|
+
"ShapeType",
|
|
60
|
+
"float",
|
|
61
|
+
"radius",
|
|
62
|
+
"CIRCLE",
|
|
63
|
+
"Shape",
|
|
64
|
+
"__init__",
|
|
65
|
+
"print",
|
|
66
|
+
]:
|
|
67
|
+
self.assertIn(i, out)
|
|
68
|
+
|
|
69
|
+
# def test_decl_impl(self) -> None:
|
|
70
|
+
# """Test of circle workspace."""
|
|
71
|
+
# loc = os.path.join(os.path.dirname(__file__))
|
|
72
|
+
# ws = Workspace(path=loc + "/../../../examples/manual_code")
|
|
73
|
+
# key = [i for i in ws.modules.keys() if "circle_clean.jac" in i][0]
|
|
74
|
+
# out = ""
|
|
75
|
+
# for i in ws.get_uses(key):
|
|
76
|
+
# out += i.pp(depth=2)
|
|
77
|
+
# for i in [
|
|
78
|
+
# "math",
|
|
79
|
+
# "calculate_area",
|
|
80
|
+
# "RAD",
|
|
81
|
+
# "expected_area",
|
|
82
|
+
# "Circle",
|
|
83
|
+
# "c",
|
|
84
|
+
# "ShapeType",
|
|
85
|
+
# "float",
|
|
86
|
+
# "radius",
|
|
87
|
+
# "CIRCLE",
|
|
88
|
+
# "Shape",
|
|
89
|
+
# "__init__",
|
|
90
|
+
# "print",
|
|
91
|
+
# ]:
|
|
92
|
+
# self.assertIn(i, out)
|