<commit_before>import re
from copy import copy
from enum import Enum, auto
from typing import Optional

from gilgamesh.errors import GilgameshError

M_BIT = 5
X_BIT = 4


class State:
    def __init__(self, p=0b0011_0000, m: Optional[int] = None, x: Optional[int] = None):
        # State can be specified by either passing a P integer value,
        # or individual M & X values to specify A and X/Y sizes.
        if (m is None) and (x is None):
            self.p = p
        else:
            assert (m is not None) and (x is not None)
            self.p = m << M_BIT
            self.p |= x << X_BIT

    @classmethod
    def from_expr(cls, expr: str) -> "State":
        # TODO: Write tests for this.
        if not (
            re.match(r"m=(0|1),x=(0|1)", expr) or re.match(r"x=(0|1),m=(0|1)", expr)
        ):
            raise GilgameshError("Unknown syntax.")

        expressions = expr.split(",")
        return cls(
            **{
                str(register): int(value)
                for register, value in (e.split("=") for e in expressions)
            }
        )

    def __str__(self) -> str:
        return f"m={self.m},x={self.x}"

    def __repr__(self) -> str:
        return f"<State: {self}>"

    def __eq__(self, other) -> bool:
        return self.p == other.p

    def __hash__(self) -> int:
        return hash(self.p)

    @property
    def m(self) -> int:
        return (self.p >> M_BIT) & 1

    @m.setter
    def m(self, m: int) -> None:
        if m:
            self.set(1 << M_BIT)
        else:
            self.reset(1 << M_BIT)

    @property
    def x(self) -> int:
        return (self.p >> X_BIT) & 1

    @x.setter
    def x(self, x: int) -> None:
        if x:
            self.set(1 << X_BIT)
        else:
            self.reset(1 << X_BIT)

    @property
    def a_size(self) -> int:
        return 1 if self.m else 2

    @property
    def x_size(self) -> int:
        return 1 if self.x else 2

    def set(self, p: int) -> None:
        p &= (1 << M_BIT) | (1 << X_BIT)
        self.p |= p

    def reset(self, p: int) -> None:
        p &= (1 << M_BIT) | (1 << X_BIT)
        p = ~p & 0xFF
        self.p &= p


class UnknownReason(Enum):
    KNOWN = auto()
    UNKNOWN = auto()
    RECURSION = auto()
    INDIRECT_JUMP = auto()
    STACK_MANIPULATION = auto()
    SUSPECT_INSTRUCTION = auto()
    MULTIPLE_RETURN_STATES = auto()


class StateChange:
    """Change in processor state caused by the execution of a subroutine."""

    def __init__(
        self,
        m: Optional[int] = None,
        x: Optional[int] = None,
        unknown_reason: Optional[UnknownReason] = None,
    ):
        self.m = m
        self.x = x
        self.unknown_reason = unknown_reason or UnknownReason.KNOWN
        self.asserted = False

    @property
    def unknown(self):
        return self.unknown_reason != UnknownReason.KNOWN

    @classmethod
    def from_expr(cls, expr: str) -> "StateChange":
        # TODO: Validate expression.
        if expr == "none":
            return cls()
        elif expr == "unknown":
            raise NotImplementedError

        expressions = expr.split(",")
        if 1 <= len(expressions) <= 2:
            return cls(
                **{  # type: ignore
                    str(register): int(value)
                    for register, value in (e.split("=") for e in expressions)
                }
            )<commit_msg>Fix bug when parsing unknowns<commit_after>import re
from copy import copy
from enum import Enum, auto
from typing import Optional

from gilgamesh.errors import GilgameshError

M_BIT = 5
X_BIT = 4


class State:
    def __init__(self, p=0b0011_0000, m: Optional[int] = None, x: Optional[int] = None):
        # State can be specified by either passing a P integer value,
        # or individual M & X values to specify A and X/Y sizes.
        if (m is None) and (x is None):
            self.p = p
        else:
            assert (m is not None) and (x is not None)
            self.p = m << M_BIT
            self.p |= x << X_BIT

    @classmethod
    def from_expr(cls, expr: str) -> "State":
        # TODO: Write tests for this.
        if not (
            re.match(r"m=(0|1),x=(0|1)", expr) or re.match(r"x=(0|1),m=(0|1)", expr)
        ):
            raise GilgameshError("Unknown syntax.")

        expressions = expr.split(",")
        return cls(
            **{
                str(register): int(value)
                for register, value in (e.split("=") for e in expressions)
            }
        )

    def __str__(self) -> str:
        return f"m={self.m},x={self.x}"

    def __repr__(self) -> str:
        return f"<State: {self}>"

    def __eq__(self, other) -> bool:
        return self.p == other.p

    def __hash__(self) -> int:
        return hash(self.p)

    @property
    def m(self) -> int:
        return (self.p >> M_BIT) & 1

    @m.setter
    def m(self, m: int) -> None:
        if m:
            self.set(1 << M_BIT)
        else:
            self.reset(1 << M_BIT)

    @property
    def x(self) -> int:
        return (self.p >> X_BIT) & 1

    @x.setter
    def x(self, x: int) -> None:
        if x:
            self.set(1 << X_BIT)
        else:
            self.reset(1 << X_BIT)

    @property
    def a_size(self) -> int:
        return 1 if self.m else 2

    @property
    def x_size(self) -> int:
        return 1 if self.x else 2

    def set(self, p: int) -> None:
        p &= (1 << M_BIT) | (1 << X_BIT)
        self.p |= p

    def reset(self, p: int) -> None:
        p &= (1 << M_BIT) | (1 << X_BIT)
        p = ~p & 0xFF
        self.p &= p


class UnknownReason(Enum):
    KNOWN = auto()
    UNKNOWN = auto()
    RECURSION = auto()
    INDIRECT_JUMP = auto()
    STACK_MANIPULATION = auto()
    SUSPECT_INSTRUCTION = auto()
    MULTIPLE_RETURN_STATES = auto()


class StateChange:
    """Change in processor state caused by the execution of a subroutine."""

    def __init__(
        self,
        m: Optional[int] = None,
        x: Optional[int] = None,
        unknown_reason: Optional[UnknownReason] = None,
    ):
        self.m = m
        self.x = x
        self.unknown_reason = unknown_reason or UnknownReason.KNOWN
        self.asserted = False

    @property
    def unknown(self):
        return self.unknown_reason != UnknownReason.KNOWN

    @classmethod
    def from_expr(cls, expr: str) -> "StateChange":
        # TODO: Validate expression.
        if expr == "none":
            return cls()
        elif expr == "unknown":
            return cls(unknown_reason=UnknownReason.UNKNOWN)

        expressions = expr.split(",")
        if 1 <= len(expressions) <= 2:
            return cls(
                **{  # type: ignore
                    str(register): int(value)
                    for register, value in (e.split("=") for e in expressions)
                }
            )
{'fraction_non_alphanumeric': 0.1251273097628401, 'fraction_numerical': 0.010475774770842427, 'mean_word_length': 1.7386454183266933, 'pattern_counts': {'":': 8, '<': 49, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '625662', 'n_tokens_mistral': 2278, 'n_tokens_neox': 2185, 'n_words': 660}