Skip to content

Commit

Permalink
Merge pull request #909 from boriel-basic/fix/fix_peephole_opt_recipe…
Browse files Browse the repository at this point in the history
…_parser

Fix/fix peephole opt recipe parser
  • Loading branch information
boriel authored Nov 24, 2024
2 parents 9536b5b + cb218d7 commit 7ee2f02
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 14 deletions.
19 changes: 11 additions & 8 deletions src/arch/z80/peephole/evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import re
from collections.abc import Callable
from enum import Enum, unique
from enum import StrEnum, unique
from typing import Any

from src.api import utils
Expand All @@ -13,7 +13,7 @@


@unique
class FN(str, Enum):
class FN(StrEnum):
OP_NOT = "!"
OP_PLUS = "+"
OP_EQ = "=="
Expand Down Expand Up @@ -215,28 +215,31 @@ def eval(self, vars_: dict[str, Any] | None = None) -> str | Evaluator | list[An
val = self.expression[0]
if not isinstance(val, str):
return val

if val == "$":
return val

if not RE_SVAR.match(val):
return val

if val not in vars_:
raise UnboundVarError(f"Unbound variable '{val}'")

return vars_[val]

if len(self.expression) == 2:
oper = self.expression[0]
oper = FN(self.expression[0])
assert oper in UNARY
operand = self.expression[1].eval(vars_)
# FIXME
return self.normalize(UNARY[oper](operand)) # type: ignore[index]
return self.normalize(UNARY[oper](operand))

if len(self.expression) == 3 and self.expression[1] != FN.OP_COMMA:
assert self.expression[1] in BINARY
oper = FN(self.expression[1])
assert oper in BINARY
# Do lazy evaluation
left_ = lambda: self.expression[0].eval(vars_)
right_ = lambda: self.expression[2].eval(vars_)
# FIXME
return self.normalize(BINARY[self.expression[1]](left_, right_)) # type: ignore[index]
return self.normalize(BINARY[oper](left_, right_))

# It's a list
return [x.eval(vars_) for i, x in enumerate(self.expression) if not i % 2]
Expand Down
16 changes: 10 additions & 6 deletions src/arch/z80/peephole/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
TreeType = list[str | list["TreeType"]]

COMMENT: Final[str] = ";;"
RE_REGION = re.compile(r"([_a-zA-Z][a-zA-Z0-9]*)[ \t]*{{")
RE_REGION = re.compile(r"([_a-zA-Z][a-zA-Z0-9]*)[ \t]*\{\{$")
RE_DEF = re.compile(r"([_a-zA-Z][a-zA-Z0-9]*)[ \t]*:[ \t]*(.*)")
RE_IFPARSE = re.compile(r'"(""|[^"])*"|[(),]|\b[_a-zA-Z]+\b|[^," \t()]+')
RE_ID = re.compile(r"\b[_a-zA-Z]+\b")
Expand Down Expand Up @@ -152,11 +152,15 @@ def parse_ifline(if_line: str, lineno: int) -> TreeType | None:
if not isinstance(op, str) or op not in IF_OPERATORS:
errmsg.warning(lineno, f"Unexpected binary operator '{op}'")
return None
# FIXME
if isinstance(left_, list) and len(left_) == 3 and IF_OPERATORS[left_[-2]] > IF_OPERATORS[op]: # type: ignore[index]
expr = [[left_[:-2], left_[-2], [left_[-1], op, right_]]] # Rebalance tree
else:
expr = [expr]

oper = FN(op)
if isinstance(left_, list) and len(left_) == 3:
oper2 = FN(left_[-2])
if IF_OPERATORS[oper2] > IF_OPERATORS[oper]:
expr = [[left_[:-2], left_[-2], [left_[-1], op, right_]]] # Rebalance tree
continue

expr = [expr]

if not error_ and paren:
errmsg.warning(lineno, "unclosed parenthesis in IF section")
Expand Down
43 changes: 43 additions & 0 deletions tests/arch/zx48k/peephole/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,46 @@ def test_in_list(self):
"WITH": ["pop $1", "$2"],
"DEFINE": [],
}

def test_parse_cond(self):
result = parser.parse_str(
"""
OLEVEL: 1
OFLAG: 14
REPLACE {{
$1
}}
WITH {{
}}
IF {{
$1 == "nop"
}}
"""
)
assert result == {
"OLEVEL": 1,
"OFLAG": 14,
"REPLACE": ["$1"],
"WITH": [],
"DEFINE": [],
"IF": ["$1", "==", "nop"],
}

def test_parse_if_must_start_in_a_new_line(self):
result = parser.parse_str(
"""
OLEVEL: 1
OFLAG: 14
REPLACE {{
$1
}}
WITH {{
}}
;; this is not valid
IF {{ $1 == "nop" }}
"""
)
assert result is None

0 comments on commit 7ee2f02

Please sign in to comment.