jaclang 0.7.27__py3-none-any.whl → 0.7.30__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/cli/cli.py +3 -0
- jaclang/compiler/__init__.py +1 -1
- jaclang/compiler/absyntree.py +30 -5
- jaclang/compiler/compile.py +1 -1
- jaclang/compiler/constant.py +0 -1
- jaclang/compiler/jac.lark +1 -5
- jaclang/compiler/parser.py +2 -10
- jaclang/compiler/passes/main/__init__.py +1 -1
- jaclang/compiler/passes/main/access_modifier_pass.py +1 -1
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +62 -33
- jaclang/compiler/passes/main/import_pass.py +285 -64
- jaclang/compiler/passes/main/inheritance_pass.py +103 -0
- jaclang/compiler/passes/main/py_collect_dep_pass.py +5 -5
- jaclang/compiler/passes/main/pyast_gen_pass.py +0 -19
- jaclang/compiler/passes/main/pyast_load_pass.py +1 -1
- jaclang/compiler/passes/main/schedules.py +2 -0
- jaclang/compiler/passes/main/sym_tab_build_pass.py +17 -0
- jaclang/compiler/passes/main/tests/fixtures/data_spatial_types.jac +130 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.py +3 -3
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.pyi +3 -3
- jaclang/compiler/passes/main/tests/test_import_pass.py +16 -17
- jaclang/compiler/passes/main/tests/test_type_check_pass.py +24 -0
- jaclang/compiler/passes/main/type_check_pass.py +3 -2
- jaclang/compiler/passes/tool/jac_formatter_pass.py +0 -1
- jaclang/compiler/py_info.py +22 -0
- jaclang/compiler/symtable.py +9 -2
- jaclang/compiler/tests/test_importer.py +45 -1
- jaclang/langserve/tests/test_server.py +2 -2
- jaclang/plugin/default.py +86 -62
- jaclang/plugin/feature.py +2 -5
- jaclang/plugin/spec.py +1 -6
- jaclang/runtimelib/architype.py +20 -16
- jaclang/runtimelib/importer.py +26 -3
- jaclang/runtimelib/machine.py +2 -2
- jaclang/runtimelib/test.py +59 -4
- jaclang/runtimelib/utils.py +15 -0
- jaclang/settings.py +3 -0
- jaclang/tests/fixtures/base_class1.jac +11 -0
- jaclang/tests/fixtures/base_class2.jac +11 -0
- jaclang/tests/fixtures/import_all.jac +7 -0
- jaclang/tests/fixtures/import_all_py.py +8 -0
- jaclang/tests/fixtures/jactest_imported.jac +6 -0
- jaclang/tests/fixtures/jactest_main.jac +22 -0
- jaclang/tests/fixtures/multi_dim_array_split.jac +2 -6
- jaclang/tests/fixtures/test_py.py +12 -0
- jaclang/tests/fixtures/visit_sequence.jac +50 -0
- jaclang/tests/test_cli.py +83 -1
- jaclang/tests/test_language.py +24 -9
- jaclang/utils/helpers.py +9 -1
- jaclang/utils/test.py +2 -2
- jaclang/utils/tests/test_lang_tools.py +4 -2
- jaclang/utils/treeprinter.py +6 -3
- {jaclang-0.7.27.dist-info → jaclang-0.7.30.dist-info}/METADATA +3 -3
- {jaclang-0.7.27.dist-info → jaclang-0.7.30.dist-info}/RECORD +56 -45
- {jaclang-0.7.27.dist-info → jaclang-0.7.30.dist-info}/WHEEL +1 -1
- {jaclang-0.7.27.dist-info → jaclang-0.7.30.dist-info}/entry_points.txt +0 -0
jaclang/plugin/spec.py
CHANGED
|
@@ -345,6 +345,7 @@ class JacFeatureSpec(
|
|
|
345
345
|
@hookspec(firstresult=True)
|
|
346
346
|
def run_test(
|
|
347
347
|
filepath: str,
|
|
348
|
+
func_name: Optional[str],
|
|
348
349
|
filter: Optional[str],
|
|
349
350
|
xit: bool,
|
|
350
351
|
maxfail: Optional[int],
|
|
@@ -354,12 +355,6 @@ class JacFeatureSpec(
|
|
|
354
355
|
"""Run the test suite in the specified .jac file."""
|
|
355
356
|
raise NotImplementedError
|
|
356
357
|
|
|
357
|
-
@staticmethod
|
|
358
|
-
@hookspec(firstresult=True)
|
|
359
|
-
def elvis(op1: Optional[T], op2: T) -> T:
|
|
360
|
-
"""Jac's elvis operator feature."""
|
|
361
|
-
raise NotImplementedError
|
|
362
|
-
|
|
363
358
|
@staticmethod
|
|
364
359
|
@hookspec(firstresult=True)
|
|
365
360
|
def has_instance_default(gen_func: Callable[[], T]) -> T:
|
jaclang/runtimelib/architype.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import inspect
|
|
6
6
|
from dataclasses import asdict, dataclass, field, fields, is_dataclass
|
|
7
7
|
from enum import IntEnum
|
|
8
|
+
from functools import cached_property
|
|
8
9
|
from logging import getLogger
|
|
9
10
|
from pickle import dumps
|
|
10
11
|
from types import UnionType
|
|
@@ -43,9 +44,9 @@ class Access:
|
|
|
43
44
|
|
|
44
45
|
anchors: dict[str, AccessLevel] = field(default_factory=dict)
|
|
45
46
|
|
|
46
|
-
def check(self, anchor: str) -> AccessLevel:
|
|
47
|
+
def check(self, anchor: str) -> AccessLevel | None:
|
|
47
48
|
"""Validate access."""
|
|
48
|
-
return self.anchors.get(anchor
|
|
49
|
+
return self.anchors.get(anchor)
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
@dataclass
|
|
@@ -220,9 +221,9 @@ class WalkerAnchor(Anchor):
|
|
|
220
221
|
"""Walker Anchor."""
|
|
221
222
|
|
|
222
223
|
architype: WalkerArchitype
|
|
223
|
-
path: list[
|
|
224
|
-
next: list[
|
|
225
|
-
ignores: list[
|
|
224
|
+
path: list[NodeAnchor] = field(default_factory=list)
|
|
225
|
+
next: list[NodeAnchor] = field(default_factory=list)
|
|
226
|
+
ignores: list[NodeAnchor] = field(default_factory=list)
|
|
226
227
|
disengaged: bool = False
|
|
227
228
|
|
|
228
229
|
|
|
@@ -311,17 +312,20 @@ class DSFunc:
|
|
|
311
312
|
name: str
|
|
312
313
|
func: Callable[[Any, Any], Any] | None = None
|
|
313
314
|
|
|
315
|
+
@cached_property
|
|
316
|
+
def trigger(self) -> type | UnionType | tuple[type | UnionType, ...] | None:
|
|
317
|
+
"""Get function parameter annotations."""
|
|
318
|
+
t = (
|
|
319
|
+
(
|
|
320
|
+
inspect.signature(self.func, eval_str=True)
|
|
321
|
+
.parameters["_jac_here_"]
|
|
322
|
+
.annotation
|
|
323
|
+
)
|
|
324
|
+
if self.func
|
|
325
|
+
else None
|
|
326
|
+
)
|
|
327
|
+
return None if t is inspect._empty else t
|
|
328
|
+
|
|
314
329
|
def resolve(self, cls: type) -> None:
|
|
315
330
|
"""Resolve the function."""
|
|
316
331
|
self.func = getattr(cls, self.name)
|
|
317
|
-
|
|
318
|
-
def get_funcparam_annotations(
|
|
319
|
-
self, func: Callable[[Any, Any], Any] | None
|
|
320
|
-
) -> type | UnionType | tuple[type | UnionType, ...] | None:
|
|
321
|
-
"""Get function parameter annotations."""
|
|
322
|
-
if not func:
|
|
323
|
-
return None
|
|
324
|
-
annotation = (
|
|
325
|
-
inspect.signature(func, eval_str=True).parameters["_jac_here_"].annotation
|
|
326
|
-
)
|
|
327
|
-
return annotation if annotation != inspect._empty else None
|
jaclang/runtimelib/importer.py
CHANGED
|
@@ -158,9 +158,6 @@ class ImportReturn:
|
|
|
158
158
|
return getattr(new_module, name, new_module)
|
|
159
159
|
except ImportError as e:
|
|
160
160
|
logger.error(dump_traceback(e))
|
|
161
|
-
# logger.error(
|
|
162
|
-
# f"Failed to load {name} from {jac_file_path} in {module.__name__}: {str(e)}"
|
|
163
|
-
# )
|
|
164
161
|
return None
|
|
165
162
|
|
|
166
163
|
|
|
@@ -319,6 +316,32 @@ class JacImporter(Importer):
|
|
|
319
316
|
"""Run the import process for Jac modules."""
|
|
320
317
|
unique_loaded_items: list[types.ModuleType] = []
|
|
321
318
|
module = None
|
|
319
|
+
# Gather all possible search paths
|
|
320
|
+
jacpaths = os.environ.get("JACPATH", "")
|
|
321
|
+
search_paths = [spec.caller_dir]
|
|
322
|
+
if jacpaths:
|
|
323
|
+
for p in jacpaths.split(os.pathsep):
|
|
324
|
+
p = p.strip()
|
|
325
|
+
if p and p not in search_paths:
|
|
326
|
+
search_paths.append(p)
|
|
327
|
+
|
|
328
|
+
# Attempt to locate the module file or directory
|
|
329
|
+
found_path = None
|
|
330
|
+
target_path_components = spec.target.split(".")
|
|
331
|
+
for search_path in search_paths:
|
|
332
|
+
candidate = os.path.join(search_path, "/".join(target_path_components))
|
|
333
|
+
# Check if the candidate is a directory or a .jac file
|
|
334
|
+
if (os.path.isdir(candidate)) or (os.path.isfile(candidate + ".jac")):
|
|
335
|
+
found_path = candidate
|
|
336
|
+
break
|
|
337
|
+
|
|
338
|
+
# If a suitable path was found, update spec.full_target; otherwise, raise an error
|
|
339
|
+
if found_path:
|
|
340
|
+
spec.full_target = os.path.abspath(found_path)
|
|
341
|
+
else:
|
|
342
|
+
raise ImportError(
|
|
343
|
+
f"Unable to locate module '{spec.target}' in {search_paths}"
|
|
344
|
+
)
|
|
322
345
|
if os.path.isfile(spec.full_target + ".jac"):
|
|
323
346
|
module_name = self.get_sys_mod_name(spec.full_target + ".jac")
|
|
324
347
|
module_name = spec.override_name if spec.override_name else module_name
|
jaclang/runtimelib/machine.py
CHANGED
|
@@ -38,6 +38,7 @@ class JacMachine:
|
|
|
38
38
|
self.loaded_modules: dict[str, types.ModuleType] = {}
|
|
39
39
|
if not base_path:
|
|
40
40
|
base_path = os.getcwd()
|
|
41
|
+
# Ensure the base_path is a list rather than a string
|
|
41
42
|
self.base_path = base_path
|
|
42
43
|
self.base_path_dir = (
|
|
43
44
|
os.path.dirname(base_path)
|
|
@@ -306,12 +307,11 @@ class JacProgram:
|
|
|
306
307
|
return marshal.load(f)
|
|
307
308
|
|
|
308
309
|
result = compile_jac(full_target, cache_result=cachable)
|
|
309
|
-
if result.errors_had
|
|
310
|
+
if result.errors_had:
|
|
310
311
|
for alrt in result.errors_had:
|
|
311
312
|
# We're not logging here, it already gets logged as the errors were added to the errors_had list.
|
|
312
313
|
# Regardless of the logging, this needs to be sent to the end user, so we'll printing it to stderr.
|
|
313
314
|
logger.error(alrt.pretty_print())
|
|
314
|
-
return None
|
|
315
315
|
if result.ir.gen.py_bytecode is not None:
|
|
316
316
|
return marshal.loads(result.ir.gen.py_bytecode)
|
|
317
317
|
else:
|
jaclang/runtimelib/test.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import unittest
|
|
6
|
+
from dataclasses import dataclass
|
|
6
7
|
from typing import Callable, Optional
|
|
7
8
|
|
|
8
9
|
|
|
@@ -56,6 +57,16 @@ class JacTestCheck:
|
|
|
56
57
|
|
|
57
58
|
test_case = unittest.TestCase()
|
|
58
59
|
test_suite = unittest.TestSuite()
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class TestSuite:
|
|
63
|
+
"""Test Suite."""
|
|
64
|
+
|
|
65
|
+
test_case: unittest.FunctionTestCase
|
|
66
|
+
func_name: str
|
|
67
|
+
|
|
68
|
+
test_suite_path: dict[str, list[TestSuite]] = {}
|
|
69
|
+
|
|
59
70
|
breaker = False
|
|
60
71
|
failcount = 0
|
|
61
72
|
|
|
@@ -64,13 +75,45 @@ class JacTestCheck:
|
|
|
64
75
|
"""Clear the test suite."""
|
|
65
76
|
JacTestCheck.test_case = unittest.TestCase()
|
|
66
77
|
JacTestCheck.test_suite = unittest.TestSuite()
|
|
78
|
+
JacTestCheck.test_suite_path = {}
|
|
67
79
|
|
|
68
80
|
@staticmethod
|
|
69
|
-
def run_test(
|
|
81
|
+
def run_test(
|
|
82
|
+
xit: bool,
|
|
83
|
+
maxfail: int | None,
|
|
84
|
+
verbose: bool,
|
|
85
|
+
filepath: str | None,
|
|
86
|
+
func_name: str | None,
|
|
87
|
+
) -> None:
|
|
70
88
|
"""Run the test suite."""
|
|
71
89
|
verb = 2 if verbose else 1
|
|
90
|
+
test_suite = JacTestCheck.test_suite
|
|
91
|
+
|
|
92
|
+
if filepath and filepath.endswith(".test.jac"):
|
|
93
|
+
filepath = filepath[:-9]
|
|
94
|
+
elif filepath and filepath.endswith(".jac"):
|
|
95
|
+
filepath = filepath[:-4]
|
|
96
|
+
|
|
97
|
+
if filepath:
|
|
98
|
+
test_cases = JacTestCheck.test_suite_path.get(filepath)
|
|
99
|
+
if test_cases is not None:
|
|
100
|
+
test_suite = unittest.TestSuite()
|
|
101
|
+
for test_case in test_cases:
|
|
102
|
+
if func_name:
|
|
103
|
+
if test_case.func_name == func_name:
|
|
104
|
+
test_suite.addTest(test_case.test_case)
|
|
105
|
+
else:
|
|
106
|
+
test_suite.addTest(test_case.test_case)
|
|
107
|
+
|
|
108
|
+
elif func_name:
|
|
109
|
+
test_suite = unittest.TestSuite()
|
|
110
|
+
for test_cases in JacTestCheck.test_suite_path.values():
|
|
111
|
+
for test_case in test_cases:
|
|
112
|
+
if test_case.func_name == func_name:
|
|
113
|
+
test_suite.addTest(test_case.test_case)
|
|
114
|
+
|
|
72
115
|
runner = JacTextTestRunner(max_failures=maxfail, failfast=xit, verbosity=verb)
|
|
73
|
-
result = runner.run(
|
|
116
|
+
result = runner.run(test_suite)
|
|
74
117
|
if result.wasSuccessful():
|
|
75
118
|
print("Passed successfully.")
|
|
76
119
|
else:
|
|
@@ -81,9 +124,21 @@ class JacTestCheck:
|
|
|
81
124
|
)
|
|
82
125
|
|
|
83
126
|
@staticmethod
|
|
84
|
-
def add_test(
|
|
127
|
+
def add_test(filepath: str, func_name: str, test_func: Callable) -> None:
|
|
85
128
|
"""Create a new test."""
|
|
86
|
-
|
|
129
|
+
if filepath and filepath.endswith(".test.jac"):
|
|
130
|
+
filepath = filepath[:-9]
|
|
131
|
+
elif filepath and filepath.endswith(".jac"):
|
|
132
|
+
filepath = filepath[:-4]
|
|
133
|
+
|
|
134
|
+
if filepath not in JacTestCheck.test_suite_path:
|
|
135
|
+
JacTestCheck.test_suite_path[filepath] = []
|
|
136
|
+
|
|
137
|
+
test_case = unittest.FunctionTestCase(test_func)
|
|
138
|
+
JacTestCheck.test_suite_path[filepath].append(
|
|
139
|
+
JacTestCheck.TestSuite(test_case=test_case, func_name=func_name)
|
|
140
|
+
)
|
|
141
|
+
JacTestCheck.test_suite.addTest(test_case)
|
|
87
142
|
|
|
88
143
|
def __getattr__(self, name: str) -> object:
|
|
89
144
|
"""Make convenient check.Equal(...) etc."""
|
jaclang/runtimelib/utils.py
CHANGED
|
@@ -231,3 +231,18 @@ def is_instance(
|
|
|
231
231
|
return isinstance(obj, target)
|
|
232
232
|
case _:
|
|
233
233
|
return False
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def all_issubclass(
|
|
237
|
+
classes: type | UnionType | tuple[type | UnionType, ...], target: type
|
|
238
|
+
) -> bool:
|
|
239
|
+
"""Check if all classes is subclass of target type."""
|
|
240
|
+
match classes:
|
|
241
|
+
case type():
|
|
242
|
+
return issubclass(classes, target)
|
|
243
|
+
case UnionType():
|
|
244
|
+
return all((all_issubclass(cls, target) for cls in classes.__args__))
|
|
245
|
+
case tuple():
|
|
246
|
+
return all((all_issubclass(cls, target) for cls in classes))
|
|
247
|
+
case _:
|
|
248
|
+
return False
|
jaclang/settings.py
CHANGED
|
@@ -16,10 +16,13 @@ class Settings:
|
|
|
16
16
|
pass_timer: bool = False
|
|
17
17
|
collect_py_dep_debug: bool = False
|
|
18
18
|
print_py_raised_ast: bool = False
|
|
19
|
+
py_import_pass_debug: bool = False
|
|
20
|
+
inherit_pass_debug: bool = False
|
|
19
21
|
|
|
20
22
|
# Compiler configuration
|
|
21
23
|
disable_mtllm: bool = False
|
|
22
24
|
ignore_test_annex: bool = False
|
|
25
|
+
allow_import_from: bool = False
|
|
23
26
|
|
|
24
27
|
# Formatter configuration
|
|
25
28
|
max_line_length: int = 88
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import jactest_imported;
|
|
2
|
+
|
|
3
|
+
can fib(n: int) -> int {
|
|
4
|
+
if n <= 1 {
|
|
5
|
+
return n;
|
|
6
|
+
}
|
|
7
|
+
return fib(n - 1) + fib(n - 2);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
test first_two {
|
|
12
|
+
print("Testing first 2 fibonacci numbers.");
|
|
13
|
+
assert fib(0) == 0;
|
|
14
|
+
assert fib(1) == 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
test from_2_to_10 {
|
|
18
|
+
print("Testing fibonacci numbers from 2 to 10.");
|
|
19
|
+
for i in range(2, 10) {
|
|
20
|
+
assert fib(i) == fib(i - 1) + fib(i - 2);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import:py numpy as np;
|
|
2
|
-
|
|
3
1
|
with entry {
|
|
4
|
-
arr =
|
|
5
|
-
[[1, 2, 3, 4, 5],
|
|
2
|
+
arr = [[1, 2, 3, 4, 5],
|
|
6
3
|
[6, 7, 8, 9, 10],
|
|
7
4
|
[11, 12, 13, 14, 15],
|
|
8
5
|
[16, 17, 18, 19, 20],
|
|
9
|
-
[21, 22, 23, 24, 25]]
|
|
10
|
-
);
|
|
6
|
+
[21, 22, 23, 24, 25]];
|
|
11
7
|
|
|
12
8
|
print('Original Array:');
|
|
13
9
|
print(arr);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
node Node {
|
|
2
|
+
has val: str;
|
|
3
|
+
|
|
4
|
+
can entry1 with entry {
|
|
5
|
+
print(f"{self.val}-2");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
can entry2 with Walker entry {
|
|
9
|
+
print(f"{self.val}-3");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
can exit1 with Walker exit {
|
|
13
|
+
print(f"{self.val}-4");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
can exit2 with exit {
|
|
17
|
+
print(f"{self.val}-5");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
walker Walker {
|
|
22
|
+
can entry1 with entry {
|
|
23
|
+
print("walker entry");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
can entry2 with `root entry {
|
|
27
|
+
print("walker enter to root");
|
|
28
|
+
visit [-->];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
can entry3 with Node entry {
|
|
32
|
+
print(f"{here.val}-1");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
can exit1 with Node exit {
|
|
36
|
+
print(f"{here.val}-6");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
can exit2 with exit {
|
|
40
|
+
print("walker exit");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
with entry{
|
|
45
|
+
root ++> Node(val = "a");
|
|
46
|
+
root ++> Node(val = "b");
|
|
47
|
+
root ++> Node(val = "c");
|
|
48
|
+
|
|
49
|
+
Walker() spawn root;
|
|
50
|
+
}
|
jaclang/tests/test_cli.py
CHANGED
|
@@ -168,7 +168,7 @@ class JacCliTests(TestCase):
|
|
|
168
168
|
cli.tool("ir", ["ast", f"{self.fixture_abs_path('import.jac')}"])
|
|
169
169
|
|
|
170
170
|
sys.stdout = sys.__stdout__
|
|
171
|
-
stdout_value = captured_output.getvalue()
|
|
171
|
+
stdout_value = captured_output.getvalue().replace("\\", "/")
|
|
172
172
|
self.assertRegex(
|
|
173
173
|
stdout_value,
|
|
174
174
|
r"1\:11 \- 1\:13.*ModulePath - os - abs_path\:.*typeshed/stdlib/os/__init__.pyi",
|
|
@@ -233,6 +233,67 @@ class JacCliTests(TestCase):
|
|
|
233
233
|
r"13\:12 \- 13\:18.*Name - append - .*SymbolPath: builtins_test.builtins.list.append",
|
|
234
234
|
)
|
|
235
235
|
|
|
236
|
+
def test_import_all(self) -> None:
|
|
237
|
+
"""Testing for print AstTool."""
|
|
238
|
+
from jaclang.settings import settings
|
|
239
|
+
|
|
240
|
+
settings.ast_symbol_info_detailed = True
|
|
241
|
+
captured_output = io.StringIO()
|
|
242
|
+
sys.stdout = captured_output
|
|
243
|
+
|
|
244
|
+
cli.tool("ir", ["ast", f"{self.fixture_abs_path('import_all.jac')}"])
|
|
245
|
+
|
|
246
|
+
sys.stdout = sys.__stdout__
|
|
247
|
+
stdout_value = captured_output.getvalue()
|
|
248
|
+
settings.ast_symbol_info_detailed = False
|
|
249
|
+
|
|
250
|
+
self.assertRegex(
|
|
251
|
+
stdout_value,
|
|
252
|
+
r"6\:25 - 6\:30.*Name - floor -.*SymbolPath: import_all.import_all_py.floor",
|
|
253
|
+
)
|
|
254
|
+
self.assertRegex(
|
|
255
|
+
stdout_value,
|
|
256
|
+
r"5\:25 - 5\:27.*Name - pi -.*SymbolPath: import_all.import_all_py.pi",
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
def test_sub_class_symbol_table_fix_1(self) -> None:
|
|
260
|
+
"""Testing for print AstTool."""
|
|
261
|
+
from jaclang.settings import settings
|
|
262
|
+
|
|
263
|
+
settings.ast_symbol_info_detailed = True
|
|
264
|
+
captured_output = io.StringIO()
|
|
265
|
+
sys.stdout = captured_output
|
|
266
|
+
|
|
267
|
+
cli.tool("ir", ["ast", f"{self.fixture_abs_path('base_class1.jac')}"])
|
|
268
|
+
|
|
269
|
+
sys.stdout = sys.__stdout__
|
|
270
|
+
stdout_value = captured_output.getvalue()
|
|
271
|
+
settings.ast_symbol_info_detailed = False
|
|
272
|
+
|
|
273
|
+
self.assertRegex(
|
|
274
|
+
stdout_value,
|
|
275
|
+
r"10:7 - 10:12.*Name - start - Type.*SymbolPath: base_class1.B.start",
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
def test_sub_class_symbol_table_fix_2(self) -> None:
|
|
279
|
+
"""Testing for print AstTool."""
|
|
280
|
+
from jaclang.settings import settings
|
|
281
|
+
|
|
282
|
+
settings.ast_symbol_info_detailed = True
|
|
283
|
+
captured_output = io.StringIO()
|
|
284
|
+
sys.stdout = captured_output
|
|
285
|
+
|
|
286
|
+
cli.tool("ir", ["ast", f"{self.fixture_abs_path('base_class2.jac')}"])
|
|
287
|
+
|
|
288
|
+
sys.stdout = sys.__stdout__
|
|
289
|
+
stdout_value = captured_output.getvalue()
|
|
290
|
+
settings.ast_symbol_info_detailed = False
|
|
291
|
+
|
|
292
|
+
self.assertRegex(
|
|
293
|
+
stdout_value,
|
|
294
|
+
r"10:7 - 10:12.*Name - start - Type.*SymbolPath: base_class2.B.start",
|
|
295
|
+
)
|
|
296
|
+
|
|
236
297
|
def test_expr_types(self) -> None:
|
|
237
298
|
"""Testing for print AstTool."""
|
|
238
299
|
captured_output = io.StringIO()
|
|
@@ -393,6 +454,27 @@ class JacCliTests(TestCase):
|
|
|
393
454
|
self.assertIn("...F", stderr)
|
|
394
455
|
self.assertIn("F.F", stderr)
|
|
395
456
|
|
|
457
|
+
def test_run_specific_test_only(self) -> None:
|
|
458
|
+
"""Test a specific test case."""
|
|
459
|
+
process = subprocess.Popen(
|
|
460
|
+
[
|
|
461
|
+
"jac",
|
|
462
|
+
"test",
|
|
463
|
+
"-t",
|
|
464
|
+
"from_2_to_10",
|
|
465
|
+
self.fixture_abs_path("jactest_main.jac"),
|
|
466
|
+
],
|
|
467
|
+
stdin=subprocess.PIPE,
|
|
468
|
+
stdout=subprocess.PIPE,
|
|
469
|
+
stderr=subprocess.PIPE,
|
|
470
|
+
text=True,
|
|
471
|
+
)
|
|
472
|
+
stdout, stderr = process.communicate()
|
|
473
|
+
self.assertIn("Ran 1 test", stderr)
|
|
474
|
+
self.assertIn("Testing fibonacci numbers from 2 to 10.", stdout)
|
|
475
|
+
self.assertNotIn("Testing first 2 fibonacci numbers.", stdout)
|
|
476
|
+
self.assertNotIn("This test should not run after import.", stdout)
|
|
477
|
+
|
|
396
478
|
def test_graph_coverage(self) -> None:
|
|
397
479
|
"""Test for coverage of graph cmd."""
|
|
398
480
|
graph_params = set(inspect.signature(cli.dot).parameters.keys())
|
jaclang/tests/test_language.py
CHANGED
|
@@ -118,9 +118,9 @@ class JacLanguageTests(TestCase):
|
|
|
118
118
|
stdout_value = captured_output.getvalue()
|
|
119
119
|
|
|
120
120
|
expected_outputs = [
|
|
121
|
-
"+-- AtomTrailer - Type:
|
|
122
|
-
" +-- Name - arr - Type:
|
|
123
|
-
" +-- IndexSlice - [IndexSlice] - Type: builtins.
|
|
121
|
+
"+-- AtomTrailer - Type: builtins.list[builtins.int]",
|
|
122
|
+
" +-- Name - arr - Type: builtins.list[builtins.list[builtins.int]], SymbolTable: list",
|
|
123
|
+
" +-- IndexSlice - [IndexSlice] - Type: builtins.list[builtins.list[builtins.int]], SymbolTable: None",
|
|
124
124
|
" +-- Token - [,",
|
|
125
125
|
" +-- Int - 1 - Type: Literal[1]?, SymbolTable: None",
|
|
126
126
|
" +-- Token - :,",
|
|
@@ -548,7 +548,7 @@ class JacLanguageTests(TestCase):
|
|
|
548
548
|
return f"Error While Jac to Py AST conversion: {e}"
|
|
549
549
|
|
|
550
550
|
ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
|
|
551
|
-
self.assertEqual(len(ir.get_all_sub_nodes(ast.Architype)),
|
|
551
|
+
self.assertEqual(len(ir.get_all_sub_nodes(ast.Architype)), 21)
|
|
552
552
|
captured_output = io.StringIO()
|
|
553
553
|
sys.stdout = captured_output
|
|
554
554
|
jac_import("needs_import_1", base_path=self.fixture_abs_path("./"))
|
|
@@ -611,7 +611,7 @@ class JacLanguageTests(TestCase):
|
|
|
611
611
|
|
|
612
612
|
ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
|
|
613
613
|
self.assertEqual(
|
|
614
|
-
len(ir.get_all_sub_nodes(ast.Architype)),
|
|
614
|
+
len(ir.get_all_sub_nodes(ast.Architype)), 27
|
|
615
615
|
) # Because of the Architype from math
|
|
616
616
|
captured_output = io.StringIO()
|
|
617
617
|
sys.stdout = captured_output
|
|
@@ -665,7 +665,7 @@ class JacLanguageTests(TestCase):
|
|
|
665
665
|
|
|
666
666
|
ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
|
|
667
667
|
self.assertEqual(
|
|
668
|
-
len(ir.get_all_sub_nodes(ast.Architype)),
|
|
668
|
+
len(ir.get_all_sub_nodes(ast.Architype)), 75
|
|
669
669
|
) # Because of the Architype from other imports
|
|
670
670
|
captured_output = io.StringIO()
|
|
671
671
|
sys.stdout = captured_output
|
|
@@ -873,7 +873,7 @@ class JacLanguageTests(TestCase):
|
|
|
873
873
|
ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
|
|
874
874
|
jac_ast = ir.pp()
|
|
875
875
|
self.assertIn(" | +-- String - 'Loop completed normally{}'", jac_ast)
|
|
876
|
-
self.assertEqual(len(ir.get_all_sub_nodes(ast.SubNodeList)),
|
|
876
|
+
self.assertEqual(len(ir.get_all_sub_nodes(ast.SubNodeList)), 586)
|
|
877
877
|
captured_output = io.StringIO()
|
|
878
878
|
sys.stdout = captured_output
|
|
879
879
|
jac_import("deep_convert", base_path=self.fixture_abs_path("./"))
|
|
@@ -1230,5 +1230,20 @@ class JacLanguageTests(TestCase):
|
|
|
1230
1230
|
jac_import("architype_def_bug", base_path=self.fixture_abs_path("./"))
|
|
1231
1231
|
sys.stdout = sys.__stdout__
|
|
1232
1232
|
stdout_value = captured_output.getvalue().split("\n")
|
|
1233
|
-
self.assertIn("
|
|
1234
|
-
self.assertIn("
|
|
1233
|
+
self.assertIn("MyWalker", stdout_value[0])
|
|
1234
|
+
self.assertIn("MyNode", stdout_value[1])
|
|
1235
|
+
|
|
1236
|
+
def test_visit_sequence(self) -> None:
|
|
1237
|
+
"""Test conn assign on edges."""
|
|
1238
|
+
captured_output = io.StringIO()
|
|
1239
|
+
sys.stdout = captured_output
|
|
1240
|
+
jac_import("visit_sequence", base_path=self.fixture_abs_path("./"))
|
|
1241
|
+
sys.stdout = sys.__stdout__
|
|
1242
|
+
self.assertEqual(
|
|
1243
|
+
"walker entry\nwalker enter to root\n"
|
|
1244
|
+
"a-1\na-2\na-3\na-4\na-5\na-6\n"
|
|
1245
|
+
"b-1\nb-2\nb-3\nb-4\nb-5\nb-6\n"
|
|
1246
|
+
"c-1\nc-2\nc-3\nc-4\nc-5\nc-6\n"
|
|
1247
|
+
"walker exit\n",
|
|
1248
|
+
captured_output.getvalue(),
|
|
1249
|
+
)
|
jaclang/utils/helpers.py
CHANGED
|
@@ -165,7 +165,15 @@ def dump_traceback(e: Exception) -> str:
|
|
|
165
165
|
(frame.lineno is not None) and frame.line and frame.line.strip() != ""
|
|
166
166
|
):
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
# Note: This is CPython internals we're trying to get since python doesn't provide
|
|
169
|
+
# the frames original line but the stripped version so we had to do this.
|
|
170
|
+
line_o = frame.line # Fallback line.
|
|
171
|
+
if hasattr(frame, "_original_line"):
|
|
172
|
+
line_o = frame._original_line.rstrip() # type: ignore [attr-defined]
|
|
173
|
+
elif hasattr(frame, "_original_lines"):
|
|
174
|
+
# https://github.com/python/cpython/issues/106922
|
|
175
|
+
line_o = frame._original_lines.split("\n")[0].rstrip() # type: ignore [attr-defined]
|
|
176
|
+
|
|
169
177
|
if frame.colno is not None and frame.end_colno is not None:
|
|
170
178
|
off_start = byte_offset_to_char_offset(line_o, frame.colno) - 1
|
|
171
179
|
off_end = byte_offset_to_char_offset(line_o, frame.end_colno) - 1
|
jaclang/utils/test.py
CHANGED
|
@@ -41,12 +41,12 @@ class TestCase(_TestCase):
|
|
|
41
41
|
raise ValueError("Unable to determine the file of the module.")
|
|
42
42
|
fixture_src = module.__file__
|
|
43
43
|
fixture_path = os.path.join(os.path.dirname(fixture_src), "fixtures", fixture)
|
|
44
|
-
with open(fixture_path, "r") as f:
|
|
44
|
+
with open(fixture_path, "r", encoding="utf-8") as f:
|
|
45
45
|
return f.read()
|
|
46
46
|
|
|
47
47
|
def file_to_str(self, file_path: str) -> str:
|
|
48
48
|
"""Load fixture from fixtures directory."""
|
|
49
|
-
with open(file_path, "r") as f:
|
|
49
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
50
50
|
return f.read()
|
|
51
51
|
|
|
52
52
|
def fixture_abs_path(self, fixture: str) -> str:
|
|
@@ -107,8 +107,10 @@ class JacFormatPassTests(TestCase):
|
|
|
107
107
|
|
|
108
108
|
def test_sym_sym_dot(self) -> None:
|
|
109
109
|
"""Testing for sym, sym. AstTool."""
|
|
110
|
-
jac_file = os.path.
|
|
111
|
-
os.path.
|
|
110
|
+
jac_file = os.path.normpath(
|
|
111
|
+
os.path.join(
|
|
112
|
+
os.path.dirname(jaclang.__file__), "../examples/reference/atom.jac"
|
|
113
|
+
)
|
|
112
114
|
)
|
|
113
115
|
out = AstTool().ir(["sym", jac_file])
|
|
114
116
|
self.assertNotIn(
|