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
@@ -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
- self.emit(node, f"{i.gen.jac} ")
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.var.value)
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("test_t"):
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
- if start:
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
- self.emit(node, node.value)
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
+ }
@@ -0,0 +1,15 @@
1
+ class foo {
2
+ """
3
+ doc string
4
+ """
5
+ can print_here() {
6
+ print("i'm here");
7
+ }
8
+
9
+ """this is a
10
+ multiline docstring
11
+ to test"""
12
+ can also_print() {
13
+ print("I'm in also");
14
+ }
15
+ }
@@ -1,4 +1,4 @@
1
- import:py from jaclang.core.llms, Anthropic;
1
+ import:py from mtllm.llms, Anthropic;
2
2
 
3
3
  glob llm = Anthropic(model_name="claude-3-sonnet-20240229");
4
4
 
@@ -1,4 +1,4 @@
1
- import:py from jaclang.core.llms, Anthropic;
1
+ import:py from mtllm.llms, Anthropic;
2
2
 
3
3
  glob llm = Anthropic(model_name="claude-3-sonnet-20240229");
4
4
 
@@ -1,4 +1,4 @@
1
- import:py from jaclang.core.llms, Anthropic;
1
+ import:py from mtllm.llms, Anthropic;
2
2
 
3
3
  glob llm = Anthropic(model_name="claude-3-sonnet-20240229");
4
4
 
@@ -1,4 +1,4 @@
1
- import:py from jaclang.core.llms, Anthropic;
1
+ import:py from mtllm.llms, Anthropic;
2
2
 
3
3
  glob llm = Anthropic(model_name="claude-3-sonnet-20240229");
4
4
 
@@ -1,4 +1,4 @@
1
- import:py from jaclang.core.llms, Anthropic;
1
+ import:py from mtllm.llms, Anthropic;
2
2
 
3
3
  glob llm = Anthropic(model_name="claude-3-sonnet-20240229");
4
4
 
@@ -1,4 +1,4 @@
1
- import:py from jaclang.core.llms, Anthropic;
1
+ import:py from mtllm.llms, Anthropic;
2
2
 
3
3
  glob llm = Anthropic(model_name="claude-3-sonnet-20240229");
4
4
 
@@ -1,4 +1,4 @@
1
- import:py from jaclang.core.llms, Anthropic;
1
+ import:py from mtllm.llms, Anthropic;
2
2
 
3
3
  glob llm = Anthropic(model_name="claude-3-sonnet-20240229");
4
4
 
@@ -1,5 +1,5 @@
1
1
  import:py wikipedia;
2
- import:py from jaclang.core.llms, Anthropic;
2
+ import:py from mtllm.llms, Anthropic;
3
3
 
4
4
  glob llm = Anthropic(model_name="claude-3-sonnet-20240229");
5
5
 
@@ -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
- # raise AssertionError("Files differ after formatting.")
48
- self.skipTest("Test failed, but skipping instead of failing.")
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
- self.skipTest("Test failed, but skipping instead of failing.")
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
- self.skipTest(f"Test failed, but skipping instead of failing: {e}")
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__.__module__)
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
@@ -2,71 +2,14 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from enum import Enum
6
- from typing import Optional, TYPE_CHECKING
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.AstSymbolNode,
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.typ = typ
84
- self.defn: list[ast.AstSymbolNode] = [defn]
85
- defn.sym_link = self
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.AstSymbolNode:
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.sym_type
44
+ return self.decl.sym_category
103
45
 
104
- def add_defn(self, node: ast.AstSymbolNode) -> None:
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.sym_link = self
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 if parent else self
81
+ self.parent = parent
127
82
  self.kid: list[SymbolTable] = []
128
83
  self.tab: dict[str, Symbol] = {}
129
- self.uses: list[ast.AstSymbolNode] = []
84
+ self.inherit: list[SymbolTable] = []
130
85
 
131
- def has_parent(self) -> bool:
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
- if deep and self.has_parent():
146
- return self.get_parent().lookup(name, deep)
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.sym_link = self.tab[node.sym_name]
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
- "NameSpec",
122
+ "NameAtom",
123
123
  "ArchSpec",
124
124
  "MatchPattern",
125
125
  ]