jaclang 0.7.1__py3-none-any.whl → 0.7.2__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 (48) hide show
  1. jaclang/compiler/absyntree.py +51 -14
  2. jaclang/compiler/passes/main/def_impl_match_pass.py +9 -3
  3. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +20 -1
  4. jaclang/compiler/passes/main/import_pass.py +4 -1
  5. jaclang/compiler/passes/main/pyast_gen_pass.py +14 -6
  6. jaclang/compiler/passes/main/pyast_load_pass.py +2 -1
  7. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +6 -1
  8. jaclang/compiler/passes/main/pyout_pass.py +3 -1
  9. jaclang/compiler/passes/main/tests/test_import_pass.py +8 -0
  10. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  11. jaclang/compiler/passes/tool/jac_formatter_pass.py +14 -2
  12. jaclang/compiler/passes/tool/tests/fixtures/doc_string.jac +15 -0
  13. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +7 -5
  14. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
  15. jaclang/compiler/symtable.py +21 -1
  16. jaclang/core/aott.py +107 -11
  17. jaclang/core/construct.py +171 -5
  18. jaclang/core/llms/anthropic.py +31 -2
  19. jaclang/core/llms/base.py +3 -3
  20. jaclang/core/llms/groq.py +4 -1
  21. jaclang/core/llms/huggingface.py +4 -1
  22. jaclang/core/llms/ollama.py +4 -1
  23. jaclang/core/llms/openai.py +6 -2
  24. jaclang/core/llms/togetherai.py +4 -1
  25. jaclang/langserve/engine.py +99 -115
  26. jaclang/langserve/server.py +27 -5
  27. jaclang/langserve/tests/fixtures/circle_pure.impl.jac +8 -4
  28. jaclang/langserve/tests/fixtures/circle_pure.jac +2 -2
  29. jaclang/langserve/tests/test_server.py +123 -0
  30. jaclang/langserve/utils.py +100 -10
  31. jaclang/plugin/default.py +25 -83
  32. jaclang/plugin/feature.py +10 -12
  33. jaclang/plugin/tests/test_features.py +0 -33
  34. jaclang/settings.py +1 -0
  35. jaclang/tests/fixtures/byllmissue.jac +3 -0
  36. jaclang/tests/fixtures/hash_init_check.jac +17 -0
  37. jaclang/tests/fixtures/math_question.jpg +0 -0
  38. jaclang/tests/fixtures/nosigself.jac +19 -0
  39. jaclang/tests/fixtures/walker_override.jac +21 -0
  40. jaclang/tests/fixtures/with_llm_vision.jac +25 -0
  41. jaclang/tests/test_language.py +61 -11
  42. jaclang/utils/treeprinter.py +19 -2
  43. {jaclang-0.7.1.dist-info → jaclang-0.7.2.dist-info}/METADATA +3 -2
  44. {jaclang-0.7.1.dist-info → jaclang-0.7.2.dist-info}/RECORD +46 -41
  45. jaclang/core/memory.py +0 -48
  46. jaclang/core/shelve_storage.py +0 -55
  47. {jaclang-0.7.1.dist-info → jaclang-0.7.2.dist-info}/WHEEL +0 -0
  48. {jaclang-0.7.1.dist-info → jaclang-0.7.2.dist-info}/entry_points.txt +0 -0
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import ast as ast3
6
+ import os
6
7
  from hashlib import md5
7
8
  from types import EllipsisType
8
9
  from typing import Any, Callable, Generic, Optional, Sequence, Type, TypeVar
@@ -31,7 +32,6 @@ class AstNode:
31
32
  self.kid: list[AstNode] = [x.set_parent(self) for x in kid]
32
33
  self.sym_tab: Optional[SymbolTable] = None
33
34
  self._sub_node_tab: dict[type, list[AstNode]] = {}
34
- self._typ: type = type(None)
35
35
  self.gen: CodeGenTarget = CodeGenTarget()
36
36
  self.meta: dict[str, str] = {}
37
37
  self.loc: CodeLocInfo = CodeLocInfo(*self.resolve_tok_range())
@@ -111,11 +111,15 @@ class AstNode:
111
111
 
