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.
- jaclang/__init__.py +2 -1
- jaclang/cli/__jac_gen__/__init__.py +0 -0
- jaclang/cli/__jac_gen__/cli.py +175 -0
- jaclang/cli/__jac_gen__/cmds.py +132 -0
- jaclang/cli/cli.jac +2 -2
- jaclang/cli/cmds.jac +8 -2
- jaclang/cli/impl/__jac_gen__/__init__.py +0 -0
- jaclang/cli/impl/__jac_gen__/cli_impl.py +16 -0
- jaclang/cli/impl/__jac_gen__/cmds_impl.py +26 -0
- jaclang/cli/impl/cli_impl.jac +25 -8
- jaclang/cli/impl/cmds_impl.jac +35 -6
- jaclang/core/__jac_gen__/__init__.py +0 -0
- jaclang/core/__jac_gen__/primitives.py +567 -0
- jaclang/core/impl/__jac_gen__/__init__.py +0 -0
- jaclang/core/impl/__jac_gen__/arch_impl.py +24 -0
- jaclang/core/impl/__jac_gen__/element_impl.py +26 -0
- jaclang/core/impl/__jac_gen__/exec_ctx_impl.py +12 -0
- jaclang/core/impl/__jac_gen__/memory_impl.py +14 -0
- jaclang/core/impl/element_impl.jac +3 -3
- jaclang/core/impl/exec_ctx_impl.jac +3 -6
- jaclang/core/primitives.jac +4 -3
- jaclang/jac/absyntree.py +555 -180
- jaclang/jac/constant.py +6 -0
- jaclang/jac/importer.py +34 -56
- jaclang/jac/langserve.py +26 -0
- jaclang/jac/lexer.py +35 -3
- jaclang/jac/parser.py +146 -115
- jaclang/jac/passes/blue/__init__.py +8 -3
- jaclang/jac/passes/blue/ast_build_pass.py +454 -305
- jaclang/jac/passes/blue/blue_pygen_pass.py +112 -74
- jaclang/jac/passes/blue/decl_def_match_pass.py +49 -277
- jaclang/jac/passes/blue/import_pass.py +1 -1
- jaclang/jac/passes/blue/pyout_pass.py +74 -0
- jaclang/jac/passes/blue/semantic_check_pass.py +37 -0
- jaclang/jac/passes/blue/sym_tab_build_pass.py +1045 -0
- jaclang/jac/passes/blue/tests/test_ast_build_pass.py +2 -2
- jaclang/jac/passes/blue/tests/test_blue_pygen_pass.py +9 -28
- jaclang/jac/passes/blue/tests/test_decl_def_match_pass.py +13 -22
- jaclang/jac/passes/blue/tests/test_sym_tab_build_pass.py +22 -0
- jaclang/jac/passes/ir_pass.py +8 -6
- jaclang/jac/passes/purple/__jac_gen__/__init__.py +0 -0
- jaclang/jac/passes/purple/__jac_gen__/analyze_pass.py +37 -0
- jaclang/jac/passes/purple/__jac_gen__/purple_pygen_pass.py +305 -0
- jaclang/jac/passes/purple/impl/__jac_gen__/__init__.py +0 -0
- jaclang/jac/passes/purple/impl/__jac_gen__/purple_pygen_pass_impl.py +23 -0
- jaclang/jac/passes/purple/impl/purple_pygen_pass_impl.jac +2 -5
- jaclang/jac/symtable.py +154 -0
- jaclang/jac/tests/fixtures/__jac_gen__/__init__.py +0 -0
- jaclang/jac/tests/fixtures/__jac_gen__/hello_world.py +16 -0
- jaclang/jac/tests/fixtures/fam.jac +7 -8
- jaclang/jac/tests/fixtures/mod_doc_test.jac +1 -0
- jaclang/jac/tests/test_parser.py +8 -0
- jaclang/jac/transform.py +41 -14
- jaclang/jac/transpiler.py +18 -9
- jaclang/utils/fstring_parser.py +2 -2
- jaclang/utils/helpers.py +41 -0
- jaclang/utils/lang_tools.py +12 -2
- jaclang/utils/test.py +41 -0
- jaclang/vendor/__init__.py +1 -0
- jaclang/vendor/pygls/__init__.py +25 -0
- jaclang/vendor/pygls/capabilities.py +502 -0
- jaclang/vendor/pygls/client.py +176 -0
- jaclang/vendor/pygls/constants.py +26 -0
- jaclang/vendor/pygls/exceptions.py +220 -0
- jaclang/vendor/pygls/feature_manager.py +241 -0
- jaclang/vendor/pygls/lsp/__init__.py +139 -0
- jaclang/vendor/pygls/lsp/client.py +2224 -0
- jaclang/vendor/pygls/lsprotocol/__init__.py +2 -0
- jaclang/vendor/pygls/lsprotocol/_hooks.py +1233 -0
- jaclang/vendor/pygls/lsprotocol/converters.py +17 -0
- jaclang/vendor/pygls/lsprotocol/types.py +12820 -0
- jaclang/vendor/pygls/lsprotocol/validators.py +47 -0
- jaclang/vendor/pygls/progress.py +79 -0
- jaclang/vendor/pygls/protocol.py +1184 -0
- jaclang/vendor/pygls/server.py +620 -0
- jaclang/vendor/pygls/uris.py +184 -0
- jaclang/vendor/pygls/workspace/__init__.py +81 -0
- jaclang/vendor/pygls/workspace/position.py +204 -0
- jaclang/vendor/pygls/workspace/text_document.py +234 -0
- jaclang/vendor/pygls/workspace/workspace.py +311 -0
- {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/METADATA +1 -1
- jaclang-0.0.8.dist-info/RECORD +118 -0
- jaclang/core/jaclang.jac +0 -62
- jaclang/jac/passes/blue/tests/test_type_analyze_pass.py +0 -53
- jaclang/jac/passes/blue/type_analyze_pass.py +0 -728
- jaclang/jac/sym_table.py +0 -127
- jaclang-0.0.5.dist-info/RECORD +0 -73
- /jaclang/{utils → vendor}/sly/__init__.py +0 -0
- /jaclang/{utils → vendor}/sly/docparse.py +0 -0
- /jaclang/{utils → vendor}/sly/lex.py +0 -0
- /jaclang/{utils → vendor}/sly/yacc.py +0 -0
- {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/WHEEL +0 -0
- {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/entry_points.txt +0 -0
- {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/top_level.txt +0 -0
jaclang/jac/symtable.py
ADDED
|
@@ -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
|
|
45
|
-
a = spawn
|
|
46
|
-
a =
|
|
47
|
-
a =
|
|
48
|
-
a = b
|
|
49
|
-
a =
|
|
50
|
-
|
|
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"); }
|
jaclang/jac/tests/test_parser.py
CHANGED
|
@@ -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.
|
|
12
|
-
from jaclang.
|
|
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__(
|
|
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
|
-
|
|
62
|
-
self.errors_had.append(
|
|
63
|
-
self.logger.error(
|
|
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
|
-
|
|
68
|
-
self.warnings_had.append(
|
|
69
|
-
self.logger.warning(
|
|
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) ->
|
|
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,
|
|
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
|
-
|
|
34
|
+
print_pass = PyOutPass(
|
|
35
|
+
mod_path=file_path, input_ir=code.ir, base_path=base_dir, prior=code
|
|
36
|
+
)
|
|
32
37
|
else:
|
|
33
|
-
|
|
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) ->
|
|
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
|
-
|
|
53
|
+
print_pass = PyOutPass(
|
|
54
|
+
mod_path=file_path, input_ir=code.ir, base_path=base_dir, prior=code
|
|
55
|
+
)
|
|
48
56
|
else:
|
|
49
|
-
|
|
57
|
+
return code.errors_had
|
|
58
|
+
return print_pass.errors_had
|
|
50
59
|
|
|
51
60
|
|
|
52
61
|
def jac_file_to_pass(
|
jaclang/utils/fstring_parser.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# type: ignore
|
|
2
2
|
"""Python Like F-String Parser."""
|
|
3
|
-
from jaclang.
|
|
4
|
-
from jaclang.
|
|
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
|
jaclang/utils/lang_tools.py
CHANGED
|
@@ -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 [
|
|
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)
|
|
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"
|