jaclang 0.0.5__py3-none-any.whl → 0.0.8__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 (94) hide show
  1. jaclang/__init__.py +2 -1
  2. jaclang/cli/__jac_gen__/__init__.py +0 -0
  3. jaclang/cli/__jac_gen__/cli.py +175 -0
  4. jaclang/cli/__jac_gen__/cmds.py +132 -0
  5. jaclang/cli/cli.jac +2 -2
  6. jaclang/cli/cmds.jac +8 -2
  7. jaclang/cli/impl/__jac_gen__/__init__.py +0 -0
  8. jaclang/cli/impl/__jac_gen__/cli_impl.py +16 -0
  9. jaclang/cli/impl/__jac_gen__/cmds_impl.py +26 -0
  10. jaclang/cli/impl/cli_impl.jac +25 -8
  11. jaclang/cli/impl/cmds_impl.jac +35 -6
  12. jaclang/core/__jac_gen__/__init__.py +0 -0
  13. jaclang/core/__jac_gen__/primitives.py +567 -0
  14. jaclang/core/impl/__jac_gen__/__init__.py +0 -0
  15. jaclang/core/impl/__jac_gen__/arch_impl.py +24 -0
  16. jaclang/core/impl/__jac_gen__/element_impl.py +26 -0
  17. jaclang/core/impl/__jac_gen__/exec_ctx_impl.py +12 -0
  18. jaclang/core/impl/__jac_gen__/memory_impl.py +14 -0
  19. jaclang/core/impl/element_impl.jac +3 -3
  20. jaclang/core/impl/exec_ctx_impl.jac +3 -6
  21. jaclang/core/primitives.jac +4 -3
  22. jaclang/jac/absyntree.py +555 -180
  23. jaclang/jac/constant.py +6 -0
  24. jaclang/jac/importer.py +34 -56
  25. jaclang/jac/langserve.py +26 -0
  26. jaclang/jac/lexer.py +35 -3
  27. jaclang/jac/parser.py +146 -115
  28. jaclang/jac/passes/blue/__init__.py +8 -3
  29. jaclang/jac/passes/blue/ast_build_pass.py +454 -305
  30. jaclang/jac/passes/blue/blue_pygen_pass.py +112 -74
  31. jaclang/jac/passes/blue/decl_def_match_pass.py +49 -277
  32. jaclang/jac/passes/blue/import_pass.py +1 -1
  33. jaclang/jac/passes/blue/pyout_pass.py +74 -0
  34. jaclang/jac/passes/blue/semantic_check_pass.py +37 -0
  35. jaclang/jac/passes/blue/sym_tab_build_pass.py +1045 -0
  36. jaclang/jac/passes/blue/tests/test_ast_build_pass.py +2 -2
  37. jaclang/jac/passes/blue/tests/test_blue_pygen_pass.py +9 -28
  38. jaclang/jac/passes/blue/tests/test_decl_def_match_pass.py +13 -22
  39. jaclang/jac/passes/blue/tests/test_sym_tab_build_pass.py +22 -0
  40. jaclang/jac/passes/ir_pass.py +8 -6
  41. jaclang/jac/passes/purple/__jac_gen__/__init__.py +0 -0
  42. jaclang/jac/passes/purple/__jac_gen__/analyze_pass.py +37 -0
  43. jaclang/jac/passes/purple/__jac_gen__/purple_pygen_pass.py +305 -0
  44. jaclang/jac/passes/purple/impl/__jac_gen__/__init__.py +0 -0
  45. jaclang/jac/passes/purple/impl/__jac_gen__/purple_pygen_pass_impl.py +23 -0
  46. jaclang/jac/passes/purple/impl/purple_pygen_pass_impl.jac +2 -5
  47. jaclang/jac/symtable.py +154 -0
  48. jaclang/jac/tests/fixtures/__jac_gen__/__init__.py +0 -0
  49. jaclang/jac/tests/fixtures/__jac_gen__/hello_world.py +16 -0
  50. jaclang/jac/tests/fixtures/fam.jac +7 -8
  51. jaclang/jac/tests/fixtures/mod_doc_test.jac +1 -0
  52. jaclang/jac/tests/test_parser.py +8 -0
  53. jaclang/jac/transform.py +41 -14
  54. jaclang/jac/transpiler.py +18 -9
  55. jaclang/utils/fstring_parser.py +2 -2
  56. jaclang/utils/helpers.py +41 -0
  57. jaclang/utils/lang_tools.py +12 -2
  58. jaclang/utils/test.py +41 -0
  59. jaclang/vendor/__init__.py +1 -0
  60. jaclang/vendor/pygls/__init__.py +25 -0
  61. jaclang/vendor/pygls/capabilities.py +502 -0
  62. jaclang/vendor/pygls/client.py +176 -0
  63. jaclang/vendor/pygls/constants.py +26 -0
  64. jaclang/vendor/pygls/exceptions.py +220 -0
  65. jaclang/vendor/pygls/feature_manager.py +241 -0
  66. jaclang/vendor/pygls/lsp/__init__.py +139 -0
  67. jaclang/vendor/pygls/lsp/client.py +2224 -0
  68. jaclang/vendor/pygls/lsprotocol/__init__.py +2 -0
  69. jaclang/vendor/pygls/lsprotocol/_hooks.py +1233 -0
  70. jaclang/vendor/pygls/lsprotocol/converters.py +17 -0
  71. jaclang/vendor/pygls/lsprotocol/types.py +12820 -0
  72. jaclang/vendor/pygls/lsprotocol/validators.py +47 -0
  73. jaclang/vendor/pygls/progress.py +79 -0
  74. jaclang/vendor/pygls/protocol.py +1184 -0
  75. jaclang/vendor/pygls/server.py +620 -0
  76. jaclang/vendor/pygls/uris.py +184 -0
  77. jaclang/vendor/pygls/workspace/__init__.py +81 -0
  78. jaclang/vendor/pygls/workspace/position.py +204 -0
  79. jaclang/vendor/pygls/workspace/text_document.py +234 -0
  80. jaclang/vendor/pygls/workspace/workspace.py +311 -0
  81. {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/METADATA +1 -1
  82. jaclang-0.0.8.dist-info/RECORD +118 -0
  83. jaclang/core/jaclang.jac +0 -62
  84. jaclang/jac/passes/blue/tests/test_type_analyze_pass.py +0 -53
  85. jaclang/jac/passes/blue/type_analyze_pass.py +0 -728
  86. jaclang/jac/sym_table.py +0 -127
  87. jaclang-0.0.5.dist-info/RECORD +0 -73
  88. /jaclang/{utils → vendor}/sly/__init__.py +0 -0
  89. /jaclang/{utils → vendor}/sly/docparse.py +0 -0
  90. /jaclang/{utils → vendor}/sly/lex.py +0 -0
  91. /jaclang/{utils → vendor}/sly/yacc.py +0 -0
  92. {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/WHEEL +0 -0
  93. {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/entry_points.txt +0 -0
  94. {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,154 @@
1
+ """Jac Symbol Table."""
2
+ from __future__ import annotations
3
+
4
+ from enum import Enum
5
+ from typing import Optional, TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ import jaclang.jac.absyntree as ast
9
+
10
+
11
+ class SymbolType(Enum):
12
+ """Symbol types."""
13
+
14
+ VAR = "var"
15
+ ABILITY = "ability"
16
+ ARCH = "arch"
17
+ IMPL = "impl"
18
+ HAS = "field"
19
+
20
+
21
+ class SymbolHitType(Enum):
22
+ """Symbol types."""
23
+
24
+ DECL = "decl"
25
+ DEFN = "defn"
26
+ DECL_DEFN = "decl_defn"
27
+ USE = "use"
28
+
29
+
30
+ class Symbol:
31
+ """Symbol."""
32
+
33
+ def __init__(
34
+ self,
35
+ name: str,
36
+ sym_type: SymbolType,
37
+ typ: Optional[type] = None,
38
+ decl: Optional[ast.AstNode] = None,
39
+ defn: Optional[list[ast.AstNode]] = None,
40
+ uses: Optional[list[ast.AstNode]] = None,
41
+ ) -> None:
42
+ """Initialize."""
43
+ self.name = name
44
+ self.sym_type = sym_type
45
+ self.typ = typ
46
+ self.decl = decl
47
+ self.defn: list[ast.AstNode] = defn if defn else []
48
+ self.uses: list[ast.AstNode] = uses if uses else []
49
+
50
+ def __repr__(self) -> str:
51
+ """Repr."""
52
+ return (
53
+ f"Symbol({self.name}, {self.sym_type}, {self.typ}, "
54
+ f"{self.decl}, {self.defn}, {self.uses})"
55
+ )
56
+
57
+
58
+ class SymbolTable:
59
+ """Symbol Table."""
60
+
61
+ def __init__(
62
+ self, name: str, key_node: ast.AstNode, parent: Optional[SymbolTable] = None
63
+ ) -> None:
64
+ """Initialize."""
65
+ self.name = name
66
+ self.key_node = key_node
67
+ self.parent = parent if parent else self
68
+ self.kid: list[SymbolTable] = []
69
+ self.tab: dict[str, Symbol] = {}
70
+
71
+ def has_parent(self) -> bool:
72
+ """Check if has parent."""
73
+ return self.parent != self
74
+
75
+ def get_parent(self) -> SymbolTable:
76
+ """Get parent."""
77
+ if self.parent == self:
78
+ raise Exception("No parent")
79
+ return self.parent
80
+
81
+ def lookup(
82
+ self, name: str, sym_hit: Optional[SymbolHitType] = None, deep: bool = True
83
+ ) -> Optional[Symbol]:
84
+ """Lookup a variable in the symbol table."""
85
+ if name in self.tab and (
86
+ not sym_hit
87
+ or (sym_hit == SymbolHitType.DECL and self.tab[name].decl)
88
+ or (sym_hit == SymbolHitType.DEFN and len(self.tab[name].defn))
89
+ or (
90
+ sym_hit == SymbolHitType.DECL_DEFN
91
+ and (self.tab[name].decl or len(self.tab[name].defn))
92
+ )
93
+ or (sym_hit == SymbolHitType.USE and len(self.tab[name].uses))
94
+ ):
95
+ return self.tab[name]
96
+ if deep and self.has_parent():
97
+ return self.get_parent().lookup(name, sym_hit, deep)
98
+ return None
99
+
100
+ def insert(
101
+ self,
102
+ name: str,
103
+ sym_type: SymbolType,
104
+ sym_hit: SymbolHitType,
105
+ node: ast.AstNode,
106
+ single: bool = False,
107
+ ) -> Optional[ast.AstNode]:
108
+ """Set a variable in the symbol table.
109
+
110
+ Returns original symbol single check fails.
111
+ """
112
+ if single:
113
+ if (
114
+ sym_hit in [SymbolHitType.DECL, SymbolHitType.DECL_DEFN]
115
+ and name in self.tab
116
+ and self.tab[name].decl
117
+ ):
118
+ return self.tab[name].decl
119
+ elif (
120
+ sym_hit in [SymbolHitType.DEFN, SymbolHitType.DECL_DEFN]
121
+ and name in self.tab
122
+ and len(self.tab[name].defn)
123
+ ):
124
+ return self.tab[name].defn[-1]
125
+ elif (
126
+ sym_hit == SymbolHitType.USE
127
+ and name in self.tab
128
+ and len(self.tab[name].uses)
129
+ ):
130
+ return self.tab[name].uses[-1]
131
+ if name not in self.tab:
132
+ self.tab[name] = Symbol(name=name, sym_type=sym_type)
133
+ if sym_hit == SymbolHitType.DECL:
134
+ self.tab[name].decl = node
135
+ elif sym_hit == SymbolHitType.DEFN:
136
+ self.tab[name].defn.append(node)
137
+ elif sym_hit == SymbolHitType.DECL_DEFN:
138
+ self.tab[name].defn.append(node)
139
+ if not self.tab[name].decl:
140
+ self.tab[name].decl = node
141
+ elif sym_hit == SymbolHitType.USE:
142
+ self.tab[name].uses.append(node)
143
+
144
+ def push_scope(self, name: str, key_node: ast.AstNode) -> SymbolTable:
145
+ """Push a new scope onto the symbol table."""
146
+ self.kid.append(SymbolTable(name, key_node, self))
147
+ return self.kid[-1]
148
+
149
+ def __repr__(self) -> str:
150
+ """Repr."""
151
+ out = f"{self.name} {super().__repr__()}:\n"
152
+ for k, v in self.tab.items():
153
+ out += f" {k}: {v}\n"
154
+ return out
File without changes
@@ -0,0 +1,16 @@
1
+ """ Basic Hello World function """ # 0 1
2
+ from __future__ import annotations
3
+ import traceback as __jac_traceback__ # -1 0
4
+ from jaclang import handle_jac_error as __jac_error__ # -1 0
5
+ def hello(): # 0 3
6
+ try: # 0 3
7
+ return "Hello World!" # 0 4
8
+ except Exception as e: # 0 3
9
+ tb = __jac_traceback__.extract_tb(e.__traceback__) # 0 3
10
+ __jac_tmp__ = __jac_error__(_jac_pycodestring_, e, tb) # 0 3
11
+ e.args = (f'{e.args[0]}\n' + __jac_tmp__,) + e.args[1:] if 'Jac error originates from...' not in str(e) else e.args # 0 3
12
+ raise e # 0 3
13
+
14
+ r""" JAC DEBUG INFO
15
+ /home/ninja/jaclang/jaclang/jac/tests/fixtures/hello_world.jac
16
+ JAC DEBUG INFO """
@@ -41,14 +41,13 @@ walker tourist {
41
41
  has passport: list[str];
42
42
 
43
43
  can make_visit with location|other exit {
44
- b=:g:stuff:w:tourist;
45
- a = spawn :g:stuff:w:tourist;
46
- a = spawn :w:tourist;
47
- a = <-[:g:edget:e:myedge:a==1,b==2]-;
48
- a = b +[:g:edget:e:myedge:a=1]+> c;
49
- a = b <+[:g:edget:e:myedge:a=1]+ c;
50
- a = <here> +[:g:edget:e:myedge:a=1]+> spawn :g:stuff:n:tourist;
51
- :g:stuff:w:tourist |> <here>;
44
+ b=tourist;
45
+ a = spawn tourist;
46
+ a = <-[myedge:a==1,b==2]-;
47
+ a = b +[myedge:a=1]+> c;
48
+ a = b <+[myedge:a=1]+ c;
49
+ a = <here> +[myedge:a=1]+> spawn tourist;
50
+ tourist |> <here>;
52
51
  report <h>.activities;
53
52
  }
54
53
 
@@ -0,0 +1 @@
1
+ with entry { print("hello"); }
@@ -45,6 +45,14 @@ class TestParser(TestCaseMicroSuite):
45
45
  self.assertFalse(prse.errors_had)
46
46
  self.assertIn("'name': 'KWESC_NAME', 'value': 'walker'", str(output.to_dict()))
47
47
 
48
+ def test_no_mod_doc(self) -> None:
49
+ """Basic test for parsing."""
50
+ lex = JacLexer(
51
+ mod_path="mod_doc_test.jac", input_ir=self.load_fixture("mod_doc_test.jac")
52
+ ).ir
53
+ prse = JacParser(mod_path="mod_doc_test.jac", input_ir=lex)
54
+ self.assertFalse(prse.errors_had)
55
+
48
56
  def test_parsing_jac_cli(self) -> None:
49
57
  """Basic test for parsing."""
50
58
  lex = JacLexer(
jaclang/jac/transform.py CHANGED
@@ -5,28 +5,55 @@ import os
5
5
  from abc import ABC, ABCMeta, abstractmethod
6
6
  from typing import Optional
7
7
 
8
-
9
8
  from jaclang.jac.absyntree import AstNode
9
+ from jaclang.jac.constant import Constants as Con, Values as Val
10
+ from jaclang.utils.helpers import add_line_numbers, clip_code_section
10
11
  from jaclang.utils.log import logging
11
- from jaclang.utils.sly.lex import LexerMeta
12
- from jaclang.utils.sly.yacc import ParserMeta
12
+ from jaclang.vendor.sly.lex import LexerMeta
13
+ from jaclang.vendor.sly.yacc import ParserMeta
14
+
15
+
16
+ class Alert:
17
+ """Alert interface."""
18
+
19
+ def __init__(self, msg: str, mod: str, line: int) -> None:
20
+ """Initialize alert."""
21
+ self.msg = msg
22
+ self.mod = mod
23
+ self.line = line
24
+
25
+ def __str__(self) -> str:
26
+ """Return string representation of alert."""
27
+ mod_path = os.path.relpath(self.mod, start=os.getcwd())
28
+ return f"{mod_path}, line {self.line}: {self.msg}"
13
29
 
14
30
 
15
31
  class TransformError(Exception):
16
32
  """Error during transformation."""
17
33
 
18
- def __init__(self, message: str, errors: list[str], warnings: list[str]) -> None:
34
+ def __init__(
35
+ self, message: str, errors: list[Alert], warnings: list[Alert]
36
+ ) -> None:
19
37
  """Initialize error."""
20
38
  self.errors = errors
21
39
  self.warnings = warnings
22
40
  if len(errors):
23
41
  message += "\nErrors:"
24
42
  for i in self.errors:
25
- message += "\n" + i
43
+ message += "\n" + str(i)
26
44
  if len(warnings):
27
45
  message += "\nWarnings:"
28
46
  for i in self.warnings:
29
- message += "\n" + i
47
+ message += "\n" + str(i)
48
+ if len(errors) or len(warnings):
49
+ jac_err_line = errors[0].line if len(errors) else warnings[0].line
50
+ with open(errors[0].mod, "r") as file:
51
+ jac_code_string = file.read()
52
+ message += f"\n{Con.JAC_ERROR_PREAMBLE}\n" + clip_code_section(
53
+ add_line_numbers(jac_code_string),
54
+ jac_err_line,
55
+ Val.JAC_ERROR_LINE_RANGE,
56
+ )
30
57
  super().__init__(message)
31
58
 
32
59
 
@@ -42,8 +69,8 @@ class Transform(ABC):
42
69
  ) -> None:
43
70
  """Initialize pass."""
44
71
  self.logger = logging.getLogger(self.__class__.__module__)
45
- self.errors_had = [] if not prior else prior.errors_had
46
- self.warnings_had = [] if not prior else prior.warnings_had
72
+ self.errors_had: list[Alert] = [] if not prior else prior.errors_had
73
+ self.warnings_had: list[Alert] = [] if not prior else prior.warnings_had
47
74
  self.cur_line = 0
48
75
  self.mod_path = mod_path
49
76
  self.rel_mod_path = (
@@ -58,15 +85,15 @@ class Transform(ABC):
58
85
 
59
86
  def log_error(self, msg: str) -> None:
60
87
  """Pass Error."""
61
- msg = f"Mod {self.rel_mod_path}: Line {self.cur_line}, " + msg
62
- self.errors_had.append(msg)
63
- self.logger.error(msg)
88
+ alrt = Alert(msg, self.mod_path, self.cur_line)
89
+ self.errors_had.append(alrt)
90
+ self.logger.error(str(alrt))
64
91
 
65
92
  def log_warning(self, msg: str) -> None:
66
93
  """Pass Error."""
67
- msg = f"Mod {self.rel_mod_path}: Line {self.cur_line}, " + msg
68
- self.warnings_had.append(msg)
69
- self.logger.warning(msg)
94
+ alrt = Alert(msg, self.mod_path, self.cur_line)
95
+ self.warnings_had.append(alrt)
96
+ self.logger.warning(str(alrt))
70
97
 
71
98
  def gen_exception(
72
99
  self, msg: str = "Error in code transform, see above for details."
jaclang/jac/transpiler.py CHANGED
@@ -5,8 +5,8 @@ import jaclang.jac.absyntree as ast
5
5
  from jaclang.jac.parser import JacLexer
6
6
  from jaclang.jac.parser import JacParser
7
7
  from jaclang.jac.passes import Pass
8
- from jaclang.jac.passes.blue import BluePygenPass, pass_schedule
9
- from jaclang.jac.transform import Transform
8
+ from jaclang.jac.passes.blue import BluePygenPass, PyOutPass, pass_schedule
9
+ from jaclang.jac.transform import Alert, Transform
10
10
 
11
11
 
12
12
  T = TypeVar("T", bound=Pass)
@@ -22,18 +22,24 @@ def jac_file_to_parse_tree(file_path: str, base_dir: str) -> Transform:
22
22
  return prse
23
23
 
24
24
 
25
- def transpile_jac_blue(file_path: str, base_dir: str) -> str:
25
+ def transpile_jac_blue(file_path: str, base_dir: str) -> list[Alert]:
26
26
  """Transpiler Jac file and return python code as string."""
27
27
  code = jac_file_to_pass(
28
- file_path=file_path, base_dir=base_dir, target=BluePygenPass
28
+ file_path=file_path,
29
+ base_dir=base_dir,
30
+ target=BluePygenPass,
31
+ schedule=pass_schedule,
29
32
  )
30
33
  if isinstance(code.ir, ast.Module):
31
- return code.ir.meta["py_code"]
34
+ print_pass = PyOutPass(
35
+ mod_path=file_path, input_ir=code.ir, base_path=base_dir, prior=code
36
+ )
32
37
  else:
33
- raise code.gen_exception("Transpilation of Jac file failed.")
38
+ return code.errors_had
39
+ return print_pass.errors_had
34
40
 
35
41
 
36
- def transpile_jac_purple(file_path: str, base_dir: str) -> str:
42
+ def transpile_jac_purple(file_path: str, base_dir: str) -> list[Alert]:
37
43
  """Transpiler Jac file and return python code as string."""
38
44
  from jaclang.jac.passes.purple import pass_schedule, PurplePygenPass
39
45
 
@@ -44,9 +50,12 @@ def transpile_jac_purple(file_path: str, base_dir: str) -> str:
44
50
  schedule=pass_schedule,
45
51
  )
46
52
  if isinstance(code.ir, ast.Module):
47
- return code.ir.meta["py_code"]
53
+ print_pass = PyOutPass(
54
+ mod_path=file_path, input_ir=code.ir, base_path=base_dir, prior=code
55
+ )
48
56
  else:
49
- raise code.gen_exception("Transpilation of Jac file failed.")
57
+ return code.errors_had
58
+ return print_pass.errors_had
50
59
 
51
60
 
52
61
  def jac_file_to_pass(
@@ -1,7 +1,7 @@
1
1
  # type: ignore
2
2
  """Python Like F-String Parser."""
3
- from jaclang.utils.sly.lex import Lexer
4
- from jaclang.utils.sly.yacc import Parser, YaccProduction
3
+ from jaclang.vendor.sly.lex import Lexer
4
+ from jaclang.vendor.sly.yacc import Parser, YaccProduction
5
5
 
6
6
  _ = None # For flake8 linting and sly compatibility
7
7
 
jaclang/utils/helpers.py CHANGED
@@ -1,7 +1,9 @@
1
1
  """Utility functions and classes for Jac compilation toolchain."""
2
2
  import re
3
+ import traceback
3
4
 
4
5
  import jaclang.jac.absyntree as ast
6
+ from jaclang.jac.constant import Constants as Con, Values as Val
5
7
 
6
8
 
7
9
  def pascal_to_snake(pascal_string: str) -> str:
@@ -31,6 +33,45 @@ def clip_code_section(s: str, target_line: int, line_range: int) -> str:
31
33
  return "\n".join(result)
32
34
 
33
35
 
36
+ def dedent_code_block(code: str) -> str:
37
+ """Dedent a code block."""
38
+ lines = code.splitlines()
39
+ min_indent = min(len(line) - len(line.lstrip()) for line in lines if line.strip())
40
+ dedented_lines = [line[min_indent:] for line in lines]
41
+ dedented_code = "\n".join(dedented_lines)
42
+ return dedented_code
43
+
44
+
45
+ def handle_jac_error(code_string: str, e: Exception, tb: traceback.StackSummary) -> str:
46
+ """Handle Jac Error."""
47
+ except_line = e.end_lineno if isinstance(e, SyntaxError) else list(tb)[-1].lineno
48
+ if not isinstance(except_line, int) or except_line == 0:
49
+ return ""
50
+ py_error_region = clip_code_section(
51
+ add_line_numbers(code_string), except_line, Val.JAC_ERROR_LINE_RANGE
52
+ )
53
+ try:
54
+ jac_err_line = int(code_string.splitlines()[except_line - 1].split()[-1])
55
+ mod_index = int(code_string.splitlines()[except_line - 1].split()[-2])
56
+ mod_paths = code_string.split(Con.JAC_DEBUG_SPLITTER)[1].strip().splitlines()
57
+ target_mod = mod_paths[mod_index]
58
+ with open(target_mod, "r") as file:
59
+ jac_code_string = file.read()
60
+ jac_error_region = clip_code_section(
61
+ add_line_numbers(jac_code_string), jac_err_line, Val.JAC_ERROR_LINE_RANGE
62
+ )
63
+ except Exception as e:
64
+ jac_error_region = str(e)
65
+ target_mod = ""
66
+ snippet = (
67
+ f"{Con.JAC_ERROR_PREAMBLE}\n"
68
+ f"{target_mod}\n"
69
+ f"JacCode Snippet:\n{jac_error_region}\n"
70
+ f"PyCode Snippet:\n{py_error_region}\n"
71
+ )
72
+ return snippet
73
+
74
+
34
75
  def get_ast_nodes_as_snake_case() -> list[str]:
35
76
  """Get all AST nodes as snake case."""
36
77
  import inspect
@@ -38,7 +38,14 @@ class AstNodeInfo:
38
38
  self.init_sig = inspect.signature(cls.__init__)
39
39
  self.kids: list[AstKidInfo] = []
40
40
  for param_name, param in self.init_sig.parameters.items():
41
- if param_name not in ["self", "parent", "kid", "line", "mod_link"]:
41
+ if param_name not in [
42
+ "self",
43
+ "parent",
44
+ "kid",
45
+ "line",
46
+ "mod_link",
47
+ "sym_tab",
48
+ ]:
42
49
  param_type = (
43
50
  param.annotation
44
51
  if param.annotation != inspect.Parameter.empty
@@ -59,7 +66,10 @@ class AstTool:
59
66
  source_code = inspect.getsource(module)
60
67
  classes = inspect.getmembers(module, inspect.isclass)
61
68
  ast_node_classes = [
62
- AstNodeInfo(cls) for _, cls in classes if issubclass(cls, ast.AstNode)
69
+ AstNodeInfo(cls)
70
+ for _, cls in classes
71
+ if issubclass(cls, ast.AstNode)
72
+ and cls.__name__ not in ["AstNode", "OOPAccessNode", "WalkerStmtOnlyNode"]
63
73
  ]
64
74
  self.ast_classes = sorted(
65
75
  ast_node_classes,
jaclang/utils/test.py CHANGED
@@ -5,6 +5,8 @@ import os
5
5
  from abc import ABC, abstractmethod
6
6
  from unittest import TestCase as _TestCase
7
7
 
8
+ from jaclang.utils.helpers import get_ast_nodes_as_snake_case as ast_snakes
9
+
8
10
 
9
11
  class TestCase(_TestCase):
10
12
  """Base test case for Jaseci."""
@@ -65,6 +67,17 @@ class TestCaseMicroSuite(ABC, TestCase):
65
67
  cls, method_name, lambda self, f=file_path: self.micro_suite_test(f)
66
68
  )
67
69
 
70
+ directory = os.path.dirname(__file__) + "/../../examples/manual_code"
71
+ for filename in os.listdir(directory):
72
+ if os.path.isfile(os.path.join(directory, filename)) and filename.endswith(
73
+ ".jac"
74
+ ):
75
+ method_name = f"test_micro_{filename.replace('.jac', '')}"
76
+ file_path = os.path.join(directory, filename)
77
+ setattr(
78
+ cls, method_name, lambda self, f=file_path: self.micro_suite_test(f)
79
+ )
80
+
68
81
  directory = os.path.dirname(__file__) + "/../../examples/guess_game"
69
82
  for filename in os.listdir(directory):
70
83
  if os.path.isfile(os.path.join(directory, filename)) and filename.endswith(
@@ -90,3 +103,31 @@ class TestCaseMicroSuite(ABC, TestCase):
90
103
  def micro_suite_test(self, filename: str) -> None:
91
104
  """Test micro jac file."""
92
105
  pass
106
+
107
+
108
+ class AstSyncTestMixin:
109
+ """Mixin for testing AST sync."""
110
+
111
+ TargetPass = None
112
+
113
+ def test_pass_ast_complete(self) -> None:
114
+ """Test for enter/exit name diffs with parser."""
115
+ ast_func_names = [
116
+ x
117
+ for x in ast_snakes()
118
+ if x not in ["ast_node", "o_o_p_access_node", "walker_stmt_only_node"]
119
+ ]
120
+ pygen_func_names = []
121
+ for name, value in inspect.getmembers(self.TargetPass):
122
+ if (
123
+ (name.startswith("enter_") or name.startswith("exit_"))
124
+ and inspect.isfunction(value)
125
+ and not getattr(self.TargetPass.__base__, value.__name__, False) # type: ignore
126
+ and value.__qualname__.split(".")[0]
127
+ == self.TargetPass.__name__.replace("enter_", "").replace("exit_", "") # type: ignore
128
+ ):
129
+ pygen_func_names.append(name.replace("enter_", "").replace("exit_", ""))
130
+ for name in pygen_func_names:
131
+ self.assertIn(name, ast_func_names) # type: ignore
132
+ for name in ast_func_names:
133
+ self.assertIn(name, pygen_func_names) # type: ignore
@@ -0,0 +1 @@
1
+ """Vendor packages for JACLang."""
@@ -0,0 +1,25 @@
1
+ ############################################################################
2
+ # Original work Copyright 2018 Palantir Technologies, Inc. #
3
+ # Original work licensed under the MIT License. #
4
+ # See ThirdPartyNotices.txt in the project root for license information. #
5
+ # All modifications Copyright (c) Open Law Library. All rights reserved. #
6
+ # #
7
+ # Licensed under the Apache License, Version 2.0 (the "License") #
8
+ # you may not use this file except in compliance with the License. #
9
+ # You may obtain a copy of the License at #
10
+ # #
11
+ # http: // www.apache.org/licenses/LICENSE-2.0 #
12
+ # #
13
+ # Unless required by applicable law or agreed to in writing, software #
14
+ # distributed under the License is distributed on an "AS IS" BASIS, #
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
16
+ # See the License for the specific language governing permissions and #
17
+ # limitations under the License. #
18
+ ############################################################################
19
+ import os
20
+ import sys
21
+
22
+ IS_WIN = os.name == "nt"
23
+ IS_PYODIDE = "pyodide" in sys.modules
24
+
25
+ pygls = "pygls"