jaclang 0.7.13__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 (96) 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 +95 -17
  5. jaclang/compiler/jac.lark +4 -3
  6. jaclang/compiler/parser.py +35 -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 +19 -23
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +308 -567
  12. jaclang/compiler/passes/main/pyast_load_pass.py +33 -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/tests/test_import_pass.py +5 -1
  17. jaclang/compiler/passes/main/type_check_pass.py +7 -0
  18. jaclang/compiler/passes/tool/fuse_comments_pass.py +14 -2
  19. jaclang/compiler/passes/tool/jac_formatter_pass.py +144 -94
  20. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +0 -1
  21. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
  22. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
  23. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
  24. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
  25. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
  26. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
  27. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
  28. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
  29. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
  30. jaclang/compiler/passes/transform.py +4 -0
  31. jaclang/compiler/semtable.py +31 -7
  32. jaclang/compiler/tests/test_importer.py +12 -5
  33. jaclang/langserve/engine.py +82 -143
  34. jaclang/langserve/sem_manager.py +379 -0
  35. jaclang/langserve/server.py +8 -10
  36. jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
  37. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  38. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  39. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  40. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  41. jaclang/langserve/tests/test_sem_tokens.py +277 -0
  42. jaclang/langserve/tests/test_server.py +96 -16
  43. jaclang/langserve/utils.py +163 -96
  44. jaclang/plugin/builtin.py +1 -1
  45. jaclang/plugin/default.py +214 -24
  46. jaclang/plugin/feature.py +59 -11
  47. jaclang/plugin/spec.py +58 -6
  48. jaclang/{core → runtimelib}/architype.py +1 -1
  49. jaclang/{core → runtimelib}/context.py +8 -1
  50. jaclang/runtimelib/importer.py +361 -0
  51. jaclang/runtimelib/machine.py +94 -0
  52. jaclang/{core → runtimelib}/utils.py +13 -5
  53. jaclang/settings.py +4 -1
  54. jaclang/tests/fixtures/abc.jac +3 -3
  55. jaclang/tests/fixtures/blankwithentry.jac +3 -0
  56. jaclang/tests/fixtures/byllmissue.jac +1 -5
  57. jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
  58. jaclang/tests/fixtures/cls_method.jac +41 -0
  59. jaclang/tests/fixtures/dblhello.jac +6 -0
  60. jaclang/tests/fixtures/deep/one_lev.jac +3 -3
  61. jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
  62. jaclang/tests/fixtures/deep_import_mods.jac +13 -0
  63. jaclang/tests/fixtures/err.impl.jac +3 -0
  64. jaclang/tests/fixtures/err.jac +4 -2
  65. jaclang/tests/fixtures/err.test.jac +3 -0
  66. jaclang/tests/fixtures/err_runtime.jac +15 -0
  67. jaclang/tests/fixtures/game1.jac +1 -1
  68. jaclang/tests/fixtures/hello.jac +4 -0
  69. jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
  70. jaclang/tests/fixtures/impl_grab.jac +4 -1
  71. jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
  72. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  73. jaclang/tests/fixtures/needs_import.jac +2 -2
  74. jaclang/tests/fixtures/pyfunc_2.py +3 -0
  75. jaclang/tests/fixtures/registry.jac +9 -0
  76. jaclang/tests/fixtures/run_test.jac +4 -4
  77. jaclang/tests/fixtures/semstr.jac +1 -4
  78. jaclang/tests/fixtures/simple_archs.jac +1 -1
  79. jaclang/tests/test_cli.py +65 -2
  80. jaclang/tests/test_language.py +83 -7
  81. jaclang/tests/test_man_code.py +17 -0
  82. jaclang/tests/test_reference.py +6 -0
  83. jaclang/utils/helpers.py +45 -21
  84. jaclang/utils/test.py +9 -0
  85. jaclang/utils/treeprinter.py +0 -4
  86. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/METADATA +3 -2
  87. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/RECORD +93 -77
  88. jaclang/core/importer.py +0 -344
  89. jaclang/tests/fixtures/aott_raise.jac +0 -25
  90. jaclang/tests/fixtures/package_import.jac +0 -6
  91. /jaclang/{core → runtimelib}/__init__.py +0 -0
  92. /jaclang/{core → runtimelib}/constructs.py +0 -0
  93. /jaclang/{core → runtimelib}/memory.py +0 -0
  94. /jaclang/{core → runtimelib}/test.py +0 -0
  95. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/WHEEL +0 -0
  96. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/entry_points.txt +0 -0
