jaclang 0.8.8__py3-none-any.whl → 0.8.10__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 +194 -10
- jaclang/cli/cmdreg.py +144 -8
- jaclang/compiler/__init__.py +6 -1
- jaclang/compiler/codeinfo.py +16 -1
- jaclang/compiler/constant.py +33 -8
- jaclang/compiler/jac.lark +154 -62
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +656 -149
- jaclang/compiler/passes/__init__.py +2 -1
- jaclang/compiler/passes/ast_gen/__init__.py +5 -0
- jaclang/compiler/passes/ast_gen/base_ast_gen_pass.py +54 -0
- jaclang/compiler/passes/ast_gen/jsx_processor.py +344 -0
- jaclang/compiler/passes/ecmascript/__init__.py +25 -0
- jaclang/compiler/passes/ecmascript/es_unparse.py +576 -0
- jaclang/compiler/passes/ecmascript/esast_gen_pass.py +2068 -0
- jaclang/compiler/passes/ecmascript/estree.py +972 -0
- jaclang/compiler/passes/ecmascript/tests/__init__.py +1 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/advanced_language_features.jac +170 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.impl.jac +30 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.jac +14 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/client_jsx.jac +89 -0
- jaclang/compiler/passes/ecmascript/tests/fixtures/core_language_features.jac +195 -0
- jaclang/compiler/passes/ecmascript/tests/test_esast_gen_pass.py +167 -0
- jaclang/compiler/passes/ecmascript/tests/test_js_generation.py +239 -0
- jaclang/compiler/passes/main/__init__.py +0 -3
- jaclang/compiler/passes/main/annex_pass.py +23 -1
- jaclang/compiler/passes/main/def_use_pass.py +1 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +413 -255
- jaclang/compiler/passes/main/pyast_load_pass.py +48 -11
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +2 -0
- jaclang/compiler/passes/main/sym_tab_build_pass.py +18 -1
- jaclang/compiler/passes/main/tests/fixtures/autoimpl.cl.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +3 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_class_construct.jac +33 -0
- jaclang/compiler/passes/main/tests/fixtures/defuse_modpath.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +2 -1
- jaclang/compiler/passes/main/tests/test_checker_pass.py +31 -3
- jaclang/compiler/passes/main/tests/test_def_use_pass.py +12 -0
- jaclang/compiler/passes/main/tests/test_import_pass.py +23 -4
- jaclang/compiler/passes/main/tests/test_predynamo_pass.py +13 -14
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +25 -0
- jaclang/compiler/passes/main/type_checker_pass.py +7 -0
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +219 -20
- jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -10
- jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -2
- jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +7 -1
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +135 -29
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -1
- jaclang/compiler/passes/transform.py +9 -1
- jaclang/compiler/passes/uni_pass.py +5 -7
- jaclang/compiler/program.py +27 -26
- jaclang/compiler/tests/test_client_codegen.py +113 -0
- jaclang/compiler/tests/test_importer.py +12 -10
- jaclang/compiler/tests/test_parser.py +249 -3
- jaclang/compiler/type_system/type_evaluator.jac +1078 -0
- jaclang/compiler/type_system/type_utils.py +1 -1
- jaclang/compiler/type_system/types.py +6 -0
- jaclang/compiler/unitree.py +438 -82
- jaclang/langserve/engine.jac +224 -288
- jaclang/langserve/sem_manager.jac +12 -8
- jaclang/langserve/server.jac +48 -48
- jaclang/langserve/tests/fixtures/greet.py +17 -0
- jaclang/langserve/tests/fixtures/md_path.jac +22 -0
- jaclang/langserve/tests/fixtures/user.jac +15 -0
- jaclang/langserve/tests/test_server.py +66 -371
- jaclang/lib.py +17 -0
- jaclang/runtimelib/archetype.py +25 -25
- jaclang/runtimelib/client_bundle.py +169 -0
- jaclang/runtimelib/client_runtime.jac +586 -0
- jaclang/runtimelib/constructs.py +4 -2
- jaclang/runtimelib/machine.py +308 -139
- jaclang/runtimelib/meta_importer.py +111 -22
- jaclang/runtimelib/mtp.py +15 -0
- jaclang/runtimelib/server.py +1089 -0
- jaclang/runtimelib/tests/fixtures/client_app.jac +18 -0
- jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
- jaclang/runtimelib/tests/fixtures/savable_object.jac +4 -5
- jaclang/runtimelib/tests/fixtures/serve_api.jac +75 -0
- jaclang/runtimelib/tests/test_client_bundle.py +55 -0
- jaclang/runtimelib/tests/test_client_render.py +63 -0
- jaclang/runtimelib/tests/test_serve.py +1069 -0
- jaclang/settings.py +0 -3
- jaclang/tests/fixtures/attr_pattern_case.jac +18 -0
- jaclang/tests/fixtures/funccall_genexpr.jac +7 -0
- jaclang/tests/fixtures/funccall_genexpr.py +5 -0
- jaclang/tests/fixtures/iife_functions.jac +142 -0
- jaclang/tests/fixtures/iife_functions_client.jac +143 -0
- jaclang/tests/fixtures/multistatement_lambda.jac +116 -0
- jaclang/tests/fixtures/multistatement_lambda_client.jac +113 -0
- jaclang/tests/fixtures/needs_import_dup.jac +6 -4
- jaclang/tests/fixtures/py2jac_empty.py +0 -0
- jaclang/tests/fixtures/py_run.py +7 -5
- jaclang/tests/fixtures/pyfunc_fstr.py +2 -2
- jaclang/tests/fixtures/simple_lambda_test.jac +12 -0
- jaclang/tests/test_cli.py +134 -18
- jaclang/tests/test_language.py +120 -32
- jaclang/tests/test_reference.py +20 -3
- jaclang/utils/NonGPT.py +375 -0
- jaclang/utils/helpers.py +64 -20
- jaclang/utils/lang_tools.py +31 -4
- jaclang/utils/tests/test_lang_tools.py +5 -16
- jaclang/utils/treeprinter.py +8 -3
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/METADATA +3 -3
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/RECORD +106 -71
- jaclang/compiler/passes/main/binder_pass.py +0 -594
- jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +0 -47
- jaclang/compiler/passes/main/tests/test_binder_pass.py +0 -111
- jaclang/compiler/type_system/type_evaluator.py +0 -844
- jaclang/langserve/tests/session.jac +0 -294
- jaclang/langserve/tests/test_dev_server.py +0 -80
- jaclang/runtimelib/importer.py +0 -351
- jaclang/tests/test_typecheck.py +0 -542
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/WHEEL +0 -0
- {jaclang-0.8.8.dist-info → jaclang-0.8.10.dist-info}/entry_points.txt +0 -0
|
@@ -4,6 +4,7 @@ import inspect
|
|
|
4
4
|
import io
|
|
5
5
|
import os
|
|
6
6
|
import sys
|
|
7
|
+
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
from jaclang import JacMachineInterface as Jac
|
|
9
10
|
from jaclang.compiler import jac_lark as jl
|
|
@@ -215,12 +216,12 @@ class TestLarkParser(TestCaseMicroSuite):
|
|
|
215
216
|
}
|
|
216
217
|
""",
|
|
217
218
|
"""
|
|
218
|
-
|
|
219
|
+
Unexpected token 'bar'
|
|
220
|
+
with entry {
|
|
219
221
|
foo = Foo(;
|
|
220
222
|
func(foo bar)
|
|
223
|
+
^^^
|
|
221
224
|
foo.bar;
|
|
222
|
-
^^^
|
|
223
|
-
}
|
|
224
225
|
"""
|
|
225
226
|
]
|
|
226
227
|
for idx, alrt in enumerate(prog.errors_had):
|
|
@@ -229,4 +230,249 @@ class TestLarkParser(TestCaseMicroSuite):
|
|
|
229
230
|
line = line.strip()
|
|
230
231
|
self.assertIn(line, pretty)
|
|
231
232
|
|
|
233
|
+
def _load_combined_jsx_fixture(self) -> tuple[str, JacParser]:
|
|
234
|
+
"""Parse the consolidated JSX fixture once for downstream assertions."""
|
|
235
|
+
fixture_path = (
|
|
236
|
+
Path(__file__)
|
|
237
|
+
.resolve()
|
|
238
|
+
.parent
|
|
239
|
+
.parent
|
|
240
|
+
/ "passes"
|
|
241
|
+
/ "ecmascript"
|
|
242
|
+
/ "tests"
|
|
243
|
+
/ "fixtures"
|
|
244
|
+
/ "client_jsx.jac"
|
|
245
|
+
)
|
|
246
|
+
source_text = fixture_path.read_text(encoding="utf-8")
|
|
247
|
+
prse = JacParser(
|
|
248
|
+
root_ir=Source(source_text, mod_path=str(fixture_path)),
|
|
249
|
+
prog=JacProgram(),
|
|
250
|
+
)
|
|
251
|
+
self.assertFalse(
|
|
252
|
+
prse.errors_had,
|
|
253
|
+
f"Parser reported errors for JSX fixture: {[str(e) for e in prse.errors_had]}",
|
|
254
|
+
)
|
|
255
|
+
return source_text, prse
|
|
256
|
+
|
|
257
|
+
def test_jsx_comprehensive_fixture(self) -> None:
|
|
258
|
+
"""Ensure the consolidated JSX fixture exercises varied grammar shapes."""
|
|
259
|
+
source_text, prse = self._load_combined_jsx_fixture()
|
|
260
|
+
tree_repr = prse.ir_out.pp()
|
|
261
|
+
|
|
262
|
+
expected_snippets = {
|
|
263
|
+
"self_closing": "<div />",
|
|
264
|
+
"attribute_binding": 'id={name}',
|
|
265
|
+
"namespaced_component": "<Form.Input.Text />",
|
|
266
|
+
"fragment": "<>",
|
|
267
|
+
"spread_attribute": "{...props}",
|
|
268
|
+
"expression_child": '{"Hello " + name + "!"}',
|
|
269
|
+
}
|
|
270
|
+
for label, snippet in expected_snippets.items():
|
|
271
|
+
with self.subTest(label=label):
|
|
272
|
+
self.assertIn(snippet, source_text)
|
|
273
|
+
|
|
274
|
+
ast_markers = {
|
|
275
|
+
"JsxElement": "JsxElement" in tree_repr,
|
|
276
|
+
"FragmentTokens": "Token - <>" in tree_repr and "Token - </>" in tree_repr,
|
|
277
|
+
"JsxSpreadAttribute": "JsxSpreadAttribute" in tree_repr,
|
|
278
|
+
}
|
|
279
|
+
for label, present in ast_markers.items():
|
|
280
|
+
with self.subTest(node=label):
|
|
281
|
+
self.assertTrue(present, f"{label} missing from AST pretty print")
|
|
282
|
+
|
|
283
|
+
def test_client_keyword_tagging(self) -> None:
|
|
284
|
+
"""Test that cl keyword properly tags elements as client declarations.
|
|
285
|
+
|
|
286
|
+
Tests:
|
|
287
|
+
- Single statement with cl prefix
|
|
288
|
+
- Statement without cl prefix
|
|
289
|
+
- Block of statements with cl { }
|
|
290
|
+
- Empty cl blocks
|
|
291
|
+
- Multiple cl blocks at top level
|
|
292
|
+
- Various statement types (import, let, obj, test)
|
|
293
|
+
"""
|
|
294
|
+
# Test 1: Mixed single and block client markers
|
|
295
|
+
source = """
|
|
296
|
+
cl let foo = 1;
|
|
297
|
+
let bar = 2;
|
|
298
|
+
cl {
|
|
299
|
+
let baz = 3;
|
|
300
|
+
test sample {}
|
|
301
|
+
}
|
|
302
|
+
"""
|
|
303
|
+
module = JacProgram().parse_str(source, "test.jac")
|
|
304
|
+
body = module.body
|
|
305
|
+
|
|
306
|
+
self.assertEqual(
|
|
307
|
+
[type(stmt).__name__ for stmt in body],
|
|
308
|
+
["GlobalVars", "GlobalVars", "GlobalVars", "Test"],
|
|
309
|
+
)
|
|
310
|
+
self.assertEqual(
|
|
311
|
+
[getattr(stmt, "is_client_decl", False) for stmt in body],
|
|
312
|
+
[True, False, True, True], # cl let, let, cl{let}, cl{test}
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# Test 2: Block with different statement types
|
|
316
|
+
source = """
|
|
317
|
+
cl {
|
|
318
|
+
import foo;
|
|
319
|
+
let x = 1;
|
|
320
|
+
obj MyClass {}
|
|
321
|
+
test my_test {}
|
|
322
|
+
}
|
|
323
|
+
"""
|
|
324
|
+
module = JacProgram().parse_str(source, "test.jac")
|
|
325
|
+
body = module.body
|
|
326
|
+
|
|
327
|
+
self.assertEqual(len(body), 4)
|
|
328
|
+
self.assertTrue(
|
|
329
|
+
all(
|
|
330
|
+
getattr(stmt, "is_client_decl", False)
|
|
331
|
+
for stmt in body
|
|
332
|
+
if hasattr(stmt, "is_client_decl")
|
|
333
|
+
)
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# Test 3: Multiple cl blocks at top level
|
|
337
|
+
source = """
|
|
338
|
+
cl {
|
|
339
|
+
let a = 1;
|
|
340
|
+
}
|
|
341
|
+
let b = 2;
|
|
342
|
+
cl {
|
|
343
|
+
let c = 3;
|
|
344
|
+
}
|
|
345
|
+
"""
|
|
346
|
+
module = JacProgram().parse_str(source, "test.jac")
|
|
347
|
+
body = module.body
|
|
348
|
+
|
|
349
|
+
self.assertEqual(len(body), 3)
|
|
350
|
+
self.assertEqual(
|
|
351
|
+
[getattr(stmt, "is_client_decl", False) for stmt in body],
|
|
352
|
+
[True, False, True], # cl{let a}, let b, cl{let c}
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
# Test 4: Empty client block
|
|
356
|
+
source = """
|
|
357
|
+
cl {}
|
|
358
|
+
let x = 1;
|
|
359
|
+
"""
|
|
360
|
+
module = JacProgram().parse_str(source, "test.jac")
|
|
361
|
+
body = module.body
|
|
362
|
+
|
|
363
|
+
self.assertEqual(len(body), 1)
|
|
364
|
+
self.assertFalse(getattr(body[0], "is_client_decl", False))
|
|
365
|
+
|
|
366
|
+
# Test 5: Various statement types with single cl marker
|
|
367
|
+
source = """
|
|
368
|
+
cl import foo;
|
|
369
|
+
cl obj MyClass {}
|
|
370
|
+
cl test my_test {}
|
|
371
|
+
"""
|
|
372
|
+
module = JacProgram().parse_str(source, "test.jac")
|
|
373
|
+
body = module.body
|
|
374
|
+
|
|
375
|
+
self.assertEqual(len(body), 3)
|
|
376
|
+
self.assertTrue(
|
|
377
|
+
all(
|
|
378
|
+
getattr(stmt, "is_client_decl", False)
|
|
379
|
+
for stmt in body
|
|
380
|
+
if hasattr(stmt, "is_client_decl")
|
|
381
|
+
)
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
def test_anonymous_ability_decl(self) -> None:
|
|
385
|
+
"""Test that abilities can be declared without explicit names.
|
|
386
|
+
|
|
387
|
+
Tests:
|
|
388
|
+
- Anonymous ability with entry event
|
|
389
|
+
- Anonymous ability with exit event
|
|
390
|
+
- Named ability still works
|
|
391
|
+
- Autogenerated names are unique based on location
|
|
392
|
+
"""
|
|
393
|
+
# Test 1: Anonymous ability with entry event
|
|
394
|
+
source = """
|
|
395
|
+
walker MyWalker {
|
|
396
|
+
can with entry {
|
|
397
|
+
print("hello");
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
"""
|
|
401
|
+
prog = JacProgram()
|
|
402
|
+
module = prog.parse_str(source, "test.jac")
|
|
403
|
+
self.assertFalse(prog.errors_had)
|
|
404
|
+
|
|
405
|
+
# Find the walker and its ability
|
|
406
|
+
walker = module.body[0]
|
|
407
|
+
abilities = [stmt for stmt in walker.body if type(stmt).__name__ == "Ability"]
|
|
408
|
+
self.assertEqual(len(abilities), 1)
|
|
409
|
+
|
|
410
|
+
ability = abilities[0]
|
|
411
|
+
self.assertIsNone(ability.name_ref)
|
|
412
|
+
# Check that py_resolve_name generates a name
|
|
413
|
+
resolved_name = ability.py_resolve_name()
|
|
414
|
+
self.assertTrue(resolved_name.startswith("__ability_entry_"))
|
|
415
|
+
self.assertTrue(resolved_name.endswith("__"))
|
|
416
|
+
|
|
417
|
+
# Test 2: Anonymous ability with exit event
|
|
418
|
+
source = """
|
|
419
|
+
walker MyWalker {
|
|
420
|
+
can with exit {
|
|
421
|
+
print("goodbye");
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
"""
|
|
425
|
+
prog = JacProgram()
|
|
426
|
+
module = prog.parse_str(source, "test.jac")
|
|
427
|
+
self.assertFalse(prog.errors_had)
|
|
428
|
+
|
|
429
|
+
walker = module.body[0]
|
|
430
|
+
abilities = [stmt for stmt in walker.body if type(stmt).__name__ == "Ability"]
|
|
431
|
+
ability = abilities[0]
|
|
432
|
+
resolved_name = ability.py_resolve_name()
|
|
433
|
+
self.assertTrue(resolved_name.startswith("__ability_exit_"))
|
|
434
|
+
|
|
435
|
+
# Test 3: Named ability still works
|
|
436
|
+
source = """
|
|
437
|
+
walker MyWalker {
|
|
438
|
+
can my_ability with entry {
|
|
439
|
+
print("named");
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
"""
|
|
443
|
+
prog = JacProgram()
|
|
444
|
+
module = prog.parse_str(source, "test.jac")
|
|
445
|
+
self.assertFalse(prog.errors_had)
|
|
446
|
+
|
|
447
|
+
walker = module.body[0]
|
|
448
|
+
abilities = [stmt for stmt in walker.body if type(stmt).__name__ == "Ability"]
|
|
449
|
+
ability = abilities[0]
|
|
450
|
+
self.assertIsNotNone(ability.name_ref)
|
|
451
|
+
self.assertEqual(ability.py_resolve_name(), "my_ability")
|
|
452
|
+
|
|
453
|
+
# Test 4: Multiple anonymous abilities generate unique names
|
|
454
|
+
source = """
|
|
455
|
+
walker MyWalker {
|
|
456
|
+
can with entry {
|
|
457
|
+
print("first");
|
|
458
|
+
}
|
|
459
|
+
can with entry {
|
|
460
|
+
print("second");
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
"""
|
|
464
|
+
prog = JacProgram()
|
|
465
|
+
module = prog.parse_str(source, "test.jac")
|
|
466
|
+
self.assertFalse(prog.errors_had)
|
|
467
|
+
|
|
468
|
+
walker = module.body[0]
|
|
469
|
+
abilities = [stmt for stmt in walker.body if type(stmt).__name__ == "Ability"]
|
|
470
|
+
self.assertEqual(len(abilities), 2)
|
|
471
|
+
|
|
472
|
+
name1 = abilities[0].py_resolve_name()
|
|
473
|
+
name2 = abilities[1].py_resolve_name()
|
|
474
|
+
# Names should be different due to different locations
|
|
475
|
+
self.assertNotEqual(name1, name2)
|
|
476
|
+
|
|
477
|
+
|
|
232
478
|
TestLarkParser.self_attach_micro_tests()
|