112
112
  return Pass.get_all_sub_nodes(node=self, typ=typ, brute_force=brute_force)
113
113
 
114
- def parent_of_type(self, typ: Type[T]) -> T:
114
+ def find_parent_of_type(self, typ: Type[T]) -> Optional[T]:
115
115
  """Get parent of type."""
116
116
  from jaclang.compiler.passes import Pass
117
117
 
118
- ret = Pass.has_parent_of_type(node=self, typ=typ)
118
+ return Pass.has_parent_of_type(node=self, typ=typ)
119
+
120
+ def parent_of_type(self, typ: Type[T]) -> T:
121
+ """Get parent of type."""
122
+ ret = self.find_parent_of_type(typ)
119
123
  if isinstance(ret, typ):
120
124
  return ret
121
125
  else:
@@ -178,6 +182,8 @@ class AstSymbolNode(AstNode):
178
182
  self.sym_link: Optional[Symbol] = None
179
183
  self.sym_name: str = sym_name
180
184
  self.sym_name_node = sym_name_node
185
+ if isinstance(self.sym_name_node, NameSpec):
186
+ self.sym_name_node.name_of = self
181
187
  self.sym_type: SymbolType = sym_type
182
188
  self.sym_info: SymbolInfo = SymbolInfo()
183
189
  self.py_ctx_func: Type[ast3.AST] = ast3.Load
@@ -258,8 +264,11 @@ class WalkerStmtOnlyNode(AstNode):
258
264
  class AstImplOnlyNode(AstNode):
259
265
  """ImplOnly node type for Jac Ast."""
260
266
 
261
- def __init__(self, body: SubNodeList, decl_link: Optional[AstNode]) -> None:
267
+ def __init__(
268
+ self, target: ArchRefChain, body: SubNodeList, decl_link: Optional[AstNode]
269
+ ) -> None:
262
270
  """Initialize impl only node."""
271
+ self.target = target
263
272
  self.body = body
264
273
  self.decl_link = decl_link
265
274
 
@@ -304,6 +313,10 @@ class CodeBlockStmt(AstNode):
304
313
  class NameSpec(AtomExpr, EnumBlockStmt):
305
314
  """NameSpec node type for Jac Ast."""
306
315
 
316
+ def __init__(self) -> None:
317
+ """Initialize name spec node."""
318
+ self.name_of: AstSymbolNode = self
319
+
307
320
 
308
321
  class ArchSpec(ElementStmt, CodeBlockStmt, AstSymbolNode, AstDocNode, AstSemStrNode):
309
322
  """ArchSpec node type for Jac Ast."""
@@ -392,7 +405,7 @@ class Module(AstDocNode):
392
405
  body: Sequence[ElementStmt | String | EmptyToken],
393
406
  is_imported: bool,
394
407
  kid: Sequence[AstNode],
395
- test_mod: Optional[Module] = None,
408
+ stub_only: bool = False,
396
409
  registry: Optional[SemRegistry] = None,
397
410
  ) -> None:
398
411
  """Initialize whole program node."""
@@ -400,13 +413,37 @@ class Module(AstDocNode):
400
413
  self.source = source
401
414
  self.body = body
402
415
  self.is_imported = is_imported
416
+ self.stub_only = stub_only
403
417
  self.impl_mod: list[Module] = []
404
- self.test_mod = test_mod
418
+ self.test_mod: list[Module] = []
405
419
  self.mod_deps: dict[str, Module] = {}
406
420
  self.registry = registry
407
421
  AstNode.__init__(self, kid=kid)
408
422
  AstDocNode.__init__(self, doc=doc)
409
423
 
