#!/usr/bin/env python3.9 # -*- coding: utf-8 -*- """ JFinal Arith - Arithmetic Expression """ from .Expr import Expr from decimal import Decimal, ROUND_HALF_UP class Arith(Expr): """Arithmetic expression""" ADD = "+" SUB = "-" MUL = "*" DIV = "/" MOD = "%" _rounding_mode = ROUND_HALF_UP def __init__(self, left: Expr, operator: str, right: Expr): """ Initialize arithmetic expression Args: left: Left expression operator: Arithmetic operator right: Right expression """ self._left = left self._operator = operator self._right = right def eval(self, scope): """Evaluate arithmetic expression""" left_val = self._left.eval(scope) right_val = self._right.eval(scope) # Handle None values if left_val is None or right_val is None: return None # Convert to appropriate numeric types left_num = self._to_number(left_val) right_num = self._to_number(right_val) if left_num is None or right_num is None: return None # Perform operation if self._operator == Arith.ADD: return left_num + right_num elif self._operator == Arith.SUB: return left_num - right_num elif self._operator == Arith.MUL: return left_num * right_num elif self._operator == Arith.DIV: if right_num == 0: raise ZeroDivisionError("Division by zero") return self._divide(left_num, right_num) elif self._operator == Arith.MOD: return left_num % right_num else: raise ValueError(f"Unknown operator: {self._operator}") def _to_number(self, value): """Convert value to number""" if isinstance(value, (int, float)): return value if isinstance(value, Decimal): return value if isinstance(value, str): try: if '.' in value: return float(value) else: return int(value) except ValueError: return None return None def _divide(self, left, right): """Handle division with proper rounding""" if isinstance(left, Decimal) or isinstance(right, Decimal): result = Decimal(str(left)) / Decimal(str(right)) return result.quantize(Decimal('0.00000001'), rounding=self._rounding_mode) else: return left / right @classmethod def set_big_decimal_divide_rounding_mode(cls, rounding_mode): """Set rounding mode for decimal division""" cls._rounding_mode = rounding_mode def __repr__(self) -> str: return f"Arith({self._left} {self._operator} {self._right})" class Unary(Expr): """Unary expression (positive, negative, increment, decrement)""" POSITIVE = "+" NEGATIVE = "-" NOT = "!" def __init__(self, operator: str, expr: Expr): """ Initialize unary expression Args: operator: Unary operator expr: Expression to operate on """ self._operator = operator self._expr = expr def eval(self, scope): """Evaluate unary expression""" val = self._expr.eval(scope) if self._operator == Unary.POSITIVE: return +val if isinstance(val, (int, float)) else val elif self._operator == Unary.NEGATIVE: return -val if isinstance(val, (int, float)) else val elif self._operator == Unary.NOT: return not val else: raise ValueError(f"Unknown operator: {self._operator}") def __repr__(self) -> str: return f"Unary({self._operator}{self._expr})" class IncDec(Expr): """Increment/Decrement expression""" INC = "++" DEC = "--" def __init__(self, expr: Expr, operator: str, is_prefix: bool = True): """ Initialize increment/decrement Args: expr: Expression to increment/decrement operator: INC or DEC is_prefix: Whether this is prefix (++x) or postfix (x++) """ self._expr = expr self._operator = operator self._is_prefix = is_prefix def eval(self, scope): """Evaluate increment/decrement""" # This is a simplified implementation # In a real implementation, this would modify the variable current_val = self._expr.eval(scope) if isinstance(current_val, int): if self._operator == IncDec.INC: return current_val + 1 else: return current_val - 1 return current_val def __repr__(self) -> str: op_str = self._operator if self._is_prefix: return f"IncDec({op_str}{self._expr})" else: return f"IncDec({self._expr}{op_str})"