jaclang 0.7.23__py3-none-any.whl → 0.7.25__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 (50) hide show
  1. jaclang/cli/cli.py +46 -29
  2. jaclang/compiler/__init__.py +2 -2
  3. jaclang/compiler/absyntree.py +87 -48
  4. jaclang/compiler/codeloc.py +7 -2
  5. jaclang/compiler/compile.py +10 -3
  6. jaclang/compiler/parser.py +26 -23
  7. jaclang/compiler/passes/ir_pass.py +2 -2
  8. jaclang/compiler/passes/main/def_impl_match_pass.py +46 -0
  9. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +146 -123
  10. jaclang/compiler/passes/main/import_pass.py +6 -2
  11. jaclang/compiler/passes/main/pyast_load_pass.py +36 -35
  12. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -7
  13. jaclang/compiler/passes/main/registry_pass.py +3 -12
  14. jaclang/compiler/passes/main/tests/fixtures/defn_decl_mismatch.jac +19 -0
  15. jaclang/compiler/passes/main/tests/fixtures/fstrings.jac +2 -0
  16. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +59 -0
  17. jaclang/compiler/passes/main/tests/test_registry_pass.py +2 -10
  18. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  19. jaclang/compiler/passes/transform.py +27 -3
  20. jaclang/compiler/passes/utils/mypy_ast_build.py +246 -26
  21. jaclang/compiler/symtable.py +6 -0
  22. jaclang/compiler/tests/test_importer.py +2 -2
  23. jaclang/langserve/engine.py +14 -12
  24. jaclang/langserve/server.py +7 -2
  25. jaclang/langserve/tests/test_server.py +1 -1
  26. jaclang/langserve/utils.py +17 -3
  27. jaclang/plugin/default.py +32 -32
  28. jaclang/plugin/feature.py +2 -2
  29. jaclang/plugin/plugin.md +471 -0
  30. jaclang/plugin/spec.py +2 -1
  31. jaclang/runtimelib/context.py +2 -0
  32. jaclang/runtimelib/importer.py +7 -2
  33. jaclang/runtimelib/machine.py +21 -6
  34. jaclang/settings.py +3 -0
  35. jaclang/tests/fixtures/builtin_dotgen.jac +6 -6
  36. jaclang/tests/fixtures/enum_inside_archtype.jac +16 -11
  37. jaclang/tests/fixtures/expr_type.jac +54 -0
  38. jaclang/tests/fixtures/glob_multivar_statement.jac +15 -0
  39. jaclang/tests/fixtures/registry.jac +20 -8
  40. jaclang/tests/foo/__init__.jac +0 -0
  41. jaclang/tests/main.jac +2 -0
  42. jaclang/tests/test_cli.py +68 -4
  43. jaclang/tests/test_language.py +60 -27
  44. jaclang/utils/helpers.py +92 -14
  45. jaclang/utils/lang_tools.py +6 -2
  46. jaclang/utils/treeprinter.py +4 -2
  47. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/METADATA +2 -1
  48. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/RECORD +50 -44
  49. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/WHEEL +1 -1
  50. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/entry_points.txt +0 -0
@@ -16,6 +16,7 @@ import mypy.build as myb
16
16
  import mypy.checkexpr as mycke
17
17
  import mypy.errors as mye
18
18
  import mypy.fastparse as myfp
19
+ import mypy.nodes as mypy_nodes
19
20
  from mypy.build import BuildSource
20
21
  from mypy.build import BuildSourceSet
21
22
  from mypy.build import FileSystemCache
@@ -36,6 +37,55 @@ if TYPE_CHECKING:
36
37
  from mypy.report import Reports # Avoid unconditional slow import
37
38
 
38
39
 