424
+ @property
425
+ def annexable_by(self) -> Optional[str]:
426
+ """Get annexable by."""
427
+ if not self.stub_only and self.loc.mod_path.endswith("impl.jac"):
428
+ head_mod_name = self.name.split(".")[0]
429
+ potential_path = os.path.join(
430
+ os.path.dirname(self.loc.mod_path),
431
+ f"{head_mod_name}.jac",
432
+ )
433
+ if os.path.exists(potential_path):
434
+ return potential_path
435
+ if os.path.split(os.path.dirname(self.loc.mod_path))[-1].endswith(".impl"):
436
+ head_mod_name = os.path.split(os.path.dirname(self.loc.mod_path))[
437
+ -1
438
+ ].split(".")[0]
439
+ potential_path = os.path.join(
440
+ os.path.dirname(os.path.dirname(self.loc.mod_path)),
441
+ f"{head_mod_name}.jac",
442
+ )
443
+ if os.path.exists(potential_path):
444
+ return potential_path
445
+ return None
446
+
410
447
  def normalize(self, deep: bool = False) -> bool:
411
448
  """Normalize module node."""
412
449
  res = True
@@ -841,7 +878,6 @@ class ArchDef(ArchSpec, AstImplOnlyNode):
841
878
  decl_link: Optional[Architype] = None,
842
879
  ) -> None:
843
880
  """Initialize arch def node."""
844
- self.target = target
845
881
  AstNode.__init__(self, kid=kid)
846
882
  AstSymbolNode.__init__(
847
883
  self,
@@ -851,7 +887,7 @@ class ArchDef(ArchSpec, AstImplOnlyNode):
851
887
  )
852
888
  AstDocNode.__init__(self, doc=doc)
853
889
  ArchSpec.__init__(self, decorators=decorators)
854
- AstImplOnlyNode.__init__(self, body=body, decl_link=decl_link)
890
+ AstImplOnlyNode.__init__(self, target=target, body=body, decl_link=decl_link)
855
891
 
856
892
  def normalize(self, deep: bool = False) -> bool:
857
893
  """Normalize arch def node."""
@@ -952,7 +988,6 @@ class EnumDef(ArchSpec, AstImplOnlyNode):
952
988
  decl_link: Optional[Enum] = None,
953
989
  ) -> None:
954
990
  """Initialize arch def node."""
955
- self.target = target
956
991
  AstNode.__init__(self, kid=kid)
957
992
  AstSymbolNode.__init__(
958
993
  self,
@@ -962,7 +997,7 @@ class EnumDef(ArchSpec, AstImplOnlyNode):
962
997
  )
963
998
  AstDocNode.__init__(self, doc=doc)
964
999
  ArchSpec.__init__(self, decorators=decorators)
965
- AstImplOnlyNode.__init__(self, body=body, decl_link=decl_link)
1000
+ AstImplOnlyNode.__init__(self, target=target, body=body, decl_link=decl_link)
966
1001
 
967
1002
  def normalize(self, deep: bool = False) -> bool:
968
1003
  """Normalize enum def node."""
@@ -1002,7 +1037,7 @@ class Ability(
1002
1037
  is_static: bool,
1003
1038
  is_abstract: bool,
1004
1039
  access: Optional[SubTag[Token]],
1005
- signature: Optional[FuncSignature | EventSignature],
1040
+ signature: FuncSignature | EventSignature,
1006
1041
  body: Optional[SubNodeList[CodeBlockStmt] | AbilityDef | FuncCall],
1007
1042
  kid: Sequence[AstNode],
1008
1043
  semstr: Optional[String] = None,
@@ -1111,7 +1146,6 @@ class AbilityDef(AstSymbolNode, ElementStmt, AstImplOnlyNode, CodeBlockStmt):
1111
1146
  decl_link: Optional[Ability] = None,
1112
1147
  ) -> None:
1113
1148
  """Initialize ability def node."""
1114
- self.target = target
1115
1149
  self.signature = signature
1116
1150
  self.decorators = decorators
1117
1151
  AstNode.__init__(self, kid=kid)
@@ -1122,7 +1156,7 @@ class AbilityDef(AstSymbolNode, ElementStmt, AstImplOnlyNode, CodeBlockStmt):
1122
1156
  sym_type=SymbolType.IMPL,
1123
1157
  )
1124
1158
  AstDocNode.__init__(self, doc=doc)
1125
- AstImplOnlyNode.__init__(self, body=body, decl_link=decl_link)
1159
+ AstImplOnlyNode.__init__(self, target=target, body=body, decl_link=decl_link)
1126
1160
 
1127
1161
  def normalize(self, deep: bool = False) -> bool:
