jaclang 0.7.23__py3-none-any.whl → 0.7.25__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/cli/cli.py +46 -29
- jaclang/compiler/__init__.py +2 -2
- jaclang/compiler/absyntree.py +87 -48
- jaclang/compiler/codeloc.py +7 -2
- jaclang/compiler/compile.py +10 -3
- jaclang/compiler/parser.py +26 -23
- jaclang/compiler/passes/ir_pass.py +2 -2
- jaclang/compiler/passes/main/def_impl_match_pass.py +46 -0
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +146 -123
- jaclang/compiler/passes/main/import_pass.py +6 -2
- jaclang/compiler/passes/main/pyast_load_pass.py +36 -35
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -7
- jaclang/compiler/passes/main/registry_pass.py +3 -12
- jaclang/compiler/passes/main/tests/fixtures/defn_decl_mismatch.jac +19 -0
- jaclang/compiler/passes/main/tests/fixtures/fstrings.jac +2 -0
- jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +59 -0
- jaclang/compiler/passes/main/tests/test_registry_pass.py +2 -10
- jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
- jaclang/compiler/passes/transform.py +27 -3
- jaclang/compiler/passes/utils/mypy_ast_build.py +246 -26
- jaclang/compiler/symtable.py +6 -0
- jaclang/compiler/tests/test_importer.py +2 -2
- jaclang/langserve/engine.py +14 -12
- jaclang/langserve/server.py +7 -2
- jaclang/langserve/tests/test_server.py +1 -1
- jaclang/langserve/utils.py +17 -3
- jaclang/plugin/default.py +32 -32
- jaclang/plugin/feature.py +2 -2
- jaclang/plugin/plugin.md +471 -0
- jaclang/plugin/spec.py +2 -1
- jaclang/runtimelib/context.py +2 -0
- jaclang/runtimelib/importer.py +7 -2
- jaclang/runtimelib/machine.py +21 -6
- jaclang/settings.py +3 -0
- jaclang/tests/fixtures/builtin_dotgen.jac +6 -6
- jaclang/tests/fixtures/enum_inside_archtype.jac +16 -11
- jaclang/tests/fixtures/expr_type.jac +54 -0
- jaclang/tests/fixtures/glob_multivar_statement.jac +15 -0
- jaclang/tests/fixtures/registry.jac +20 -8
- jaclang/tests/foo/__init__.jac +0 -0
- jaclang/tests/main.jac +2 -0
- jaclang/tests/test_cli.py +68 -4
- jaclang/tests/test_language.py +60 -27
- jaclang/utils/helpers.py +92 -14
- jaclang/utils/lang_tools.py +6 -2
- jaclang/utils/treeprinter.py +4 -2
- {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/METADATA +2 -1
- {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/RECORD +50 -44
- {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/WHEEL +1 -1
- {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
with entry {
|
|
2
|
+
a = 4;
|
|
3
|
+
b = 7;
|
|
4
|
+
c = a + b; # OpExpr.
|
|
5
|
+
d = a + b + c;
|
|
6
|
+
|
|
7
|
+
h = float(a); # CallExpr.
|
|
8
|
+
|
|
9
|
+
(1 < 2); # ComparisonExpr.
|
|
10
|
+
('a' + 'b').upper(); # CallExpr.
|
|
11
|
+
[1,2][0]; # IndexExpr.
|
|
12
|
+
not False; # UnaryExpr.
|
|
13
|
+
"a" if True else "b"; # ConditionalExpr.
|
|
14
|
+
[i for i in range(10)]; # ListComprehension.
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Remaining expressions to test:
|
|
18
|
+
# AssertTypeExpr,
|
|
19
|
+
# AssignmentExpr,
|
|
20
|
+
# AwaitExpr,
|
|
21
|
+
# BytesExpr,
|
|
22
|
+
# CastExpr,
|
|
23
|
+
# ComplexExpr,
|
|
24
|
+
# DictionaryComprehension,
|
|
25
|
+
# DictExpr,
|
|
26
|
+
# EllipsisExpr,
|
|
27
|
+
# EnumCallExpr,
|
|
28
|
+
# Expression,
|
|
29
|
+
# FloatExpr,
|
|
30
|
+
# GeneratorExpr,
|
|
31
|
+
# IntExpr,
|
|
32
|
+
# LambdaExpr,
|
|
33
|
+
# ListExpr,
|
|
34
|
+
# MemberExpr,
|
|
35
|
+
# NamedTupleExpr,
|
|
36
|
+
# NameExpr,
|
|
37
|
+
# NewTypeExpr,
|
|
38
|
+
# ParamSpecExpr,
|
|
39
|
+
# PromoteExpr,
|
|
40
|
+
# RefExpr,
|
|
41
|
+
# RevealExpr,
|
|
42
|
+
# SetComprehension,
|
|
43
|
+
# SetExpr,
|
|
44
|
+
# SliceExpr,
|
|
45
|
+
# StarExpr,
|
|
46
|
+
# StrExpr,
|
|
47
|
+
# SuperExpr,
|
|
48
|
+
# TupleExpr,
|
|
49
|
+
# TypeAliasExpr,
|
|
50
|
+
# TypedDictExpr,
|
|
51
|
+
# TypeVarExpr,
|
|
52
|
+
# TypeVarTupleExpr,
|
|
53
|
+
# YieldExpr,
|
|
54
|
+
# YieldFromExpr,
|
|
@@ -13,16 +13,16 @@ Person {
|
|
|
13
13
|
|
|
14
14
|
enum 'Personality of the Person'
|
|
15
15
|
Personality {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
INTROVERT: 'Person who is shy and reticent' = 9,
|
|
17
|
+
EXTROVERT: 'Person who is outgoing and socially confident'
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
glob personality_examples: 'Personality Information of Famous People': dict[str, Personality|None] = {
|
|
20
|
+
glob personality_examples: 'Personality Information of Famous People': dict[str, Personality | None] = {
|
|
21
21
|
'Albert Einstein': Personality.INTROVERT,
|
|
22
22
|
'Barack Obama': Personality.EXTROVERT
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
glob person_value
|
|
25
|
+
glob person_value: list[tuple[dict[str, Personality], int]] = (-90);
|
|
26
26
|
|
|
27
27
|
can 'GenAI ability'
|
|
28
28
|
genai_ability(x: 'Something': str) -> 'Something Else': str by llm();
|
|
@@ -34,13 +34,25 @@ normal_ability(x: 'Something': str) -> 'Something Else': str {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
can foo() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
person_value = 22;
|
|
38
|
+
can bar() {
|
|
39
|
+
person_value = 33;
|
|
40
|
+
}
|
|
41
41
|
}
|
|
42
42
|
with entry {
|
|
43
43
|
einstein_age: int = 75;
|
|
44
44
|
einstein_age += 1;
|
|
45
45
|
einstein = Person('Albert Einstein', einstein_age);
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
import from jaclang.runtimelib.machine { JacMachine }
|
|
49
|
+
|
|
50
|
+
with entry {
|
|
51
|
+
registry = JacMachine.get().jac_program.sem_ir;
|
|
52
|
+
|
|
53
|
+
print(len(registry.registry));
|
|
54
|
+
print(len(list(registry.registry.items())[0][1]));
|
|
55
|
+
print(list(registry.registry.items())[3][0].scope);
|
|
56
|
+
(_, sem_info) = registry.lookup(name="normal_ability");
|
|
57
|
+
print(len(sem_info.get_children(registry)));
|
|
58
|
+
}
|
|
File without changes
|
jaclang/tests/main.jac
ADDED
jaclang/tests/test_cli.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Test Jac cli module."""
|
|
2
2
|
|
|
3
|
+
import contextlib
|
|
3
4
|
import inspect
|
|
4
5
|
import io
|
|
5
6
|
import os
|
|
@@ -55,10 +56,8 @@ class JacCliTests(TestCase):
|
|
|
55
56
|
sys.stdout = captured_output
|
|
56
57
|
sys.stderr = captured_output
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
with contextlib.suppress(Exception):
|
|
59
60
|
cli.run(self.fixture_abs_path("err_runtime.jac"))
|
|
60
|
-
except Exception as e:
|
|
61
|
-
print(f"Error: {e}")
|
|
62
61
|
|
|
63
62
|
sys.stdout = sys.__stdout__
|
|
64
63
|
sys.stderr = sys.__stderr__
|
|
@@ -71,7 +70,6 @@ class JacCliTests(TestCase):
|
|
|
71
70
|
" at foo() ",
|
|
72
71
|
" at <module> ",
|
|
73
72
|
)
|
|
74
|
-
|
|
75
73
|
logger_capture = "\n".join([rec.message for rec in self.caplog.records])
|
|
76
74
|
for exp in expected_stdout_values:
|
|
77
75
|
self.assertIn(exp, logger_capture)
|
|
@@ -217,6 +215,42 @@ class JacCliTests(TestCase):
|
|
|
217
215
|
r"13\:12 \- 13\:18.*Name - append - .*SymbolPath: builtins_test.builtins.list.append",
|
|
218
216
|
)
|
|
219
217
|
|
|
218
|
+
def test_expr_types(self) -> None:
|
|
219
|
+
"""Testing for print AstTool."""
|
|
220
|
+
captured_output = io.StringIO()
|
|
221
|
+
sys.stdout = captured_output
|
|
222
|
+
|
|
223
|
+
cli.tool("ir", ["ast", f"{self.fixture_abs_path('expr_type.jac')}"])
|
|
224
|
+
|
|
225
|
+
sys.stdout = sys.__stdout__
|
|
226
|
+
stdout_value = captured_output.getvalue()
|
|
227
|
+
|
|
228
|
+
self.assertRegex(
|
|
229
|
+
stdout_value, r"4\:9 \- 4\:14.*BinaryExpr \- Type\: builtins.int"
|
|
230
|
+
)
|
|
231
|
+
self.assertRegex(
|
|
232
|
+
stdout_value, r"7\:9 \- 7\:17.*FuncCall \- Type\: builtins.float"
|
|
233
|
+
)
|
|
234
|
+
self.assertRegex(
|
|
235
|
+
stdout_value, r"9\:6 \- 9\:11.*CompareExpr \- Type\: builtins.bool"
|
|
236
|
+
)
|
|
237
|
+
self.assertRegex(
|
|
238
|
+
stdout_value, r"10\:6 - 10\:15.*BinaryExpr \- Type\: builtins.str"
|
|
239
|
+
)
|
|
240
|
+
self.assertRegex(
|
|
241
|
+
stdout_value, r"11\:5 \- 11\:13.*AtomTrailer \- Type\: builtins.int"
|
|
242
|
+
)
|
|
243
|
+
self.assertRegex(
|
|
244
|
+
stdout_value, r"12\:5 \- 12\:14.*UnaryExpr \- Type\: builtins.bool"
|
|
245
|
+
)
|
|
246
|
+
self.assertRegex(
|
|
247
|
+
stdout_value, r"13\:5 \- 13\:25.*IfElseExpr \- Type\: Literal\['a']\?"
|
|
248
|
+
)
|
|
249
|
+
self.assertRegex(
|
|
250
|
+
stdout_value,
|
|
251
|
+
r"14\:5 \- 14\:27.*ListCompr - \[ListCompr] \- Type\: builtins.list\[builtins.int]",
|
|
252
|
+
)
|
|
253
|
+
|
|
220
254
|
def test_ast_dotgen(self) -> None:
|
|
221
255
|
"""Testing for print AstTool."""
|
|
222
256
|
captured_output = io.StringIO()
|
|
@@ -247,6 +281,8 @@ class JacCliTests(TestCase):
|
|
|
247
281
|
self.assertEqual(stdout_value.count("type_info.ServerWrapper"), 7)
|
|
248
282
|
self.assertEqual(stdout_value.count("builtins.int"), 3)
|
|
249
283
|
self.assertEqual(stdout_value.count("builtins.str"), 10)
|
|
284
|
+
self.assertIn("Literal['test_server']", stdout_value)
|
|
285
|
+
self.assertIn("Literal['1']", stdout_value)
|
|
250
286
|
|
|
251
287
|
def test_build_and_run(self) -> None:
|
|
252
288
|
"""Testing for print AstTool."""
|
|
@@ -368,3 +404,31 @@ class JacCliTests(TestCase):
|
|
|
368
404
|
sys.stdout = sys.__stdout__
|
|
369
405
|
stdout_value = captured_output.getvalue()
|
|
370
406
|
self.assertIn("can my_print(x: object) -> None", stdout_value)
|
|
407
|
+
|
|
408
|
+
def test_caching_issue(self) -> None:
|
|
409
|
+
"""Test for Caching Issue."""
|
|
410
|
+
test_file = self.fixture_abs_path("test_caching_issue.jac")
|
|
411
|
+
test_cases = [(10, True), (11, False)]
|
|
412
|
+
for x, is_passed in test_cases:
|
|
413
|
+
with open(test_file, "w") as f:
|
|
414
|
+
f.write(
|
|
415
|
+
f"""
|
|
416
|
+
test mytest{{
|
|
417
|
+
check 10 == {x};
|
|
418
|
+
}}
|
|
419
|
+
"""
|
|
420
|
+
)
|
|
421
|
+
process = subprocess.Popen(
|
|
422
|
+
["jac", "test", test_file],
|
|
423
|
+
stdout=subprocess.PIPE,
|
|
424
|
+
stderr=subprocess.PIPE,
|
|
425
|
+
text=True,
|
|
426
|
+
)
|
|
427
|
+
stdout, stderr = process.communicate()
|
|
428
|
+
if is_passed:
|
|
429
|
+
self.assertIn("Passed successfully.", stdout)
|
|
430
|
+
self.assertIn(".", stderr)
|
|
431
|
+
else:
|
|
432
|
+
self.assertNotIn("Passed successfully.", stdout)
|
|
433
|
+
self.assertIn("F", stderr)
|
|
434
|
+
os.remove(test_file)
|
jaclang/tests/test_language.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import io
|
|
4
4
|
import os
|
|
5
|
-
import pickle
|
|
6
5
|
import sys
|
|
7
6
|
import sysconfig
|
|
8
7
|
|
|
@@ -24,7 +23,7 @@ class JacLanguageTests(TestCase):
|
|
|
24
23
|
"""Set up test."""
|
|
25
24
|
SUPER_ROOT_ANCHOR.edges.clear()
|
|
26
25
|
JacMachine(self.fixture_abs_path("./")).attach_program(
|
|
27
|
-
JacProgram(mod_bundle=None, bytecode=None)
|
|
26
|
+
JacProgram(mod_bundle=None, bytecode=None, sem_ir=None)
|
|
28
27
|
)
|
|
29
28
|
return super().setUp()
|
|
30
29
|
|
|
@@ -209,8 +208,10 @@ class JacLanguageTests(TestCase):
|
|
|
209
208
|
"""Test semstring."""
|
|
210
209
|
captured_output = io.StringIO()
|
|
211
210
|
sys.stdout = captured_output
|
|
211
|
+
sys.stderr = captured_output
|
|
212
212
|
jac_import("semstr", base_path=self.fixture_abs_path("./"))
|
|
213
213
|
sys.stdout = sys.__stdout__
|
|
214
|
+
sys.stderr = sys.__stderr__
|
|
214
215
|
stdout_value = captured_output.getvalue()
|
|
215
216
|
self.assertNotIn("Error", stdout_value)
|
|
216
217
|
|
|
@@ -237,6 +238,7 @@ class JacLanguageTests(TestCase):
|
|
|
237
238
|
self.assertEqual(stdout_value.split("\n")[0], "11 13 12 12 11 12 12")
|
|
238
239
|
self.assertEqual(stdout_value.split("\n")[1], '12 12 """hello""" 18 18')
|
|
239
240
|
self.assertEqual(stdout_value.split("\n")[2], "11 12 11 12 11 18 23")
|
|
241
|
+
self.assertEqual(stdout_value.split("\n")[3], 'hello klkl"""')
|
|
240
242
|
|
|
241
243
|
def test_deep_imports(self) -> None:
|
|
242
244
|
"""Parse micro jac file."""
|
|
@@ -465,24 +467,22 @@ class JacLanguageTests(TestCase):
|
|
|
465
467
|
"""Test Jac registry feature."""
|
|
466
468
|
captured_output = io.StringIO()
|
|
467
469
|
sys.stdout = captured_output
|
|
470
|
+
sys.stderr = captured_output
|
|
468
471
|
jac_import("registry", base_path=self.fixture_abs_path("./"))
|
|
469
472
|
sys.stdout = sys.__stdout__
|
|
473
|
+
sys.stderr = sys.__stderr__
|
|
470
474
|
stdout_value = captured_output.getvalue()
|
|
471
475
|
self.assertNotIn("Error", stdout_value)
|
|
472
476
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
"rb",
|
|
478
|
-
) as f:
|
|
479
|
-
registry = pickle.load(f)
|
|
477
|
+
output_lines = stdout_value.strip().split("\n")
|
|
478
|
+
outputs = [
|
|
479
|
+
int(output_lines[i]) if i != 2 else output_lines[i] for i in range(4)
|
|
480
|
+
]
|
|
480
481
|
|
|
481
|
-
self.assertEqual(
|
|
482
|
-
self.assertEqual(
|
|
483
|
-
self.assertEqual(
|
|
484
|
-
|
|
485
|
-
self.assertEqual(len(sem_info.get_children(registry)), 2)
|
|
482
|
+
self.assertEqual(outputs[0], 9)
|
|
483
|
+
self.assertEqual(outputs[1], 2)
|
|
484
|
+
self.assertEqual(outputs[2], "Person")
|
|
485
|
+
self.assertEqual(outputs[3], 2)
|
|
486
486
|
|
|
487
487
|
def test_enum_inside_arch(self) -> None:
|
|
488
488
|
"""Test Enum as member stmt."""
|
|
@@ -491,7 +491,7 @@ class JacLanguageTests(TestCase):
|
|
|
491
491
|
jac_import("enum_inside_archtype", base_path=self.fixture_abs_path("./"))
|
|
492
492
|
sys.stdout = sys.__stdout__
|
|
493
493
|
stdout_value = captured_output.getvalue()
|
|
494
|
-
self.
|
|
494
|
+
self.assertIn("2 Accessing privileged Data", stdout_value)
|
|
495
495
|
|
|
496
496
|
def test_needs_import_1(self) -> None:
|
|
497
497
|
"""Test py ast to Jac ast conversion output."""
|
|
@@ -503,10 +503,13 @@ class JacLanguageTests(TestCase):
|
|
|
503
503
|
import jaclang.compiler.absyntree as ast
|
|
504
504
|
|
|
505
505
|
with open(file_name, "r") as f:
|
|
506
|
-
|
|
506
|
+
file_source = f.read()
|
|
507
|
+
parsed_ast = py_ast.parse(file_source)
|
|
507
508
|
try:
|
|
508
509
|
py_ast_build_pass = PyastBuildPass(
|
|
509
|
-
input_ir=ast.PythonModuleAst(
|
|
510
|
+
input_ir=ast.PythonModuleAst(
|
|
511
|
+
parsed_ast, orig_src=ast.JacSource(file_source, file_name)
|
|
512
|
+
),
|
|
510
513
|
)
|
|
511
514
|
except Exception as e:
|
|
512
515
|
return f"Error While Jac to Py AST conversion: {e}"
|
|
@@ -528,9 +531,11 @@ class JacLanguageTests(TestCase):
|
|
|
528
531
|
|
|
529
532
|
py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_1.py")
|
|
530
533
|
with open(py_out_path) as f:
|
|
534
|
+
file_source = f.read()
|
|
531
535
|
output = PyastBuildPass(
|
|
532
536
|
input_ir=ast.PythonModuleAst(
|
|
533
|
-
py_ast.parse(
|
|
537
|
+
py_ast.parse(file_source),
|
|
538
|
+
orig_src=ast.JacSource(file_source, py_out_path),
|
|
534
539
|
),
|
|
535
540
|
).ir.unparse()
|
|
536
541
|
# print(output)
|
|
@@ -559,10 +564,14 @@ class JacLanguageTests(TestCase):
|
|
|
559
564
|
import jaclang.compiler.absyntree as ast
|
|
560
565
|
|
|
561
566
|
with open(file_name, "r") as f:
|
|
562
|
-
|
|
567
|
+
file_source = f.read()
|
|
568
|
+
parsed_ast = py_ast.parse(file_source)
|
|
563
569
|
try:
|
|
564
570
|
py_ast_build_pass = PyastBuildPass(
|
|
565
|
-
input_ir=ast.PythonModuleAst(
|
|
571
|
+
input_ir=ast.PythonModuleAst(
|
|
572
|
+
parsed_ast,
|
|
573
|
+
orig_src=ast.JacSource(file_source, file_name),
|
|
574
|
+
),
|
|
566
575
|
)
|
|
567
576
|
except Exception as e:
|
|
568
577
|
return f"Error While Jac to Py AST conversion: {e}"
|
|
@@ -587,9 +596,11 @@ class JacLanguageTests(TestCase):
|
|
|
587
596
|
|
|
588
597
|
py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_2.py")
|
|
589
598
|
with open(py_out_path) as f:
|
|
599
|
+
file_source = f.read()
|
|
590
600
|
output = PyastBuildPass(
|
|
591
601
|
input_ir=ast.PythonModuleAst(
|
|
592
|
-
py_ast.parse(
|
|
602
|
+
py_ast.parse(file_source),
|
|
603
|
+
orig_src=ast.JacSource(file_source, py_out_path),
|
|
593
604
|
),
|
|
594
605
|
).ir.unparse()
|
|
595
606
|
self.assertIn("class X {\n with entry {\n\n a_b = 67;", output)
|
|
@@ -607,10 +618,14 @@ class JacLanguageTests(TestCase):
|
|
|
607
618
|
import jaclang.compiler.absyntree as ast
|
|
608
619
|
|
|
609
620
|
with open(file_name, "r") as f:
|
|
610
|
-
|
|
621
|
+
file_source = f.read()
|
|
622
|
+
parsed_ast = py_ast.parse(file_source)
|
|
611
623
|
try:
|
|
612
624
|
py_ast_build_pass = PyastBuildPass(
|
|
613
|
-
input_ir=ast.PythonModuleAst(
|
|
625
|
+
input_ir=ast.PythonModuleAst(
|
|
626
|
+
parsed_ast,
|
|
627
|
+
orig_src=ast.JacSource(file_source, file_name),
|
|
628
|
+
),
|
|
614
629
|
)
|
|
615
630
|
except Exception as e:
|
|
616
631
|
return f"Error While Jac to Py AST conversion: {e}"
|
|
@@ -634,9 +649,11 @@ class JacLanguageTests(TestCase):
|
|
|
634
649
|
|
|
635
650
|
py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_3.py")
|
|
636
651
|
with open(py_out_path) as f:
|
|
652
|
+
file_source = f.read()
|
|
637
653
|
output = PyastBuildPass(
|
|
638
654
|
input_ir=ast.PythonModuleAst(
|
|
639
|
-
py_ast.parse(
|
|
655
|
+
py_ast.parse(file_source),
|
|
656
|
+
orig_src=ast.JacSource(file_source, py_out_path),
|
|
640
657
|
),
|
|
641
658
|
).ir.unparse()
|
|
642
659
|
self.assertIn("if 0 <= x<= 5 {", output)
|
|
@@ -761,9 +778,11 @@ class JacLanguageTests(TestCase):
|
|
|
761
778
|
module_path + ".py",
|
|
762
779
|
)
|
|
763
780
|
with open(file_path) as f:
|
|
781
|
+
file_source = f.read()
|
|
764
782
|
jac_ast = PyastBuildPass(
|
|
765
783
|
input_ir=ast.PythonModuleAst(
|
|
766
|
-
py_ast.parse(
|
|
784
|
+
py_ast.parse(file_source),
|
|
785
|
+
orig_src=ast.JacSource(file_source, file_path),
|
|
767
786
|
)
|
|
768
787
|
)
|
|
769
788
|
settings.print_py_raised_ast = True
|
|
@@ -786,11 +805,13 @@ class JacLanguageTests(TestCase):
|
|
|
786
805
|
"""Test for access tags working."""
|
|
787
806
|
captured_output = io.StringIO()
|
|
788
807
|
sys.stdout = captured_output
|
|
808
|
+
sys.stderr = captured_output
|
|
789
809
|
cli.check(
|
|
790
810
|
self.fixture_abs_path("../../tests/fixtures/access_modifier.jac"),
|
|
791
811
|
print_errs=True,
|
|
792
812
|
)
|
|
793
813
|
sys.stdout = sys.__stdout__
|
|
814
|
+
sys.stderr = sys.__stderr__
|
|
794
815
|
stdout_value = captured_output.getvalue()
|
|
795
816
|
self.assertEqual(stdout_value.count("Invalid access"), 18)
|
|
796
817
|
|
|
@@ -808,10 +829,12 @@ class JacLanguageTests(TestCase):
|
|
|
808
829
|
parsed_ast = py_ast.parse(f.read())
|
|
809
830
|
try:
|
|
810
831
|
py_ast_build_pass = PyastBuildPass(
|
|
811
|
-
input_ir=ast.PythonModuleAst(
|
|
832
|
+
input_ir=ast.PythonModuleAst(
|
|
833
|
+
parsed_ast, orig_src=ast.JacSource(f.read(), file_name)
|
|
834
|
+
)
|
|
812
835
|
)
|
|
813
836
|
except Exception as e:
|
|
814
|
-
|
|
837
|
+
raise Exception(f"Error While Jac to Py AST conversion: {e}")
|
|
815
838
|
|
|
816
839
|
settings.print_py_raised_ast = True
|
|
817
840
|
ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
|
|
@@ -1156,3 +1179,13 @@ class JacLanguageTests(TestCase):
|
|
|
1156
1179
|
sys.stdout = sys.__stdout__
|
|
1157
1180
|
stdout_value = captured_output.getvalue()
|
|
1158
1181
|
self.assertEqual("[MyNode(Name='End'), MyNode(Name='Middle')]\n", stdout_value)
|
|
1182
|
+
|
|
1183
|
+
def test_global_multivar(self) -> None:
|
|
1184
|
+
"""Test supporting multiple global variable in a statement."""
|
|
1185
|
+
captured_output = io.StringIO()
|
|
1186
|
+
sys.stdout = captured_output
|
|
1187
|
+
jac_import("glob_multivar_statement", base_path=self.fixture_abs_path("./"))
|
|
1188
|
+
sys.stdout = sys.__stdout__
|
|
1189
|
+
stdout_value = captured_output.getvalue().split("\n")
|
|
1190
|
+
self.assertIn("Hello World !", stdout_value[0])
|
|
1191
|
+
self.assertIn("Welcome to Jaseci!", stdout_value[1])
|
jaclang/utils/helpers.py
CHANGED
|
@@ -147,7 +147,7 @@ def dump_traceback(e: Exception) -> str:
|
|
|
147
147
|
return len(string.encode("utf-8")[:offset].decode("utf-8", errors="replace"))
|
|
148
148
|
|
|
149
149
|
tb = TracebackException(type(e), e, e.__traceback__, limit=None, compact=True)
|
|
150
|
-
trace_dump += f"Error: {str(e)}"
|
|
150
|
+
trace_dump += f"Error: {str(e)}\n"
|
|
151
151
|
|
|
152
152
|
# The first frame is the call the to the above `exec` function, not usefull to the enduser,
|
|
153
153
|
# and Make the most recent call first.
|
|
@@ -155,33 +155,111 @@ def dump_traceback(e: Exception) -> str:
|
|
|
155
155
|
tb.stack.reverse()
|
|
156
156
|
|
|
157
157
|
# FIXME: should be some settings, we should replace to ensure the anchors length match.
|
|
158
|
-
dump_tab_width =
|
|
158
|
+
dump_tab_width = 2
|
|
159
159
|
|
|
160
160
|
for idx, frame in enumerate(tb.stack):
|
|
161
161
|
func_signature = frame.name + ("()" if frame.name.isidentifier() else "")
|
|
162
162
|
|
|
163
163
|
# Pretty print the most recent call's location.
|
|
164
|
-
if idx == 0 and (
|
|
164
|
+
if idx == 0 and (
|
|
165
|
+
(frame.lineno is not None) and frame.line and frame.line.strip() != ""
|
|
166
|
+
):
|
|
167
|
+
|
|
165
168
|
line_o = frame._original_line.rstrip() # type: ignore [attr-defined]
|
|
166
|
-
line_s = frame.line.rstrip() if frame.line else ""
|
|
167
|
-
stripped_chars = len(line_o) - len(line_s)
|
|
168
|
-
trace_dump += f'\n{" " * (dump_tab_width * 2)}{line_s}'
|
|
169
169
|
if frame.colno is not None and frame.end_colno is not None:
|
|
170
|
-
off_start = byte_offset_to_char_offset(line_o, frame.colno)
|
|
171
|
-
off_end = byte_offset_to_char_offset(line_o, frame.end_colno)
|
|
172
|
-
|
|
173
|
-
#
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
off_start = byte_offset_to_char_offset(line_o, frame.colno) - 1
|
|
171
|
+
off_end = byte_offset_to_char_offset(line_o, frame.end_colno) - 1
|
|
172
|
+
|
|
173
|
+
# Get the source.
|
|
174
|
+
file_source = None
|
|
175
|
+
with open(frame.filename, "r") as file:
|
|
176
|
+
file_source = file.read()
|
|
177
|
+
|
|
178
|
+
# Get the source offset.
|
|
179
|
+
lines = file_source.split("\n")
|
|
180
|
+
for i in range(frame.lineno - 1):
|
|
181
|
+
off_start += len(lines[i]) + 1
|
|
182
|
+
off_end += len(lines[i]) + 1
|
|
183
|
+
|
|
184
|
+
trace_dump += pretty_print_source_location(
|
|
185
|
+
frame.filename, file_source, frame.lineno, off_start, off_end
|
|
176
186
|
)
|
|
177
187
|
|
|
178
|
-
trace_dump += f'\n{" " * (dump_tab_width * 2)}{anchors}'
|
|
179
|
-
|
|
180
188
|
trace_dump += f'\n{" " * dump_tab_width}at {func_signature} {frame.filename}:{frame.lineno}'
|
|
181
189
|
|
|
182
190
|
return trace_dump
|
|
183
191
|
|
|
184
192
|
|
|
193
|
+
# TODO: After implementing the TextRange (or simillar named) class to mark a text range
|
|
194
|
+
# refactor the parameter to accept an instace of that text range object.
|
|
195
|
+
def pretty_print_source_location(
|
|
196
|
+
file_path: str,
|
|
197
|
+
file_source: str,
|
|
198
|
+
error_line: int,
|
|
199
|
+
pos_start: int,
|
|
200
|
+
pos_end: int,
|
|
201
|
+
) -> str:
|
|
202
|
+
"""Pretty print internal method for the pretty_print method."""
|
|
203
|
+
# NOTE: The Line numbers and the column numbers are starts with 1.
|
|
204
|
+
# We print totally 5 lines (error line and above 2 and bellow 2).
|
|
205
|
+
|
|
206
|
+
# The width of the line number we'll be printing (more of a settings).
|
|
207
|
+
line_num_width: int = 5
|
|
208
|
+
|
|
209
|
+
idx: int = pos_start # Pointer for the current character.
|
|
210
|
+
|
|
211
|
+
if file_source == "" or file_path == "":
|
|
212
|
+
return ""
|
|
213
|
+
|
|
214
|
+
start_line: int = error_line - 2
|
|
215
|
+
if start_line < 1:
|
|
216
|
+
start_line = 1
|
|
217
|
+
end_line: int = start_line + 5 # Index is exclusive.
|
|
218
|
+
|
|
219
|
+
# Get the first character of the [start_line].
|
|
220
|
+
file_source.splitlines(True)[start_line - 1]
|
|
221
|
+
curr_line: int = error_line
|
|
222
|
+
while idx >= 0 and curr_line >= start_line:
|
|
223
|
+
idx -= 1
|
|
224
|
+
if idx < 0:
|
|
225
|
+
break
|
|
226
|
+
if file_source[idx] == "\n":
|
|
227
|
+
curr_line -= 1
|
|
228
|
+
|
|
229
|
+
idx += 1 # Enter the line.
|
|
230
|
+
assert idx == 0 or file_source[idx - 1] == "\n"
|
|
231
|
+
|
|
232
|
+
pretty_dump = ""
|
|
233
|
+
|
|
234
|
+
# Print each lines.
|
|
235
|
+
curr_line = start_line
|
|
236
|
+
while curr_line < end_line:
|
|
237
|
+
pretty_dump += f"%{line_num_width}d | " % curr_line
|
|
238
|
+
|
|
239
|
+
idx_line_start = idx
|
|
240
|
+
while idx < len(file_source) and file_source[idx] != "\n":
|
|
241
|
+
idx += 1 # Run to the line end.
|
|
242
|
+
pretty_dump += file_source[idx_line_start:idx]
|
|
243
|
+
pretty_dump += "\n"
|
|
244
|
+
|
|
245
|
+
if curr_line == error_line: # Print the current line with indicator.
|
|
246
|
+
pretty_dump += f"%{line_num_width}s | " % " "
|
|
247
|
+
|
|
248
|
+
spaces = ""
|
|
249
|
+
for idx_pre in range(idx_line_start, pos_start):
|
|
250
|
+
spaces += "\t" if file_source[idx_pre] == "\t" else " "
|
|
251
|
+
|
|
252
|
+
err_token_len = pos_end - pos_start
|
|
253
|
+
pretty_dump += spaces + ("^" * err_token_len) + "\n"
|
|
254
|
+
|
|
255
|
+
if idx == len(file_source):
|
|
256
|
+
break
|
|
257
|
+
curr_line += 1
|
|
258
|
+
idx += 1
|
|
259
|
+
|
|
260
|
+
return pretty_dump[:-1] # Get rid of the last newline (of the last line).
|
|
261
|
+
|
|
262
|
+
|
|
185
263
|
class Jdb(pdb.Pdb):
|
|
186
264
|
"""Jac debugger."""
|
|
187
265
|
|
jaclang/utils/lang_tools.py
CHANGED
|
@@ -215,12 +215,16 @@ class AstTool:
|
|
|
215
215
|
|
|
216
216
|
if file_name.endswith(".py"):
|
|
217
217
|
with open(file_name, "r") as f:
|
|
218
|
-
|
|
218
|
+
file_source = f.read()
|
|
219
|
+
parsed_ast = py_ast.parse(file_source)
|
|
219
220
|
if output == "pyast":
|
|
220
221
|
return f"\n{py_ast.dump(parsed_ast, indent=2)}"
|
|
221
222
|
try:
|
|
222
223
|
rep = PyastBuildPass(
|
|
223
|
-
input_ir=ast.PythonModuleAst(
|
|
224
|
+
input_ir=ast.PythonModuleAst(
|
|
225
|
+
parsed_ast,
|
|
226
|
+
orig_src=ast.JacSource(file_source, file_name),
|
|
227
|
+
),
|
|
224
228
|
).ir
|
|
225
229
|
|
|
226
230
|
schedule = py_code_gen_typed
|
jaclang/utils/treeprinter.py
CHANGED
|
@@ -105,7 +105,7 @@ def print_ast_tree(
|
|
|
105
105
|
if isinstance(node, Token) and isinstance(node, AstSymbolNode):
|
|
106
106
|
out = (
|
|
107
107
|
f"{node.__class__.__name__} - {node.value} - "
|
|
108
|
-
f"Type: {node.
|
|
108
|
+
f"Type: {node.expr_type}, {access} {sym_table_link}"
|
|
109
109
|
)
|
|
110
110
|
if settings.ast_symbol_info_detailed:
|
|
111
111
|
symbol = (
|
|
@@ -133,7 +133,7 @@ def print_ast_tree(
|
|
|
133
133
|
elif isinstance(node, AstSymbolNode):
|
|
134
134
|
out = (
|
|
135
135
|
f"{node.__class__.__name__} - {node.sym_name} - "
|
|
136
|
-
f"Type: {node.
|
|
136
|
+
f"Type: {node.expr_type}, {access} {sym_table_link}"
|
|
137
137
|
)
|
|
138
138
|
if settings.ast_symbol_info_detailed:
|
|
139
139
|
symbol = (
|
|
@@ -143,6 +143,8 @@ def print_ast_tree(
|
|
|
143
143
|
)
|
|
144
144
|
out += f" SymbolPath: {symbol}"
|
|
145
145
|
return out
|
|
146
|
+
elif isinstance(node, ast.Expr):
|
|
147
|
+
return f"{node.__class__.__name__} - Type: {node.expr_type}"
|
|
146
148
|
else:
|
|
147
149
|
return f"{node.__class__.__name__}, {access}"
|
|
148
150
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: jaclang
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.25
|
|
4
4
|
Summary: Jac is a unique and powerful programming language that runs on top of Python, offering an unprecedented level of intelligence and intuitive understanding.
|
|
5
5
|
Home-page: https://jaseci.org
|
|
6
6
|
License: MIT
|
|
@@ -14,6 +14,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
18
|
Provides-Extra: all
|
|
18
19
|
Provides-Extra: llm
|
|
19
20
|
Provides-Extra: streamlit
|