jaclang 0.7.9__py3-none-any.whl → 0.7.13__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 (35) hide show
  1. jaclang/cli/cli.py +13 -3
  2. jaclang/compiler/absyntree.py +10 -2
  3. jaclang/compiler/parser.py +2 -1
  4. jaclang/compiler/passes/ir_pass.py +9 -0
  5. jaclang/compiler/passes/main/import_pass.py +15 -2
  6. jaclang/compiler/passes/main/pyast_gen_pass.py +238 -32
  7. jaclang/compiler/passes/main/pyast_load_pass.py +3 -1
  8. jaclang/compiler/passes/main/tests/test_import_pass.py +13 -0
  9. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -2
  10. jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
  11. jaclang/compiler/passes/main/type_check_pass.py +0 -17
  12. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
  13. jaclang/compiler/tests/test_importer.py +1 -1
  14. jaclang/core/importer.py +233 -62
  15. jaclang/langserve/engine.py +182 -136
  16. jaclang/langserve/server.py +29 -7
  17. jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -2
  18. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  19. jaclang/langserve/tests/test_server.py +73 -66
  20. jaclang/langserve/utils.py +266 -0
  21. jaclang/plugin/default.py +7 -4
  22. jaclang/plugin/feature.py +3 -3
  23. jaclang/plugin/spec.py +3 -3
  24. jaclang/settings.py +1 -0
  25. jaclang/tests/fixtures/deep/one_lev.jac +6 -4
  26. jaclang/tests/fixtures/needs_import.jac +1 -1
  27. jaclang/tests/test_cli.py +7 -9
  28. jaclang/tests/test_language.py +9 -13
  29. jaclang/tests/test_man_code.py +8 -10
  30. jaclang/utils/helpers.py +3 -3
  31. jaclang/utils/test.py +8 -0
  32. {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/METADATA +2 -2
  33. {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/RECORD +35 -35
  34. {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/WHEEL +0 -0
  35. {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/entry_points.txt +0 -0
@@ -39,36 +39,6 @@ class TestJacLangServer(TestCase):
39
39
  ],
40
40
  )
41
41
 
42
- def test_syntax_diagnostics(self) -> None:
43
- """Test diagnostics."""
44
- lsp = JacLangServer()
45
- # Set up the workspace path to "fixtures/"
46
- workspace_path = self.fixture_abs_path("")
47
- workspace = Workspace(workspace_path, lsp)
48
- lsp.lsp._workspace = workspace
49
- circle_file = uris.from_fs_path(self.fixture_abs_path("circle_err.jac"))
50
- lsp.quick_check(circle_file)
51
- self.assertEqual(len(lsp.modules), 1)
52
- self.assertEqual(lsp.modules[circle_file].diagnostics[0].range.start.line, 22)
53
-
54
- def test_doesnt_run_if_syntax_error(self) -> None:
55
- """Test that the server doesn't run if there is a syntax error."""
56
- lsp = JacLangServer()
57
- # Set up the workspace path to "fixtures/"
58
- workspace_path = self.fixture_abs_path("")
59
- workspace = Workspace(workspace_path, lsp)
60
- lsp.lsp._workspace = workspace
61
- circle_file = uris.from_fs_path(self.fixture_abs_path("circle_err.jac"))
62
- lsp.quick_check(circle_file)
63
- self.assertEqual(len(lsp.modules), 1)
64
- self.assertEqual(lsp.modules[circle_file].diagnostics[0].range.start.line, 22)
65
- lsp.deep_check(circle_file)
66
- # self.assertEqual(len(lsp.modules), 1)
67
- self.assertEqual(lsp.modules[circle_file].diagnostics[0].range.start.line, 22)
68
- lsp.type_check(circle_file)
69
- # self.assertEqual(len(lsp.modules), 1)
70
- self.assertEqual(lsp.modules[circle_file].diagnostics[0].range.start.line, 22)
71
-
72
42
  def test_impl_stay_connected(self) -> None:
73
43
  """Test that the server doesn't run if there is a syntax error."""
74
44
  lsp = JacLangServer()
@@ -80,15 +50,13 @@ class TestJacLangServer(TestCase):
80
50
  circle_impl_file = uris.from_fs_path(
81
51
  self.fixture_abs_path("circle_pure.impl.jac")
82
52
  )
83
- lsp.quick_check(circle_file)
84
53
  lsp.deep_check(circle_file)
85
- lsp.type_check(circle_file)
86
54
  pos = lspt.Position(20, 8)
87
55
  self.assertIn(
88
56
  "Circle class inherits from Shape.",
89
57
  lsp.get_hover_info(circle_file, pos).contents.value,
90
58
  )
91
- lsp.type_check(circle_impl_file)
59
+ lsp.deep_check(circle_impl_file)
92
60
  pos = lspt.Position(8, 11)
93
61
  self.assertIn(
94
62
  "ability) calculate_area: float",
@@ -105,9 +73,7 @@ class TestJacLangServer(TestCase):
105
73
  circle_impl_file = uris.from_fs_path(
106
74
  self.fixture_abs_path("circle_pure.impl.jac")
107
75
  )
108
- lsp.quick_check(circle_impl_file)
109
76
  lsp.deep_check(circle_impl_file)
110
- lsp.type_check(circle_impl_file)
111
77
  pos = lspt.Position(8, 11)
112
78
  self.assertIn(
113
79
  "ability) calculate_area: float",
@@ -121,12 +87,8 @@ class TestJacLangServer(TestCase):
121
87
  workspace_path = self.fixture_abs_path("")
122
88
  workspace = Workspace(workspace_path, lsp)
123
89
  lsp.lsp._workspace = workspace
124
- target = uris.from_fs_path(
125
- self.fixture_abs_path("../../../../examples/guess_game/guess_game4.jac")
126
- )
127
- lsp.quick_check(target)
90
+ target = uris.from_fs_path(self.examples_abs_path("guess_game/guess_game4.jac"))
128
91
  lsp.deep_check(target)
129
- lsp.type_check(target)
130
92
  pos = lspt.Position(43, 18)
131
93
  self.assertIn(
132
94
  "attempts: int",
@@ -140,9 +102,7 @@ class TestJacLangServer(TestCase):
140
102
  workspace = Workspace(workspace_path, lsp)
141
103
  lsp.lsp._workspace = workspace
142
104
  circle_file = uris.from_fs_path(self.fixture_abs_path("circle_pure.jac"))
143
- lsp.quick_check(circle_file)
144
105
  lsp.deep_check(circle_file)
145
- lsp.type_check(circle_file)
146
106
  self.assertEqual(8, len(lsp.get_document_symbols(circle_file)))
147
107
 
148
108
  def test_go_to_definition(self) -> None:
@@ -152,9 +112,7 @@ class TestJacLangServer(TestCase):
152
112
  workspace = Workspace(workspace_path, lsp)
153
113
  lsp.lsp._workspace = workspace
154
114
  circle_file = uris.from_fs_path(self.fixture_abs_path("circle_pure.jac"))
155
- lsp.quick_check(circle_file)
156
115
  lsp.deep_check(circle_file)
157
- lsp.type_check(circle_file)
158
116
  self.assertIn(
159
117
  "fixtures/circle_pure.impl.jac:8:0-8:19",
160
118
  str(lsp.get_definition(circle_file, lspt.Position(9, 16))),
@@ -171,11 +129,9 @@ class TestJacLangServer(TestCase):
171
129
  workspace = Workspace(workspace_path, lsp)
172
130
  lsp.lsp._workspace = workspace
173
131
  guess_game_file = uris.from_fs_path(
174
- self.fixture_abs_path("../../../../examples/guess_game/guess_game4.jac")
132
+ self.examples_abs_path("guess_game/guess_game4.jac")
175
133
  )
176
- lsp.quick_check(guess_game_file)
177
134
  lsp.deep_check(guess_game_file)
178
- lsp.type_check(guess_game_file)
179
135
  self.assertIn(
180
136
  "guess_game4.jac:27:8-27:21",
181
137
  str(lsp.get_definition(guess_game_file, lspt.Position(46, 45))),
@@ -189,9 +145,7 @@ class TestJacLangServer(TestCase):
189
145
  workspace = Workspace(workspace_path, lsp)
190
146
  lsp.lsp._workspace = workspace
191
147
  circle_file = uris.from_fs_path(self.fixture_abs_path("circle_pure.test.jac"))
192
- lsp.quick_check(circle_file)
193
148
  lsp.deep_check(circle_file)
194
- lsp.type_check(circle_file)
195
149
  pos = lspt.Position(13, 29)
196
150
  self.assertIn(
197
151
  "shape_type: circle_pure.ShapeType",
@@ -207,13 +161,11 @@ class TestJacLangServer(TestCase):
207
161
  import_file = uris.from_fs_path(
208
162
  self.fixture_abs_path("import_include_statements.jac")
209
163
  )
210
- lsp.quick_check(import_file)
211
164
  lsp.deep_check(import_file)
212
- lsp.type_check(import_file)
213
165
  positions = [
214
166
  (2, 16, "datetime.py:0:0-0:0"),
215
167
  (3, 17, "base_module_structure.jac:0:0-0:0"),
216
- (3, 74, "base_module_structure.jac:23:0-23:5"),
168
+ (3, 87, "base_module_structure.jac:23:0-23:5"),
217
169
  (5, 65, "py_import.py:12:0-20:5"),
218
170
  (5, 35, "py_import.py:3:0-4:5"),
219
171
  ]
@@ -232,35 +184,90 @@ class TestJacLangServer(TestCase):
232
184
  workspace = Workspace(workspace_path, lsp)
233
185
  lsp.lsp._workspace = workspace
234
186
  circle_file = uris.from_fs_path(self.fixture_abs_path("circle.jac"))
235
- lsp.quick_check(circle_file)
236
187
  lsp.deep_check(circle_file)
237
- lsp.type_check(circle_file)
238
188
  sem_list = lsp.get_semantic_tokens(circle_file).data
239
189
  expected_counts = [
240
- ("<JacSemTokenType.VARIABLE: 8>, <JacSemTokenModifier.READONLY: 4>", 206),
190
+ ("<JacSemTokenType.VARIABLE: 8>, <JacSemTokenModifier.READONLY: 4>", 12),
241
191
  (
242
192
  "<JacSemTokenType.PROPERTY: 9>, <JacSemTokenModifier.DEFINITION: 2>,",
243
- 112,
193
+ 19,
244
194
  ),
245
195
  (
246
196
  "<JacSemTokenType.PARAMETER: 7>, <JacSemTokenModifier.DECLARATION: 1>,",
247
- 56,
197
+ 5,
248
198
  ),
249
199
  (
250
200
  "<JacSemTokenType.FUNCTION: 12>, <JacSemTokenModifier.DECLARATION: 1>,",
251
- 25,
201
+ 9,
252
202
  ),
253
- ("<JacSemTokenType.METHOD: 13>, <JacSemTokenModifier.DECLARATION: 1>", 12),
254
- ("<JacSemTokenType.ENUM: 3>, <JacSemTokenModifier.DECLARATION: 1>,", 37),
255
- ("<JacSemTokenType.CLASS: 2>, <JacSemTokenModifier.DECLARATION: ", 162),
203
+ ("<JacSemTokenType.METHOD: 13>, <JacSemTokenModifier.DECLARATION: 1>", 6),
204
+ ("<JacSemTokenType.ENUM: 3>, <JacSemTokenModifier.DECLARATION: 1>,", 4),
205
+ ("<JacSemTokenType.CLASS: 2>, <JacSemTokenModifier.DECLARATION: ", 12),
256
206
  (
257
207
  "<JacSemTokenType.NAMESPACE: 0>, <JacSemTokenModifier.DEFINITION: 2>,",
258
- 10,
208
+ 3,
259
209
  ),
260
- ("0, 0, 4,", 22),
261
- ("0, 0, 3,", 192),
262
- ("0, 0, 6, ", 65),
263
- (" 0, 7, 3,", 3),
264
210
  ]
265
211
  for token_type, expected_count in expected_counts:
266
212
  self.assertEqual(str(sem_list).count(token_type), expected_count)
213
+
214
+ def test_completion(self) -> None:
215
+ """Test that the completions are correct."""
216
+ lsp = JacLangServer()
217
+ workspace_path = self.fixture_abs_path("")
218
+ workspace = Workspace(workspace_path, lsp)
219
+ lsp.lsp._workspace = workspace
220
+ base_module_file = uris.from_fs_path(
221
+ self.fixture_abs_path("base_module_structure.jac")
222
+ )
223
+ lsp.deep_check(base_module_file)
224
+ test_cases = [
225
+ (lspt.Position(37, 16), ["get_color1", "color1", "point1"], 3),
226
+ (
227
+ lspt.Position(51, 12),
228
+ [
229
+ "get_color1",
230
+ "color1",
231
+ "point1",
232
+ "base_colorred",
233
+ "pointred",
234
+ "color2",
235
+ ],
236
+ 6,
237
+ ),
238
+ (lspt.Position(52, 19), ["color22", "point22"], 2),
239
+ ]
240
+ for position, expected_completions, expected_length in test_cases:
241
+ completions = lsp.get_completion(
242
+ base_module_file, position, completion_trigger="."
243
+ ).items
244
+ for completion in expected_completions:
245
+ self.assertIn(completion, str(completions))
246
+ self.assertEqual(expected_length, len(completions))
247
+
248
+ if position == lspt.Position(47, 12):
249
+ self.assertEqual(
250
+ 1, str(completions).count("kind=<CompletionItemKind.Function: 3>")
251
+ )
252
+ self.assertEqual(
253
+ 4, str(completions).count("kind=<CompletionItemKind.Field: 5>")
254
+ )
255
+
256
+ def test_go_to_reference(self) -> None:
257
+ """Test that the go to reference is correct."""
258
+ lsp = JacLangServer()
259
+ workspace_path = self.fixture_abs_path("")
260
+ workspace = Workspace(workspace_path, lsp)
261
+ lsp.lsp._workspace = workspace
262
+
263
+ circle_file = uris.from_fs_path(self.fixture_abs_path("circle.jac"))
264
+ lsp.deep_check(circle_file)
265
+ test_cases = [
266
+ (47, 12, ["circle.jac:47:8-47:14", "69:8-69:14", "74:8-74:14"]),
267
+ (54, 66, ["54:62-54:76", "65:28-65:42"]),
268
+ (62, 14, ["65:49-65:62", "70:38-70:51"]),
269
+ ]
270
+ for line, char, expected_refs in test_cases:
271
+ references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
272
+ for expected in expected_refs:
273
+ self.assertIn(expected, references)
@@ -4,14 +4,18 @@ import asyncio
4
4
  import builtins
5
5
  import importlib.util
6
6
  import os
7
+ import re
7
8
  import sys
8
9
  from functools import wraps
9
10
  from typing import Any, Awaitable, Callable, Coroutine, Optional, ParamSpec, TypeVar
10
11
 
11
12
  import jaclang.compiler.absyntree as ast
12
13
  from jaclang.compiler.codeloc import CodeLocInfo
14
+ from jaclang.compiler.constant import SymbolType
15
+ from jaclang.compiler.passes.transform import Alert
13
16
  from jaclang.compiler.symtable import Symbol, SymbolTable
14
17
  from jaclang.utils.helpers import import_target_to_relative_path
18
+ from jaclang.vendor.pygls import uris
15
19
 
16
20
  import lsprotocol.types as lspt
17
21
 
@@ -19,6 +23,29 @@ T = TypeVar("T", bound=Callable[..., Coroutine[Any, Any, Any]])
19
23
  P = ParamSpec("P")
20
24
 
21
25
 
26
+ def gen_diagnostics(
27
+ from_path: str, errors: list[Alert], warnings: list[Alert]
28
+ ) -> list[lspt.Diagnostic]:
29
+ """Return diagnostics."""
30
+ return [
31
+ lspt.Diagnostic(
32
+ range=create_range(error.loc),
33
+ message=error.msg,
34
+ severity=lspt.DiagnosticSeverity.Error,
35
+ )
36
+ for error in errors
37
+ if error.loc.mod_path == uris.to_fs_path(from_path)
38
+ ] + [
39
+ lspt.Diagnostic(
40
+ range=create_range(warning.loc),
41
+ message=warning.msg,
42
+ severity=lspt.DiagnosticSeverity.Warning,
43
+ )
44
+ for warning in warnings
45
+ if warning.loc.mod_path == uris.to_fs_path(from_path)
46
+ ]
47
+
48
+
22
49
  def debounce(wait: float) -> Callable[[T], Callable[..., Awaitable[None]]]:
23
50
  """Debounce decorator for async functions."""
24
51
 
@@ -194,6 +221,49 @@ def kind_map(sub_tab: ast.AstNode) -> lspt.SymbolKind:
194
221
  )
195
222
 
196
223
 
224
+ def label_map(sub_tab: SymbolType) -> lspt.CompletionItemKind:
225
+ """Map the symbol node to an lspt.CompletionItemKind."""
226
+ return (
227
+ lspt.CompletionItemKind.Function
228
+ if sub_tab in [SymbolType.ABILITY, SymbolType.TEST]
229
+ else (
230
+ lspt.CompletionItemKind.Class
231
+ if sub_tab
232
+ in [
233
+ SymbolType.OBJECT_ARCH,
234
+ SymbolType.NODE_ARCH,
235
+ SymbolType.EDGE_ARCH,
236
+ SymbolType.WALKER_ARCH,
237
+ ]
238
+ else (
239
+ lspt.CompletionItemKind.Module
240
+ if sub_tab == SymbolType.MODULE
241
+ else (
242
+ lspt.CompletionItemKind.Enum
243
+ if sub_tab == SymbolType.ENUM_ARCH
244
+ else (
245
+ lspt.CompletionItemKind.Field
246
+ if sub_tab == SymbolType.HAS_VAR
247
+ else (
248
+ lspt.CompletionItemKind.Method
249
+ if sub_tab == SymbolType.METHOD
250
+ else (
251
+ lspt.CompletionItemKind.EnumMember
252
+ if sub_tab == SymbolType.ENUM_MEMBER
253
+ else (
254
+ lspt.CompletionItemKind.Interface
255
+ if sub_tab == SymbolType.IMPL
256
+ else lspt.CompletionItemKind.Variable
257
+ )
258
+ )
259
+ )
260
+ )
261
+ )
262
+ )
263
+ )
264
+ )
265
+
266
+
197
267
  def get_mod_path(mod_path: ast.ModulePath, name_node: ast.Name) -> str | None:
198
268
  """Get path for a module import name."""
199
269
  ret_target = None
@@ -292,3 +362,199 @@ def get_definition_range(
292
362
  return filename, (start_line - 1, end_line - 1)
293
363
 
294
364
  return None
365
+
366
+
367
+ def locate_affected_token(
368
+ tokens: list[int],
369
+ change_start_line: int,
370
+ change_start_char: int,
371
+ change_end_line: int,
372
+ change_end_char: int,
373
+ ) -> Optional[int]:
374
+ """Find in which token change is occurring."""
375
+ token_index = 0
376
+ current_line = 0
377
+ line_char_offset = 0
378
+
379
+ while token_index < len(tokens):
380
+ token_line_delta = tokens[token_index]
381
+ token_start_char = tokens[token_index + 1]
382
+ token_length = tokens[token_index + 2]
383
+
384
+ if token_line_delta > 0:
385
+ current_line += token_line_delta
386
+ line_char_offset = 0
387
+ token_abs_start_char = line_char_offset + token_start_char
388
+ token_abs_end_char = token_abs_start_char + token_length
389
+ if (
390
+ current_line == change_start_line == change_end_line
391
+ and token_abs_start_char <= change_start_char
392
+ and change_end_char <= token_abs_end_char
393
+ ):
394
+ return token_index
395
+ if (
396
+ current_line == change_start_line
397
+ and token_abs_start_char <= change_start_char < token_abs_end_char
398
+ ):
399
+ return token_index
400
+ if (
401
+ current_line == change_end_line
402
+ and token_abs_start_char < change_end_char <= token_abs_end_char
403
+ ):
404
+ return token_index
405
+
406
+ line_char_offset += token_start_char
407
+ token_index += 5
408
+ return None
409
+
410
+
411
+ def collect_all_symbols_in_scope(
412
+ sym_tab: SymbolTable, up_tree: bool = True
413
+ ) -> list[lspt.CompletionItem]:
414
+ """Return all symbols in scope."""
415
+ symbols = []
416
+ visited = set()
417
+ current_tab: Optional[SymbolTable] = sym_tab
418
+
419
+ while current_tab is not None and current_tab not in visited:
420
+ visited.add(current_tab)
421
+ for name, symbol in current_tab.tab.items():
422
+ if name not in dir(builtins):
423
+ symbols.append(
424
+ lspt.CompletionItem(label=name, kind=label_map(symbol.sym_type))
425
+ )
426
+ if not up_tree:
427
+ return symbols
428
+ current_tab = current_tab.parent if current_tab.parent != current_tab else None
429
+ return symbols
430
+
431
+
432
+ def parse_symbol_path(text: str, dot_position: int) -> list[str]:
433
+ """Parse text and return a list of symbols."""
434
+ text = text[:dot_position].strip()
435
+ pattern = re.compile(r"\b\w+\(\)?|\b\w+\b")
436
+ matches = pattern.findall(text)
437
+ if text.endswith("."):
438
+ matches.append("")
439
+ symbol_path = []
440
+ i = 0
441
+ while i < len(matches):
442
+ if matches[i].endswith("("):
443
+ i += 1
444
+ continue
445
+ elif "(" in matches[i]:
446
+ symbol_path.append(matches[i])
447
+ elif matches[i] == "":
448
+ pass
449
+ else:
450
+ symbol_path.append(matches[i])
451
+ i += 1
452
+
453
+ return symbol_path
454
+
455
+
456
+ def resolve_symbol_path(sym_name: str, node_tab: SymbolTable) -> str:
457
+ """Resolve symbol path."""
458
+ visited = set()
459
+ current_tab: Optional[SymbolTable] = node_tab
460
+
461
+ while current_tab is not None and current_tab not in visited:
462
+ visited.add(current_tab)
463
+ for name, symbol in current_tab.tab.items():
464
+ if name not in dir(builtins) and name == sym_name:
465
+ path = symbol.defn[0]._sym_type
466
+ return path
467
+ current_tab = current_tab.parent if current_tab.parent != current_tab else None
468
+ return ""
469
+
470
+
471
+ def find_symbol_table(path: str, current_tab: Optional[SymbolTable]) -> SymbolTable:
472
+ """Find symbol table."""
473
+ path = path.lstrip(".")
474
+ current_table = current_tab
475
+ if current_table:
476
+ for segment in path.split("."):
477
+ current_table = next(
478
+ (
479
+ child_table
480
+ for child_table in current_table.kid
481
+ if child_table.name == segment
482
+ ),
483
+ current_table,
484
+ )
485
+ if current_table:
486
+ return current_table
487
+ raise ValueError(f"Symbol table not found for path {path}")
488
+
489
+
490
+ def resolve_completion_symbol_table(
491
+ mod_tab: SymbolTable,
492
+ current_symbol_path: list[str],
493
+ current_tab: Optional[SymbolTable],
494
+ ) -> list[lspt.CompletionItem]:
495
+ """Resolve symbol table for completion items."""
496
+ current_symbol_table = mod_tab
497
+ for obj in current_symbol_path:
498
+ if obj == "self":
499
+ try:
500
+ try:
501
+ is_abilitydef = (
502
+ mod_tab.owner
503
+ if isinstance(mod_tab.owner, ast.AbilityDef)
504
+ else mod_tab.owner.parent_of_type(ast.AbilityDef)
505
+ )
506
+ archi_owner = (
507
+ (is_abilitydef.decl_link.parent_of_type(ast.Architype))
508
+ if is_abilitydef.decl_link
509
+ else None
510
+ )
511
+ current_symbol_table = (
512
+ archi_owner._sym_tab
513
+ if archi_owner and archi_owner._sym_tab
514
+ else mod_tab
515
+ )
516
+ continue
517
+
518
+ except ValueError:
519
+ pass
520
+ archi_owner = mod_tab.owner.parent_of_type(ast.Architype)
521
+ current_symbol_table = (
522
+ archi_owner._sym_tab
523
+ if archi_owner and archi_owner._sym_tab
524
+ else mod_tab
525
+ )
526
+ except ValueError:
527
+ pass
528
+ else:
529
+ path: str = resolve_symbol_path(obj, current_symbol_table)
530
+ if path:
531
+ current_symbol_table = find_symbol_table(path, current_tab)
532
+ else:
533
+ if (
534
+ isinstance(current_symbol_table.owner, ast.Architype)
535
+ and current_symbol_table.owner.base_classes
536
+ ):
537
+ for base_name in current_symbol_table.owner.base_classes.items:
538
+ if isinstance(base_name, ast.Name) and base_name.sym:
539
+ path = base_name.sym.sym_dotted_name + "." + obj
540
+ current_symbol_table = find_symbol_table(path, current_tab)
541
+ if (
542
+ isinstance(current_symbol_table.owner, ast.Architype)
543
+ and current_symbol_table.owner.base_classes
544
+ ):
545
+ base = []
546
+ for base_name in current_symbol_table.owner.base_classes.items:
547
+ if isinstance(base_name, ast.Name) and base_name.sym:
548
+ base.append(base_name.sym.sym_dotted_name)
549
+ for base_ in base:
550
+ completion_items = collect_all_symbols_in_scope(
551
+ find_symbol_table(base_, current_tab),
552
+ up_tree=False,
553
+ )
554
+ else:
555
+ completion_items = []
556
+
557
+ completion_items.extend(
558
+ collect_all_symbols_in_scope(current_symbol_table, up_tree=False)
559
+ )
560
+ return completion_items
jaclang/plugin/default.py CHANGED
@@ -213,8 +213,8 @@ class JacFeatureDefaults:
213
213
  override_name: Optional[str],
214
214
  mod_bundle: Optional[Module | str],
215
215
  lng: Optional[str],
216
- items: Optional[dict[str, Union[str, bool]]],
217
- ) -> Optional[types.ModuleType]:
216
+ items: Optional[dict[str, Union[str, Optional[str]]]],
217
+ ) -> tuple[types.ModuleType, ...]:
218
218
  """Core Import Process."""
219
219
  result = jac_importer(
220
220
  target=target,
@@ -251,9 +251,10 @@ class JacFeatureDefaults:
251
251
  maxfail: Optional[int],
252
252
  directory: Optional[str],
253
253
  verbose: bool,
254
- ) -> bool:
254
+ ) -> int:
255
255
  """Run the test suite in the specified .jac file."""
256
256
  test_file = False
257
+ ret_count = 0
257
258
  if filepath:
258
259
  if filepath.endswith(".jac"):
259
260
  base, mod_name = os.path.split(filepath)
@@ -262,6 +263,7 @@ class JacFeatureDefaults:
262
263
  JacTestCheck.reset()
263
264
  Jac.jac_import(target=mod_name, base_path=base)
264
265
  JacTestCheck.run_test(xit, maxfail, verbose)
266
+ ret_count = JacTestCheck.failcount
265
267
  else:
266
268
  print("Not a .jac file.")
267
269
  else:
@@ -293,10 +295,11 @@ class JacFeatureDefaults:
293
295
  if JacTestCheck.breaker and (xit or maxfail):
294
296
  break
295
297
  JacTestCheck.breaker = False
298
+ ret_count += JacTestCheck.failcount
296
299
  JacTestCheck.failcount = 0
297
300
  print("No test files found.") if not test_file else None
298
301
 
299
- return True
302
+ return ret_count
300
303
 
301
304
  @staticmethod
302
305
  @hookimpl
jaclang/plugin/feature.py CHANGED
@@ -104,8 +104,8 @@ class JacFeature:
104
104
  override_name: Optional[str] = None,
105
105
  mod_bundle: Optional[Module | str] = None,
106
106
  lng: Optional[str] = "jac",
107
- items: Optional[dict[str, Union[str, bool]]] = None,
108
- ) -> Optional[types.ModuleType]:
107
+ items: Optional[dict[str, Union[str, Optional[str]]]] = None,
108
+ ) -> tuple[types.ModuleType, ...]:
109
109
  """Core Import Process."""
110
110
  return pm.hook.jac_import(
111
111
  target=target,
@@ -132,7 +132,7 @@ class JacFeature:
132
132
  maxfail: Optional[int] = None,
133
133
  directory: Optional[str] = None,
134
134
  verbose: bool = False,
135
- ) -> bool:
135
+ ) -> int:
136
136
  """Run the test suite in the specified .jac file."""
137
137
  return pm.hook.run_test(
138
138
  filepath=filepath,
jaclang/plugin/spec.py CHANGED
@@ -101,8 +101,8 @@ class JacFeatureSpec:
101
101
  override_name: Optional[str],
102
102
  mod_bundle: Optional[Module | str],
103
103
  lng: Optional[str],
104
- items: Optional[dict[str, Union[str, bool]]],
105
- ) -> Optional[types.ModuleType]:
104
+ items: Optional[dict[str, Union[str, Optional[str]]]],
105
+ ) -> tuple[types.ModuleType, ...]:
106
106
  """Core Import Process."""
107
107
  raise NotImplementedError
108
108
 
@@ -121,7 +121,7 @@ class JacFeatureSpec:
121
121
  maxfail: Optional[int],
122
122
  directory: Optional[str],
123
123
  verbose: bool,
124
- ) -> bool:
124
+ ) -> int:
125
125
  """Run the test suite in the specified .jac file."""