40
+ # All the expression nodes of mypy.
41
+ EXPRESSION_NODES = (
42
+ mypy_nodes.AssertTypeExpr,
43
+ mypy_nodes.AssignmentExpr,
44
+ mypy_nodes.AwaitExpr,
45
+ mypy_nodes.BytesExpr,
46
+ mypy_nodes.CallExpr,
47
+ mypy_nodes.CastExpr,
48
+ mypy_nodes.ComparisonExpr,
49
+ mypy_nodes.ComplexExpr,
50
+ mypy_nodes.ConditionalExpr,
51
+ mypy_nodes.DictionaryComprehension,
52
+ mypy_nodes.DictExpr,
53
+ mypy_nodes.EllipsisExpr,
54
+ mypy_nodes.EnumCallExpr,
55
+ mypy_nodes.Expression,
56
+ mypy_nodes.FloatExpr,
57
+ mypy_nodes.GeneratorExpr,
58
+ mypy_nodes.IndexExpr,
59
+ mypy_nodes.IntExpr,
60
+ mypy_nodes.LambdaExpr,
61
+ mypy_nodes.ListComprehension,
62
+ mypy_nodes.ListExpr,
63
+ mypy_nodes.MemberExpr,
64
+ mypy_nodes.NamedTupleExpr,
65
+ mypy_nodes.NameExpr,
66
+ mypy_nodes.NewTypeExpr,
67
+ mypy_nodes.OpExpr,
68
+ mypy_nodes.ParamSpecExpr,
69
+ mypy_nodes.PromoteExpr,
70
+ mypy_nodes.RefExpr,
71
+ mypy_nodes.RevealExpr,
72
+ mypy_nodes.SetComprehension,
73
+ mypy_nodes.SetExpr,
74
+ mypy_nodes.SliceExpr,
75
+ mypy_nodes.StarExpr,
76
+ mypy_nodes.StrExpr,
77
+ mypy_nodes.SuperExpr,
78
+ mypy_nodes.TupleExpr,
79
+ mypy_nodes.TypeAliasExpr,
80
+ mypy_nodes.TypedDictExpr,
81
+ mypy_nodes.TypeVarExpr,
82
+ mypy_nodes.TypeVarTupleExpr,
83
+ mypy_nodes.UnaryExpr,
84
+ mypy_nodes.YieldExpr,
85
+ mypy_nodes.YieldFromExpr,
86
+ )
87
+
88
+
39
89
  mypy_to_jac_node_map: dict[
40
90
  tuple[int, int | None, int | None, int | None], list[AstNode]
41
91
  ] = {}
@@ -131,61 +181,231 @@ class ExpressionChecker(mycke.ExpressionChecker):
131
181
  """Override to mypy expression checker for direct AST pass through."""
132
182
  super().__init__(tc, msg, plugin, per_line_checking_time_ns)
133
183
 
