Skip to content

Commit 64e25ca

Browse files
committed
Current CFG progress
1 parent 910e1bb commit 64e25ca

3 files changed

Lines changed: 212 additions & 160 deletions

File tree

lib/laundromat/cfg.py

Lines changed: 1 addition & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,15 @@
11
import matplotlib.pyplot as plt
22
import networkx as nx
33

4-
import operator
5-
6-
from dataclasses import dataclass, replace
7-
84
from lib.fourmat.parse import *
5+
from lib.laundromat.node import *
96

107

118
class InvalidDirective(TypeError):
129
def __init__(self, directive: Directive | str):
1310
super().__init__(f"invalid directive: {directive}")
1411

1512

16-
Operand = Special | int | str
17-
18-
@dataclass(frozen=True)
19-
class Condition:
20-
a: Operand
21-
b: Operand = None
22-
c: Operand = None
23-
24-
def __str__(self) -> str:
25-
match self.params:
26-
case [a]:
27-
return a
28-
29-
case [a, b]:
30-
return f"{a} = {b}"
31-
32-
case [a, b, c]:
33-
return f"{a} <= {b} <= {c}"
34-
35-
@property
36-
def op(self):
37-
match len(self.params):
38-
case 1:
39-
return operator.not_
40-
41-
case 2:
42-
return operator.eq
43-
44-
case 3:
45-
return operator.le
46-
47-
@property
48-
def params(self) -> list[Operand]:
49-
return [x for x in (self.a, self.b, self.c) if x is not None]
50-
51-
def check(self, pointer: tuple[int, int], tape: list[list[str]]) -> tuple[bool, bool]:
52-
lower, upper = pointer
53-
54-
match self.params:
55-
case ["T"]:
56-
return True, True
57-
58-
case [Special.Hash, Special.Hash] | [Special.Hash, Special.Hash, Special.Hash]:
59-
return True, False
60-
61-
case [Special.Hash, b] | [b, Special.Hash] | [Special.Hash, b, Special.Hash]:
62-
return lower <= int(b) <= upper, not lower == int(b) == upper
63-
64-
case [a, b]:
65-
t = f = False
66-
for x in (tape[0] if a == Special.V else [a]):
67-
for y in (tape[1] if b == Special.V else [b]):
68-
t |= x == y
69-
f |= x != y
70-
71-
if t and f:
72-
return True, True
73-
74-
return t, f
75-
76-
case [Special.Hash, Special.Hash, c]:
77-
return lower <= int(c), int(c) <= upper
78-
79-
case [a, Special.Hash, Special.Hash]:
80-
return int(a) <= upper, lower <= int(a)
81-
82-
case [Special.Hash, b, c]:
83-
return lower <= int(b) <= int(c), int(b) <= upper or int(b) > int(c)
84-
85-
case [a, Special.Hash, c]:
86-
return (int(a) <= lower <= int(c) or int(a) <= upper <= int(c),
87-
upper < int(a) or int(c) < lower or int(a) > int(c))
88-
89-
case [a, b, Special.Hash]:
90-
return int(a) <= int(b) <= upper, lower <= int(b) or int(a) > int(b)
91-
92-
case [a, b, c]:
93-
t = f = False
94-
for x in (tape[0] if a == Special.V else [a]):
95-
for y in (tape[1] if b == Special.V else [b]):
96-
for z in (tape[2] if c == Special.V else [c]):
97-
t |= x <= y <= z
98-
f |= not x <= y <= z
99-
100-
if t and f:
101-
return True, True
102-
103-
return t, f
104-
105-
106-
@dataclass(eq=False)
107-
class Node:
108-
directive: Directive | Condition | str
109-
on_tape: bool = False
110-
111-
def __hash__(self) -> int:
112-
return id(self)
113-
114-
def __str__(self) -> str:
115-
return f"{self.directive}"
116-
117-
@property
118-
def is_condition(self) -> bool:
119-
return isinstance(self.directive, Condition)
120-
121-
@property
122-
def is_conditional(self) -> bool:
123-
return isinstance(self.directive, Directive) and self.directive.kind in "[]"
124-
125-
@property
126-
def is_loop(self) -> bool:
127-
return isinstance(self.directive, Directive) and self.directive.kind in "{}"
128-
129-
def copy(self, **changes) -> 'Node':
130-
return replace(self, **changes)
131-
132-
def condition(self, a: Operand, b: Operand = None, c: Operand = None) -> 'Node':
133-
return self.copy(directive=Condition(a, b, c))
134-
135-
13613
START = Node("S")
13714
END = Node("E")
13815
CRASH = Node("C")

