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.
- jaclang/cli/cli.py +2 -2
- jaclang/compiler/absyntree.py +539 -297
- jaclang/compiler/codeloc.py +2 -2
- jaclang/compiler/constant.py +100 -2
- jaclang/compiler/jac.lark +27 -19
- jaclang/compiler/parser.py +119 -92
- jaclang/compiler/passes/main/access_modifier_pass.py +20 -12
- jaclang/compiler/passes/main/def_impl_match_pass.py +32 -12
- jaclang/compiler/passes/main/def_use_pass.py +59 -40
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +71 -30
- jaclang/compiler/passes/main/import_pass.py +12 -7
- jaclang/compiler/passes/main/pyast_gen_pass.py +110 -47
- jaclang/compiler/passes/main/pyast_load_pass.py +49 -13
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +25 -11
- jaclang/compiler/passes/main/pyout_pass.py +3 -1
- jaclang/compiler/passes/main/registry_pass.py +6 -6
- jaclang/compiler/passes/main/sub_node_tab_pass.py +0 -5
- jaclang/compiler/passes/main/sym_tab_build_pass.py +43 -235
- jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +21 -4
- jaclang/compiler/passes/main/tests/test_def_use_pass.py +5 -10
- jaclang/compiler/passes/main/tests/test_import_pass.py +8 -0
- jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
- jaclang/compiler/passes/main/type_check_pass.py +2 -1
- jaclang/compiler/passes/tool/jac_formatter_pass.py +44 -11
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +16 -0
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +16 -0
- jaclang/compiler/passes/tool/tests/fixtures/doc_string.jac +15 -0
- jaclang/compiler/passes/tool/tests/fixtures/genai/essay_review.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/expert_answer.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/joke_gen.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/odd_word_out.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/personality_finder.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/text_to_type.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/translator.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/wikipedia.jac +1 -1
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +7 -5
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
- jaclang/compiler/passes/transform.py +2 -4
- jaclang/{core/registry.py → compiler/semtable.py} +1 -3
- jaclang/compiler/symtable.py +150 -89
- jaclang/compiler/tests/test_parser.py +2 -2
- jaclang/core/aott.py +118 -18
- jaclang/core/{construct.py → architype.py} +44 -93
- jaclang/core/constructs.py +44 -0
- jaclang/core/context.py +157 -0
- jaclang/core/importer.py +18 -9
- jaclang/core/memory.py +53 -2
- jaclang/core/test.py +90 -0
- jaclang/core/utils.py +2 -2
- jaclang/langserve/engine.py +199 -138
- jaclang/langserve/server.py +48 -53
- jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -0
- jaclang/langserve/tests/fixtures/circle.jac +16 -12
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.impl.jac +8 -4
- jaclang/langserve/tests/fixtures/circle_pure.jac +2 -2
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +15 -0
- jaclang/langserve/tests/fixtures/import_include_statements.jac +6 -0
- jaclang/langserve/tests/fixtures/py_import.py +26 -0
- jaclang/langserve/tests/test_server.py +200 -2
- jaclang/langserve/utils.py +214 -10
- jaclang/plugin/builtin.py +1 -1
- jaclang/plugin/default.py +48 -92
- jaclang/plugin/feature.py +33 -17
- jaclang/plugin/spec.py +18 -20
- jaclang/plugin/tests/test_features.py +0 -33
- jaclang/settings.py +4 -0
- jaclang/tests/fixtures/abc.jac +16 -12
- jaclang/tests/fixtures/aott_raise.jac +1 -1
- jaclang/tests/fixtures/byllmissue.jac +12 -0
- jaclang/tests/fixtures/edgetypeissue.jac +10 -0
- jaclang/tests/fixtures/hash_init_check.jac +17 -0
- jaclang/tests/fixtures/hello.jac +1 -1
- jaclang/tests/fixtures/impl_match_confused.impl.jac +1 -0
- jaclang/tests/fixtures/impl_match_confused.jac +5 -0
- jaclang/tests/fixtures/math_question.jpg +0 -0
- jaclang/tests/fixtures/maxfail_run_test.jac +17 -5
- jaclang/tests/fixtures/nosigself.jac +19 -0
- jaclang/tests/fixtures/run_test.jac +17 -5
- jaclang/tests/fixtures/walker_override.jac +21 -0
- jaclang/tests/fixtures/with_llm_function.jac +1 -1
- jaclang/tests/fixtures/with_llm_lower.jac +1 -1
- jaclang/tests/fixtures/with_llm_method.jac +1 -1
- jaclang/tests/fixtures/with_llm_type.jac +1 -1
- jaclang/tests/fixtures/with_llm_vision.jac +25 -0
- jaclang/tests/test_bugs.py +19 -0
- jaclang/tests/test_cli.py +1 -1
- jaclang/tests/test_language.py +197 -82
- jaclang/tests/test_reference.py +1 -1
- jaclang/utils/lang_tools.py +5 -4
- jaclang/utils/test.py +2 -1
- jaclang/utils/treeprinter.py +35 -4
- {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/METADATA +3 -2
- {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/RECORD +96 -88
- jaclang/core/llms/__init__.py +0 -20
- jaclang/core/llms/anthropic.py +0 -61
- jaclang/core/llms/base.py +0 -206
- jaclang/core/llms/groq.py +0 -67
- jaclang/core/llms/huggingface.py +0 -73
- jaclang/core/llms/ollama.py +0 -78
- jaclang/core/llms/openai.py +0 -61
- jaclang/core/llms/togetherai.py +0 -60
- jaclang/core/llms/utils.py +0 -9
- jaclang/core/shelve_storage.py +0 -55
- {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/WHEEL +0 -0
- {jaclang-0.7.1.dist-info → jaclang-0.7.7.dist-info}/entry_points.txt +0 -0
|
@@ -8,9 +8,9 @@ import os
|
|
|
8
8
|
import pathlib
|
|
9
9
|
import sys
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
import jaclang.compiler.absyntree as ast
|
|
13
12
|
import jaclang.compiler.passes.utils.mypy_ast_build as myab
|
|
13
|
+
from jaclang.compiler.constant import Constants as Con
|
|
14
14
|
from jaclang.compiler.passes import Pass
|
|
15
15
|
|
|
16
16
|
|
|
@@ -48,6 +48,7 @@ class JacTypeCheckPass(Pass):
|
|
|
48
48
|
"""Call mypy APIs to implement type checking in Jac."""
|
|
49
49
|
# Creating mypy api objects
|
|
50
50
|
options = myab.myb.Options()
|
|
51
|
+
options.cache_dir = Con.JAC_MYPY_CACHE
|
|
51
52
|
errors = myab.Errors(self, options)
|
|
52
53
|
fs_cache = myab.FileSystemCache()
|
|
53
54
|
search_paths = myab.compute_search_paths([], options, str(self.__path))
|
|
@@ -421,7 +421,10 @@ class JacFormatPass(Pass):
|
|
|
421
421
|
self.emit_ln(node, "")
|
|
422
422
|
self.emit_ln(node, i.gen.jac)
|
|
423
423
|
if isinstance(i, ast.Token) and i.name == Tok.KW_BY:
|
|
424
|
-
|
|
424
|
+
if not node.params:
|
|
425
|
+
self.emit(node, f"{i.gen.jac} ")
|
|
426
|
+
else:
|
|
427
|
+
self.emit(node, f" {i.gen.jac} ")
|
|
425
428
|
else:
|
|
426
429
|
if (
|
|
427
430
|
line_break_needed
|
|
@@ -481,7 +484,7 @@ class JacFormatPass(Pass):
|
|
|
481
484
|
|
|
482
485
|
var: Token,
|
|
483
486
|
"""
|
|
484
|
-
self.emit(node, node.
|
|
487
|
+
self.emit(node, node.orig.value)
|
|
485
488
|
|
|
486
489
|
def exit_ability_def(self, node: ast.AbilityDef) -> None:
|
|
487
490
|
"""Sub objects.
|
|
@@ -1868,6 +1871,32 @@ class JacFormatPass(Pass):
|
|
|
1868
1871
|
if isinstance(node.kid[-1], (ast.Semi, ast.CommentToken)):
|
|
1869
1872
|
self.emit_ln(node, "")
|
|
1870
1873
|
|
|
1874
|
+
def exit_check_stmt(self, node: ast.CheckStmt) -> None:
|
|
1875
|
+
"""Sub objects.
|
|
1876
|
+
|
|
1877
|
+
target: ExprType,
|
|
1878
|
+
"""
|
|
1879
|
+
start = True
|
|
1880
|
+
for i in node.kid:
|
|
1881
|
+
if isinstance(i, ast.CommentToken):
|
|
1882
|
+
if i.is_inline:
|
|
1883
|
+
self.emit(node, f" {i.gen.jac}")
|
|
1884
|
+
else:
|
|
1885
|
+
if not node.gen.jac.endswith("\n"):
|
|
1886
|
+
self.emit_ln(node, "")
|
|
1887
|
+
self.emit_ln(node, "")
|
|
1888
|
+
self.emit(node, i.gen.jac)
|
|
1889
|
+
elif isinstance(i, ast.Semi):
|
|
1890
|
+
self.emit(node, i.gen.jac)
|
|
1891
|
+
else:
|
|
1892
|
+
if start:
|
|
1893
|
+
self.emit(node, i.gen.jac)
|
|
1894
|
+
start = False
|
|
1895
|
+
else:
|
|
1896
|
+
self.emit(node, f" {i.gen.jac}")
|
|
1897
|
+
if isinstance(node.kid[-1], (ast.Semi, ast.CommentToken)):
|
|
1898
|
+
self.emit_ln(node, "")
|
|
1899
|
+
|
|
1871
1900
|
def exit_ctrl_stmt(self, node: ast.CtrlStmt) -> None:
|
|
1872
1901
|
"""Sub objects.
|
|
1873
1902
|
|
|
@@ -1999,7 +2028,6 @@ class JacFormatPass(Pass):
|
|
|
1999
2028
|
doc: Optional[Token],
|
|
2000
2029
|
body: CodeBlock,
|
|
2001
2030
|
"""
|
|
2002
|
-
start = True
|
|
2003
2031
|
for i in node.kid:
|
|
2004
2032
|
if isinstance(i, ast.CommentToken):
|
|
2005
2033
|
if i.is_inline:
|
|
@@ -2010,14 +2038,10 @@ class JacFormatPass(Pass):
|
|
|
2010
2038
|
elif isinstance(i, ast.Semi):
|
|
2011
2039
|
self.emit(node, i.gen.jac)
|
|
2012
2040
|
elif isinstance(i, ast.Name):
|
|
2013
|
-
if not i.value.startswith("
|
|
2014
|
-
self.emit(node, f" {i.value}
|
|
2041
|
+
if not i.value.startswith("_jac_gen_"):
|
|
2042
|
+
self.emit(node, f" {i.value}")
|
|
2015
2043
|
else:
|
|
2016
|
-
|
|
2017
|
-
self.emit(node, i.gen.jac)
|
|
2018
|
-
start = False
|
|
2019
|
-
else:
|
|
2020
|
-
self.emit(node, f" {i.gen.jac}")
|
|
2044
|
+
self.emit(node, i.gen.jac)
|
|
2021
2045
|
if isinstance(node.kid[-1], (ast.Semi, ast.CommentToken)):
|
|
2022
2046
|
self.emit_ln(node, "")
|
|
2023
2047
|
|
|
@@ -2402,7 +2426,16 @@ class JacFormatPass(Pass):
|
|
|
2402
2426
|
and isinstance(node.parent.parent, ast.FString)
|
|
2403
2427
|
):
|
|
2404
2428
|
self.emit(node, node.value)
|
|
2405
|
-
|
|
2429
|
+
if "\n" in node.value:
|
|
2430
|
+
string_type = node.value[0:3]
|
|
2431
|
+
pure_string = node.value[3:-3]
|
|
2432
|
+
lines = pure_string.split("\n")
|
|
2433
|
+
self.emit(node, string_type)
|
|
2434
|
+
for line in lines[:-1]:
|
|
2435
|
+
self.emit_ln(node, line)
|
|
2436
|
+
self.emit_ln(node, f"{lines[-1]}{string_type}")
|
|
2437
|
+
else:
|
|
2438
|
+
self.emit(node, node.value)
|
|
2406
2439
|
|
|
2407
2440
|
def enter_bool(self, node: ast.Bool) -> None:
|
|
2408
2441
|
"""Sub objects.
|
|
@@ -478,3 +478,19 @@ obj JacPlugin {
|
|
|
478
478
|
(walker_obj: Any, expr: Any) -> bool {
|
|
479
479
|
return walker_obj._jac_.visit_node(expr);
|
|
480
480
|
}
|
|
481
|
+
|
|
482
|
+
glob expected_area = 78.53981633974483;
|
|
483
|
+
|
|
484
|
+
test a1 {
|
|
485
|
+
check assertAlmostEqual(calculate_area(RAD), expected_area);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
test a2 {
|
|
489
|
+
c = Circle(RAD);
|
|
490
|
+
check assertAlmostEqual(c.area(), expected_area);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
test a3 {
|
|
494
|
+
c = Circle(RAD);
|
|
495
|
+
check assertEqual(c.shape_type, ShapeType.CIRCLE);
|
|
496
|
+
}
|
|
@@ -478,3 +478,19 @@ obj JacPlugin {
|
|
|
478
478
|
(walker_obj: Any, expr: Any) -> bool {
|
|
479
479
|
return walker_obj._jac_.visit_node(expr);
|
|
480
480
|
}
|
|
481
|
+
|
|
482
|
+
glob expected_area = 78.53981633974483;
|
|
483
|
+
|
|
484
|
+
test a1 {
|
|
485
|
+
check assertAlmostEqual(calculate_area(RAD), expected_area);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
test a2 {
|
|
489
|
+
c = Circle(RAD);
|
|
490
|
+
check assertAlmostEqual(c.area(), expected_area);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
test a3 {
|
|
494
|
+
c = Circle(RAD);
|
|
495
|
+
check assertEqual(c.shape_type, ShapeType.CIRCLE);
|
|
496
|
+
}
|
|
@@ -44,8 +44,8 @@ class JacFormatPassTests(TestCaseMicroSuite, AstSyncTestMixin):
|
|
|
44
44
|
|
|
45
45
|
if diff:
|
|
46
46
|
print(f"Differences found in comparison:\n{diff}")
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
raise AssertionError("Files differ after formatting.")
|
|
48
|
+
|
|
49
49
|
except FileNotFoundError:
|
|
50
50
|
print(f"File not found: {original_file} or {formatted_file}")
|
|
51
51
|
raise
|
|
@@ -76,6 +76,9 @@ class JacFormatPassTests(TestCaseMicroSuite, AstSyncTestMixin):
|
|
|
76
76
|
self.compare_files(
|
|
77
77
|
os.path.join(self.fixture_abs_path(""), "corelib_fmt.jac"),
|
|
78
78
|
)
|
|
79
|
+
self.compare_files(
|
|
80
|
+
os.path.join(self.fixture_abs_path(""), "doc_string.jac"),
|
|
81
|
+
)
|
|
79
82
|
|
|
80
83
|
def test_compare_myca_fixtures(self) -> None:
|
|
81
84
|
"""Tests if files in the myca fixtures directory do not change after being formatted."""
|
|
@@ -135,14 +138,13 @@ class JacFormatPassTests(TestCaseMicroSuite, AstSyncTestMixin):
|
|
|
135
138
|
diff = "\n".join(unified_diff(before.splitlines(), after.splitlines()))
|
|
136
139
|
self.assertFalse(diff, "AST structures differ after formatting.")
|
|
137
140
|
|
|
138
|
-
except Exception:
|
|
141
|
+
except Exception as e:
|
|
139
142
|
print(add_line_numbers(code_gen_pure.ir.source.code))
|
|
140
143
|
print("\n+++++++++++++++++++++++++++++++++++++++\n")
|
|
141
144
|
print(add_line_numbers(code_gen_format.ir.gen.jac))
|
|
142
145
|
print("\n+++++++++++++++++++++++++++++++++++++++\n")
|
|
143
146
|
print("\n".join(unified_diff(before.splitlines(), after.splitlines())))
|
|
144
|
-
|
|
145
|
-
# raise e
|
|
147
|
+
raise e
|
|
146
148
|
|
|
147
149
|
|
|
148
150
|
JacFormatPassTests.self_attach_micro_tests()
|
|
@@ -30,7 +30,7 @@ class JacUnparseTests(TestCaseMicroSuite, AstSyncTestMixin):
|
|
|
30
30
|
self.assertEqual(x, y)
|
|
31
31
|
except Exception as e:
|
|
32
32
|
print("\n".join(unified_diff(x.splitlines(), y.splitlines())))
|
|
33
|
-
|
|
33
|
+
raise e
|
|
34
34
|
|
|
35
35
|
def micro_suite_test(self, filename: str) -> None:
|
|
36
36
|
"""Parse micro jac file."""
|
|
@@ -75,7 +75,6 @@ class JacUnparseTests(TestCaseMicroSuite, AstSyncTestMixin):
|
|
|
75
75
|
|
|
76
76
|
except Exception as e:
|
|
77
77
|
raise e
|
|
78
|
-
# self.skipTest(f"Test failed, but skipping instead of failing: {e}")
|
|
79
78
|
|
|
80
79
|
|
|
81
80
|
JacUnparseTests.self_attach_micro_tests()
|
|
@@ -22,7 +22,7 @@ class Alert:
|
|
|
22
22
|
def __str__(self) -> str:
|
|
23
23
|
"""Return string representation of alert."""
|
|
24
24
|
return (
|
|
25
|
-
f"{self.loc.mod_path}, line {self.loc.first_line},"
|
|
25
|
+
f" {self.loc.mod_path}, line {self.loc.first_line},"
|
|
26
26
|
f" col {self.loc.col_start}: {self.msg}"
|
|
27
27
|
)
|
|
28
28
|
|
|
@@ -40,7 +40,7 @@ class Transform(ABC, Generic[T]):
|
|
|
40
40
|
prior: Optional[Transform] = None,
|
|
41
41
|
) -> None:
|
|
42
42
|
"""Initialize pass."""
|
|
43
|
-
self.logger = logging.getLogger(self.__class__.
|
|
43
|
+
self.logger = logging.getLogger(self.__class__.__name__)
|
|
44
44
|
self.errors_had: list[Alert] = [] if not prior else prior.errors_had
|
|
45
45
|
self.warnings_had: list[Alert] = [] if not prior else prior.warnings_had
|
|
46
46
|
self.cur_node: AstNode = input_ir # tracks current node during traversal
|
|
@@ -59,7 +59,6 @@ class Transform(ABC, Generic[T]):
|
|
|
59
59
|
self.__class__,
|
|
60
60
|
)
|
|
61
61
|
self.errors_had.append(alrt)
|
|
62
|
-
# print("Error:", str(alrt))
|
|
63
62
|
self.logger.error(str(alrt))
|
|
64
63
|
|
|
65
64
|
def log_warning(self, msg: str, node_override: Optional[AstNode] = None) -> None:
|
|
@@ -70,5 +69,4 @@ class Transform(ABC, Generic[T]):
|
|
|
70
69
|
self.__class__,
|
|
71
70
|
)
|
|
72
71
|
self.warnings_had.append(alrt)
|
|
73
|
-
# print("Warning:", str(alrt))
|
|
74
72
|
self.logger.warning(str(alrt))
|
|
@@ -12,9 +12,7 @@ from typing import Optional
|
|
|
12
12
|
class SemInfo:
|
|
13
13
|
"""Semantic information class."""
|
|
14
14
|
|
|
15
|
-
def __init__(
|
|
16
|
-
self, name: str, type: Optional[str] = None, semstr: Optional[str] = None
|
|
17
|
-
) -> None:
|
|
15
|
+
def __init__(self, name: str, type: Optional[str] = None, semstr: str = "") -> None:
|
|
18
16
|
"""Initialize the class."""
|
|
19
17
|
self.name = name
|
|
20
18
|
self.type = type
|
jaclang/compiler/symtable.py
CHANGED
|
@@ -2,71 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
from typing import Optional,
|
|
5
|
+
import ast as ast3
|
|
6
|
+
from typing import Optional, Sequence
|
|
7
7
|
|
|
8
|
+
import jaclang.compiler.absyntree as ast
|
|
9
|
+
from jaclang.compiler.constant import SymbolAccess, SymbolType
|
|
8
10
|
from jaclang.utils.treeprinter import dotgen_symtab_tree, print_symtab_tree
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
import jaclang.compiler.absyntree as ast
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class SymbolType(Enum):
|
|
16
|
-
"""Symbol types."""
|
|
17
|
-
|
|
18
|
-
MODULE = "module" # LSP: Module
|
|
19
|
-
MOD_VAR = "mod_var" # LSP: Variable
|
|
20
|
-
VAR = "var" # LSP: Variable
|
|
21
|
-
IMM_VAR = "immutable" # LSP: Constant
|
|
22
|
-
ABILITY = "ability" # LSP: Function
|
|
23
|
-
OBJECT_ARCH = "object" # LSP: Class
|
|
24
|
-
NODE_ARCH = "node" # LSP: Class
|
|
25
|
-
EDGE_ARCH = "edge" # LSP: Class
|
|
26
|
-
WALKER_ARCH = "walker" # LSP: Class
|
|
27
|
-
ENUM_ARCH = "enum" # LSP: Enum
|
|
28
|
-
TEST = "test" # LSP: Function
|
|
29
|
-
TYPE = "type" # LSP: TypeParameter
|
|
30
|
-
IMPL = "impl" # LSP: Interface or Property
|
|
31
|
-
HAS_VAR = "field" # LSP: Field
|
|
32
|
-
METHOD = "method" # LSP: Method
|
|
33
|
-
CONSTRUCTOR = "constructor" # LSP: Constructor
|
|
34
|
-
ENUM_MEMBER = "enum_member" # LSP: EnumMember
|
|
35
|
-
NUMBER = "number" # LSP: Number
|
|
36
|
-
STRING = "string" # LSP: String
|
|
37
|
-
BOOL = "bool" # LSP: Boolean
|
|
38
|
-
SEQUENCE = "sequence" # LSP: Array
|
|
39
|
-
NULL = "null" # LSP: Null
|
|
40
|
-
|
|
41
|
-
def __str__(self) -> str:
|
|
42
|
-
"""Stringify."""
|
|
43
|
-
return self.value
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class SymbolInfo:
|
|
47
|
-
"""Symbol Info."""
|
|
48
|
-
|
|
49
|
-
def __init__(
|
|
50
|
-
self, typ: str = "NoType", acc_tag: Optional[SymbolAccess] = None
|
|
51
|
-
) -> None: # noqa: ANN401
|
|
52
|
-
"""Initialize."""
|
|
53
|
-
self.typ = typ
|
|
54
|
-
self.acc_tag: Optional[SymbolAccess] = acc_tag
|
|
55
|
-
self.typ_sym_table: Optional[SymbolTable] = None
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class SymbolAccess(Enum):
|
|
59
|
-
"""Symbol types."""
|
|
60
|
-
|
|
61
|
-
PRIVATE = "private"
|
|
62
|
-
PUBLIC = "public"
|
|
63
|
-
PROTECTED = "protected"
|
|
64
|
-
|
|
65
|
-
def __str__(self) -> str:
|
|
66
|
-
"""Stringify."""
|
|
67
|
-
return self.value
|
|
68
|
-
|
|
69
|
-
|
|
70
13
|
# Symbols can have mulitple definitions but resolves decl to be the
|
|
71
14
|
# first such definition in a given scope.
|
|
72
15
|
class Symbol:
|
|
@@ -74,20 +17,19 @@ class Symbol:
|
|
|
74
17
|
|
|
75
18
|
def __init__(
|
|
76
19
|
self,
|
|
77
|
-
defn: ast.
|
|
20
|
+
defn: ast.NameAtom,
|
|
78
21
|
access: SymbolAccess,
|
|
79
22
|
parent_tab: SymbolTable,
|
|
80
|
-
typ: Optional[type] = None,
|
|
81
23
|
) -> None:
|
|
82
24
|
"""Initialize."""
|
|
83
|
-
self.
|
|
84
|
-
self.
|
|
85
|
-
defn.
|
|
86
|
-
self.access = access
|
|
25
|
+
self.defn: list[ast.NameAtom] = [defn]
|
|
26
|
+
self.uses: list[ast.NameAtom] = []
|
|
27
|
+
defn.sym = self
|
|
28
|
+
self.access: SymbolAccess = access
|
|
87
29
|
self.parent_tab = parent_tab
|
|
88
30
|
|
|
89
31
|
@property
|
|
90
|
-
def decl(self) -> ast.
|
|
32
|
+
def decl(self) -> ast.NameAtom:
|
|
91
33
|
"""Get decl."""
|
|
92
34
|
return self.defn[0]
|
|
93
35
|
|
|
@@ -99,19 +41,32 @@ class Symbol:
|
|
|
99
41
|
@property
|
|
100
42
|
def sym_type(self) -> SymbolType:
|
|
101
43
|
"""Get sym_type."""
|
|
102
|
-
return self.decl.
|
|
44
|
+
return self.decl.sym_category
|
|
103
45
|
|
|
104
|
-
|
|
46
|
+
@property
|
|
47
|
+
def sym_dotted_name(self) -> str:
|
|
48
|
+
"""Return a full path of the symbol."""
|
|
49
|
+
out = [self.defn[0].sym_name]
|
|
50
|
+
current_tab: SymbolTable | None = self.parent_tab
|
|
51
|
+
while current_tab is not None:
|
|
52
|
+
out.append(current_tab.name)
|
|
53
|
+
current_tab = current_tab.parent
|
|
54
|
+
out.reverse()
|
|
55
|
+
return ".".join(out)
|
|
56
|
+
|
|
57
|
+
def add_defn(self, node: ast.NameAtom) -> None:
|
|
105
58
|
"""Add defn."""
|
|
106
59
|
self.defn.append(node)
|
|
107
|
-
node.
|
|
60
|
+
node.sym = self
|
|
61
|
+
|
|
62
|
+
def add_use(self, node: ast.NameAtom) -> None:
|
|
63
|
+
"""Add use."""
|
|
64
|
+
self.uses.append(node)
|
|
65
|
+
node.sym = self
|
|
108
66
|
|
|
109
67
|
def __repr__(self) -> str:
|
|
110
68
|
"""Repr."""
|
|
111
|
-
return (
|
|
112
|
-
f"Symbol({self.sym_name}, {self.sym_type}, {self.access}, "
|
|
113
|
-
f"{self.typ}, {self.defn})"
|
|
114
|
-
)
|
|
69
|
+
return f"Symbol({self.sym_name}, {self.sym_type}, {self.access}, {self.defn})"
|
|
115
70
|
|
|
116
71
|
|
|
117
72
|
class SymbolTable:
|
|
@@ -123,27 +78,25 @@ class SymbolTable:
|
|
|
123
78
|
"""Initialize."""
|
|
124
79
|
self.name = name
|
|
125
80
|
self.owner = owner
|
|
126
|
-
self.parent = parent
|
|
81
|
+
self.parent = parent
|
|
127
82
|
self.kid: list[SymbolTable] = []
|
|
128
83
|
self.tab: dict[str, Symbol] = {}
|
|
129
|
-
self.
|
|
84
|
+
self.inherit: list[SymbolTable] = []
|
|
130
85
|
|
|
131
|
-
def
|
|
132
|
-
"""Check if has parent."""
|
|
133
|
-
return self.parent != self
|
|
134
|
-
|
|
135
|
-
def get_parent(self) -> SymbolTable:
|
|
86
|
+
def get_parent(self) -> Optional[SymbolTable]:
|
|
136
87
|
"""Get parent."""
|
|
137
|
-
if self.parent == self:
|
|
138
|
-
raise Exception("No parent")
|
|
139
88
|
return self.parent
|
|
140
89
|
|
|
141
90
|
def lookup(self, name: str, deep: bool = True) -> Optional[Symbol]:
|
|
142
91
|
"""Lookup a variable in the symbol table."""
|
|
143
92
|
if name in self.tab:
|
|
144
93
|
return self.tab[name]
|
|
145
|
-
|
|
146
|
-
|
|
94
|
+
for i in self.inherit:
|
|
95
|
+
found = i.lookup(name, deep=False)
|
|
96
|
+
if found:
|
|
97
|
+
return found
|
|
98
|
+
if deep and self.parent:
|
|
99
|
+
return self.parent.lookup(name, deep)
|
|
147
100
|
return None
|
|
148
101
|
|
|
149
102
|
def insert(
|
|
@@ -164,7 +117,7 @@ class SymbolTable:
|
|
|
164
117
|
)
|
|
165
118
|
if node.sym_name not in self.tab:
|
|
166
119
|
self.tab[node.sym_name] = Symbol(
|
|
167
|
-
defn=node,
|
|
120
|
+
defn=node.name_spec,
|
|
168
121
|
access=(
|
|
169
122
|
access_spec
|
|
170
123
|
if isinstance(access_spec, SymbolAccess)
|
|
@@ -173,8 +126,8 @@ class SymbolTable:
|
|
|
173
126
|
parent_tab=self,
|
|
174
127
|
)
|
|
175
128
|
else:
|
|
176
|
-
self.tab[node.sym_name].add_defn(node)
|
|
177
|
-
node.
|
|
129
|
+
self.tab[node.sym_name].add_defn(node.name_spec)
|
|
130
|
+
node.name_spec.sym = self.tab[node.sym_name]
|
|
178
131
|
return collision
|
|
179
132
|
|
|
180
133
|
def find_scope(self, name: str) -> Optional[SymbolTable]:
|
|
@@ -189,6 +142,114 @@ class SymbolTable:
|
|
|
189
142
|
self.kid.append(SymbolTable(name, key_node, self))
|
|
190
143
|
return self.kid[-1]
|
|
191
144
|
|
|
145
|
+
def inherit_sym_tab(self, target_sym_tab: SymbolTable) -> None:
|
|
146
|
+
"""Inherit symbol table."""
|
|
147
|
+
for i in target_sym_tab.tab.values():
|
|
148
|
+
self.def_insert(i.decl, access_spec=i.access)
|
|
149
|
+
|
|
150
|
+
def def_insert(
|
|
151
|
+
self,
|
|
152
|
+
node: ast.AstSymbolNode,
|
|
153
|
+
access_spec: Optional[ast.AstAccessNode] | SymbolAccess = None,
|
|
154
|
+
single_decl: Optional[str] = None,
|
|
155
|
+
) -> Optional[Symbol]:
|
|
156
|
+
"""Insert into symbol table."""
|
|
157
|
+
if node.sym and self == node.sym.parent_tab:
|
|
158
|
+
return node.sym
|
|
159
|
+
self.insert(node=node, single=single_decl is not None, access_spec=access_spec)
|
|
160
|
+
self.update_py_ctx_for_def(node)
|
|
161
|
+
return node.sym
|
|
162
|
+
|
|
163
|
+
def chain_def_insert(self, node_list: list[ast.AstSymbolNode]) -> None:
|
|
164
|
+
"""Link chain of containing names to symbol."""
|
|
165
|
+
if not node_list:
|
|
166
|
+
return
|
|
167
|
+
cur_sym_tab: SymbolTable | None = node_list[0].sym_tab
|
|
168
|
+
node_list[-1].name_spec.py_ctx_func = ast3.Store
|
|
169
|
+
if isinstance(node_list[-1].name_spec, ast.AstSymbolNode):
|
|
170
|
+
node_list[-1].name_spec.py_ctx_func = ast3.Store
|
|
171
|
+
|
|
172
|
+
node_list = node_list[:-1] # Just performs lookup mappings of pre assign chain
|
|
173
|
+
for i in node_list:
|
|
174
|
+
cur_sym_tab = (
|
|
175
|
+
lookup.decl.sym_tab
|
|
176
|
+
if (
|
|
177
|
+
lookup := self.use_lookup(
|
|
178
|
+
i,
|
|
179
|
+
sym_table=cur_sym_tab,
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
else None
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
def use_lookup(
|
|
186
|
+
self,
|
|
187
|
+
node: ast.AstSymbolNode,
|
|
188
|
+
sym_table: Optional[SymbolTable] = None,
|
|
189
|
+
) -> Optional[Symbol]:
|
|
190
|
+
"""Link to symbol."""
|
|
191
|
+
if node.sym:
|
|
192
|
+
return node.sym
|
|
193
|
+
if not sym_table:
|
|
194
|
+
sym_table = node.sym_tab
|
|
195
|
+
if sym_table:
|
|
196
|
+
lookup = sym_table.lookup(name=node.sym_name, deep=True)
|
|
197
|
+
lookup.add_use(node.name_spec) if lookup else None
|
|
198
|
+
return node.sym
|
|
199
|
+
|
|
200
|
+
def chain_use_lookup(self, node_list: Sequence[ast.AstSymbolNode]) -> None:
|
|
201
|
+
"""Link chain of containing names to symbol."""
|
|
202
|
+
if not node_list:
|
|
203
|
+
return
|
|
204
|
+
cur_sym_tab: SymbolTable | None = node_list[0].sym_tab
|
|
205
|
+
for i in node_list:
|
|
206
|
+
if cur_sym_tab is None:
|
|
207
|
+
break
|
|
208
|
+
cur_sym_tab = (
|
|
209
|
+
lookup.decl.sym_tab
|
|
210
|
+
if (
|
|
211
|
+
lookup := self.use_lookup(
|
|
212
|
+
i,
|
|
213
|
+
sym_table=cur_sym_tab,
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
else None
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def update_py_ctx_for_def(self, node: ast.AstSymbolNode) -> None:
|
|
220
|
+
"""Update python context for definition."""
|
|
221
|
+
node.name_spec.py_ctx_func = ast3.Store
|
|
222
|
+
if isinstance(node, (ast.TupleVal, ast.ListVal)) and node.values:
|
|
223
|
+
# Handling of UnaryExpr case for item is only necessary for
|
|
224
|
+
# the generation of Starred nodes in the AST for examples
|
|
225
|
+
# like `(a, *b) = (1, 2, 3, 4)`.
|
|
226
|
+
def fix(item: ast.TupleVal | ast.ListVal | ast.UnaryExpr) -> None:
|
|
227
|
+
if isinstance(item, ast.UnaryExpr):
|
|
228
|
+
if isinstance(item.operand, ast.AstSymbolNode):
|
|
229
|
+
item.operand.name_spec.py_ctx_func = ast3.Store
|
|
230
|
+
elif isinstance(item, (ast.TupleVal, ast.ListVal)):
|
|
231
|
+
for i in item.values.items if item.values else []:
|
|
232
|
+
if isinstance(i, ast.AstSymbolNode):
|
|
233
|
+
i.name_spec.py_ctx_func = ast3.Store
|
|
234
|
+
elif isinstance(i, ast.AtomTrailer):
|
|
235
|
+
self.chain_def_insert(i.as_attr_list)
|
|
236
|
+
if isinstance(i, (ast.TupleVal, ast.ListVal, ast.UnaryExpr)):
|
|
237
|
+
fix(i)
|
|
238
|
+
|
|
239
|
+
fix(node)
|
|
240
|
+
|
|
241
|
+
def inherit_baseclasses_sym(self, node: ast.Architype | ast.Enum) -> None:
|
|
242
|
+
"""Inherit base classes symbol tables."""
|
|
243
|
+
if node.base_classes:
|
|
244
|
+
for base_cls in node.base_classes.items:
|
|
245
|
+
if (
|
|
246
|
+
isinstance(base_cls, ast.AstSymbolNode)
|
|
247
|
+
and (found := self.use_lookup(base_cls))
|
|
248
|
+
and found
|
|
249
|
+
):
|
|
250
|
+
self.inherit.append(found.decl.sym_tab)
|
|
251
|
+
base_cls.name_spec.name_of = found.decl.name_of
|
|
252
|
+
|
|
192
253
|
def pp(self, depth: Optional[int] = None) -> str:
|
|
193
254
|
"""Pretty print."""
|
|
194
255
|
return print_symtab_tree(root=self, depth=depth)
|
|
@@ -102,9 +102,9 @@ class TestLarkParser(TestCaseMicroSuite):
|
|
|
102
102
|
"JacSource",
|
|
103
103
|
"EmptyToken",
|
|
104
104
|
"AstSymbolNode",
|
|
105
|
+
"AstSymbolStubNode",
|
|
105
106
|
"AstImplNeedingNode",
|
|
106
107
|
"AstAccessNode",
|
|
107
|
-
"TokenSymbol",
|
|
108
108
|
"Literal",
|
|
109
109
|
"AstDocNode",
|
|
110
110
|
"AstSemStrNode",
|
|
@@ -119,7 +119,7 @@ class TestLarkParser(TestCaseMicroSuite):
|
|
|
119
119
|
"ArchBlockStmt",
|
|
120
120
|
"EnumBlockStmt",
|
|
121
121
|
"CodeBlockStmt",
|
|
122
|
-
"
|
|
122
|
+
"NameAtom",
|
|
123
123
|
"ArchSpec",
|
|
124
124
|
"MatchPattern",
|
|
125
125
|
]
|