jaclang 0.8.4__py3-none-any.whl → 0.8.6__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 (88) hide show
  1. jaclang/cli/cli.md +1 -0
  2. jaclang/cli/cli.py +109 -37
  3. jaclang/compiler/jac.lark +3 -3
  4. jaclang/compiler/larkparse/jac_parser.py +2 -2
  5. jaclang/compiler/parser.py +14 -21
  6. jaclang/compiler/passes/main/__init__.py +5 -1
  7. jaclang/compiler/passes/main/binder_pass.py +594 -0
  8. jaclang/compiler/passes/main/cfg_build_pass.py +21 -1
  9. jaclang/compiler/passes/main/import_pass.py +8 -256
  10. jaclang/compiler/passes/main/inheritance_pass.py +10 -3
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +92 -77
  12. jaclang/compiler/passes/main/pyast_load_pass.py +24 -13
  13. jaclang/compiler/passes/main/sem_def_match_pass.py +1 -1
  14. jaclang/compiler/passes/main/sym_tab_build_pass.py +4 -0
  15. jaclang/compiler/passes/main/tests/fixtures/M1.jac +3 -0
  16. jaclang/compiler/passes/main/tests/fixtures/cfg_has_var.jac +12 -0
  17. jaclang/compiler/passes/main/tests/fixtures/cfg_if_no_else.jac +11 -0
  18. jaclang/compiler/passes/main/tests/fixtures/cfg_return.jac +9 -0
  19. jaclang/compiler/passes/main/tests/fixtures/checker_imported.jac +2 -0
  20. jaclang/compiler/passes/main/tests/fixtures/checker_importer.jac +6 -0
  21. jaclang/compiler/passes/main/tests/fixtures/data_spatial_types.jac +1 -1
  22. jaclang/compiler/passes/main/tests/fixtures/import_symbol_type_infer.jac +11 -0
  23. jaclang/compiler/passes/main/tests/fixtures/infer_type_assignment.jac +5 -0
  24. jaclang/compiler/passes/main/tests/fixtures/member_access_type_inferred.jac +13 -0
  25. jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +11 -0
  26. jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +47 -0
  27. jaclang/compiler/passes/main/tests/fixtures/type_annotation_assignment.jac +8 -0
  28. jaclang/compiler/passes/main/tests/test_binder_pass.py +111 -0
  29. jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +62 -24
  30. jaclang/compiler/passes/main/tests/test_checker_pass.py +87 -0
  31. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +13 -13
  32. jaclang/compiler/passes/main/tests/test_sem_def_match_pass.py +6 -6
  33. jaclang/compiler/passes/main/type_checker_pass.py +128 -0
  34. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +2 -0
  35. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -0
  36. jaclang/compiler/program.py +32 -11
  37. jaclang/compiler/tests/test_sr_errors.py +32 -0
  38. jaclang/compiler/type_system/__init__.py +1 -0
  39. jaclang/compiler/type_system/type_evaluator.py +421 -0
  40. jaclang/compiler/type_system/type_utils.py +41 -0
  41. jaclang/compiler/type_system/types.py +240 -0
  42. jaclang/compiler/unitree.py +36 -24
  43. jaclang/langserve/dev_engine.jac +645 -0
  44. jaclang/langserve/dev_server.jac +201 -0
  45. jaclang/langserve/engine.jac +24 -5
  46. jaclang/langserve/tests/server_test/test_lang_serve.py +2 -2
  47. jaclang/langserve/tests/test_dev_server.py +80 -0
  48. jaclang/langserve/tests/test_server.py +13 -0
  49. jaclang/runtimelib/builtin.py +28 -39
  50. jaclang/runtimelib/importer.py +34 -63
  51. jaclang/runtimelib/machine.py +48 -64
  52. jaclang/runtimelib/memory.py +23 -5
  53. jaclang/runtimelib/tests/fixtures/savable_object.jac +10 -2
  54. jaclang/runtimelib/utils.py +42 -6
  55. jaclang/tests/fixtures/edge_node_walk.jac +1 -1
  56. jaclang/tests/fixtures/edges_walk.jac +1 -1
  57. jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
  58. jaclang/tests/fixtures/py_run.jac +8 -0
  59. jaclang/tests/fixtures/py_run.py +23 -0
  60. jaclang/tests/fixtures/pyfunc.py +2 -0
  61. jaclang/tests/fixtures/pyfunc_fmt.py +60 -0
  62. jaclang/tests/fixtures/pyfunc_fstr.py +25 -0
  63. jaclang/tests/fixtures/pyfunc_kwesc.py +33 -0
  64. jaclang/tests/fixtures/python_run_test.py +19 -0
  65. jaclang/tests/test_cli.py +107 -0
  66. jaclang/tests/test_language.py +106 -5
  67. jaclang/utils/lang_tools.py +6 -3
  68. jaclang/utils/module_resolver.py +90 -0
  69. jaclang/utils/symtable_test_helpers.py +125 -0
  70. jaclang/utils/test.py +3 -4
  71. jaclang/vendor/interegular/__init__.py +34 -0
  72. jaclang/vendor/interegular/comparator.py +163 -0
  73. jaclang/vendor/interegular/fsm.py +1015 -0
  74. jaclang/vendor/interegular/patterns.py +732 -0
  75. jaclang/vendor/interegular/py.typed +0 -0
  76. jaclang/vendor/interegular/utils/__init__.py +15 -0
  77. jaclang/vendor/interegular/utils/simple_parser.py +165 -0
  78. jaclang/vendor/interegular-0.3.3.dist-info/INSTALLER +1 -0
  79. jaclang/vendor/interegular-0.3.3.dist-info/LICENSE.txt +21 -0
  80. jaclang/vendor/interegular-0.3.3.dist-info/METADATA +64 -0
  81. jaclang/vendor/interegular-0.3.3.dist-info/RECORD +20 -0
  82. jaclang/vendor/interegular-0.3.3.dist-info/REQUESTED +0 -0
  83. jaclang/vendor/interegular-0.3.3.dist-info/WHEEL +5 -0
  84. jaclang/vendor/interegular-0.3.3.dist-info/top_level.txt +1 -0
  85. {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/METADATA +2 -1
  86. {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/RECORD +88 -43
  87. {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/WHEEL +0 -0
  88. {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/entry_points.txt +0 -0
@@ -57,7 +57,6 @@ from jaclang.runtimelib.constructs import (
57
57
  from jaclang.runtimelib.memory import Memory, Shelf, ShelfStorage
58
58
  from jaclang.runtimelib.utils import (
59
59
  all_issubclass,
60
- collect_node_connections,
61
60
  traverse_graph,
62
61
  )
63
62
  from jaclang.utils import infer_language
@@ -266,30 +265,6 @@ class JacAccessValidation:
266
265
  class JacNode:
267
266
  """Jac Node Operations."""
268
267
 
269
- @staticmethod
270
- def node_dot(node: NodeArchetype, dot_file: Optional[str] = None) -> str:
271
- """Generate Dot file for visualizing nodes and edges."""
272
- visited_nodes: set[NodeAnchor] = set()
273
- connections: set[tuple[NodeArchetype, NodeArchetype, str]] = set()
274
- unique_node_id_dict = {}
275
-
276
- collect_node_connections(node.__jac__, visited_nodes, connections)
277
- dot_content = 'digraph {\nnode [style="filled", shape="ellipse", fillcolor="invis", fontcolor="black"];\n'
278
- for idx, i in enumerate([nodes_.archetype for nodes_ in visited_nodes]):
279
- unique_node_id_dict[i] = (i.__class__.__name__, str(idx))
280
- dot_content += f'{idx} [label="{i}"];\n'
281
- dot_content += 'edge [color="gray", style="solid"];\n'
282
-
283
- for pair in list(set(connections)):
284
- dot_content += (
285
- f"{unique_node_id_dict[pair[0]][1]} -> {unique_node_id_dict[pair[1]][1]}"
286
- f' [label="{pair[2]}"];\n'
287
- )
288
- if dot_file:
289
- with open(dot_file, "w") as f:
290
- f.write(dot_content + "}")
291
- return dot_content + "}"
292
-
293
268
  @staticmethod
294
269
  def get_edges(
295
270
  origin: list[NodeArchetype], destination: DataSpatialDestination
@@ -879,6 +854,15 @@ class JacBasics:
879
854
  """Get current execution context."""
880
855
  return JacMachine.exec_ctx
881
856
 
857
+ @staticmethod
858
+ def commit(anchor: Anchor | Archetype | None = None) -> None:
859
+ """Commit all data from memory to datasource."""
860
+ if isinstance(anchor, Archetype):
861
+ anchor = anchor.__jac__
862
+
863
+ mem = JacMachineInterface.get_context().mem
864
+ mem.commit(anchor)
865
+
882
866
  @staticmethod
883
867
  def reset_graph(root: Optional[Root] = None) -> int:
884
868
  """Purge current or target graph."""
@@ -987,6 +971,7 @@ class JacBasics:
987
971
  override_name: Optional[str] = None,
988
972
  items: Optional[dict[str, Union[str, Optional[str]]]] = None,
989
973
  reload_module: Optional[bool] = False,
974
+ lng: Optional[str] = None,
990
975
  ) -> tuple[types.ModuleType, ...]:
991
976
  """Core Import Process."""
992
977
  from jaclang.runtimelib.importer import (
@@ -995,7 +980,8 @@ class JacBasics:
995
980
  PythonImporter,
996
981
  )
997
982
 
998
- lng = infer_language(target, base_path)
983
+ if lng is None:
984
+ lng = infer_language(target, base_path)
999
985
 
1000
986
  spec = ImportPathSpec(
1001
987
  target,
@@ -1358,12 +1344,10 @@ class JacBasics:
1358
1344
  return decorator
1359
1345
 
1360
1346
  @staticmethod
1361
- def call_llm(
1362
- model: object, caller: Callable, args: dict[str | int, object]
1363
- ) -> Any: # noqa: ANN401
1347
+ def call_llm(model: object, mtir: object) -> Any: # noqa: ANN401
1364
1348
  """Call the LLM model."""
1365
1349
  raise ImportError(
1366
- "mtllm is not installed. Please install it with `pip install mtllm` and run `jac clean`."
1350
+ "byLLM is not installed. Please install it with `pip install byllm` and run `jac clean`."
1367
1351
  )
1368
1352
 
1369
1353
 
@@ -1587,40 +1571,6 @@ class JacMachineInterface(
1587
1571
  """Jac Feature."""
1588
1572
 
1589
1573
 
1590
- class JacMachine(JacMachineInterface):
1591
- """Jac Machine State."""
1592
-
1593
- loaded_modules: dict[str, types.ModuleType] = {}
1594
- base_path_dir: str = os.getcwd()
1595
- program: JacProgram = JacProgram()
1596
- pool: ThreadPoolExecutor = ThreadPoolExecutor()
1597
- exec_ctx: ExecutionContext = ExecutionContext()
1598
-
1599
- @staticmethod
1600
- def set_base_path(base_path: str) -> None:
1601
- """Set the base path for the machine."""
1602
- JacMachine.reset_machine()
1603
- JacMachine.base_path_dir = (
1604
- base_path if os.path.isdir(base_path) else os.path.dirname(base_path)
1605
- )
1606
-
1607
- @staticmethod
1608
- def set_context(context: ExecutionContext) -> None:
1609
- """Set the context for the machine."""
1610
- JacMachine.exec_ctx = context
1611
-
1612
- @staticmethod
1613
- def reset_machine() -> None:
1614
- """Reset the machine."""
1615
- # for i in JacMachine.loaded_modules.values():
1616
- # sys.modules.pop(i.__name__, None)
1617
- JacMachine.loaded_modules.clear()
1618
- JacMachine.base_path_dir = os.getcwd()
1619
- JacMachine.program = JacProgram()
1620
- JacMachine.pool = ThreadPoolExecutor()
1621
- JacMachine.exec_ctx = ExecutionContext()
1622
-
1623
-
1624
1574
  def generate_plugin_helpers(
1625
1575
  plugin_class: Type[Any],
1626
1576
  ) -> tuple[Type[Any], Type[Any], Type[Any]]:
@@ -1726,3 +1676,37 @@ def generate_plugin_helpers(
1726
1676
 
1727
1677
  JacMachineSpec, JacMachineImpl, JacMachineInterface = generate_plugin_helpers(JacMachineInterface) # type: ignore[misc]
1728
1678
  plugin_manager.add_hookspecs(JacMachineSpec)
1679
+
1680
+
1681
+ class JacMachine(JacMachineInterface):
1682
+ """Jac Machine State."""
1683
+
1684
+ loaded_modules: dict[str, types.ModuleType] = {}
1685
+ base_path_dir: str = os.getcwd()
1686
+ program: JacProgram = JacProgram()
1687
+ pool: ThreadPoolExecutor = ThreadPoolExecutor()
1688
+ exec_ctx: ExecutionContext = ExecutionContext()
1689
+
1690
+ @staticmethod
1691
+ def set_base_path(base_path: str) -> None:
1692
+ """Set the base path for the machine."""
1693
+ JacMachine.reset_machine()
1694
+ JacMachine.base_path_dir = (
1695
+ base_path if os.path.isdir(base_path) else os.path.dirname(base_path)
1696
+ )
1697
+
1698
+ @staticmethod
1699
+ def set_context(context: ExecutionContext) -> None:
1700
+ """Set the context for the machine."""
1701
+ JacMachine.exec_ctx = context
1702
+
1703
+ @staticmethod
1704
+ def reset_machine() -> None:
1705
+ """Reset the machine."""
1706
+ # for i in JacMachine.loaded_modules.values():
1707
+ # sys.modules.pop(i.__name__, None)
1708
+ JacMachine.loaded_modules.clear()
1709
+ JacMachine.base_path_dir = os.getcwd()
1710
+ JacMachine.program = JacProgram()
1711
+ JacMachine.pool = ThreadPoolExecutor()
1712
+ JacMachine.exec_ctx = ExecutionContext()
@@ -82,6 +82,9 @@ class Memory(Generic[ID, TANCH]):
82
82
  if anchor := self.__mem__.pop(id, None):
83
83
  self.__gc__.add(anchor)
84
84
 
85
+ def commit(self, anchor: TANCH | None = None) -> None:
86
+ """Commit all data from memory to datasource."""
87
+
85
88
 
86
89
  @dataclass
87
90
  class ShelfStorage(Memory[UUID, Anchor]):
@@ -94,12 +97,21 @@ class ShelfStorage(Memory[UUID, Anchor]):
94
97
  super().__init__()
95
98
  self.__shelf__ = open(session) if session else None # noqa: SIM115
96
99
 
97
- def close(self) -> None:
98
- """Close memory handler."""
100
+ def commit(self, anchor: Anchor | None = None) -> None:
101
+ """Commit all data from memory to datasource."""
99
102
  if isinstance(self.__shelf__, Shelf):
100
- for anchor in self.__gc__:
101
- self.__shelf__.pop(str(anchor.id), None)
102
- self.__mem__.pop(anchor.id, None)
103
+ if anchor:
104
+ if anchor in self.__gc__:
105
+ self.__shelf__.pop(str(anchor.id), None)
106
+ self.__mem__.pop(anchor.id, None)
107
+ self.__gc__.remove(anchor)
108
+ else:
109
+ self.sync_mem_to_db([anchor.id])
110
+ return
111
+
112
+ for anc in self.__gc__:
113
+ self.__shelf__.pop(str(anc.id), None)
114
+ self.__mem__.pop(anc.id, None)
103
115
 
104
116
  keys = set(self.__mem__.keys())
105
117
 
@@ -109,7 +121,13 @@ class ShelfStorage(Memory[UUID, Anchor]):
109
121
  # additional after memory sync
110
122
  self.sync_mem_to_db(set(self.__mem__.keys() - keys))
111
123
 
124
+ def close(self) -> None:
125
+ """Close memory handler."""
126
+ self.commit()
127
+
128
+ if isinstance(self.__shelf__, Shelf):
112
129
  self.__shelf__.close()
130
+
113
131
  super().close()
114
132
 
115
133
  def sync_mem_to_db(self, keys: Iterable[UUID]) -> None:
@@ -18,7 +18,7 @@ obj SavableObject {
18
18
 
19
19
  walker create_custom_object {
20
20
  can enter1 with `root entry {
21
- o = SavableObject(
21
+ self.obj = SavableObject(
22
22
  val=0,
23
23
  arr=[],
24
24
  json={},
@@ -36,7 +36,15 @@ walker create_custom_object {
36
36
  ),
37
37
  enum_field = Enum.A
38
38
  );
39
- _.save(o);
39
+ save(self.obj);
40
+
41
+ # commit the object to db
42
+ commit(self.obj);
43
+ }
44
+
45
+ can exit1 with `root exit {
46
+ # get directly from shelf
47
+ o = _.get_context().mem.__shelf__.get(str(self.obj.__jac__.id)).archetype;
40
48
  print(jid(o));
41
49
  print(o);
42
50
  }
@@ -11,7 +11,36 @@ from typing import Callable, Iterator, TYPE_CHECKING
11
11
  import jaclang.compiler.unitree as uni
12
12
 
13
13
  if TYPE_CHECKING:
14
- from jaclang.runtimelib.constructs import NodeAnchor, NodeArchetype
14
+ from jaclang.runtimelib.constructs import NodeArchetype
15
+
16
+
17
+ def read_file_with_encoding(file_path: str) -> str:
18
+ """Read file with proper encoding detection."""
19
+ encodings_to_try = [
20
+ "utf-8-sig",
21
+ "utf-8",
22
+ "utf-16",
23
+ "utf-16le",
24
+ "utf-16be",
25
+ # "latin-1", # TODO: Support reading files with Latin-1 encoding
26
+ ]
27
+
28
+ for encoding in encodings_to_try:
29
+ try:
30
+ with open(file_path, "r", encoding=encoding) as f:
31
+ return f.read()
32
+ except UnicodeError:
33
+ continue
34
+ except Exception as e:
35
+ raise IOError(
36
+ f"Could not read file {file_path}: {e}. "
37
+ f"Report this issue: https://github.com/jaseci-labs/jaseci/issues"
38
+ ) from e
39
+
40
+ raise IOError(
41
+ f"Could not read file {file_path} with any encoding. "
42
+ f"Report this issue: https://github.com/jaseci-labs/jaseci/issues"
43
+ )
15
44
 
16
45
 
17
46
  @contextmanager
@@ -28,25 +57,32 @@ def sys_path_context(path: str) -> Iterator[None]:
28
57
 
29
58
 
30
59
  def collect_node_connections(
31
- current_node: NodeAnchor,
60
+ current_node: NodeArchetype,
32
61
  visited_nodes: set,
33
62
  connections: set,
63
+ edge_ids: set,
34
64
  ) -> None:
35
65
  """Nodes and edges representing the graph are collected in visited_nodes and connections."""
36
66
  if current_node not in visited_nodes:
37
67
  visited_nodes.add(current_node)
38
- edges = current_node.edges
68
+ edges = current_node.__jac__.edges
39
69
  for edge_ in edges:
70
+ if edge_.id in edge_ids:
71
+ continue
72
+ edge_ids.add(edge_.id)
40
73
  target = edge_.target
41
74
  if target:
42
75
  connections.add(
43
76
  (
44
- current_node.archetype,
77
+ edge_.id,
78
+ edge_.source.archetype,
45
79
  target.archetype,
46
- edge_.__class__.__name__,
80
+ edge_.archetype,
47
81
  )
48
82
  )
49
- collect_node_connections(target, visited_nodes, connections)
83
+ collect_node_connections(
84
+ target.archetype, visited_nodes, connections, edge_ids
85
+ )
50
86
 
51
87
 
52
88
  def traverse_graph(
@@ -37,7 +37,7 @@ impl creator.create {
37
37
 
38
38
  with entry {
39
39
  print(root spawn creator());
40
- print(_.node_dot(root));
40
+ print(printgraph(root));
41
41
  print([root->:Edge_a:->]);
42
42
  print([root->:Edge_c:->]);
43
43
  print([root->:Edge_a:->->:Edge_b:->]);
@@ -30,7 +30,7 @@ impl creator.create{
30
30
 
31
31
  with entry{
32
32
  print(root spawn creator());
33
- print(_.node_dot(root));
33
+ print(printgraph(root));
34
34
  print([root ->:Edge_a:->]);
35
35
  print([root ->:Edge_c:->]);
36
36
  print([root ->:Edge_a:-> ->:Edge_b:->]);
@@ -73,5 +73,5 @@ with entry {
73
73
  root spawn walker1();
74
74
  root spawn walker2();
75
75
  root spawn walker3();
76
- print(_.node_dot(root));
76
+ print(printgraph(root));
77
77
  }
@@ -0,0 +1,8 @@
1
+ with entry {
2
+ print('Hello, Jaseci');
3
+ a = 10;
4
+ b = 15;
5
+ sum_ab = (a + b);
6
+ print('Sum:', sum_ab);
7
+ }
8
+
@@ -0,0 +1,23 @@
1
+ # Print Hello, World!
2
+ print("Hello, World!")
3
+
4
+ a = 5
5
+ b = 3
6
+ sum_ab = a + b
7
+ print("Sum:", sum_ab)
8
+
9
+ num = 7
10
+ if num % 2 == 0:
11
+ print(num, "is even")
12
+ else:
13
+ print(num, "is odd")
14
+
15
+ # Loop through a list
16
+ fruits = ["apple", "banana", "cherry"]
17
+ for fruit in fruits:
18
+ print(fruit)
19
+
20
+ def greet(name):
21
+ return f"Hello, {name}!"
22
+
23
+ print(greet("Alice"))
@@ -4,6 +4,8 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
+ class MyClass:
8
+ pass
7
9
 
8
10
  def my_print(x: object) -> None:
9
11
  """Print function."""
@@ -0,0 +1,60 @@
1
+
2
+
3
+
4
+
5
+ if __name__ == "__main__":
6
+
7
+ def foo():
8
+ print("One")
9
+ return "foo"
10
+ foo()
11
+
12
+ condition = True
13
+
14
+ if condition:
15
+
16
+ print("Two")
17
+
18
+ def bar():
19
+ return
20
+
21
+ main_mod = None
22
+ bar()
23
+
24
+ def baz():
25
+ print("Three")
26
+ return "baz"
27
+
28
+ print(baz())
29
+
30
+
31
+ try:
32
+ a = 90
33
+ except FileNotFoundError:
34
+ pass
35
+
36
+
37
+ condition = 10
38
+
39
+
40
+ while condition:
41
+ print("Processing...")
42
+
43
+ while condition:
44
+ print("Four")
45
+ condition -= 10
46
+ break
47
+
48
+ if condition:
49
+
50
+ def foo():
51
+ return
52
+ foo()
53
+ print("Exiting the loop.")
54
+
55
+ if condition:
56
+ print("still +")
57
+ def foo():
58
+ return
59
+
60
+ print("The End.")
@@ -0,0 +1,25 @@
1
+
2
+
3
+
4
+
5
+
6
+ name = 'Peter'
7
+ relation = 'mother'
8
+ mom_name = 'Mary'
9
+
10
+
11
+ print(f"Hello {name}")
12
+ print(f"Hello {name} {name}")
13
+ print(f"{name} squared is {name} {name}")
14
+
15
+
16
+ print(f"{name.upper()}! wrong poem.")
17
+ print(f"Hello {name} , yoo {relation} is {mom_name}. Myself, I am {name}.")
18
+
19
+
20
+
21
+ item = "Apple"
22
+ price = 1.23
23
+
24
+ print(f"Left aligned: {item:<10} | Price: {price:.2f}")
25
+ print(f"{name = } 🤔")
@@ -0,0 +1,33 @@
1
+
2
+
3
+
4
+ def foo(type= 90):
5
+ """This is a function with a docstring."""
6
+ return type
7
+
8
+ print(foo(type=89))
9
+
10
+ def bar(node= 12, *args,**kwargs):
11
+ """This is another function with a docstring."""
12
+ return node, args, kwargs
13
+
14
+ print(str(bar(node=13, a=1, b=2)))
15
+
16
+
17
+ functions = [
18
+
19
+ dict(
20
+ name="replace_lines",
21
+ args=[
22
+ dict(name="text", type="str", default=None),
23
+ dict(name="old", type="str", default=None),
24
+ dict(name="new", type="str", default=None),
25
+ ],
26
+ returns=dict(type="str", default=None),
27
+ ),
28
+ ]
29
+
30
+ print(f"Functions: {functions}")
31
+
32
+ dict = 90
33
+ print(f"Dict: {dict}")
@@ -0,0 +1,19 @@
1
+ """Simple Python test file for jac run command."""
2
+
3
+ print("Hello from Python!")
4
+ print("This is a test Python file.")
5
+
6
+ def main():
7
+ """Main function to demonstrate execution."""
8
+ result = 42
9
+ print(f"Result: {result}")
10
+ return result
11
+
12
+ if __name__ == "__main__":
13
+ main()
14
+ print("Python execution completed.")
15
+
16
+
17
+ from jaclang.tests.fixtures import py_namedexpr
18
+
19
+ py_namedexpr.walrus_example()
jaclang/tests/test_cli.py CHANGED
@@ -35,6 +35,73 @@ class JacCliTests(TestCase):
35
35
 
36
36
  self.assertIn("Hello World!", stdout_value)
37
37
 
38
+ def test_jac_cli_run_python_file(self) -> None:
39
+ """Test running Python files with jac run command."""
40
+ captured_output = io.StringIO()
41
+ sys.stdout = captured_output
42
+
43
+ cli.run(self.fixture_abs_path("python_run_test.py"))
44
+
45
+ sys.stdout = sys.__stdout__
46
+ stdout_value = captured_output.getvalue()
47
+
48
+ self.assertIn("Hello from Python!", stdout_value)
49
+ self.assertIn("This is a test Python file.", stdout_value)
50
+ self.assertIn("Result: 42", stdout_value)
51
+ self.assertIn("Python execution completed.", stdout_value)
52
+ self.assertIn("10", stdout_value)
53
+
54
+ def test_jac_run_py_fstr(self) -> None:
55
+ """Test running Python files with jac run command."""
56
+ captured_output = io.StringIO()
57
+ sys.stdout = captured_output
58
+
59
+ cli.run(self.fixture_abs_path("pyfunc_fstr.py"))
60
+
61
+ sys.stdout = sys.__stdout__
62
+ stdout_value = captured_output.getvalue()
63
+
64
+ self.assertIn("Hello Peter", stdout_value)
65
+ self.assertIn("Hello Peter Peter", stdout_value)
66
+ self.assertIn("Peter squared is Peter Peter", stdout_value)
67
+ self.assertIn("PETER! wrong poem", stdout_value)
68
+ self.assertIn("Hello Peter , yoo mother is Mary. Myself, I am Peter.", stdout_value)
69
+ self.assertIn("Left aligned: Apple | Price: 1.23", stdout_value)
70
+ self.assertIn("name = Peter 🤔", stdout_value)
71
+
72
+ def test_jac_run_py_fmt(self) -> None:
73
+ """Test running Python files with jac run command."""
74
+ captured_output = io.StringIO()
75
+ sys.stdout = captured_output
76
+
77
+ cli.run(self.fixture_abs_path("pyfunc_fmt.py"))
78
+
79
+ sys.stdout = sys.__stdout__
80
+ stdout_value = captured_output.getvalue()
81
+
82
+ self.assertIn("One", stdout_value)
83
+ self.assertIn("Two", stdout_value)
84
+ self.assertIn("Three", stdout_value)
85
+ self.assertIn("baz", stdout_value)
86
+ self.assertIn("Processing...", stdout_value)
87
+ self.assertIn("Four", stdout_value)
88
+ self.assertIn("The End.", stdout_value)
89
+
90
+ def test_jac_run_pyfunc_kwesc(self) -> None:
91
+ """Test running Python files with jac run command."""
92
+ captured_output = io.StringIO()
93
+ sys.stdout = captured_output
94
+
95
+ cli.run(self.fixture_abs_path("pyfunc_kwesc.py"))
96
+
97
+ sys.stdout = sys.__stdout__
98
+ stdout_value = captured_output.getvalue()
99
+ out = stdout_value.split("\n")
100
+ self.assertIn("89", out[0])
101
+ self.assertIn("(13, (), {'a': 1, 'b': 2})", out[1])
102
+ self.assertIn("Functions: [{'name': 'replace_lines'", out[2])
103
+ self.assertIn("Dict: 90", out[3])
104
+
38
105
  def test_jac_cli_alert_based_err(self) -> None:
39
106
  """Basic test for pass."""
40
107
  captured_output = io.StringIO()
@@ -203,6 +270,27 @@ class JacCliTests(TestCase):
203
270
  '[label="MultiString" shape="oval" style="filled" fillcolor="#fccca4"]',
204
271
  stdout_value,
205
272
  )
273
+
274
+ def test_cfg_printgraph(self) -> None:
275
+ """Testing for print CFG."""
276
+ captured_output = io.StringIO()
277
+ sys.stdout = captured_output
278
+
279
+ cli.tool("ir", ["cfg.", f"{self.fixture_abs_path('hello.jac')}"])
280
+
281
+ sys.stdout = sys.__stdout__
282
+ stdout_value = captured_output.getvalue()
283
+ correct_graph = (
284
+ "digraph G {\n"
285
+ ' 0 [label="BB0\\n\\nprint ( \\"im still here\\" ) ;\", shape=box];\n'
286
+ ' 1 [label="BB1\\n\\"Hello World!\\" |> print ;\", shape=box];\n'
287
+ "}\n\n"
288
+ )
289
+
290
+ self.assertEqual(
291
+ correct_graph,
292
+ stdout_value,
293
+ )
206
294
 
207
295
  def test_del_clean(self) -> None:
208
296
  """Testing for print AstTool."""
@@ -324,6 +412,8 @@ class JacCliTests(TestCase):
324
412
  sys.stdout = sys.__stdout__
325
413
  stdout_value = captured_output.getvalue()
326
414
  self.assertIn("def my_print(x: object) -> None", stdout_value)
415
+ self.assertIn("class MyClass {", stdout_value)
416
+ self.assertIn('"""Print function."""', stdout_value)
327
417
 
328
418
  def test_caching_issue(self) -> None:
329
419
  """Test for Caching Issue."""
@@ -453,3 +543,20 @@ class JacCliTests(TestCase):
453
543
  description_pattern,
454
544
  f"Parameter description for '{param_name}' not found in help text for '{cmd_name}'",
455
545
  )
546
+
547
+ def test_run_jac_name_py(self) -> None:
548
+ """Test a specific test case."""
549
+ process = subprocess.Popen(
550
+ [
551
+ "jac",
552
+ "run",
553
+ self.fixture_abs_path("py_run.py"),
554
+ ],
555
+ stdin=subprocess.PIPE,
556
+ stdout=subprocess.PIPE,
557
+ stderr=subprocess.PIPE,
558
+ text=True,
559
+ )
560
+ stdout, stderr = process.communicate()
561
+ self.assertIn("Hello, World!", stdout)
562
+ self.assertIn("Sum: 8", stdout)