Skip to content

Commit e995c50

Browse files
Support Single IF.
1 parent 1cdf05e commit e995c50

5 files changed

Lines changed: 128 additions & 103 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
# AmritaSense
22
Next-Gen Graph workflow engine.
3+
4+
<center>
5+
6+
> ## *"Any is things all you need."*
7+
8+
</center>

src/amrita_sense/exceptions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ class NullPointerException(Exception):
1313
class BreakLoop(Exception):
1414
"""Throwed when break loop (in while or do-while clause)"""
1515

16+
1617
class DependsException(Exception):
1718
"""Throwed when DI resolve failed."""
1819

1920

2021
class DependsResolveFailed(Exception):
2122
"""Throwed when DI resolve failed."""
2223

24+
2325
class DependsInjectFailed(Exception):
2426
"""Throwed when DI resolve failed."""

src/amrita_sense/instructions/if_clause.py

Lines changed: 109 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from abc import ABC
33
from collections.abc import Callable
44
from types import FrameType
5-
from typing import Any, TypeAlias
5+
from typing import Any, TypeVar
66

77
from typing_extensions import Self
88

@@ -11,78 +11,8 @@
1111
from amrita_sense.node.self_compile import SelfCompileInstruction
1212
from amrita_sense.runtime.workflow import WorkflowPC
1313

14-
15-
class Condition(ABC):
16-
condition: Node[bool]
17-
do: BaseNode
18-
19-
20-
class IFClause(SelfCompileInstruction, Condition):
21-
"""IF Clause
22-
Usage:
23-
```python
24-
IF(CONDITION,PAYLOAD)
25-
IF(CONDITION,PAYLOAD).ELSE(ELSE_PAYLOAD)
26-
IF(CONDITION,PAYLOAD).ELIF(ELIF_CONDITION,ELIF_PAYLOAD).ELSE(ELSE_PAYLOAD)
27-
```
28-
"""
29-
30-
def __init__(self, condition: Node[bool], do: BaseNode):
31-
self.condition = condition
32-
self.do = do
33-
34-
def extract(self) -> NodeCompose:
35-
return NodeCompose(
36-
ConditionJumpNode(
37-
condition_offset=1,
38-
do_offset=2,
39-
false_offset=3,
40-
then_addr=3,
41-
),
42-
self.condition,
43-
self.do,
44-
NOP,
45-
)
46-
47-
@property
48-
def ELIF(self) -> Callable[[Node, Node], "ELIFClause"]:
49-
return lambda condition, node: ELIFClause(self, condition, node)
50-
51-
@property
52-
def ELSE(self) -> Callable[[Node], "ELSEClause"]:
53-
return lambda node: ELSEClause(self, node)
54-
55-
56-
class NestedELIFClause(Condition):
57-
parent: "ELIFClause"
58-
59-
def __init__(self, if_clause: "ELIFClause", condition: Node[bool], do: Node):
60-
self.condition = condition
61-
self.do = do
62-
self.parent = if_clause
63-
64-
65-
class ELIFClause(Condition):
66-
parent: IFClause
67-
_elif_compose: list[NestedELIFClause]
68-
69-
def __init__(self, if_clause: IFClause, condition: Node[bool], do: Node):
70-
self.condition = condition
71-
self.do = do
72-
self.parent = if_clause
73-
self._elif_compose = []
74-
75-
@property
76-
def ELIF(self) -> Callable[[Node, Node], Self]:
77-
def _elif(condition, do):
78-
self._elif_compose.append(NestedELIFClause(self, condition, do))
79-
return self
80-
81-
return _elif
82-
83-
@property
84-
def ELSE(self) -> Callable[[Node | None], "ELSEClause"]:
85-
return lambda node=None: ELSEClause(self, node or NOP)
14+
T_cod = TypeVar("T_cod", bound=Node[bool], covariant=True)
15+
T_ret = TypeVar("T_ret", bound=BaseNode, covariant=True)
8616

8717

8818
class ConditionJumpNode(BaseNode):
@@ -154,6 +84,109 @@ async def _do(self, pc: WorkflowPC):
15484
def __call__(self, pc: WorkflowPC):
15585
return self._do(pc)
15686