1128
1162
  """Normalize ability def node."""
@@ -1394,7 +1428,7 @@ class HasVar(AstSymbolNode, AstTypedVarNode, AstSemStrNode):
1394
1428
  self,
1395
1429
  sym_name=name.value,
1396
1430
  sym_name_node=name,
1397
- sym_type=SymbolType.VAR,
1431
+ sym_type=SymbolType.HAS_VAR,
1398
1432
  )
1399
1433
  AstTypedVarNode.__init__(self, type_tag=type_tag)
1400
1434
  AstSemStrNode.__init__(self, semstr=semstr)
@@ -3066,6 +3100,7 @@ class ArchRef(NameSpec):
3066
3100
  sym_name_node=name_ref,
3067
3101
  sym_type=SymbolType.TYPE,
3068
3102
  )
3103
+ NameSpec.__init__(self)
3069
3104
 
3070
3105
  def normalize(self, deep: bool = False) -> bool:
3071
3106
  """Normalize ast node."""
@@ -3103,6 +3138,7 @@ class SpecialVarRef(NameSpec):
3103
3138
  sym_name_node=var,
3104
3139
  sym_type=SymbolType.VAR,
3105
3140
  )
3141
+ NameSpec.__init__(self)
3106
3142
 
3107
3143
  def normalize(self, deep: bool = False) -> bool:
3108
3144
  """Normalize ast node."""
@@ -3786,6 +3822,7 @@ class Name(Token, NameSpec):
3786
3822
  sym_name_node=self,
3787
3823
  sym_type=SymbolType.VAR,
3788
3824
  )
3825
+ NameSpec.__init__(self)
3789
3826
 
3790
3827
  def unparse(self) -> str:
3791
3828
  """Unparse name."""
@@ -9,7 +9,7 @@ body field.
9
9
  import jaclang.compiler.absyntree as ast
10
10
  from jaclang.compiler.passes import Pass
11
11
  from jaclang.compiler.passes.main import SubNodeTabPass
12
- from jaclang.compiler.symtable import Symbol, SymbolTable, SymbolType
12
+ from jaclang.compiler.symtable import Symbol, SymbolTable
13
13
 
14
14
 
15
15
  class DeclImplMatchPass(Pass):
@@ -39,11 +39,12 @@ class DeclImplMatchPass(Pass):
39
39
  def connect_def_impl(self, sym_tab: SymbolTable) -> None:
40
40
  """Connect Decls and Defs."""
41
41
  for sym in sym_tab.tab.values():
42
- if sym.sym_type == SymbolType.IMPL:
42
+ if isinstance(sym.decl, ast.AstImplOnlyNode):
43
43
  # currently strips the type info from impls
44
44
  arch_refs = [x[3:] for x in sym.sym_name.split(".")]
45
+ name_of_links = [] # to link archref names to decls
45
46
  lookup = sym_tab.lookup(arch_refs[0])
46
- # Below may need to be a while instead of if to skip over local
47
+ # If below may need to be a while instead of if to skip over local
47
48
  # import name collisions (see test: test_impl_decl_resolution_fix)
48
49
  if lookup and not isinstance(lookup.decl, ast.AstImplNeedingNode):
49
50
  lookup = sym_tab.parent.lookup(arch_refs[0])
@@ -52,6 +53,7 @@ class DeclImplMatchPass(Pass):
52
53
  if len(arch_refs) == 1 and lookup
53
54
  else lookup.defn[-1] if lookup else None
54
55
  )
56
+ name_of_links.append(decl_node) if decl_node else None
55
57
  for name in arch_refs[1:]:
56
58
  if decl_node:
57
59
  lookup = (
@@ -64,6 +66,7 @@ class DeclImplMatchPass(Pass):
64
66
  if len(arch_refs) == 1 and lookup
65
67
  else lookup.defn[-1] if lookup else None
66
68
  )
69
+ name_of_links.append(decl_node) if decl_node else None
67
70
  else:
68
71
  break
69
72
  if not decl_node:
@@ -76,6 +79,9 @@ class DeclImplMatchPass(Pass):
76
79
  continue
