001package jmri.jmrit.logixng.util.parser; 002 003import jmri.JmriException; 004import jmri.jmrit.logixng.SymbolTable; 005 006/** 007 * A parsed expression 008 */ 009public class ExpressionNodeComparingOperator implements ExpressionNode { 010 011 private final TokenType _tokenType; 012 private final ExpressionNode _leftSide; 013 private final ExpressionNode _rightSide; 014 015 public ExpressionNodeComparingOperator(TokenType tokenType, ExpressionNode leftSide, ExpressionNode rightSide) { 016 _tokenType = tokenType; 017 _leftSide = leftSide; 018 _rightSide = rightSide; 019 020 if (_leftSide == null) { 021 throw new IllegalArgumentException("leftSide must not be null"); 022 } 023 if (_rightSide == null) { 024 throw new IllegalArgumentException("rightSide must not be null"); 025 } 026 027 // Verify that the token is of the correct type 028 switch (_tokenType) { 029 case EQUAL: 030 case NOT_EQUAL: 031 case LESS_THAN: 032 case LESS_OR_EQUAL: 033 case GREATER_THAN: 034 case GREATER_OR_EQUAL: 035 break; 036 037 default: 038 throw new RuntimeException("Unknown comparing operator: "+_tokenType.name()); 039 } 040 } 041 042 public Object calculateNull(Object left, Object right) throws JmriException { 043 if ((left != null) && (right != null)) { 044 throw new RuntimeException("This method is only valid if left and/or right is null"); 045 } 046 047 switch (_tokenType) { 048 case EQUAL: 049 return left == right; 050 case NOT_EQUAL: 051 return left != right; 052 case LESS_THAN: 053 return (left == null) && (right != null); 054 case LESS_OR_EQUAL: 055 return left == null; 056 case GREATER_THAN: 057 return (left != null) && (right == null); 058 case GREATER_OR_EQUAL: 059 return right == null; 060 061 default: 062 throw new RuntimeException("Unknown arithmetic operator: "+_tokenType.name()); 063 } 064 } 065 066 @Override 067 public Object calculate(SymbolTable symbolTable) throws JmriException { 068 Object left = _leftSide.calculate(symbolTable); 069 Object right = _rightSide.calculate(symbolTable); 070 071 if ((left == null) || (right == null)) return calculateNull(left, right); 072 073 // Convert a boolean value to an integer value. false = 0 and true = 1. 074 if (left instanceof Boolean) { 075 left = ((Boolean)left) ? 1 : 0; 076 } 077 if (right instanceof Boolean) { 078 right = ((Boolean)right) ? 1 : 0; 079 } 080 081 // If the operands are not numbers, ensure that they are strings 082 if ((!(left instanceof Number)) && (!(left instanceof String))) { 083 left = left.toString(); 084 } 085 if ((!(right instanceof Number)) && (!(right instanceof String))) { 086 right = right.toString(); 087 } 088 089 // Object.toString() might return null 090 if ((left == null) || (right == null)) return calculateNull(left, right); 091 092 // A number is always less than a String. If one operand is a number 093 // and the other operand is a String, we can change the operands to 094 // two integers to make the check easier. 095 if ((left instanceof Number) && (!(right instanceof Number))) { 096 left = 1; 097 right = 2; 098 } else if (!(left instanceof Number) && ((right instanceof Number))) { 099 left = 2; 100 right = 1; 101 } 102 103 if ((left instanceof Double) && (!(right instanceof Double))) { 104 right = ((Number)left).doubleValue(); 105 } 106 if ((right instanceof Double) && (!(left instanceof Double))) { 107 left = ((Number)left).doubleValue(); 108 } 109 110 if ((left instanceof Long) && (!(right instanceof Long))) { 111 right = ((Number)right).longValue(); 112 } 113 if ((right instanceof Long) && (!(left instanceof Long))) { 114 left = ((Number)left).longValue(); 115 } 116 117 if (left instanceof Number) { 118 switch (_tokenType) { 119 case EQUAL: 120 return left.equals(right); 121 case NOT_EQUAL: 122 return ! left.equals(right); 123 case LESS_THAN: 124 return ((Number) left).doubleValue() < ((Number) right).doubleValue(); 125 case LESS_OR_EQUAL: 126 return ((Number) left).doubleValue() <= ((Number) right).doubleValue(); 127 case GREATER_THAN: 128 return ((Number) left).doubleValue() > ((Number) right).doubleValue(); 129 case GREATER_OR_EQUAL: 130 return ((Number) left).doubleValue() >= ((Number) right).doubleValue(); 131 132 default: 133 throw new RuntimeException("Unknown arithmetic operator: "+_tokenType.name()); 134 } 135 } else { 136 switch (_tokenType) { 137 case EQUAL: 138 return left.equals(right); 139 case NOT_EQUAL: 140 return ! left.equals(right); 141 case LESS_THAN: 142 return ((String)left).compareTo(((String)right)) < 0; 143 case LESS_OR_EQUAL: 144 return ((String)left).compareTo(((String)right)) <= 0; 145 case GREATER_THAN: 146 return ((String)left).compareTo(((String)right)) > 0; 147 case GREATER_OR_EQUAL: 148 return ((String)left).compareTo(((String)right)) >= 0; 149 150 default: 151 throw new RuntimeException("Unknown comparing operator: "+_tokenType.name()); 152 } 153 } 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 public String getDefinitionString() { 159 String operStr; 160 switch (_tokenType) { 161 case EQUAL: 162 operStr = "=="; 163 break; 164 165 case NOT_EQUAL: 166 operStr = "!="; 167 break; 168 169 case LESS_THAN: 170 operStr = "<"; 171 break; 172 173 case LESS_OR_EQUAL: 174 operStr = "<="; 175 break; 176 177 case GREATER_THAN: 178 operStr = ">"; 179 break; 180 181 case GREATER_OR_EQUAL: 182 operStr = ">="; 183 break; 184 185 default: 186 throw new RuntimeException("Unknown comparing operator: "+_tokenType.name()); 187 } 188 return "("+_leftSide.getDefinitionString()+")" + operStr + "("+_rightSide.getDefinitionString()+")"; 189 } 190 191}