jaclang 0.7.13__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 (96) 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 +95 -17
  5. jaclang/compiler/jac.lark +4 -3
  6. jaclang/compiler/parser.py +35 -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 +19 -23
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +308 -567
  12. jaclang/compiler/passes/main/pyast_load_pass.py +33 -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/tests/test_import_pass.py +5 -1
  17. jaclang/compiler/passes/main/type_check_pass.py +7 -0
  18. jaclang/compiler/passes/tool/fuse_comments_pass.py +14 -2
  19. jaclang/compiler/passes/tool/jac_formatter_pass.py +144 -94
  20. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +0 -1
  21. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
  22. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
  23. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
  24. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
  25. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
  26. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
  27. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
  28. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
  29. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
  30. jaclang/compiler/passes/transform.py +4 -0
  31. jaclang/compiler/semtable.py +31 -7
  32. jaclang/compiler/tests/test_importer.py +12 -5
  33. jaclang/langserve/engine.py +82 -143
  34. jaclang/langserve/sem_manager.py +379 -0
  35. jaclang/langserve/server.py +8 -10
  36. jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
  37. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  38. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  39. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  40. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  41. jaclang/langserve/tests/test_sem_tokens.py +277 -0
  42. jaclang/langserve/tests/test_server.py +96 -16
  43. jaclang/langserve/utils.py +163 -96
  44. jaclang/plugin/builtin.py +1 -1
  45. jaclang/plugin/default.py +214 -24
  46. jaclang/plugin/feature.py +59 -11
  47. jaclang/plugin/spec.py +58 -6
  48. jaclang/{core → runtimelib}/architype.py +1 -1
  49. jaclang/{core → runtimelib}/context.py +8 -1
  50. jaclang/runtimelib/importer.py +361 -0
  51. jaclang/runtimelib/machine.py +94 -0
  52. jaclang/{core → runtimelib}/utils.py +13 -5
  53. jaclang/settings.py +4 -1
  54. jaclang/tests/fixtures/abc.jac +3 -3
  55. jaclang/tests/fixtures/blankwithentry.jac +3 -0
  56. jaclang/tests/fixtures/byllmissue.jac +1 -5
  57. jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
  58. jaclang/tests/fixtures/cls_method.jac +41 -0
  59. jaclang/tests/fixtures/dblhello.jac +6 -0
  60. jaclang/tests/fixtures/deep/one_lev.jac +3 -3
  61. jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
  62. jaclang/tests/fixtures/deep_import_mods.jac +13 -0
  63. jaclang/tests/fixtures/err.impl.jac +3 -0
  64. jaclang/tests/fixtures/err.jac +4 -2
  65. jaclang/tests/fixtures/err.test.jac +3 -0
  66. jaclang/tests/fixtures/err_runtime.jac +15 -0
  67. jaclang/tests/fixtures/game1.jac +1 -1
  68. jaclang/tests/fixtures/hello.jac +4 -0
  69. jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
  70. jaclang/tests/fixtures/impl_grab.jac +4 -1
  71. jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
  72. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  73. jaclang/tests/fixtures/needs_import.jac +2 -2
  74. jaclang/tests/fixtures/pyfunc_2.py +3 -0
  75. jaclang/tests/fixtures/registry.jac +9 -0
  76. jaclang/tests/fixtures/run_test.jac +4 -4
  77. jaclang/tests/fixtures/semstr.jac +1 -4
  78. jaclang/tests/fixtures/simple_archs.jac +1 -1
  79. jaclang/tests/test_cli.py +65 -2
  80. jaclang/tests/test_language.py +83 -7
  81. jaclang/tests/test_man_code.py +17 -0
  82. jaclang/tests/test_reference.py +6 -0
  83. jaclang/utils/helpers.py +45 -21
  84. jaclang/utils/test.py +9 -0
  85. jaclang/utils/treeprinter.py +0 -4
  86. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/METADATA +3 -2
  87. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/RECORD +93 -77
  88. jaclang/core/importer.py +0 -344
  89. jaclang/tests/fixtures/aott_raise.jac +0 -25
  90. jaclang/tests/fixtures/package_import.jac +0 -6
  91. /jaclang/{core → runtimelib}/__init__.py +0 -0
  92. /jaclang/{core → runtimelib}/constructs.py +0 -0
  93. /jaclang/{core → runtimelib}/memory.py +0 -0
  94. /jaclang/{core → runtimelib}/test.py +0 -0
  95. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/WHEEL +0 -0
  96. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/entry_points.txt +0 -0