@@ -4,26 +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.compiler.passes.transform import Alert
17
+ from jaclang.langserve.sem_manager import SemTokManager
18
18
  from jaclang.langserve.utils import (
19
19
  collect_all_symbols_in_scope,
20
- collect_symbols,
21
20
  create_range,
22
21
  find_deepest_symbol_node_at_pos,
22
+ find_index,
23
23
  gen_diagnostics,
24
24
  get_item_path,
25
25
  get_mod_path,
26
- locate_affected_token,
26
+ get_symbols_for_outline,
27
27
  parse_symbol_path,
28
28
  resolve_completion_symbol_table,
29
29
  )
@@ -39,111 +39,18 @@ class ModuleInfo:
39
39
  def __init__(
40
40
  self,
41
41
  ir: ast.Module,
42
- errors: list[Alert],
43
- warnings: list[Alert],
44
- parent: Optional[ModuleInfo] = None,
42
+ impl_parent: Optional[ModuleInfo] = None,
45
43
  ) -> None:
46
44
  """Initialize module info."""
47
45
  self.ir = ir
48
- self.parent: Optional[ModuleInfo] = parent
49
- self.sem_tokens: list[int] = self.gen_sem_tokens()
46
+ self.impl_parent: Optional[ModuleInfo] = impl_parent
47
+ self.sem_manager = SemTokManager(ir=ir)
50
48
 
51
49
  @property
52
50
  def uri(self) -> str:
53
51
  """Return uri."""
54
52
  return uris.from_fs_path(self.ir.loc.mod_path)
55
53
 
56
- def gen_sem_tokens(self) -> list[int]:
57
- """Return semantic tokens."""
58
- tokens = []
59
- prev_line, prev_col = 0, 0
60
- for node in self.ir._in_mod_nodes:
61
- if isinstance(node, ast.NameAtom) and node.sem_token:
62
- line, col_start, col_end = (
63
- node.loc.first_line - 1,
64
- node.loc.col_start - 1,
65
- node.loc.col_end - 1,
66
- )
67
- length = col_end - col_start
68
- tokens += [
69
- line - prev_line,
70
- col_start if line != prev_line else col_start - prev_col,
71
- length,
72
- *node.sem_token,
73
- ]
74
- prev_line, prev_col = line, col_start
75
- return tokens
76
-
77
- def update_sem_tokens(
78
- self, content_changes: lspt.DidChangeTextDocumentParams
79
- ) -> list[int]:
80
- """Update semantic tokens on change."""
81
- for change in [
82
- x
83
- for x in content_changes.content_changes
84
- if isinstance(x, lspt.TextDocumentContentChangeEvent_Type1)
85
- ]:
86
- change_start_line = change.range.start.line
87
- change_start_char = change.range.start.character
88
- change_end_line = change.range.end.line
89
- change_end_char = change.range.end.character
90
-
91
- line_delta = change.text.count("\n") - (change_end_line - change_start_line)
92
- if line_delta == 0:
93
- char_delta = len(change.text) - (change_end_char - change_start_char)
94
- else:
95
- last_newline_index = change.text.rfind("\n")
96
- char_delta = (
97
- len(change.text)
98
- - last_newline_index
99
- - 1
100
- - change_end_char
101
- + change_start_char
102
- )
103
-
104
- changed_token_index = locate_affected_token(
105
- self.sem_tokens,
106
- change_start_line,
107
- change_start_char,
108
- change_end_line,
109
- change_end_char,
110
- )
111
- if changed_token_index:
112
- self.sem_tokens[changed_token_index + 2] = max(
113
- 1, self.sem_tokens[changed_token_index + 2] + char_delta
114
- )
115
- if (
116
- len(self.sem_tokens) > changed_token_index + 5
117
- and self.sem_tokens[changed_token_index + 5] == 0
118
- ):
119
- next_token_index = changed_token_index + 5
120
- self.sem_tokens[next_token_index + 1] = max(
121
- 0, self.sem_tokens[next_token_index + 1] + char_delta
122
- )
123
- return self.sem_tokens
124
-
125
- current_token_index = 0
126
- line_offset = 0
127
- while current_token_index < len(self.sem_tokens):
128
- token_line_number = self.sem_tokens[current_token_index] + line_offset
129
- token_start_pos = self.sem_tokens[current_token_index + 1]
130
-
131
- if token_line_number > change_start_line or (
132
- token_line_number == change_start_line
133
- and token_start_pos >= change_start_char
134
- ):
135
- self.sem_tokens[current_token_index] += line_delta
136
- if token_line_number == change_start_line:
137
- self.sem_tokens[current_token_index + 1] += char_delta
138
- if token_line_number > change_end_line or (
139
- token_line_number == change_end_line
140
- and token_start_pos >= change_end_char
141
- ):
142
- break
143
- line_offset += self.sem_tokens[current_token_index]
144
- current_token_index += 5
145
- return self.sem_tokens
146
-
147
54
 
