001package jmri.jmrit.logixng.util.parser; 002 003import jmri.JmriException; 004import jmri.jmrit.logixng.SymbolTable; 005import jmri.util.TypeConversionUtil; 006 007/** 008 * A parsed expression 009 */ 010public class ExpressionNodeBooleanOperator implements ExpressionNode { 011 012 private final TokenType _tokenType; 013 private final ExpressionNode _leftSide; 014 private final ExpressionNode _rightSide; 015 016 public ExpressionNodeBooleanOperator(TokenType tokenType, ExpressionNode leftSide, ExpressionNode rightSide) { 017 _tokenType = tokenType; 018 _leftSide = leftSide; 019 _rightSide = rightSide; 020 021 if (_rightSide == null) { 022 throw new IllegalArgumentException("rightSide must not be null"); 023 } 024 025 // Verify that the token is of the correct type 026 switch (_tokenType) { 027 case BOOLEAN_OR: 028 case BOOLEAN_XOR: 029 case BOOLEAN_AND: 030 if (_leftSide == null) { 031 throw new IllegalArgumentException("leftSide must not be null for operators AND, OR and XOR"); 032 } 033 break; 034 035 case BOOLEAN_NOT: 036 if (_leftSide != null) { 037 throw new IllegalArgumentException("leftSide must be null for operator NOT"); 038 } 039 break; 040 041 default: 042 throw new IllegalArgumentException("Unsupported boolean operator: "+_tokenType.name()); 043 } 044 } 045 046 @Override 047 public Object calculate(SymbolTable symbolTable) throws JmriException { 048 049 boolean left = false; 050 if (_tokenType != TokenType.BOOLEAN_NOT) { 051 // Left value must be calculated _before_ right value is calculated. 052 // When a value is calculated, a method might be called, and the 053 // order of these calls must be correct. 054 // For example, if myArray is an array, the formula might be: 055 // myArray.add("Hello") && myArray.add(" ") && myArray.add("World!") 056 Object leftValue = _leftSide.calculate(symbolTable); 057 if (leftValue == null) leftValue = false; 058 059 if (!(leftValue instanceof Boolean)) { 060 if (TypeConversionUtil.isIntegerNumber(leftValue)) { 061 // Convert to true or false 062 leftValue = ((Number)leftValue).longValue() != 0; 063 } else { 064 throw new CalculateException(Bundle.getMessage("ArithmeticNotBooleanOrIntegerNumberError", leftValue)); 065 } 066 } 067 068 left = (Boolean)leftValue; 069 070 // The operators && and || only calculate the right value if 071 // the left value doesn't decide the result. 072 if ((_tokenType == TokenType.BOOLEAN_AND) && !left) { 073 return false; 074 } 075 if ((_tokenType == TokenType.BOOLEAN_OR) && left) { 076 return true; 077 } 078 } 079 080 Object rightValue = _rightSide.calculate(symbolTable); 081 if (rightValue == null) rightValue = false; 082 083 if (!(rightValue instanceof Boolean)) { 084 if (TypeConversionUtil.isIntegerNumber(rightValue)) { 085 // Convert to true or false 086 rightValue = ((Number)rightValue).longValue() != 0; 087 } else { 088 throw new CalculateException(Bundle.getMessage("ArithmeticNotBooleanOrIntegerNumberError", rightValue)); 089 } 090 } 091 boolean right = (Boolean)rightValue; 092 093 if (_tokenType == TokenType.BOOLEAN_NOT) { 094 return ! right; 095 } 096 097 switch (_tokenType) { 098 case BOOLEAN_OR: 099 return left || right; 100 101 case BOOLEAN_XOR: 102 return (left && !right) || (!left && right); 103 104 case BOOLEAN_AND: 105 return left && right; 106 107 default: 108 throw new CalculateException("Unknown boolean operator: "+_tokenType.name()); 109 } 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 public String getDefinitionString() { 115 String operStr; 116 switch (_tokenType) { 117 case BOOLEAN_OR: 118 operStr = "||"; 119 break; 120 121 case BOOLEAN_XOR: 122 operStr = "^^"; 123 break; 124 125 case BOOLEAN_AND: 126 operStr = "&&"; 127 break; 128 129 case BOOLEAN_NOT: 130 operStr = "!"; 131 break; 132 133 default: 134 throw new UnsupportedOperationException("Unknown arithmetic operator: "+_tokenType.name()); 135 } 136 if (_leftSide != null) { 137 return "("+_leftSide.getDefinitionString()+")" + operStr + "("+_rightSide.getDefinitionString()+")"; 138 } else { 139 return operStr + "("+_rightSide.getDefinitionString()+")"; 140 } 141 } 142 143}