77
80
  decl_node.body = sym.decl # type: ignore
78
81
  sym.decl.decl_link = decl_node # type: ignore
82
+ for idx, a in enumerate(sym.decl.target.archs):
83
+ if isinstance(a.name_ref.sym_name_node, ast.NameSpec):
84
+ a.name_ref.sym_name_node.name_of = name_of_links[idx]
79
85
  decl_node.sym_tab.tab = sym.decl.sym_tab.tab # type: ignore
80
86
  for i in sym_tab.kid:
81
87
  self.connect_def_impl(i)
@@ -129,8 +129,10 @@ class FuseTypeInfoPass(Pass):
129
129
  if isinstance(mypy_node, MypyNodes.MemberExpr):
130
130
  if mypy_node in self.node_type_hash:
131
131
  t = str(self.node_type_hash[mypy_node])
132
- if "->" in t:
132
+ if "def" in t and "->" in t:
133
133
  t = t.split("->")[1].strip()
134
+ elif "def" in t:
135
+ t = "None"
134
136
  node.sym_info.typ = t
135
137
  else:
136
138
  self.__debug_print(f"{node.loc} MemberExpr type is not found")
@@ -181,6 +183,18 @@ class FuseTypeInfoPass(Pass):
181
183
  """Pass handler for name nodes."""
182
184
  self.__collect_type_from_symbol(node)
183
185
 
186
+ # Assign correct symbols to sym_link in case of
187
+ # AtomTrailer Object
188
+ if isinstance(node.parent, ast.AtomTrailer):
189
+ target_node = node.parent.target
190
+ if isinstance(target_node, ast.AstSymbolNode):
191
+ parent_symbol_table = target_node.sym_info.typ_sym_table
192
+ if isinstance(parent_symbol_table, ast.SymbolTable):
193
+ owner = parent_symbol_table.owner
194
+ if isinstance(owner, ast.AstSymbolNode):
195
+ target_node.sym_link = owner.sym_link
196
+ node.sym_link = parent_symbol_table.lookup(node.sym_name)
197
+
184
198
  @__handle_node
185
199
  def enter_module_path(self, node: ast.ModulePath) -> None:
186
200
  """Pass handler for ModulePath nodes."""
@@ -263,6 +277,11 @@ class FuseTypeInfoPass(Pass):
263
277
  "Getting type of 'HasVar' is only supported with AssignmentStmt"
264
278
  )
265
279
 
280
+ def exit_has_var(self, node: ast.HasVar) -> None:
281
+ """Pass handler for HasVar nodes."""
282
+ node.sym_info.typ = node.name.sym_info.typ
283
+ node.sym_info.typ_sym_table = node.name.sym_info.typ_sym_table
284
+
266
285
  @__handle_node
267
286
  def enter_multi_string(self, node: ast.MultiString) -> None:
268
287
  """Pass handler for MultiString nodes."""
@@ -63,6 +63,8 @@ class JacImportPass(Pass):
63
63
 
64
64
  def __annex_impl(self, node: ast.Module) -> None:
65
65
  """Annex impl and test modules."""
66
+ if node.stub_only:
67
+ return
66
68
  if not node.loc.mod_path:
67
69
  self.error("Module has no path")
68
70
  if not node.loc.mod_path.endswith(".jac"):
@@ -105,7 +107,7 @@ class JacImportPass(Pass):
105
107
  ) and cur_file.endswith(".test.jac"):
106
108
  mod = self.import_jac_mod_from_file(cur_file)
107
109
  if mod:
108
- node.test_mod = mod
110
+ node.test_mod.append(mod)
109
111
  node.add_kids_right([mod], pos_update=False)
110
112
  mod.parent = node
111
113
 
@@ -167,6 +169,7 @@ class JacImportPass(Pass):
167
169
  doc=None,
168
170
  body=[],
169
171
  is_imported=False,
172
+ stub_only=True,
170
173
  kid=[ast.EmptyToken()],
171
174
  )
172
175
 
@@ -54,6 +54,13 @@ class PyastGenPass(Pass):
54
54
  )
55
55
  ]
56
56
 
