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.
- jaclang/cli/cli.md +3 -3
- jaclang/cli/cli.py +37 -37
- jaclang/cli/cmdreg.py +45 -140
- jaclang/compiler/constant.py +0 -1
- jaclang/compiler/jac.lark +3 -6
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +213 -34
- jaclang/compiler/passes/main/__init__.py +2 -4
- jaclang/compiler/passes/main/def_use_pass.py +0 -4
- jaclang/compiler/passes/main/predynamo_pass.py +221 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +83 -55
- jaclang/compiler/passes/main/pyast_load_pass.py +66 -40
- jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
- jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
- jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
- jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_binary_op.jac +21 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_call_expr_class.jac +12 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_cyclic_symbol.jac +4 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_expr_call.jac +9 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_import_missing_module.jac +13 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_magic_call.jac +17 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_mod_path.jac +8 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
- jaclang/compiler/passes/main/tests/test_checker_pass.py +265 -0
- jaclang/compiler/passes/main/tests/test_predynamo_pass.py +57 -0
- jaclang/compiler/passes/main/type_checker_pass.py +36 -61
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +204 -44
- jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +171 -11
- jaclang/compiler/passes/transform.py +12 -8
- jaclang/compiler/program.py +14 -6
- jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
- jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
- jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
- jaclang/compiler/tests/fixtures/python_module.py +1 -0
- jaclang/compiler/tests/test_importer.py +39 -0
- jaclang/compiler/tests/test_parser.py +49 -0
- jaclang/compiler/type_system/operations.py +104 -0
- jaclang/compiler/type_system/type_evaluator.py +470 -47
- jaclang/compiler/type_system/type_utils.py +246 -0
- jaclang/compiler/type_system/types.py +58 -2
- jaclang/compiler/unitree.py +79 -94
- jaclang/langserve/engine.jac +253 -230
- jaclang/langserve/server.jac +46 -15
- jaclang/langserve/tests/fixtures/circle.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
- jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
- jaclang/langserve/tests/server_test/circle_template.jac +80 -0
- jaclang/langserve/tests/server_test/glob_template.jac +4 -0
- jaclang/langserve/tests/server_test/test_lang_serve.py +154 -312
- jaclang/langserve/tests/server_test/utils.py +153 -116
- jaclang/langserve/tests/test_dev_server.py +1 -1
- jaclang/langserve/tests/test_server.py +30 -86
- jaclang/langserve/utils.jac +56 -63
- jaclang/runtimelib/machine.py +7 -0
- jaclang/runtimelib/meta_importer.py +27 -1
- jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
- jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
- jaclang/settings.py +18 -14
- jaclang/tests/fixtures/abc_check.jac +3 -3
- jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
- jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
- jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
- jaclang/tests/fixtures/jac_run_py_bugs.py +18 -0
- jaclang/tests/fixtures/jac_run_py_import.py +13 -0
- jaclang/tests/fixtures/lambda_arg_annotation.jac +15 -0
- jaclang/tests/fixtures/lambda_self.jac +18 -0
- jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
- jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
- jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
- jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
- jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
- jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
- jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
- jaclang/tests/fixtures/py2jac_params.py +8 -0
- jaclang/tests/fixtures/run_test.jac +4 -4
- jaclang/tests/test_cli.py +103 -18
- jaclang/tests/test_language.py +74 -16
- jaclang/utils/helpers.py +47 -2
- jaclang/utils/module_resolver.py +11 -1
- jaclang/utils/test.py +8 -0
- jaclang/utils/treeprinter.py +0 -18
- {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/METADATA +3 -3
- {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/RECORD +99 -62
- {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/WHEEL +1 -1
- jaclang/compiler/passes/main/inheritance_pass.py +0 -131
- jaclang/langserve/dev_engine.jac +0 -645
- jaclang/langserve/dev_server.jac +0 -201
- jaclang/langserve/tests/server_test/code_test.py +0 -0
- {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Test failing positional-only parameter cases
|
|
2
|
+
|
|
3
|
+
def strict_posonly(a: int, b: str, /) -> str {
|
|
4
|
+
return f"{a}: {b}";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
def mixed_posonly(x: int, /, y: str, z: float = 1.0) -> str {
|
|
8
|
+
return f"{x}-{y}-{z}";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def complex_posonly(a: int, b: str = "def", /, c: float, *args: int, kw: bool, **kwargs: any) -> dict {
|
|
12
|
+
return {"a": a, "b": b, "c": c, "args": list(args), "kw": kw, "kwargs": kwargs};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def edge_case_posonly(/, x: int) -> int {
|
|
16
|
+
return x;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def no_regular_params(a: int, /, *, b: str) -> str {
|
|
20
|
+
return f"{a}: {b}";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
with entry {
|
|
24
|
+
print("=== TESTING POSITIONAL-ONLY FAILURES ===");
|
|
25
|
+
|
|
26
|
+
# Test 1: Calling pos-only with keyword arguments
|
|
27
|
+
try {
|
|
28
|
+
result = strict_posonly(a=10, b="test");
|
|
29
|
+
print("❌ FAIL: Should reject pos-only as keywords");
|
|
30
|
+
} except Exception as e {
|
|
31
|
+
print("✅ PASS: Caught pos-only keyword error");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Test 2: Partial keyword arguments on pos-only
|
|
35
|
+
try {
|
|
36
|
+
result = strict_posonly(10, b="test");
|
|
37
|
+
print("❌ FAIL: Should reject mixed pos-only calling");
|
|
38
|
+
} except Exception as e {
|
|
39
|
+
print("✅ PASS: Caught mixed pos-only error");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Test 3: Too many positional arguments
|
|
43
|
+
try {
|
|
44
|
+
result = strict_posonly(1, "test", "extra");
|
|
45
|
+
print("❌ FAIL: Should reject too many args");
|
|
46
|
+
} except Exception as e {
|
|
47
|
+
print("✅ PASS: Caught too many args error");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Test 4: Missing required positional-only
|
|
51
|
+
try {
|
|
52
|
+
result = strict_posonly(42);
|
|
53
|
+
print("❌ FAIL: Should reject missing required pos-only");
|
|
54
|
+
} except Exception as e {
|
|
55
|
+
print("✅ PASS: Caught missing pos-only error");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Test 5: Mixed signature - wrong keyword usage
|
|
59
|
+
try {
|
|
60
|
+
result = mixed_posonly(x=10, y="test");
|
|
61
|
+
print("❌ FAIL: Should reject pos-only x as keyword");
|
|
62
|
+
} except Exception as e {
|
|
63
|
+
print("✅ PASS: Caught mixed signature error");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Test 6: Complex signature - pos-only as keyword
|
|
67
|
+
try {
|
|
68
|
+
result = complex_posonly(a=1, c=2.5, kw=True);
|
|
69
|
+
print("❌ FAIL: Should reject pos-only a as keyword");
|
|
70
|
+
} except Exception as e {
|
|
71
|
+
print("✅ PASS: Caught complex pos-only error");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Test 7: Edge case - only separator with keyword
|
|
75
|
+
try {
|
|
76
|
+
result = edge_case_posonly(x=42);
|
|
77
|
+
print("✅ PASS: Edge case works:", result);
|
|
78
|
+
} except Exception as e {
|
|
79
|
+
print("✅ PASS: Edge case properly rejected");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Test 8: No regular params - wrong calling pattern
|
|
83
|
+
try {
|
|
84
|
+
result = no_regular_params(1, "test");
|
|
85
|
+
print("❌ FAIL: Should reject positional for keyword-only");
|
|
86
|
+
} except Exception as e {
|
|
87
|
+
print("✅ PASS: Caught no-regular-params error");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
result = strict_posonly("not_int", "test");
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# Test 10: Empty call to required pos-only
|
|
95
|
+
try {
|
|
96
|
+
result = strict_posonly();
|
|
97
|
+
print("❌ FAIL: Should reject empty call");
|
|
98
|
+
} except Exception as e {
|
|
99
|
+
print("✅ PASS: Caught empty call error");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Test 11: Valid calls that should work
|
|
103
|
+
try {
|
|
104
|
+
result = strict_posonly(42, "valid");
|
|
105
|
+
print("✅ PASS: Valid pos-only call:", result);
|
|
106
|
+
} except Exception as e {
|
|
107
|
+
print("❌ FAIL: Valid call rejected");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
result = mixed_posonly(1, "test", 3.14);
|
|
112
|
+
print("✅ PASS: Valid mixed call:", result);
|
|
113
|
+
} except Exception as e {
|
|
114
|
+
print("❌ FAIL: Valid mixed call rejected");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# Test failing variable arguments cases (*args, **kwargs)
|
|
2
|
+
|
|
3
|
+
def simple_args_only(*args: int) -> int {
|
|
4
|
+
return sum(args);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
def simple_kwargs_only(**kwargs: str) -> int {
|
|
8
|
+
return len(kwargs);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def args_with_required(req: str, *args: int) -> str {
|
|
12
|
+
return f"{req}: {sum(args)}";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def kwargs_with_required(req: int, **kwargs: str) -> dict {
|
|
16
|
+
return {"req": req, "kwargs": kwargs};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def full_varargs_signature(
|
|
20
|
+
pos: int,
|
|
21
|
+
/,
|
|
22
|
+
reg: str,
|
|
23
|
+
def_param: float = 1.0,
|
|
24
|
+
*args: int,
|
|
25
|
+
kw_req: bool,
|
|
26
|
+
kw_opt: str = "default",
|
|
27
|
+
**kwargs: any
|
|
28
|
+
) -> dict {
|
|
29
|
+
return {
|
|
30
|
+
"pos": pos, "reg": reg, "def_param": def_param,
|
|
31
|
+
"args": list(args), "kw_req": kw_req, "kw_opt": kw_opt, "kwargs": kwargs
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
def conflicting_names(name: str, *args: str, name_kw: str, **kwargs: str) -> dict {
|
|
36
|
+
return {"name": name, "args": list(args), "name_kw": name_kw, "kwargs": kwargs};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def type_sensitive_varargs(*args: int, **kwargs: int) -> dict {
|
|
40
|
+
return {"args_sum": sum(args), "kwargs_sum": sum(kwargs.values())};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def edge_case_empty_varargs(required: str, *args: float, **kwargs: bool) -> str {
|
|
44
|
+
return f"{required}: args={len(args)}, kwargs={len(kwargs)}";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
def double_star_issues(**kwargs: dict) -> int {
|
|
48
|
+
total = 0;
|
|
49
|
+
for (k, v) in kwargs.items() {
|
|
50
|
+
if isinstance(v, dict) {
|
|
51
|
+
total += len(v);
|
|
52
|
+
} else {
|
|
53
|
+
total += 1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return total;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
def additional_varargs_edge_cases() -> None {
|
|
60
|
+
print("\n=== ADDITIONAL VARARGS EDGE CASES ===");
|
|
61
|
+
|
|
62
|
+
# Test 16: Empty containers passed to varargs
|
|
63
|
+
def test_empty_containers(*args: list, **kwargs: dict) -> dict {
|
|
64
|
+
return {"args_count": len(args), "kwargs_count": len(kwargs)};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
result = test_empty_containers([], {}, third_arg=[]);
|
|
69
|
+
print("✅ PASS: Empty containers:", result);
|
|
70
|
+
} except Exception as e {
|
|
71
|
+
print("❌ FAIL: Empty containers failed");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Test 17: Nested data structures
|
|
75
|
+
def complex_data_varargs(*args: dict, **kwargs: list) -> dict {
|
|
76
|
+
return {"total_keys": sum(args), "total_items": len(kwargs)};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
result = complex_data_varargs(
|
|
81
|
+
12,
|
|
82
|
+
16,
|
|
83
|
+
list1=[1, 2, 3],
|
|
84
|
+
list2=[4, 5]
|
|
85
|
+
);
|
|
86
|
+
print("✅ PASS: Complex data structures:", result);
|
|
87
|
+
} except Exception as e {
|
|
88
|
+
print("❌ FAIL: Complex data structures failed");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# Test 18: Special character handling in kwargs keys
|
|
92
|
+
def special_chars_kwargs(**kwargs: str) -> dict {
|
|
93
|
+
return {"keys": list(kwargs.keys()), "count": len(kwargs)};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
# Note: Most of these won't work as valid identifiers, but let's test what we can
|
|
98
|
+
result = special_chars_kwargs(normal="value", with_underscore="test");
|
|
99
|
+
print("✅ PASS: Special chars in kwargs:", result);
|
|
100
|
+
} except Exception as e {
|
|
101
|
+
print("❌ FAIL: Special chars failed");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Test 19: Very large argument counts
|
|
105
|
+
def stress_test_args(*args: int) -> dict {
|
|
106
|
+
return {"count": len(args), "sum": sum(args), "avg": sum(args)/len(args) if args else 0};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
large_args = list(range(100)); # 100 arguments
|
|
111
|
+
result = stress_test_args(*large_args);
|
|
112
|
+
print("✅ PASS: Large arg count:", f"count={result['count']}, avg={result['avg']}");
|
|
113
|
+
} except Exception as e {
|
|
114
|
+
print("❌ FAIL: Large arg count failed");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# Test 20: Mixing unpacking with explicit args
|
|
118
|
+
def mixed_unpacking_test(first: str, *args: int, last: str, **kwargs: bool) -> dict {
|
|
119
|
+
_sum = sum(args);
|
|
120
|
+
_kwargs_true_count = 0;
|
|
121
|
+
for v in kwargs.values() {
|
|
122
|
+
if v {
|
|
123
|
+
_kwargs_true_count += 1;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
"first": first,
|
|
128
|
+
"args_sum": _sum,
|
|
129
|
+
"last": last,
|
|
130
|
+
"kwargs_true_count": _kwargs_true_count
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
numbers = [10, 20, 30];
|
|
136
|
+
flags = {"debug": True, "verbose": False, "strict": True};
|
|
137
|
+
result = mixed_unpacking_test("start", *numbers, last="end", **flags);
|
|
138
|
+
print("✅ PASS: Mixed unpacking:", result);
|
|
139
|
+
} except Exception as e {
|
|
140
|
+
print("❌ FAIL: Mixed unpacking failed");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# Test 21: Recursive function with varargs
|
|
144
|
+
def recursive_varargs(depth: int, *args: str, **kwargs: int) -> dict {
|
|
145
|
+
if depth <= 0 or not args {
|
|
146
|
+
return {"depth": depth, "args": list(args), "kwargs": kwargs};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
new_args = args[1:]; # Remove first arg
|
|
150
|
+
new_kwargs = {k: v+1 for (k, v) in kwargs.items()}; # Increment all values
|
|
151
|
+
|
|
152
|
+
return recursive_varargs(depth-1, *new_args, **new_kwargs);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
result = recursive_varargs(3, "a", "b", "c", "d", x=1, y=2);
|
|
157
|
+
print("✅ PASS: Recursive varargs:", result);
|
|
158
|
+
} except Exception as e {
|
|
159
|
+
print("❌ FAIL: Recursive varargs failed");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
with entry {
|
|
164
|
+
print("=== TESTING VARIABLE ARGUMENTS FAILURES ===");
|
|
165
|
+
|
|
166
|
+
# Test 1: Wrong types in *args (if type checking enabled)
|
|
167
|
+
try {
|
|
168
|
+
result = simple_args_only(1, 2, "not_int", 4);
|
|
169
|
+
print("❌ FAIL: Should catch mixed types in *args");
|
|
170
|
+
} except Exception as e {
|
|
171
|
+
print("✅ PASS: Caught *args type error");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Test 2: Wrong types in **kwargs (if type checking enabled)
|
|
175
|
+
try {
|
|
176
|
+
result = simple_kwargs_only(12,a="string", b=123, c="string");
|
|
177
|
+
print("❌ FAIL: Should catch mixed types in **kwargs");
|
|
178
|
+
} except Exception as e {
|
|
179
|
+
print("✅ PASS: Caught **kwargs type error");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Test 3: Missing required before *args
|
|
183
|
+
try {
|
|
184
|
+
result = args_with_required(1, 2, 3, apple=90);
|
|
185
|
+
} except Exception as e {
|
|
186
|
+
print("✅ PASS: Caught required param type error");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
# Test 4: Missing required before **kwargs
|
|
190
|
+
try {
|
|
191
|
+
result = kwargs_with_required(name="test", value="data");
|
|
192
|
+
print("❌ FAIL: Should catch wrong types for required");
|
|
193
|
+
} except Exception as e {
|
|
194
|
+
print("✅ PASS: Caught required before kwargs error");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
# Test 5: Complex signature - pos-only passed as keyword
|
|
198
|
+
try {
|
|
199
|
+
result = full_varargs_signature(
|
|
200
|
+
pos=1, reg="test", kw_req=True
|
|
201
|
+
);
|
|
202
|
+
print("❌ FAIL: Should reject pos-only as keyword in varargs");
|
|
203
|
+
} except Exception as e {
|
|
204
|
+
print("✅ PASS: Caught pos-only in varargs error");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Test 6: Complex signature - missing required kw-only
|
|
208
|
+
try {
|
|
209
|
+
result = full_varargs_signature(1, "test", 2.0, 10, 20);
|
|
210
|
+
print("❌ FAIL: Should reject missing kw-only in varargs");
|
|
211
|
+
} except Exception as e {
|
|
212
|
+
print("✅ PASS: Caught missing kw-only in varargs");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
# Test 7: Name conflicts between params and kwargs
|
|
216
|
+
try {
|
|
217
|
+
result = conflicting_names("test", "arg1", name_kw="kw_test", name="conflict");
|
|
218
|
+
print("❌ FAIL: Should catch parameter name conflicts");
|
|
219
|
+
} except Exception as e {
|
|
220
|
+
print("✅ PASS: Caught name conflict error");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# Test 8: Type-sensitive varargs with wrong types
|
|
224
|
+
try {
|
|
225
|
+
result = type_sensitive_varargs(1, 2, 3, a="not_int", b=4.5);
|
|
226
|
+
print("❌ FAIL: Should catch type mismatch in kwargs");
|
|
227
|
+
} except Exception as e {
|
|
228
|
+
print("✅ PASS: Caught varargs type sensitivity error");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# Test 9: Double unpacking issues
|
|
233
|
+
try {
|
|
234
|
+
data = {"a": {"nested": "dict"}, "b": "simple"};
|
|
235
|
+
result = double_star_issues(**data);
|
|
236
|
+
print("✅ INFO: Double star result:", result);
|
|
237
|
+
} except Exception as e {
|
|
238
|
+
print("✅ PASS: Caught double star error");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
# Test 10: Empty varargs but required params missing
|
|
242
|
+
try {
|
|
243
|
+
result = edge_case_empty_varargs();
|
|
244
|
+
print("❌ FAIL: Should catch missing required with empty varargs");
|
|
245
|
+
} except Exception as e {
|
|
246
|
+
print("✅ PASS: Caught missing required in empty varargs");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# Test 11: Keyword argument conflicts with *args collection
|
|
251
|
+
try {
|
|
252
|
+
items = [1, 2, 3];
|
|
253
|
+
result = args_with_required("test", *items, args="conflict");
|
|
254
|
+
print("❌ FAIL: Should catch args name conflict");
|
|
255
|
+
} except Exception as e {
|
|
256
|
+
print("✅ PASS: Caught args conflict error");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
# Test 12: **kwargs conflicts with explicit keywords
|
|
260
|
+
try {
|
|
261
|
+
extra_data = {"kw_req": True, "extra": "data"};
|
|
262
|
+
result = full_varargs_signature(1, "test", kw_req=False, **extra_data);
|
|
263
|
+
print("❌ FAIL: Should catch kwargs conflict with explicit");
|
|
264
|
+
} except Exception as e {
|
|
265
|
+
print("✅ PASS: Caught kwargs explicit conflict");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# Test 13: Valid calls that should work
|
|
269
|
+
try {
|
|
270
|
+
result = simple_args_only(1, 2, 3, 4, 5);
|
|
271
|
+
print("✅ PASS: Valid *args call:", result);
|
|
272
|
+
} except Exception as e {
|
|
273
|
+
print("❌ FAIL: Valid *args call rejected");
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
result = simple_kwargs_only(a="test", b="data", c="more");
|
|
278
|
+
print("✅ PASS: Valid **kwargs call:", result);
|
|
279
|
+
} except Exception as e {
|
|
280
|
+
print("❌ FAIL: Valid **kwargs call rejected");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
result = full_varargs_signature(
|
|
285
|
+
1, # pos (pos-only)
|
|
286
|
+
"regular", # reg
|
|
287
|
+
2.5, # def_param
|
|
288
|
+
10, 20, 30, # *args
|
|
289
|
+
kw_req=True, # kw_req (required kw-only)
|
|
290
|
+
kw_opt="custom", # kw_opt (optional kw-only)
|
|
291
|
+
extra="data", # **kwargs
|
|
292
|
+
more="info"
|
|
293
|
+
);
|
|
294
|
+
print("✅ PASS: Valid complex varargs call keys:", list(result.keys()));
|
|
295
|
+
} except Exception as e {
|
|
296
|
+
print("❌ FAIL: Valid complex varargs rejected");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
additional_varargs_edge_cases();
|
|
300
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Test keyword-only parameters
|
|
2
|
+
|
|
3
|
+
def simple_kwonly(*, x: int) -> int {
|
|
4
|
+
return x;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
def kwonly_with_defaults(*, x: int = 10, y: str = "def") -> str {
|
|
8
|
+
return f"{x}-{y}";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def regular_plus_kwonly(normal: int, *, kw: str) -> str {
|
|
12
|
+
return f"{normal}|{kw}";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def mixed_kwonly(pos: int, reg: str = "def", *, kw1: float, kw2: bool = True) -> str {
|
|
16
|
+
return f"{pos}-{reg}-{kw1}-{kw2}";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def all_kwonly(*, a: int, b: str = "test", c: float = 1.0) -> str {
|
|
20
|
+
return f"{a}:{b}:{c}";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
with entry {
|
|
24
|
+
print("KW_SIMPLE:", simple_kwonly(x=42));
|
|
25
|
+
print("KW_DEF:", kwonly_with_defaults(), kwonly_with_defaults(x=20));
|
|
26
|
+
print("REG_KW:", regular_plus_kwonly(10, kw="test"));
|
|
27
|
+
print("MIXED_KW:", mixed_kwonly(1, kw1=2.5), mixed_kwonly(2, "custom", kw1=3.5, kw2=False));
|
|
28
|
+
print("ALL_KW:", all_kwonly(a=100), all_kwonly(a=200, b="hi", c=9.9));
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from typing_extensions import TypeAlias
|
|
2
|
+
import collections.abc
|
|
3
|
+
|
|
4
|
+
_ClassInfo: TypeAlias = type | tuple[object, ...]
|
|
5
|
+
Sized = collections.abc.Sized
|
|
6
|
+
|
|
7
|
+
def isinstance(obj: object, class_or_tuple: _ClassInfo, /) -> bool: ...
|
|
8
|
+
def len(obj: Sized,astt ,/, z: int, j: str,a= 90) -> int: ...
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
glob a = 5, b = 2;
|
|
2
2
|
|
|
3
3
|
test t1 {
|
|
4
|
-
|
|
4
|
+
assert almostEqual(a, 6);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
test t2 {
|
|
8
|
-
|
|
8
|
+
assert a != b;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
test t3 {
|
|
12
|
-
|
|
12
|
+
assert "d" in "abc";
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
test t4 {
|
|
16
|
-
|
|
16
|
+
assert a - b == 3;
|
|
17
17
|
}
|
jaclang/tests/test_cli.py
CHANGED
|
@@ -7,6 +7,7 @@ import os
|
|
|
7
7
|
import re
|
|
8
8
|
import subprocess
|
|
9
9
|
import sys
|
|
10
|
+
import tempfile
|
|
10
11
|
import traceback
|
|
11
12
|
import unittest
|
|
12
13
|
from jaclang.cli import cli
|
|
@@ -65,7 +66,9 @@ class JacCliTests(TestCase):
|
|
|
65
66
|
self.assertIn("Hello Peter Peter", stdout_value)
|
|
66
67
|
self.assertIn("Peter squared is Peter Peter", stdout_value)
|
|
67
68
|
self.assertIn("PETER! wrong poem", stdout_value)
|
|
68
|
-
self.assertIn(
|
|
69
|
+
self.assertIn(
|
|
70
|
+
"Hello Peter , yoo mother is Mary. Myself, I am Peter.", stdout_value
|
|
71
|
+
)
|
|
69
72
|
self.assertIn("Left aligned: Apple | Price: 1.23", stdout_value)
|
|
70
73
|
self.assertIn("name = Peter 🤔", stdout_value)
|
|
71
74
|
|
|
@@ -205,19 +208,6 @@ class JacCliTests(TestCase):
|
|
|
205
208
|
self.assertIn("Sub objects.", stdout_value)
|
|
206
209
|
self.assertGreater(stdout_value.count("def exit_"), 10)
|
|
207
210
|
|
|
208
|
-
def test_jac_cmd_line(self) -> None:
|
|
209
|
-
"""Basic test for pass."""
|
|
210
|
-
process = subprocess.Popen(
|
|
211
|
-
["jac"],
|
|
212
|
-
stdin=subprocess.PIPE,
|
|
213
|
-
stdout=subprocess.PIPE,
|
|
214
|
-
stderr=subprocess.PIPE,
|
|
215
|
-
text=True,
|
|
216
|
-
)
|
|
217
|
-
stdout_value, _ = process.communicate(input="exit\n")
|
|
218
|
-
self.assertEqual(process.returncode, 0, "Process did not exit successfully")
|
|
219
|
-
self.assertIn("Welcome to the Jac CLI!", stdout_value)
|
|
220
|
-
|
|
221
211
|
def test_ast_print(self) -> None:
|
|
222
212
|
"""Testing for print AstTool."""
|
|
223
213
|
captured_output = io.StringIO()
|
|
@@ -270,7 +260,7 @@ class JacCliTests(TestCase):
|
|
|
270
260
|
'[label="MultiString" shape="oval" style="filled" fillcolor="#fccca4"]',
|
|
271
261
|
stdout_value,
|
|
272
262
|
)
|
|
273
|
-
|
|
263
|
+
|
|
274
264
|
def test_cfg_printgraph(self) -> None:
|
|
275
265
|
"""Testing for print CFG."""
|
|
276
266
|
captured_output = io.StringIO()
|
|
@@ -282,8 +272,8 @@ class JacCliTests(TestCase):
|
|
|
282
272
|
stdout_value = captured_output.getvalue()
|
|
283
273
|
correct_graph = (
|
|
284
274
|
"digraph G {\n"
|
|
285
|
-
' 0 [label="BB0\\n\\nprint ( \\"im still here\\" )
|
|
286
|
-
' 1 [label="BB1\\n\\"Hello World!\\" |> print
|
|
275
|
+
' 0 [label="BB0\\n\\nprint ( \\"im still here\\" ) ;", shape=box];\n'
|
|
276
|
+
' 1 [label="BB1\\n\\"Hello World!\\" |> print ;", shape=box];\n'
|
|
287
277
|
"}\n\n"
|
|
288
278
|
)
|
|
289
279
|
|
|
@@ -415,6 +405,69 @@ class JacCliTests(TestCase):
|
|
|
415
405
|
self.assertIn("class MyClass {", stdout_value)
|
|
416
406
|
self.assertIn('"""Print function."""', stdout_value)
|
|
417
407
|
|
|
408
|
+
def test_lambda_arg_annotation(self) -> None:
|
|
409
|
+
"""Test for lambda argument annotation."""
|
|
410
|
+
captured_output = io.StringIO()
|
|
411
|
+
sys.stdout = captured_output
|
|
412
|
+
cli.jac2py(
|
|
413
|
+
f"{self.fixture_abs_path('../../tests/fixtures/lambda_arg_annotation.jac')}"
|
|
414
|
+
)
|
|
415
|
+
sys.stdout = sys.__stdout__
|
|
416
|
+
stdout_value = captured_output.getvalue()
|
|
417
|
+
self.assertIn("x = lambda a, b: b + a", stdout_value)
|
|
418
|
+
self.assertIn("y = lambda: 567", stdout_value)
|
|
419
|
+
self.assertIn("f = lambda x: 'even' if x % 2 == 0 else 'odd'", stdout_value)
|
|
420
|
+
|
|
421
|
+
def test_lambda_self(self) -> None:
|
|
422
|
+
"""Test for lambda argument annotation."""
|
|
423
|
+
captured_output = io.StringIO()
|
|
424
|
+
sys.stdout = captured_output
|
|
425
|
+
cli.jac2py(f"{self.fixture_abs_path('../../tests/fixtures/lambda_self.jac')}")
|
|
426
|
+
sys.stdout = sys.__stdout__
|
|
427
|
+
stdout_value = captured_output.getvalue()
|
|
428
|
+
self.assertIn("def travel(self, here: City) -> None:", stdout_value)
|
|
429
|
+
self.assertIn("def foo(a: int) -> None:", stdout_value)
|
|
430
|
+
self.assertIn("x = lambda a, b: b + a", stdout_value)
|
|
431
|
+
self.assertIn("def visit_city(self, c: City) -> None:", stdout_value)
|
|
432
|
+
self.assertIn(
|
|
433
|
+
"sorted(users, key=lambda x: x['email'], reverse=True)", stdout_value
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
def test_param_arg(self) -> None:
|
|
437
|
+
"""Test for lambda argument annotation."""
|
|
438
|
+
captured_output = io.StringIO()
|
|
439
|
+
sys.stdout = captured_output
|
|
440
|
+
from jaclang.compiler.program import JacProgram
|
|
441
|
+
|
|
442
|
+
filename = self.fixture_abs_path('../../tests/fixtures/params/test_complex_params.jac')
|
|
443
|
+
cli.jac2py(f"{self.fixture_abs_path('../../tests/fixtures/params/test_complex_params.jac')}")
|
|
444
|
+
py_code = JacProgram().compile(file_path=filename).gen.py
|
|
445
|
+
|
|
446
|
+
# Create temporary Python file
|
|
447
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as temp_file:
|
|
448
|
+
temp_file.write(py_code)
|
|
449
|
+
py_file_path = temp_file.name
|
|
450
|
+
|
|
451
|
+
try:
|
|
452
|
+
jac_code = JacProgram().compile(use_str=py_code, file_path=py_file_path).unparse()
|
|
453
|
+
# Create temporary Jac file
|
|
454
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.jac', delete=False) as temp_file:
|
|
455
|
+
temp_file.write(jac_code)
|
|
456
|
+
jac_file_path = temp_file.name
|
|
457
|
+
cli.run(jac_file_path)
|
|
458
|
+
finally:
|
|
459
|
+
os.remove(py_file_path)
|
|
460
|
+
os.remove(jac_file_path)
|
|
461
|
+
|
|
462
|
+
sys.stdout = sys.__stdout__
|
|
463
|
+
stdout_value = captured_output.getvalue().split("\n")
|
|
464
|
+
self.assertEqual("ULTIMATE_MIN: 1|def|2.5|0|test|100|0", stdout_value[-7])
|
|
465
|
+
self.assertEqual("ULTIMATE_FULL: 1|custom|3.14|3|req|200|1", stdout_value[-6])
|
|
466
|
+
self.assertEqual("SEPARATORS: 42", stdout_value[-5])
|
|
467
|
+
self.assertEqual("EDGE_MIX: 1-test-2-True-1", stdout_value[-4])
|
|
468
|
+
self.assertEqual("RECURSIVE: 7 11", stdout_value[-3])
|
|
469
|
+
self.assertEqual("VALIDATION: x:1,y:2.5,z:10,args:1,w:True,kwargs:1", stdout_value[-2])
|
|
470
|
+
|
|
418
471
|
def test_caching_issue(self) -> None:
|
|
419
472
|
"""Test for Caching Issue."""
|
|
420
473
|
test_file = self.fixture_abs_path("test_caching_issue.jac")
|
|
@@ -424,7 +477,7 @@ class JacCliTests(TestCase):
|
|
|
424
477
|
f.write(
|
|
425
478
|
f"""
|
|
426
479
|
test mytest{{
|
|
427
|
-
|
|
480
|
+
assert 10 == {x};
|
|
428
481
|
}}
|
|
429
482
|
"""
|
|
430
483
|
)
|
|
@@ -560,3 +613,35 @@ class JacCliTests(TestCase):
|
|
|
560
613
|
stdout, stderr = process.communicate()
|
|
561
614
|
self.assertIn("Hello, World!", stdout)
|
|
562
615
|
self.assertIn("Sum: 8", stdout)
|
|
616
|
+
|
|
617
|
+
def test_jac_run_py_bugs(self) -> None:
|
|
618
|
+
"""Test jac run python files."""
|
|
619
|
+
process = subprocess.Popen(
|
|
620
|
+
[
|
|
621
|
+
"jac",
|
|
622
|
+
"run",
|
|
623
|
+
self.fixture_abs_path("jac_run_py_bugs.py"),
|
|
624
|
+
],
|
|
625
|
+
stdin=subprocess.PIPE,
|
|
626
|
+
stdout=subprocess.PIPE,
|
|
627
|
+
stderr=subprocess.PIPE,
|
|
628
|
+
text=True,
|
|
629
|
+
)
|
|
630
|
+
stdout, stderr = process.communicate()
|
|
631
|
+
self.assertIn("Hello, my name is Alice and I am 30 years old.", stdout)
|
|
632
|
+
self.assertIn("MyModule initialized!", stdout)
|
|
633
|
+
|
|
634
|
+
def test_cli_defaults_to_run_with_file(self) -> None:
|
|
635
|
+
"""jac myfile.jac should behave like jac run myfile.jac."""
|
|
636
|
+
process = subprocess.Popen(
|
|
637
|
+
[
|
|
638
|
+
"jac",
|
|
639
|
+
self.fixture_abs_path("hello.jac"),
|
|
640
|
+
],
|
|
641
|
+
stdin=subprocess.PIPE,
|
|
642
|
+
stdout=subprocess.PIPE,
|
|
643
|
+
stderr=subprocess.PIPE,
|
|
644
|
+
text=True,
|
|
645
|
+
)
|
|
646
|
+
stdout, stderr = process.communicate()
|
|
647
|
+
self.assertIn("Hello World!", stdout)
|