jaclang 0.7.17__py3-none-any.whl → 0.7.19__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 (33) hide show
  1. jaclang/cli/cli.py +5 -7
  2. jaclang/compiler/passes/ir_pass.py +2 -0
  3. jaclang/compiler/passes/main/import_pass.py +2 -1
  4. jaclang/compiler/passes/main/py_collect_dep_pass.py +8 -0
  5. jaclang/compiler/passes/main/pyast_gen_pass.py +25 -0
  6. jaclang/compiler/passes/main/registry_pass.py +4 -0
  7. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.pyi +3 -0
  8. jaclang/compiler/passes/main/tests/test_import_pass.py +10 -10
  9. jaclang/compiler/passes/main/type_check_pass.py +4 -4
  10. jaclang/compiler/passes/tool/jac_formatter_pass.py +52 -32
  11. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/line_spacing.jac +55 -0
  12. jaclang/langserve/engine.py +28 -16
  13. jaclang/langserve/tests/fixtures/import_include_statements.jac +3 -3
  14. jaclang/langserve/tests/test_server.py +10 -6
  15. jaclang/langserve/utils.py +11 -100
  16. jaclang/plugin/builtin.py +8 -4
  17. jaclang/plugin/default.py +17 -3
  18. jaclang/plugin/feature.py +10 -0
  19. jaclang/plugin/spec.py +12 -0
  20. jaclang/runtimelib/importer.py +2 -0
  21. jaclang/runtimelib/machine.py +45 -3
  22. jaclang/runtimelib/memory.py +6 -6
  23. jaclang/settings.py +4 -0
  24. jaclang/tests/fixtures/bar.jac +1 -1
  25. jaclang/tests/fixtures/builtin_dotgen.jac +1 -0
  26. jaclang/tests/fixtures/foo.jac +0 -1
  27. jaclang/tests/fixtures/objref.jac +12 -0
  28. jaclang/tests/fixtures/walker_update.jac +19 -0
  29. jaclang/tests/test_language.py +73 -4
  30. {jaclang-0.7.17.dist-info → jaclang-0.7.19.dist-info}/METADATA +6 -2
  31. {jaclang-0.7.17.dist-info → jaclang-0.7.19.dist-info}/RECORD +33 -29
  32. {jaclang-0.7.17.dist-info → jaclang-0.7.19.dist-info}/WHEEL +0 -0
  33. {jaclang-0.7.17.dist-info → jaclang-0.7.19.dist-info}/entry_points.txt +0 -0
jaclang/cli/cli.py CHANGED
@@ -8,7 +8,6 @@ import pickle
8
8
  import shutil
9
9
  import types
10
10
  from typing import Optional
11
- from uuid import UUID
12
11
 
13
12
  import jaclang.compiler.absyntree as ast
14
13
  from jaclang import jac_import
