Skip to content

Commit 7ee2f02

Browse files
authored
Merge pull request #909 from boriel-basic/fix/fix_peephole_opt_recipe_parser
Fix/fix peephole opt recipe parser
2 parents 9536b5b + cb218d7 commit 7ee2f02

3 files changed

Lines changed: 64 additions & 14 deletions

File tree

src/arch/z80/peephole/evaluator.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import re
44
from collections.abc import Callable
5-
from enum import Enum, unique
5+
from enum import StrEnum, unique
66
from typing import Any
77

88
from src.api import utils
@@ -13,7 +13,7 @@
1313

1414

1515
@unique
16-
class FN(str, Enum):
16+
class FN(StrEnum):
1717
OP_NOT = "!"
1818
OP_PLUS = "+"
1919
OP_EQ = "=="
@@ -215,28 +215,31 @@ def eval(self, vars_: dict[str, Any] | None = None) -> str | Evaluator | list[An
215215
val = self.expression[0]
216216
if not isinstance(val, str):
217217
return val
218+
218219
if val == "$":
219220
return val
221+
220222
if not RE_SVAR.match(val):
221223
return val
224+
222225
if val not in vars_:
223226
raise UnboundVarError(f"Unbound variable '{val}'")
227+
224228
return vars_[val]
225229

226230
if len(self.expression) == 2:
227-
oper = self.expression[0]
231+
oper = FN(self.expression[0])
228232
assert oper in UNARY
229233
operand = self.expression[1].eval(vars_)
230-
# FIXME
231-
return self.normalize(UNARY[oper](operand)) # type: ignore[index]
234+
return self.normalize(UNARY[oper](operand))
232235

233236
if len(self.expression) == 3 and self.expression[1] != FN.OP_COMMA:
234-
assert self.expression[1] in BINARY
237+
oper = FN(self.expression[1])
238+
assert oper in BINARY
235239
# Do lazy evaluation
236240
left_ = lambda: self.expression[0].eval(vars_)
237241
right_ = lambda: self.expression[2].eval(vars_)
238-
# FIXME
239-
return self.normalize(BINARY[self.expression[1]](left_, right_)) # type: ignore[index]
242+
return self.normalize(BINARY[oper](left_, right_))
240243

241244
# It's a list
242245
return [x.eval(vars_) for i, x in enumerate(self.expression) if not i % 2]

src/arch/z80/peephole/parser.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
TreeType = list[str | list["TreeType"]]
1212

1313
COMMENT: Final[str] = ";;"
14-
RE_REGION = re.compile(r"([_a-zA-Z][a-zA-Z0-9]*)[ \t]*{{")
14+
RE_REGION = re.compile(r"([_a-zA-Z][a-zA-Z0-9]*)[ \t]*\{\{$")
1515
RE_DEF = re.compile(r"([_a-zA-Z][a-zA-Z0-9]*)[ \t]*:[ \t]*(.*)")
1616
RE_IFPARSE = re.compile(r'"(""|[^"])*"|[(),]|\b[_a-zA-Z]+\b|[^," \t()]+')
1717
RE_ID = re.compile(r"\b[_a-zA-Z]+\b")
@@ -152,11 +152,15 @@ def parse_ifline(if_line: str, lineno: int) -> TreeType | None:
152152
if not isinstance(op, str) or op not in IF_OPERATORS:
153153
errmsg.warning(lineno, f"Unexpected binary operator '{op}'")
154154
return None
155-
# FIXME
156-
if isinstance(left_, list) and len(left_) == 3 and IF_OPERATORS[left_[-2]] > IF_OPERATORS[op]: # type: ignore[index]
157-
expr = [[left_[:-2], left_[-2], [left_[-1], op, right_]]] # Rebalance tree
158-
else:
159-
expr = [expr]
155+
156+
oper = FN(op)
157+
if isinstance(left_, list) and len(left_) == 3:
158+
oper2 = FN(left_[-2])
159+
if IF_OPERATORS[oper2] > IF_OPERATORS[oper]:
160+
expr = [[left_[:-2], left_[-2], [left_[-1], op, right_]]] # Rebalance tree
161+
continue
162+
163+
expr = [expr]
160164

161165
if not error_ and paren:
162166
errmsg.warning(lineno, "unclosed parenthesis in IF section")

tests/arch/zx48k/peephole/test_parser.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,46 @@ def test_in_list(self):
355355
"WITH": ["pop $1", "$2"],
356356
"DEFINE": [],
357357
}
358+
359+
def test_parse_cond(self):
360+
result = parser.parse_str(
361+
"""
362+
OLEVEL: 1
363+
OFLAG: 14
364+
REPLACE {{
365+
$1
366+
}}
367+
368+
WITH {{
369+
}}
370+
371+
IF {{
372+
$1 == "nop"
373+
}}
374+
"""
375+
)
376+
assert result == {
377+
"OLEVEL": 1,
378+
"OFLAG": 14,
379+
"REPLACE": ["$1"],
380+
"WITH": [],
381+
"DEFINE": [],
382+
"IF": ["$1", "==", "nop"],
383+
}
384+
385+
def test_parse_if_must_start_in_a_new_line(self):
386+
result = parser.parse_str(
387+
"""
388+
OLEVEL: 1
389+
OFLAG: 14
390+
REPLACE {{
391+
$1
392+
}}
393+
394+
WITH {{
395+
}}
396+
;; this is not valid
397+
IF {{ $1 == "nop" }}
398+
"""
399+
)
400+
assert result is None

0 commit comments

Comments
 (0)