57
+ def enter_node(self, node: ast.AstNode) -> None:
58
+ """Enter node."""
59
+ if node.gen.py_ast:
60
+ self.prune()
61
+ return
62
+ super().enter_node(node)
63
+
57
64
  def exit_node(self, node: ast.AstNode) -> None:
58
65
  """Exit node."""
59
66
  super().exit_node(node)
@@ -325,7 +332,8 @@ class PyastGenPass(Pass):
325
332
  for pbody in node.impl_mod:
326
333
  pre_body = [*pre_body, *pbody.body]
327
334
  pre_body = [*pre_body, *clean_body]
328
- pre_body = [*pre_body, *node.test_mod.body] if node.test_mod else pre_body
335
+ for pbody in node.test_mod:
336
+ pre_body = [*pre_body, *pbody.body]
329
337
  body = (
330
338
  [
331
339
  self.sync(ast3.Expr(value=node.doc.gen.py_ast[0]), jac_node=node.doc),
@@ -676,9 +684,9 @@ class PyastGenPass(Pass):
676
684
  if isinstance(node.body, ast.ArchDef)
677
685
  else node.body.items if node.body else []
678
686
  ):
679
- if isinstance(i, ast.Ability) and i.signature:
687
+ if isinstance(i, ast.Ability):
680
688
  self.method_sigs.append(i.signature)
681
- if isinstance(node.body, ast.ArchDef):
689
+ if isinstance(node.body, ast.AstImplOnlyNode):
682
690
  self.traverse(node.body)
683
691
 
684
692
  def exit_architype(self, node: ast.Architype) -> None:
@@ -854,7 +862,7 @@ class PyastGenPass(Pass):
854
862
  doc: Optional[String],
855
863
  decorators: Optional[SubNodeList[ExprType]],
856
864
  """
857
- if isinstance(node.body, ast.EnumDef):
865
+ if isinstance(node.body, ast.AstImplOnlyNode):
858
866
  self.traverse(node.body)
859
867
 
860
868
  def exit_enum(self, node: ast.Enum) -> None:
@@ -920,7 +928,7 @@ class PyastGenPass(Pass):
920
928
  doc: Optional[String],
921
929
  decorators: Optional[SubNodeList[ExprType]],
922
930
  """
923
- if isinstance(node.body, ast.AbilityDef):
931
+ if isinstance(node.body, ast.AstImplOnlyNode):
924
932
  self.traverse(node.body)
925
933
 
926
934
  def exit_ability(self, node: ast.Ability) -> None:
@@ -1096,7 +1104,7 @@ class PyastGenPass(Pass):
1096
1104
  action = (
1097
1105
  node.semstr.gen.py_ast[0]
1098
1106
  if node.semstr
1099
- else self.sync(ast3.Constant(value=None))
1107
+ else self.sync(ast3.Constant(value=node.name_ref.sym_name))
1100
1108
  )
1101
1109
  return [
1102
1110
  self.sync(
@@ -127,7 +127,6 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
127
127
  is_imported=False,
128
128
  kid=valid,
129
129
  )
130
- ret.gen.py_ast = [node]
131
130
  return self.nu(ret)
132
131
 
133
132
  def proc_function_def(
@@ -209,6 +208,8 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
209
208
  kid = ([doc] if doc else []) + (
210
209
  [name, sig, valid_body] if sig else [name, valid_body]
211
210
  )
211
+ if not sig:
212
+ raise self.ice("Function signature not found")
212
213
  ret = ast.Ability(
213
214
  name_ref=name,
214
215
  is_async=False,
@@ -1,4 +1,9 @@
1
- """Jac to python ast link pass."""
1
+ """Jac to python ast link pass.
2
+
3
+ This pass is needed so cases where there are multiple Jac nodes relevant to a
4
+ single python node can be linked. For example FuncDef doesn't have a Name node
5
+ however Ability does.
6
+ """
2
7
 
3
8
  import ast as ast3
4
9
 
@@ -35,7 +35,9 @@ class PyOutPass(Pass):
35
35
  f"Unable to find module {node.loc.mod_path} or no code present.", node
36
36
  )
37
37
  return
38
- mods = [node] + self.get_all_sub_nodes(node, ast.Module)
38
+ mods = [node] + [
39
+ i for i in self.get_all_sub_nodes(node, ast.Module) if not i.stub_only
40
+ ]
39
41
  for mod in mods:
40
42
  mod_path, out_path_py, out_path_pyc = self.get_output_targets(mod)
41
43
  if os.path.exists(out_path_pyc) and os.path.getmtime(
@@ -41,3 +41,11 @@ class ImportPassPassTests(TestCase):
41
41
  self.assertIn("autoimpl", mod_names)
42
42
  self.assertIn("autoimpl.impl", mod_names)
43
43
  self.assertIn("autoimpl.something.else.impl", mod_names)
44
+
45
+ def test_annexalbe_by_discovery(self) -> None:
46
+ """Basic test for pass."""
47
+ state = jac_file_to_pass(
48
+ self.fixture_abs_path("incautoimpl.jac"), JacImportPass
49
+ )
50
+ for i in state.ir.get_all_sub_nodes(ast.Module):
51
+ self.assertEqual(i.annexable_by, self.fixture_abs_path("autoimpl.jac"))
@@ -59,6 +59,6 @@ class MypyTypeCheckPassTests(TestCase):
59
59
  self.assertIn("HasVar - species - Type: builtins.str", out)
60
60
  self.assertIn("myDog - Type: type_info.Dog", out)
61
61
  self.assertIn("Body - Type: type_info.Dog.Body", out)
62
- self.assertEqual(out.count("Type: builtins.str"), 27)
62
+ self.assertEqual(out.count("Type: builtins.str"), 28)
63
63
  for i in lis:
64
64
  self.assertNotIn(i, out)
@@ -421,7 +421,10 @@ class JacFormatPass(Pass):
421
421
  self.emit_ln(node, "")
422
422
  self.emit_ln(node, i.gen.jac)
423
423
  if isinstance(i, ast.Token) and i.name == Tok.KW_BY:
424
- self.emit(node, f"{i.gen.jac} ")
424
+ if not node.params:
425
+ self.emit(node, f"{i.gen.jac} ")
426
+ else:
427
+ self.emit(node, f" {i.gen.jac} ")
425
428
  else:
426
429
  if (
427
430
  line_break_needed
@@ -2402,7 +2405,16 @@ class JacFormatPass(Pass):
2402
2405
  and isinstance(node.parent.parent, ast.FString)
2403
2406
  ):
2404
2407
  self.emit(node, node.value)
2405
- self.emit(node, node.value)
2408
+ if "\n" in node.value:
2409
+ string_type = node.value[0:3]
2410
+ pure_string = node.value[3:-3]
2411
+ lines = pure_string.split("\n")
2412
+ self.emit(node, string_type)
2413
+ for line in lines[:-1]:
2414
+ self.emit_ln(node, line)
2415
+ self.emit_ln(node, f"{lines[-1]}{string_type}")
2416
+ else:
2417
+ self.emit(node, node.value)
2406
2418
 
2407
2419
  def enter_bool(self, node: ast.Bool) -> None:
2408
2420
  """Sub objects.
@@ -0,0 +1,15 @@
1
+ class foo {
2
+ """
3
+ doc string
4
+ """
5
+ can print_here() {
6
+ print("i'm here");
7
+ }
8
+
9
+ """this is a
10
+ multiline docstring
11
+ to test"""
12
+ can also_print() {
13
+ print("I'm in also");
14
+ }
15
+ }
@@ -44,8 +44,8 @@ class JacFormatPassTests(TestCaseMicroSuite, AstSyncTestMixin):
44
44
 
45
45
  if diff:
46
46
  print(f"Differences found in comparison:\n{diff}")
47
- # raise AssertionError("Files differ after formatting.")
48
- self.skipTest("Test failed, but skipping instead of failing.")
47
+ raise AssertionError("Files differ after formatting.")
48
+
49
49
  except FileNotFoundError:
50
50
  print(f"File not found: {original_file} or {formatted_file}")
51
51
  raise
@@ -76,6 +76,9 @@ class JacFormatPassTests(TestCaseMicroSuite, AstSyncTestMixin):
76
76
  self.compare_files(
77
77
  os.path.join(self.fixture_abs_path(""), "corelib_fmt.jac"),
78
78
  )
79
+ self.compare_files(
80
+ os.path.join(self.fixture_abs_path(""), "doc_string.jac"),
81
+ )
79
82
 
80
83
  def test_compare_myca_fixtures(self) -> None:
81
84
  """Tests if files in the myca fixtures directory do not change after being formatted."""
@@ -135,14 +138,13 @@ class JacFormatPassTests(TestCaseMicroSuite, AstSyncTestMixin):
135
138
  diff = "\n".join(unified_diff(before.splitlines(), after.splitlines()))
136
139
  self.assertFalse(diff, "AST structures differ after formatting.")
137
140
 
138
- except Exception:
141
+ except Exception as e:
139
142
  print(add_line_numbers(code_gen_pure.ir.source.code))
140
143
  print("\n+++++++++++++++++++++++++++++++++++++++\n")
141
144
  print(add_line_numbers(code_gen_format.ir.gen.jac))
142
145
  print("\n+++++++++++++++++++++++++++++++++++++++\n")
143
146
  print("\n".join(unified_diff(before.splitlines(), after.splitlines())))
144
- self.skipTest("Test failed, but skipping instead of failing.")
145
- # raise e
147
+ raise e
146
148
 
147
149
 
148
150
  JacFormatPassTests.self_attach_micro_tests()
@@ -30,7 +30,7 @@ class JacUnparseTests(TestCaseMicroSuite, AstSyncTestMixin):
30
30
  self.assertEqual(x, y)
31
31
  except Exception as e:
32
32
  print("\n".join(unified_diff(x.splitlines(), y.splitlines())))
33
- self.skipTest(f"Test failed, but skipping instead of failing: {e}")
33
+ raise e
34
34
 
35
35
  def micro_suite_test(self, filename: str) -> None:
36
36
  """Parse micro jac file."""
@@ -75,7 +75,6 @@ class JacUnparseTests(TestCaseMicroSuite, AstSyncTestMixin):
75
75
 
76
76
  except Exception as e:
77
77
  raise e
78
- # self.skipTest(f"Test failed, but skipping instead of failing: {e}")
79
78
 
80
79
 
81
80
  JacUnparseTests.self_attach_micro_tests()
@@ -17,7 +17,7 @@ class SymbolType(Enum):
17
17
 
18
18
  MODULE = "module" # LSP: Module
19
19
  MOD_VAR = "mod_var" # LSP: Variable
20
- VAR = "var" # LSP: Variable
20
+ VAR = "variable" # LSP: Variable
21
21
  IMM_VAR = "immutable" # LSP: Constant
22
22
  ABILITY = "ability" # LSP: Function
23
23
  OBJECT_ARCH = "object" # LSP: Class
@@ -54,6 +54,12 @@ class SymbolInfo:
54
54
  self.acc_tag: Optional[SymbolAccess] = acc_tag
55
55
  self.typ_sym_table: Optional[SymbolTable] = None
56
56
 
57
+ @property
58
+ def clean_type(self) -> str:
59
+ """Get clean type."""
60
+ ret_type = self.typ.replace("builtins.", "").replace("NoType", "")
61
+ return ret_type
62
+
57
63
 
58
64
  class SymbolAccess(Enum):
59
65
  """Symbol types."""
@@ -101,6 +107,20 @@ class Symbol:
101
107
  """Get sym_type."""
102
108
  return self.decl.sym_type
103
109
 
110
+ @property
111
+ def sym_path_str(self) -> str:
112
+ """Return a full path of the symbol."""
113
+ out = [self.defn[0].sym_name]
114
+ current_tab = self.parent_tab
115
+ while current_tab is not None:
116
+ out.append(current_tab.name)
117
+ if current_tab.has_parent():
118
+ current_tab = current_tab.parent
119
+ else:
120
+ break
121
+ out.reverse()
122
+ return ".".join(out)
123
+
104
124
  def add_defn(self, node: ast.AstSymbolNode) -> None:
105
125
  """Add defn."""
106
126
  self.defn.append(node)