148
55
  class JacLangServer(LanguageServer):
149
56
  """Class for managing workspace."""
@@ -162,29 +69,17 @@ class JacLangServer(LanguageServer):
162
69
  if not isinstance(build.ir, ast.Module):
163
70
  self.log_error("Error with module build.")
164
71
  return
165
- self.modules[file_path] = ModuleInfo(
166
- ir=build.ir,
167
- errors=[
168
- i
169
- for i in build.errors_had
170
- if i.loc.mod_path == uris.to_fs_path(file_path)
171
- ],
172
- warnings=[
173
- i
174
- for i in build.warnings_had
175
- if i.loc.mod_path == uris.to_fs_path(file_path)
176
- ],
72
+ keep_parent = (
73
+ self.modules[file_path].impl_parent if file_path in self.modules else None
177
74
  )
75
+ self.modules[file_path] = ModuleInfo(ir=build.ir, impl_parent=keep_parent)
178
76
  for p in build.ir.mod_deps.keys():
179
77
  uri = uris.from_fs_path(p)
180
- self.modules[uri] = ModuleInfo(
181
- ir=build.ir.mod_deps[p],
182
- errors=[i for i in build.errors_had if i.loc.mod_path == p],
183
- warnings=[i for i in build.warnings_had if i.loc.mod_path == p],
184
- )
185
- self.modules[uri].parent = (
186
- self.modules[file_path] if file_path != uri else None
187
- )
78
+ if file_path != uri:
79
+ self.modules[uri] = ModuleInfo(
80
+ ir=build.ir.mod_deps[p],
81
+ impl_parent=self.modules[file_path],
82
+ )
188
83
 
189
84
  def quick_check(self, file_path: str) -> bool:
190
85
  """Rebuild a file."""
@@ -205,7 +100,14 @@ class JacLangServer(LanguageServer):
205
100
  def deep_check(self, file_path: str, annex_view: Optional[str] = None) -> bool:
206
101
  """Rebuild a file and its dependencies."""
207
102
  try:
103
+ start_time = time.time()
208
104
  document = self.workspace.get_text_document(file_path)
105
+ if file_path in self.modules and (
106
+ parent := self.modules[file_path].impl_parent
107
+ ):
108
+ return self.deep_check(
109
+ uris.from_fs_path(parent.ir.loc.mod_path), annex_view=file_path
110
+ )
209
111
  build = jac_str_to_pass(
210
112
  jac_str=document.source,
211
113
  file_path=document.path,
@@ -216,14 +118,16 @@ class JacLangServer(LanguageServer):
216
118
  return self.deep_check(
217
119
  uris.from_fs_path(discover), annex_view=file_path
218
120
  )
121
+
219
122
  self.publish_diagnostics(
220
- file_path,
123
+ annex_view if annex_view else file_path,
221
124
  gen_diagnostics(
222
125
  annex_view if annex_view else file_path,
223
126
  build.errors_had,
224
127
  build.warnings_had,
225
128
  ),
226
129
  )
130
+ self.log_py(f"PROFILE: Deep check took {time.time() - start_time} seconds.")
227
131
  return len(build.errors_had) == 0
228
132
  except Exception as e:
229
133
  self.log_error(f"Error during deep check: {e}")
@@ -264,12 +168,12 @@ class JacLangServer(LanguageServer):
264
168
  current_line = document.lines[position.line]
265
169
  current_pos = position.character
266
170
  current_symbol_path = parse_symbol_path(current_line, current_pos)
171
+
267
172
  node_selected = find_deepest_symbol_node_at_pos(
268
173
  self.modules[file_path].ir,
269
174
  position.line,
270
175
  position.character - 2,
271
176
  )
272
-
273
177
  mod_tab = (
274
178
  self.modules[file_path].ir.sym_tab
275
179
  if not node_selected
@@ -277,15 +181,30 @@ class JacLangServer(LanguageServer):
277
181
  )
278
182
  current_tab = self.modules[file_path].ir._sym_tab
279
183
  current_symbol_table = mod_tab
184
+
280
185
  if completion_trigger == ".":
281
- completion_items = resolve_completion_symbol_table(
282
- mod_tab, current_symbol_path, current_tab
283
- )
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 = []
284
192
  else:
285
- try: # noqa SIM105
286
- completion_items = collect_all_symbols_in_scope(current_symbol_table)
287
- except AttributeError:
288
- 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
+ )
289
208
  return lspt.CompletionList(is_incomplete=False, items=completion_items)
290
209
 
291
210
  def rename_module(self, old_path: str, new_path: str) -> None:
@@ -335,9 +254,16 @@ class JacLangServer(LanguageServer):
335
254
  """Return hover information for a file."""
336
255
  if file_path not in self.modules:
337
256
  return None
338
- node_selected = find_deepest_symbol_node_at_pos(
339
- 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,
340
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]
341
267
  value = self.get_node_info(node_selected) if node_selected else None
342
268
  if value:
343
269
  return lspt.Hover(
@@ -369,12 +295,12 @@ class JacLangServer(LanguageServer):
369
295
  self.log_warning(f"Attribute error when accessing node attributes: {e}")
370
296
  return node_info.strip()
371
297
 
372
- def get_document_symbols(self, file_path: str) -> list[lspt.DocumentSymbol]:
298
+ def get_outline(self, file_path: str) -> list[lspt.DocumentSymbol]:
373
299
  """Return document symbols for a file."""
374
300
  if file_path in self.modules and (
375
301
  root_node := self.modules[file_path].ir._sym_tab
376
302
  ):
377
- return collect_symbols(root_node)
303
+ return get_symbols_for_outline(root_node)
378
304
  return []
379
305
 
380
306
  def get_definition(
@@ -383,9 +309,16 @@ class JacLangServer(LanguageServer):
383
309
  """Return definition location for a file."""
384
310
  if file_path not in self.modules:
385
311
  return None
386
- node_selected: Optional[ast.AstSymbolNode] = find_deepest_symbol_node_at_pos(
387
- 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,
388
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]
389
322
  if node_selected:
390
323
  if (
391
324
  isinstance(node_selected, ast.Name)
@@ -408,13 +341,13 @@ class JacLangServer(LanguageServer):
408
341
  ):
409
342
  path_range = get_item_path(node_selected.parent)
410
343
  if path_range:
411
- path, range = path_range
412
- if path and range:
344
+ path, loc_range = path_range
345
+ if path and loc_range:
413
346
  return lspt.Location(
414
347
  uri=uris.from_fs_path(path),
415
348
  range=lspt.Range(
416
- start=lspt.Position(line=range[0], character=0),
417
- 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),
418
351
  ),
419
352
  )
420
353
  else:
@@ -432,7 +365,6 @@ class JacLangServer(LanguageServer):
432
365
  else node_selected
433
366
  )
434
367
  )
