jaclang 0.7.2__py3-none-any.whl → 0.7.7__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 +2 -2
- jaclang/compiler/absyntree.py +499 -294
- jaclang/compiler/codeloc.py +2 -2
- jaclang/compiler/constant.py +100 -2
- jaclang/compiler/jac.lark +27 -19
- jaclang/compiler/parser.py +119 -92
- jaclang/compiler/passes/main/access_modifier_pass.py +20 -12
- jaclang/compiler/passes/main/def_impl_match_pass.py +28 -14
- jaclang/compiler/passes/main/def_use_pass.py +59 -40
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +65 -43
- jaclang/compiler/passes/main/import_pass.py +8 -6
- jaclang/compiler/passes/main/pyast_gen_pass.py +97 -42
- jaclang/compiler/passes/main/pyast_load_pass.py +47 -12
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +19 -10
- jaclang/compiler/passes/main/registry_pass.py +6 -6
- jaclang/compiler/passes/main/sub_node_tab_pass.py +0 -5
- jaclang/compiler/passes/main/sym_tab_build_pass.py +43 -235
- jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +21 -4
- jaclang/compiler/passes/main/tests/test_def_use_pass.py +5 -10
- jaclang/compiler/passes/main/type_check_pass.py +2 -1
- jaclang/compiler/passes/tool/jac_formatter_pass.py +30 -9
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +16 -0
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +16 -0
- jaclang/compiler/passes/tool/tests/fixtures/genai/essay_review.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/expert_answer.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/joke_gen.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/odd_word_out.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/personality_finder.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/text_to_type.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/translator.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/wikipedia.jac +1 -1
- jaclang/compiler/passes/transform.py +2 -4
- jaclang/{core/registry.py → compiler/semtable.py} +1 -3
- jaclang/compiler/symtable.py +142 -101
- jaclang/compiler/tests/test_parser.py +2 -2
- jaclang/core/aott.py +15 -11
- jaclang/core/{construct.py → architype.py} +25 -240
- jaclang/core/constructs.py +44 -0
- jaclang/core/context.py +157 -0
- jaclang/core/importer.py +18 -9
- jaclang/core/memory.py +99 -0
- jaclang/core/test.py +90 -0
- jaclang/core/utils.py +2 -2
- jaclang/langserve/engine.py +127 -50
- jaclang/langserve/server.py +34 -61
- jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -0
- jaclang/langserve/tests/fixtures/circle.jac +16 -12
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +15 -0
- jaclang/langserve/tests/fixtures/import_include_statements.jac +6 -0
- jaclang/langserve/tests/fixtures/py_import.py +26 -0
- jaclang/langserve/tests/test_server.py +93 -18
- jaclang/langserve/utils.py +124 -10
- jaclang/plugin/builtin.py +1 -1
- jaclang/plugin/default.py +23 -9
- jaclang/plugin/feature.py +25 -7
- jaclang/plugin/spec.py +18 -20
- jaclang/settings.py +3 -0
- jaclang/tests/fixtures/abc.jac +16 -12
- jaclang/tests/fixtures/aott_raise.jac +1 -1
- jaclang/tests/fixtures/byllmissue.jac +9 -0
- jaclang/tests/fixtures/edgetypeissue.jac +10 -0
- jaclang/tests/fixtures/hello.jac +1 -1
- jaclang/tests/fixtures/impl_match_confused.impl.jac +1 -0
- jaclang/tests/fixtures/impl_match_confused.jac +5 -0
- jaclang/tests/fixtures/maxfail_run_test.jac +17 -5
- jaclang/tests/fixtures/run_test.jac +17 -5
- jaclang/tests/fixtures/with_llm_function.jac +1 -1
- jaclang/tests/fixtures/with_llm_lower.jac +1 -1
- jaclang/tests/fixtures/with_llm_method.jac +1 -1
- jaclang/tests/fixtures/with_llm_type.jac +1 -1
- jaclang/tests/fixtures/with_llm_vision.jac +1 -1
- jaclang/tests/test_bugs.py +19 -0
- jaclang/tests/test_cli.py +1 -1
- jaclang/tests/test_language.py +161 -96
- jaclang/tests/test_reference.py +1 -1
- jaclang/utils/lang_tools.py +5 -4
- jaclang/utils/test.py +2 -1
- jaclang/utils/treeprinter.py +22 -8
- {jaclang-0.7.2.dist-info → jaclang-0.7.7.dist-info}/METADATA +1 -1
- {jaclang-0.7.2.dist-info → jaclang-0.7.7.dist-info}/RECORD +83 -80
- jaclang/core/llms/__init__.py +0 -20
- jaclang/core/llms/anthropic.py +0 -90
- jaclang/core/llms/base.py +0 -206
- jaclang/core/llms/groq.py +0 -70
- jaclang/core/llms/huggingface.py +0 -76
- jaclang/core/llms/ollama.py +0 -81
- jaclang/core/llms/openai.py +0 -65
- jaclang/core/llms/togetherai.py +0 -63
- jaclang/core/llms/utils.py +0 -9
- {jaclang-0.7.2.dist-info → jaclang-0.7.7.dist-info}/WHEEL +0 -0
- {jaclang-0.7.2.dist-info → jaclang-0.7.7.dist-info}/entry_points.txt +0 -0
|
@@ -2,16 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import unittest
|
|
7
|
-
from contextvars import ContextVar
|
|
5
|
+
import types
|
|
8
6
|
from dataclasses import dataclass, field
|
|
9
|
-
from typing import Callable, Optional
|
|
7
|
+
from typing import Any, Callable, Optional
|
|
10
8
|
from uuid import UUID, uuid4
|
|
11
9
|
|
|
12
10
|
from jaclang.compiler.constant import EdgeDir
|
|
13
11
|
from jaclang.core.utils import collect_node_connections
|
|
14
|
-
from jaclang.plugin.spec import DSFunc
|
|
15
12
|
|
|
16
13
|
|
|
17
14
|
@dataclass(eq=False)
|
|
@@ -232,7 +229,13 @@ class WalkerAnchor(ObjectAnchor):
|
|
|
232
229
|
|
|
233
230
|
def visit_node(
|
|
234
231
|
self,
|
|
235
|
-
nds:
|
|
232
|
+
nds: (
|
|
233
|
+
list[NodeArchitype | EdgeArchitype]
|
|
234
|
+
| list[NodeArchitype]
|
|
235
|
+
| list[EdgeArchitype]
|
|
236
|
+
| NodeArchitype
|
|
237
|
+
| EdgeArchitype
|
|
238
|
+
),
|
|
236
239
|
) -> bool:
|
|
237
240
|
"""Walker visits node."""
|
|
238
241
|
nd_list: list[NodeArchitype | EdgeArchitype]
|
|
@@ -254,7 +257,13 @@ class WalkerAnchor(ObjectAnchor):
|
|
|
254
257
|
|
|
255
258
|
def ignore_node(
|
|
256
259
|
self,
|
|
257
|
-
nds:
|
|
260
|
+
nds: (
|
|
261
|
+
list[NodeArchitype | EdgeArchitype]
|
|
262
|
+
| list[NodeArchitype]
|
|
263
|
+
| list[EdgeArchitype]
|
|
264
|
+
| NodeArchitype
|
|
265
|
+
| EdgeArchitype
|
|
266
|
+
),
|
|
258
267
|
) -> bool:
|
|
259
268
|
"""Walker ignores node."""
|
|
260
269
|
nd_list: list[NodeArchitype | EdgeArchitype]
|
|
@@ -480,238 +489,14 @@ class Root(NodeArchitype):
|
|
|
480
489
|
self._jac_.edges = []
|
|
481
490
|
|
|
482
491
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
mem: dict[UUID, Architype] = {}
|
|
487
|
-
save_obj_list: dict[UUID, Architype] = {}
|
|
488
|
-
|
|
489
|
-
def __init__(self) -> None:
|
|
490
|
-
"""init."""
|
|
491
|
-
pass
|
|
492
|
-
|
|
493
|
-
def get_obj(self, obj_id: UUID) -> Architype | None:
|
|
494
|
-
"""Get object from memory."""
|
|
495
|
-
return self.get_obj_from_store(obj_id)
|
|
496
|
-
|
|
497
|
-
def get_obj_from_store(self, obj_id: UUID) -> Architype | None:
|
|
498
|
-
"""Get object from the underlying store."""
|
|
499
|
-
ret = self.mem.get(obj_id)
|
|
500
|
-
return ret
|
|
501
|
-
|
|
502
|
-
def has_obj(self, obj_id: UUID) -> bool:
|
|
503
|
-
"""Check if the object exists."""
|
|
504
|
-
return self.has_obj_in_store(obj_id)
|
|
505
|
-
|
|
506
|
-
def has_obj_in_store(self, obj_id: UUID) -> bool:
|
|
507
|
-
"""Check if the object exists in the underlying store."""
|
|
508
|
-
return obj_id in self.mem
|
|
509
|
-
|
|
510
|
-
def save_obj(self, item: Architype, persistent: bool) -> None:
|
|
511
|
-
"""Save object."""
|
|
512
|
-
self.mem[item._jac_.id] = item
|
|
513
|
-
if persistent:
|
|
514
|
-
# TODO: check if it needs to be saved, i.e. dirty or not
|
|
515
|
-
self.save_obj_list[item._jac_.id] = item
|
|
516
|
-
|
|
517
|
-
def commit(self) -> None:
|
|
518
|
-
"""Commit changes to persistent storage, if applicable."""
|
|
519
|
-
pass
|
|
520
|
-
|
|
521
|
-
def close(self) -> None:
|
|
522
|
-
"""Close any connection, if applicable."""
|
|
523
|
-
self.mem.clear()
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
class ShelveStorage(Memory):
|
|
527
|
-
"""Shelve storage for jaclang runtime object."""
|
|
528
|
-
|
|
529
|
-
storage: shelve.Shelf | None = None
|
|
530
|
-
|
|
531
|
-
def __init__(self, session: str = "") -> None:
|
|
532
|
-
"""Init shelve storage."""
|
|
533
|
-
super().__init__()
|
|
534
|
-
if session:
|
|
535
|
-
self.connect(session)
|
|
536
|
-
|
|
537
|
-
def get_obj_from_store(self, obj_id: UUID) -> Architype | None:
|
|
538
|
-
"""Get object from the underlying store."""
|
|
539
|
-
obj = super().get_obj_from_store(obj_id)
|
|
540
|
-
if obj is None and self.storage:
|
|
541
|
-
obj = self.storage.get(str(obj_id))
|
|
542
|
-
if obj is not None:
|
|
543
|
-
self.mem[obj_id] = obj
|
|
544
|
-
|
|
545
|
-
return obj
|
|
546
|
-
|
|
547
|
-
def has_obj_in_store(self, obj_id: UUID | str) -> bool:
|
|
548
|
-
"""Check if the object exists in the underlying store."""
|
|
549
|
-
return obj_id in self.mem or (
|
|
550
|
-
str(obj_id) in self.storage if self.storage else False
|
|
551
|
-
)
|
|
552
|
-
|
|
553
|
-
def commit(self) -> None:
|
|
554
|
-
"""Commit changes to persistent storage."""
|
|
555
|
-
if self.storage is not None:
|
|
556
|
-
for obj_id, obj in self.save_obj_list.items():
|
|
557
|
-
self.storage[str(obj_id)] = obj
|
|
558
|
-
self.save_obj_list.clear()
|
|
559
|
-
|
|
560
|
-
def connect(self, session: str) -> None:
|
|
561
|
-
"""Connect to storage."""
|
|
562
|
-
self.session = session
|
|
563
|
-
self.storage = shelve.open(session)
|
|
564
|
-
|
|
565
|
-
def close(self) -> None:
|
|
566
|
-
"""Close the storage."""
|
|
567
|
-
super().close()
|
|
568
|
-
self.commit()
|
|
569
|
-
if self.storage:
|
|
570
|
-
self.storage.close()
|
|
571
|
-
self.storage = None
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
class ExecutionContext:
|
|
575
|
-
"""Default Execution Context implementation."""
|
|
576
|
-
|
|
577
|
-
mem: Optional[Memory]
|
|
578
|
-
root: Optional[Root]
|
|
579
|
-
|
|
580
|
-
def __init__(self) -> None:
|
|
581
|
-
"""Create execution context."""
|
|
582
|
-
super().__init__()
|
|
583
|
-
self.mem = ShelveStorage()
|
|
584
|
-
self.root = None
|
|
585
|
-
|
|
586
|
-
def init_memory(self, session: str = "") -> None:
|
|
587
|
-
"""Initialize memory."""
|
|
588
|
-
if session:
|
|
589
|
-
self.mem = ShelveStorage(session)
|
|
590
|
-
else:
|
|
591
|
-
self.mem = Memory()
|
|
592
|
-
|
|
593
|
-
def get_root(self) -> Root:
|
|
594
|
-
"""Get the root object."""
|
|
595
|
-
if self.mem is None:
|
|
596
|
-
raise ValueError("Memory not initialized")
|
|
597
|
-
|
|
598
|
-
if not self.root:
|
|
599
|
-
root = self.mem.get_obj(UUID(int=0))
|
|
600
|
-
if root is None:
|
|
601
|
-
self.root = Root()
|
|
602
|
-
self.mem.save_obj(self.root, persistent=self.root._jac_.persistent)
|
|
603
|
-
elif not isinstance(root, Root):
|
|
604
|
-
raise ValueError(f"Invalid root object: {root}")
|
|
605
|
-
else:
|
|
606
|
-
self.root = root
|
|
607
|
-
return self.root
|
|
608
|
-
|
|
609
|
-
def get_obj(self, obj_id: UUID) -> Architype | None:
|
|
610
|
-
"""Get object from memory."""
|
|
611
|
-
if self.mem is None:
|
|
612
|
-
raise ValueError("Memory not initialized")
|
|
613
|
-
|
|
614
|
-
return self.mem.get_obj(obj_id)
|
|
615
|
-
|
|
616
|
-
def save_obj(self, item: Architype, persistent: bool) -> None:
|
|
617
|
-
"""Save object to memory."""
|
|
618
|
-
if self.mem is None:
|
|
619
|
-
raise ValueError("Memory not initialized")
|
|
620
|
-
|
|
621
|
-
self.mem.save_obj(item, persistent)
|
|
622
|
-
|
|
623
|
-
def reset(self) -> None:
|
|
624
|
-
"""Reset the execution context."""
|
|
625
|
-
if self.mem:
|
|
626
|
-
self.mem.close()
|
|
627
|
-
self.mem = None
|
|
628
|
-
self.root = None
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
exec_context: ContextVar[ExecutionContext | None] = ContextVar(
|
|
632
|
-
"ExecutionContext", default=None
|
|
633
|
-
)
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
class JacTestResult(unittest.TextTestResult):
|
|
637
|
-
"""Jac test result class."""
|
|
638
|
-
|
|
639
|
-
def __init__(
|
|
640
|
-
self,
|
|
641
|
-
stream, # noqa
|
|
642
|
-
descriptions, # noqa
|
|
643
|
-
verbosity: int,
|
|
644
|
-
max_failures: Optional[int] = None,
|
|
645
|
-
) -> None:
|
|
646
|
-
"""Initialize FailFastTestResult object."""
|
|
647
|
-
super().__init__(stream, descriptions, verbosity) # noqa
|
|
648
|
-
self.failures_count = JacTestCheck.failcount
|
|
649
|
-
self.max_failures = max_failures
|
|
650
|
-
|
|
651
|
-
def addFailure(self, test, err) -> None: # noqa
|
|
652
|
-
"""Count failures and stop."""
|
|
653
|
-
super().addFailure(test, err)
|
|
654
|
-
self.failures_count += 1
|
|
655
|
-
if self.max_failures is not None and self.failures_count >= self.max_failures:
|
|
656
|
-
self.stop()
|
|
657
|
-
|
|
658
|
-
def stop(self) -> None:
|
|
659
|
-
"""Stop the test execution."""
|
|
660
|
-
self.shouldStop = True
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
class JacTextTestRunner(unittest.TextTestRunner):
|
|
664
|
-
"""Jac test runner class."""
|
|
665
|
-
|
|
666
|
-
def __init__(self, max_failures: Optional[int] = None, **kwargs) -> None: # noqa
|
|
667
|
-
"""Initialize JacTextTestRunner object."""
|
|
668
|
-
self.max_failures = max_failures
|
|
669
|
-
super().__init__(**kwargs)
|
|
670
|
-
|
|
671
|
-
def _makeResult(self) -> JacTestResult: # noqa
|
|
672
|
-
"""Override the method to return an instance of JacTestResult."""
|
|
673
|
-
return JacTestResult(
|
|
674
|
-
self.stream,
|
|
675
|
-
self.descriptions,
|
|
676
|
-
self.verbosity,
|
|
677
|
-
max_failures=self.max_failures,
|
|
678
|
-
)
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
class JacTestCheck:
|
|
682
|
-
"""Jac Testing and Checking."""
|
|
683
|
-
|
|
684
|
-
test_case = unittest.TestCase()
|
|
685
|
-
test_suite = unittest.TestSuite()
|
|
686
|
-
breaker = False
|
|
687
|
-
failcount = 0
|
|
688
|
-
|
|
689
|
-
@staticmethod
|
|
690
|
-
def reset() -> None:
|
|
691
|
-
"""Clear the test suite."""
|
|
692
|
-
JacTestCheck.test_case = unittest.TestCase()
|
|
693
|
-
JacTestCheck.test_suite = unittest.TestSuite()
|
|
694
|
-
|
|
695
|
-
@staticmethod
|
|
696
|
-
def run_test(xit: bool, maxfail: int | None, verbose: bool) -> None:
|
|
697
|
-
"""Run the test suite."""
|
|
698
|
-
verb = 2 if verbose else 1
|
|
699
|
-
runner = JacTextTestRunner(max_failures=maxfail, failfast=xit, verbosity=verb)
|
|
700
|
-
result = runner.run(JacTestCheck.test_suite)
|
|
701
|
-
if result.wasSuccessful():
|
|
702
|
-
print("Passed successfully.")
|
|
703
|
-
else:
|
|
704
|
-
fails = len(result.failures)
|
|
705
|
-
JacTestCheck.failcount += fails
|
|
706
|
-
JacTestCheck.breaker = (
|
|
707
|
-
(JacTestCheck.failcount >= maxfail) if maxfail else True
|
|
708
|
-
)
|
|
492
|
+
@dataclass(eq=False)
|
|
493
|
+
class DSFunc:
|
|
494
|
+
"""Data Spatial Function."""
|
|
709
495
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
JacTestCheck.test_suite.addTest(unittest.FunctionTestCase(test_fun))
|
|
496
|
+
name: str
|
|
497
|
+
trigger: type | types.UnionType | tuple[type | types.UnionType, ...] | None
|
|
498
|
+
func: Callable[[Any, Any], Any] | None = None
|
|
714
499
|
|
|
715
|
-
def
|
|
716
|
-
"""
|
|
717
|
-
|
|
500
|
+
def resolve(self, cls: type) -> None:
|
|
501
|
+
"""Resolve the function."""
|
|
502
|
+
self.func = getattr(cls, self.name)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Core constructs for Jac Language."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from .architype import (
|
|
7
|
+
Architype,
|
|
8
|
+
DSFunc,
|
|
9
|
+
EdgeAnchor,
|
|
10
|
+
EdgeArchitype,
|
|
11
|
+
ElementAnchor,
|
|
12
|
+
GenericEdge,
|
|
13
|
+
NodeAnchor,
|
|
14
|
+
NodeArchitype,
|
|
15
|
+
ObjectAnchor,
|
|
16
|
+
Root,
|
|
17
|
+
WalkerAnchor,
|
|
18
|
+
WalkerArchitype,
|
|
19
|
+
)
|
|
20
|
+
from .context import ExecutionContext, exec_context
|
|
21
|
+
from .memory import Memory, ShelveStorage
|
|
22
|
+
from .test import JacTestCheck, JacTestResult, JacTextTestRunner
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"ElementAnchor",
|
|
26
|
+
"ObjectAnchor",
|
|
27
|
+
"NodeAnchor",
|
|
28
|
+
"EdgeAnchor",
|
|
29
|
+
"WalkerAnchor",
|
|
30
|
+
"Architype",
|
|
31
|
+
"NodeArchitype",
|
|
32
|
+
"EdgeArchitype",
|
|
33
|
+
"WalkerArchitype",
|
|
34
|
+
"GenericEdge",
|
|
35
|
+
"Root",
|
|
36
|
+
"DSFunc",
|
|
37
|
+
"Memory",
|
|
38
|
+
"ShelveStorage",
|
|
39
|
+
"ExecutionContext",
|
|
40
|
+
"exec_context",
|
|
41
|
+
"JacTestResult",
|
|
42
|
+
"JacTextTestRunner",
|
|
43
|
+
"JacTestCheck",
|
|
44
|
+
]
|
jaclang/core/context.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""Core constructs for Jac Language."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import unittest
|
|
6
|
+
from contextvars import ContextVar
|
|
7
|
+
from typing import Callable, Optional
|
|
8
|
+
from uuid import UUID
|
|
9
|
+
|
|
10
|
+
from .architype import Architype, Root
|
|
11
|
+
from .memory import Memory, ShelveStorage
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ExecutionContext:
|
|
15
|
+
"""Default Execution Context implementation."""
|
|
16
|
+
|
|
17
|
+
mem: Optional[Memory]
|
|
18
|
+
root: Optional[Root]
|
|
19
|
+
|
|
20
|
+
def __init__(self) -> None:
|
|
21
|
+
"""Create execution context."""
|
|
22
|
+
super().__init__()
|
|
23
|
+
self.mem = ShelveStorage()
|
|
24
|
+
self.root = None
|
|
25
|
+
|
|
26
|
+
def init_memory(self, session: str = "") -> None:
|
|
27
|
+
"""Initialize memory."""
|
|
28
|
+
if session:
|
|
29
|
+
self.mem = ShelveStorage(session)
|
|
30
|
+
else:
|
|
31
|
+
self.mem = Memory()
|
|
32
|
+
|
|
33
|
+
def get_root(self) -> Root:
|
|
34
|
+
"""Get the root object."""
|
|
35
|
+
if self.mem is None:
|
|
36
|
+
raise ValueError("Memory not initialized")
|
|
37
|
+
|
|
38
|
+
if not self.root:
|
|
39
|
+
root = self.mem.get_obj(UUID(int=0))
|
|
40
|
+
if root is None:
|
|
41
|
+
self.root = Root()
|
|
42
|
+
self.mem.save_obj(self.root, persistent=self.root._jac_.persistent)
|
|
43
|
+
elif not isinstance(root, Root):
|
|
44
|
+
raise ValueError(f"Invalid root object: {root}")
|
|
45
|
+
else:
|
|
46
|
+
self.root = root
|
|
47
|
+
return self.root
|
|
48
|
+
|
|
49
|
+
def get_obj(self, obj_id: UUID) -> Architype | None:
|
|
50
|
+
"""Get object from memory."""
|
|
51
|
+
if self.mem is None:
|
|
52
|
+
raise ValueError("Memory not initialized")
|
|
53
|
+
|
|
54
|
+
return self.mem.get_obj(obj_id)
|
|
55
|
+
|
|
56
|
+
def save_obj(self, item: Architype, persistent: bool) -> None:
|
|
57
|
+
"""Save object to memory."""
|
|
58
|
+
if self.mem is None:
|
|
59
|
+
raise ValueError("Memory not initialized")
|
|
60
|
+
|
|
61
|
+
self.mem.save_obj(item, persistent)
|
|
62
|
+
|
|
63
|
+
def reset(self) -> None:
|
|
64
|
+
"""Reset the execution context."""
|
|
65
|
+
if self.mem:
|
|
66
|
+
self.mem.close()
|
|
67
|
+
self.mem = None
|
|
68
|
+
self.root = None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
exec_context: ContextVar[ExecutionContext | None] = ContextVar(
|
|
72
|
+
"ExecutionContext", default=None
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class JacTestResult(unittest.TextTestResult):
|
|
77
|
+
"""Jac test result class."""
|
|
78
|
+
|
|
79
|
+
def __init__(
|
|
80
|
+
self,
|
|
81
|
+
stream, # noqa
|
|
82
|
+
descriptions, # noqa
|
|
83
|
+
verbosity: int,
|
|
84
|
+
max_failures: Optional[int] = None,
|
|
85
|
+
) -> None:
|
|
86
|
+
"""Initialize FailFastTestResult object."""
|
|
87
|
+
super().__init__(stream, descriptions, verbosity) # noqa
|
|
88
|
+
self.failures_count = JacTestCheck.failcount
|
|
89
|
+
self.max_failures = max_failures
|
|
90
|
+
|
|
91
|
+
def addFailure(self, test, err) -> None: # noqa
|
|
92
|
+
"""Count failures and stop."""
|
|
93
|
+
super().addFailure(test, err)
|
|
94
|
+
self.failures_count += 1
|
|
95
|
+
if self.max_failures is not None and self.failures_count >= self.max_failures:
|
|
96
|
+
self.stop()
|
|
97
|
+
|
|
98
|
+
def stop(self) -> None:
|
|
99
|
+
"""Stop the test execution."""
|
|
100
|
+
self.shouldStop = True
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class JacTextTestRunner(unittest.TextTestRunner):
|
|
104
|
+
"""Jac test runner class."""
|
|
105
|
+
|
|
106
|
+
def __init__(self, max_failures: Optional[int] = None, **kwargs) -> None: # noqa
|
|
107
|
+
"""Initialize JacTextTestRunner object."""
|
|
108
|
+
self.max_failures = max_failures
|
|
109
|
+
super().__init__(**kwargs)
|
|
110
|
+
|
|
111
|
+
def _makeResult(self) -> JacTestResult: # noqa
|
|
112
|
+
"""Override the method to return an instance of JacTestResult."""
|
|
113
|
+
return JacTestResult(
|
|
114
|
+
self.stream,
|
|
115
|
+
self.descriptions,
|
|
116
|
+
self.verbosity,
|
|
117
|
+
max_failures=self.max_failures,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class JacTestCheck:
|
|
122
|
+
"""Jac Testing and Checking."""
|
|
123
|
+
|
|
124
|
+
test_case = unittest.TestCase()
|
|
125
|
+
test_suite = unittest.TestSuite()
|
|
126
|
+
breaker = False
|
|
127
|
+
failcount = 0
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def reset() -> None:
|
|
131
|
+
"""Clear the test suite."""
|
|
132
|
+
JacTestCheck.test_case = unittest.TestCase()
|
|
133
|
+
JacTestCheck.test_suite = unittest.TestSuite()
|
|
134
|
+
|
|
135
|
+
@staticmethod
|
|
136
|
+
def run_test(xit: bool, maxfail: int | None, verbose: bool) -> None:
|
|
137
|
+
"""Run the test suite."""
|
|
138
|
+
verb = 2 if verbose else 1
|
|
139
|
+
runner = JacTextTestRunner(max_failures=maxfail, failfast=xit, verbosity=verb)
|
|
140
|
+
result = runner.run(JacTestCheck.test_suite)
|
|
141
|
+
if result.wasSuccessful():
|
|
142
|
+
print("Passed successfully.")
|
|
143
|
+
else:
|
|
144
|
+
fails = len(result.failures)
|
|
145
|
+
JacTestCheck.failcount += fails
|
|
146
|
+
JacTestCheck.breaker = (
|
|
147
|
+
(JacTestCheck.failcount >= maxfail) if maxfail else True
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
@staticmethod
|
|
151
|
+
def add_test(test_fun: Callable) -> None:
|
|
152
|
+
"""Create a new test."""
|
|
153
|
+
JacTestCheck.test_suite.addTest(unittest.FunctionTestCase(test_fun))
|
|
154
|
+
|
|
155
|
+
def __getattr__(self, name: str) -> object:
|
|
156
|
+
"""Make convenient check.Equal(...) etc."""
|
|
157
|
+
return getattr(JacTestCheck.test_case, name)
|
jaclang/core/importer.py
CHANGED
|
@@ -11,7 +11,6 @@ from jaclang.compiler.absyntree import Module
|
|
|
11
11
|
from jaclang.compiler.compile import compile_jac
|
|
12
12
|
from jaclang.compiler.constant import Constants as Con
|
|
13
13
|
from jaclang.core.utils import sys_path_context
|
|
14
|
-
from jaclang.utils.log import logging
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
def jac_importer(
|
|
@@ -21,7 +20,7 @@ def jac_importer(
|
|
|
21
20
|
cachable: bool = True,
|
|
22
21
|
mdl_alias: Optional[str] = None,
|
|
23
22
|
override_name: Optional[str] = None,
|
|
24
|
-
mod_bundle: Optional[Module] = None,
|
|
23
|
+
mod_bundle: Optional[Module | str] = None,
|
|
25
24
|
lng: Optional[str] = "jac",
|
|
26
25
|
items: Optional[dict[str, Union[str, bool]]] = None,
|
|
27
26
|
) -> Optional[types.ModuleType]:
|
|
@@ -41,6 +40,14 @@ def jac_importer(
|
|
|
41
40
|
elif not override_name and not package_path and module_name in sys.modules:
|
|
42
41
|
return sys.modules[module_name]
|
|
43
42
|
|
|
43
|
+
valid_mod_bundle = (
|
|
44
|
+
sys.modules[mod_bundle].__jac_mod_bundle__
|
|
45
|
+
if isinstance(mod_bundle, str)
|
|
46
|
+
and mod_bundle in sys.modules
|
|
47
|
+
and "__jac_mod_bundle__" in sys.modules[mod_bundle].__dict__
|
|
48
|
+
else None
|
|
49
|
+
)
|
|
50
|
+
|
|
44
51
|
caller_dir = get_caller_dir(target, base_path, dir_path)
|
|
45
52
|
full_target = path.normpath(path.join(caller_dir, file_name))
|
|
46
53
|
|
|
@@ -51,10 +58,10 @@ def jac_importer(
|
|
|
51
58
|
else:
|
|
52
59
|
module_name = override_name if override_name else module_name
|
|
53
60
|
module = create_jac_py_module(
|
|
54
|
-
|
|
61
|
+
valid_mod_bundle, module_name, package_path, full_target
|
|
55
62
|
)
|
|
56
|
-
if
|
|
57
|
-
codeobj =
|
|
63
|
+
if valid_mod_bundle:
|
|
64
|
+
codeobj = valid_mod_bundle.mod_deps[full_target].gen.py_bytecode
|
|
58
65
|
codeobj = marshal.loads(codeobj) if isinstance(codeobj, bytes) else None
|
|
59
66
|
else:
|
|
60
67
|
gen_dir = path.join(caller_dir, Con.JAC_GEN_DIR)
|
|
@@ -69,9 +76,8 @@ def jac_importer(
|
|
|
69
76
|
else:
|
|
70
77
|
result = compile_jac(full_target, cache_result=cachable)
|
|
71
78
|
if result.errors_had or not result.ir.gen.py_bytecode:
|
|
72
|
-
for e in result.errors_had:
|
|
73
|
-
|
|
74
|
-
logging.error(e)
|
|
79
|
+
# for e in result.errors_had:
|
|
80
|
+
# print(e)
|
|
75
81
|
return None
|
|
76
82
|
else:
|
|
77
83
|
codeobj = marshal.loads(result.ir.gen.py_bytecode)
|
|
@@ -84,7 +90,10 @@ def jac_importer(
|
|
|
84
90
|
|
|
85
91
|
|
|
86
92
|
def create_jac_py_module(
|
|
87
|
-
mod_bundle: Optional[Module
|
|
93
|
+
mod_bundle: Optional[Module | str],
|
|
94
|
+
module_name: str,
|
|
95
|
+
package_path: str,
|
|
96
|
+
full_target: str,
|
|
88
97
|
) -> types.ModuleType:
|
|
89
98
|
"""Create a module."""
|
|
90
99
|
module = types.ModuleType(module_name)
|
jaclang/core/memory.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Core constructs for Jac Language."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import shelve
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from .architype import Architype
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Memory:
|
|
12
|
+
"""Memory module interface."""
|
|
13
|
+
|
|
14
|
+
mem: dict[UUID, Architype] = {}
|
|
15
|
+
save_obj_list: dict[UUID, Architype] = {}
|
|
16
|
+
|
|
17
|
+
def __init__(self) -> None:
|
|
18
|
+
"""init."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
def get_obj(self, obj_id: UUID) -> Architype | None:
|
|
22
|
+
"""Get object from memory."""
|
|
23
|
+
return self.get_obj_from_store(obj_id)
|
|
24
|
+
|
|
25
|
+
def get_obj_from_store(self, obj_id: UUID) -> Architype | None:
|
|
26
|
+
"""Get object from the underlying store."""
|
|
27
|
+
ret = self.mem.get(obj_id)
|
|
28
|
+
return ret
|
|
29
|
+
|
|
30
|
+
def has_obj(self, obj_id: UUID) -> bool:
|
|
31
|
+
"""Check if the object exists."""
|
|
32
|
+
return self.has_obj_in_store(obj_id)
|
|
33
|
+
|
|
34
|
+
def has_obj_in_store(self, obj_id: UUID) -> bool:
|
|
35
|
+
"""Check if the object exists in the underlying store."""
|
|
36
|
+
return obj_id in self.mem
|
|
37
|
+
|
|
38
|
+
def save_obj(self, item: Architype, persistent: bool) -> None:
|
|
39
|
+
"""Save object."""
|
|
40
|
+
self.mem[item._jac_.id] = item
|
|
41
|
+
if persistent:
|
|
42
|
+
# TODO: check if it needs to be saved, i.e. dirty or not
|
|
43
|
+
self.save_obj_list[item._jac_.id] = item
|
|
44
|
+
|
|
45
|
+
def commit(self) -> None:
|
|
46
|
+
"""Commit changes to persistent storage, if applicable."""
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
def close(self) -> None:
|
|
50
|
+
"""Close any connection, if applicable."""
|
|
51
|
+
self.mem.clear()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ShelveStorage(Memory):
|
|
55
|
+
"""Shelve storage for jaclang runtime object."""
|
|
56
|
+
|
|
57
|
+
storage: shelve.Shelf | None = None
|
|
58
|
+
|
|
59
|
+
def __init__(self, session: str = "") -> None:
|
|
60
|
+
"""Init shelve storage."""
|
|
61
|
+
super().__init__()
|
|
62
|
+
if session:
|
|
63
|
+
self.connect(session)
|
|
64
|
+
|
|
65
|
+
def get_obj_from_store(self, obj_id: UUID) -> Architype | None:
|
|
66
|
+
"""Get object from the underlying store."""
|
|
67
|
+
obj = super().get_obj_from_store(obj_id)
|
|
68
|
+
if obj is None and self.storage:
|
|
69
|
+
obj = self.storage.get(str(obj_id))
|
|
70
|
+
if obj is not None:
|
|
71
|
+
self.mem[obj_id] = obj
|
|
72
|
+
|
|
73
|
+
return obj
|
|
74
|
+
|
|
75
|
+
def has_obj_in_store(self, obj_id: UUID | str) -> bool:
|
|
76
|
+
"""Check if the object exists in the underlying store."""
|
|
77
|
+
return obj_id in self.mem or (
|
|
78
|
+
str(obj_id) in self.storage if self.storage else False
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def commit(self) -> None:
|
|
82
|
+
"""Commit changes to persistent storage."""
|
|
83
|
+
if self.storage is not None:
|
|
84
|
+
for obj_id, obj in self.save_obj_list.items():
|
|
85
|
+
self.storage[str(obj_id)] = obj
|
|
86
|
+
self.save_obj_list.clear()
|
|
87
|
+
|
|
88
|
+
def connect(self, session: str) -> None:
|
|
89
|
+
"""Connect to storage."""
|
|
90
|
+
self.session = session
|
|
91
|
+
self.storage = shelve.open(session)
|
|
92
|
+
|
|
93
|
+
def close(self) -> None:
|
|
94
|
+
"""Close the storage."""
|
|
95
|
+
super().close()
|
|
96
|
+
self.commit()
|
|
97
|
+
if self.storage:
|
|
98
|
+
self.storage.close()
|
|
99
|
+
self.storage = None
|