jaclang 0.7.14__py3-none-any.whl → 0.7.17__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 (131) hide show
  1. jaclang/cli/cli.py +147 -77
  2. jaclang/cli/cmdreg.py +9 -12
  3. jaclang/compiler/__init__.py +19 -53
  4. jaclang/compiler/absyntree.py +94 -16
  5. jaclang/compiler/constant.py +8 -8
  6. jaclang/compiler/jac.lark +4 -3
  7. jaclang/compiler/parser.py +41 -25
  8. jaclang/compiler/passes/ir_pass.py +4 -13
  9. jaclang/compiler/passes/main/__init__.py +1 -1
  10. jaclang/compiler/passes/main/access_modifier_pass.py +96 -147
  11. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +155 -54
  12. jaclang/compiler/passes/main/import_pass.py +99 -75
  13. jaclang/compiler/passes/main/py_collect_dep_pass.py +70 -0
  14. jaclang/compiler/passes/main/pyast_gen_pass.py +328 -565
  15. jaclang/compiler/passes/main/pyast_load_pass.py +33 -6
  16. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -0
  17. jaclang/compiler/passes/main/registry_pass.py +37 -3
  18. jaclang/compiler/passes/main/schedules.py +9 -2
  19. jaclang/compiler/passes/main/sym_tab_build_pass.py +10 -6
  20. jaclang/compiler/passes/main/tests/__init__.py +1 -1
  21. jaclang/compiler/passes/main/tests/fixtures/autoimpl.empty.impl.jac +0 -0
  22. jaclang/compiler/passes/main/tests/fixtures/autoimpl.jac +1 -1
  23. jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac +29 -0
  24. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.py +3 -0
  25. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/color.py +3 -0
  26. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/constants.py +5 -0
  27. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/display.py +2 -0
  28. jaclang/compiler/passes/main/tests/test_import_pass.py +72 -13
  29. jaclang/compiler/passes/main/type_check_pass.py +22 -5
  30. jaclang/compiler/passes/tool/jac_formatter_pass.py +135 -89
  31. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +37 -41
  32. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +37 -42
  33. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/access_mod_check.jac +27 -0
  34. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
  35. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
  36. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
  37. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
  38. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
  39. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
  40. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
  41. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
  42. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
  43. jaclang/compiler/passes/transform.py +4 -0
  44. jaclang/compiler/passes/utils/mypy_ast_build.py +45 -0
  45. jaclang/compiler/semtable.py +31 -7
  46. jaclang/compiler/symtable.py +16 -11
  47. jaclang/compiler/tests/test_importer.py +25 -10
  48. jaclang/langserve/engine.py +104 -118
  49. jaclang/langserve/sem_manager.py +379 -0
  50. jaclang/langserve/server.py +24 -11
  51. jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
  52. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  53. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  54. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  55. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  56. jaclang/langserve/tests/fixtures/rename.jac +30 -0
  57. jaclang/langserve/tests/test_sem_tokens.py +277 -0
  58. jaclang/langserve/tests/test_server.py +287 -17
  59. jaclang/langserve/utils.py +184 -98
  60. jaclang/plugin/builtin.py +1 -1
  61. jaclang/plugin/default.py +288 -92
  62. jaclang/plugin/feature.py +65 -27
  63. jaclang/plugin/spec.py +62 -23
  64. jaclang/plugin/tests/fixtures/other_root_access.jac +82 -0
  65. jaclang/plugin/tests/test_jaseci.py +414 -42
  66. jaclang/runtimelib/architype.py +650 -0
  67. jaclang/{core → runtimelib}/constructs.py +5 -8
  68. jaclang/{core → runtimelib}/context.py +86 -59
  69. jaclang/runtimelib/importer.py +361 -0
  70. jaclang/runtimelib/machine.py +158 -0
  71. jaclang/runtimelib/memory.py +158 -0
  72. jaclang/{core → runtimelib}/utils.py +30 -15
  73. jaclang/settings.py +5 -4
  74. jaclang/tests/fixtures/abc.jac +3 -3
  75. jaclang/tests/fixtures/access_checker.jac +12 -17
  76. jaclang/tests/fixtures/access_modifier.jac +88 -33
  77. jaclang/tests/fixtures/baddy.jac +3 -0
  78. jaclang/tests/fixtures/baddy.test.jac +3 -0
  79. jaclang/tests/fixtures/bar.jac +34 -0
  80. jaclang/tests/fixtures/byllmissue.jac +1 -5
  81. jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
  82. jaclang/tests/fixtures/cls_method.jac +41 -0
  83. jaclang/tests/fixtures/dblhello.jac +6 -0
  84. jaclang/tests/fixtures/deep/one_lev.jac +3 -3
  85. jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
  86. jaclang/tests/fixtures/deep_import_mods.jac +13 -0
  87. jaclang/tests/fixtures/edge_node_walk.jac +1 -1
  88. jaclang/tests/fixtures/edge_ops.jac +1 -1
  89. jaclang/tests/fixtures/edges_walk.jac +1 -1
  90. jaclang/tests/fixtures/err.impl.jac +3 -0
  91. jaclang/tests/fixtures/err.jac +4 -2
  92. jaclang/tests/fixtures/err_runtime.jac +15 -0
  93. jaclang/tests/fixtures/foo.jac +43 -0
  94. jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
  95. jaclang/tests/fixtures/hello.jac +4 -0
  96. jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
  97. jaclang/tests/fixtures/impl_grab.jac +4 -1
  98. jaclang/tests/fixtures/import.jac +9 -0
  99. jaclang/tests/fixtures/index_slice.jac +30 -0
  100. jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
  101. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  102. jaclang/tests/fixtures/needs_import.jac +2 -2
  103. jaclang/tests/fixtures/pyfunc_1.py +1 -1
  104. jaclang/tests/fixtures/pyfunc_2.py +5 -2
  105. jaclang/tests/fixtures/pygame_mock/__init__.py +3 -0
  106. jaclang/tests/fixtures/pygame_mock/color.py +3 -0
  107. jaclang/tests/fixtures/pygame_mock/constants.py +5 -0
  108. jaclang/tests/fixtures/pygame_mock/display.py +2 -0
  109. jaclang/tests/fixtures/pygame_mock/inner/__init__.py +0 -0
  110. jaclang/tests/fixtures/pygame_mock/inner/iner_mod.py +2 -0
  111. jaclang/tests/fixtures/registry.jac +9 -0
  112. jaclang/tests/fixtures/run_test.jac +4 -4
  113. jaclang/tests/fixtures/semstr.jac +1 -4
  114. jaclang/tests/fixtures/simple_archs.jac +1 -1
  115. jaclang/tests/test_cli.py +109 -3
  116. jaclang/tests/test_language.py +170 -68
  117. jaclang/tests/test_reference.py +2 -3
  118. jaclang/utils/helpers.py +45 -21
  119. jaclang/utils/test.py +9 -0
  120. jaclang/utils/treeprinter.py +30 -7
  121. {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/METADATA +3 -2
  122. {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/RECORD +126 -90
  123. jaclang/core/architype.py +0 -502
  124. jaclang/core/importer.py +0 -344
  125. jaclang/core/memory.py +0 -99
  126. jaclang/tests/fixtures/aott_raise.jac +0 -25
  127. jaclang/tests/fixtures/package_import.jac +0 -6
  128. /jaclang/{core → runtimelib}/__init__.py +0 -0
  129. /jaclang/{core → runtimelib}/test.py +0 -0
  130. {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/WHEEL +0 -0
  131. {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/entry_points.txt +0 -0
@@ -12,8 +12,8 @@ from jaclang import jac_import
12
12
  from jaclang.cli import cli
13
13
  from jaclang.compiler.compile import jac_file_to_pass, jac_pass_to_pass, jac_str_to_pass
14
14
  from jaclang.compiler.passes.main.schedules import py_code_gen_typed
15
- from jaclang.plugin.feature import JacFeature as Jac
16
- from jaclang.settings import settings
15
+ from jaclang.runtimelib.context import SUPER_ROOT_ANCHOR
16
+ from jaclang.runtimelib.machine import JacMachine, JacProgram
17
17
  from jaclang.utils.test import TestCase
18
18
 
19
19
 
@@ -22,8 +22,17 @@ class JacLanguageTests(TestCase):
22
22
 
23
23
  def setUp(self) -> None:
24
24
  """Set up test."""
25
+ SUPER_ROOT_ANCHOR.edges.clear()
26
+ JacMachine(self.fixture_abs_path("./")).attach_program(
27
+ JacProgram(mod_bundle=None, bytecode=None)
28
+ )
25
29
  return super().setUp()
26
30
 
31
+ def tearDown(self) -> None:
32
+ """Tear down test."""
33
+ JacMachine.detach()
34
+ return super().tearDown()
35
+
27
36
  def test_sub_abilities(self) -> None:
28
37
  """Basic test for pass."""
29
38
  captured_output = io.StringIO()
@@ -106,13 +115,12 @@ class JacLanguageTests(TestCase):
106
115
  stdout_value,
107
116
  "{'apple': None, 'pineapple': None}\n"
108
117
  "This is a long\n"
109
- " line of code.\n"
118
+ " line of code.\n"
110
119
  "{'a': 'apple', 'b': 'ball', 'c': 'cat', 'd': 'dog', 'e': 'elephant'}\n",
111
120
  )
112
121
 
113
122
  def test_ignore(self) -> None:
114
123
  """Parse micro jac file."""
115
- Jac.get_root()._jac_.edges.clear()
116
124
  captured_output = io.StringIO()
117
125
  sys.stdout = captured_output
118
126
  jac_import("ignore_dup", base_path=self.fixture_abs_path("./"))
@@ -206,17 +214,34 @@ class JacLanguageTests(TestCase):
206
214
 
207
215
  def test_deep_imports(self) -> None:
208
216
  """Parse micro jac file."""
209
- Jac.get_root()._jac_.edges.clear()
210
217
  captured_output = io.StringIO()
211
218
  sys.stdout = captured_output
219
+
212
220
  jac_import("deep_import", base_path=self.fixture_abs_path("./"))
213
221
  sys.stdout = sys.__stdout__
214
222
  stdout_value = captured_output.getvalue()
215
223
  self.assertEqual(stdout_value.split("\n")[0], "one level deeperslHello World!")
216
224
 
225
+ def test_deep_imports_mods(self) -> None:
226
+ """Parse micro jac file."""
227
+ targets = [
228
+ "deep",
229
+ "deep.deeper",
230
+ "deep.mycode",
231
+ "deep.deeper.snd_lev",
232
+ "deep.one_lev",
233
+ ]
234
+ for i in targets:
235
+ if i in sys.modules:
236
+ del sys.modules[i]
237
+ jac_import("deep_import_mods", base_path=self.fixture_abs_path("./"))
238
+ mods = JacMachine.get().loaded_modules.keys()
239
+ for i in targets:
240
+ self.assertIn(i, mods)
241
+ self.assertEqual(len([i for i in mods if i.startswith("deep")]), 6)
242
+
217
243
  def test_deep_outer_imports_one(self) -> None:
218
244
  """Parse micro jac file."""
219
- Jac.get_root()._jac_.edges.clear()
220
245
  captured_output = io.StringIO()
221
246
  sys.stdout = captured_output
222
247
  jac_import(
@@ -229,7 +254,6 @@ class JacLanguageTests(TestCase):
229
254
 
230
255
  def test_deep_outer_imports_from_loc(self) -> None:
231
256
  """Parse micro jac file."""
232
- Jac.get_root()._jac_.edges.clear()
233
257
  captured_output = io.StringIO()
234
258
  sys.stdout = captured_output
235
259
  os.chdir(self.fixture_abs_path("./deep/deeper/"))
@@ -241,7 +265,6 @@ class JacLanguageTests(TestCase):
241
265
 
242
266
  # def test_second_deep_outer_imports(self) -> None:
243
267
  # """Parse micro jac file."""
244
- # Jac.get_root()._jac_.edges.clear()
245
268
  # captured_output = io.StringIO()
246
269
  # sys.stdout = captured_output
247
270
  # jac_import(
@@ -254,7 +277,6 @@ class JacLanguageTests(TestCase):
254
277
 
255
278
  def test_has_lambda_goodness(self) -> None:
256
279
  """Test has lambda_goodness."""
257
- Jac.get_root()._jac_.edges.clear()
258
280
  captured_output = io.StringIO()
259
281
  sys.stdout = captured_output
260
282
  jac_import("has_goodness", base_path=self.fixture_abs_path("./"))
@@ -265,7 +287,6 @@ class JacLanguageTests(TestCase):
265
287
 
266
288
  def test_conn_assign_on_edges(self) -> None:
267
289
  """Test conn assign on edges."""
268
- Jac.get_root()._jac_.edges.clear()
269
290
  captured_output = io.StringIO()
270
291
  sys.stdout = captured_output
271
292
  jac_import("edge_ops", base_path=self.fixture_abs_path("./"))
@@ -277,7 +298,6 @@ class JacLanguageTests(TestCase):
277
298
 
278
299
  def test_disconnect(self) -> None:
279
300
  """Test conn assign on edges."""
280
- Jac.get_root()._jac_.edges.clear()
281
301
  captured_output = io.StringIO()
282
302
  sys.stdout = captured_output
283
303
  jac_import("disconn", base_path=self.fixture_abs_path("./"))
@@ -295,7 +315,6 @@ class JacLanguageTests(TestCase):
295
315
 
296
316
  def test_simple_archs(self) -> None:
297
317
  """Test conn assign on edges."""
298
- Jac.get_root()._jac_.edges.clear()
299
318
  captured_output = io.StringIO()
300
319
  sys.stdout = captured_output
301
320
  jac_import("simple_archs", base_path=self.fixture_abs_path("./"))
@@ -306,7 +325,6 @@ class JacLanguageTests(TestCase):
306
325
 
307
326
  def test_edge_walk(self) -> None:
308
327
  """Test walking through edges."""
309
- Jac.get_root()._jac_.edges.clear()
310
328
  captured_output = io.StringIO()
311
329
  sys.stdout = captured_output
312
330
  jac_import("edges_walk", base_path=self.fixture_abs_path("./"))
@@ -320,7 +338,6 @@ class JacLanguageTests(TestCase):
320
338
 
321
339
  def test_impl_grab(self) -> None:
322
340
  """Test walking through edges."""
323
- Jac.get_root()._jac_.edges.clear()
324
341
  captured_output = io.StringIO()
325
342
  sys.stdout = captured_output
326
343
  jac_import("impl_grab", base_path=self.fixture_abs_path("./"))
@@ -330,7 +347,6 @@ class JacLanguageTests(TestCase):
330
347
 
331
348
  def test_tuple_of_tuple_assign(self) -> None:
332
349
  """Test walking through edges."""
333
- Jac.get_root()._jac_.edges.clear()
334
350
  captured_output = io.StringIO()
335
351
  sys.stdout = captured_output
336
352
  jac_import("tuplytuples", base_path=self.fixture_abs_path("./"))
@@ -343,7 +359,6 @@ class JacLanguageTests(TestCase):
343
359
 
344
360
  def test_deferred_field(self) -> None:
345
361
  """Test walking through edges."""
346
- Jac.get_root()._jac_.edges.clear()
347
362
  captured_output = io.StringIO()
348
363
  sys.stdout = captured_output
349
364
  jac_import("deferred_field", base_path=self.fixture_abs_path("./"))
@@ -356,18 +371,15 @@ class JacLanguageTests(TestCase):
356
371
 
357
372
  def test_gen_dot_builtin(self) -> None:
358
373
  """Test the dot gen of nodes and edges as a builtin."""
359
- Jac.get_root()._jac_.edges.clear()
360
374
  captured_output = io.StringIO()
361
375
  sys.stdout = captured_output
362
376
  jac_import("builtin_dotgen", base_path=self.fixture_abs_path("./"))
363
377
  sys.stdout = sys.__stdout__
364
378
  stdout_value = captured_output.getvalue()
365
- print(stdout_value)
366
379
  self.assertEqual(stdout_value.count("True"), 14)
367
380
 
368
381
  def test_with_contexts(self) -> None:
369
382
  """Test walking through edges."""
370
- Jac.get_root()._jac_.edges.clear()
371
383
  captured_output = io.StringIO()
372
384
  sys.stdout = captured_output
373
385
  jac_import("with_context", base_path=self.fixture_abs_path("./"))
@@ -385,10 +397,7 @@ class JacLanguageTests(TestCase):
385
397
  """Parse micro jac file."""
386
398
  captured_output = io.StringIO()
387
399
  sys.stdout = captured_output
388
- jac_import(
389
- "micro.typed_filter_compr",
390
- base_path=self.examples_abs_path(""),
391
- )
400
+ jac_import("micro.typed_filter_compr", base_path=self.examples_abs_path(""))
392
401
  sys.stdout = sys.__stdout__
393
402
  stdout_value = captured_output.getvalue()
394
403
  self.assertIn(
@@ -400,7 +409,6 @@ class JacLanguageTests(TestCase):
400
409
 
401
410
  def test_edge_node_walk(self) -> None:
402
411
  """Test walking through edges and nodes."""
403
- Jac.get_root()._jac_.edges.clear()
404
412
  captured_output = io.StringIO()
405
413
  sys.stdout = captured_output
406
414
  jac_import("edge_node_walk", base_path=self.fixture_abs_path("./"))
@@ -414,14 +422,12 @@ class JacLanguageTests(TestCase):
414
422
 
415
423
  def test_annotation_tuple_issue(self) -> None:
416
424
  """Test conn assign on edges."""
417
- Jac.get_root()._jac_.edges.clear()
418
425
  mypass = jac_file_to_pass(self.fixture_abs_path("./slice_vals.jac"))
419
426
  self.assertIn("Annotated[Str, INT, BLAH]", mypass.ir.gen.py)
420
427
  self.assertIn("tuple[int, Optional[type], Optional[tuple]]", mypass.ir.gen.py)
421
428
 
422
429
  def test_impl_decl_resolution_fix(self) -> None:
423
430
  """Test walking through edges and nodes."""
424
- Jac.get_root()._jac_.edges.clear()
425
431
  captured_output = io.StringIO()
426
432
  sys.stdout = captured_output
427
433
  jac_import("mtest", base_path=self.fixture_abs_path("./"))
@@ -446,9 +452,11 @@ class JacLanguageTests(TestCase):
446
452
  ) as f:
447
453
  registry = pickle.load(f)
448
454
 
449
- self.assertEqual(len(registry.registry), 3)
450
- self.assertEqual(len(list(registry.registry.items())[0][1]), 10)
451
- self.assertEqual(list(registry.registry.items())[1][0].scope, "Person")
455
+ self.assertEqual(len(registry.registry), 9)
456
+ self.assertEqual(len(list(registry.registry.items())[0][1]), 2)
457
+ self.assertEqual(list(registry.registry.items())[3][0].scope, "Person")
458
+ _, sem_info = registry.lookup(name="normal_ability")
459
+ self.assertEqual(len(sem_info.get_children(registry)), 2)
452
460
 
453
461
  def test_enum_inside_arch(self) -> None:
454
462
  """Test Enum as member stmt."""
@@ -461,12 +469,23 @@ class JacLanguageTests(TestCase):
461
469
 
462
470
  def test_needs_import_1(self) -> None:
463
471
  """Test py ast to Jac ast conversion output."""
464
- settings.py_raise = True
465
- file_name = os.path.join(self.fixture_abs_path("./"), "needs_import_1.jac")
466
- from jaclang.compiler.passes.main.schedules import py_code_gen
472
+ file_name = self.fixture_abs_path("pyfunc_1.py")
473
+
474
+ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
475
+ from jaclang.compiler.passes.main.pyast_load_pass import PyastBuildPass
476
+ import ast as py_ast
467
477
  import jaclang.compiler.absyntree as ast
468
478
 
469
- ir = jac_file_to_pass(file_name, schedule=py_code_gen).ir
479
+ with open(file_name, "r") as f:
480
+ parsed_ast = py_ast.parse(f.read())
481
+ try:
482
+ py_ast_build_pass = PyastBuildPass(
483
+ input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
484
+ )
485
+ except Exception as e:
486
+ return f"Error While Jac to Py AST conversion: {e}"
487
+
488
+ ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
470
489
  self.assertEqual(len(ir.get_all_sub_nodes(ast.Architype)), 7)
471
490
  captured_output = io.StringIO()
472
491
  sys.stdout = captured_output
@@ -474,7 +493,6 @@ class JacLanguageTests(TestCase):
474
493
  sys.stdout = sys.__stdout__
475
494
  stdout_value = captured_output.getvalue()
476
495
  self.assertIn("pyfunc_1 imported", stdout_value)
477
- settings.py_raise = False
478
496
 
479
497
  def test_pyfunc_1(self) -> None:
480
498
  """Test py ast to Jac ast conversion."""
@@ -509,13 +527,26 @@ class JacLanguageTests(TestCase):
509
527
 
510
528
  def test_needs_import_2(self) -> None:
511
529
  """Test py ast to Jac ast conversion output."""
512
- settings.py_raise = True
513
- file_name = os.path.join(self.fixture_abs_path("./"), "needs_import_2.jac")
514
- from jaclang.compiler.passes.main.schedules import py_code_gen
530
+ file_name = self.fixture_abs_path("pyfunc_2.py")
531
+
532
+ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
533
+ from jaclang.compiler.passes.main.pyast_load_pass import PyastBuildPass
534
+ import ast as py_ast
515
535
  import jaclang.compiler.absyntree as ast
516
536
 
517
- ir = jac_file_to_pass(file_name, schedule=py_code_gen).ir
518
- self.assertEqual(len(ir.get_all_sub_nodes(ast.Architype)), 5)
537
+ with open(file_name, "r") as f:
538
+ parsed_ast = py_ast.parse(f.read())
539
+ try:
540
+ py_ast_build_pass = PyastBuildPass(
541
+ input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
542
+ )
543
+ except Exception as e:
544
+ return f"Error While Jac to Py AST conversion: {e}"
545
+
546
+ ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
547
+ self.assertEqual(
548
+ len(ir.get_all_sub_nodes(ast.Architype)), 8
549
+ ) # Because of the Architype from math
519
550
  captured_output = io.StringIO()
520
551
  sys.stdout = captured_output
521
552
  jac_import("needs_import_2", base_path=self.fixture_abs_path("./"))
@@ -523,7 +554,6 @@ class JacLanguageTests(TestCase):
523
554
  stdout_value = captured_output.getvalue()
524
555
  self.assertIn("pyfunc_2 imported", stdout_value)
525
556
  self.assertEqual(stdout_value.count("<class 'bytes'>"), 3)
526
- settings.py_raise = False
527
557
 
528
558
  def test_pyfunc_2(self) -> None:
529
559
  """Test py ast to Jac ast conversion."""
@@ -541,23 +571,36 @@ class JacLanguageTests(TestCase):
541
571
  self.assertIn("class X {\n with entry {\n a_b = 67;", output)
542
572
  self.assertIn("br = b'Hello\\\\\\\\nWorld'", output)
543
573
  self.assertIn("class Circle {\n can init(radius: float", output)
574
+ self.assertIn("<>node = 90; \n print(<>node) ;\n}\n", output)
544
575
 
545
576
  def test_needs_import_3(self) -> None:
546
577
  """Test py ast to Jac ast conversion output."""
547
- settings.py_raise = True
548
- file_name = os.path.join(self.fixture_abs_path("./"), "needs_import_3.jac")
549
- from jaclang.compiler.passes.main.schedules import py_code_gen
578
+ file_name = self.fixture_abs_path("pyfunc_3.py")
579
+
580
+ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
581
+ from jaclang.compiler.passes.main.pyast_load_pass import PyastBuildPass
582
+ import ast as py_ast
550
583
  import jaclang.compiler.absyntree as ast
551
584
 
552
- ir = jac_file_to_pass(file_name, schedule=py_code_gen).ir
553
- self.assertEqual(len(ir.get_all_sub_nodes(ast.Architype)), 6)
585
+ with open(file_name, "r") as f:
586
+ parsed_ast = py_ast.parse(f.read())
587
+ try:
588
+ py_ast_build_pass = PyastBuildPass(
589
+ input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
590
+ )
591
+ except Exception as e:
592
+ return f"Error While Jac to Py AST conversion: {e}"
593
+
594
+ ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
595
+ self.assertEqual(
596
+ len(ir.get_all_sub_nodes(ast.Architype)), 38
597
+ ) # Because of the Architype from other imports
554
598
  captured_output = io.StringIO()
555
599
  sys.stdout = captured_output
556
600
  jac_import("needs_import_3", base_path=self.fixture_abs_path("./"))
557
601
  sys.stdout = sys.__stdout__
558
602
  stdout_value = captured_output.getvalue()
559
603
  self.assertIn("pyfunc_3 imported", stdout_value)
560
- settings.py_raise = False
561
604
 
562
605
  def test_pyfunc_3(self) -> None:
563
606
  """Test py ast to Jac ast conversion."""
@@ -672,18 +715,17 @@ class JacLanguageTests(TestCase):
672
715
 
673
716
  def test_random_check(self) -> None:
674
717
  """Test py ast to Jac ast conversion output."""
675
- settings.py_raise = True
676
-
677
718
  from jaclang.compiler.passes.main import PyastBuildPass
678
719
  import jaclang.compiler.absyntree as ast
679
720
  import ast as py_ast
721
+ from jaclang.settings import settings
680
722
 
681
- module_paths = ["random", "tkinter"]
723
+ module_paths = ["random", "ast"]
682
724
  for module_path in module_paths:
683
725
  stdlib_dir = sysconfig.get_paths()["stdlib"]
684
726
  file_path = os.path.join(
685
727
  stdlib_dir,
686
- module_path + (".py" if module_path == "random" else "/__init__.py"),
728
+ module_path + ".py",
687
729
  )
688
730
  with open(file_path) as f:
689
731
  jac_ast = PyastBuildPass(
@@ -691,23 +733,21 @@ class JacLanguageTests(TestCase):
691
733
  py_ast.parse(f.read()), mod_path=file_path
692
734
  )
693
735
  )
736
+ settings.print_py_raised_ast = True
694
737
  ir = jac_pass_to_pass(jac_ast).ir
695
738
  gen_ast = ir.pp()
696
739
  if module_path == "random":
697
740
  self.assertIn("ModulePath - statistics -", gen_ast)
698
741
  else:
699
- self.assertIn("+-- Name - TclError - Type: No", gen_ast)
700
- settings.py_raise = False
742
+ self.assertIn("+-- Name - NodeTransformer - Type: No", gen_ast)
701
743
 
702
744
  def test_deep_py_load_imports(self) -> None: # we can get rid of this, isn't?
703
745
  """Test py ast to Jac ast conversion output."""
704
- settings.py_raise = True
705
746
  file_name = os.path.join(self.fixture_abs_path("./"), "random_check.jac")
706
747
  from jaclang.compiler.passes.main.schedules import py_code_gen, PyImportPass
707
748
 
708
749
  imp = jac_file_to_pass(file_name, schedule=py_code_gen, target=PyImportPass)
709
750
  self.assertEqual(len(imp.import_table), 1)
710
- settings.py_raise = False
711
751
 
712
752
  def test_access_modifier(self) -> None:
713
753
  """Test for access tags working."""
@@ -719,29 +759,38 @@ class JacLanguageTests(TestCase):
719
759
  )
720
760
  sys.stdout = sys.__stdout__
721
761
  stdout_value = captured_output.getvalue()
722
- self.assertIn('Can not access private variable "p"', stdout_value)
723
- self.assertIn('Can not access private variable "privmethod"', stdout_value)
724
- self.assertIn('Can not access private variable "BankAccount"', stdout_value)
725
- self.assertNotIn(" Name: ", stdout_value)
762
+ self.assertEqual(stdout_value.count("Invalid access"), 18)
726
763
 
727
764
  def test_deep_convert(self) -> None:
728
765
  """Test py ast to Jac ast conversion output."""
729
- settings.py_raise = settings.py_raise_deep = True
730
- file_name = os.path.join(self.fixture_abs_path("./"), "deep_convert.jac")
731
- from jaclang.compiler.passes.main.schedules import py_code_gen
766
+ file_name = self.fixture_abs_path("pyfunc_1.py")
767
+
768
+ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
769
+ from jaclang.compiler.passes.main.pyast_load_pass import PyastBuildPass
770
+ import ast as py_ast
732
771
  import jaclang.compiler.absyntree as ast
772
+ from jaclang.settings import settings
773
+
774
+ with open(file_name, "r") as f:
775
+ parsed_ast = py_ast.parse(f.read())
776
+ try:
777
+ py_ast_build_pass = PyastBuildPass(
778
+ input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
779
+ )
780
+ except Exception as e:
781
+ return f"Error While Jac to Py AST conversion: {e}"
733
782
 
734
- ir = jac_file_to_pass(file_name, schedule=py_code_gen).ir
783
+ settings.print_py_raised_ast = True
784
+ ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
735
785
  jac_ast = ir.pp()
736
786
  self.assertIn(' | +-- String - "Loop compl', jac_ast)
737
- self.assertEqual(len(ir.get_all_sub_nodes(ast.SubNodeList)), 272)
787
+ self.assertEqual(len(ir.get_all_sub_nodes(ast.SubNodeList)), 269)
738
788
  captured_output = io.StringIO()
739
789
  sys.stdout = captured_output
740
790
  jac_import("deep_convert", base_path=self.fixture_abs_path("./"))
741
791
  sys.stdout = sys.__stdout__
742
792
  stdout_value = captured_output.getvalue()
743
793
  self.assertIn("Deep convo is imported", stdout_value)
744
- settings.py_raise = settings.py_raise_deep = False
745
794
 
746
795
  def test_override_walker_inherit(self) -> None:
747
796
  """Test py ast to Jac ast conversion output."""
@@ -754,7 +803,6 @@ class JacLanguageTests(TestCase):
754
803
 
755
804
  def test_ds_type_check_pass(self) -> None:
756
805
  """Test conn assign on edges."""
757
- Jac.get_root()._jac_.edges.clear()
758
806
  mypass = jac_file_to_pass(
759
807
  self.examples_abs_path("micro/simple_walk.jac"),
760
808
  schedule=py_code_gen_typed,
@@ -764,7 +812,6 @@ class JacLanguageTests(TestCase):
764
812
 
765
813
  def test_ds_type_check_pass2(self) -> None:
766
814
  """Test conn assign on edges."""
767
- Jac.get_root()._jac_.edges.clear()
768
815
  mypass = jac_file_to_pass(
769
816
  self.examples_abs_path("guess_game/guess_game5.jac"),
770
817
  schedule=py_code_gen_typed,
@@ -772,6 +819,15 @@ class JacLanguageTests(TestCase):
772
819
  self.assertEqual(len(mypass.errors_had), 0)
773
820
  self.assertEqual(len(mypass.warnings_had), 0)
774
821
 
822
+ def test_circle_override1_type_check_pass(self) -> None:
823
+ """Test conn assign on edges."""
824
+ mypass = jac_file_to_pass(
825
+ self.examples_abs_path("manual_code/circle.jac"),
826
+ schedule=py_code_gen_typed,
827
+ )
828
+ self.assertEqual(len(mypass.errors_had), 0)
829
+ self.assertEqual(len(mypass.warnings_had), 0)
830
+
775
831
  def test_self_with_no_sig(self) -> None: # we can get rid of this, isn't?
776
832
  """Test py ast to Jac ast conversion output."""
777
833
  captured_output = io.StringIO()
@@ -792,7 +848,6 @@ class JacLanguageTests(TestCase):
792
848
 
793
849
  def test_multiline_single_tok(self) -> None:
794
850
  """Test conn assign on edges."""
795
- Jac.get_root()._jac_.edges.clear()
796
851
  mypass = jac_file_to_pass(self.fixture_abs_path("byllmissue.jac"))
797
852
  self.assertIn("2:5 - 4:8", mypass.ir.pp())
798
853
 
@@ -822,7 +877,6 @@ class JacLanguageTests(TestCase):
822
877
  )
823
878
  table = None
824
879
  for i in mypass.ir.sym_tab.kid:
825
- print(i.name)
826
880
  if i.name == "GuessTheNumberGame":
827
881
  for j in i.kid:
828
882
  if j.name == "play":
@@ -849,3 +903,51 @@ class JacLanguageTests(TestCase):
849
903
  sys.stdout = sys.__stdout__
850
904
  stdout_value = captured_output.getvalue()
851
905
  self.assertIn("i work", stdout_value)
906
+
907
+ def test_double_import_exec(self) -> None:
908
+ """Test importing python."""
909
+ captured_output = io.StringIO()
910
+ sys.stdout = captured_output
911
+ jac_import("dblhello", base_path=self.fixture_abs_path("./"))
912
+ sys.stdout = sys.__stdout__
913
+ stdout_value = captured_output.getvalue()
914
+ self.assertEqual(stdout_value.count("Hello World!"), 1)
915
+ self.assertIn("im still here", stdout_value)
916
+
917
+ def test_cls_method(self) -> None:
918
+ """Test class method output."""
919
+ captured_output = io.StringIO()
920
+ sys.stdout = captured_output
921
+ jac_import("cls_method", base_path=self.fixture_abs_path("./"))
922
+ sys.stdout = sys.__stdout__
923
+ stdout_value = captured_output.getvalue().split("\n")
924
+ self.assertEqual("MyClass", stdout_value[0])
925
+ self.assertEqual("Hello, World1! Hello, World2!", stdout_value[1])
926
+ self.assertEqual("Hello, World! Hello, World22!", stdout_value[2])
927
+
928
+ def test_list_methods(self) -> None:
929
+ """Test list_modules, list_walkers, list_nodes, and list_edges."""
930
+ captured_output = io.StringIO()
931
+ sys.stdout = captured_output
932
+
933
+ jac_import("foo", base_path=self.fixture_abs_path("."))
934
+
935
+ sys.stdout = sys.__stdout__
936
+ stdout_value = captured_output.getvalue()
937
+
938
+ self.assertIn(
939
+ "Module: foo",
940
+ stdout_value,
941
+ )
942
+ self.assertIn(
943
+ "Module: bar",
944
+ stdout_value,
945
+ )
946
+ self.assertIn(
947
+ "Walkers in bar:\n - Walker: bar_walk",
948
+ stdout_value,
949
+ )
950
+ self.assertIn("Nodes in bar:\n - Node: Item", stdout_value)
951
+ self.assertIn("Edges in bar:\n - Edge: Link", stdout_value)
952
+ self.assertIn("Item value: 0", stdout_value)
953
+ self.assertIn("Created 5 items.", stdout_value)
@@ -7,7 +7,7 @@ from typing import Callable, Optional
7
7
 
8
8
  import jaclang
9
9
  from jaclang.compiler.compile import jac_file_to_pass
10
- from jaclang.plugin.feature import JacFeature as Jac
10
+ from jaclang.runtimelib.context import SUPER_ROOT_ANCHOR
11
11
  from jaclang.utils.test import TestCase
12
12
 
13
13
 
@@ -52,7 +52,7 @@ class JacReferenceTests(TestCase):
52
52
  """Test file."""
53
53
 
54
54
  def execute_and_capture_output(code: str | bytes, filename: str = "") -> str:
55
- Jac.get_root().reset()
55
+ SUPER_ROOT_ANCHOR.edges.clear()
56
56
  f = io.StringIO()
57
57
  with redirect_stdout(f):
58
58
  exec(
@@ -60,7 +60,6 @@ class JacReferenceTests(TestCase):
60
60
  {
61
61
  "__file__": filename,
62
62
  "__name__": "__main__",
63
- "__jac_mod_bundle__": None,
64
63
  },
65
64
  )
66
65
  return f.getvalue()
jaclang/utils/helpers.py CHANGED
@@ -5,7 +5,7 @@ import marshal
5
5
  import os
6
6
  import pdb
7
7
  import re
8
- from typing import Optional
8
+ from traceback import TracebackException
9
9
 
10
10
 
11
11
  def pascal_to_snake(pascal_string: str) -> str:
@@ -127,26 +127,6 @@ def auto_generate_refs() -> None:
127
127
  md_file.write("")
128
128
 
129
129
 
130
- def import_target_to_relative_path(
131
- level: int, target: str, base_path: Optional[str] = None
132
- ) -> str:
133
- """Convert an import target string into a relative file path."""
134
- if not base_path:
135
- base_path = os.getcwd()
136
- parts = target.split(".")
137
- traversal_levels = level - 1 if level > 0 else 0
138
- actual_parts = parts[traversal_levels:]
139
- for _ in range(traversal_levels):
140
- base_path = os.path.dirname(base_path)
141
- relative_path = os.path.join(base_path, *actual_parts)
142
- relative_path = (
143
- relative_path + ".jac"
144
- if os.path.exists(relative_path + ".jac")
145
- else relative_path
146
- )
147
- return relative_path
148
-
149
-
150
130
  def is_standard_lib_module(module_path: str) -> bool:
151
131
  """Check if a module is a standard library module."""
152
132
  import os
@@ -158,6 +138,50 @@ def is_standard_lib_module(module_path: str) -> bool:
158
138
  return os.path.isfile(file_path) or os.path.isdir(direc_path)
159
139
 
160
140
 
141
+ def dump_traceback(e: Exception) -> str:
142
+ """Dump the stack frames of the exception."""
143
+ trace_dump = ""
144
+
145
+ # Utility function to get the error line char offset.
146
+ def byte_offset_to_char_offset(string: str, offset: int) -> int:
147
+ return len(string.encode("utf-8")[:offset].decode("utf-8", errors="replace"))
148
+
149
+ tb = TracebackException(type(e), e, e.__traceback__, limit=None, compact=True)
150
+ trace_dump += f"Error: {str(e)}"
151
+
152
+ # The first frame is the call the to the above `exec` function, not usefull to the enduser,
153
+ # and Make the most recent call first.
154
+ tb.stack.pop(0)
155
+ tb.stack.reverse()
156
+
157
+ # FIXME: should be some settings, we should replace to ensure the anchors length match.
158
+ dump_tab_width = 4
159
+
160
+ for idx, frame in enumerate(tb.stack):
161
+ func_signature = frame.name + ("()" if frame.name.isidentifier() else "")
162
+
163
+ # Pretty print the most recent call's location.
164
+ if idx == 0 and (frame.line and frame.line.strip() != ""):
165
+ line_o = frame._original_line.rstrip() # type: ignore [attr-defined]
166
+ line_s = frame.line.rstrip() if frame.line else ""
167
+ stripped_chars = len(line_o) - len(line_s)
168
+ trace_dump += f'\n{" " * (dump_tab_width * 2)}{line_s}'
169
+ if frame.colno is not None and frame.end_colno is not None:
170
+ off_start = byte_offset_to_char_offset(line_o, frame.colno)
171
+ off_end = byte_offset_to_char_offset(line_o, frame.end_colno)
172
+
173
+ # A bunch of caret '^' characters under the error location.
174
+ anchors = (" " * (off_start - stripped_chars - 1)) + "^" * len(
175
+ line_o[off_start:off_end].replace("\t", " " * dump_tab_width)
176
+ )
177
+
178
+ trace_dump += f'\n{" " * (dump_tab_width * 2)}{anchors}'
179
+
180
+ trace_dump += f'\n{" " * dump_tab_width}at {func_signature} {frame.filename}:{frame.lineno}'
181
+
182
+ return trace_dump
183
+
184
+
161
185
  class Jdb(pdb.Pdb):
162
186
  """Jac debugger."""
163
187
 
jaclang/utils/test.py CHANGED
@@ -5,15 +5,24 @@ import os
5
5
  from typing import Callable, Optional
6
6
  from unittest import TestCase as _TestCase
7
7
 
8
+ from _pytest.logging import LogCaptureFixture
8
9
 
9
10
  import jaclang
10
11
  from jaclang.compiler.passes import Pass
11
12
  from jaclang.utils.helpers import get_ast_nodes_as_snake_case as ast_snakes
12
13
 
14
+ import pytest
15
+
13
16
 
14
17
  class TestCase(_TestCase):
15
18
  """Base test case for Jaseci."""
16
19
 
20
+ # Reference: https://stackoverflow.com/a/50375022
21
+ @pytest.fixture(autouse=True)
22
+ def inject_fixtures(self, caplog: LogCaptureFixture) -> None:
23
+ """Store the logger capture records within the tests."""
24
+ self.caplog = caplog
25
+
17
26
  def setUp(self) -> None:
18
27
  """Set up test case."""
19
28
  return super().setUp()