jaclang/cli/cli.py CHANGED
@@ -19,10 +19,11 @@ 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
+ from jaclang.runtimelib.machine import JacProgram
26
27
  from jaclang.utils.helpers import debugger as db
27
28
  from jaclang.utils.lang_tools import AstTool
28
29
 
@@ -86,11 +87,10 @@ def run(
86
87
  else ""
87
88
  )
88
89
 
89
- Jac.context().init_memory(session)
90
-
91
90
  base, mod = os.path.split(filename)
92
91
  base = base if base else "./"
93
92
  mod = mod[:-4]
93
+ Jac.context().init_memory(base_path=base, session=session)
94
94
  if filename.endswith(".jac"):
95
95
  ret_module = jac_import(
96
96
  target=mod,
@@ -105,12 +105,13 @@ def run(
105
105
  elif filename.endswith(".jir"):
106
106
  with open(filename, "rb") as f:
107
107
  ir = pickle.load(f)
108
+ jac_program = JacProgram(mod_bundle=ir, bytecode=None)
109
+ Jac.context().jac_machine.attach_program(jac_program)
108
110
  ret_module = jac_import(
109
111
  target=mod,
110
112
  base_path=base,
111
113
  cachable=cache,
112
114
  override_name="__main__" if main else None,
113
- mod_bundle=ir,
114
115
  )
115
116
  if ret_module is None:
116
117
  loaded_mod = None
@@ -146,7 +147,7 @@ def get_object(id: str, session: str = "") -> dict:
146
147
  if session == "":
147
148
  session = cmd_registry.args.session if "session" in cmd_registry.args else ""
148
149
 
149
- Jac.context().init_memory(session)
150
+ Jac.context().init_memory(session=session)
150
151
 
151
152
  if id == "root":
152
153
  id_uuid = UUID(int=0)
@@ -221,7 +222,7 @@ def enter(filename: str, entrypoint: str, args: list) -> None:
221
222
  base, mod_name = os.path.split(filename)
222
223
  base = base if base else "./"
223
224
  mod_name = mod_name[:-4]
224
- mod = jac_import(target=mod_name, base_path=base)
225
+ (mod,) = jac_import(target=mod_name, base_path=base)
225
226
  if not mod:
226
227
  print("Errors occurred while importing the module.")
227
228
  return
@@ -357,11 +358,10 @@ def dot(
357
358
  else ""
358
359
  )
359
360
 
360
- Jac.context().init_memory(session)
361
-
362
361
  base, mod = os.path.split(filename)
363
362
  base = base if base else "./"
364
363
  mod = mod[:-4]
364
+ Jac.context().init_memory(base_path=base, session=session)
365
365
  if filename.endswith(".jac"):
366
366
  jac_import(
367
367
  target=mod,
@@ -437,12 +437,17 @@ def start_cli() -> None:
437
437
  parser = cmd_registry.parser
438
438
  args = parser.parse_args()
439
439
  cmd_registry.args = args
440
+
441
+ if args.version:
442
+ version = importlib.metadata.version("jaclang")
443
+ print(f"Jac version {version}")
444
+ return
445
+
440
446
  command = cmd_registry.get(args.command)
441
447
  if command:
442
448
  args_dict = vars(args)
443
449
  args_dict.pop("command")
444
- if command not in ["run"]:
445
- args_dict.pop("session")
450
+ args_dict.pop("version", None)
446
451
  ret = command.call(**args_dict)
447
452
  if ret:
448
453
  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."""
@@ -35,7 +35,6 @@ def generate_static_parser(force: bool = False) -> None:
35
35
  logging.error(f"Error generating reference files: {e}")
36
36
 
37
37
 
38
- generate_static_parser()
39
38
  try:
40
39
  from jaclang.compiler.generated import jac_parser as jac_lark
41
40
  except ModuleNotFoundError:
@@ -50,62 +49,29 @@ TOKEN_MAP = {
50
49
  for x in jac_lark.Lark_StandAlone().parser.lexer_conf.terminals
51
50
  }
52
51
 
52
+ # fmt: off
53
53
  TOKEN_MAP.update(
54
54
  {
55
- "CARROW_L": "<++",
56
- "CARROW_R": "++>",
57
- "GLOBAL_OP": ":global:",
58
- "NONLOCAL_OP": ":nonlocal:",
59
- "WALKER_OP": ":walker:",
60
- "NODE_OP": ":node:",
61
- "EDGE_OP": ":edge:",
62
- "CLASS_OP": ":class:",
63
- "OBJECT_OP": ":obj:",
64
- "TYPE_OP": "`",
65
- "ABILITY_OP": ":can:",
66
- "ELVIS_OP": "?:",
67
- "NULL_OK": "?",
68
- "KW_OR": "|",
69
- "ARROW_BI": "<-->",
70
- "ARROW_L": "<--",
71
- "ARROW_R": "-->",
72
- "ARROW_L_P1": "<-:",
73
- "ARROW_R_P2": ":->",
74
- "ARROW_L_P2": ":-",
75
- "ARROW_R_P1": "-:",
76
- "CARROW_BI": "<++>",
77
- "CARROW_L": "<++",
78
- "CARROW_R": "++>",
79
- "CARROW_L_P1": "<+:",
80
- "CARROW_R_P2": ":+>",
81
- "CARROW_L_P2": ":+",
82
- "CARROW_R_P1": "+:",
83
- "PIPE_FWD": "|>",
84
- "PIPE_BKWD": "<|",
85
- "A_PIPE_FWD": ":>",
86
- "A_PIPE_BKWD": "<:",
87
- "DOT_FWD": ".>",
88
- "STAR_POW": "**",
89
- "STAR_MUL": "*",
90
- "FLOOR_DIV": "//",
91
- "DIV": "/",
92
- "PYNLINE": "::py::",
93
- "ADD_EQ": "+=",
94
- "SUB_EQ": "-=",
95
- "STAR_POW_EQ": "**=",
96
- "MUL_EQ": "*=",
97
- "FLOOR_DIV_EQ": "//=",
98
- "DIV_EQ": "/=",
99
- "MOD_EQ": "%=",
100
- "BW_AND_EQ": "&=",
101
- "BW_OR_EQ": "|=",
102
- "BW_XOR_EQ": "^=",
103
- "BW_NOT_EQ": "~=",
104
- "LSHIFT_EQ": "<<=",
105
- "RSHIFT_EQ": ">>=",
106
- "ELLIPSIS": "...",
55
+ "CARROW_L": "<++", "CARROW_R": "++>", "GLOBAL_OP": ":global:",
56
+ "NONLOCAL_OP": ":nonlocal:", "WALKER_OP": ":walker:", "NODE_OP": ":node:",
57
+ "EDGE_OP": ":edge:", "CLASS_OP": ":class:", "OBJECT_OP": ":obj:",
58
+ "TYPE_OP": "`", "ABILITY_OP": ":can:", "ELVIS_OP": "?:", "NULL_OK": "?",
59
+ "KW_OR": "|", "ARROW_BI": "<-->", "ARROW_L": "<--",
60
+ "ARROW_R": "-->", "ARROW_L_P1": "<-:", "ARROW_R_P2": ":->",
61
+ "ARROW_L_P2": ":-", "ARROW_R_P1": "-:", "CARROW_BI": "<++>",
62
+ "CARROW_L": "<++", "CARROW_R": "++>", "CARROW_L_P1": "<+:",
63
+ "CARROW_R_P2": ":+>", "CARROW_L_P2": ":+", "CARROW_R_P1": "+:",
64
+ "PIPE_FWD": "|>", "PIPE_BKWD": "<|", "A_PIPE_FWD": ":>",
65
+ "A_PIPE_BKWD": "<:", "DOT_FWD": ".>", "STAR_POW": "**",
66
+ "STAR_MUL": "*", "FLOOR_DIV": "//", "DIV": "/",
67
+ "PYNLINE": "::py::", "ADD_EQ": "+=", "SUB_EQ": "-=",
68
+ "STAR_POW_EQ": "**=", "MUL_EQ": "*=", "FLOOR_DIV_EQ": "//=",
69
+ "DIV_EQ": "/=", "MOD_EQ": "%=", "BW_AND_EQ": "&=",
70
+ "BW_OR_EQ": "|=", "BW_XOR_EQ": "^=", "BW_NOT_EQ": "~=",
71
+ "LSHIFT_EQ": "<<=", "RSHIFT_EQ": ">>=", "ELLIPSIS": "...",
107
72
  }
108
73
  )
74
+ # fmt: on
109
75
 
110
76
 
111
77
  __all__ = ["jac_lark", "TOKEN_MAP"]
@@ -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
 
@@ -163,7 +158,7 @@ class AstNode:
163
158
  """Get parent of type."""
164
159
  from jaclang.compiler.passes import Pass
165
160
 
166
- return Pass.has_parent_of_type(node=self, typ=typ)
161
+ return Pass.find_parent_of_type(node=self, typ=typ)
167
162
 
168
163
  def parent_of_type(self, typ: Type[T]) -> T:
169
164
  """Get parent of type."""
@@ -621,6 +616,7 @@ class Module(AstDocNode):
621
616
  doc: Optional[String],
622
617
  body: Sequence[ElementStmt | String | EmptyToken],
623
618
  is_imported: bool,
619
+ terminals: list[Token],
624
620
  kid: Sequence[AstNode],
625
621
  stub_only: bool = False,
626
622
  registry: Optional[SemRegistry] = None,
@@ -635,6 +631,7 @@ class Module(AstDocNode):
635
631
  self.test_mod: list[Module] = []
636
632
  self.mod_deps: dict[str, Module] = {}
637
633
  self.registry = registry
634
+ self.terminals: list[Token] = terminals
638
635
  AstNode.__init__(self, kid=kid)
639
636
  AstDocNode.__init__(self, doc=doc)
640
637
 
@@ -642,15 +639,15 @@ class Module(AstDocNode):
642
639
  def annexable_by(self) -> Optional[str]:
643
640
  """Get annexable by."""
644
641
  if not self.stub_only and (
645
- self.loc.mod_path.endswith("impl.jac")
646
- or self.loc.mod_path.endswith("test.jac")
642
+ self.loc.mod_path.endswith(".impl.jac")
643
+ or self.loc.mod_path.endswith(".test.jac")
647
644
  ):
648
645
  head_mod_name = self.name.split(".")[0]
649
646
  potential_path = os.path.join(
650
647
  os.path.dirname(self.loc.mod_path),
651
648
  f"{head_mod_name}.jac",
652
649
  )
653
- if os.path.exists(potential_path):
650
+ if os.path.exists(potential_path) and potential_path != self.loc.mod_path:
654
651
  return potential_path
655
652
  annex_dir = os.path.split(os.path.dirname(self.loc.mod_path))[-1]
656
653
  if annex_dir.endswith(".impl") or annex_dir.endswith(".test"):
@@ -661,7 +658,10 @@ class Module(AstDocNode):
661
658
  os.path.dirname(os.path.dirname(self.loc.mod_path)),
662
659
  f"{head_mod_name}.jac",
663
660
  )
664
- if os.path.exists(potential_path):
661
+ if (
662
+ os.path.exists(potential_path)
663
+ and potential_path != self.loc.mod_path
664
+ ):
665
665
  return potential_path
666
666
  return None
667
667
 
@@ -858,7 +858,7 @@ class Import(ElementStmt, CodeBlockStmt):
858
858
 
859
859
  def __init__(
860
860
  self,
861
- hint: SubTag[Name],
861
+ hint: Optional[SubTag[Name]],
862
862
  from_loc: Optional[ModulePath],
863
863
  items: SubNodeList[ModuleItem] | SubNodeList[ModulePath],
864
864
  is_absorb: bool, # For includes
@@ -873,11 +873,52 @@ class Import(ElementStmt, CodeBlockStmt):
873
873
  AstNode.__init__(self, kid=kid)
874
874
  AstDocNode.__init__(self, doc=doc)
875
875
 
876
+ @property
877
+ def is_py(self) -> bool:
878
+ """Check if import is python."""
879
+ if self.hint and self.hint.tag.value == "py":
880
+ return True
881
+ if not self.hint:
882
+ return not self.__jac_detected
883
+ return False
884
+
885
+ @property
886
+ def is_jac(self) -> bool:
887
+ """Check if import is jac."""
888
+ if self.hint and self.hint.tag.value == "jac":
889
+ return True
890
+ if not self.hint:
891
+ return self.__jac_detected
892
+ return False
893
+
894
+ @property
895
+ def __jac_detected(self) -> bool:
896
+ """Check if import is jac."""
897
+ if self.from_loc:
898
+ if self.from_loc.resolve_relative_path().endswith(".jac"):
899
+ return True
900
+ if os.path.isdir(self.from_loc.resolve_relative_path()):
901
+ if os.path.exists(
902
+ os.path.join(self.from_loc.resolve_relative_path(), "__init__.jac")
903
+ ):
904
+ return True
905
+ for i in self.items.items:
906
+ if isinstance(
907
+ i, ModuleItem
908
+ ) and self.from_loc.resolve_relative_path(i.name.value).endswith(
909
+ ".jac"
910
+ ):
911
+ return True
912
+ return any(
913
+ isinstance(i, ModulePath) and i.resolve_relative_path().endswith(".jac")
914
+ for i in self.items.items
915
+ )
916
+
876
917
  def normalize(self, deep: bool = False) -> bool:
877
918
  """Normalize import node."""
878
919
  res = True
879
920
  if deep:
880
- res = self.hint.normalize(deep)
921
+ res = self.hint.normalize(deep) if self.hint else res
881
922
  res = res and self.from_loc.normalize(deep) if self.from_loc else res
882
923
  res = res and self.items.normalize(deep)
883
924
  res = res and self.doc.normalize(deep) if self.doc else res
@@ -888,7 +929,8 @@ class Import(ElementStmt, CodeBlockStmt):
888
929
  new_kid.append(self.gen_token(Tok.KW_INCLUDE))
889
930
  else:
890
931
  new_kid.append(self.gen_token(Tok.KW_IMPORT))
891
- new_kid.append(self.hint)
932
+ if self.hint:
933
+ new_kid.append(self.hint)
892
934
  if self.from_loc:
893
935
  new_kid.append(self.gen_token(Tok.KW_FROM))
894
936
  new_kid.append(self.from_loc)
@@ -941,6 +983,26 @@ class ModulePath(AstSymbolNode):
941
983
  [p.value for p in self.path] if self.path else [self.name_spec.sym_name]
942
984
  )
943
985
 
986
+ def resolve_relative_path(self, target_item: Optional[str] = None) -> str:
987
+ """Convert an import target string into a relative file path."""
988
+ target = self.path_str
989
+ if target_item:
990
+ target += f".{target_item}"
991
+ base_path = os.path.dirname(self.loc.mod_path)
992
+ base_path = base_path if base_path else os.getcwd()
993
+ parts = target.split(".")
994
+ traversal_levels = self.level - 1 if self.level > 0 else 0
995
+ actual_parts = parts[traversal_levels:]
996
+ for _ in range(traversal_levels):
997
+ base_path = os.path.dirname(base_path)
998
+ relative_path = os.path.join(base_path, *actual_parts)
999
+ relative_path = (
1000
+ relative_path + ".jac"
1001
+ if os.path.exists(relative_path + ".jac")
1002
+ else relative_path
1003
+ )
1004
+ return relative_path
1005
+
944
1006
  def normalize(self, deep: bool = False) -> bool:
945
1007
  """Normalize module path node."""
946
1008
  res = True
@@ -1127,7 +1189,6 @@ class ArchDef(AstImplOnlyNode):
1127
1189
  body: SubNodeList[ArchBlockStmt],
1128
1190
  kid: Sequence[AstNode],
1129
1191
  doc: Optional[String] = None,
1130
- decorators: Optional[SubNodeList[Expr]] = None,
1131
1192
  decl_link: Optional[Architype] = None,
1132
1193
  ) -> None:
1133
1194
  """Initialize arch def node."""
@@ -1468,6 +1529,23 @@ class FuncSignature(AstSemStrNode):
1468
1529
  and self.parent.decl_link.is_static
1469
1530
  )
1470
1531
 
1532
+ @property
1533
+ def is_in_py_class(self) -> bool:
1534
+ """Check if the ability belongs to a class."""
1535
+ is_archi = self.find_parent_of_type(Architype)
1536
+ is_class = is_archi is not None and is_archi.arch_type.name == Tok.KW_CLASS
1537
+
1538
+ return (
1539
+ isinstance(self.parent, Ability)
1540
+ and self.parent.is_method is not None
1541
+ and is_class
1542
+ ) or (
1543
+ isinstance(self.parent, AbilityDef)
1544
+ and isinstance(self.parent.decl_link, Ability)
1545
+ and self.parent.decl_link.is_method
1546
+ and is_class
1547
+ )
1548
+
1471
1549
 
1472
1550
  class EventSignature(AstSemStrNode):
1473
1551
  """EventSignature node type for Jac Ast."""
jaclang/compiler/jac.lark CHANGED
@@ -16,8 +16,9 @@ element: import_stmt
16
16
  | test
17
17
 
18
18
  // Import/Include Statements
19
- import_stmt: KW_IMPORT sub_name KW_FROM from_path COMMA import_items SEMI
20
- | KW_IMPORT sub_name import_path (COMMA import_path)* SEMI
19
+ import_stmt: KW_IMPORT sub_name? KW_FROM from_path LBRACE import_items RBRACE
20
+ | KW_IMPORT sub_name? KW_FROM from_path COMMA import_items SEMI //Deprecated
21
+ | KW_IMPORT sub_name? import_path (COMMA import_path)* SEMI
21
22
  | include_stmt
22
23
 
23
24
  from_path: (DOT | ELLIPSIS)* import_path
@@ -27,7 +28,7 @@ import_path: named_ref (DOT named_ref)* (KW_AS NAME)?
27
28
  import_items: (import_item COMMA)* import_item
28
29
  import_item: named_ref (KW_AS NAME)?
29
30
  sub_name: COLON NAME
30
- include_stmt: KW_INCLUDE sub_name import_path SEMI
31
+ include_stmt: KW_INCLUDE sub_name? import_path SEMI
31
32
 
32
33
  // Architypes
33
34
  architype: decorators? architype_decl
@@ -56,6 +56,7 @@ class JacParser(Pass):
56
56
  source=self.source,
57
57
  doc=None,
58
58
  body=[],
59
+ terminals=[],
59
60
  is_imported=False,
60
61
  kid=[ast.EmptyToken()],
61
62
  )
@@ -120,6 +121,7 @@ class JacParser(Pass):
120
121
  """Initialize transformer."""
121
122
  super().__init__(*args, **kwargs)
122
123
  self.parse_ref = parser
124
+ self.terminals: list[ast.Token] = []
123
125
 
124
126
  def ice(self) -> Exception:
125
127
  """Raise internal compiler error."""
@@ -160,6 +162,7 @@ class JacParser(Pass):
160
162
  doc=doc,
161
163
  body=body,
162
164
  is_imported=False,
165
+ terminals=self.terminals,
163
166
  kid=kid if len(kid) else [ast.EmptyToken()],
164
167
  )
165
168
  return self.nu(mod)
@@ -295,26 +298,29 @@ class JacParser(Pass):
295
298
  def import_stmt(self, kid: list[ast.AstNode]) -> ast.Import:
296
299
  """Grammar rule.
297
300
 
298
- import_stmt: KW_IMPORT sub_name KW_FROM from_path COMMA import_items SEMI
299
- | KW_IMPORT sub_name import_path (COMMA import_path)* SEMI
301
+ import_stmt: KW_IMPORT sub_name? KW_FROM from_path LBRACE import_items RBRACE
302
+ | KW_IMPORT sub_name? KW_FROM from_path COMMA import_items SEMI //Deprecated
303
+ | KW_IMPORT sub_name? import_path (COMMA import_path)* SEMI
300
304
  | include_stmt
301
305
  """
302
306
  if len(kid) == 1 and isinstance(kid[0], ast.Import):
303
307
  return self.nu(kid[0])
304
- lang = kid[1]
305
- from_path = kid[3] if isinstance(kid[3], ast.ModulePath) else None
308
+ chomp = [*kid]
309
+ lang = kid[1] if isinstance(kid[1], ast.SubTag) else None
310
+ chomp = chomp[2:] if lang else chomp[1:]
311
+ from_path = chomp[1] if isinstance(chomp[1], ast.ModulePath) else None
306
312
  if from_path:
307
313
  items = kid[-2] if isinstance(kid[-2], ast.SubNodeList) else None
308
314
  else:
309
315
  paths = [i for i in kid if isinstance(i, ast.ModulePath)]
310
316
  items = ast.SubNodeList[ast.ModulePath](
311
- items=paths, delim=Tok.COMMA, kid=kid[2:-1]
317
+ items=paths, delim=Tok.COMMA, kid=kid[2 if lang else 1 : -1]
312
318
  )
313
- kid = kid[:2] + [items] + kid[-1:]
319
+ kid = (kid[:2] if lang else kid[:1]) + [items] + kid[-1:]
314
320
 
315
321
  is_absorb = False
316
- if isinstance(lang, ast.SubTag) and (isinstance(items, ast.SubNodeList)):
317
- return self.nu(
322
+ if isinstance(items, ast.SubNodeList):
323
+ ret = self.nu(
318
324
  ast.Import(
319
325
  hint=lang,
320
326
  from_loc=from_path,
@@ -323,7 +329,15 @@ class JacParser(Pass):
323
329
  kid=kid,
324
330
  )
325
331
  )
326
-
332
+ if (
333
+ from_path
334
+ and isinstance(kid[-1], ast.Token)
335
+ and kid[-1].name == Tok.SEMI
336
+ ):
337
+ self.parse_ref.warning(
338
+ "Deprecated syntax, use braces for multiple imports (e.g, import from mymod {a, b, c})",
339
+ )
340
+ return ret
327
341
  else:
328
342
  raise self.ice()
329
343
 
@@ -361,27 +375,24 @@ class JacParser(Pass):
361
375
 
362
376
  include_stmt: KW_INCLUDE sub_name import_path SEMI
363
377
  """
364
- lang = kid[1]
365
- from_path = kid[2]
378
+ lang = kid[1] if isinstance(kid[1], ast.SubTag) else None
379
+ from_path = kid[2] if lang else kid[1]
366
380
  if not isinstance(from_path, ast.ModulePath):
367
381
  raise self.ice()
368
382
  items = ast.SubNodeList[ast.ModulePath](
369
383
  items=[from_path], delim=Tok.COMMA, kid=[from_path]
370
384
  )
371
- kid = kid[:2] + [items] + kid[3:]
385
+ kid = (kid[:2] if lang else kid[:1]) + [items] + kid[-1:]
372
386
  is_absorb = True
373
- if isinstance(lang, ast.SubTag):
374
- return self.nu(
375
- ast.Import(
376
- hint=lang,
377
- from_loc=None,
378
- items=items,
379
- is_absorb=is_absorb,
380
- kid=kid,
381
- )
387
+ return self.nu(
388
+ ast.Import(
389
+ hint=lang,
390
+ from_loc=None,
391
+ items=items,
392
+ is_absorb=is_absorb,
393
+ kid=kid,
382
394
  )
383
- else:
384
- raise self.ice()
395
+ )
385
396
 
386
397
  def import_path(self, kid: list[ast.AstNode]) -> ast.ModulePath:
387
398
  """Grammar rule.
@@ -3983,4 +3994,5 @@ class JacParser(Pass):
3983
3994
  err.line = ret.loc.first_line
3984
3995
  err.column = ret.loc.col_start
3985
3996
  raise err
3997
+ self.terminals.append(ret)
3986
3998
  return self.nu(ret)
@@ -74,7 +74,7 @@ class Pass(Transform[T]):
74
74
  return result
75
75
 
76
76
  @staticmethod
77
- def has_parent_of_type(node: ast.AstNode, typ: Type[T]) -> Optional[T]:
77
+ def find_parent_of_type(node: ast.AstNode, typ: Type[T]) -> Optional[T]:
78
78
  """Check if node has parent of type."""
79
79
  while node.parent:
80
80
  if isinstance(node.parent, typ):
@@ -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}")
@@ -175,7 +175,7 @@ class AccessCheckPass(Pass):
175
175
  if isinstance(node.parent, ast.FuncCall):
176
176
  self.access_check(node)
177
177
 
178
- if node.sym and Pass.has_parent_of_type(
178
+ if node.sym and Pass.find_parent_of_type(
179
179
  node=node.sym.defn[-1], typ=ast.GlobalVars
180
180
  ):
181
181
  self.access_check(node)
@@ -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