@@ -159,10 +158,9 @@ def get_object(
159
158
  raise ValueError("Not a valid file!\nOnly supports `.jac` and `.jir`")
160
159
 
161
160
  data = {}
162
- if id == "root":
163
- data = jctx.root.__getstate__()
164
- elif obj := jctx.mem.find_by_id(UUID(id)):
165
- data = obj.__getstate__()
161
+ obj = Jac.get_object(id)
162
+ if obj:
163
+ data = obj.__jac__.__getstate__()
166
164
  else:
167
165
  print(f"Object with id {id} not found.")
168
166
 
@@ -431,8 +429,8 @@ def dot(
431
429
 
432
430
  if filename.endswith(".jac"):
433
431
  jac_machine = JacMachine(base)
434
- jac_import(target=mod, base_path=base)
435
- module = jac_machine.loaded_modules.get(mod)
432
+ jac_import(target=mod, base_path=base, override_name="__main__")
433
+ module = jac_machine.loaded_modules.get("__main__")
436
434
  globals().update(vars(module))
437
435
  try:
438
436
  node = globals().get(initial, eval(initial)) if initial else None
@@ -133,6 +133,8 @@ class Pass(Transform[T]):
133
133
  else:
134
134
  self.prune_signal = False
135
135
  self.cur_node = node
136
+ if self.term_signal:
137
+ return node
136
138
  self.exit_node(node)
137
139
  return node
138
140
 
@@ -13,6 +13,7 @@ from typing import Optional
13
13
  import jaclang.compiler.absyntree as ast
14
14
  from jaclang.compiler.passes import Pass
15
15
  from jaclang.compiler.passes.main import SubNodeTabPass, SymTabBuildPass
16
+ from jaclang.settings import settings
16
17
  from jaclang.utils.log import logging
17
18
 
18
19
 
@@ -105,7 +106,7 @@ class JacImportPass(Pass):
105
106
  or test_folder == os.path.dirname(cur_file)
106
107
  ) and cur_file.endswith(".test.jac"):
107
108
  mod = self.import_jac_mod_from_file(cur_file)
108
- if mod:
109
+ if mod and not settings.ignore_test_annex:
109
110
  node.test_mod.append(mod)
110
111
  node.add_kids_right([mod], pos_update=False)
111
112
  mod.parent = node
@@ -7,6 +7,8 @@ that are only relevant to actual references source from Jac code.
7
7
  from __future__ import annotations
8
8
 
9
9
 
10
+ import os
11
+
10
12
  import jaclang.compiler.absyntree as ast
11
13
  from jaclang.compiler.passes import Pass
12
14
  from jaclang.settings import settings
@@ -28,11 +30,15 @@ class PyCollectDepsPass(Pass):
28
30
  if not isinstance(node, ast.AstSymbolNode):
29
31
  return
30
32
 
33
+ # Adding the path of the file related to the py import
31
34
  path: str = ""
32
35
  if isinstance(node, ast.ModulePath):
33
36
  if node.path:
34
37
  path = ".".join([i.value for i in node.path])
35
38
  node.abs_path = self.ir.py_mod_dep_map.get(path)
39
+ if node.abs_path and os.path.isfile(node.abs_path.replace(".pyi", ".py")):
40
+ node.abs_path = node.abs_path.replace(".pyi", ".py")
41
+
36
42
  elif isinstance(node, ast.ModuleItem):
37
43
  imp = node.parent_of_type(ast.Import)
38
44
  mod_path_node = imp.get_all_sub_nodes(ast.ModulePath)[0]
@@ -40,6 +46,8 @@ class PyCollectDepsPass(Pass):
40
46
  path = ".".join([i.value for i in mod_path_node.path])
41
47
  path += f".{node.name.value}"
42
48
  node.abs_path = self.ir.py_mod_dep_map.get(path)
49
+ if node.abs_path and os.path.isfile(node.abs_path.replace(".pyi", ".py")):
50
+ node.abs_path = node.abs_path.replace(".pyi", ".py")
43
51
 
44
52
  if len(node.gen.mypy_ast) == 0:
45
53
  return
@@ -2641,6 +2641,31 @@ class PyastGenPass(Pass):
2641
2641
  ]
2642
2642
  elif node.op.name in [Tok.STAR_POW]:
2643
2643
  node.gen.py_ast = node.operand.gen.py_ast
2644
+ elif node.op.name in [Tok.BW_AND]:
2645
+ node.gen.py_ast = [
2646
+ self.sync(
2647
+ ast3.Call(
2648
+ func=self.sync(
2649
+ ast3.Attribute(
2650
+ value=self.sync(
2651
+ ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
2652
+ ),
2653
+ attr="get_object",
2654
+ ctx=ast3.Load(),
2655
+ )
2656
+ ),
2657
+ args=[],
2658
+ keywords=[
2659
+ self.sync(
2660
+ ast3.keyword(
2661
+ arg="id",
2662
+ value=node.operand.gen.py_ast[0],
2663
+ )
2664
+ ),
2665
+ ],
2666
+ )
2667
+ )
2668
+ ]
2644
2669
  else:
2645
2670
  self.ice(f"Unknown Unary operator {node.op.value}")
2646
2671
 
@@ -14,6 +14,7 @@ from jaclang.compiler.constant import Constants as Con
14
14
  from jaclang.compiler.passes import Pass
15
15
  from jaclang.compiler.semtable import SemInfo, SemRegistry
16
16
  from jaclang.runtimelib.utils import get_sem_scope
17
+ from jaclang.settings import settings
17
18
 
18
19
 
19
20
  class RegistryPass(Pass):
@@ -23,6 +24,9 @@ class RegistryPass(Pass):
23
24
 
24
25
  def enter_module(self, node: ast.Module) -> None:
25
26
  """Create registry for each module."""
27
+ if settings.disable_mtllm:
28
+ self.terminate()
29
+ return None
26
30
  node.registry = SemRegistry()
27
31
  self.modules_visited.append(node)
28
32
 
@@ -0,0 +1,3 @@
1
+ from .display import *
2
+ from .color import *
3
+ from .constants import *
@@ -70,19 +70,19 @@ class ImportPassPassTests(TestCase):
70
70
  )
71
71
  assert isinstance(build.ir, ast.Module)
72
72
  p = {
73
- "math": "jaclang/jaclang/vendor/mypy/typeshed/stdlib/math.pyi",
74
- "pygame_mock": "pygame_mock/__init__.py",
75
- "pygame_mock.color": "pygame_mock/color.py",
76
- "pygame_mock.constants": "pygame_mock/constants.py",
77
- "argparse": "jaclang/vendor/mypy/typeshed/stdlib/argparse.pyi",
78
- "builtins": "jaclang/vendor/mypy/typeshed/stdlib/builtins.pyi",
79
- "pygame_mock.display": "pygame_mock/display.py",
80
- "os": "jaclang/vendor/mypy/typeshed/stdlib/os/__init__.pyi",
81
- "genericpath": "jaclang/vendor/mypy/typeshed/stdlib/genericpath.pyi",
73
+ "math": r"jaclang/vendor/mypy/typeshed/stdlib/math.pyi$",
74
+ "pygame_mock": r"pygame_mock/__init__.pyi$",
75
+ "pygame_mock.color": r"pygame_mock/color.py$",
76
+ "pygame_mock.constants": r"pygame_mock/constants.py$",
77
+ "argparse": r"jaclang/vendor/mypy/typeshed/stdlib/argparse.pyi$",
78
+ "builtins": r"jaclang/vendor/mypy/typeshed/stdlib/builtins.pyi$",
79
+ "pygame_mock.display": r"pygame_mock/display.py$",
80
+ "os": r"jaclang/vendor/mypy/typeshed/stdlib/os/__init__.pyi$",
81
+ "genericpath": r"jaclang/vendor/mypy/typeshed/stdlib/genericpath.pyi$",
82
82
  }
83
83
  for i in p:
84
84
  self.assertIn(i, build.ir.py_raise_map)
85
- self.assertIn(p[i], re.sub(r".*fixtures/", "", build.ir.py_raise_map[i]))
85
+ self.assertRegex(re.sub(r".*fixtures/", "", build.ir.py_raise_map[i]), p[i])
86
86
 
87
87
  def test_py_raised_mods(self) -> None:
88
88
  """Basic test for pass."""
@@ -51,10 +51,10 @@ class JacTypeCheckPass(Pass):
51
51
  options.ignore_missing_imports = True
52
52
  options.cache_dir = Con.JAC_MYPY_CACHE
53
53
  options.mypy_path = [
54
- str(
55
- pathlib.Path(os.path.dirname(__file__)).parent.parent.parent.parent
56
- / "stubs"
57
- )
54
+ # str( # TODO: Remove me, this was the wrong way to point to stubs
55
+ # pathlib.Path(os.path.dirname(__file__)).parent.parent.parent.parent
56
+ # / "stubs"
57
+ # )
58
58
  ]
59
59
  if top_module_path != "":
60
60
  options.mypy_path.append(top_module_path)
@@ -126,11 +126,14 @@ class JacFormatPass(Pass):
126
126
  last_element = None
127
127
  for counter, i in enumerate(node.body):
128
128
  counter += 1
129
+ if last_element and (
130
+ i.loc.first_line - last_element.loc.last_line > 1
131
+ and not last_element.gen.jac.endswith("\n\n")
132
+ ):
133
+ self.emit_ln(node, "")
129
134
  if isinstance(i, ast.Import):
130
135
  self.emit_ln(node, i.gen.jac)
131
136
  else:
