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 ExpressionNodeAssignmentOperator implements ExpressionNode { 011 012 private final TokenType _tokenType; 013 private final ExpressionNode _leftSide; 014 private final ExpressionNode _rightSide; 015 016 017 public ExpressionNodeAssignmentOperator(TokenType tokenType, ExpressionNode leftSide, ExpressionNode rightSide) { 018 _tokenType = tokenType; 019 _leftSide = leftSide; 020 _rightSide = rightSide; 021 022 if (_leftSide == null) { 023 throw new IllegalArgumentException("leftSide must not be null"); 024 } 025 026 if (! _leftSide.canBeAssigned()) { 027 throw new IllegalArgumentException("leftSide must assignable"); 028 } 029 030 // Verify that the token is of the correct type 031 switch (_tokenType) { 032 case ASSIGN: 033 case ASSIGN_ADD: 034 case ASSIGN_SUBTRACKT: 035 break; 036 037 case ASSIGN_MULTIPLY: 038 case ASSIGN_DIVIDE: 039 case ASSIGN_MODULO: 040 case ASSIGN_AND: 041 case ASSIGN_OR: 042 case ASSIGN_XOR: 043 case ASSIGN_SHIFT_LEFT: 044 case ASSIGN_SHIFT_RIGHT: 045 case ASSIGN_UNSIGNED_SHIFT_RIGHT: 046 if (_leftSide == null) { 047 throw new IllegalArgumentException("leftSide must not be null for operators *, /, %, <<, >>, >>>"); 048 } 049 break; 050 051 default: 052 throw new IllegalArgumentException("Unknown arithmetic operator: "+_tokenType.name()); 053 } 054 } 055 056 057 private Object add(Object left, Object right) throws CalculateException { 058 if (TypeConversionUtil.isIntegerNumber(left) 059 && TypeConversionUtil.isIntegerNumber(right)) { 060 return ((Number)left).longValue() + ((Number)right).longValue(); 061 062 } else if (TypeConversionUtil.isFloatingNumber(left) 063 && TypeConversionUtil.isFloatingNumber(right)) { 064 return ((Number)left).doubleValue() + ((Number)right).doubleValue(); 065 066 } else { 067 if (TypeConversionUtil.isString(left) && TypeConversionUtil.isString(right)) { 068 return ((String)left) + ((String)right); 069 } else { 070 throw new CalculateException(Bundle.getMessage("ArithmeticNotCompatibleOperands", left, right)); 071 } 072 } 073 } 074 075 076 private Object subtract(Object left, Object right) throws CalculateException { 077 if (TypeConversionUtil.isIntegerNumber(left)) { 078 if (TypeConversionUtil.isIntegerNumber(right)) { 079 return ((Number)left).longValue() - ((Number)right).longValue(); 080 } else if (TypeConversionUtil.isFloatingNumber(right)) { 081 return ((Number)left).doubleValue() - ((Number)right).doubleValue(); 082 } else { 083 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", right)); 084 } 085 } else if (TypeConversionUtil.isFloatingNumber(left)) { 086 if (TypeConversionUtil.isFloatingNumber(right)) { 087 return ((Number)left).doubleValue() - ((Number)right).doubleValue(); 088 } else { 089 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", right)); 090 } 091 } else { 092 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", left)); 093 } 094 } 095 096 097 private Object multiply(Object left, Object right) throws CalculateException { 098 if (TypeConversionUtil.isIntegerNumber(left)) { 099 if (TypeConversionUtil.isIntegerNumber(right)) { 100 return ((Number)left).longValue() * ((Number)right).longValue(); 101 } else if (TypeConversionUtil.isFloatingNumber(right)) { 102 return ((Number)left).doubleValue() * ((Number)right).doubleValue(); 103 } else { 104 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", right)); 105 } 106 } else if (TypeConversionUtil.isFloatingNumber(left)) { 107 if (TypeConversionUtil.isFloatingNumber(right)) { 108 return ((Number)left).doubleValue() * ((Number)right).doubleValue(); 109 } else { 110 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", right)); 111 } 112 } else { 113 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", left)); 114 } 115 } 116 117 118 private Object divide(Object left, Object right) throws CalculateException { 119 if (TypeConversionUtil.isIntegerNumber(left)) { 120 if (TypeConversionUtil.isIntegerNumber(right)) { 121 return ((Number)left).longValue() / ((Number)right).longValue(); 122 } else if (TypeConversionUtil.isFloatingNumber(right)) { 123 return ((Number)left).doubleValue() / ((Number)right).doubleValue(); 124 } else { 125 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", right)); 126 } 127 } else if (TypeConversionUtil.isFloatingNumber(left)) { 128 if (TypeConversionUtil.isFloatingNumber(right)) { 129 return ((Number)left).doubleValue() / ((Number)right).doubleValue(); 130 } else { 131 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", right)); 132 } 133 } else { 134 throw new CalculateException(Bundle.getMessage("ArithmeticNotNumberError", left)); 135 } 136 } 137 138 139 private Object modulo(Object left, Object right) throws CalculateException { 140 if (TypeConversionUtil.isIntegerNumber(left)) { 141 if (TypeConversionUtil.isIntegerNumber(right)) { 142 return ((Number)left).longValue() % ((Number)right).longValue(); 143 } else { 144 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", right)); 145 } 146 } else { 147 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", left)); 148 } 149 } 150 151 152 private Object and(Object left, Object right) throws CalculateException { 153 if (TypeConversionUtil.isIntegerNumber(left)) { 154 if (TypeConversionUtil.isIntegerNumber(right)) { 155 return ((Number)left).longValue() & ((Number)right).longValue(); 156 } else { 157 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", right)); 158 } 159 } else { 160 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", left)); 161 } 162 } 163 164 165 private Object or(Object left, Object right) throws CalculateException { 166 if (TypeConversionUtil.isIntegerNumber(left)) { 167 if (TypeConversionUtil.isIntegerNumber(right)) { 168 return ((Number)left).longValue() | ((Number)right).longValue(); 169 } else { 170 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", right)); 171 } 172 } else { 173 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", left)); 174 } 175 } 176 177 178 private Object xor(Object left, Object right) throws CalculateException { 179 if (TypeConversionUtil.isIntegerNumber(left)) { 180 if (TypeConversionUtil.isIntegerNumber(right)) { 181 return ((Number)left).longValue() ^ ((Number)right).longValue(); 182 } else { 183 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", right)); 184 } 185 } else { 186 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", left)); 187 } 188 } 189 190 191 private Object shiftLeft(Object left, Object right) throws CalculateException { 192 if (TypeConversionUtil.isIntegerNumber(left)) { 193 if (TypeConversionUtil.isIntegerNumber(right)) { 194 return ((Number)left).longValue() << ((Number)right).longValue(); 195 } else { 196 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", right)); 197 } 198 } else { 199 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", left)); 200 } 201 } 202 203 204 private Object shiftRight(Object left, Object right) throws CalculateException { 205 if (TypeConversionUtil.isIntegerNumber(left)) { 206 if (TypeConversionUtil.isIntegerNumber(right)) { 207 return ((Number)left).longValue() >> ((Number)right).longValue(); 208 } else { 209 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", right)); 210 } 211 } else { 212 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", left)); 213 } 214 } 215 216 217 private Object unsignedShiftRight(Object left, Object right) throws CalculateException { 218 if (TypeConversionUtil.isIntegerNumber(left)) { 219 if (TypeConversionUtil.isIntegerNumber(right)) { 220 return ((Number)left).longValue() >>> ((Number)right).longValue(); 221 } else { 222 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", right)); 223 } 224 } else { 225 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", left)); 226 } 227 } 228 229 230 @Override 231 public Object calculate(SymbolTable symbolTable) throws JmriException { 232 233 if (_tokenType == TokenType.ASSIGN) { 234 Object value = _rightSide.calculate(symbolTable); 235 _leftSide.assignValue(symbolTable, value); 236 return value; 237 } 238 239 Object left = _leftSide.calculate(symbolTable); 240 Object right = _rightSide.calculate(symbolTable); 241 242 // Convert a boolean value to an integer value 243 if (left instanceof Boolean) { 244 left = ((Boolean)left) ? 1 : 0; 245 } 246 if (right instanceof Boolean) { 247 right = ((Boolean)right) ? 1 : 0; 248 } 249 250 Object result; 251 252 if (_tokenType == TokenType.ASSIGN_ADD) { 253 // Add can handle String concatenation 254 result = add(left, right); 255 } else { 256 // For the other arithmetic operators, except add, only numbers can 257 // be handled. For other types, return 0. 258 if (! TypeConversionUtil.isFloatingNumber(left)) { 259 result = 0; 260 } else if (! TypeConversionUtil.isFloatingNumber(right)) { 261 result = 0; 262 } else { 263 switch (_tokenType) { 264 case ASSIGN_SUBTRACKT: 265 result = subtract(left, right); 266 break; 267 case ASSIGN_MULTIPLY: 268 result = multiply(left, right); 269 break; 270 case ASSIGN_DIVIDE: 271 result = divide(left, right); 272 break; 273 case ASSIGN_MODULO: 274 result = modulo(left, right); 275 break; 276 case ASSIGN_AND: 277 result = and(left, right); 278 break; 279 case ASSIGN_OR: 280 result = or(left, right); 281 break; 282 case ASSIGN_XOR: 283 result = xor(left, right); 284 break; 285 case ASSIGN_SHIFT_LEFT: 286 result = shiftLeft(left, right); 287 break; 288 case ASSIGN_SHIFT_RIGHT: 289 result = shiftRight(left, right); 290 break; 291 case ASSIGN_UNSIGNED_SHIFT_RIGHT: 292 result = unsignedShiftRight(left, right); 293 break; 294 default: 295 throw new CalculateException("Unknown arithmetic operator: "+_tokenType.name()); 296 } 297 } 298 } 299 300 _leftSide.assignValue(symbolTable, result); 301 return result; 302 } 303 304 305 /** {@inheritDoc} */ 306 @Override 307 public String getDefinitionString() { 308 String operStr; 309 switch (_tokenType) { 310 case ADD: 311 operStr = "+"; 312 break; 313 314 case SUBTRACKT: 315 operStr = "-"; 316 break; 317 318 case MULTIPLY: 319 operStr = "*"; 320 break; 321 322 case DIVIDE: 323 operStr = "/"; 324 break; 325 326 case MODULO: 327 operStr = "%"; 328 break; 329 330 case ASSIGN: 331 operStr = "="; 332 break; 333 334 case ASSIGN_ADD: 335 operStr = "+="; 336 break; 337 338 case ASSIGN_SUBTRACKT: 339 operStr = "-="; 340 break; 341 342 case ASSIGN_MULTIPLY: 343 operStr = "*="; 344 break; 345 346 case ASSIGN_DIVIDE: 347 operStr = "/="; 348 break; 349 350 case ASSIGN_MODULO: 351 operStr = "%="; 352 break; 353 354 case ASSIGN_AND: 355 operStr = "&="; 356 break; 357 358 case ASSIGN_OR: 359 operStr = "|="; 360 break; 361 362 case ASSIGN_XOR: 363 operStr = "^="; 364 break; 365 366 case ASSIGN_SHIFT_LEFT: 367 operStr = "<<="; 368 break; 369 370 case ASSIGN_SHIFT_RIGHT: 371 operStr = ">>="; 372 break; 373 374 case ASSIGN_UNSIGNED_SHIFT_RIGHT: 375 operStr = ">>>="; 376 break; 377 378 default: 379 throw new UnsupportedOperationException("Unknown arithmetic operator: "+_tokenType.name()); 380 } 381 382 String leftSideString = _leftSide != null ? _leftSide.getDefinitionString() : "null"; 383 String rightSideString = _rightSide != null ? _rightSide.getDefinitionString() : "null"; 384 return "("+leftSideString+")" + operStr + "("+rightSideString+")"; 385 } 386 387}