jaclang 0.7.14__py3-none-any.whl → 0.7.16__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 (92) hide show
  1. jaclang/cli/cli.py +15 -10
  2. jaclang/cli/cmdreg.py +9 -12
  3. jaclang/compiler/__init__.py +19 -53
  4. jaclang/compiler/absyntree.py +86 -13
  5. jaclang/compiler/jac.lark +4 -3
  6. jaclang/compiler/parser.py +31 -23
  7. jaclang/compiler/passes/ir_pass.py +4 -13
  8. jaclang/compiler/passes/main/access_modifier_pass.py +1 -1
  9. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +4 -5
  10. jaclang/compiler/passes/main/import_pass.py +18 -23
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +307 -559
  12. jaclang/compiler/passes/main/pyast_load_pass.py +32 -6
  13. jaclang/compiler/passes/main/registry_pass.py +37 -3
  14. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
  15. jaclang/compiler/passes/main/tests/__init__.py +1 -1
  16. jaclang/compiler/passes/main/type_check_pass.py +7 -0
  17. jaclang/compiler/passes/tool/jac_formatter_pass.py +124 -86
  18. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +0 -1
  19. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
  20. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
  21. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
  22. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
  23. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
  24. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
  25. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
  26. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
  27. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
  28. jaclang/compiler/passes/transform.py +4 -0
  29. jaclang/compiler/semtable.py +31 -7
  30. jaclang/compiler/tests/test_importer.py +12 -5
  31. jaclang/langserve/engine.py +65 -118
  32. jaclang/langserve/sem_manager.py +379 -0
  33. jaclang/langserve/server.py +8 -10
  34. jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
  35. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  36. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  37. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  38. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  39. jaclang/langserve/tests/test_sem_tokens.py +277 -0
  40. jaclang/langserve/tests/test_server.py +72 -16
  41. jaclang/langserve/utils.py +163 -96
  42. jaclang/plugin/builtin.py +1 -1
  43. jaclang/plugin/default.py +212 -24
  44. jaclang/plugin/feature.py +59 -11
  45. jaclang/plugin/spec.py +58 -6
  46. jaclang/{core → runtimelib}/architype.py +1 -1
  47. jaclang/{core → runtimelib}/context.py +8 -1
  48. jaclang/runtimelib/importer.py +361 -0
  49. jaclang/runtimelib/machine.py +94 -0
  50. jaclang/{core → runtimelib}/utils.py +13 -5
  51. jaclang/settings.py +4 -1
  52. jaclang/tests/fixtures/abc.jac +3 -3
  53. jaclang/tests/fixtures/byllmissue.jac +1 -5
  54. jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
  55. jaclang/tests/fixtures/cls_method.jac +41 -0
  56. jaclang/tests/fixtures/dblhello.jac +6 -0
  57. jaclang/tests/fixtures/deep/one_lev.jac +3 -3
  58. jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
  59. jaclang/tests/fixtures/deep_import_mods.jac +13 -0
  60. jaclang/tests/fixtures/err.impl.jac +3 -0
  61. jaclang/tests/fixtures/err.jac +4 -2
  62. jaclang/tests/fixtures/err.test.jac +3 -0
  63. jaclang/tests/fixtures/err_runtime.jac +15 -0
  64. jaclang/tests/fixtures/game1.jac +1 -1
  65. jaclang/tests/fixtures/hello.jac +4 -0
  66. jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
  67. jaclang/tests/fixtures/impl_grab.jac +4 -1
  68. jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
  69. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  70. jaclang/tests/fixtures/needs_import.jac +2 -2
  71. jaclang/tests/fixtures/pyfunc_2.py +3 -0
  72. jaclang/tests/fixtures/registry.jac +9 -0
  73. jaclang/tests/fixtures/run_test.jac +4 -4
  74. jaclang/tests/fixtures/semstr.jac +1 -4
  75. jaclang/tests/fixtures/simple_archs.jac +1 -1
  76. jaclang/tests/test_cli.py +65 -2
  77. jaclang/tests/test_language.py +74 -7
  78. jaclang/tests/test_reference.py +6 -0
  79. jaclang/utils/helpers.py +45 -21
  80. jaclang/utils/test.py +9 -0
  81. jaclang/utils/treeprinter.py +0 -4
  82. {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/METADATA +3 -2
  83. {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/RECORD +89 -74
  84. jaclang/core/importer.py +0 -344
  85. jaclang/tests/fixtures/aott_raise.jac +0 -25
  86. jaclang/tests/fixtures/package_import.jac +0 -6
  87. /jaclang/{core → runtimelib}/__init__.py +0 -0
  88. /jaclang/{core → runtimelib}/constructs.py +0 -0
  89. /jaclang/{core → runtimelib}/memory.py +0 -0
  90. /jaclang/{core → runtimelib}/test.py +0 -0
  91. {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/WHEEL +0 -0
  92. {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,19 @@
1
+ with entry {
2
+ long_variable_name_1 = another_long_variable_name_2
3
+ = yet_another_long_variable_name_3
4
+ = still_another_long_variable_name_4
5
+ = yet_still_another_long_variable_name_5
6
+ = one_more_long_variable_name_6
7
+ = and_another_long_variable_name_7
8
+ = final_long_variable_name_8
9
+ =1.5;
10
+ result = long_variable_name_1
11
+ + another_long_variable_name_2
12
+ * yet_another_long_variable_name_3
13
+ - still_another_long_variable_name_4
14
+ / yet_still_another_long_variable_name_5
15
+ + one_more_long_variable_name_6
16
+ * and_another_long_variable_name_7
17
+ - final_long_variable_name_8;
18
+ print("The result of the ugly calculation is:", result);
19
+ }
@@ -0,0 +1,6 @@
1
+ with entry {
2
+ triple_quoted_string = """This is a triple quoted string.
3
+ It can span multiple lines.
4
+ It can contain any number of quotes or apostrophes.
5
+ """;
6
+ }
@@ -102,6 +102,17 @@ class JacFormatPassTests(TestCaseMicroSuite, AstSyncTestMixin):
102
102
  file_path = os.path.join(fixtures_dir, file_name)
103
103
  self.compare_files(file_path)
104
104
 
105
+ def test_general_format_fixtures(self) -> None:
106
+ """Tests if files in the general fixtures directory do not change after being formatted."""
107
+ fixtures_dir = os.path.join(self.fixture_abs_path(""), "general_format_checks")
108
+ fixture_files = os.listdir(fixtures_dir)
109
+ for file_name in fixture_files:
110
+ if file_name == "__jac_gen__":
111
+ continue
112
+ with self.subTest(file=file_name):
113
+ file_path = os.path.join(fixtures_dir, file_name)
114
+ self.compare_files(file_path)
115
+
105
116
  def micro_suite_test(self, filename: str) -> None:
106
117
  """Parse micro jac file."""
107
118
  code_gen_pure = jac_file_to_pass(
@@ -33,47 +33,41 @@ class JacUnparseTests(TestCaseMicroSuite, AstSyncTestMixin):
33
33
 
34
34
  def micro_suite_test(self, filename: str) -> None:
35
35
  """Parse micro jac file."""
36
- try:
37
- code_gen_pure = jac_file_to_pass(
38
- self.fixture_abs_path(filename),
39
- target=PyastGenPass,
40
- schedule=without_format,
36
+ code_gen_pure = jac_file_to_pass(
37
+ self.fixture_abs_path(filename),
38
+ target=PyastGenPass,
39
+ schedule=without_format,
40
+ )
41
+ before = ast3.dump(code_gen_pure.ir.gen.py_ast[0], indent=2)
42
+ x = code_gen_pure.ir.unparse()
43
+ # print(x)
44
+ # print(f"Testing {code_gen_pure.ir.name}")
45
+ # print(code_gen_pure.ir.pp())
46
+ code_gen_jac = jac_str_to_pass(
47
+ jac_str=x,
48
+ file_path=filename,
49
+ target=PyastGenPass,
50
+ schedule=without_format,
51
+ )
52
+ after = ast3.dump(code_gen_jac.ir.gen.py_ast[0], indent=2)
53
+ if "circle_clean_tests.jac" in filename:
54
+ self.assertEqual(
55
+ len(
56
+ [
57
+ i
58
+ for i in unified_diff(
59
+ before.splitlines(), after.splitlines(), n=0
60
+ )
61
+ if "test" not in i
62
+ ]
63
+ ),
64
+ 5,
41
65
  )
42
- before = ast3.dump(code_gen_pure.ir.gen.py_ast[0], indent=2)
43
- x = code_gen_pure.ir.unparse()
44
- # print(x)
45
- # print(f"Testing {code_gen_pure.ir.name}")
46
- # print(code_gen_pure.ir.pp())
47
- code_gen_jac = jac_str_to_pass(
48
- jac_str=x,
49
- file_path=filename,
50
- target=PyastGenPass,
51
- schedule=without_format,
66
+ else:
67
+ self.assertEqual(
68
+ len("\n".join(unified_diff(before.splitlines(), after.splitlines()))),
69
+ 0,
52
70
  )
53
- after = ast3.dump(code_gen_jac.ir.gen.py_ast[0], indent=2)
54
- if "circle_clean_tests.jac" in filename:
55
- self.assertEqual(
56
- len(
57
- [
58
- i
59
- for i in unified_diff(
60
- before.splitlines(), after.splitlines(), n=0
61
- )
62
- if "test" not in i
63
- ]
64
- ),
65
- 5,
66
- )
67
- else:
68
- self.assertEqual(
69
- len(
70
- "\n".join(unified_diff(before.splitlines(), after.splitlines()))
71
- ),
72
- 0,
73
- )
74
-
75
- except Exception as e:
76
- raise e
77
71
 
78
72
 
79
73
  JacUnparseTests.self_attach_micro_tests()
@@ -70,3 +70,7 @@ class Transform(ABC, Generic[T]):
70
70
  )
71
71
  self.warnings_had.append(alrt)
72
72
  self.logger.warning(str(alrt))
73
+
74
+ def log_info(self, msg: str) -> None:
75
+ """Log info."""
76
+ self.logger.info(msg)
@@ -6,14 +6,24 @@ semantic information.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- from typing import Optional
9
+ from typing import Optional, TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ import jaclang.compiler.absyntree as ast
10
13
 
11
14
 
12
15
  class SemInfo:
13
16
  """Semantic information class."""
14
17
 
15
- def __init__(self, name: str, type: Optional[str] = None, semstr: str = "") -> None:
18
+ def __init__(
19
+ self,
20
+ node: ast.AstNode,
21
+ name: str,
22
+ type: Optional[str] = None,
23
+ semstr: str = "",
24
+ ) -> None:
16
25
  """Initialize the class."""
26
+ self.node = node
17
27
  self.name = name
18
28
  self.type = type
19
29
  self.semstr = semstr
@@ -22,6 +32,17 @@ class SemInfo:
22
32
  """Return the string representation of the class."""
23
33
  return f"{self.semstr} ({self.type}) ({self.name})"
24
34
 
35
+ def get_children(
36
+ self, sem_registry: SemRegistry, filter: Optional[type[ast.AstNode]] = None
37
+ ) -> list[SemInfo]:
38
+ """Get the children of the SemInfo."""
39
+ scope, _ = sem_registry.lookup(name=self.name)
40
+ self_scope = str(scope) + f".{self.name}({self.type})"
41
+ _, children = sem_registry.lookup(scope=SemScope.get_scope_from_str(self_scope))
42
+ if filter and children and isinstance(children, list):
43
+ return [i for i in children if isinstance(i.node, filter)]
44
+ return children if children and isinstance(children, list) else []
45
+
25
46
 
26
47
  class SemScope:
27
48
  """Scope class."""
@@ -38,7 +59,8 @@ class SemScope:
38
59
  """Return the string representation of the class."""
39
60
  if self.parent:
40
61
  return f"{self.parent}.{self.scope}({self.type})"
41
- return f"{self.scope}({self.type})"
62
+ else:
63
+ return f"{self.scope}({self.type})"
42
64
 
43
65
  def __repr__(self) -> str:
44
66
  """Return the string representation of the class."""
@@ -57,7 +79,7 @@ class SemScope:
57
79
 
58
80
  @property
59
81
  def as_type_str(self) -> Optional[str]:
60
- """Return the type string representation of the SemsScope."""
82
+ """Return the type string representation of the SemScope."""
61
83
  if self.type not in ["class", "node", "obj"]:
62
84
  return None
63
85
  type_str = self.scope
@@ -127,9 +149,11 @@ class SemRegistry:
127
149
  break
128
150
  return i
129
151
 
130
- def pp(self) -> None:
152
+ def pp(self) -> str:
131
153
  """Pretty print the registry."""
154
+ ret_str = ""
132
155
  for k, v in self.registry.items():
133
- print(k)
156
+ ret_str += f"{k}\n"
134
157
  for i in v:
135
- print(f" {i.name} {i.type} {i.semstr}")
158
+ ret_str += f" {i.name} {i.type} {i.semstr}\n"
159
+ return ret_str
@@ -5,6 +5,7 @@ import sys
5
5
 
6
6
  from jaclang import jac_import
7
7
  from jaclang.cli import cli
8
+ from jaclang.plugin.feature import JacFeature as Jac
8
9
  from jaclang.utils.test import TestCase
9
10
 
10
11
 
@@ -17,13 +18,15 @@ class TestLoader(TestCase):
17
18
 
18
19
  def test_import_basic_python(self) -> None:
19
20
  """Test basic self loading."""
21
+ Jac.context().init_memory(base_path=self.fixture_abs_path(__file__))
20
22
  (h,) = jac_import("fixtures.hello_world", base_path=__file__)
21
23
  self.assertEqual(h.hello(), "Hello World!") # type: ignore
22
24
 
23
25
  def test_modules_correct(self) -> None:
24
26
  """Test basic self loading."""
27
+ Jac.context().init_memory(base_path=self.fixture_abs_path(__file__))
25
28
  jac_import("fixtures.hello_world", base_path=__file__)
26
- self.assertIn("module 'hello_world'", str(sys.modules))
29
+ self.assertIn("module 'fixtures.hello_world'", str(sys.modules))
27
30
  self.assertIn("/tests/fixtures/hello_world.jac", str(sys.modules))
28
31
 
29
32
  def test_jac_py_import(self) -> None:
@@ -39,11 +42,15 @@ class TestLoader(TestCase):
39
42
  stdout_value,
40
43
  )
41
44
 
42
- def test_package_import(self) -> None:
43
- """Test package import."""
45
+ def test_jac_py_import_auto(self) -> None:
46
+ """Basic test for pass."""
44
47
  captured_output = io.StringIO()
45
48
  sys.stdout = captured_output
46
- cli.run(self.fixture_abs_path("../../../tests/fixtures/package_import.jac"))
49
+ cli.run(self.fixture_abs_path("../../../tests/fixtures/jp_importer_auto.jac"))
47
50
  sys.stdout = sys.__stdout__
48
51
  stdout_value = captured_output.getvalue()
49
- self.assertEqual("package is imported successfully!\n", stdout_value)
52
+ self.assertIn("Hello World!", stdout_value)
53
+ self.assertIn(
54
+ "{SomeObj(a=10): 'check'} [MyObj(apple=5, banana=7), MyObj(apple=5, banana=7)]",
55
+ stdout_value,
56
+ )
@@ -4,25 +4,26 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import logging
7
+ import time
7
8
  from concurrent.futures import ThreadPoolExecutor
8
9
  from typing import Callable, Optional
9
10
 
10
-
11
11
  import jaclang.compiler.absyntree as ast
12
12
  from jaclang.compiler.compile import jac_str_to_pass
13
13
  from jaclang.compiler.parser import JacParser
14
14
  from jaclang.compiler.passes import Pass
15
15
  from jaclang.compiler.passes.main.schedules import py_code_gen_typed
16
16
  from jaclang.compiler.passes.tool import FuseCommentsPass, JacFormatPass
17
+ from jaclang.langserve.sem_manager import SemTokManager
17
18
  from jaclang.langserve.utils import (
18
19
  collect_all_symbols_in_scope,
19
- collect_symbols,
20
20
  create_range,
21
21
  find_deepest_symbol_node_at_pos,
22
+ find_index,
22
23
  gen_diagnostics,
23
24
  get_item_path,
24
25
  get_mod_path,
25
- locate_affected_token,
26
+ get_symbols_for_outline,
26
27
  parse_symbol_path,
27
28
  resolve_completion_symbol_table,
28
29
  )
@@ -43,104 +44,13 @@ class ModuleInfo:
43
44
  """Initialize module info."""
44
45
  self.ir = ir
45
46
  self.impl_parent: Optional[ModuleInfo] = impl_parent
46
- self.sem_tokens: list[int] = self.gen_sem_tokens()
47
+ self.sem_manager = SemTokManager(ir=ir)
47
48
 
48
49
  @property
49
50
  def uri(self) -> str:
50
51
  """Return uri."""
51
52
  return uris.from_fs_path(self.ir.loc.mod_path)
52
53
 
53
- def gen_sem_tokens(self) -> list[int]:
54
- """Return semantic tokens."""
55
- tokens = []
56
- prev_line, prev_col = 0, 0
57
- for node in self.ir._in_mod_nodes:
58
- if isinstance(node, ast.NameAtom) and node.sem_token:
59
- line, col_start, col_end = (
60
- node.loc.first_line - 1,
61
- node.loc.col_start - 1,
62
- node.loc.col_end - 1,
63
- )
64
- length = col_end - col_start
65
- tokens += [
66
- line - prev_line,
67
- col_start if line != prev_line else col_start - prev_col,
68
- length,
69
- *node.sem_token,
70
- ]
71
- prev_line, prev_col = line, col_start
72
- return tokens
73
-
74
- def update_sem_tokens(
75
- self, content_changes: lspt.DidChangeTextDocumentParams
76
- ) -> list[int]:
77
- """Update semantic tokens on change."""
78
- for change in [
79
- x
80
- for x in content_changes.content_changes
81
- if isinstance(x, lspt.TextDocumentContentChangeEvent_Type1)
82
- ]:
83
- change_start_line = change.range.start.line
84
- change_start_char = change.range.start.character
85
- change_end_line = change.range.end.line
86
- change_end_char = change.range.end.character
87
-
88
- line_delta = change.text.count("\n") - (change_end_line - change_start_line)
89
- if line_delta == 0:
90
- char_delta = len(change.text) - (change_end_char - change_start_char)
91
- else:
92
- last_newline_index = change.text.rfind("\n")
93
- char_delta = (
94
- len(change.text)
95
- - last_newline_index
96
- - 1
97
- - change_end_char
98
- + change_start_char
99
- )
100
-
101
- changed_token_index = locate_affected_token(
102
- self.sem_tokens,
103
- change_start_line,
104
- change_start_char,
105
- change_end_line,
106
- change_end_char,
107
- )
108
- if changed_token_index:
109
- self.sem_tokens[changed_token_index + 2] = max(
110
- 1, self.sem_tokens[changed_token_index + 2] + char_delta
111
- )
112
- if (
113
- len(self.sem_tokens) > changed_token_index + 5
114
- and self.sem_tokens[changed_token_index + 5] == 0
115
- ):
116
- next_token_index = changed_token_index + 5
117
- self.sem_tokens[next_token_index + 1] = max(
118
- 0, self.sem_tokens[next_token_index + 1] + char_delta
119
- )
120
- return self.sem_tokens
121
-
122
- current_token_index = 0
123
- line_offset = 0
124
- while current_token_index < len(self.sem_tokens):
125
- token_line_number = self.sem_tokens[current_token_index] + line_offset
126
- token_start_pos = self.sem_tokens[current_token_index + 1]
127
-
128
- if token_line_number > change_start_line or (
129
- token_line_number == change_start_line
130
- and token_start_pos >= change_start_char
131
- ):
132
- self.sem_tokens[current_token_index] += line_delta
133
- if token_line_number == change_start_line:
134
- self.sem_tokens[current_token_index + 1] += char_delta
135
- if token_line_number > change_end_line or (
136
- token_line_number == change_end_line
137
- and token_start_pos >= change_end_char
138
- ):
139
- break
140
- line_offset += self.sem_tokens[current_token_index]
141
- current_token_index += 5
142
- return self.sem_tokens
143
-
144
54
 
145
55
  class JacLangServer(LanguageServer):
146
56
  """Class for managing workspace."""
@@ -190,6 +100,7 @@ class JacLangServer(LanguageServer):
190
100
  def deep_check(self, file_path: str, annex_view: Optional[str] = None) -> bool:
191
101
  """Rebuild a file and its dependencies."""
192
102
  try:
103
+ start_time = time.time()
193
104
  document = self.workspace.get_text_document(file_path)
194
105
  if file_path in self.modules and (
195
106
  parent := self.modules[file_path].impl_parent
@@ -209,13 +120,14 @@ class JacLangServer(LanguageServer):
209
120
  )
210
121
 
211
122
  self.publish_diagnostics(
212
- file_path,
123
+ annex_view if annex_view else file_path,
213
124
  gen_diagnostics(
214
125
  annex_view if annex_view else file_path,
215
126
  build.errors_had,
216
127
  build.warnings_had,
217
128
  ),
218
129
  )
130
+ self.log_py(f"PROFILE: Deep check took {time.time() - start_time} seconds.")
219
131
  return len(build.errors_had) == 0
220
132
  except Exception as e:
221
133
  self.log_error(f"Error during deep check: {e}")
@@ -256,12 +168,12 @@ class JacLangServer(LanguageServer):
256
168
  current_line = document.lines[position.line]
257
169
  current_pos = position.character
258
170
  current_symbol_path = parse_symbol_path(current_line, current_pos)
171
+
259
172
  node_selected = find_deepest_symbol_node_at_pos(
260
173
  self.modules[file_path].ir,
261
174
  position.line,
262
175
  position.character - 2,
263
176
  )
264
-
265
177
  mod_tab = (
266
178
  self.modules[file_path].ir.sym_tab
267
179
  if not node_selected
@@ -269,15 +181,30 @@ class JacLangServer(LanguageServer):
269
181
  )
270
182
  current_tab = self.modules[file_path].ir._sym_tab
271
183
  current_symbol_table = mod_tab
184
+
272
185
  if completion_trigger == ".":
273
- completion_items = resolve_completion_symbol_table(
274
- mod_tab, current_symbol_path, current_tab
275
- )
186
+ if current_symbol_path:
187
+ completion_items = resolve_completion_symbol_table(
188
+ mod_tab, current_symbol_path, current_tab
189
+ )
190
+ else:
191
+ completion_items = []
276
192
  else:
277
- try: # noqa SIM105
278
- completion_items = collect_all_symbols_in_scope(current_symbol_table)
279
- except AttributeError:
280
- pass
193
+ if node_selected and (
194
+ node_selected.find_parent_of_type(ast.Architype)
195
+ or node_selected.find_parent_of_type(ast.AbilityDef)
196
+ ):
197
+ self_symbol = [
198
+ lspt.CompletionItem(
199
+ label="self", kind=lspt.CompletionItemKind.Variable
200
+ )
201
+ ]
202
+ else:
203
+ self_symbol = []
204
+
205
+ completion_items = (
206
+ collect_all_symbols_in_scope(current_symbol_table) + self_symbol
207
+ )
281
208
  return lspt.CompletionList(is_incomplete=False, items=completion_items)
282
209
 
283
210
  def rename_module(self, old_path: str, new_path: str) -> None:
@@ -327,9 +254,16 @@ class JacLangServer(LanguageServer):
327
254
  """Return hover information for a file."""
328
255
  if file_path not in self.modules:
329
256
  return None
330
- node_selected = find_deepest_symbol_node_at_pos(
331
- self.modules[file_path].ir, position.line, position.character
257
+ token_index = find_index(
258
+ self.modules[file_path].sem_manager.sem_tokens,
259
+ position.line,
260
+ position.character,
332
261
  )
262
+ if token_index is None:
263
+ return None
264
+ node_selected = self.modules[file_path].sem_manager.static_sem_tokens[
265
+ token_index
266
+ ][3]
333
267
  value = self.get_node_info(node_selected) if node_selected else None
334
268
  if value:
335
269
  return lspt.Hover(
@@ -361,12 +295,12 @@ class JacLangServer(LanguageServer):
361
295
  self.log_warning(f"Attribute error when accessing node attributes: {e}")
362
296
  return node_info.strip()
363
297
 
364
- def get_document_symbols(self, file_path: str) -> list[lspt.DocumentSymbol]:
298
+ def get_outline(self, file_path: str) -> list[lspt.DocumentSymbol]:
365
299
  """Return document symbols for a file."""
366
300
  if file_path in self.modules and (
367
301
  root_node := self.modules[file_path].ir._sym_tab
368
302
  ):
369
- return collect_symbols(root_node)
303
+ return get_symbols_for_outline(root_node)
370
304
  return []
371
305
 
372
306
  def get_definition(
@@ -375,9 +309,16 @@ class JacLangServer(LanguageServer):
375
309
  """Return definition location for a file."""
376
310
  if file_path not in self.modules:
377
311
  return None
378
- node_selected: Optional[ast.AstSymbolNode] = find_deepest_symbol_node_at_pos(
379
- self.modules[file_path].ir, position.line, position.character
312
+ token_index = find_index(
313
+ self.modules[file_path].sem_manager.sem_tokens,
314
+ position.line,
315
+ position.character,
380
316
  )
317
+ if token_index is None:
318
+ return None
319
+ node_selected = self.modules[file_path].sem_manager.static_sem_tokens[
320
+ token_index
321
+ ][3]
381
322
  if node_selected:
382
323
  if (
383
324
  isinstance(node_selected, ast.Name)
@@ -400,13 +341,13 @@ class JacLangServer(LanguageServer):
400
341
  ):
401
342
  path_range = get_item_path(node_selected.parent)
402
343
  if path_range:
403
- path, range = path_range
404
- if path and range:
344
+ path, loc_range = path_range
345
+ if path and loc_range:
405
346
  return lspt.Location(
406
347
  uri=uris.from_fs_path(path),
407
348
  range=lspt.Range(
408
- start=lspt.Position(line=range[0], character=0),
409
- end=lspt.Position(line=range[1], character=5),
349
+ start=lspt.Position(line=loc_range[0], character=0),
350
+ end=lspt.Position(line=loc_range[1], character=5),
410
351
  ),
411
352
  )
412
353
  else:
@@ -424,7 +365,6 @@ class JacLangServer(LanguageServer):
424
365
  else node_selected
425
366
  )
426
367
  )
427
- self.log_py(f"{node_selected}, {decl_node}")
428
368
  decl_uri = uris.from_fs_path(decl_node.loc.mod_path)
429
369
  try:
430
370
  decl_range = create_range(decl_node.loc)
@@ -443,9 +383,16 @@ class JacLangServer(LanguageServer):
443
383
  self, file_path: str, position: lspt.Position
444
384
  ) -> list[lspt.Location]:
445
385
  """Return references for a file."""
446
- node_selected = find_deepest_symbol_node_at_pos(
447
- self.modules[file_path].ir, position.line, position.character
386
+ if file_path not in self.modules:
387
+ return []
388
+ index1 = find_index(
389
+ self.modules[file_path].sem_manager.sem_tokens,
390
+ position.line,
391
+ position.character,
448
392
  )
393
+ if index1 is None:
394
+ return []
395
+ node_selected = self.modules[file_path].sem_manager.static_sem_tokens[index1][3]
449
396
  if node_selected and node_selected.sym:
450
397
  list_of_references: list[lspt.Location] = [
451
398
  lspt.Location(
@@ -461,7 +408,7 @@ class JacLangServer(LanguageServer):
461
408
  """Return semantic tokens for a file."""
462
409
  if file_path not in self.modules:
463
410
  return lspt.SemanticTokens(data=[])
464
- return lspt.SemanticTokens(data=self.modules[file_path].sem_tokens)
411
+ return lspt.SemanticTokens(data=self.modules[file_path].sem_manager.sem_tokens)
465
412
 
466
413
  def log_error(self, message: str) -> None:
467
414
  """Log an error message."""