184
+ def visit_assert_type_expr(self, e: mycke.AssertTypeExpr) -> mycke.Type:
185
+ """Type check AssertTypeExpr expression."""
186
+ out = super().visit_assert_type_expr(e)
187
+ FuseTypeInfoPass.node_type_hash[e] = out
188
+ return out
189
+
190
+ def visit_assignment_expr(self, e: mycke.AssignmentExpr) -> mycke.Type:
191
+ """Type check AssignmentExpr expression."""
192
+ out = super().visit_assignment_expr(e)
193
+ FuseTypeInfoPass.node_type_hash[e] = out
194
+ return out
195
+
196
+ def visit_await_expr(
197
+ self, e: mycke.AwaitExpr, allow_none_return: bool = False
198
+ ) -> mycke.Type:
199
+ """Type check AwaitExpr expression."""
200
+ out = super().visit_await_expr(e, allow_none_return)
201
+ FuseTypeInfoPass.node_type_hash[e] = out
202
+ return out
203
+
204
+ def visit_bytes_expr(self, e: mycke.BytesExpr) -> mycke.Type:
205
+ """Type check BytesExpr expression."""
206
+ out = super().visit_bytes_expr(e)
207
+ FuseTypeInfoPass.node_type_hash[e] = out
208
+ return out
209
+
210
+ def visit_call_expr(
211
+ self, e: mycke.CallExpr, allow_none_return: bool = False
212
+ ) -> mycke.Type:
213
+ """Type check CallExpr expression."""
214
+ out = super().visit_call_expr(e, allow_none_return)
215
+ FuseTypeInfoPass.node_type_hash[e] = out
216
+ return out
217
+
218
+ def visit_cast_expr(self, e: mycke.CastExpr) -> mycke.Type:
219
+ """Type check CastExpr expression."""
220
+ out = super().visit_cast_expr(e)
221
+ FuseTypeInfoPass.node_type_hash[e] = out
222
+ return out
223
+
224
+ def visit_comparison_expr(self, e: mycke.ComparisonExpr) -> mycke.Type:
225
+ """Type check ComparisonExpr expression."""
226
+ out = super().visit_comparison_expr(e)
227
+ FuseTypeInfoPass.node_type_hash[e] = out
228
+ return out
229
+
230
+ def visit_complex_expr(self, e: mycke.ComplexExpr) -> mycke.Type:
231
+ """Type check ComplexExpr expression."""
232
+ out = super().visit_complex_expr(e)
233
+ FuseTypeInfoPass.node_type_hash[e] = out
234
+ return out
235
+
236
+ def visit_conditional_expr(
237
+ self, e: mycke.ConditionalExpr, allow_none_return: bool = False
238
+ ) -> mycke.Type:
239
+ """Type check ConditionalExpr expression."""
240
+ out = super().visit_conditional_expr(e, allow_none_return)
241
+ FuseTypeInfoPass.node_type_hash[e] = out
242
+ return out
243
+
244
+ def visit_dictionary_comprehension(
245
+ self, e: mycke.DictionaryComprehension
246
+ ) -> mycke.Type:
247
+ """Type check DictionaryComprehension expression."""
248
+ out = super().visit_dictionary_comprehension(e)
249
+ FuseTypeInfoPass.node_type_hash[e] = out
250
+ return out
251
+
252
+ def visit_dict_expr(self, e: mycke.DictExpr) -> mycke.Type:
253
+ """Type check DictExpr expression."""
254
+ out = super().visit_dict_expr(e)
255
+ FuseTypeInfoPass.node_type_hash[e] = out
256
+ return out
257
+
258
+ def visit_enum_call_expr(self, e: mycke.EnumCallExpr) -> mycke.Type:
259
+ """Type check EnumCallExpr expression."""
260
+ out = super().visit_enum_call_expr(e)
261
+ FuseTypeInfoPass.node_type_hash[e] = out
262
+ return out
263
+
264
+ def visit_float_expr(self, e: mycke.FloatExpr) -> mycke.Type:
265
+ """Type check FloatExpr expression."""
266
+ out = super().visit_float_expr(e)
267
+ FuseTypeInfoPass.node_type_hash[e] = out
268
+ return out
269
+
270
+ def visit_generator_expr(self, e: mycke.GeneratorExpr) -> mycke.Type:
271
+ """Type check GeneratorExpr expression."""
272
+ out = super().visit_generator_expr(e)
273
+ FuseTypeInfoPass.node_type_hash[e] = out
274
+ return out
275
+
276
+ def visit_index_expr(self, e: mycke.IndexExpr) -> mycke.Type:
277
+ """Type check IndexExpr expression."""
278
+ out = super().visit_index_expr(e)
279
+ FuseTypeInfoPass.node_type_hash[e] = out
280
+ return out
281
+
282
+ def visit_int_expr(self, e: mycke.IntExpr) -> mycke.Type:
283
+ """Type check IntExpr expression."""
284
+ out = super().visit_int_expr(e)
285
+ FuseTypeInfoPass.node_type_hash[e] = out
286
+ return out
287
+
288
+ def visit_lambda_expr(self, e: mycke.LambdaExpr) -> mycke.Type:
289
+ """Type check LambdaExpr expression."""
290
+ out = super().visit_lambda_expr(e)
291
+ FuseTypeInfoPass.node_type_hash[e] = out
292
+ return out
293
+
294
+ def visit_list_comprehension(self, e: mycke.ListComprehension) -> mycke.Type:
295
+ """Type check ListComprehension expression."""
296
+ out = super().visit_list_comprehension(e)
297
+ FuseTypeInfoPass.node_type_hash[e] = out
298
+ return out
299
+
134
300
  def visit_list_expr(self, e: mycke.ListExpr) -> mycke.Type:
135
- """Type check a list expression [...]."""
301
+ """Type check ListExpr expression."""
136
302
  out = super().visit_list_expr(e)
137
303
  FuseTypeInfoPass.node_type_hash[e] = out
138
304
  return out
139
305
 