87+
@classmethod
88+
def make_chunk(
89+
cls, condition: T_cod, do: T_ret, then: int, false: int
90+
) -> tuple[Self, T_cod, T_ret]:
91+
return (cls(1, 2, false, then), condition, do)
92+
93+
94+
class Condition(ABC):
95+
condition: Node[bool]
96+
do: BaseNode
97+
98+
99+
class IFClause(SelfCompileInstruction, Condition):
100+
"""IF Clause
101+
Usage:
102+
```python
103+
IF(CONDITION,PAYLOAD)
104+
IF(CONDITION,PAYLOAD).ELIF(ELIF_CONDITION,ELIF_PAYLOAD)
105+
IF(CONDITION,PAYLOAD).ELSE(ELSE_PAYLOAD)
106+
IF(CONDITION,PAYLOAD).ELIF(ELIF_CONDITION,ELIF_PAYLOAD).ELSE(ELSE_PAYLOAD)
107+
```
108+
"""
109+
110+
def __init__(self, condition: Node[bool], do: BaseNode):
111+
self.condition = condition
112+
self.do = do
113+
114+
def extract(self) -> NodeCompose:
115+
return NodeCompose(
116+
*ConditionJumpNode.make_chunk(self.condition, self.do, 3, 3),
117+
NOP,
118+
)
119+
120+
@property
121+
def ELIF(self) -> Callable[[Node, Node], "ELIFClause"]:
122+
return lambda condition, node: ELIFClause(self, condition, node)
123+
124+
@property
125+
def ELSE(self) -> Callable[[Node], "ELSEClause"]:
126+
return lambda node: ELSEClause(self, node)
127+
128+
129+
class NestedELIFClause(Condition):
130+
parent: "ELIFClause"
131+
132+
def __init__(self, if_clause: "ELIFClause", condition: Node[bool], do: Node):
133+
self.condition = condition
134+
self.do = do
135+
self.parent = if_clause
136+
137+
138+
class ELIFClause(SelfCompileInstruction, Condition):
139+
parent: IFClause
140+
_elif_compose: list[NestedELIFClause]
141+
142+
def __init__(self, if_clause: IFClause, condition: Node[bool], do: Node):
143+
self.condition = condition
144+
self.do = do
145+
self.parent = if_clause
146+
self._elif_compose = []
147+
148+
@property
149+
def ELIF(self) -> Callable[[Node, Node], Self]:
150+
def _elif(condition, do):
151+
self._elif_compose.append(NestedELIFClause(self, condition, do))
152+
return self
153+
154+
return _elif
155+
156+
@property
157+
def ELSE(self) -> Callable[[Node | None], "ELSEClause"]:
158+
return lambda node=None: ELSEClause(self, node or NOP)
159+
160+
def extract(self) -> NodeCompose:
161+
total_length = (
162+
3 # IF + CONDI + DO
163+
+ 3 # Main ELIF Clause
164+
+ len(self._elif_compose) * 3 # Each 3 elements
165+
+ 1 # NOP exit point
166+
)
167+
jump_out_addr = total_length - 1
168+
compose_chunk: list[ConditionJumpNode | Node[bool] | BaseNode] = [
169+
*ConditionJumpNode.make_chunk(
170+
self.parent.condition, self.parent.do, jump_out_addr, 3
171+
),
172+
*ConditionJumpNode.make_chunk(self.condition, self.do, jump_out_addr, 3),
173+
]
174+
175+
elif_chains_nodes: list[ConditionJumpNode | Node[bool] | BaseNode] = []
176+
for i in self._elif_compose:
177+
elif_chains_nodes.extend(
178+
[
179+
*ConditionJumpNode.make_chunk(
180+
i.condition, i.do, then=jump_out_addr, false=3
181+
),
182+
]
183+
)
184+
compose_chunk.extend(elif_chains_nodes)
185+
compose_chunk.append(NOP)
186+
return NodeCompose(
187+
*compose_chunk,
188+
)
189+
157190

