public List < AbstractExpression > bindingToIndexedExpression ( AbstractExpression expr ) { // Defer the result construction for as long as possible on the // assumption that this function mostly gets applied to eliminate // negative cases. if ( m_type != expr . m_type ) { // The only allowed difference in expression types is between a // parameter and its original constant value. // That's handled in the independent override. return null ; } // From here, this is much like the straight equality check, // except that this function and "equals" must each call themselves // in their recursions. // Delegating to this factored-out component of the "equals" // implementation eases simultaneous refinement of both methods. if ( ! hasEqualAttributes ( expr ) ) { return null ; } // The derived classes have verified that any added attributes // are identical. // Check that the presence, or lack, of children is the same if ( ( expr . m_left == null ) != ( m_left == null ) ) { return null ; } if ( ( expr . m_right == null ) != ( m_right == null ) ) { return null ; } if ( ( expr . m_args == null ) != ( m_args == null ) ) { return null ; } // Check that the children identify themselves as matching List < AbstractExpression > leftBindings = null ; if ( m_left != null ) { leftBindings = m_left . bindingToIndexedExpression ( expr . m_left ) ; if ( leftBindings == null ) { return null ; } } List < AbstractExpression > rightBindings = null ; if ( m_right != null ) { rightBindings = m_right . bindingToIndexedExpression ( expr . m_right ) ; if ( rightBindings == null ) { return null ; } } List < AbstractExpression > argBindings = null ; if ( m_args != null ) { if ( m_args . size ( ) != expr . m_args . size ( ) ) { return null ; } argBindings = new ArrayList <> ( ) ; int ii = 0 ; // iterate the args lists in parallel, binding pairwise for ( AbstractExpression rhs : expr . m_args ) { AbstractExpression lhs = m_args . get ( ii ++ ) ; List < AbstractExpression > moreBindings = lhs . bindingToIndexedExpression ( rhs ) ; if ( moreBindings == null ) { // fail on any non-match return null ; } argBindings . addAll ( moreBindings ) ; } } // It's a match, so gather up the details. // It's rare (if even possible) for the same bound parameter to get // listed twice, so don't worry about duplicate entries, here. // That should not cause any issue for the caller. List < AbstractExpression > result = new ArrayList <> ( ) ; if ( leftBindings != null ) { // null here can only mean no left child result . addAll ( leftBindings ) ; } if ( rightBindings != null ) { // null here can only mean no right child result . addAll ( rightBindings ) ; } if ( argBindings != null ) { // null here can only mean no args result . addAll ( argBindings ) ; } return result ; }
strict expression equality that didn t involve parameters .