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 ExpressionNodeBinaryOperator implements ExpressionNode { 011 012 private final TokenType _tokenType; 013 private final ExpressionNode _leftSide; 014 private final ExpressionNode _rightSide; 015 016 public ExpressionNodeBinaryOperator(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 BINARY_OR: 028 case BINARY_XOR: 029 case BINARY_AND: 030 if (_leftSide == null) { 031 throw new IllegalArgumentException("leftSide must not be null for operators BINARY AND, BINARY OR and BINARY XOR"); 032 } 033 break; 034 035 case BINARY_NOT: 036 if (_leftSide != null) { 037 throw new IllegalArgumentException("leftSide must be null for operator BINARY NOT"); 038 } 039 break; 040 041 default: 042 throw new IllegalArgumentException("Unsupported binary operator: "+_tokenType.name()); 043 } 044 } 045 046 @Override 047 public Object calculate(SymbolTable symbolTable) throws JmriException { 048 049 Object leftValue = null; 050 if (_tokenType != TokenType.BINARY_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 leftValue = _leftSide.calculate(symbolTable); 055 } 056 if (leftValue == null) leftValue = false; 057 058 Object rightValue = _rightSide.calculate(symbolTable); 059 if (rightValue == null) rightValue = false; 060 061 if (!TypeConversionUtil.isIntegerNumber(rightValue)) { 062 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", rightValue)); 063 } 064 long right = TypeConversionUtil.convertToLong(rightValue); 065 066 if (_tokenType == TokenType.BINARY_NOT) { 067 return ~ right; 068 } 069 070 if (!TypeConversionUtil.isIntegerNumber(leftValue)) { 071 throw new CalculateException(Bundle.getMessage("ArithmeticNotIntegerNumberError", leftValue)); 072 } 073 long left = TypeConversionUtil.convertToLong(leftValue); 074 075 switch (_tokenType) { 076 case BINARY_OR: 077 return left | right; 078 079 case BINARY_XOR: 080 return left ^ right; 081 082 case BINARY_AND: 083 return left & right; 084 085 default: 086 throw new CalculateException("Unknown binary operator: "+_tokenType.name()); 087 } 088 } 089 090 /** {@inheritDoc} */ 091 @Override 092 public String getDefinitionString() { 093 String operStr; 094 switch (_tokenType) { 095 case BINARY_OR: 096 operStr = "|"; 097 break; 098 099 case BINARY_XOR: 100 operStr = "^"; 101 break; 102 103 case BINARY_AND: 104 operStr = "&"; 105 break; 106 107 case BINARY_NOT: 108 operStr = "~"; 109 break; 110 111 default: 112 throw new UnsupportedOperationException("Unknown arithmetic operator: "+_tokenType.name()); 113 } 114 if (_leftSide != null) { 115 return "("+_leftSide.getDefinitionString()+")" + operStr + "("+_rightSide.getDefinitionString()+")"; 116 } else { 117 return operStr + "("+_rightSide.getDefinitionString()+")"; 118 } 119 } 120 121}