435
- self.log_py(f"{node_selected}, {decl_node}")
436
368
  decl_uri = uris.from_fs_path(decl_node.loc.mod_path)
437
369
  try:
438
370
  decl_range = create_range(decl_node.loc)
@@ -451,9 +383,16 @@ class JacLangServer(LanguageServer):
451
383
  self, file_path: str, position: lspt.Position
452
384
  ) -> list[lspt.Location]:
453
385
  """Return references for a file."""
454
- node_selected = find_deepest_symbol_node_at_pos(
455
- 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,
456
392
  )
393
+ if index1 is None:
394
+ return []
395
+ node_selected = self.modules[file_path].sem_manager.static_sem_tokens[index1][3]
457
396
  if node_selected and node_selected.sym:
458
397
  list_of_references: list[lspt.Location] = [
459
398
  lspt.Location(
@@ -469,7 +408,7 @@ class JacLangServer(LanguageServer):
469
408
  """Return semantic tokens for a file."""
470
409
  if file_path not in self.modules:
471
410
  return lspt.SemanticTokens(data=[])
472
- return lspt.SemanticTokens(data=self.modules[file_path].sem_tokens)
411
+ return lspt.SemanticTokens(data=self.modules[file_path].sem_manager.sem_tokens)
473
412
 
474
413
  def log_error(self, message: str) -> None:
475
414
  """Log an error message."""