jaclang 0.7.23__py3-none-any.whl → 0.7.25__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 (50) hide show
  1. jaclang/cli/cli.py +46 -29
  2. jaclang/compiler/__init__.py +2 -2
  3. jaclang/compiler/absyntree.py +87 -48
  4. jaclang/compiler/codeloc.py +7 -2
  5. jaclang/compiler/compile.py +10 -3
  6. jaclang/compiler/parser.py +26 -23
  7. jaclang/compiler/passes/ir_pass.py +2 -2
  8. jaclang/compiler/passes/main/def_impl_match_pass.py +46 -0
  9. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +146 -123
  10. jaclang/compiler/passes/main/import_pass.py +6 -2
  11. jaclang/compiler/passes/main/pyast_load_pass.py +36 -35
  12. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -7
  13. jaclang/compiler/passes/main/registry_pass.py +3 -12
  14. jaclang/compiler/passes/main/tests/fixtures/defn_decl_mismatch.jac +19 -0
  15. jaclang/compiler/passes/main/tests/fixtures/fstrings.jac +2 -0
  16. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +59 -0
  17. jaclang/compiler/passes/main/tests/test_registry_pass.py +2 -10
  18. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  19. jaclang/compiler/passes/transform.py +27 -3
  20. jaclang/compiler/passes/utils/mypy_ast_build.py +246 -26
  21. jaclang/compiler/symtable.py +6 -0
  22. jaclang/compiler/tests/test_importer.py +2 -2
  23. jaclang/langserve/engine.py +14 -12
  24. jaclang/langserve/server.py +7 -2
  25. jaclang/langserve/tests/test_server.py +1 -1
  26. jaclang/langserve/utils.py +17 -3
  27. jaclang/plugin/default.py +32 -32
  28. jaclang/plugin/feature.py +2 -2
  29. jaclang/plugin/plugin.md +471 -0
  30. jaclang/plugin/spec.py +2 -1
  31. jaclang/runtimelib/context.py +2 -0
  32. jaclang/runtimelib/importer.py +7 -2
  33. jaclang/runtimelib/machine.py +21 -6
  34. jaclang/settings.py +3 -0
  35. jaclang/tests/fixtures/builtin_dotgen.jac +6 -6
  36. jaclang/tests/fixtures/enum_inside_archtype.jac +16 -11
  37. jaclang/tests/fixtures/expr_type.jac +54 -0
  38. jaclang/tests/fixtures/glob_multivar_statement.jac +15 -0
  39. jaclang/tests/fixtures/registry.jac +20 -8
  40. jaclang/tests/foo/__init__.jac +0 -0
  41. jaclang/tests/main.jac +2 -0
  42. jaclang/tests/test_cli.py +68 -4
  43. jaclang/tests/test_language.py +60 -27
  44. jaclang/utils/helpers.py +92 -14
  45. jaclang/utils/lang_tools.py +6 -2
  46. jaclang/utils/treeprinter.py +4 -2
  47. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/METADATA +2 -1
  48. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/RECORD +50 -44
  49. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/WHEEL +1 -1
  50. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/entry_points.txt +0 -0
@@ -9,7 +9,7 @@ from typing import Optional, TYPE_CHECKING
9
9
  from jaclang.vendor.mypy.nodes import Node as MypyNode
10
10
 
11
11
  if TYPE_CHECKING:
12
- from jaclang.compiler.absyntree import Token
12
+ from jaclang.compiler.absyntree import JacSource, Token
13
13
 
14
14
 
15
15
  @dataclass
@@ -42,10 +42,15 @@ class CodeLocInfo:
42
42
  self.first_tok = first_tok
43
43
  self.last_tok = last_tok
44
44
 
45
+ @property
46
+ def orig_src(self) -> JacSource:
47
+ """Get file source."""
48
+ return self.first_tok.orig_src
49
+
45
50
  @property
46
51
  def mod_path(self) -> str:
47
52
  """Get line number."""
48
- return self.first_tok.file_path
53
+ return self.first_tok.orig_src.file_path
49
54
 
50
55
  @property
51
56
  def first_line(self) -> int:
@@ -16,11 +16,13 @@ def compile_jac(file_path: str, cache_result: bool = False) -> Pass:
16
16
  file_path=file_path,
17
17
  schedule=pass_schedule,
18
18
  )
19
- if cache_result and isinstance(code.ir, ast.Module):
19
+ # If there is syntax error, the code will be an instance of JacParser as there is
20
+ # no more passes were processed, in that case we can ignore it.
21
+ had_syntax_error = isinstance(code, JacParser) and len(code.errors_had) != 0
22
+ if cache_result and (not had_syntax_error) and isinstance(code.ir, ast.Module):
20
23
  print_pass = PyOutPass(input_ir=code.ir, prior=code)
21
24
  return print_pass
22
- else:
23
- return code
25
+ return code
24
26
 