306
+ def visit_member_expr(
307
+ self, e: mycke.MemberExpr, is_lvalue: bool = False
308
+ ) -> mycke.Type:
309
+ """Type check MemberExpr expression."""
310
+ out = super().visit_member_expr(e, is_lvalue)
311
+ FuseTypeInfoPass.node_type_hash[e] = out
312
+ return out
313
+
314
+ def visit_name_expr(self, e: mycke.NameExpr) -> mycke.Type:
315
+ """Type check NameExpr expression."""
316
+ out = super().visit_name_expr(e)
317
+ FuseTypeInfoPass.node_type_hash[e] = out
318
+ return out
319
+
320
+ def visit_op_expr(self, e: mycke.OpExpr) -> mycke.Type:
321
+ """Type check OpExpr expression."""
322
+ out = super().visit_op_expr(e)
323
+ FuseTypeInfoPass.node_type_hash[e] = out
324
+ return out
325
+
326
+ def visit_reveal_expr(self, e: mycke.RevealExpr) -> mycke.Type:
327
+ """Type check RevealExpr expression."""
328
+ out = super().visit_reveal_expr(e)
329
+ FuseTypeInfoPass.node_type_hash[e] = out
330
+ return out
331
+
332
+ def visit_set_comprehension(self, e: mycke.SetComprehension) -> mycke.Type:
333
+ """Type check SetComprehension expression."""
334
+ out = super().visit_set_comprehension(e)
335
+ FuseTypeInfoPass.node_type_hash[e] = out
336
+ return out
337
+
140
338
  def visit_set_expr(self, e: mycke.SetExpr) -> mycke.Type:
141
- """Type check a set expression {...}."""
339
+ """Type check SetExpr expression."""
142
340
  out = super().visit_set_expr(e)
143
341
  FuseTypeInfoPass.node_type_hash[e] = out
144
342
  return out
145
343
 
146
- def visit_tuple_expr(self, e: myfp.TupleExpr) -> myb.Type:
147
- """Type check a tuple expression (...)."""
344
+ def visit_slice_expr(self, e: mycke.SliceExpr) -> mycke.Type:
345
+ """Type check SliceExpr expression."""
346
+ out = super().visit_slice_expr(e)
347
+ FuseTypeInfoPass.node_type_hash[e] = out
348
+ return out
349
+
350
+ def visit_star_expr(self, e: mycke.StarExpr) -> mycke.Type:
351
+ """Type check StarExpr expression."""
352
+ out = super().visit_star_expr(e)
353
+ FuseTypeInfoPass.node_type_hash[e] = out
354
+ return out
355
+
356
+ def visit_str_expr(self, e: mycke.StrExpr) -> mycke.Type:
357
+ """Type check StrExpr expression."""
358
+ out = super().visit_str_expr(e)
359
+ FuseTypeInfoPass.node_type_hash[e] = out
360
+ return out
361
+
362
+ def visit_super_expr(self, e: mycke.SuperExpr) -> mycke.Type:
363
+ """Type check SuperExpr expression."""
364
+ out = super().visit_super_expr(e)
365
+ FuseTypeInfoPass.node_type_hash[e] = out
366
+ return out
367
+
368
+ def visit_tuple_expr(self, e: mycke.TupleExpr) -> mycke.Type:
369
+ """Type check TupleExpr expression."""
148
370
  out = super().visit_tuple_expr(e)
149
371
  FuseTypeInfoPass.node_type_hash[e] = out
150
372
  return out
151
373
 
152
- def visit_dict_expr(self, e: myfp.DictExpr) -> myb.Type:
153
- """Type check a dictionary expression {...}."""
154
- out = super().visit_dict_expr(e)
374
+ def visit_type_alias_expr(self, e: mycke.TypeAliasExpr) -> mycke.Type:
375
+ """Type check TypeAliasExpr expression."""
376
+ out = super().visit_type_alias_expr(e)
155
377
  FuseTypeInfoPass.node_type_hash[e] = out
156
378
  return out
157
379
 
158
- def visit_list_comprehension(self, e: myfp.ListComprehension) -> myb.Type:
159
- """Type check a list comprehension."""
160
- out = super().visit_list_comprehension(e)
380
+ def visit_type_var_expr(self, e: mycke.TypeVarExpr) -> mycke.Type:
381
+ """Type check TypeVarExpr expression."""
382
+ out = super().visit_type_var_expr(e)
161
383
  FuseTypeInfoPass.node_type_hash[e] = out