lib/laundromat/node.py

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import operator
2+
3+
from dataclasses import dataclass, replace
4+
5+
from lib.fourmat.parse import *
6+
7+
8+
Operand = Special | int | str
9+
10+
@dataclass(frozen=True)
11+
class Condition:
12+
a: Operand
13+
b: Operand = None
14+
c: Operand = None
15+
16+
def __str__(self) -> str:
17+
match self.params:
18+
case [a]:
19+
return a
20+
21+
case [a, b]:
22+
return f"{a} = {b}"
23+
24+
case [a, b, c]:
25+
return f"{a} <= {b} <= {c}"
26+
27+
@property
28+
def op(self):
29+
match len(self.params):
30+
case 1:
31+
return operator.not_
32+
33+
case 2:
34+
return operator.eq
35+
36+
case 3:
37+
return operator.le
38+
39+
@property
40+
def params(self) -> list[Operand]:
41+
return [x for x in (self.a, self.b, self.c) if x is not None]
42+
43+
def check(self, pointer: tuple[int, int], tape: list[list[str]]) -> tuple[bool, bool]:
44+
lower, upper = pointer
45+
46+
match self.params:
47+
case ["T"]:
48+
return True, True
49+
50+
case [Special.Hash, Special.Hash] | [Special.Hash, Special.Hash, Special.Hash]:
51+
return True, False
52+
53+
case [Special.Hash, b] | [b, Special.Hash] | [Special.Hash, b, Special.Hash]:
54+
return lower <= int(b) <= upper, not lower == int(b) == upper
55+
56+
case [a, b]:
57+
t = f = False
58+
for x in (tape[0] if a == Special.V else [a]):
59+
for y in (tape[1] if b == Special.V else [b]):
60+
t |= x == y
61+
f |= x != y
62+
63+
if t and f:
64+
return True, True
65+
66+
return t, f
67+
68+
case [Special.Hash, Special.Hash, c]:
69+
return lower <= int(c), int(c) <= upper
70+
71+
case [a, Special.Hash, Special.Hash]:
72+
return int(a) <= upper, lower <= int(a)
73+
74+
case [Special.Hash, b, c]:
75+
return lower <= int(b) <= int(c), int(b) <= upper or int(b) > int(c)
76+
77+
case [a, Special.Hash, c]:
78+
return (int(a) <= lower <= int(c) or int(a) <= upper <= int(c),
79+
upper < int(a) or int(c) < lower or int(a) > int(c))
80+
81+
case [a, b, Special.Hash]:
82+
return int(a) <= int(b) <= upper, lower <= int(b) or int(a) > int(b)
83+
84+
case [a, b, c]:
85+
t = f = False
86+
for x in (tape[0] if a == Special.V else [a]):
87+
for y in (tape[1] if b == Special.V else [b]):
88+
for z in (tape[2] if c == Special.V else [c]):
89+
t |= x <= y <= z
90+
f |= not x <= y <= z
91+
92+
if t and f:
93+
return True, True
94+
95+
return t, f
96+
97+
98+
@dataclass(eq=False)
99+
class Node:
100+
directive: Directive | Condition | str
101+
on_tape: bool = False
102+
103+
def __hash__(self) -> int:
104+
return id(self)
105+
106+
def __str__(self) -> str:
107+
return f"{self.directive}"
108+
109+
@property
110+
def is_condition(self) -> bool:
111+
return isinstance(self.directive, Condition)
112+
113+
@property
114+
def is_conditional(self) -> bool:
115+
return isinstance(self.directive, Directive) and self.directive.kind in "[]"
116+
117+
@property
118+
def is_loop(self) -> bool:
119+
return isinstance(self.directive, Directive) and self.directive.kind in "{}"
120+
121+
@property
122+
def consumes(self) -> int | None:
123+
if isinstance(self.directive, (Condition, str)):
124+
return 0
125+
126+
match self.directive.kind:
127+
case 'a' | 'd' | 'e' | 'f' | 'g' | 'o' | 'r' | 's' | 'w' | 'x' | '$':
128+
return 1 + self.directive.params.count(Special.V) if self.on_tape else 1
129+
130+
case 'c':
131+
return 1
132+
133+
case 't' | '%' | '&' | '|' | '~' | '^':
134+
return self.directive.params.count(Special.V)
135+
136+
case '?':
137+
return 1
138+
139+
case '/':
140+
return 1
141+
142+
case '*' if (n := self.directive.get_param(0, 1)) not in Special:
143+
if self.directive.at_sign:
144+
return None
145+
146+
elif self.directive.colon:
147+
return -n
148+
149+
else:
150+
return n
151+
152+
case _:
153+
return None
154+
155+
@property
156+
def writes(self) -> int | None:
157+
if isinstance(self.directive, Condition):
158+
return 0
159+
160+
if isinstance(self.directive, str):
161+
return len(self.directive)
162+
163+
match self.directive.kind:
164+
case 'a' | 'd' | 'e' | 'f' | 'g' | 'o' | 'r' | 's' | 'w' | 'x':
165+
return None
166+
167+
case 'c':
168+
return 1
169+
170+
case 't':
171+
return None
172+
173+
case '%' | '&' | '|' | '~':
174+
return self.directive.get_param(0, 1)
175+
176+
case '/':
177+
return None
178+
179+
case _:
180+
return 0
181+
182+
def copy(self, **changes) -> 'Node':
183+
return replace(self, **changes)
184+
185+
def condition(self, a: Operand, b: Operand = None, c: Operand = None) -> 'Node':
186+
return self.copy(directive=Condition(a, b, c))

0 commit comments

Comments
 (0)