132
- if isinstance(last_element, ast.Import):
133
- self.emit_ln(node, "")
134
137
  if last_element and (
135
138
  isinstance(i, ast.Architype)
136
139
  and isinstance(last_element, ast.Architype)
@@ -140,21 +143,6 @@ class JacFormatPass(Pass):
140
143
  self.emit_ln(node, "")
141
144
  self.emit_ln(node, i.gen.jac)
142
145
 
143
- if counter <= len(node.body) - 1:
144
- if (
145
- isinstance(i, ast.Ability)
146
- and isinstance(node.body[counter], ast.Ability)
147
- and i.gen.jac.endswith(";")
148
- or (
149
- isinstance(i, ast.Architype)
150
- and len(node.body[counter].kid[-1].kid) == 2
151
- and len(node.body[counter - 1].kid[-1].kid) == 2
152
- )
153
- and node.gen.jac.endswith("\n")
154
- ):
155
- self.emit(node, "")
156
- else:
157
- self.emit_ln(node, "")
158
146
  last_element = i
159
147
 
160
148
  def exit_global_vars(self, node: ast.GlobalVars) -> None:
@@ -222,6 +210,20 @@ class JacFormatPass(Pass):
222
210
  """
223
211
  prev_token = None
224
212
  for stmt in node.kid:
213
+ line_emiited = False
214
+ if prev_token and stmt.loc.first_line - prev_token.loc.last_line > 1:
215
+ if (
216
+ stmt.kid
217
+ and isinstance(stmt.kid[-1], ast.SubNodeList)
218
+ and not isinstance(stmt.kid[-1].kid[-1], ast.CommentToken)
219
+ ):
220
+ self.emit(node, "")
221
+
222
+ else:
223
+ line_emiited = True
224
+ self.indent_level -= 1
225
+ self.emit_ln(node, "")
226
+ self.indent_level += 1
225
227
  if isinstance(node.parent, (ast.EnumDef, ast.Enum)) and stmt.gen.jac == ",":
226
228
  self.indent_level -= 1
227
229
  self.emit_ln(node, f"{stmt.gen.jac}")
@@ -266,9 +268,10 @@ class JacFormatPass(Pass):
266
268
  self.indent_level += 1
267
269
  else:
268
270
  self.emit(node, f" {stmt.gen.jac}")
269
- self.indent_level -= 1
270
- self.emit_ln(node, "")
271
- self.indent_level += 1
271
+ if not line_emiited:
272
+ self.indent_level -= 1
273
+ self.emit_ln(node, "")
274
+ self.indent_level += 1
272
275
  else:
273
276
  if not node.gen.jac.endswith("\n"):
274
277
  self.indent_level -= 1
@@ -280,11 +283,10 @@ class JacFormatPass(Pass):
280
283
  self.emit(node, f"{stmt.gen.jac}")
281
284
  else:
282
285
  self.emit(node, stmt.gen.jac)
283
- if not stmt.gen.jac.endswith("postinit;"):
284
- self.indent_level -= 1
285
- self.emit_ln(stmt, "")
286
- self.emit_ln(node, "")
287
- self.indent_level += 1
286
+ self.indent_level -= 1
287
+ self.emit_ln(stmt, "")
288
+ self.emit_ln(node, "")
289
+ self.indent_level += 1
288
290
  elif stmt.gen.jac == ",":
289
291
  self.emit(node, f"{stmt.value} ")
290
292
  elif stmt.value == "=":
@@ -304,10 +306,29 @@ class JacFormatPass(Pass):
304
306
  isinstance(prev_token, ast.Ability)
305
307
  and isinstance(stmt, (ast.Ability, ast.AbilityDef))
306
308
  ):
307
- if not isinstance(prev_token.kid[-1], ast.CommentToken):
308
- self.indent_level -= 1
309
- self.emit_ln(node, "")
310
- self.indent_level += 1
309
+ if (
310
+ not isinstance(prev_token.kid[-1], ast.CommentToken)
311
+ and not line_emiited
312
+ ):
313
+ if (
314
+ prev_token.kid
315
+ and isinstance(prev_token.kid[-1], ast.SubNodeList)
316
+ and isinstance(prev_token.kid[-1].kid[-1], ast.CommentToken)
317
+ ):
318
+ if (
319
+ prev_token
320
+ and stmt.loc.first_line - prev_token.kid[-1].kid[-1].line_no
321
+ > 1
322
+ ):
323
+ self.indent_level -= 1
324
+ self.emit_ln(node, "")
325
+ self.indent_level += 1
326
+ else:
327
+ self.emit(node, "")
328
+ else:
329
+ self.indent_level -= 1
330
+ self.emit_ln(node, "")
331
+ self.indent_level += 1
311
332
  self.emit(node, stmt.gen.jac)
312
333
  else:
313
334
  if prev_token and prev_token.gen.jac.strip() == "{":
@@ -907,8 +928,6 @@ class JacFormatPass(Pass):
907
928
  """Check if the length of the current generated code exceeds the max line length."""
908
929
  if max_line_length == 0:
909
930
  max_line_length = self.MAX_LINE_LENGTH
910
- # print(content)
911
- # print(len(content))
912
931
  return len(content) > max_line_length
913
932
 
914
933
  def exit_binary_expr(self, node: ast.BinaryExpr) -> None:
@@ -958,7 +977,6 @@ class JacFormatPass(Pass):
958
977
  self.error(
959
978
  f"Binary operator {node.op.value} not supported in bootstrap Jac"
960
979
  )
961
- # print(node.gen)
962
980
  if isinstance(
963
981
  node.kid[-1], (ast.Semi, ast.CommentToken)
964
982
  ) and not node.gen.jac.endswith("\n"):
@@ -1562,6 +1580,8 @@ class JacFormatPass(Pass):
1562
1580
  self.emit(node, f"not {node.operand.gen.jac}")
1563
1581
  elif node.op.name in [Tok.PIPE_FWD, Tok.KW_SPAWN, Tok.A_PIPE_FWD]:
1564
1582
  self.emit(node, f"{node.op.value} {node.operand.gen.jac}")
1583
+ elif node.op.name in [Tok.BW_AND]:
1584
+ self.emit(node, f"{node.op.value}{node.operand.gen.jac}")
1565
1585
  else:
1566
1586
  self.error(f"Unary operator {node.op.value} not supported in bootstrap Jac")
1567
1587
 
@@ -0,0 +1,55 @@
1
+ import:py math;
2
+
3
+ glob RAD = 5;
4
+ glob DIA = 10;
5
+
6
+ # this comment is for walker
7
+ walker decorator_walk {
8
+ can hash(func: Any) {
9
+ can inner(a: Any) {
10
+ print(("#" * 20));
11
+ func(a);
12
+ print(("#" * 20));
13
+ }
14
+ return inner;
15
+ }
16
+
17
+ can exclaim(func: Any) {
18
+ can inner(b: Any) {
19
+ print(("!" * 20));
20
+ func(b);
21
+ print(("!" * 20));
22
+ }
23
+ return inner;
24
+ }
25
+
26
+ can tilde(func: Any) {
27
+ can inner(c: Any) {
28
+ print(("~" * 20));
29
+ func(c);
30
+ print(("~" * 20));
31
+ }
32
+ return inner;
33
+ }
34
+
35
+ can greeter(name: Any) {
36
+ print("Hello, " + name + "!");
37
+ }
38
+
39
+ # Entry point for the walker
40
+
41
+ can start with entry {
42
+ # Apply decorators to greeter
43
+ decorated_greeter = hash(exclaim(tilde(greeter)));
44
+
45
+ # Call the decorated greeter function
46
+ decorated_greeter("World");
47
+
48
+ # this is another comment
49
+
50
+ }
51
+ }
52
+
53
+ with entry {
54
+ root spawn decorator_walk();
55
+ }
@@ -22,8 +22,7 @@ from jaclang.langserve.utils import (
22
22
  find_deepest_symbol_node_at_pos,
23
23
  find_index,
24
24
  gen_diagnostics,
25
- get_item_path,
26
- get_mod_path,
25
+ get_location_range,
27
26
  get_symbols_for_outline,
28
27
  parse_symbol_path,
29
28
  resolve_completion_symbol_table,
@@ -335,8 +334,9 @@ class JacLangServer(LanguageServer):
335
334
  and node_selected.parent
336
335
  and isinstance(node_selected.parent, ast.ModulePath)
337
336
  ):
338
- spec = get_mod_path(node_selected.parent, node_selected)
337
+ spec = node_selected.parent.abs_path
339
338
  if spec:
339
+ spec = spec[5:] if spec.startswith("File:") else spec
340
340
  return lspt.Location(
341
341
  uri=uris.from_fs_path(spec),
342
342
  range=lspt.Range(
@@ -349,19 +349,31 @@ class JacLangServer(LanguageServer):
349
349
  elif node_selected.parent and isinstance(
350
350
  node_selected.parent, ast.ModuleItem
351
351
  ):
352
- path_range = get_item_path(node_selected.parent)
353
- if path_range:
354
- path, loc_range = path_range
355
- if path and loc_range:
356
- return lspt.Location(
357
- uri=uris.from_fs_path(path),
358
- range=lspt.Range(
359
- start=lspt.Position(line=loc_range[0], character=0),
360
- end=lspt.Position(line=loc_range[1], character=5),
352
+ path = (
353
+ node_selected.parent.abs_path
354
+ or node_selected.parent.from_mod_path.abs_path
355
+ )
356
+ try: # TODO: Get rid of this when 'from' import is fixed
357
+ loc_range = tuple(
358
+ loc - 1 if loc > 0 else loc
359
+ for loc in get_location_range(node_selected.parent)
360
+ )
361
+ except ValueError:
362
+ loc_range = (0, 0, 0, 0)
363
+
364
+ if path and loc_range:
365
+ path = path[5:] if path.startswith("File:") else path
366
+ return lspt.Location(
367
+ uri=uris.from_fs_path(path),
368
+ range=lspt.Range(
369
+ start=lspt.Position(
370
+ line=loc_range[0], character=loc_range[1]
361
371
  ),
362
- )
363
- else:
364
- return None
372
+ end=lspt.Position(
373
+ line=loc_range[2], character=loc_range[3]
374
+ ),
375
+ ),
376
+ )
365
377
  elif isinstance(node_selected, (ast.ElementStmt, ast.BuiltinType)):
366
378
  return None
367
379
  decl_node = (
@@ -378,7 +390,7 @@ class JacLangServer(LanguageServer):
378
390
  decl_uri = uris.from_fs_path(decl_node.loc.mod_path)
379
391
  try:
380
392
  decl_range = create_range(decl_node.loc)
381
- except ValueError: # 'print' name has decl in 0,0,0,0
393
+ except ValueError:
382
394
  return None
383
395
  decl_location = lspt.Location(
384
396
  uri=decl_uri,
@@ -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}
@@ -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:
@@ -214,9 +218,9 @@ class TestJacLangServer(TestCase):
214
218
  )
215
219
  lsp.deep_check(import_file)
216
220
  positions = [
217
- (6, 39, "/pygame_mock/__init__.py:2:0-2:0"),
221
+ (6, 39, "/pygame_mock/__init__.pyi:2:0-2:0"),
218
222
  (6, 45, "/pygame_mock/constants.py:3:0-4:1"),
219
- (7, 31, "/pygame_mock/__init__.py:2:0-2:0"),
223
+ (7, 31, "/pygame_mock/__init__.pyi:2:0-2:0"),
220
224
  (7, 35, "/pygame_mock/constants.py:3:0-4:1"),
221
225
  (20, 51, "/py_imp_test.jac:6:4-6:11"),
222
226
  (20, 64, "/pygame_mock/constants.py:4:3-4:15"),
@@ -2,10 +2,7 @@
2
2
 
3
3
  import asyncio
4
4
  import builtins
5
- import importlib.util
6
- import os
7
5
  import re
8
- import sys
9
6
  from functools import wraps
10
7
  from typing import Any, Awaitable, Callable, Coroutine, Optional, ParamSpec, TypeVar
11
8
 
@@ -209,6 +206,17 @@ def create_range(loc: CodeLocInfo) -> lspt.Range:
209
206
  )
210
207
 
211
208
 
209
+ def get_location_range(mod_item: ast.ModuleItem) -> tuple[int, int, int, int]:
210
+ """Get location range."""
211
+ if not mod_item.from_mod_path.sub_module:
212
+ raise ValueError("Module items should have module path. Not Possible.")
213
+ lookup = mod_item.from_mod_path.sub_module.sym_tab.lookup(mod_item.name.value)
214
+ if not lookup:
215
+ raise ValueError("Module items should have a symbol table entry. Not Possible.")
216
+ loc = lookup.decl.loc
217
+ return loc.first_line, loc.col_start, loc.last_line, loc.col_end
218
+
219
+
212
220
  def kind_map(sub_tab: ast.AstNode) -> lspt.SymbolKind:
213
221
  """Map the symbol node to an lspt.SymbolKind."""
214
222
  return (
@@ -273,103 +281,6 @@ def label_map(sub_tab: SymbolType) -> lspt.CompletionItemKind:
273
281
  )
274
282
 
275
283
 
276
- def get_mod_path(
277
- mod_path: ast.ModulePath, name_node: ast.Name
278
- ) -> str | None: # TODO: This should go away
279
- """Get path for a module import name."""
280
- ret_target = None
281
- if mod_path.parent and (
282
- (
283
- isinstance(mod_path.parent.parent, ast.Import)
284
- and mod_path.parent.parent.is_py
285
- )
286
- or (
287
- isinstance(mod_path.parent, ast.Import)
288
- and mod_path.parent.from_loc
289
- and mod_path.parent.is_py
290
- )
291
- ):
292
- if mod_path.path and name_node in mod_path.path:
293
- temporary_path_str = ("." * mod_path.level) + ".".join(
294
- [p.value for p in mod_path.path[: mod_path.path.index(name_node) + 1]]
295
- if mod_path.path
296
- else ""
297
- )
298
- else:
299
- temporary_path_str = mod_path.dot_path_str
300
- sys.path.append(os.path.dirname(mod_path.loc.mod_path))
301
- spec = importlib.util.find_spec(temporary_path_str)
302
- sys.path.remove(os.path.dirname(mod_path.loc.mod_path))
303
- if spec and spec.origin and spec.origin.endswith(".py"):
304
- ret_target = spec.origin
305
- elif mod_path.parent and (
306
- (
307
- isinstance(mod_path.parent.parent, ast.Import)
308
- and mod_path.parent.parent.is_jac
309
- )
310
- or (
311
- isinstance(mod_path.parent, ast.Import)
312
- and mod_path.parent.from_loc
313
- and mod_path.parent.is_jac
314
- )
315
- ):
316
- ret_target = mod_path.resolve_relative_path()
317
- return ret_target
318
-
319
-
320
- def get_item_path(mod_item: ast.ModuleItem) -> tuple[str, tuple[int, int]] | None:
321
- """Get path."""
322
- item_name = mod_item.name.value
323
- if mod_item.from_parent.is_py and mod_item.from_parent.from_loc:
324
- path = get_mod_path(mod_item.from_parent.from_loc, mod_item.name)
325
- if path:
326
- return get_definition_range(path, item_name)
327
- elif mod_item.from_parent.is_jac:
328
- mod_node = mod_item.from_mod_path
329
- if mod_node.sub_module and mod_node.sub_module._sym_tab:
330
- for symbol_name, symbol in mod_node.sub_module._sym_tab.tab.items():
331
- if symbol_name == item_name:
332
- return symbol.decl.loc.mod_path, (
333
- symbol.decl.loc.first_line - 1,
334
- symbol.decl.loc.last_line - 1,
335
- )
336
- return None
337
-
338
-
339
- def get_definition_range(
340
- filename: str, name: str
341
- ) -> tuple[str, tuple[int, int]] | None:
342
- """Get the start and end line of a function or class definition in a file."""
343
- import ast
344
-
345
- with open(filename, "r") as file:
346
- source = file.read()
347
-
348
- tree = ast.parse(source)
349
-
350
- for node in ast.walk(tree):
351
- if isinstance(node, (ast.FunctionDef, ast.ClassDef)) and node.name == name:
352
- start_line = node.lineno
353
- end_line = (
354
- node.body[-1].end_lineno
355
- if hasattr(node.body[-1], "end_lineno")
356
- else node.body[-1].lineno
357
- )
358
- if start_line and end_line:
359
- return filename, (start_line - 1, end_line - 1)
360
- elif isinstance(node, ast.Assign):
361
- for target in node.targets:
362
- if isinstance(target, ast.Name) and target.id == name:
363
- start_line = node.lineno
364
- end_line = (
365
- node.end_lineno if hasattr(node, "end_lineno") else node.lineno
366
- )
367
- if start_line and end_line:
368
- return filename, (start_line - 1, end_line - 1)
369
-
370
- return None
371
-
372
-
373
284
  def collect_all_symbols_in_scope(
374
285
  sym_tab: SymbolTable, up_tree: bool = True
375
286
  ) -> list[lspt.CompletionItem]: