jaclang 0.7.14__py3-none-any.whl → 0.7.15__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 (43) hide show
  1. jaclang/cli/cli.py +11 -8
  2. jaclang/cli/cmdreg.py +9 -12
  3. jaclang/compiler/__init__.py +0 -2
  4. jaclang/compiler/absyntree.py +3 -8
  5. jaclang/compiler/passes/ir_pass.py +3 -12
  6. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +4 -5
  7. jaclang/compiler/passes/main/import_pass.py +4 -2
  8. jaclang/compiler/passes/main/pyast_gen_pass.py +32 -31
  9. jaclang/compiler/passes/main/registry_pass.py +1 -1
  10. jaclang/compiler/passes/tool/jac_formatter_pass.py +3 -20
  11. jaclang/compiler/passes/transform.py +4 -0
  12. jaclang/compiler/semtable.py +5 -3
  13. jaclang/compiler/tests/test_importer.py +3 -0
  14. jaclang/langserve/engine.py +210 -69
  15. jaclang/langserve/server.py +6 -10
  16. jaclang/langserve/tests/fixtures/base_module_structure.jac +1 -1
  17. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  18. jaclang/langserve/tests/test_sem_tokens.py +277 -0
  19. jaclang/langserve/tests/test_server.py +4 -4
  20. jaclang/langserve/utils.py +128 -95
  21. jaclang/plugin/builtin.py +1 -1
  22. jaclang/plugin/default.py +23 -16
  23. jaclang/plugin/feature.py +4 -5
  24. jaclang/plugin/spec.py +2 -2
  25. jaclang/{core → runtimelib}/architype.py +1 -1
  26. jaclang/{core → runtimelib}/context.py +4 -1
  27. jaclang/runtimelib/importer.py +414 -0
  28. jaclang/runtimelib/machine.py +19 -0
  29. jaclang/{core → runtimelib}/utils.py +1 -1
  30. jaclang/tests/fixtures/deep/one_lev.jac +3 -3
  31. jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
  32. jaclang/tests/test_cli.py +1 -1
  33. jaclang/tests/test_language.py +7 -0
  34. jaclang/utils/treeprinter.py +0 -4
  35. {jaclang-0.7.14.dist-info → jaclang-0.7.15.dist-info}/METADATA +1 -1
  36. {jaclang-0.7.14.dist-info → jaclang-0.7.15.dist-info}/RECORD +42 -40
  37. jaclang/core/importer.py +0 -344
  38. /jaclang/{core → runtimelib}/__init__.py +0 -0
  39. /jaclang/{core → runtimelib}/constructs.py +0 -0
  40. /jaclang/{core → runtimelib}/memory.py +0 -0
  41. /jaclang/{core → runtimelib}/test.py +0 -0
  42. {jaclang-0.7.14.dist-info → jaclang-0.7.15.dist-info}/WHEEL +0 -0
  43. {jaclang-0.7.14.dist-info → jaclang-0.7.15.dist-info}/entry_points.txt +0 -0
jaclang/cli/cli.py CHANGED
@@ -19,10 +19,10 @@ from jaclang.compiler.constant import Constants
19
19
  from jaclang.compiler.passes.main.pyast_load_pass import PyastBuildPass
20
20
  from jaclang.compiler.passes.main.schedules import py_code_gen_typed
21
21
  from jaclang.compiler.passes.tool.schedules import format_pass
22
- from jaclang.core.constructs import Architype
23
22
  from jaclang.plugin.builtin import dotgen
24
23
  from jaclang.plugin.feature import JacCmd as Cmd
25
24
  from jaclang.plugin.feature import JacFeature as Jac
25
+ from jaclang.runtimelib.constructs import Architype
26
26
  from jaclang.utils.helpers import debugger as db
27
27
  from jaclang.utils.lang_tools import AstTool
28
28
 
@@ -86,11 +86,10 @@ def run(
86
86
  else ""
87
87
  )
88
88
 
89
- Jac.context().init_memory(session)
90
-
91
89
  base, mod = os.path.split(filename)
92
90
  base = base if base else "./"
93
91
  mod = mod[:-4]
92
+ Jac.context().init_memory(base_path=base, session=session)
94
93
  if filename.endswith(".jac"):
95
94
  ret_module = jac_import(
96
95
  target=mod,
@@ -146,7 +145,7 @@ def get_object(id: str, session: str = "") -> dict:
146
145
  if session == "":
147
146
  session = cmd_registry.args.session if "session" in cmd_registry.args else ""
148
147
 
149
- Jac.context().init_memory(session)
148
+ Jac.context().init_memory(session=session)
150
149
 
151
150
  if id == "root":
152
151
  id_uuid = UUID(int=0)
@@ -357,11 +356,10 @@ def dot(
357
356
  else ""
358
357
  )
359
358
 
360
- Jac.context().init_memory(session)
361
-
362
359
  base, mod = os.path.split(filename)
363
360
  base = base if base else "./"
364
361
  mod = mod[:-4]
362
+ Jac.context().init_memory(base_path=base, session=session)
365
363
  if filename.endswith(".jac"):
366
364
  jac_import(
367
365
  target=mod,
@@ -437,12 +435,17 @@ def start_cli() -> None:
437
435
  parser = cmd_registry.parser
438
436
  args = parser.parse_args()
439
437
  cmd_registry.args = args
438
+
439
+ if args.version:
440
+ version = importlib.metadata.version("jaclang")
441
+ print(f"Jac version {version}")
442
+ return
443
+
440
444
  command = cmd_registry.get(args.command)
441
445
  if command:
442
446
  args_dict = vars(args)
443
447
  args_dict.pop("command")
444
- if command not in ["run"]:
445
- args_dict.pop("session")
448
+ args_dict.pop("version", None)
446
449
  ret = command.call(**args_dict)
447
450
  if ret:
448
451
  print(ret)
jaclang/cli/cmdreg.py CHANGED
@@ -38,7 +38,7 @@ class CommandRegistry:
38
38
  self.registry = {}
39
39
  self.parser = argparse.ArgumentParser(prog="jac")
40
40
  self.parser.add_argument(
41
- "--session", help="Session file path", nargs="?", default=""
41
+ "-V", "--version", action="store_true", help="Show the Jac version"
42
42
  )
43
43
  self.sub_parsers = self.parser.add_subparsers(title="commands", dest="command")
44
44
  self.args = argparse.Namespace()
@@ -172,17 +172,14 @@ class CommandShell(cmd.Cmd):
172
172
 
173
173
  def default(self, line: str) -> None:
174
174
  """Process the command line input."""
175
- try:
176
- args = vars(self.cmd_reg.parser.parse_args(line.split()))
177
- command = self.cmd_reg.get(args["command"])
178
- if command:
179
- args.pop("command")
180
- ret = command.call(**args)
181
- if ret:
182
- ret_str = pprint.pformat(ret, indent=2)
183
- self.stdout.write(f"{ret_str}\n")
184
- except Exception as e:
185
- print(e)
175
+ args = vars(self.cmd_reg.parser.parse_args(line.split()))
176
+ command = self.cmd_reg.get(args["command"])
177
+ if command:
178
+ args.pop("command")
179
+ ret = command.call(**args)
180
+ if ret:
181
+ ret_str = pprint.pformat(ret, indent=2)
182
+ self.stdout.write(f"{ret_str}\n")
186
183
 
187
184
  def do_help(self, arg: str) -> None:
188
185
  """Jac CLI 'help' implementaion."""
@@ -34,8 +34,6 @@ def generate_static_parser(force: bool = False) -> None:
34
34
  except Exception as e:
35
35
  logging.error(f"Error generating reference files: {e}")
36
36
 
37
-
38
- generate_static_parser()
39
37
  try:
40
38
  from jaclang.compiler.generated import jac_parser as jac_lark
41
39
  except ModuleNotFoundError:
@@ -55,15 +55,10 @@ class AstNode:
55
55
  """Get symbol table."""
56
56
  # sym_tab should never be accessed without being set in codebase
57
57
  if not self._sym_tab:
58
- import traceback
59
-
60
- if self.parent:
61
- print(f"Parent: {self.parent.pp()}")
62
- print("Node: ", self.pp())
63
- stack_trace = traceback.format_stack()
64
- print("".join(stack_trace))
65
58
  raise ValueError(
66
- f"Symbol table not set for {type(self).__name__}. Impossible."
59
+ f"Symbol table not set for {type(self).__name__}. Impossible.\n"
60
+ f"Node: {self.pp()}\n"
61
+ f"Parent: {self.parent.pp() if self.parent else None}\n"
67
62
  )
68
63
  return self._sym_tab
69
64
 
@@ -115,7 +115,7 @@ class Pass(Transform[T]):
115
115
  self.after_pass()
116
116
  self.time_taken = time.time() - start_time
117
117
  if settings.pass_timer:
118
- print(
118
+ self.log_info(
119
119
  f"Time taken in {self.__class__.__name__}: {self.time_taken:.4f} seconds"
120
120
  )
121
121
  return self.ir
@@ -136,21 +136,12 @@ class Pass(Transform[T]):
136
136
  self.exit_node(node)
137
137
  return node
138
138
 
139
- def update_code_loc(self, node: Optional[ast.AstNode] = None) -> None:
140
- """Update code location."""
141
- if node is None:
142
- node = self.cur_node
143
- if not isinstance(node, ast.AstNode):
144
- self.ice("Current node is not an AstNode.")
145
-
146
139
  def error(self, msg: str, node_override: Optional[ast.AstNode] = None) -> None:
147
140
  """Pass Error."""
148
- self.update_code_loc(node_override)
149
141
  self.log_error(f"{msg}", node_override=node_override)
150
142
 
151
143
  def warning(self, msg: str, node_override: Optional[ast.AstNode] = None) -> None:
152
144
  """Pass Error."""
153
- self.update_code_loc(node_override)
154
145
  self.log_warning(f"{msg}", node_override=node_override)
155
146
 
156
147
  def ice(self, msg: str = "Something went horribly wrong!") -> RuntimeError:
@@ -166,10 +157,10 @@ class PrinterPass(Pass):
166
157
 
167
158
  def enter_node(self, node: ast.AstNode) -> None:
168
159
  """Run on entering node."""
169
- print("Entering:", node)
160
+ self.log_info(f"Entering: {node.__class__.__name__}: {node.loc}")
170
161
  super().enter_node(node)
171
162
 
172
163
  def exit_node(self, node: ast.AstNode) -> None:
173
164
  """Run on exiting node."""
174
165
  super().exit_node(node)
175
- print("Exiting:", node)
166
+ self.log_info(f"Exiting: {node.__class__.__name__}: {node.loc}")
@@ -6,7 +6,6 @@ mypy apis into Jac and use jac py ast in it.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- import traceback
10
9
  from typing import Callable, TypeVar
11
10
 
12
11
  import jaclang.compiler.absyntree as ast
@@ -32,7 +31,7 @@ class FuseTypeInfoPass(Pass):
32
31
 
33
32
  def __debug_print(self, *argv: object) -> None:
34
33
  if settings.fuse_type_info_debug:
35
- print("FuseTypeInfo::", *argv)
34
+ self.log_info("FuseTypeInfo::", *argv)
36
35
 
37
36
  def __call_type_handler(
38
37
  self, node: ast.AstSymbolNode, mypy_type: MypyTypes.ProperType
@@ -72,7 +71,9 @@ class FuseTypeInfoPass(Pass):
72
71
  ) -> Callable[[FuseTypeInfoPass, T], None]:
73
72
  def node_handler(self: FuseTypeInfoPass, node: T) -> None:
74
73
  if not isinstance(node, ast.AstSymbolNode):
75
- print(f"Warning {node.__class__.__name__} is not an AstSymbolNode")
74
+ self.__debug_print(
75
+ f"Warning {node.__class__.__name__} is not an AstSymbolNode"
76
+ )
76
77
 
77
78
  try:
78
79
  jac_node_str = f'jac node "{node.loc}::{node.__class__.__name__}'
@@ -119,8 +120,6 @@ class FuseTypeInfoPass(Pass):
119
120
  self.__debug_print(
120
121
  f'Internal error happened while parsing "{e.obj.__class__.__name__}"'
121
122
  )
122
- traceback.print_exc()
123
- print(e)
124
123
 
125
124
  return node_handler
126
125
 
@@ -17,6 +17,9 @@ from jaclang.compiler.passes import Pass
17
17
  from jaclang.compiler.passes.main import SubNodeTabPass
18
18
  from jaclang.settings import settings
19
19
  from jaclang.utils.helpers import import_target_to_relative_path, is_standard_lib_module
20
+ from jaclang.utils.log import logging
21
+
22
+ logger = logging.getLogger(__name__)
20
23
 
21
24
 
22
25
  class JacImportPass(Pass):
@@ -204,7 +207,7 @@ class JacImportPass(Pass):
204
207
  self.warnings_had += mod_pass.warnings_had
205
208
  mod = mod_pass.ir
206
209
  except Exception as e:
207
- print(e)
210
+ logger.info(e)
208
211
  mod = None
209
212
  if isinstance(mod, ast.Module):
210
213
  self.import_table[target] = mod
@@ -252,7 +255,6 @@ class PyImportPass(JacImportPass):
252
255
  if spec.origin in self.import_table:
253
256
  return self.import_table[spec.origin]
254
257
  with open(spec.origin, "r", encoding="utf-8") as f:
255
- # print(f"\nImporting python module {node.path_str}")
256
258
  mod = PyastBuildPass(
257
259
  input_ir=ast.PythonModuleAst(
258
260
  py_ast.parse(f.read()), mod_path=spec.origin
@@ -11,7 +11,7 @@ from typing import Optional, Sequence, TypeVar
11
11
  import jaclang.compiler.absyntree as ast
12
12
  from jaclang.compiler.constant import Constants as Con, EdgeDir, Tokens as Tok
13
13
  from jaclang.compiler.passes import Pass
14
- from jaclang.core.utils import extract_params, extract_type, get_sem_scope
14
+ from jaclang.runtimelib.utils import extract_params, extract_type, get_sem_scope
15
15
 
16
16
  T = TypeVar("T", bound=ast3.AST)
17
17
 
@@ -19,24 +19,25 @@ T = TypeVar("T", bound=ast3.AST)
19
19
  class PyastGenPass(Pass):
20
20
  """Jac blue transpilation to python pass."""
21
21
 
22
- @staticmethod
23
- def node_compilable_test(node: ast3.AST) -> None:
24
- """Convert any AST node to a compilable module node."""
25
- if isinstance(node, ast3.Module):
26
- pass
27
- elif isinstance(node, (ast3.Expr, ast3.stmt)):
28
- node = ast3.Module(body=[node], type_ignores=[])
29
- elif isinstance(node, list) and all(isinstance(n, ast3.stmt) for n in node):
30
- node = ast3.Module(body=node, type_ignores=[])
31
- else:
32
- node = ast3.Module(body=[], type_ignores=[])
33
- try:
34
- compile(node, "<ast>", "exec")
35
- except TypeError as e:
36
- print(ast3.dump(node, indent=2))
37
- raise e
38
- except Exception:
39
- pass
22
+ # TODO: This should live in utils and perhaps a test added using it
23
+ # @staticmethod
24
+ # def node_compilable_test(node: ast3.AST) -> None:
25
+ # """Convert any AST node to a compilable module node."""
26
+ # if isinstance(node, ast3.Module):
27
+ # pass
28
+ # elif isinstance(node, (ast3.Expr, ast3.stmt)):
29
+ # node = ast3.Module(body=[node], type_ignores=[])
30
+ # elif isinstance(node, list) and all(isinstance(n, ast3.stmt) for n in node):
31
+ # node = ast3.Module(body=node, type_ignores=[])
32
+ # else:
33
+ # node = ast3.Module(body=[], type_ignores=[])
34
+ # try:
35
+ # compile(node, "<ast>", "exec")
36
+ # except TypeError as e:
37
+ # print(ast3.dump(node, indent=2))
38
+ # raise e
39
+ # except Exception:
40
+ # pass
40
41
 
41
42
  def before_pass(self) -> None:
42
43
  """Initialize pass."""
@@ -80,7 +81,7 @@ class PyastGenPass(Pass):
80
81
 
81
82
  def needs_jac_import(self) -> None:
82
83
  """Check if import is needed."""
83
- if "jimport" in self.already_added:
84
+ if self.needs_jac_import.__name__ in self.already_added:
84
85
  return
85
86
  self.preamble.append(
86
87
  self.sync(
@@ -96,11 +97,11 @@ class PyastGenPass(Pass):
96
97
  jac_node=self.ir,
97
98
  )
98
99
  )
99
- self.already_added.append("jimport")
100
+ self.already_added.append(self.needs_jac_import.__name__)
100
101
 
101
102
  def needs_typing(self) -> None:
102
103
  """Check if enum is needed."""
103
- if "typing" in self.already_added:
104
+ if self.needs_typing.__name__ in self.already_added:
104
105
  return
105
106
  self.preamble.append(
106
107
  self.sync(
@@ -115,11 +116,11 @@ class PyastGenPass(Pass):
115
116
  jac_node=self.ir,
116
117
  )
117
118
  )
118
- self.already_added.append("typing")
119
+ self.already_added.append(self.needs_typing.__name__)
119
120
 
120
121
  def needs_enum(self) -> None:
121
122
  """Check if enum is needed."""
122
- if "enum" in self.already_added:
123
+ if self.needs_enum.__name__ in self.already_added:
123
124
  return
124
125
  self.preamble.append(
125
126
  self.sync(
@@ -134,11 +135,11 @@ class PyastGenPass(Pass):
134
135
  jac_node=self.ir,
135
136
  )
136
137
  )
137
- self.already_added.append("enum")
138
+ self.already_added.append(self.needs_enum.__name__)
138
139
 
139
140
  def needs_jac_feature(self) -> None:
140
141
  """Check if enum is needed."""
141
- if "jac_feature" in self.already_added:
142
+ if self.needs_jac_feature.__name__ in self.already_added:
142
143
  return
143
144
  self.preamble.append(
144
145
  self.sync(
@@ -164,11 +165,11 @@ class PyastGenPass(Pass):
164
165
  jac_node=self.ir,
165
166
  )
166
167
  )
167
- self.already_added.append("jac_feature")
168
+ self.already_added.append(self.needs_jac_feature.__name__)
168
169
 
169
170
  def needs_dataclass(self) -> None:
170
171
  """Check if enum is needed."""
171
- if "dataclass" in self.already_added:
172
+ if self.needs_dataclass.__name__ in self.already_added:
172
173
  return
173
174
  self.preamble.append(
174
175
  self.sync(
@@ -184,11 +185,11 @@ class PyastGenPass(Pass):
184
185
  jac_node=self.ir,
185
186
  )
186
187
  )
187
- self.already_added.append("dataclass")
188
+ self.already_added.append(self.needs_dataclass.__name__)
188
189
 
189
190
  def needs_dataclass_field(self) -> None:
190
191
  """Check if enum is needed."""
191
- if "dataclass_field" in self.already_added:
192
+ if self.needs_dataclass_field.__name__ in self.already_added:
192
193
  return
193
194
  self.preamble.append(
194
195
  self.sync(
@@ -202,7 +203,7 @@ class PyastGenPass(Pass):
202
203
  jac_node=self.ir,
203
204
  )
204
205
  )
205
- self.already_added.append("dataclass_field")
206
+ self.already_added.append(self.needs_dataclass_field.__name__)
206
207
 
207
208
  def flatten(self, body: list[T | list[T] | None]) -> list[T]:
208
209
  """Flatten ast list."""
@@ -13,7 +13,7 @@ import jaclang.compiler.absyntree as ast
13
13
  from jaclang.compiler.constant import Constants as Con
14
14
  from jaclang.compiler.passes import Pass
15
15
  from jaclang.compiler.semtable import SemInfo, SemRegistry
16
- from jaclang.core.utils import get_sem_scope
16
+ from jaclang.runtimelib.utils import get_sem_scope
17
17
 
18
18
 
19
19
  class RegistryPass(Pass):
@@ -212,7 +212,7 @@ class JacFormatPass(Pass):
212
212
  items: list[T],
213
213
  """
214
214
  prev_token = None
215
- for i, stmt in enumerate(node.kid):
215
+ for stmt in node.kid:
216
216
  if isinstance(node.parent, (ast.EnumDef, ast.Enum)) and stmt.gen.jac == ",":
217
217
  self.indent_level -= 1
218
218
  self.emit_ln(node, f"{stmt.gen.jac}")
@@ -240,27 +240,10 @@ class JacFormatPass(Pass):
240
240
  elif stmt.name == Tok.RBRACE:
241
241
  if self.indent_level > 0:
242
242
  self.indent_level -= 1
243
- if (stmt.parent and stmt.parent.gen.jac.strip() == "{") or (
244
- stmt.parent
245
- and stmt.parent.parent
246
- and isinstance(
247
- stmt.parent.parent,
248
- (ast.ElseIf, ast.IfStmt, ast.IterForStmt, ast.TryStmt),
249
- )
250
- ):
243
+ if stmt.parent and stmt.parent.gen.jac.strip() == "{":
251
244
  self.emit(node, f"{stmt.value}")
252
245
  else:
253
- next_kid = (
254
- node.kid[i + 1]
255
- if i < (len(node.kid) - 1)
256
- else ast.EmptyToken()
257
- )
258
- if (
259
- isinstance(next_kid, ast.CommentToken)
260
- and next_kid.is_inline
261
- ):
262
- self.emit(node, f" {stmt.value}")
263
- elif not (node.gen.jac).endswith("\n"):
246
+ if not (node.gen.jac).endswith("\n"):
264
247
  self.emit_ln(node, "")
265
248
  self.emit(node, f"{stmt.value}")
266
249
  else:
@@ -70,3 +70,7 @@ class Transform(ABC, Generic[T]):
70
70
  )
71
71
  self.warnings_had.append(alrt)
72
72
  self.logger.warning(str(alrt))
73
+
74
+ def log_info(self, msg: str) -> None:
75
+ """Log info."""
76
+ self.logger.info(msg)
@@ -127,9 +127,11 @@ class SemRegistry:
127
127
  break
128
128
  return i
129
129
 
130
- def pp(self) -> None:
130
+ def pp(self) -> str:
131
131
  """Pretty print the registry."""
132
+ ret_str = ""
132
133
  for k, v in self.registry.items():
133
- print(k)
134
+ ret_str += f"{k}\n"
134
135
  for i in v:
135
- print(f" {i.name} {i.type} {i.semstr}")
136
+ ret_str += f" {i.name} {i.type} {i.semstr}\n"
137
+ return ret_str
@@ -5,6 +5,7 @@ import sys
5
5
 
6
6
  from jaclang import jac_import
7
7
  from jaclang.cli import cli
8
+ from jaclang.plugin.feature import JacFeature as Jac
8
9
  from jaclang.utils.test import TestCase
9
10
 
10
11
 
@@ -17,11 +18,13 @@ class TestLoader(TestCase):
17
18
 
18
19
  def test_import_basic_python(self) -> None:
19
20
  """Test basic self loading."""
21
+ Jac.context().init_memory(base_path=self.fixture_abs_path(__file__))
20
22
  (h,) = jac_import("fixtures.hello_world", base_path=__file__)
21
23
  self.assertEqual(h.hello(), "Hello World!") # type: ignore
22
24
 
23
25
  def test_modules_correct(self) -> None:
24
26
  """Test basic self loading."""
27
+ Jac.context().init_memory(base_path=self.fixture_abs_path(__file__))
25
28
  jac_import("fixtures.hello_world", base_path=__file__)
26
29
  self.assertIn("module 'hello_world'", str(sys.modules))
27
30
  self.assertIn("/tests/fixtures/hello_world.jac", str(sys.modules))