jaclang 0.7.16__py3-none-any.whl → 0.7.18__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 (81) hide show
  1. jaclang/cli/cli.py +140 -77
  2. jaclang/compiler/absyntree.py +9 -4
  3. jaclang/compiler/constant.py +8 -8
  4. jaclang/compiler/parser.py +10 -2
  5. jaclang/compiler/passes/main/__init__.py +1 -1
  6. jaclang/compiler/passes/main/access_modifier_pass.py +96 -147
  7. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +152 -50
  8. jaclang/compiler/passes/main/import_pass.py +88 -59
  9. jaclang/compiler/passes/main/py_collect_dep_pass.py +70 -0
  10. jaclang/compiler/passes/main/pyast_gen_pass.py +46 -6
  11. jaclang/compiler/passes/main/pyast_load_pass.py +1 -0
  12. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -0
  13. jaclang/compiler/passes/main/schedules.py +9 -2
  14. jaclang/compiler/passes/main/sym_tab_build_pass.py +9 -5
  15. jaclang/compiler/passes/main/tests/fixtures/autoimpl.empty.impl.jac +0 -0
  16. jaclang/compiler/passes/main/tests/fixtures/autoimpl.jac +1 -1
  17. jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac +29 -0
  18. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.py +3 -0
  19. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/color.py +3 -0
  20. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/constants.py +5 -0
  21. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/display.py +2 -0
  22. jaclang/compiler/passes/main/tests/test_import_pass.py +72 -13
  23. jaclang/compiler/passes/main/type_check_pass.py +15 -5
  24. jaclang/compiler/passes/tool/jac_formatter_pass.py +13 -3
  25. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +37 -41
  26. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +37 -41
  27. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/access_mod_check.jac +27 -0
  28. jaclang/compiler/passes/utils/mypy_ast_build.py +45 -0
  29. jaclang/compiler/symtable.py +16 -11
  30. jaclang/compiler/tests/test_importer.py +17 -9
  31. jaclang/langserve/engine.py +64 -16
  32. jaclang/langserve/server.py +16 -1
  33. jaclang/langserve/tests/fixtures/import_include_statements.jac +3 -3
  34. jaclang/langserve/tests/fixtures/rename.jac +30 -0
  35. jaclang/langserve/tests/test_server.py +224 -6
  36. jaclang/langserve/utils.py +28 -98
  37. jaclang/plugin/builtin.py +8 -4
  38. jaclang/plugin/default.py +86 -64
  39. jaclang/plugin/feature.py +13 -13
  40. jaclang/plugin/spec.py +10 -11
  41. jaclang/plugin/tests/fixtures/other_root_access.jac +82 -0
  42. jaclang/plugin/tests/test_jaseci.py +414 -42
  43. jaclang/runtimelib/architype.py +481 -333
  44. jaclang/runtimelib/constructs.py +5 -8
  45. jaclang/runtimelib/context.py +89 -69
  46. jaclang/runtimelib/importer.py +16 -15
  47. jaclang/runtimelib/machine.py +66 -2
  48. jaclang/runtimelib/memory.py +134 -75
  49. jaclang/runtimelib/utils.py +17 -10
  50. jaclang/settings.py +2 -4
  51. jaclang/tests/fixtures/access_checker.jac +12 -17
  52. jaclang/tests/fixtures/access_modifier.jac +88 -33
  53. jaclang/tests/fixtures/baddy.jac +3 -0
  54. jaclang/tests/fixtures/bar.jac +34 -0
  55. jaclang/tests/fixtures/builtin_dotgen.jac +1 -0
  56. jaclang/tests/fixtures/edge_node_walk.jac +1 -1
  57. jaclang/tests/fixtures/edge_ops.jac +1 -1
  58. jaclang/tests/fixtures/edges_walk.jac +1 -1
  59. jaclang/tests/fixtures/foo.jac +43 -0
  60. jaclang/tests/fixtures/game1.jac +1 -1
  61. jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
  62. jaclang/tests/fixtures/import.jac +9 -0
  63. jaclang/tests/fixtures/index_slice.jac +30 -0
  64. jaclang/tests/fixtures/objref.jac +12 -0
  65. jaclang/tests/fixtures/pyfunc_1.py +1 -1
  66. jaclang/tests/fixtures/pyfunc_2.py +2 -2
  67. jaclang/tests/fixtures/pygame_mock/__init__.py +3 -0
  68. jaclang/tests/fixtures/pygame_mock/color.py +3 -0
  69. jaclang/tests/fixtures/pygame_mock/constants.py +5 -0
  70. jaclang/tests/fixtures/pygame_mock/display.py +2 -0
  71. jaclang/tests/fixtures/pygame_mock/inner/__init__.py +0 -0
  72. jaclang/tests/fixtures/pygame_mock/inner/iner_mod.py +2 -0
  73. jaclang/tests/test_cli.py +49 -6
  74. jaclang/tests/test_language.py +126 -80
  75. jaclang/tests/test_reference.py +2 -9
  76. jaclang/utils/treeprinter.py +30 -3
  77. {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/METADATA +3 -1
  78. {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/RECORD +81 -59
  79. /jaclang/tests/fixtures/{err.test.jac → baddy.test.jac} +0 -0
  80. {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/WHEEL +0 -0
  81. {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/entry_points.txt +0 -0
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import ast
6
6
  import os
7
+ from typing import Callable, TYPE_CHECKING, TextIO
7
8
 
8
9
  from jaclang.compiler.absyntree import AstNode
9
10
  from jaclang.compiler.passes import Pass
@@ -21,13 +22,19 @@ from mypy.build import FileSystemCache
21
22
  from mypy.build import Graph
22
23
  from mypy.build import ModuleNotFound
23
24
  from mypy.build import PRI_INDIRECT
25
+ from mypy.build import Plugin
26
+ from mypy.build import SearchPaths
24
27
  from mypy.build import compute_search_paths
25
28
  from mypy.build import find_module_simple
29
+ from mypy.build import find_module_with_reason
26
30
  from mypy.build import load_plugins
27
31
  from mypy.build import process_graph
28
32
  from mypy.options import Options
29
33
  from mypy.semanal_main import semantic_analysis_for_scc
30
34
 
35
+ if TYPE_CHECKING:
36
+ from mypy.report import Reports # Avoid unconditional slow import
37
+
31
38
 
32
39
  mypy_to_jac_node_map: dict[
33
40
  tuple[int, int | None, int | None, int | None], list[AstNode]
@@ -37,6 +44,43 @@ mypy_to_jac_node_map: dict[
37
44
  class BuildManager(myb.BuildManager):
38
45
  """Overrides to mypy build manager for direct AST pass through."""
39
46
 
47
+ def __init__(
48
+ self,
49
+ data_dir: str,
50
+ search_paths: SearchPaths,
51
+ ignore_prefix: str,
52
+ source_set: BuildSourceSet,
53
+ reports: Reports | None,
54
+ options: Options,
55
+ version_id: str,
56
+ plugin: Plugin,
57
+ plugins_snapshot: dict[str, str],
58
+ errors: Errors,
59
+ flush_errors: Callable[[str | None, list[str], bool], None],
60
+ fscache: FileSystemCache,
61
+ stdout: TextIO,
62
+ stderr: TextIO,
63
+ ) -> None:
64
+ """Override mypy BuildManager constructor to initialize jac related map."""
65
+ global mypy_to_jac_node_map
66
+ super().__init__(
67
+ data_dir,
68
+ search_paths,
69
+ ignore_prefix,
70
+ source_set,
71
+ reports,
72
+ options,
73
+ version_id,
74
+ plugin,
75
+ plugins_snapshot,
76
+ errors,
77
+ flush_errors,
78
+ fscache,
79
+ stdout,
80
+ stderr,
81
+ )
82
+ mypy_to_jac_node_map = {}
83
+
40
84
  def parse_file(
41
85
  self,
42
86
  id: str,
@@ -664,6 +708,7 @@ __all__ = [
664
708
  "BuildSource",
665
709
  "BuildSourceSet",
666
710
  "FileSystemCache",
711
+ "find_module_with_reason",
667
712
  "compute_search_paths",
668
713
  "load_graph",
669
714
  "load_plugins",
@@ -137,7 +137,7 @@ class SymbolTable:
137
137
  return k
138
138
  return None
139
139
 
140
- def push_scope(self, name: str, key_node: ast.AstNode) -> SymbolTable:
140
+ def push_kid_scope(self, name: str, key_node: ast.AstNode) -> SymbolTable:
141
141
  """Push a new scope onto the symbol table."""
142
142
  self.kid.append(SymbolTable(name, key_node, self))
143
143
  return self.kid[-1]
@@ -205,16 +205,21 @@ class SymbolTable:
205
205
  for i in node_list:
206
206
  if cur_sym_tab is None:
207
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
- )
208
+ lookup = self.use_lookup(i, sym_table=cur_sym_tab)
209
+ if lookup:
210
+ cur_sym_tab = lookup.decl.sym_tab
211
+
212
+ # check if the symbol table name is not the same as symbol name
213
+ # then try to find a child scope with the same name
214
+ # This is used to get the scope in case of
215
+ # import:py math;
216
+ # b = math.floor(1.7);
217
+ if cur_sym_tab.name != i.sym_name:
218
+ t = cur_sym_tab.find_scope(i.sym_name)
219
+ if t:
220
+ cur_sym_tab = t
221
+ else:
222
+ cur_sym_tab = None
218
223
 
219
224
  def update_py_ctx_for_def(self, node: ast.AstSymbolNode) -> None:
220
225
  """Update python context for definition."""
@@ -5,29 +5,37 @@ 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
+ from jaclang.runtimelib.machine import JacMachine, JacProgram
9
9
  from jaclang.utils.test import TestCase
10
10
 
11
11
 
12
12
  class TestLoader(TestCase):
13
13
  """Test Jac self.prse."""
14
14
 
15
- def setUp(self) -> None:
16
- """Set up test."""
17
- return super().setUp()
18
-
19
15
  def test_import_basic_python(self) -> None:
20
16
  """Test basic self loading."""
21
- Jac.context().init_memory(base_path=self.fixture_abs_path(__file__))
17
+ JacMachine(self.fixture_abs_path(__file__)).attach_program(
18
+ JacProgram(mod_bundle=None, bytecode=None)
19
+ )
22
20
  (h,) = jac_import("fixtures.hello_world", base_path=__file__)
23
21
  self.assertEqual(h.hello(), "Hello World!") # type: ignore
22
+ JacMachine.detach()
24
23
 
25
24
  def test_modules_correct(self) -> None:
26
25
  """Test basic self loading."""
27
- Jac.context().init_memory(base_path=self.fixture_abs_path(__file__))
26
+ JacMachine(self.fixture_abs_path(__file__)).attach_program(
27
+ JacProgram(mod_bundle=None, bytecode=None)
28
+ )
28
29
  jac_import("fixtures.hello_world", base_path=__file__)
29
- self.assertIn("module 'fixtures.hello_world'", str(sys.modules))
30
- self.assertIn("/tests/fixtures/hello_world.jac", str(sys.modules))
30
+ self.assertIn(
31
+ "module 'fixtures.hello_world'",
32
+ str(JacMachine.get().loaded_modules),
33
+ )
34
+ self.assertIn(
35
+ "/tests/fixtures/hello_world.jac",
36
+ str(JacMachine.get().loaded_modules),
37
+ )
38
+ JacMachine.detach()
31
39
 
32
40
  def test_jac_py_import(self) -> None:
33
41
  """Basic test for pass."""
@@ -16,13 +16,13 @@ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
16
16
  from jaclang.compiler.passes.tool import FuseCommentsPass, JacFormatPass
17
17
  from jaclang.langserve.sem_manager import SemTokManager
18
18
  from jaclang.langserve.utils import (
19
+ add_unique_text_edit,
19
20
  collect_all_symbols_in_scope,
20
21
  create_range,
21
22
  find_deepest_symbol_node_at_pos,
22
23
  find_index,
23
24
  gen_diagnostics,
24
- get_item_path,
25
- get_mod_path,
25
+ get_location_range,
26
26
  get_symbols_for_outline,
27
27
  parse_symbol_path,
28
28
  resolve_completion_symbol_table,
@@ -127,6 +127,15 @@ class JacLangServer(LanguageServer):
127
127
  build.warnings_had,
128
128
  ),
129
129
  )
130
+ if annex_view:
131
+ self.publish_diagnostics(
132
+ file_path,
133
+ gen_diagnostics(
134
+ file_path,
135
+ build.errors_had,
136
+ build.warnings_had,
137
+ ),
138
+ )
130
139
  self.log_py(f"PROFILE: Deep check took {time.time() - start_time} seconds.")
131
140
  return len(build.errors_had) == 0
132
141
  except Exception as e:
@@ -325,8 +334,9 @@ class JacLangServer(LanguageServer):
325
334
  and node_selected.parent
326
335
  and isinstance(node_selected.parent, ast.ModulePath)
327
336
  ):
328
- spec = get_mod_path(node_selected.parent, node_selected)
337
+ spec = node_selected.parent.abs_path
329
338
  if spec:
339
+ spec = spec[5:] if spec.startswith("File:") else spec
330
340
  return lspt.Location(
331
341
  uri=uris.from_fs_path(spec),
332
342
  range=lspt.Range(
@@ -339,19 +349,28 @@ class JacLangServer(LanguageServer):
339
349
  elif node_selected.parent and isinstance(
340
350
  node_selected.parent, ast.ModuleItem
341
351
  ):
342
- path_range = get_item_path(node_selected.parent)
343
- if path_range:
344
- path, loc_range = path_range
345
- if path and loc_range:
346
- return lspt.Location(
347
- uri=uris.from_fs_path(path),
348
- range=lspt.Range(
349
- start=lspt.Position(line=loc_range[0], character=0),
350
- end=lspt.Position(line=loc_range[1], character=5),
352
+ path = node_selected.parent.from_mod_path.abs_path
353
+ try: # TODO: Get rid of this when 'from' import is fixed
354
+ loc_range = tuple(
355
+ loc - 1 if loc > 0 else loc
356
+ for loc in get_location_range(node_selected.parent)
357
+ )
358
+ except ValueError:
359
+ loc_range = (0, 0, 0, 0)
360
+
361
+ if path and loc_range:
362
+ path = path[5:] if path.startswith("File:") else path
363
+ return lspt.Location(
364
+ uri=uris.from_fs_path(path),
365
+ range=lspt.Range(
366
+ start=lspt.Position(
367
+ line=loc_range[0], character=loc_range[1]
351
368
  ),
352
- )
353
- else:
354
- return None
369
+ end=lspt.Position(
370
+ line=loc_range[2], character=loc_range[3]
371
+ ),
372
+ ),
373
+ )
355
374
  elif isinstance(node_selected, (ast.ElementStmt, ast.BuiltinType)):
356
375
  return None
357
376
  decl_node = (
@@ -368,7 +387,7 @@ class JacLangServer(LanguageServer):
368
387
  decl_uri = uris.from_fs_path(decl_node.loc.mod_path)
369
388
  try:
370
389
  decl_range = create_range(decl_node.loc)
371
- except ValueError: # 'print' name has decl in 0,0,0,0
390
+ except ValueError:
372
391
  return None
373
392
  decl_location = lspt.Location(
374
393
  uri=decl_uri,
@@ -404,6 +423,35 @@ class JacLangServer(LanguageServer):
404
423
  return list_of_references
405
424
  return []
406
425
 
426
+ def rename_symbol(
427
+ self, file_path: str, position: lspt.Position, new_name: str
428
+ ) -> Optional[lspt.WorkspaceEdit]:
429
+ """Rename a symbol in a file."""
430
+ if file_path not in self.modules:
431
+ return None
432
+ index1 = find_index(
433
+ self.modules[file_path].sem_manager.sem_tokens,
434
+ position.line,
435
+ position.character,
436
+ )
437
+ if index1 is None:
438
+ return None
439
+ node_selected = self.modules[file_path].sem_manager.static_sem_tokens[index1][3]
440
+ if node_selected and node_selected.sym:
441
+ changes: dict[str, list[lspt.TextEdit]] = {}
442
+ for node in [
443
+ *node_selected.sym.uses,
444
+ node_selected.sym.defn[0],
445
+ ]:
446
+ key = uris.from_fs_path(node.loc.mod_path)
447
+ new_edit = lspt.TextEdit(
448
+ range=create_range(node.loc),
449
+ new_text=new_name,
450
+ )
451
+ add_unique_text_edit(changes, key, new_edit)
452
+ return lspt.WorkspaceEdit(changes=changes)
453
+ return None
454
+
407
455
  def get_semantic_tokens(self, file_path: str) -> lspt.SemanticTokens:
408
456
  """Return semantic tokens for a file."""
409
457
  if file_path not in self.modules:
@@ -17,8 +17,14 @@ server = JacLangServer()
17
17
 
18
18
 
19
19
  @server.feature(lspt.TEXT_DOCUMENT_DID_OPEN)
20
- @server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
21
20
  async def did_open(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
21
+ """Check syntax on change."""
22
+ ls.deep_check(params.text_document.uri)
23
+ ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
24
+
25
+
26
+ @server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
27
+ async def did_save(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
22
28
  """Check syntax on change."""
23
29
  await ls.launch_deep_check(params.text_document.uri)
24
30
  ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
@@ -132,6 +138,15 @@ def references(ls: JacLangServer, params: lspt.ReferenceParams) -> list[lspt.Loc
132
138
  return ls.get_references(params.text_document.uri, params.position)
133
139
 
134
140
 
141
+ @server.feature(lspt.TEXT_DOCUMENT_RENAME)
142
+ def rename(
143
+ ls: JacLangServer, params: lspt.RenameParams
144
+ ) -> Optional[lspt.WorkspaceEdit]:
145
+ """Rename symbol."""
146
+ ls.log_warning("Auto Rename is Experimental, Please use with caution.")
147
+ return ls.rename_symbol(params.text_document.uri, params.position, params.new_name)
148
+
149
+
135
150
  @server.feature(
136
151
  lspt.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
137
152
  lspt.SemanticTokensLegend(
@@ -1,6 +1,6 @@
1
1
  import:py os;
2
- import:py from math, sqrt as square_root;
2
+ import:py from math{ sqrt as square_root}
3
3
  import:py datetime as dt;
4
- import:jac from base_module_structure, add as add_numbers , subtract,x,Colorenum as clr;
4
+ import:jac from base_module_structure{ add as add_numbers , subtract,x,Colorenum as clr}
5
5
  import:jac base_module_structure as base_module_structure;
6
- import:py from py_import,add1 as ss, sub1 as subtract1,apple,Orange1;
6
+ import:py from py_import{add1 as ss, sub1 as subtract1,apple,Orange1}
@@ -0,0 +1,30 @@
1
+ can foo;
2
+
3
+
4
+
5
+ :can:foo{
6
+ print("foo");
7
+ }
8
+
9
+
10
+ obj out{
11
+ has cnt :int;
12
+ can bar;
13
+ can baz;
14
+ }
15
+
16
+
17
+ :obj:out:can:bar{
18
+ print("bar");
19
+ }
20
+
21
+ :obj:out:can:baz{
22
+ print("baz");
23
+ }
24
+
25
+ with entry{
26
+ foo();
27
+ new = out();
28
+ new.cnt;
29
+ out(1).bar();
30
+ }
@@ -187,11 +187,15 @@ class TestJacLangServer(TestCase):
187
187
  )
188
188
  lsp.deep_check(import_file)
189
189
  positions = [
190
- (2, 24, "datetime.py:0:0-0:0"),
190
+ (0, 12, "tdlib/os/__init__.pyi:0:0-0:0"),
191
+ (1, 18, "stdlib/math.pyi:0:0-0:0"),
192
+ (2, 24, "datetime.pyi:0:0-0:0"),
191
193
  (3, 17, "base_module_structure.jac:0:0-0:0"),
192
- (3, 87, "base_module_structure.jac:23:0-23:5"),
193
- (5, 65, "py_import.py:12:0-20:5"),
194
- (5, 35, "py_import.py:3:0-4:5"),
194
+ (3, 87, "base_module_structure.jac:23:5-23:14"),
195
+ (5, 65, "py_import.py:0:0-0:0"),
196
+ (5, 35, "py_import.py:0:0-0:0"),
197
+ # (5, 65, "py_import.py:12:0-20:5"), # TODO : Should work after 'from' import files are raised
198
+ # (5, 35, "py_import.py:3:0-4:5"),
195
199
  ]
196
200
 
197
201
  for line, char, expected in positions:
@@ -201,6 +205,62 @@ class TestJacLangServer(TestCase):
201
205
  str(lsp.get_definition(import_file, lspt.Position(line, char))),
202
206
  )
203
207
 
208
+ def test_go_to_definition_foolme(self) -> None:
209
+ """Test that the go to definition is correct."""
210
+ lsp = JacLangServer()
211
+ workspace_path = self.fixture_abs_path("")
212
+ workspace = Workspace(workspace_path, lsp)
213
+ lsp.lsp._workspace = workspace
214
+ import_file = uris.from_fs_path(
215
+ self.fixture_abs_path(
216
+ "../../../../jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac"
217
+ )
218
+ )
219
+ lsp.deep_check(import_file)
220
+ positions = [
221
+ (6, 39, "/pygame_mock/__init__.py:2:0-2:0"),
222
+ (6, 45, "/pygame_mock/constants.py:3:0-4:1"),
223
+ (7, 31, "/pygame_mock/__init__.py:2:0-2:0"),
224
+ (7, 35, "/pygame_mock/constants.py:3:0-4:1"),
225
+ (20, 51, "/py_imp_test.jac:6:4-6:11"),
226
+ (20, 64, "/pygame_mock/constants.py:4:3-4:15"),
227
+ (21, 48, "/py_imp_test.jac:10:4-10:6"),
228
+ (21, 58, "/py_imp_test.jac:11:8-11:15"),
229
+ (21, 68, "/pygame_mock/constants.py:4:3-4:15"),
230
+ (23, 58, "/pygame_mock/constants.py:4:3-4:15"),
231
+ ]
232
+
233
+ for line, char, expected in positions:
234
+ with self.subTest(line=line, char=char):
235
+ self.assertIn(
236
+ expected,
237
+ str(lsp.get_definition(import_file, lspt.Position(line, char))),
238
+ )
239
+
240
+ def test_go_to_definition_index_expr(self) -> None:
241
+ """Test that the go to definition is correct."""
242
+ lsp = JacLangServer()
243
+ workspace_path = self.fixture_abs_path("")
244
+ workspace = Workspace(workspace_path, lsp)
245
+ lsp.lsp._workspace = workspace
246
+ import_file = uris.from_fs_path(
247
+ self.fixture_abs_path("../../../../jaclang/tests/fixtures/index_slice.jac")
248
+ )
249
+ lsp.deep_check(import_file)
250
+ positions = [
251
+ (23, 20, "index_slice.jac:2:8-2:13"),
252
+ (24, 24, "index_slice.jac:2:8-2:13"),
253
+ (27, 33, "index_slice.jac:2:8-2:13"),
254
+ ]
255
+
256
+ for line, char, expected in positions:
257
+ with self.subTest(line=line, char=char):
258
+ print(str(lsp.get_definition(import_file, lspt.Position(line, char))))
259
+ self.assertIn(
260
+ expected,
261
+ str(lsp.get_definition(import_file, lspt.Position(line, char))),
262
+ )
263
+
204
264
  def test_sem_tokens(self) -> None:
205
265
  """Test that the Semantic Tokens are generated correctly."""
206
266
  lsp = JacLangServer()
@@ -214,7 +274,7 @@ class TestJacLangServer(TestCase):
214
274
  ("<JacSemTokenType.VARIABLE: 8>, <JacSemTokenModifier.READONLY: 4>", 12),
215
275
  (
216
276
  "<JacSemTokenType.PROPERTY: 9>, <JacSemTokenModifier.DEFINITION: 2>,",
217
- 19,
277
+ 21,
218
278
  ),
219
279
  (
220
280
  "<JacSemTokenType.PARAMETER: 7>, <JacSemTokenModifier.DECLARATION: 1>,",
@@ -232,7 +292,6 @@ class TestJacLangServer(TestCase):
232
292
  3,
233
293
  ),
234
294
  ]
235
- print(str(sem_list))
236
295
  for token_type, expected_count in expected_counts:
237
296
  self.assertEqual(str(sem_list).count(token_type), expected_count)
238
297
 
@@ -351,3 +410,162 @@ class TestJacLangServer(TestCase):
351
410
  references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
352
411
  for expected in expected_refs:
353
412
  self.assertIn(expected, references)
413
+
414
+ def test_py_type__definition(self) -> None:
415
+ """Test that the go to definition is correct for pythoon imports."""
416
+ lsp = JacLangServer()
417
+ workspace_path = self.fixture_abs_path("")
418
+ workspace = Workspace(workspace_path, lsp)
419
+ lsp.lsp._workspace = workspace
420
+ import_file = uris.from_fs_path(
421
+ self.fixture_abs_path(
422
+ "../../../../jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac"
423
+ )
424
+ )
425
+ lsp.deep_check(import_file)
426
+ positions = [
427
+ (19, 29, "pygame_mock/color.py:0:0-2:4"),
428
+ (3, 17, "/pygame_mock/__init__.py:0:0-0:0"),
429
+ (20, 45, "pygame_mock/color.py:0:0-2:4"),
430
+ (19, 77, "mock/constants.py:4:3-4:15"),
431
+ (26, 28, "mock/display.py:0:0-1:7"),
432
+ (24, 22, "/argparse.pyi:124:0-249:13"),
433
+ (19, 74, "pygame_mock/constants.py:4:3-4:15"),
434
+ (27, 17, "/stdlib/os/__init__.pyi:50:0-50:3"),
435
+ ]
436
+
437
+ for line, char, expected in positions:
438
+ with self.subTest(line=line, char=char):
439
+ self.assertIn(
440
+ expected,
441
+ str(lsp.get_definition(import_file, lspt.Position(line, char))),
442
+ )
443
+
444
+ def test_py_type__references(self) -> None:
445
+ """Test that the go to definition is correct for pythoon imports."""
446
+ lsp = JacLangServer()
447
+ workspace_path = self.fixture_abs_path("")
448
+ workspace = Workspace(workspace_path, lsp)
449
+ lsp.lsp._workspace = workspace
450
+
451
+ circle_file = uris.from_fs_path(
452
+ self.fixture_abs_path(
453
+ "../../../../jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac"
454
+ )
455
+ )
456
+ lsp.deep_check(circle_file)
457
+ test_cases = [
458
+ (
459
+ 2,
460
+ 21,
461
+ [
462
+ ":6:21-6:32",
463
+ ":7:11-7:22",
464
+ ":11:25-11:36",
465
+ ":12:15-12:26",
466
+ ":18:33-18:44",
467
+ "19:46-19:57",
468
+ ":19:8-19:19",
469
+ ":19:46-19:57",
470
+ ":20:8-20:19",
471
+ "21:8-21:19,",
472
+ "23:8-23:19",
473
+ ":26:4-26:15",
474
+ ],
475
+ ),
476
+ (
477
+ 19,
478
+ 63,
479
+ [
480
+ "6:33-6:42",
481
+ "7:23-7:32",
482
+ "18:45-18:54",
483
+ "19:58-19:67",
484
+ "11:37-11:46",
485
+ "12:27-12:36",
486
+ ],
487
+ ),
488
+ (
489
+ 24,
490
+ 53,
491
+ [
492
+ "24:42-24:56",
493
+ "24:16-24:30",
494
+ "argparse.pyi:334:21-334:35",
495
+ "argparse.pyi:163:29-163:43",
496
+ "argparse.pyi:32:52-32:66",
497
+ ],
498
+ ),
499
+ ]
500
+ for line, char, expected_refs in test_cases:
501
+ references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
502
+ for expected in expected_refs:
503
+ self.assertIn(expected, references)
504
+
505
+ def test_rename_symbol(self) -> None:
506
+ """Test that the rename is correct."""
507
+ lsp = JacLangServer()
508
+ workspace_path = self.fixture_abs_path("")
509
+ workspace = Workspace(workspace_path, lsp)
510
+ lsp.lsp._workspace = workspace
511
+
512
+ circle_file = uris.from_fs_path(self.fixture_abs_path("circle.jac"))
513
+ lsp.deep_check(circle_file)
514
+ test_cases = [
515
+ (
516
+ 20,
517
+ 14,
518
+ "ShapeKind",
519
+ "27:20-27:29,",
520
+ "36:19-36:28",
521
+ "75:26-75:35",
522
+ "20:5-20:14",
523
+ ),
524
+ (12, 34, "circleRadius", "12:21-12:27", "12:30-12:36", "11:19-11:25"),
525
+ (62, 14, "target_area", "65:43-65:56", "70:32-70:45", "62:5-62:18"),
526
+ (57, 33, "type_of_shape", "75:12-75:22", "27:8-27:18,", "57:23-57:33"),
527
+ ]
528
+ for tup in test_cases:
529
+ line, char, new_name, *expected_refs = tup
530
+ references = str(
531
+ lsp.rename_symbol(circle_file, lspt.Position(line, char), new_name)
532
+ )
533
+ for expected in expected_refs:
534
+ self.assertIn(expected, references)
535
+
536
+ def test_rename_uses(self) -> None:
537
+ """Test that the rename is correct."""
538
+ lsp = JacLangServer()
539
+ workspace_path = self.fixture_abs_path("")
540
+ workspace = Workspace(workspace_path, lsp)
541
+ lsp.lsp._workspace = workspace
542
+
543
+ circle_file = uris.from_fs_path(self.fixture_abs_path("rename.jac"))
544
+ lsp.deep_check(circle_file)
545
+ # fmt: off
546
+ test_cases = [
547
+ (0, 7, "func", "25:4-25:7", "0:4-0:7", "4:5-4:8",),
548
+ (4, 6, "func", "25:4-25:7", "0:4-0:7", "4:5-4:8",),
549
+ (25, 7, "func", "25:4-25:7", "0:4-0:7", "4:5-4:8",),
550
+ (10, 10, "canBar", "27:8-27:11", "10:8-10:11"),
551
+ (27, 9, "canBar", "27:8-27:11", "10:8-10:11"),
552
+ (9, 6, "canBar", "26:10-26:13", "28:4-28:7", "16:5-16:8", "9:4-9:7"),
553
+ (26, 11, "canBar", "26:10-26:13", "28:4-28:7", "16:5-16:8", "9:4-9:7"),
554
+ (16, 7, "canBar", "26:10-26:13", "28:4-28:7", "16:5-16:8", "9:4-9:7"),
555
+ (28, 6, "canBar", "26:10-26:13", "28:4-28:7", "16:5-16:8", "9:4-9:7"),
556
+ (11, 10, "canBar", "11:8-11:11", "16:13-16:16", "28:11-28:14"),
557
+ (16, 14, "canBar", "11:8-11:11", "16:13-16:16", "28:11-28:14"),
558
+ (28, 13, "canBar", "11:8-11:11", "16:13-16:16", "28:11-28:14"),
559
+ (12, 10, "canBaz", "12:8-12:11", "20:13-20:16"),
560
+ (20, 14, "canBaz", "12:8-12:11", "20:13-20:16"),
561
+ (26, 6, "count", "27:4-27:7", "26:4-26:7"),
562
+ (27, 5, "count", "27:4-27:7", "26:4-26:7"),
563
+ ]
564
+ # fmt: on
565
+ for tup in test_cases:
566
+ line, char, new_name, *expected_refs = tup
567
+ references = str(
568
+ lsp.rename_symbol(circle_file, lspt.Position(line, char), new_name)
569
+ )
570
+ for expected in expected_refs:
571
+ self.assertIn(expected, references)