jaclang 0.8.6__py3-none-any.whl → 0.8.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 (103) hide show
  1. jaclang/cli/cli.md +3 -3
  2. jaclang/cli/cli.py +37 -37
  3. jaclang/cli/cmdreg.py +45 -140
  4. jaclang/compiler/constant.py +0 -1
  5. jaclang/compiler/jac.lark +3 -6
  6. jaclang/compiler/larkparse/jac_parser.py +2 -2
  7. jaclang/compiler/parser.py +213 -34
  8. jaclang/compiler/passes/main/__init__.py +2 -4
  9. jaclang/compiler/passes/main/def_use_pass.py +0 -4
  10. jaclang/compiler/passes/main/predynamo_pass.py +221 -0
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +83 -55
  12. jaclang/compiler/passes/main/pyast_load_pass.py +66 -40
  13. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
  14. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
  15. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
  16. jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
  17. jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
  18. jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
  19. jaclang/compiler/passes/main/tests/fixtures/checker_binary_op.jac +21 -0
  20. jaclang/compiler/passes/main/tests/fixtures/checker_call_expr_class.jac +12 -0
  21. jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
  22. jaclang/compiler/passes/main/tests/fixtures/checker_cyclic_symbol.jac +4 -0
  23. jaclang/compiler/passes/main/tests/fixtures/checker_expr_call.jac +9 -0
  24. jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
  25. jaclang/compiler/passes/main/tests/fixtures/checker_import_missing_module.jac +13 -0
  26. jaclang/compiler/passes/main/tests/fixtures/checker_magic_call.jac +17 -0
  27. jaclang/compiler/passes/main/tests/fixtures/checker_mod_path.jac +8 -0
  28. jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
  29. jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
  30. jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
  31. jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
  32. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
  33. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
  34. jaclang/compiler/passes/main/tests/test_checker_pass.py +265 -0
  35. jaclang/compiler/passes/main/tests/test_predynamo_pass.py +57 -0
  36. jaclang/compiler/passes/main/type_checker_pass.py +36 -61
  37. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +204 -44
  38. jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
  39. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
  40. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
  41. jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +171 -11
  42. jaclang/compiler/passes/transform.py +12 -8
  43. jaclang/compiler/program.py +14 -6
  44. jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
  45. jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
  46. jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
  47. jaclang/compiler/tests/fixtures/python_module.py +1 -0
  48. jaclang/compiler/tests/test_importer.py +39 -0
  49. jaclang/compiler/tests/test_parser.py +49 -0
  50. jaclang/compiler/type_system/operations.py +104 -0
  51. jaclang/compiler/type_system/type_evaluator.py +470 -47
  52. jaclang/compiler/type_system/type_utils.py +246 -0
  53. jaclang/compiler/type_system/types.py +58 -2
  54. jaclang/compiler/unitree.py +79 -94
  55. jaclang/langserve/engine.jac +253 -230
  56. jaclang/langserve/server.jac +46 -15
  57. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  58. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  59. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  60. jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
  61. jaclang/langserve/tests/server_test/circle_template.jac +80 -0
  62. jaclang/langserve/tests/server_test/glob_template.jac +4 -0
  63. jaclang/langserve/tests/server_test/test_lang_serve.py +154 -312
  64. jaclang/langserve/tests/server_test/utils.py +153 -116
  65. jaclang/langserve/tests/test_dev_server.py +1 -1
  66. jaclang/langserve/tests/test_server.py +30 -86
  67. jaclang/langserve/utils.jac +56 -63
  68. jaclang/runtimelib/machine.py +7 -0
  69. jaclang/runtimelib/meta_importer.py +27 -1
  70. jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
  71. jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
  72. jaclang/settings.py +18 -14
  73. jaclang/tests/fixtures/abc_check.jac +3 -3
  74. jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
  75. jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
  76. jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
  77. jaclang/tests/fixtures/jac_run_py_bugs.py +18 -0
  78. jaclang/tests/fixtures/jac_run_py_import.py +13 -0
  79. jaclang/tests/fixtures/lambda_arg_annotation.jac +15 -0
  80. jaclang/tests/fixtures/lambda_self.jac +18 -0
  81. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  82. jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
  83. jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
  84. jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
  85. jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
  86. jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
  87. jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
  88. jaclang/tests/fixtures/py2jac_params.py +8 -0
  89. jaclang/tests/fixtures/run_test.jac +4 -4
  90. jaclang/tests/test_cli.py +103 -18
  91. jaclang/tests/test_language.py +74 -16
  92. jaclang/utils/helpers.py +47 -2
  93. jaclang/utils/module_resolver.py +11 -1
  94. jaclang/utils/test.py +8 -0
  95. jaclang/utils/treeprinter.py +0 -18
  96. {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/METADATA +3 -3
  97. {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/RECORD +99 -62
  98. {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/WHEEL +1 -1
  99. jaclang/compiler/passes/main/inheritance_pass.py +0 -131
  100. jaclang/langserve/dev_engine.jac +0 -645
  101. jaclang/langserve/dev_server.jac +0 -201
  102. jaclang/langserve/tests/server_test/code_test.py +0 -0
  103. {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/entry_points.txt +0 -0
@@ -1,18 +1,178 @@
1
- class SemTokManager {
1
+ #this file is part of formatter tests and is not meant to be run
2
+ class SemTokManager {
2
3
  """Initialize semantic token manager."""
3
4
  def init(self: SemTokManager, ir: uni.Module) -> None {
4
- self.sem_tokens: List[int] = self.gen_sem_tokens(ir);
5
5
  self.aaaaastatic_sem_tokens:
6
- List[Tuple[lspt.Position, int, int, uni.AstSymbolNode]] =
7
- self.gen_sem_tok_node(ir);
6
+ List[Tuple[lspt.Position, int, int, uni.AstSymbolNode]] = self.gen_sem_tok_node(
7
+ ir
8
+ );
8
9
  }
9
10
  }
10
11
 
11
12
 
12
- def init(
13
- self: ModuleManager,
14
- program: JacProgram,
15
- sem_managers: <>dict,
16
- program2: JacProgram,
17
- sem_managers2: <>dict
18
- ) -> None { }
13
+ def walrus_example() {
14
+ if ((x := 10) > 5) {
15
+ print(x);
16
+ b = a(
17
+ 11111111111111111111111111111111111111111111111111111111111111111111111111
18
+ );
19
+ }
20
+ }
21
+
22
+
23
+ with entry {
24
+ c = (
25
+ a()
26
+ if 1 and
27
+ isinstance(a, int) and
28
+ isinstance(a, int) and
29
+ isinstance(a, int) and
30
+ isinstance(a, int) and
31
+ isinstance(a, int)
32
+ else (
33
+ 999
34
+ if isinstance(a, int) and
35
+ isinstance(a, int) and
36
+ isinstance(a, int) and
37
+ isinstance(4, bool)
38
+ else 7
39
+ )
40
+ );
41
+ print(
42
+ """This is a long
43
+ line of code."""
44
+ );
45
+ }
46
+
47
+
48
+ class ModuleManager {
49
+ def clear_alerts_for_file(self: ModuleManager, file_path_fs: str) -> None {
50
+ #list comprehension example
51
+ self.warnings_had = [
52
+ w
53
+ for w in self.program
54
+ if w.loc.mod_path != file_path_fs
55
+ ];
56
+ self.program.errors_had = [
57
+ e
58
+ for e in self.program.errors_haddddddddd
59
+ if e.loc.mod_path != file_path_fs
60
+ ];
61
+ self.program.errors_had = [
62
+ e
63
+ for e in self.program.errors_haddddddddddddddddddddddddddddddddddddddddd
64
+ if e.loc.mod_path != file_path_fs
65
+ ];
66
+ # dict comprehension example
67
+ squares_dict = {x : x ** 2 for x in numbers};
68
+ squares_dict = {
69
+ x : x ** 2 for x in numberssssssssssssssssssssssssssssssssssssssssssssss
70
+ };
71
+ squares_dict = {
72
+ x : x ** 2
73
+ for x in numbersssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
74
+ };
75
+ # set comprehension example
76
+ squares_set = {x ** 2 for x in numbers};
77
+ squares_set = {
78
+ x ** 2 for x in numberssssssssssssssssssssssssssssssssssssssssssssssss
79
+ };
80
+ squares_set = {
81
+ x ** 2
82
+ for x in numbersssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
83
+ };
84
+ # generator comprehension example
85
+ squares_gen = (x ** 2 for x in numbers);
86
+ squares_gen = (
87
+ x ** 2 for x in numberssssssssssssssssssssssssssssssssssssssssssssssssssss
88
+ );
89
+ squares_gen = (
90
+ x ** 2
91
+ for x in numbersssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
92
+ );
93
+ }
94
+ }
95
+
96
+
97
+ ## expr as item extra space issue
98
+ with entry {
99
+ with open(f"Apple{apple}.txt") as f {
100
+ # Fix syntax highlighting
101
+ print(
102
+ f.read()
103
+ );
104
+ }
105
+ }
106
+
107
+
108
+ def func_with_very_long_params(
109
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: int,
110
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: int,
111
+ ) -> None {
112
+ print(
113
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
114
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
115
+ );
116
+ }
117
+
118
+
119
+ def func_with_long_params(
120
+ aaaaaaaaaaaaaaaaaaaaaa: int, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: int,
121
+ ) -> None {
122
+ print(
123
+ aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, 1111111111111
124
+ );
125
+ }
126
+
127
+
128
+ def func_with_short_params(a: int, b: int) -> None {
129
+ print(a + b + c[5:]);
130
+ }
131
+
132
+
133
+ with entry {
134
+ if (
135
+ node_selected and
136
+ node_selected.find_parent_of_type(uni.Archetype) or
137
+ node_selected.find_parent_of_type(uni.ImplDef)
138
+ ) {
139
+ self_symbol = [
140
+ lspt.CompletionItem(label='self', kind=lspt.CompletionItemKind.Variable)
141
+ ];
142
+ } else {
143
+ self_symbol = [];
144
+ }
145
+ x = (
146
+ 1222222222 and
147
+ 2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
148
+ );
149
+ a = 4 if True else 4;
150
+ }
151
+
152
+
153
+ """Return diagnostics."""
154
+ def gen_diagnostics(
155
+ from_path: str, errors: list[Alert], warnings: list[Alert]
156
+ ) -> list[lspt.Diagnostic] {
157
+ if (
158
+ isinstance(node_selected, uni.Name) and
159
+ node_selected.parent and
160
+ isinstance(node_selected.parent, uni.ModulePath)
161
+ ) {
162
+ node_selected = node_selected.name_of;
163
+ } elif (
164
+ isinstance(node_selected, uni.Name) and
165
+ node_selected.parent and
166
+ isinstance(node_selected.parent, uni.ModulePath)
167
+ ) {
168
+ spec = node_selected.parent.parent.abs_path;
169
+ }
170
+ }
171
+
172
+
173
+ @decorator
174
+ def x() { }
175
+
176
+
177
+ @decorator()
178
+ class KK {}
@@ -9,7 +9,7 @@ from typing import Generic, Optional, TYPE_CHECKING, Type, TypeVar
9
9
  from jaclang.compiler.codeinfo import CodeLocInfo
10
10
  from jaclang.compiler.unitree import UniNode
11
11
  from jaclang.settings import settings
12
- from jaclang.utils.helpers import pretty_print_source_location
12
+ from jaclang.utils.helpers import ANSIColors, pretty_print_source_location
13
13
  from jaclang.utils.log import logging
14
14
 
15
15
  if TYPE_CHECKING:
@@ -39,7 +39,7 @@ class Alert:
39
39
  """Return string representation of alert."""
40
40
  return self.as_log()
41
41
 
42
- def as_log(self) -> str:
42
+ def as_log(self, *, colors: bool = False) -> str:
43
43
  """Return the alert as a single line log as opposed to the pretty print."""
44
44
  file_path: str = self.loc.mod_path
45
45
  if file_path == "":
@@ -47,20 +47,24 @@ class Alert:
47
47
 
48
48
  line: int = self.loc.first_line
49
49
  column: int = self.loc.col_start
50
- return f"{file_path}:{line}:{column} {self.msg}"
51
50
 
52
- def pretty_print(self) -> str:
53
- """Pretty pritns the Alert to show the alert with source location."""
51
+ # TODO: Set if the alert is error or warning and color accordingly.
52
+ msg = self.msg if not colors else f"{ANSIColors.RED}{self.msg}{ANSIColors.END}"
53
+ return f"{file_path}:{line}:{column} {msg}"
54
+
55
+ def pretty_print(self, *, colors: bool = False) -> str:
56
+ """Pretty prints the Alert to show the alert with source location."""
54
57
  pretty_dump = pretty_print_source_location(
55
58
  self.loc.mod_path,
56
59
  self.loc.orig_src.code,
57
60
  self.loc.first_line,
58
61
  self.loc.pos_start,
59
62
  self.loc.pos_end,
63
+ colors=colors,
60
64
  )
61
65
  if pretty_dump != "":
62
66
  pretty_dump = "\n" + pretty_dump
63
- return self.as_log() + pretty_dump
67
+ return self.as_log(colors=colors) + pretty_dump
64
68
 
65
69
 
66
70
  class Transform(ABC, Generic[T, R]):
@@ -115,7 +119,7 @@ class Transform(ABC, Generic[T, R]):
115
119
  )
116
120
  self.errors_had.append(alrt)
117
121
  self.prog.errors_had.append(alrt)
118
- self.logger.error(alrt.as_log())
122
+ # self.logger.error(alrt.as_log())
119
123
 
120
124
  def log_warning(self, msg: str, node_override: Optional[UniNode] = None) -> None:
121
125
  """Pass Error."""
@@ -126,7 +130,7 @@ class Transform(ABC, Generic[T, R]):
126
130
  )
127
131
  self.warnings_had.append(alrt)
128
132
  self.prog.warnings_had.append(alrt)
129
- self.logger.warning(alrt.as_log())
133
+ # self.logger.warning(alrt.as_log())
130
134
 
131
135
  def log_info(self, msg: str) -> None:
132
136
  """Log info."""
@@ -15,16 +15,15 @@ from jaclang.compiler.passes.main import (
15
15
  CFGBuildPass,
16
16
  DeclImplMatchPass,
17
17
  DefUsePass,
18
- InheritancePass,
19
18
  JacAnnexPass,
20
19
  JacImportDepsPass,
20
+ PreDynamoPass,
21
21
  PyBytecodeGenPass,
22
22
  PyJacAstLinkPass,
23
23
  PyastBuildPass,
24
24
  PyastGenPass,
25
25
  SemDefMatchPass,
26
26
  SymTabBuildPass,
27
- SymTabLinkPass,
28
27
  Transform,
29
28
  TypeCheckPass,
30
29
  )
@@ -33,7 +32,9 @@ from jaclang.compiler.passes.tool import (
33
32
  FuseCommentsPass,
34
33
  JacFormatPass,
35
34
  )
35
+ from jaclang.compiler.type_system.type_evaluator import TypeEvaluator
36
36
  from jaclang.runtimelib.utils import read_file_with_encoding
37
+ from jaclang.settings import settings
37
38
  from jaclang.utils.log import logging
38
39
 
39
40
 
@@ -45,7 +46,6 @@ ir_gen_sched = [
45
46
  DefUsePass,
46
47
  SemDefMatchPass,
47
48
  CFGBuildPass,
48
- InheritancePass,
49
49
  ]
50
50
  type_check_sched: list = [
51
51
  TypeCheckPass,
@@ -67,6 +67,13 @@ class JacProgram:
67
67
  self.py_raise_map: dict[str, str] = {}
68
68
  self.errors_had: list[Alert] = []
69
69
  self.warnings_had: list[Alert] = []
70
+ self.type_evaluator: TypeEvaluator | None = None
71
+
72
+ def get_type_evaluator(self) -> TypeEvaluator:
73
+ """Return the type evaluator."""
74
+ if not self.type_evaluator:
75
+ self.type_evaluator = TypeEvaluator(program=self)
76
+ return self.type_evaluator
70
77
 
71
78
  def get_bytecode(self, full_target: str) -> Optional[types.CodeType]:
72
79
  """Get the bytecode for a specific module."""
@@ -120,7 +127,10 @@ class JacProgram:
120
127
  self.run_schedule(mod=mod_targ, passes=ir_gen_sched)
121
128
  if type_check:
122
129
  self.run_schedule(mod=mod_targ, passes=type_check_sched)
123
- if not no_cgen:
130
+ # If the module has syntax errors, we skip code generation.
131
+ if (not mod_targ.has_syntax_errors) and (not no_cgen):
132
+ if settings.predynamo_pass and PreDynamoPass not in py_code_gen:
133
+ py_code_gen.insert(0, PreDynamoPass)
124
134
  self.run_schedule(mod=mod_targ, passes=py_code_gen)
125
135
  return mod_targ
126
136
 
@@ -137,8 +147,6 @@ class JacProgram:
137
147
  """Convert a Jac file to an AST."""
138
148
  mod_targ = self.compile(file_path, use_str, type_check=type_check)
139
149
  JacImportDepsPass(ir_in=mod_targ, prog=self)
140
- for mod in self.mod.hub.values():
141
- SymTabLinkPass(ir_in=mod, prog=self)
142
150
  for mod in self.mod.hub.values():
143
151
  DefUsePass(mod, prog=self)
144
152
  return mod_targ
@@ -0,0 +1,4 @@
1
+ import python_module
2
+ import jac_module
3
+
4
+ print("This is main test file for jac import of python files")
@@ -0,0 +1,3 @@
1
+ with entry {
2
+ print("Hello from Jac module!");
3
+ }
@@ -0,0 +1,10 @@
1
+
2
+ obj Foo {
3
+ has bar: int = 42;
4
+ }
5
+
6
+ with entry {
7
+ foo = Foo(;
8
+ func(foo bar)
9
+ foo.bar;
10
+ }
@@ -0,0 +1 @@
1
+ print("Hello from Python module!")
@@ -1,6 +1,7 @@
1
1
  """Tests for Jac Loader."""
2
2
 
3
3
  import io
4
+ import os
4
5
  import sys
5
6
 
6
7
  from jaclang import JacMachine as Jac
@@ -8,6 +9,7 @@ from jaclang.cli import cli
8
9
  from jaclang.compiler.program import JacProgram
9
10
  from jaclang.runtimelib.machine import JacMachineInterface
10
11
  from jaclang.utils.test import TestCase
12
+ from jaclang.settings import settings
11
13
 
12
14
 
13
15
  class TestLoader(TestCase):
@@ -128,3 +130,40 @@ class TestLoader(TestCase):
128
130
  self.assertIn("Helper function called", stdout_value)
129
131
  self.assertIn("Tool function executed", stdout_value)
130
132
  self.assertIn("pkg_import_lib_py.glob_var_lib", stdout_value)
133
+
134
+ def test_jac_import_py_files(self) -> None:
135
+ """Test importing Python files using Jac import system."""
136
+ captured_output = io.StringIO()
137
+ sys.stdout = captured_output
138
+ os.environ["JAC_PYFILE_RAISE"] = "True"
139
+ settings.load_env_vars()
140
+ original_cwd = os.getcwd()
141
+ try:
142
+ os.chdir(os.path.dirname(self.fixture_abs_path("jac_import_py_files.py")))
143
+ Jac.set_base_path(self.fixture_abs_path("jac_import_py_files.py"))
144
+ JacMachineInterface.attach_program(
145
+ program:=JacProgram(),
146
+ )
147
+ Jac.jac_import("jac_import_py_files", base_path=self.fixture_abs_path("jac_import_py_files.py"), lng="py")
148
+ cli.run(self.fixture_abs_path("jac_import_py_files.py"))
149
+ sys.stdout = sys.__stdout__
150
+ stdout_value = captured_output.getvalue()
151
+ self.assertIn("This is main test file for jac import of python files", stdout_value)
152
+ self.assertIn("python_module <jaclang.compiler.unitree.Module object", str(program.mod.hub))
153
+ self.assertIn("jac_module <jaclang.compiler.unitree.Module object", str(program.mod.hub))
154
+ os.environ["JAC_PYFILE_RAISE"] = "false"
155
+ settings.load_env_vars()
156
+ os.chdir(os.path.dirname(self.fixture_abs_path("jac_import_py_files.py")))
157
+ Jac.set_base_path(self.fixture_abs_path("jac_import_py_files.py"))
158
+ JacMachineInterface.attach_program(
159
+ program:=JacProgram(),
160
+ )
161
+ Jac.jac_import("jac_import_py_files", base_path=self.fixture_abs_path("jac_import_py_files.py"), lng="py")
162
+ cli.run(self.fixture_abs_path("jac_import_py_files.py"))
163
+ sys.stdout = sys.__stdout__
164
+ stdout_value = captured_output.getvalue()
165
+ self.assertIn("This is main test file for jac import of python files", stdout_value)
166
+ self.assertNotIn("python_module <jaclang.compiler.unitree.Module object", str(program.mod.hub))
167
+ self.assertNotIn("jac_module <jaclang.compiler.unitree.Module object", str(program.mod.hub))
168
+ finally:
169
+ os.chdir(original_cwd)
@@ -179,5 +179,54 @@ class TestLarkParser(TestCaseMicroSuite):
179
179
  prog.compile(self.fixture_abs_path("codegentext.jac"))
180
180
  self.assertFalse(prog.errors_had)
181
181
 
182
+ def test_param_syntax(self) -> None:
183
+ """Parse param syntax jac file."""
184
+ captured_output = io.StringIO()
185
+ sys.stdout = captured_output
186
+ prog = JacProgram()
187
+ prog.compile(self.lang_fixture_abs_path("params/param_syntax_err.jac"))
188
+ sys.stdout = sys.__stdout__
189
+ self.assertEqual(len(prog.errors_had), 8)
190
+
191
+ def test_multiple_syntax_errors(self) -> None:
192
+ """Parse param syntax jac file."""
193
+ captured_output = io.StringIO()
194
+ sys.stdout = captured_output
195
+ prog = JacProgram()
196
+ prog.compile(self.fixture_abs_path("multiple_syntax_errors.jac"))
197
+ sys.stdout = sys.__stdout__
198
+ self.assertEqual(len(prog.errors_had), 3)
199
+ expected_errors = [
200
+ """
201
+ Missing RPAREN
202
+ with entry {
203
+ foo = Foo(;
204
+ ^
205
+ func(foo bar)
206
+ foo.bar;
207
+ """,
208
+ """
209
+ Missing COMMA
210
+ with entry {
211
+ foo = Foo(;
212
+ func(foo bar)
213
+ ^^^
214
+ foo.bar;
215
+ }
216
+ """,
217
+ """
218
+ Missing SEMI
219
+ foo = Foo(;
220
+ func(foo bar)
221
+ foo.bar;
222
+ ^^^
223
+ }
224
+ """
225
+ ]
226
+ for idx, alrt in enumerate(prog.errors_had):
227
+ pretty = alrt.pretty_print()
228
+ for line in expected_errors[idx].strip().split("\n"):
229
+ line = line.strip()
230
+ self.assertIn(line, pretty)
182
231
 
183
232
  TestLarkParser.self_attach_micro_tests()
@@ -0,0 +1,104 @@
1
+ # flake8: noqa: I300
2
+ """Provides type evaluation logic for unary, binary, augmented assignment and ternary operators.
3
+
4
+ PyrightReference: packages/pyright-internal/src/analyzer/operations.ts
5
+ """
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ import jaclang.compiler.unitree as uni
10
+ from jaclang.compiler.constant import Tokens as Tok
11
+
12
+ from . import types as jtypes
13
+
14
+ if TYPE_CHECKING:
15
+ # Type evaluator is the one depends on this module and not the way around.
16
+ # however this module needs a reference to the type evaluator.
17
+ from .type_evaluator import TypeEvaluator
18
+
19
+
20
+ # Maps binary operators to the magic methods that implement them.
21
+ BINARY_OPERATOR_MAP: dict[str, tuple[str, str]] = {
22
+ Tok.PLUS: ("__add__", "__radd__"),
23
+ Tok.MINUS: ("__sub__", "__rsub__"),
24
+ Tok.STAR_MUL: ("__mul__", "__rmul__"),
25
+ Tok.FLOOR_DIV: ("__floordiv__", "__rfloordiv__"),
26
+ Tok.DIV: ("__truediv__", "__rtruediv__"),
27
+ Tok.MOD: ("__mod__", "__rmod__"),
28
+ Tok.STAR_POW: ("__pow__", "__rpow__"),
29
+ Tok.DECOR_OP: ("__matmul__", "__rmatmul__"),
30
+ Tok.BW_AND: ("__and__", "__rand__"),
31
+ Tok.BW_OR: ("__or__", "__ror__"),
32
+ Tok.BW_XOR: ("__xor__", "__rxor__"),
33
+ Tok.LSHIFT: ("__lshift__", "__rlshift__"),
34
+ Tok.RSHIFT: ("__rshift__", "__rrshift__"),
35
+ Tok.EE: ("__eq__", "__eq__"),
36
+ Tok.NE: ("__ne__", "__ne__"),
37
+ Tok.LT: ("__lt__", "__gt__"),
38
+ Tok.LTE: ("__le__", "__ge__"),
39
+ Tok.GT: ("__gt__", "__lt__"),
40
+ Tok.GTE: ("__ge__", "__le__"),
41
+ }
42
+
43
+
44
+ # Mirror of the `export function getTypeOfBinaryOperation` function in pyright.
45
+ def get_type_of_binary_operation(
46
+ evaluator: "TypeEvaluator", expr: uni.BinaryExpr
47
+ ) -> jtypes.TypeBase:
48
+ """Return the binary operator's jtype."""
49
+ left_type = evaluator.get_type_of_expression(expr.left)
50
+ right_type = evaluator.get_type_of_expression(expr.right)
51
+
52
+ # TODO: Check how pyright is dealing with chaining operation (a < b < c < d) and
53
+ # it handles here with the condition `if operatorSupportsChaining()`.:
54
+
55
+ # TODO:
56
+ # Is this a "|" operator used in a context where it is supposed to be
57
+ # interpreted as a union operator?
58
+
59
+ # pyright is using another function however I don't see the need of it yet, so imma use
60
+ # the logic here, if needed define `validateBinaryOperation` for re-usability.
61
+
62
+ # TODO: Handle and, or
63
+ #
64
+ # <left> and <right> <--- This is equlavent to the bellow
65
+ #
66
+ # def left_and_right(left, right):
67
+ # if bool(left):
68
+ # return left
69
+ # return right
70
+ #
71
+ # And the type will be Union[left.type, right.type]
72
+ #
73
+
74
+ # NOTE: in will call `__contains__` magic method in custom type and should return `bool`
75
+ # however it can technically return anything otherthan `bool` and pyright is handing that way
76
+ # I don't see `__str__` method return anything other than string should be valid either.
77
+ if (expr.op in (Tok.KW_IS, Tok.KW_ISN, Tok.KW_IN, Tok.KW_NIN)) and (
78
+ evaluator.prefetch.bool_class is not None
79
+ ):
80
+ evaluator._convert_to_instance(evaluator.prefetch.bool_class)
81
+
82
+ # TODO: `expr.op` can be of 3 types, Token, connect, disconnect.
83
+ if isinstance(expr.op, uni.Token) and (expr.op.name in BINARY_OPERATOR_MAP):
84
+ # TODO: validateArithmeticOperation() has more cases and special conditions that we may
85
+ # need to implement in the future however in this simple case we're implementing the
86
+ # bare minimal checking.
87
+ magic, rmagic = BINARY_OPERATOR_MAP[expr.op.name]
88
+
89
+ # TODO: Handle overloaded call check:
90
+ # Grep this in pyright typeEvaluator.ts:
91
+ # callResult.overloadsUsedForCall.forEach((overload) => {
92
+ # overloadsUsedForCall.push(overload);
93
+ # ...
94
+ # });
95
+
96
+ # FIXME: We need to have validateCallArgs() method and do a check here before returning.
97
+ return (
98
+ evaluator.get_type_of_magic_method_call(left_type, magic)
99
+ or evaluator.get_type_of_magic_method_call(right_type, rmagic)
100
+ or jtypes.UnknownType()
101
+ )
102
+
103
+ # TODO: Handle for connect and disconnect operators.
104
+ return jtypes.UnknownType()