126
126
  raise NotImplementedError
127
127
 
jaclang/settings.py CHANGED
@@ -13,6 +13,7 @@ class Settings:
13
13
  fuse_type_info_debug: bool = False
14
14
  filter_sym_builtins: bool = True
15
15
  ast_symbol_info_detailed: bool = False
16
+ pass_timer: bool = False
16
17
 
17
18
  # Import configuration
18
19
  py_raise: bool = False
@@ -1,6 +1,8 @@
1
- import:jac deeper.snd_lev as snd_lev;
1
+ import:jac from .deeper, snd_lev as snd_lev;
2
+ import:jac from ..deep, deeper;
3
+ import:jac from ., deeper as mydeeper;
2
4
 
3
- can olprint ->str {
5
+ can olprint -> str {
6
+ # deeper.snd_lev.slprint(); FIXME:
4
7
  return "one level deeper" + snd_lev.slprint();
5
- }
6
-
8
+ }
@@ -1,11 +1,11 @@
1
1
  """Test of jac importing python."""
2
+
2
3
  import:py os;
3
4
  import:py pyfunc;
4
5
  import:py random;
5
6
  import:py from pyfunc, my_print;
6
7
 
7
8
  with entry {
8
-
9
9
  my_print(pyfunc);
10
10
  print(random.random());
11
11
  }