jaclang 0.7.14__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 (92) 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 +86 -13
  5. jaclang/compiler/jac.lark +4 -3
  6. jaclang/compiler/parser.py +31 -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 +18 -23
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +307 -559
  12. jaclang/compiler/passes/main/pyast_load_pass.py +32 -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/type_check_pass.py +7 -0
  17. jaclang/compiler/passes/tool/jac_formatter_pass.py +124 -86
  18. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +0 -1
  19. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
  20. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
  21. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
  22. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
  23. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
  24. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
  25. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
  26. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
  27. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
  28. jaclang/compiler/passes/transform.py +4 -0
  29. jaclang/compiler/semtable.py +31 -7
  30. jaclang/compiler/tests/test_importer.py +12 -5
  31. jaclang/langserve/engine.py +65 -118
  32. jaclang/langserve/sem_manager.py +379 -0
  33. jaclang/langserve/server.py +8 -10
  34. jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
  35. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  36. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  37. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  38. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  39. jaclang/langserve/tests/test_sem_tokens.py +277 -0
  40. jaclang/langserve/tests/test_server.py +72 -16
  41. jaclang/langserve/utils.py +163 -96
  42. jaclang/plugin/builtin.py +1 -1
  43. jaclang/plugin/default.py +212 -24
  44. jaclang/plugin/feature.py +59 -11
  45. jaclang/plugin/spec.py +58 -6
  46. jaclang/{core → runtimelib}/architype.py +1 -1
  47. jaclang/{core → runtimelib}/context.py +8 -1
  48. jaclang/runtimelib/importer.py +361 -0
  49. jaclang/runtimelib/machine.py +94 -0
  50. jaclang/{core → runtimelib}/utils.py +13 -5
  51. jaclang/settings.py +4 -1
  52. jaclang/tests/fixtures/abc.jac +3 -3
  53. jaclang/tests/fixtures/byllmissue.jac +1 -5
  54. jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
  55. jaclang/tests/fixtures/cls_method.jac +41 -0
  56. jaclang/tests/fixtures/dblhello.jac +6 -0
  57. jaclang/tests/fixtures/deep/one_lev.jac +3 -3
  58. jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
  59. jaclang/tests/fixtures/deep_import_mods.jac +13 -0
  60. jaclang/tests/fixtures/err.impl.jac +3 -0
  61. jaclang/tests/fixtures/err.jac +4 -2
  62. jaclang/tests/fixtures/err.test.jac +3 -0
  63. jaclang/tests/fixtures/err_runtime.jac +15 -0
  64. jaclang/tests/fixtures/game1.jac +1 -1
  65. jaclang/tests/fixtures/hello.jac +4 -0
  66. jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
  67. jaclang/tests/fixtures/impl_grab.jac +4 -1
  68. jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
  69. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  70. jaclang/tests/fixtures/needs_import.jac +2 -2
  71. jaclang/tests/fixtures/pyfunc_2.py +3 -0
  72. jaclang/tests/fixtures/registry.jac +9 -0
  73. jaclang/tests/fixtures/run_test.jac +4 -4
  74. jaclang/tests/fixtures/semstr.jac +1 -4
  75. jaclang/tests/fixtures/simple_archs.jac +1 -1
  76. jaclang/tests/test_cli.py +65 -2
  77. jaclang/tests/test_language.py +74 -7
  78. jaclang/tests/test_reference.py +6 -0
  79. jaclang/utils/helpers.py +45 -21
  80. jaclang/utils/test.py +9 -0
  81. jaclang/utils/treeprinter.py +0 -4
  82. {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/METADATA +3 -2
  83. {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/RECORD +89 -74
  84. jaclang/core/importer.py +0 -344
  85. jaclang/tests/fixtures/aott_raise.jac +0 -25
  86. jaclang/tests/fixtures/package_import.jac +0 -6
  87. /jaclang/{core → runtimelib}/__init__.py +0 -0
  88. /jaclang/{core → runtimelib}/constructs.py +0 -0
  89. /jaclang/{core → runtimelib}/memory.py +0 -0
  90. /jaclang/{core → runtimelib}/test.py +0 -0
  91. {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/WHEEL +0 -0
  92. {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/entry_points.txt +0 -0
@@ -60,6 +60,7 @@ class JacLanguageTests(TestCase):
60
60
 
61
61
  def test_simple_jac_red(self) -> None:
62
62
  """Parse micro jac file."""
63
+ Jac.context().init_memory(base_path=self.examples_abs_path(""))
63
64
  captured_output = io.StringIO()
64
65
  sys.stdout = captured_output
65
66
  jac_import("micro.simple_walk", base_path=self.examples_abs_path(""))
@@ -106,7 +107,7 @@ class JacLanguageTests(TestCase):
106
107
  stdout_value,
107
108
  "{'apple': None, 'pineapple': None}\n"
108
109
  "This is a long\n"
109
- " line of code.\n"
110
+ " line of code.\n"
110
111
  "{'a': 'apple', 'b': 'ball', 'c': 'cat', 'd': 'dog', 'e': 'elephant'}\n",
111
112
  )
112
113
 
@@ -151,6 +152,7 @@ class JacLanguageTests(TestCase):
151
152
 
152
153
  def test_filter_compr(self) -> None:
153
154
  """Testing filter comprehension."""
155
+ Jac.context().init_memory(base_path=self.examples_abs_path("./"))
154
156
  captured_output = io.StringIO()
155
157
  sys.stdout = captured_output
156
158
  jac_import(
@@ -207,16 +209,45 @@ class JacLanguageTests(TestCase):
207
209
  def test_deep_imports(self) -> None:
208
210
  """Parse micro jac file."""
209
211
  Jac.get_root()._jac_.edges.clear()
212
+ Jac.context().init_memory(base_path=self.fixture_abs_path("./"))
210
213
  captured_output = io.StringIO()
211
214
  sys.stdout = captured_output
215
+
212
216
  jac_import("deep_import", base_path=self.fixture_abs_path("./"))
213
217
  sys.stdout = sys.__stdout__
214
218
  stdout_value = captured_output.getvalue()
215
219
  self.assertEqual(stdout_value.split("\n")[0], "one level deeperslHello World!")
216
220
 
221
+ def test_deep_imports_mods(self) -> None:
222
+ """Parse micro jac file."""
223
+ import sys
224
+
225
+ targets = [
226
+ "deep",
227
+ "deep.deeper",
228
+ "deep.mycode",
229
+ "deep.deeper.snd_lev",
230
+ "deep.one_lev",
231
+ ]
232
+ for i in targets:
233
+ if i in sys.modules:
234
+ del sys.modules[i]
235
+ Jac.get_root()._jac_.edges.clear()
236
+ Jac.context().init_memory(base_path=self.fixture_abs_path("./"))
237
+ captured_output = io.StringIO()
238
+ sys.stdout = captured_output
239
+ jac_import("deep_import_mods", base_path=self.fixture_abs_path("./"))
240
+ sys.stdout = sys.__stdout__
241
+ stdout_value = captured_output.getvalue()
242
+ mods = eval(stdout_value)
243
+ for i in targets:
244
+ self.assertIn(i, mods)
245
+ self.assertEqual(len([i for i in mods if i.startswith("deep")]), 5)
246
+
217
247
  def test_deep_outer_imports_one(self) -> None:
218
248
  """Parse micro jac file."""
219
249
  Jac.get_root()._jac_.edges.clear()
250
+ Jac.context().init_memory(base_path=self.fixture_abs_path("./"))
220
251
  captured_output = io.StringIO()
221
252
  sys.stdout = captured_output
222
253
  jac_import(
@@ -230,6 +261,7 @@ class JacLanguageTests(TestCase):
230
261
  def test_deep_outer_imports_from_loc(self) -> None:
231
262
  """Parse micro jac file."""
232
263
  Jac.get_root()._jac_.edges.clear()
264
+ Jac.context().init_memory(base_path=self.fixture_abs_path("./deep/deeper/"))
233
265
  captured_output = io.StringIO()
234
266
  sys.stdout = captured_output
235
267
  os.chdir(self.fixture_abs_path("./deep/deeper/"))
@@ -383,6 +415,7 @@ class JacLanguageTests(TestCase):
383
415
 
384
416
  def test_typed_filter_compr(self) -> None:
385
417
  """Parse micro jac file."""
418
+ Jac.context().init_memory(base_path=self.examples_abs_path(""))
386
419
  captured_output = io.StringIO()
387
420
  sys.stdout = captured_output
388
421
  jac_import(
@@ -446,9 +479,11 @@ class JacLanguageTests(TestCase):
446
479
  ) as f:
447
480
  registry = pickle.load(f)
448
481
 
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")
482
+ self.assertEqual(len(registry.registry), 9)
483
+ self.assertEqual(len(list(registry.registry.items())[0][1]), 2)
484
+ self.assertEqual(list(registry.registry.items())[3][0].scope, "Person")
485
+ _, sem_info = registry.lookup(name="normal_ability")
486
+ self.assertEqual(len(sem_info.get_children(registry)), 2)
452
487
 
453
488
  def test_enum_inside_arch(self) -> None:
454
489
  """Test Enum as member stmt."""
@@ -541,6 +576,7 @@ class JacLanguageTests(TestCase):
541
576
  self.assertIn("class X {\n with entry {\n a_b = 67;", output)
542
577
  self.assertIn("br = b'Hello\\\\\\\\nWorld'", output)
543
578
  self.assertIn("class Circle {\n can init(radius: float", output)
579
+ self.assertIn("<>node = 90; \n print(<>node) ;\n}\n", output)
544
580
 
545
581
  def test_needs_import_3(self) -> None:
546
582
  """Test py ast to Jac ast conversion output."""
@@ -678,12 +714,12 @@ class JacLanguageTests(TestCase):
678
714
  import jaclang.compiler.absyntree as ast
679
715
  import ast as py_ast
680
716
 
681
- module_paths = ["random", "tkinter"]
717
+ module_paths = ["random", "ast"]
682
718
  for module_path in module_paths:
683
719
  stdlib_dir = sysconfig.get_paths()["stdlib"]
684
720
  file_path = os.path.join(
685
721
  stdlib_dir,
686
- module_path + (".py" if module_path == "random" else "/__init__.py"),
722
+ module_path + ".py",
687
723
  )
688
724
  with open(file_path) as f:
689
725
  jac_ast = PyastBuildPass(
@@ -696,7 +732,7 @@ class JacLanguageTests(TestCase):
696
732
  if module_path == "random":
697
733
  self.assertIn("ModulePath - statistics -", gen_ast)
698
734
  else:
699
- self.assertIn("+-- Name - TclError - Type: No", gen_ast)
735
+ self.assertIn("+-- Name - NodeTransformer - Type: No", gen_ast)
700
736
  settings.py_raise = False
701
737
 
702
738
  def test_deep_py_load_imports(self) -> None: # we can get rid of this, isn't?
@@ -772,6 +808,16 @@ class JacLanguageTests(TestCase):
772
808
  self.assertEqual(len(mypass.errors_had), 0)
773
809
  self.assertEqual(len(mypass.warnings_had), 0)
774
810
 
811
+ def test_circle_override1_type_check_pass(self) -> None:
812
+ """Test conn assign on edges."""
813
+ Jac.get_root()._jac_.edges.clear()
814
+ mypass = jac_file_to_pass(
815
+ self.examples_abs_path("manual_code/circle.jac"),
816
+ schedule=py_code_gen_typed,
817
+ )
818
+ self.assertEqual(len(mypass.errors_had), 0)
819
+ self.assertEqual(len(mypass.warnings_had), 0)
820
+
775
821
  def test_self_with_no_sig(self) -> None: # we can get rid of this, isn't?
776
822
  """Test py ast to Jac ast conversion output."""
777
823
  captured_output = io.StringIO()
@@ -849,3 +895,24 @@ class JacLanguageTests(TestCase):
849
895
  sys.stdout = sys.__stdout__
850
896
  stdout_value = captured_output.getvalue()
851
897
  self.assertIn("i work", stdout_value)
898
+
899
+ def test_double_import_exec(self) -> None:
900
+ """Test importing python."""
901
+ captured_output = io.StringIO()
902
+ sys.stdout = captured_output
903
+ jac_import("dblhello", base_path=self.fixture_abs_path("./"))
904
+ sys.stdout = sys.__stdout__
905
+ stdout_value = captured_output.getvalue()
906
+ self.assertEqual(stdout_value.count("Hello World!"), 1)
907
+ self.assertIn("im still here", stdout_value)
908
+
909
+ def test_cls_method(self) -> None:
910
+ """Test class method output."""
911
+ captured_output = io.StringIO()
912
+ sys.stdout = captured_output
913
+ jac_import("cls_method", base_path=self.fixture_abs_path("./"))
914
+ sys.stdout = sys.__stdout__
915
+ stdout_value = captured_output.getvalue().split("\n")
916
+ self.assertEqual("MyClass", stdout_value[0])
917
+ self.assertEqual("Hello, World1! Hello, World2!", stdout_value[1])
918
+ self.assertEqual("Hello, World! Hello, World22!", stdout_value[2])
@@ -53,6 +53,12 @@ class JacReferenceTests(TestCase):
53
53
 
54
54
  def execute_and_capture_output(code: str | bytes, filename: str = "") -> str:
55
55
  Jac.get_root().reset()
56
+ Jac.context().init_memory(
57
+ base_path=os.path.join(
58
+ os.path.dirname(os.path.dirname(jaclang.__file__)),
59
+ "examples/reference",
60
+ )
61
+ )
56
62
  f = io.StringIO()
57
63
  with redirect_stdout(f):
58
64
  exec(
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()
@@ -248,10 +248,6 @@ def _build_symbol_tree_common(
248
248
  symbol_node = SymbolTree(node_name=f"{sym.sym_name}", parent=symbols)
249
249
  SymbolTree(node_name=f"{sym.access} {sym.sym_type}", parent=symbol_node)
250
250
 
251
- # if isinstance(node.owner, ast.AstSymbolNode) and node.owner.sym_info:
252
- # print("From tree printer", id(node.owner))
253
- # SymbolTree(node_name=f"Datatype: {node.owner.sym_info.typ}", parent=symbol_node)
254
-
255
251
  if sym.decl and sym.decl.loc.first_line > 0:
256
252
  SymbolTree(
257
253
  node_name=f"decl: line {sym.decl.loc.first_line}, col {sym.decl.loc.col_start}",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaclang
3
- Version: 0.7.14
3
+ Version: 0.7.16
4
4
  Summary: Jac is a unique and powerful programming language that runs on top of Python, offering an unprecedented level of intelligence and intuitive understanding.
5
5
  Home-page: https://jaseci.org
6
6
  License: MIT
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  [Jac Website] | [Getting started] | [Learn] | [Documentation] | [Contributing]
30
30
 
31
- [![PyPI version](https://img.shields.io/pypi/v/jaclang.svg)](https://pypi.org/project/jaclang/) [![Tests](https://github.com/chandralegend/jaclang/actions/workflows/run_pytest.yml/badge.svg?branch=main)](https://github.com/chandralegend/jaclang/actions/workflows/run_pytest.yml) [![codecov](https://codecov.io/github/chandralegend/jaclang/graph/badge.svg?token=OAX26B0FE4)](https://codecov.io/github/chandralegend/jaclang)
31
+ [![PyPI version](https://img.shields.io/pypi/v/jaclang.svg)](https://pypi.org/project/jaclang/) [![Tests](https://github.com/Jaseci-Labs/jaclang/actions/workflows/run_pytest.yml/badge.svg)](https://github.com/Jaseci-Labs/jaclang/actions/workflows/run_pytest.yml) [![codecov](https://codecov.io/github/chandralegend/jaclang/graph/badge.svg?token=OAX26B0FE4)](https://codecov.io/github/chandralegend/jaclang)
32
32
  </div>
33
33
 
34
34
  This is the main source code repository for the [Jac] programming language. It contains the compiler, language server, and documentation.
@@ -97,3 +97,4 @@ Third-party logos may be subject to third-party copyrights and trademarks. See [
97
97
  [jaseci]: https://jaseci.org/
98
98
  [media-guide]: https://jaseci.org/policies/logo-policy-and-media-guide/
99
99
  [policies-licenses]: https://www.jaseci.org/policies/licenses
100
+