162
384
  return out
163
385
 
164
- def visit_set_comprehension(self, e: myfp.SetComprehension) -> myb.Type:
165
- """Type check a set comprehension."""
166
- out = super().visit_set_comprehension(e)
386
+ def visit_type_var_tuple_expr(self, e: mycke.TypeVarTupleExpr) -> mycke.Type:
387
+ """Type check TypeVarTupleExpr expression."""
388
+ out = super().visit_type_var_tuple_expr(e)
167
389
  FuseTypeInfoPass.node_type_hash[e] = out
168
390
  return out
169
391
 
170
- def visit_generator_expr(self, e: myfp.GeneratorExpr) -> myb.Type:
171
- """Type check a generator expression."""
172
- out = super().visit_generator_expr(e)
392
+ def visit_unary_expr(self, e: mycke.UnaryExpr) -> mycke.Type:
393
+ """Type check UnaryExpr expression."""
394
+ out = super().visit_unary_expr(e)
173
395
  FuseTypeInfoPass.node_type_hash[e] = out
174
396
  return out
175
397
 
176
- def visit_dictionary_comprehension(
177
- self, e: myfp.DictionaryComprehension
178
- ) -> myb.Type:
179
- """Type check a dict comprehension."""
180
- out = super().visit_dictionary_comprehension(e)
398
+ def visit_yield_expr(self, e: mycke.YieldExpr) -> mycke.Type:
399
+ """Type check YieldExpr expression."""
400
+ out = super().visit_yield_expr(e)
181
401
  FuseTypeInfoPass.node_type_hash[e] = out
182
402
  return out
183
403
 
184
- def visit_member_expr(
185
- self, e: myfp.MemberExpr, is_lvalue: bool = False
186
- ) -> myb.Type:
187
- """Type check a member expr."""
188
- out = super().visit_member_expr(e, is_lvalue)
404
+ def visit_yield_from_expr(
405
+ self, e: mycke.YieldFromExpr, allow_none_return: bool = False
406
+ ) -> mycke.Type:
407
+ """Type check YieldFromExpr expression."""
408
+ out = super().visit_yield_from_expr(e, allow_none_return)
189
409
  FuseTypeInfoPass.node_type_hash[e] = out
190
410
  return out
191
411
 
@@ -88,6 +88,12 @@ class SymbolTable:
88
88
  self.tab: dict[str, Symbol] = {}
89
89
  self.inherit: list[SymbolTable] = []
90
90
 
91
+ def get_type(self) -> SymbolType:
92
+ """Get type."""
93
+ if isinstance(self.owner, ast.AstSymbolNode):
94
+ return self.owner.sym_category
95
+ return SymbolType.VAR
96
+
91
97
  def get_parent(self) -> Optional[SymbolTable]:
92
98
  """Get parent."""
93
99
  return self.parent
@@ -15,7 +15,7 @@ class TestLoader(TestCase):
15
15
  def test_import_basic_python(self) -> None:
16
16
  """Test basic self loading."""
17
17
  JacMachine(self.fixture_abs_path(__file__)).attach_program(
18
- JacProgram(mod_bundle=None, bytecode=None)
18
+ JacProgram(mod_bundle=None, bytecode=None, sem_ir=None)
19
19
  )
20
20
  (h,) = jac_import("fixtures.hello_world", base_path=__file__)
21
21
  self.assertEqual(h.hello(), "Hello World!") # type: ignore
@@ -24,7 +24,7 @@ class TestLoader(TestCase):
24
24
  def test_modules_correct(self) -> None:
25
25
  """Test basic self loading."""
26
26
  JacMachine(self.fixture_abs_path(__file__)).attach_program(
27
- JacProgram(mod_bundle=None, bytecode=None)
27
+ JacProgram(mod_bundle=None, bytecode=None, sem_ir=None)
28
28
  )
29
29
  jac_import("fixtures.hello_world", base_path=__file__)