25
27
 
26
28
  def jac_file_to_pass(
@@ -49,6 +51,11 @@ def jac_str_to_pass(
49
51
  target = schedule[-1] if schedule else None
50
52
  source = ast.JacSource(jac_str, mod_path=file_path)
51
53
  ast_ret: Pass = JacParser(input_ir=source)
54
+
55
+ # If there is syntax error, no point in processing in further passes.
56
+ if len(ast_ret.errors_had) != 0:
57
+ return ast_ret
58
+
52
59
  for i in schedule:
53
60
  if i == target:
54
61
  break
@@ -43,14 +43,22 @@ class JacParser(Pass):
43
43
  raise self.ice()
44
44
  except jl.UnexpectedInput as e:
45
45
  catch_error = ast.EmptyToken()
46
- catch_error.file_path = self.mod_path
46
+ catch_error.orig_src = self.source
47
47
  catch_error.line_no = e.line
48
48
  catch_error.end_line = e.line
49
49
  catch_error.c_start = e.column
50
50
  catch_error.c_end = e.column + 1
51
- self.error(f"Syntax Error: {e}", node_override=catch_error)
51
+ catch_error.pos_start = e.pos_in_stream or 0
52
+ catch_error.pos_end = catch_error.pos_start + 1
53
+
54
+ error_msg = "Syntax Error"
55
+ if len(e.args) >= 1 and isinstance(e.args[0], str):
56
+ error_msg += e.args[0]
57
+ self.error(error_msg, node_override=catch_error)
58
+
52
59
  except Exception as e:
53
60
  self.error(f"Internal Error: {e}")
61
+
54
62
  return ast.Module(
55
63
  name="",
56
64
  source=self.source,
@@ -65,7 +73,7 @@ class JacParser(Pass):
65
73
  def proc_comment(token: jl.Token, mod: ast.AstNode) -> ast.CommentToken:
66
74
  """Process comment."""
67
75
  return ast.CommentToken(
68
- file_path=mod.loc.mod_path,
76
+ orig_src=mod.loc.orig_src,
69
77
  name=token.type,
70
78
  value=token.value,
71
79
  line=token.line if token.line is not None else 0,
@@ -166,7 +174,7 @@ class JacParser(Pass):
166
174
  kid=(
167
175
  kid
168
176
  if len(kid)
169
- else [ast.EmptyToken(file_path=self.parse_ref.mod_path)]
177
+ else [ast.EmptyToken(ast.JacSource("", self.parse_ref.mod_path))]
170
178
  ),
171
179
  )
172
180
  return self.nu(mod)
@@ -706,10 +714,12 @@ class JacParser(Pass):
706
714
  | NAME (COLON STRING)?
707
715
  | py_code_block
708
716
  | free_code
717
+ | abstract_ability
718
+ | ability
709
719
  """
710
- if isinstance(kid[0], ast.PyInlineCode):
720
+ if isinstance(kid[0], (ast.PyInlineCode, ast.Ability)):
711
721
  return self.nu(kid[0])
712
- if isinstance(kid[0], (ast.Name)):
722
+ elif isinstance(kid[0], (ast.Name)):
713
723
  if (
714
724
  len(kid) >= 3
715
725
  and isinstance(kid[-1], ast.Expr)
@@ -1010,7 +1020,11 @@ class JacParser(Pass):
1010
1020
  kid=(
1011
1021
  kid
1012
1022
  if len(kid)
1013
- else [ast.EmptyToken(file_path=self.parse_ref.mod_path)]
1023
+ else [
1024
+ ast.EmptyToken(
1025
+ ast.JacSource("", self.parse_ref.mod_path)
1026
+ )
1027
+ ]
1014
1028
  ),
1015
1029
  )
1016
1030
  )
@@ -1228,7 +1242,7 @@ class JacParser(Pass):
1228
1242
  return self.nu(
1229
1243
  ast.BuiltinType(
1230
1244
  name=kid[0].name,
1231
- file_path=self.parse_ref.mod_path,
1245
+ orig_src=self.parse_ref.source,
1232
1246
  value=kid[0].value,
1233
1247
  line=kid[0].loc.first_line,
1234
1248
  end_line=kid[0].loc.last_line,
@@ -2786,25 +2800,14 @@ class JacParser(Pass):
2786
2800
  def name_list(self, kid: list[ast.AstNode]) -> ast.SubNodeList[ast.Name]:
2787
2801
  """Grammar rule.
2788
2802
 
2789
- name_list: (name_list COMMA)? NAME
2803
+ name_list: (named_ref COMMA)* named_ref
2790
2804
  """
2791
- consume = None
2792
- name = None
2793
- comma = None
2794
- if isinstance(kid[0], ast.SubNodeList):
2795
- consume = kid[0]
2796
- comma = kid[1]
2797
- name = kid[2]
2798
- new_kid = [*consume.kid, comma, name]
2799
- else:
2800
- name = kid[0]
2801
- new_kid = [name]
2802
- valid_kid = [i for i in new_kid if isinstance(i, ast.Name)]
2805
+ valid_kid = [i for i in kid if isinstance(i, ast.Name)]
2803
2806
  return self.nu(
2804
2807
  ast.SubNodeList[ast.Name](
2805
2808
  items=valid_kid,
2806
2809
  delim=Tok.COMMA,
2807
- kid=new_kid,
2810
+ kid=kid,
2808
2811
  )
2809
2812
  )
2810
2813
 
@@ -3996,7 +3999,7 @@ class JacParser(Pass):
3996
3999
  elif token.type == Tok.PYNLINE and isinstance(token.value, str):
3997
4000
  token.value = token.value.replace("::py::", "")
3998
4001
  ret = ret_type(
3999
- file_path=self.parse_ref.mod_path,
4002
+ orig_src=self.parse_ref.source,
4000
4003
  name=token.type,
4001
4004
  value=token.value[2:] if token.type == Tok.KWESC_NAME else token.value,
4002
4005
  line=token.line if token.line is not None else 0,
@@ -140,11 +140,11 @@ class Pass(Transform[T]):
140
140
 
141
141
  def error(self, msg: str, node_override: Optional[ast.AstNode] = None) -> None:
142
142
  """Pass Error."""
143
- self.log_error(f"{msg}", node_override=node_override)
143
+ self.log_error(msg, node_override=node_override)
144
144
 
145
145
  def warning(self, msg: str, node_override: Optional[ast.AstNode] = None) -> None:
146
146
  """Pass Error."""
147
- self.log_warning(f"{msg}", node_override=node_override)
147
+ self.log_warning(msg, node_override=node_override)
148
148
 
149
149
  def ice(self, msg: str = "Something went horribly wrong!") -> RuntimeError:
150
150
  """Pass Error."""
@@ -90,6 +90,10 @@ class DeclImplMatchPass(Pass):
90
90
  raise self.ice(
91
91
  f"Expected AstImplNeedingNode, got {valid_decl.__class__.__name__}. Not possible."
92
92
  )
93
+
94
+ # Ensure if it's an ability def impl, the parameters are matched.
95
+ self.validate_params_match(sym, decl_node.name_of)
96
+
93
97
  valid_decl.body = sym.decl.name_of
94
98
  sym.decl.name_of.decl_link = valid_decl
95
99
  for idx, a in enumerate(sym.decl.name_of.target.archs):
@@ -97,5 +101,47 @@ class DeclImplMatchPass(Pass):
97
101
  a.name_spec.sym = name_of_links[idx].sym
98
102
  sym.decl.name_of.sym_tab.tab.update(valid_decl.sym_tab.tab)
99
103
  valid_decl.sym_tab.tab = sym.decl.name_of.sym_tab.tab
104
+
100
105
  for i in sym_tab.kid:
101
106
  self.connect_def_impl(i)
107
+
108
+ def validate_params_match(self, sym: Symbol, valid_decl: ast.AstSymbolNode) -> None:
109
+ """Validate if the parameters match."""
110
+ if (
111
+ isinstance(valid_decl, ast.Ability)
112
+ and isinstance(sym.decl.name_of, ast.AbilityDef)
113
+ and isinstance(valid_decl.signature, ast.FuncSignature)
114
+ and isinstance(sym.decl.name_of.signature, ast.FuncSignature)
115
+ ):
116
+
117
+ params_decl = valid_decl.signature.params
118
+ params_defn = sym.decl.name_of.signature.params
119
+
120
+ if params_decl and params_defn:
121
+ # Check if the parameter count is matched.
122
+ if len(params_defn.items) != len(params_decl.items):
123
+ self.error(
124
+ f"Parameter count mismatch for ability {sym.sym_name}.",
125
+ sym.decl.name_of.name_spec,
126
+ )
127
+ self.error(
128
+ f"From the declaration of {valid_decl.name_spec.sym_name}.",
129
+ valid_decl.name_spec,
130
+ )
131
+ else:
132
+ for idx in range(len(params_defn.items)):
133
+ # Check if all the parameter names are matched.
134
+ # TODO: This shouldn't be an issue however if the names are not matched, it doesn't
135
+ # work as expected like in C++, for now I'm adding this validation, however this
136
+ # needs to be fixed to have a C++ style.
137
+ param_name_decl = params_decl.items[idx].name.value
138
+ param_name_defn = params_defn.items[idx].name.value
139
+ if param_name_defn != param_name_decl:
140
+ self.error(
141
+ f"Parameter name mismatch for ability {sym.sym_name}.",
142
+ params_defn.items[idx].name,
143
+ )
144
+ self.error(
145
+ f"From the declaration of {valid_decl.name_spec.sym_name}.",
146
+ params_decl.items[idx].name,
147
+ )