22from abc import ABC
33from collections .abc import Callable
44from types import FrameType
5- from typing import Any , TypeAlias
5+ from typing import Any , TypeVar
66
77from typing_extensions import Self
88
1111from amrita_sense .node .self_compile import SelfCompileInstruction
1212from 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
8818class 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
158191class 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-
204233class 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)
0 commit comments