30
30
  self.assertIn(
@@ -18,6 +18,7 @@ from jaclang.langserve.sem_manager import SemTokManager
18
18
  from jaclang.langserve.utils import (
19
19
  add_unique_text_edit,
20
20
  collect_all_symbols_in_scope,
21
+ collect_child_tabs,
21
22
  create_range,
22
23
  find_deepest_symbol_node_at_pos,
23
24
  find_index,
@@ -44,6 +45,7 @@ class ModuleInfo:
44
45
  self.ir = ir
45
46
  self.impl_parent: Optional[ModuleInfo] = impl_parent
46
47
  self.sem_manager = SemTokManager(ir=ir)
48
+ self.is_modified: bool = False
47
49
 
48
50
  @property
49
51
  def uri(self) -> str:
@@ -171,22 +173,20 @@ class JacLangServer(LanguageServer):
171
173
  self, file_path: str, position: lspt.Position, completion_trigger: Optional[str]
172
174
  ) -> lspt.CompletionList:
173
175
  """Return completion for a file."""
174
- completion_items = []
175
176
  document = self.workspace.get_text_document(file_path)
177
+ mod_ir = self.modules[file_path].ir
176
178
  current_line = document.lines[position.line]
177
179
  current_pos = position.character
178
180
  current_symbol_path = parse_symbol_path(current_line, current_pos)
181
+ builtin_tab = mod_ir.sym_tab.kid[-1]
182
+ completion_items = []
179
183
 
180
184
  node_selected = find_deepest_symbol_node_at_pos(
181
- self.modules[file_path].ir,
185
+ mod_ir,
182
186
  position.line,
183
187
  position.character - 2,
184
188
  )
185
- mod_tab = (
186
- self.modules[file_path].ir.sym_tab
187
- if not node_selected
188
- else node_selected.sym_tab
189
- )
189
+ mod_tab = mod_ir.sym_tab if not node_selected else node_selected.sym_tab
190
190
  current_symbol_table = mod_tab
191
191
 
192
192
  if completion_trigger == ".":
@@ -238,7 +238,9 @@ class JacLangServer(LanguageServer):
238
238
  )
239
239
  else:
240
240
  break
241
- completion_items = collect_all_symbols_in_scope(temp_tab, up_tree=False)
241
+ completion_items += collect_all_symbols_in_scope(
242
+ temp_tab, up_tree=False
243
+ )
242
244
  if (
243
245
  isinstance(temp_tab.owner, ast.Architype)
244
246
  and temp_tab.owner.base_classes
@@ -254,8 +256,6 @@ class JacLangServer(LanguageServer):
254
256
  up_tree=False,
255
257
  )
256
258
 
257
- else:
258
- completion_items = []
259
259
  else:
260
260
  if node_selected and (
261
261
  node_selected.find_parent_of_type(ast.Architype)
@@ -269,8 +269,10 @@ class JacLangServer(LanguageServer):
269
269
  else:
270
270
  self_symbol = []
271
271
 
272
- completion_items = (
273
- collect_all_symbols_in_scope(current_symbol_table) + self_symbol
272
+ completion_items += (
273
+ collect_all_symbols_in_scope(current_symbol_table)
274
+ + self_symbol
275
+ + collect_child_tabs(builtin_tab)
274
276
  )
275
277
  return lspt.CompletionList(is_incomplete=False, items=completion_items)
276
278
 
@@ -26,8 +26,11 @@ async def did_open(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) ->
26
26
  @server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
27
27
  async def did_save(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
28
28
  """Check syntax on change."""
29
- await ls.launch_deep_check(params.text_document.uri)
30
- ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
29
+ file_path = params.text_document.uri
30
+ if ls.modules[file_path].is_modified:
31
+ await ls.launch_deep_check(file_path)
32
+ ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
33
+ ls.modules[file_path].is_modified = False
31
34
 
32
35
 
33
36
  @server.feature(lspt.TEXT_DOCUMENT_DID_CHANGE)
@@ -35,6 +38,8 @@ async def did_change(
35
38
  ls: JacLangServer, params: lspt.DidChangeTextDocumentParams
36
39
  ) -> None:
37
40
  """Check syntax on change."""
41
+ module = ls.modules[params.text_document.uri]
42
+ module.is_modified = True
38
43
  await ls.launch_quick_check(file_path := params.text_document.uri)
39
44
  if file_path in ls.modules:
40
45
  document = ls.workspace.get_text_document(file_path)
@@ -369,7 +369,7 @@ class TestJacLangServer(TestCase):
369
369
  (
370
370
  lspt.Position(37, 12),
371
371
  ["self", "add", "subtract", "x", "Colorenum", "Colour1", "red", "r"],
372
- 8,
372
+ 160,
373
373
  None,
374
374
  ),
375
375
  ]
@@ -133,9 +133,12 @@ def find_index(
133
133
  ) -> Optional[int]:
134
134
  """Find index."""
135
135
  index = None
136
- for i, j in enumerate(
137
- [get_token_start(i, sem_tokens) for i in range(0, len(sem_tokens), 5)]
138
- ):
136
+
137
+ # A list contains all the token start positions.
138
+ token_start_list = [
139
+ get_token_start(i, sem_tokens) for i in range(0, len(sem_tokens), 5)
140
+ ]
141
+ for i, j in enumerate(token_start_list):
139
142
  if j[0] == line and j[1] <= char <= j[2]:
140
143
  return i
141
144
 
@@ -302,6 +305,17 @@ def collect_all_symbols_in_scope(
302
305
  return symbols
303
306
 
304
307
 
308
+ def collect_child_tabs(sym_tab: SymbolTable) -> list[lspt.CompletionItem]:
309
+ """Return all child tab's as completion items."""
310
+ symbols: list[lspt.CompletionItem] = []
311
+ for tab in sym_tab.kid:
312
+ if tab.name not in [i.label for i in symbols]:
313
+ symbols.append(
314
+ lspt.CompletionItem(label=tab.name, kind=label_map(tab.get_type()))
315
+ )
316
+ return symbols
317
+
318
+
305
319
  def parse_symbol_path(text: str, dot_position: int) -> list[str]:
306
320
  """Parse text and return a list of symbols."""
307
321
  text = text[:dot_position][:-1].strip()
jaclang/plugin/default.py CHANGED
@@ -6,7 +6,6 @@ import ast as ast3
6
6
  import fnmatch
7
7
  import html
8
8
  import os
9
- import pickle
10
9
  import types
11
10
  from collections import OrderedDict
12
11
  from dataclasses import field
@@ -510,9 +509,10 @@ class JacBuiltinImpl:
510
509
  'fillcolor="invis", fontcolor="black"];\n'
511
510
  )
512
511
  for source, target, edge in connections:
512
+ edge_label = html.escape(str(edge.__jac__.architype))
513
513
  dot_content += (
514
514
  f"{visited_nodes.index(source)} -> {visited_nodes.index(target)} "
515
- f' [label="{html.escape(str(edge.__jac__.architype))} "];\n'
515
+ f' [label="{edge_label if "GenericEdge" not in edge_label else ""}"];\n'
516
516
  )
517
517
  for node_ in visited_nodes:
518
518
  color = (
@@ -751,7 +751,9 @@ class JacFeatureImpl(
751
751
 
752
752
  jac_machine = JacMachine.get(base_path)
753
753
  if not jac_machine.jac_program:
754
- jac_machine.attach_program(JacProgram(mod_bundle=None, bytecode=None))
754
+ jac_machine.attach_program(
755
+ JacProgram(mod_bundle=None, bytecode=None, sem_ir=None)
756
+ )
755
757
 
756
758
  if lng == "py":
757
759
  import_result = PythonImporter(JacMachine.get()).run_import(spec)
@@ -800,7 +802,7 @@ class JacFeatureImpl(
800
802
  if mod_name.endswith(".test"):
801
803
  mod_name = mod_name[:-5]
802
804
  JacTestCheck.reset()
803
- Jac.jac_import(target=mod_name, base_path=base)
805
+ Jac.jac_import(target=mod_name, base_path=base, cachable=False)
804
806
  JacTestCheck.run_test(xit, maxfail, verbose)
805
807
  ret_count = JacTestCheck.failcount
806
808
  else:
@@ -854,8 +856,13 @@ class JacFeatureImpl(
854
856
 
855
857
  @staticmethod
856
858
  @hookimpl
857
- def report(expr: Any) -> Any: # noqa: ANN401
859
+ def report(expr: Any, custom: bool) -> None: # noqa: ANN401
858
860
  """Jac's report stmt feature."""
861
+ ctx = Jac.get_context()
862
+ if custom:
863
+ ctx.custom = expr
864
+ else:
865
+ ctx.reports.append(expr)
859
866
 
860
867
  @staticmethod
861
868
  @hookimpl
@@ -1059,16 +1066,14 @@ class JacFeatureImpl(
1059
1066
  file_loc: str, scope: str, attr: str, return_semstr: bool
1060
1067
  ) -> Optional[str]:
1061
1068
  """Jac's get_semstr_type feature."""
1069
+ from jaclang.compiler.semtable import SemInfo, SemScope, SemRegistry
1070
+ from jaclang.runtimelib.machine import JacMachine
1071
+
1062
1072
  _scope = SemScope.get_scope_from_str(scope)
1063
- with open(
1064
- os.path.join(
1065
- os.path.dirname(file_loc),
1066
- "__jac_gen__",
1067
- os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
1068
- ),
1069
- "rb",
1070
- ) as f:
1071
- mod_registry: SemRegistry = pickle.load(f)
1073
+ jac_program = JacMachine.get().jac_program
1074
+ mod_registry: SemRegistry = (
1075
+ jac_program.sem_ir if jac_program is not None else SemRegistry()
1076
+ )
1072
1077
  _, attr_seminfo = mod_registry.lookup(_scope, attr)
1073
1078
  if attr_seminfo and isinstance(attr_seminfo, SemInfo):
1074
1079
  return attr_seminfo.semstr if return_semstr else attr_seminfo.type
@@ -1078,15 +1083,12 @@ class JacFeatureImpl(
1078
1083
  @hookimpl
1079
1084
  def obj_scope(file_loc: str, attr: str) -> str:
1080
1085
  """Jac's gather_scope feature."""
1081
- with open(
1082
- os.path.join(
1083
- os.path.dirname(file_loc),
1084
- "__jac_gen__",
1085
- os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
1086
- ),
1087
- "rb",
1088
- ) as f:
1089
- mod_registry: SemRegistry = pickle.load(f)
1086
+ from jaclang.runtimelib.machine import JacMachine
1087
+
1088
+ jac_program = JacMachine.get().jac_program
1089
+ mod_registry: SemRegistry = (
1090
+ jac_program.sem_ir if jac_program is not None else SemRegistry()
1091
+ )
1090
1092
 
1091
1093
  attr_scope = None
1092
1094
  for x in attr.split("."):
@@ -1119,15 +1121,13 @@ class JacFeatureImpl(
1119
1121
  @hookimpl
1120
1122
  def get_sem_type(file_loc: str, attr: str) -> tuple[str | None, str | None]:
1121
1123
  """Jac's get_semstr_type implementation."""
1122
- with open(
1123
- os.path.join(
1124
- os.path.dirname(file_loc),
1125
- "__jac_gen__",
1126
- os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
1127
- ),
1128
- "rb",
1129
- ) as f:
1130
- mod_registry: SemRegistry = pickle.load(f)
1124
+ from jaclang.runtimelib.machine import JacMachine
1125
+ from jaclang.compiler.semtable import SemInfo, SemScope
1126
+
1127
+ jac_program = JacMachine.get().jac_program
1128
+ mod_registry: SemRegistry = (
1129
+ jac_program.sem_ir if jac_program is not None else SemRegistry()
1130
+ )
1131
1131
 
1132
1132
  attr_scope = None
1133
1133
  for x in attr.split("."):
jaclang/plugin/feature.py CHANGED
@@ -371,9 +371,9 @@ class JacFeature(
371
371
  return plugin_manager.hook.has_instance_default(gen_func=gen_func)
372
372
 
373
373
  @staticmethod
374
- def report(expr: Any) -> Any: # noqa: ANN401
374
+ def report(expr: Any, custom: bool = False) -> None: # noqa: ANN401
375
375
  """Jac's report stmt feature."""
376
- return plugin_manager.hook.report(expr=expr)
376
+ plugin_manager.hook.report(expr=expr, custom=custom)
377
377
 
378
378
  @staticmethod
379
379
  def edge_ref(