jaclang 0.7.23__py3-none-any.whl → 0.7.26__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 (68) hide show
  1. jaclang/cli/cli.py +46 -29
  2. jaclang/compiler/__init__.py +2 -2
  3. jaclang/compiler/absyntree.py +114 -66
  4. jaclang/compiler/codeloc.py +7 -2
  5. jaclang/compiler/compile.py +10 -3
  6. jaclang/compiler/jac.lark +4 -1
  7. jaclang/compiler/parser.py +63 -43
  8. jaclang/compiler/passes/ir_pass.py +2 -2
  9. jaclang/compiler/passes/main/def_impl_match_pass.py +83 -0
  10. jaclang/compiler/passes/main/def_use_pass.py +1 -2
  11. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +146 -123
  12. jaclang/compiler/passes/main/import_pass.py +6 -2
  13. jaclang/compiler/passes/main/pyast_gen_pass.py +46 -20
  14. jaclang/compiler/passes/main/pyast_load_pass.py +56 -41
  15. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -7
  16. jaclang/compiler/passes/main/registry_pass.py +3 -12
  17. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -2
  18. jaclang/compiler/passes/main/tests/fixtures/defn_decl_mismatch.jac +19 -0
  19. jaclang/compiler/passes/main/tests/fixtures/fstrings.jac +2 -0
  20. jaclang/compiler/passes/main/tests/fixtures/uninitialized_hasvars.jac +26 -0
  21. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +66 -0
  22. jaclang/compiler/passes/main/tests/test_def_use_pass.py +3 -3
  23. jaclang/compiler/passes/main/tests/test_registry_pass.py +2 -10
  24. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  25. jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -2
  26. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +3 -3
  27. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
  28. jaclang/compiler/passes/transform.py +27 -3
  29. jaclang/compiler/passes/utils/mypy_ast_build.py +246 -26
  30. jaclang/compiler/symtable.py +6 -0
  31. jaclang/compiler/tests/test_importer.py +2 -2
  32. jaclang/compiler/tests/test_parser.py +7 -1
  33. jaclang/langserve/engine.py +14 -12
  34. jaclang/langserve/server.py +7 -2
  35. jaclang/langserve/tests/test_server.py +1 -1
  36. jaclang/langserve/utils.py +17 -3
  37. jaclang/plugin/default.py +80 -43
  38. jaclang/plugin/feature.py +12 -2
  39. jaclang/plugin/plugin.md +471 -0
  40. jaclang/plugin/spec.py +14 -1
  41. jaclang/plugin/tests/fixtures/graph_purger.jac +101 -0
  42. jaclang/plugin/tests/fixtures/other_root_access.jac +9 -0
  43. jaclang/plugin/tests/test_jaseci.py +126 -6
  44. jaclang/runtimelib/architype.py +12 -1
  45. jaclang/runtimelib/context.py +2 -0
  46. jaclang/runtimelib/importer.py +7 -2
  47. jaclang/runtimelib/machine.py +21 -6
  48. jaclang/runtimelib/memory.py +5 -1
  49. jaclang/settings.py +3 -0
  50. jaclang/tests/fixtures/architype_def_bug.jac +17 -0
  51. jaclang/tests/fixtures/builtin_dotgen.jac +6 -6
  52. jaclang/tests/fixtures/decl_defn_param_name.jac +19 -0
  53. jaclang/tests/fixtures/enum_inside_archtype.jac +16 -11
  54. jaclang/tests/fixtures/expr_type.jac +54 -0
  55. jaclang/tests/fixtures/glob_multivar_statement.jac +15 -0
  56. jaclang/tests/fixtures/multi_dim_array_split.jac +19 -0
  57. jaclang/tests/fixtures/registry.jac +20 -8
  58. jaclang/tests/foo/__init__.jac +0 -0
  59. jaclang/tests/main.jac +2 -0
  60. jaclang/tests/test_cli.py +86 -4
  61. jaclang/tests/test_language.py +104 -27
  62. jaclang/utils/helpers.py +92 -14
  63. jaclang/utils/lang_tools.py +6 -2
  64. jaclang/utils/treeprinter.py +4 -2
  65. {jaclang-0.7.23.dist-info → jaclang-0.7.26.dist-info}/METADATA +2 -1
  66. {jaclang-0.7.23.dist-info → jaclang-0.7.26.dist-info}/RECORD +68 -57
  67. {jaclang-0.7.23.dist-info → jaclang-0.7.26.dist-info}/WHEEL +1 -1
  68. {jaclang-0.7.23.dist-info → jaclang-0.7.26.dist-info}/entry_points.txt +0 -0
@@ -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,
@@ -2422,8 +2436,11 @@ class JacParser(Pass):
2422
2436
  def index_slice(self, kid: list[ast.AstNode]) -> ast.IndexSlice:
2423
2437
  """Grammar rule.
2424
2438
 
2425
- index_slice: LSQUARE expression? COLON expression? (COLON expression?)? RSQUARE
2426
- | list_val
2439
+ index_slice: LSQUARE \
2440
+ expression? COLON expression? (COLON expression?)? \
2441
+ (COMMA expression? COLON expression? (COLON expression?)?)* \
2442
+ RSQUARE
2443
+ | list_val
2427
2444
  """
2428
2445
  if len(kid) == 1:
2429
2446
  index = kid[0]
@@ -2440,9 +2457,9 @@ class JacParser(Pass):
2440
2457
  kid = [expr]
2441
2458
  return self.nu(
2442
2459
  ast.IndexSlice(
2443
- start=expr,
2444
- stop=None,
2445
- step=None,
2460
+ slices=[
2461
+ ast.IndexSlice.Slice(start=expr, stop=None, step=None)
2462
+ ],
2446
2463
  is_range=False,
2447
2464
  kid=kid,
2448
2465
  )
@@ -2450,25 +2467,39 @@ class JacParser(Pass):
2450
2467
  else:
2451
2468
  raise self.ice()
2452
2469
  else:
2453
- expr1 = expr2 = expr3 = None
2470
+ slices: list[ast.IndexSlice.Slice] = []
2454
2471
  chomp = kid[1:]
2455
- if isinstance(chomp[0], ast.Expr):
2456
- expr1 = chomp[0]
2457
- chomp = chomp[1:]
2458
- chomp = chomp[1:]
2459
- if isinstance(chomp[0], ast.Expr):
2460
- expr2 = chomp[0]
2461
- chomp = chomp[1:]
2462
- if isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.COLON:
2463
- chomp = chomp[1:]
2472
+
2473
+ while not (
2474
+ isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.RSQUARE
2475
+ ):
2476
+ expr1 = expr2 = expr3 = None
2477
+
2464
2478
  if isinstance(chomp[0], ast.Expr):
2465
- expr3 = chomp[0]
2466
- chomp = chomp[1:]
2479
+ expr1 = chomp[0]
2480
+ chomp.pop(0)
2481
+ chomp.pop(0)
2482
+
2483
+ if isinstance(chomp[0], ast.Expr):
2484
+ expr2 = chomp[0]
2485
+ chomp.pop(0)
2486
+
2487
+ if isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.COLON:
2488
+ chomp.pop(0)
2489
+ if isinstance(chomp[0], ast.Expr):
2490
+ expr3 = chomp[0]
2491
+ chomp.pop(0)
2492
+
2493
+ if isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.COMMA:
2494
+ chomp.pop(0)
2495
+
2496
+ slices.append(
2497
+ ast.IndexSlice.Slice(start=expr1, stop=expr2, step=expr3)
2498
+ )
2499
+
2467
2500
  return self.nu(
2468
2501
  ast.IndexSlice(
2469
- start=expr1,
2470
- stop=expr2,
2471
- step=expr3,
2502
+ slices=slices,
2472
2503
  is_range=True,
2473
2504
  kid=kid,
2474
2505
  )
@@ -2786,25 +2817,14 @@ class JacParser(Pass):
2786
2817
  def name_list(self, kid: list[ast.AstNode]) -> ast.SubNodeList[ast.Name]:
2787
2818
  """Grammar rule.
2788
2819
 
2789
- name_list: (name_list COMMA)? NAME
2820
+ name_list: (named_ref COMMA)* named_ref
2790
2821
  """
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)]
2822
+ valid_kid = [i for i in kid if isinstance(i, ast.Name)]
2803
2823
  return self.nu(
2804
2824
  ast.SubNodeList[ast.Name](
2805
2825
  items=valid_kid,
2806
2826
  delim=Tok.COMMA,
2807
- kid=new_kid,
2827
+ kid=kid,
2808
2828
  )
2809
2829
  )
2810
2830
 
@@ -3996,7 +4016,7 @@ class JacParser(Pass):
3996
4016
  elif token.type == Tok.PYNLINE and isinstance(token.value, str):
3997
4017
  token.value = token.value.replace("::py::", "")