158191
class ELSENode(BaseNode):
159192
"""ELSE node
@@ -197,10 +230,6 @@ def __call__(self, pc: WorkflowPC):
197230
return self._else_worker(pc)
198231

199232

200-
CONDITION_CHAIN: TypeAlias = tuple[ConditionJumpNode, Node, Node]
201-
ELSE_TUPLE: TypeAlias = tuple[ELSENode, Node]
202-
203-
204233
class ELSEClause(SelfCompileInstruction, Condition):
205234
top: IFClause
206235
parent: ELIFClause | IFClause
@@ -216,9 +245,7 @@ def extract(self) -> NodeCompose:
216245

217246
# Base IF clause
218247
compose_chunk = [
219-
ConditionJumpNode(
220-
condition_offset=1, do_offset=2, false_offset=3, then_addr=0
221-
),
248+
NOP,
222249
top_if.condition,
223250
top_if.do,
224251
]
@@ -260,27 +287,14 @@ def extract(self) -> NodeCompose:
260287

261288
# Main ELIF clause
262289
elif_clause_nodes = [
263-
ConditionJumpNode(
264-
condition_offset=1, do_offset=2, false_offset=3, then_addr=then_addr
265-
),
266-
parent.condition,
267-
parent.do,
290+
*ConditionJumpNode.make_chunk(parent.condition, parent.do, then_addr, 3)
268291
]
269292

270293
# ELIF chain
271294
elif_chains_nodes = []
272295
for i in parent._elif_compose:
273296
elif_chains_nodes.extend(
274-
[
275-
ConditionJumpNode(
276-
condition_offset=1,
277-
do_offset=2,
278-
false_offset=3,
279-
then_addr=then_addr,
280-
),
281-
i.condition,
282-
i.do,
283-
]
297+
[*ConditionJumpNode.make_chunk(i.condition, i.do, then_addr, 3)]
284298
)
285299

286300
# ELSE chunk - then_addr=2 points to NOP within ELSE chunk (relative addressing)
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1+
from typing import NoReturn
2+
13
from amrita_sense.exceptions import InterruptNotice
24
from amrita_sense.node.core import Node as _Node
35

46
from ..node.wrapper import Node as _node_fun
57

68

79
@_node_fun(wrap_to_async=False, address_able=True)
8-
def _no_operation():
10+
def _no_operation() -> None:
911
pass
1012

1113

1214
@_node_fun(wrap_to_async=False, address_able=False)
13-
def _interrput_operation():
15+
def _interrput_operation() -> NoReturn:
1416
raise InterruptNotice("Interrupt Node")
1517

1618

17-
NOP: _Node = _no_operation
19+
NOP: _Node[None] = _no_operation
1820

19-
INTERRUPT: _Node = _interrput_operation
21+
INTERRUPT: _Node[NoReturn] = _interrput_operation

src/amrita_sense/runtime/workflow.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def __init__(
5151
self._pointer = PointerVector()
5252
self._ava_args = (self, *extra_args)
5353
self._ava_kwargs = deepcopy(extra_kwargs)
54-
self._exc_ignored = exception_ignored
54+
self._exc_ignored = (*exception_ignored, InterruptNotice)
5555
self.object_io = object_io or SuspendObjectStream()
5656
self._ret_addr_stack = addr_stack or Stack()
5757
self._jump_marked = False
@@ -122,10 +122,12 @@ async def call_near(self, addr: int, *ag, **kw) -> Any:
122122
logger.info(f"Calling near address {addr} at pointer {ptr}")
123123
return await self.call_sub(ptr, *ag, **kw)
124124

125-
async def call_sub(self, addr: PointerVector, /, *extra_arg, **extra_kwargs) -> Any:
125+
async def call_sub(
126+
self, addr: PointerVector | list[int], /, *extra_arg, **extra_kwargs
127+
) -> Any:
126128
pev: PointerVector = self._pointer
127129
self._ret_addr_stack.push(pev)
128-
self._pointer = addr
130+
self._pointer = addr if isinstance(addr, PointerVector) else PointerVector(addr)
129131
logger.info(f"Calling subroutine at {addr}")
130132
try:
131133
return await self._call(self.find_addr, *extra_arg, **extra_kwargs)
@@ -293,7 +295,6 @@ async def _call(
293295
self,
294296
addr_getter: Callable[[list[int]], BaseNode | NodeComposeRendered]
295297
| None = None,
296-
/,
297298
*extra_args: Any,
298299
**extra_kwargs: Any,
299300
) -> Any:

0 commit comments

Comments
 (0)