jaclang 0.0.1__py3-none-any.whl → 0.0.3__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 (73) hide show
  1. jaclang/__init__.py +4 -0
  2. jaclang/cli/__init__.py +7 -0
  3. jaclang/cli/cli.jac +46 -0
  4. jaclang/cli/cmds.jac +14 -0
  5. jaclang/cli/impl/__init__.py +1 -0
  6. jaclang/cli/impl/cli_impl.jac +93 -0
  7. jaclang/cli/impl/cmds_impl.jac +26 -0
  8. jaclang/core/__init__.py +12 -0
  9. jaclang/core/impl/__init__.py +1 -0
  10. jaclang/core/impl/arch_impl.jac +112 -0
  11. jaclang/core/impl/element_impl.jac +95 -0
  12. jaclang/core/impl/exec_ctx_impl.jac +17 -0
  13. jaclang/core/impl/memory_impl.jac +57 -0
  14. jaclang/core/primitives.jac +104 -0
  15. jaclang/jac/__init__.py +1 -0
  16. jaclang/jac/absyntree.py +1787 -0
  17. jaclang/jac/constant.py +46 -0
  18. jaclang/jac/importer.py +130 -0
  19. jaclang/jac/lexer.py +538 -0
  20. jaclang/jac/parser.py +1474 -0
  21. jaclang/jac/passes/__init__.py +5 -0
  22. jaclang/jac/passes/blue/__init__.py +25 -0
  23. jaclang/jac/passes/blue/ast_build_pass.py +3190 -0
  24. jaclang/jac/passes/blue/blue_pygen_pass.py +1335 -0
  25. jaclang/jac/passes/blue/decl_def_match_pass.py +278 -0
  26. jaclang/jac/passes/blue/import_pass.py +75 -0
  27. jaclang/jac/passes/blue/sub_node_tab_pass.py +30 -0
  28. jaclang/jac/passes/blue/tests/__init__.py +1 -0
  29. jaclang/jac/passes/blue/tests/test_ast_build_pass.py +61 -0
  30. jaclang/jac/passes/blue/tests/test_blue_pygen_pass.py +117 -0
  31. jaclang/jac/passes/blue/tests/test_decl_def_match_pass.py +43 -0
  32. jaclang/jac/passes/blue/tests/test_import_pass.py +18 -0
  33. jaclang/jac/passes/blue/tests/test_sub_node_pass.py +26 -0
  34. jaclang/jac/passes/blue/tests/test_type_analyze_pass.py +53 -0
  35. jaclang/jac/passes/blue/type_analyze_pass.py +731 -0
  36. jaclang/jac/passes/ir_pass.py +154 -0
  37. jaclang/jac/passes/purple/__init__.py +17 -0
  38. jaclang/jac/passes/purple/impl/__init__.py +1 -0
  39. jaclang/jac/passes/purple/impl/purple_pygen_pass_impl.jac +289 -0
  40. jaclang/jac/passes/purple/purple_pygen_pass.jac +35 -0
  41. jaclang/jac/sym_table.py +127 -0
  42. jaclang/jac/tests/__init__.py +1 -0
  43. jaclang/jac/tests/fixtures/__init__.py +1 -0
  44. jaclang/jac/tests/fixtures/activity.py +10 -0
  45. jaclang/jac/tests/fixtures/fam.jac +68 -0
  46. jaclang/jac/tests/fixtures/hello_world.jac +5 -0
  47. jaclang/jac/tests/fixtures/lexer_fam.jac +61 -0
  48. jaclang/jac/tests/fixtures/stuff.jac +6 -0
  49. jaclang/jac/tests/test_importer.py +24 -0
  50. jaclang/jac/tests/test_lexer.py +57 -0
  51. jaclang/jac/tests/test_parser.py +50 -0
  52. jaclang/jac/tests/test_utils.py +12 -0
  53. jaclang/jac/transform.py +63 -0
  54. jaclang/jac/transpiler.py +69 -0
  55. jaclang/jac/utils.py +120 -0
  56. jaclang/utils/__init__.py +1 -0
  57. jaclang/utils/fstring_parser.py +73 -0
  58. jaclang/utils/log.py +9 -0
  59. jaclang/utils/sly/__init__.py +6 -0
  60. jaclang/utils/sly/docparse.py +62 -0
  61. jaclang/utils/sly/lex.py +510 -0
  62. jaclang/utils/sly/yacc.py +2398 -0
  63. jaclang/utils/test.py +81 -0
  64. jaclang/utils/tests/__init__.py +1 -0
  65. jaclang/utils/tests/test_fstring_parser.py +55 -0
  66. jaclang-0.0.3.dist-info/METADATA +12 -0
  67. jaclang-0.0.3.dist-info/RECORD +70 -0
  68. {jaclang-0.0.1.dist-info → jaclang-0.0.3.dist-info}/WHEEL +1 -1
  69. jaclang-0.0.3.dist-info/entry_points.txt +3 -0
  70. jaclang-0.0.3.dist-info/top_level.txt +1 -0
  71. jaclang-0.0.1.dist-info/METADATA +0 -7
  72. jaclang-0.0.1.dist-info/RECORD +0 -4
  73. jaclang-0.0.1.dist-info/top_level.txt +0 -1