3998
4018
  ret = ret_type(
3999
- file_path=self.parse_ref.mod_path,
4019
+ orig_src=self.parse_ref.source,
4000
4020
  name=token.type,
4001
4021
  value=token.value[2:] if token.type == Tok.KWESC_NAME else token.value,
4002
4022
  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."""
@@ -7,6 +7,7 @@ body field.
7
7
  """
8
8
 
9
9
  import jaclang.compiler.absyntree as ast
10
+ from jaclang.compiler.constant import Tokens as Tok
10
11
  from jaclang.compiler.passes import Pass
11
12
  from jaclang.compiler.passes.main import SubNodeTabPass
12
13
  from jaclang.compiler.symtable import Symbol, SymbolTable
@@ -90,6 +91,10 @@ class DeclImplMatchPass(Pass):
90
91
  raise self.ice(
91
92
  f"Expected AstImplNeedingNode, got {valid_decl.__class__.__name__}. Not possible."
92
93
  )
94
+
95
+ # Ensure if it's an ability def impl, the parameters are matched.
96
+ self.validate_params_match(sym, decl_node.name_of)
97
+
93
98
  valid_decl.body = sym.decl.name_of
94
99
  sym.decl.name_of.decl_link = valid_decl
95
100
  for idx, a in enumerate(sym.decl.name_of.target.archs):
@@ -97,5 +102,83 @@ class DeclImplMatchPass(Pass):
97
102
  a.name_spec.sym = name_of_links[idx].sym
98
103
  sym.decl.name_of.sym_tab.tab.update(valid_decl.sym_tab.tab)
99
104
  valid_decl.sym_tab.tab = sym.decl.name_of.sym_tab.tab
105
+
100
106
  for i in sym_tab.kid:
101
107
  self.connect_def_impl(i)
108
+
109
+ def validate_params_match(self, sym: Symbol, valid_decl: ast.AstSymbolNode) -> None:
110
+ """Validate if the parameters match."""
111
+ if (
112
+ isinstance(valid_decl, ast.Ability)
113
+ and isinstance(sym.decl.name_of, ast.AbilityDef)
114
+ and isinstance(valid_decl.signature, ast.FuncSignature)
115
+ and isinstance(sym.decl.name_of.signature, ast.FuncSignature)
116
+ ):
117
+
118
+ params_decl = valid_decl.signature.params
119
+ params_defn = sym.decl.name_of.signature.params
120
+
121
+ if params_decl and params_defn:
122
+ # Check if the parameter count is matched.
123
+ if len(params_defn.items) != len(params_decl.items):
124
+ self.error(
125
+ f"Parameter count mismatch for ability {sym.sym_name}.",
126
+ sym.decl.name_of.name_spec,
127
+ )
128
+ self.error(
129
+ f"From the declaration of {valid_decl.name_spec.sym_name}.",
130
+ valid_decl.name_spec,
131
+ )
132
+ else:
133
+ # Copy the parameter names from the declaration to the definition.
134
+ for idx in range(len(params_defn.items)):
135
+ params_decl.items[idx] = params_defn.items[idx]
136
+ for idx in range(len(params_defn.kid)):
137
+ params_decl.kid[idx] = params_defn.kid[idx]
138
+
139
+ def exit_architype(self, node: ast.Architype) -> None:
140
+ """Exit Architype."""
141
+ if node.arch_type.name == Tok.KW_OBJECT and isinstance(
142
+ node.body, ast.SubNodeList
143
+ ):
144
+
145
+ found_default_init = False
146
+ for stmnt in node.body.items:
147
+ if not isinstance(stmnt, ast.ArchHas):
148
+ continue
149
+ for var in stmnt.vars.items:
150
+ if (var.value is not None) or (var.defer):
151
+ found_default_init = True
152
+ else:
153
+ if found_default_init:
154
+ self.error(
155
+ f"Non default attribute '{var.name.value}' follows default attribute",
156
+ node_override=var.name,
157
+ )
158
+ break
159
+
160
+ post_init_vars: list[ast.HasVar] = []
161
+ postinit_method: ast.Ability | None = None
162
+
163
+ for item in node.body.items:
164
+
165
+ if isinstance(item, ast.ArchHas):
166
+ for var in item.vars.items:
167
+ if var.defer:
168
+ post_init_vars.append(var)
169
+
170
+ elif isinstance(item, ast.Ability):
171
+ if item.is_abstract:
172
+ continue
173
+ if (
174
+ isinstance(item.name_ref, ast.SpecialVarRef)
175
+ and item.name_ref.name == "KW_POST_INIT"
176
+ ):
177
+ postinit_method = item
178
+
179
+ # Check if postinit needed and not provided.
180
+ if len(post_init_vars) != 0 and (postinit_method is None):
181
+ self.error(
182
+ 'Missing "postinit" method required by un initialized attribute(s).',
183
+ node_override=post_init_vars[0].name_spec,
184
+ ) # We show the error on the first uninitialized var.
@@ -156,8 +156,7 @@ class DefUsePass(Pass):
156
156
  def enter_index_slice(self, node: ast.IndexSlice) -> None:
157
157
  """Sub objects.
158
158
 
159
- start: Optional[ExprType],
160
- stop: Optional[ExprType],
159
+ slices: list[Slice],
161
160
  is_range: bool,
162
161
  """
163
162