@@ -0,0 +1,68 @@
1
+ # This is a comment
2
+ #*
3
+ This is multi line comment
4
+ Many styles!
5
+ *#
6
+ """
7
+ These are doc strings and can be used as comments
8
+ Use them to document your code
9
+ """
10
+
11
+ import:jac .stuff;
12
+ import:py from .activity, Activity as Actvy;
13
+
14
+ node location {
15
+ has x: int, y: int, name: str = True;
16
+ has activities: list[Activity];
17
+ has intro: str = "Welcome";
18
+ has visited: int = 0;
19
+
20
+
21
+ can record with tourist entry {
22
+ visited+=1;
23
+ for i in activities {
24
+ i.duration = visitor.duration;
25
+ if <h>.name not in visitor.passport {
26
+ if i.name == "Hiking" {
27
+ for j=0 to j<3 by j+=1 {
28
+ i.duration += 1;
29
+ }
30
+ i.duration += 1;
31
+ }
32
+ visitor.passport.append(<h>.name);
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ walker tourist {
39
+ has duration: float = .435e-2;
40
+ has budget: int;
41
+ has passport: list[str];
42
+
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>;
52
+ report <h>.activities;
53
+ }
54
+
55
+ can do_something(app: int =Actvy) -> Actvy {
56
+ app.do_something();
57
+ }
58
+ can do_something(app: int = Actvy, other: float = Actvy) -> Actvy {
59
+ return app?.do_something(other);
60
+ }
61
+
62
+ can outside_func() -> None;
63
+ }
64
+
65
+
66
+ :walker:tourist:ability:outside_func {
67
+
68
+ }
@@ -0,0 +1,5 @@
1
+ """ Basic Hello World function """
2
+
3
+ can hello() {
4
+ return "Hello World!";
5
+ }
@@ -0,0 +1,61 @@
1
+ # This is a comment
2
+
3
+ """
4
+ These are doc strings and can be used as comments
5
+ Use them to document your code
6
+ """
7
+
8
+ import:jac .stuff;
9
+ import:py from .activity, Activity as Actvy;
10
+
11
+ node location {
12
+ has x: int, y: int, name: str;
13
+ has anchor activities: list[Activity];
14
+ has hidden intro: str = "Welcome";
15
+ has visited: int = 0;
16
+
17
+
18
+ can record with tourist entry {
19
+ visited+=1;
20
+ for i in activities {
21
+ i.duration = visitor.duration;
22
+ if <h>.name not in visitor.passport {
23
+ if i.name == "Hiking" {
24
+ for j=0 to j<3 by j+=1 {
25
+ i.duration += 1;
26
+ }
27
+ i.duration += 1;
28
+ }
29
+ visitor.passport.append(<h>.name);
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ walker tourist {
36
+ has duration: int;
37
+ has budget: int;
38
+ has passport: list[str];
39
+
40
+ can make_visit with location, other exit {
41
+ b=:g:stuff:w:tourist;
42
+ a = spawn :g:stuff:w:tourist;
43
+ a = spawn (:w:tourist)::;
44
+ :g:stuff:w:tourist::;
45
+ report <h>.activities;
46
+ }
47
+
48
+ can do_something(app: int =Actvy) -> Actvy {
49
+ app.do_something();
50
+ }
51
+ can do_something(app: int = Actvy, other: float = Actvy) -> Actvy {
52
+ return app?.do_something(other);
53
+ }
54
+
55
+ can outside_func() -> None;
56
+ }
57
+
58
+
59
+ :walker:tourist:ability:outside_func {
60
+
61
+ }
@@ -0,0 +1,6 @@
1
+ global x = 54;
2
+
3
+ edge path {
4
+ has distance: int = 0;
5
+ // has: int visited = 0;
6
+ }
@@ -0,0 +1,24 @@
1
+ """Tests for Jac Loader."""
2
+ import sys
3
+
4
+ from jaclang import jac_blue_import
5
+ from jaclang.utils.test import TestCase
6
+
7
+
8
+ class TestLoader(TestCase):
9
+ """Test Jac self.prse."""
10
+
11
+ def setUp(self) -> None:
12
+ """Set up test."""
13
+ return super().setUp()
14
+
15
+ def test_import_basic_python(self) -> None:
16
+ """Test basic self loading."""
17
+ h = jac_blue_import("fixtures.hello_world")
18
+ self.assertEqual(h.hello(), "Hello World!") # type: ignore
19
+
20
+ def test_modules_correct(self) -> None:
21
+ """Test basic self loading."""
22
+ jac_blue_import("fixtures.hello_world")
23
+ self.assertIn("module 'hello_world'", str(sys.modules))
24
+ self.assertIn("/tests/fixtures/hello_world.jac", str(sys.modules))
@@ -0,0 +1,57 @@
1
+ """Tests for Jac lexer."""
2
+ from typing import Generator
3
+
4
+ from jaclang.jac.lexer import JacLexer, Tokens
5
+ from jaclang.utils.test import TestCase
6
+
7
+
8
+ class TestLexer(TestCase):
9
+ """Test Jac lexer."""
10
+
11
+ def test_lexer(self) -> None:
12
+ """Basic test for lexer."""
13
+ tokens = []
14
+ ir = JacLexer(mod_path="", input_ir=self.load_fixture("lexer_fam.jac")).ir
15
+ if not isinstance(ir, Generator):
16
+ raise ValueError("Lexer did not return generator.")
17
+ for t in ir:
18
+ tokens.append(t)
19
+ self.assertEqual(tokens[0].type, "DOC_STRING")
20
+ self.assertEqual(
21
+ [
22
+ tokens[10].type,
23
+ tokens[10].value,
24
+ tokens[10].lineno,
25
+ tokens[10].index,
26
+ tokens[10].end,
27
+ ],
28
+ ["KW_FROM", "from", 9, 140, 144],
29
+ )
30
+ self.assertEqual(
31
+ [
32
+ tokens[-1].type,
33
+ tokens[-1].value,
34
+ tokens[-1].lineno,
35
+ ],
36
+ ["RBRACE", "}", 61],
37
+ )
38
+
39
+ def test_col_idxs(self) -> None:
40
+ """Basic test for lexer."""
41
+ tokens = []
42
+ ir = JacLexer(mod_path="", input_ir=self.load_fixture("lexer_fam.jac")).ir
43
+ if not isinstance(ir, Generator):
44
+ raise ValueError("Lexer did not return generator.")
45
+ for t in ir:
46
+ tokens.append((t.value, t.lineno, t.index - t.lineidx, t.end - t.lineidx))
47
+ self.assertEqual(tokens[12], ("activity", 9, 16, 24))
48
+ self.assertEqual(tokens[-3], ("outside_func", 59, 24, 36))
49
+
50
+ def test_enum_matches_lexer_toks(self) -> None:
51
+ """Test that enum stays synced with lexer."""
52
+ for token in JacLexer.tokens:
53
+ self.assertIn(token, Tokens.__members__)
54
+ for token in Tokens:
55
+ self.assertIn(token.name, JacLexer.tokens)
56
+ for token in Tokens:
57
+ self.assertIn(token.value, JacLexer.tokens)
@@ -0,0 +1,50 @@
1
+ """Tests for Jac parser."""
2
+ from jaclang.jac.absyntree import AstNode
3
+ from jaclang.jac.lexer import JacLexer
4
+ from jaclang.jac.parser import JacParser
5
+ from jaclang.utils.test import TestCaseMicroSuite
6
+
7
+
8
+ class TestParser(TestCaseMicroSuite):
9
+ """Test Jac self.prse."""
10
+
11
+ def setUp(self) -> None:
12
+ """Set up test."""
13
+ return super().setUp()
14
+
15
+ def micro_suite_test(self, filename: str) -> None:
16
+ """Parse micro jac file."""
17
+ lex = JacLexer(mod_path=filename, input_ir=self.file_to_str(filename)).ir
18
+ prse = JacParser(mod_path=filename, input_ir=lex)
19
+ self.assertFalse(prse.errors_had)
20
+
21
+ def test_shift_reduce_conflict(self) -> None:
22
+ """Test for shift reduce conflict."""
23
+ self.assertEqual(len(JacParser._lrtable.sr_conflicts), 0)
24
+
25
+ def test_reduce_reduce_conflict(self) -> None:
26
+ """Test for reduce reduce conflict."""
27
+ self.assertEqual(len(JacParser._lrtable.rr_conflicts), 0)
28
+
29
+ def test_basci_parsing(self) -> None:
30
+ """Basic test for parsing."""
31
+ lex = JacLexer(mod_path="fam.jac", input_ir=self.load_fixture("fam.jac")).ir
32
+ prse = JacParser(mod_path="fam.jac", input_ir=lex)
33
+ output = prse.ir
34
+ self.assertFalse(prse.errors_had)
35
+ if isinstance(output, AstNode):
36
+ self.assertGreater(len(str(output.to_dict())), 1000)
37
+ else:
38
+ self.fail("Output is not an AstNode.")
39
+
40
+ def test_parsing_jac_cli(self) -> None:
41
+ """Basic test for parsing."""
42
+ lex = JacLexer(
43
+ mod_path="../../../cli/cli.jac",
44
+ input_ir=self.load_fixture("../../../cli/cli.jac"),
45
+ ).ir
46
+ prse = JacParser(mod_path="../../../cli/cli.jac", input_ir=lex)
47
+ self.assertFalse(prse.errors_had)
48
+
49
+
50
+ TestParser.self_attach_micro_tests()
@@ -0,0 +1,12 @@
1
+ """Tests for Jac utils."""
2
+ from jaclang.jac.utils import load_ast_and_print_pass_template
3
+ from jaclang.utils.test import TestCase
4
+
5
+
6
+ class TestLexer(TestCase):
7
+ """Test Jac utils."""
8
+
9
+ def test_ast_template_loader(self) -> None:
10
+ """Basic test for ast template loader."""
11
+ output = load_ast_and_print_pass_template()
12
+ self.assertGreater(len(output), 1000)
@@ -0,0 +1,63 @@
1
+ """Standardized transformation process and error interface."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+ from abc import ABC, ABCMeta, abstractmethod
6
+ from typing import Optional
7
+
8
+
9
+ from jaclang.jac.absyntree import AstNode
10
+ from jaclang.utils.log import logging
11
+ from jaclang.utils.sly.lex import LexerMeta
12
+ from jaclang.utils.sly.yacc import ParserMeta
13
+
14
+
15
+ class Transform(ABC):
16
+ """Abstract class for IR passes."""
17
+
18
+ def __init__(
19
+ self,
20
+ mod_path: str,
21
+ input_ir: AstNode,
22
+ base_path: str = "",
23
+ prior: Optional[Transform] = None,
24
+ ) -> None:
25
+ """Initialize pass."""
26
+ self.logger = logging.getLogger(self.__class__.__module__)
27
+ self.errors_had = [] if not prior else prior.errors_had
28
+ self.warnings_had = [] if not prior else prior.warnings_had
29
+ self.cur_line = 0
30
+ self.mod_path = mod_path
31
+ self.rel_mod_path = (
32
+ mod_path.replace(base_path, "") if base_path else mod_path.split(os.sep)[-1]
33
+ )
34
+ self.ir = self.transform(ir=input_ir)
35
+
36
+ @abstractmethod
37
+ def transform(self, ir: AstNode) -> AstNode:
38
+ """Transform interface."""
39
+ pass
40
+
41
+ def log_error(self, msg: str) -> None:
42
+ """Pass Error."""
43
+ msg = f"Mod {self.rel_mod_path}: Line {self.cur_line}, " + msg
44
+ self.errors_had.append(msg)
45
+ self.logger.error(msg)
46
+
47
+ def log_warning(self, msg: str) -> None:
48
+ """Pass Error."""
49
+ msg = f"Mod {self.rel_mod_path}: Line {self.cur_line}, " + msg
50
+ self.warnings_had.append(msg)
51
+ self.logger.warning(msg)
52
+
53
+
54
+ class ABCLexerMeta(ABCMeta, LexerMeta):
55
+ """Metaclass for Jac Lexer."""
56
+
57
+ pass
58
+
59
+
60
+ class ABCParserMeta(ABCMeta, ParserMeta):
61
+ """Metaclass for Jac Lexer."""
62
+
63
+ pass
@@ -0,0 +1,69 @@
1
+ """Transpilation functions."""
2
+ from typing import Type, TypeVar
3
+
4
+ import jaclang.jac.absyntree as ast
5
+ from jaclang.jac.parser import JacLexer
6
+ from jaclang.jac.parser import JacParser
7
+ from jaclang.jac.passes import Pass
8
+ from jaclang.jac.passes.blue import BluePygenPass, pass_schedule
9
+ from jaclang.jac.transform import Transform
10
+
11
+
12
+ T = TypeVar("T", bound=Pass)
13
+
14
+
15
+ def jac_file_to_parse_tree(file_path: str, base_dir: str) -> Transform:
16
+ """Convert a Jac file to an AST."""
17
+ with open(file_path) as file:
18
+ lex = JacLexer(mod_path=file_path, input_ir=file.read(), base_path=base_dir)
19
+ prse = JacParser(
20
+ mod_path=file_path, input_ir=lex.ir, base_path=base_dir, prior=lex
21
+ )
22
+ return prse
23
+
24
+
25
+ def transpile_jac_blue(file_path: str, base_dir: str) -> str:
26
+ """Transpiler Jac file and return python code as string."""
27
+ code = jac_file_to_pass(
28
+ file_path=file_path, base_dir=base_dir, target=BluePygenPass
29
+ )
30
+ if isinstance(code.ir, ast.Module):
31
+ return code.ir.meta["py_code"]
32
+ else:
33
+ raise ValueError("Transpilation of Jac file failed.")
34
+
35
+
36
+ def transpile_jac_purple(file_path: str, base_dir: str) -> str:
37
+ """Transpiler Jac file and return python code as string."""
38
+ from jaclang.jac.passes.purple import pass_schedule, PurplePygenPass
39
+
40
+ code = jac_file_to_pass(
41
+ file_path=file_path,
42
+ base_dir=base_dir,
43
+ target=PurplePygenPass,
44
+ schedule=pass_schedule,
45
+ )
46
+ if isinstance(code.ir, ast.Module):
47
+ return code.ir.meta["py_code"]
48
+ else:
49
+ raise ValueError("Transpilation of Jac file failed.")
50
+
51
+
52
+ def jac_file_to_pass(
53
+ file_path: str,
54
+ base_dir: str = "",
55
+ target: Type[T] = BluePygenPass,
56
+ schedule: list[Type[T]] = pass_schedule,
57
+ ) -> T:
58
+ """Convert a Jac file to an AST."""
59
+ ast_ret = jac_file_to_parse_tree(file_path, base_dir)
60
+ for i in schedule:
61
+ if i == target:
62
+ break
63
+ ast_ret = i(
64
+ mod_path=file_path, input_ir=ast_ret.ir, base_path=base_dir, prior=ast_ret
65
+ )
66
+ ast_ret = target(
67
+ mod_path=file_path, input_ir=ast_ret.ir, base_path=base_dir, prior=ast_ret
68
+ )
69
+ return ast_ret
jaclang/jac/utils.py ADDED
@@ -0,0 +1,120 @@
1
+ """Utility functions and classes for Jac compilation toolchain."""
2
+ import re
3
+
4
+ import jaclang.jac.absyntree as ast
5
+ from jaclang.jac.parser import JacLexer
6
+
7
+
8
+ def get_all_jac_keywords() -> str:
9
+ """Get all Jac keywords as an or string."""
10
+ ret = ""
11
+ for k in JacLexer._remapping["NAME"].keys():
12
+ ret += f"{k}|"
13
+ return ret[:-1]
14
+
15
+
16
+ def pascal_to_snake(pascal_string: str) -> str:
17
+ """Convert pascal case to snake case."""
18
+ snake_string = re.sub(r"(?<!^)(?=[A-Z])", "_", pascal_string).lower()
19
+ return snake_string
20
+
21
+
22
+ def add_line_numbers(s: str) -> str:
23
+ """Add line numbers to a string."""
24
+ lines = s.split("\n")
25
+ return "\n".join(f"{i+1}: \t{line}" for i, line in enumerate(lines))
26
+
27
+
28
+ def clip_code_section(s: str, target_line: int, line_range: int) -> str:
29
+ """Clip a section of code and highlight target line."""
30
+ lines = s.split("\n")
31
+ start = max(0, target_line - line_range - 1)
32
+ end = min(target_line + line_range, len(lines))
33
+
34
+ result = []
35
+ for i in range(start, end):
36
+ line = lines[i]
37
+ if i == target_line - 1:
38
+ line = "*" + line
39
+ result.append(line)
40
+ return "\n".join(result)
41
+
42
+
43
+ def get_ast_nodes_as_snake_case() -> list[str]:
44
+ """Get all AST nodes as snake case."""
45
+ import inspect
46
+ import sys
47
+
48
+ module_name = ast.__name__
49
+ module = sys.modules[module_name]
50
+
51
+ # Retrieve the source code of the module
52
+ source_code = inspect.getsource(module)
53
+
54
+ classes = inspect.getmembers(module, inspect.isclass)
55
+ ast_node_classes = [cls for _, cls in classes if issubclass(cls, ast.AstNode)]
56
+
57
+ ordered_classes = sorted(
58
+ ast_node_classes, key=lambda cls: source_code.find(f"class {cls.__name__}")
59
+ )
60
+ snake_names = []
61
+ for cls in ordered_classes:
62
+ class_name = cls.__name__
63
+ snake_names.append(pascal_to_snake(class_name))
64
+ return snake_names
65
+
66
+
67
+ def load_ast_and_print_pass_template() -> str:
68
+ """Load and print classes."""
69
+ import inspect
70
+ import sys
71
+
72
+ module_name = ast.__name__
73
+ module = sys.modules[module_name]
74
+
75
+ # Retrieve the source code of the module
76
+ source_code = inspect.getsource(module)
77
+
78
+ classes = inspect.getmembers(module, inspect.isclass)
79
+ ast_node_classes = [cls for _, cls in classes if issubclass(cls, ast.AstNode)]
80
+
81
+ ordered_classes = sorted(
82
+ ast_node_classes, key=lambda cls: source_code.find(f"class {cls.__name__}")
83
+ )
84
+ output = ""
85
+ for cls in ordered_classes:
86
+ class_name = cls.__name__
87
+ snake_case_name = pascal_to_snake(class_name)
88
+
89
+ output += f"def exit_{snake_case_name}(self, node: ast.{class_name}) -> None:\n"
90
+ output += ' """Sub objects.\n\n'
91
+
92
+ init_func = cls.__init__
93
+ init_signature = inspect.signature(init_func)
94
+
95
+ for param_name, param in init_signature.parameters.items():
96
+ if param_name not in ["self", "parent", "kid", "line"]:
97
+ param_type = (
98
+ param.annotation
99
+ if param.annotation != inspect.Parameter.empty
100
+ else "Any"
101
+ )
102
+ param_default = (
103
+ param.default if param.default != inspect.Parameter.empty else None
104
+ )
105
+ output += f" {param_name}: {param_type}{' ='+param_default if param_default else ''},\n"
106
+
107
+ output += ' """\n\n'
108
+ output = output.replace("jaclang.jac.absyntree.", "")
109
+ output = output.replace("typing.", "")
110
+ output = output.replace("<enum '", "")
111
+ output = output.replace("'>", "")
112
+ output = output.replace("<class '", "")
113
+ output = output.replace("ForwardRef('", "")
114
+ output = output.replace("')", "")
115
+ return output
116
+
117
+
118
+ if __name__ == "__main__":
119
+ print(get_all_jac_keywords())
120
+ print(load_ast_and_print_pass_template())
@@ -0,0 +1 @@
1
+ """Jaseci utility functions and libraries."""
@@ -0,0 +1,73 @@
1
+ # type: ignore
2
+ """Python Like F-String Parser."""
3
+ from jaclang.utils.sly.lex import Lexer
4
+ from jaclang.utils.sly.yacc import Parser, YaccProduction
5
+
6
+ _ = None # For flake8 linting and sly compatibility
7
+
8
+
9
+ class FStringLexer(Lexer):
10
+ """Python Like F-String Lexer."""
11
+
12
+ tokens = {
13
+ "STRING_START",
14
+ "STRING_END",
15
+ "EXPR_START",
16
+ "EXPR_END",
17
+ "PIECE",
18
+ }
19
+ # ignore = " \t"
20
+
21
+ # Tokens
22
+
23
+ STRING_START = r"f\""
24
+ STRING_END = r"\""
25
+ PIECE = r"[^\{\}\"]+|\{\{|\}\}"
26
+ EXPR_START = r"(?<!\{)\{(?!\{)"
27
+ EXPR_END = r"(?<!\})\}(?!\})"
28
+
29
+
30
+ class FStringParser(Parser):
31
+ """Python Like F-String Parser."""
32
+
33
+ tokens = FStringLexer.tokens
34
+ start = "fstring"
35
+
36
+ @_("STRING_START fstr_parts STRING_END")
37
+ def fstring(self, p: YaccProduction) -> YaccProduction:
38
+ """Start rule for fstring."""
39
+ return p
40
+
41
+ @_(
42
+ "fstr_parts fstr_expr",
43
+ "fstr_parts PIECE",
44
+ "PIECE",
45
+ "fstr_expr",
46
+ "fstring",
47
+ )
48
+ def fstr_parts(self, p: YaccProduction) -> YaccProduction:
49
+ """Parts of the string both in string and in expression."""
50
+ return p
51
+
52
+ @_("EXPR_START fstr_parts EXPR_END")
53
+ def fstr_expr(self, p: YaccProduction) -> YaccProduction:
54
+ """Expressions rule."""
55
+ return p
56
+
57
+
58
+ if __name__ == "__main__":
59
+ """Run the parser for live testing."""
60
+ lexer = FStringLexer()
61
+ parser = FStringParser()
62
+ while True:
63
+ try:
64
+ text = input("fstring > ")
65
+ except EOFError:
66
+ break
67
+ if text:
68
+ tokens = lexer.tokenize(text)
69
+ for i in tokens:
70
+ print(i, end=", ")
71
+ tokens = lexer.tokenize(text)
72
+ result = parser.parse(tokens)
73
+ print(result)
jaclang/utils/log.py ADDED
@@ -0,0 +1,9 @@
1
+ """Basic Logging Module for Jac Compiler."""
2
+
3
+ import logging
4
+
5
+ logging.basicConfig(
6
+ # level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
7
+ level=logging.INFO,
8
+ format="%(levelname)s - %(message)s",
9
+ )
@@ -0,0 +1,6 @@
1
+ # flake8: noqa
2
+ from .lex import *
3
+ from .yacc import *
4
+
5
+ __version__ = "0.5"
6
+ __all__ = [*lex.__all__, *yacc.__all__]