function _exactMatch(p, q) {
    if (p instanceof ConstantNode && q instanceof ConstantNode) {
      if (!equal(p.value, q.value)) {
        return false;
      }
    } else if (p instanceof SymbolNode && q instanceof SymbolNode) {
      if (p.name !== q.name) {
        return false;
      }
    } else if (p instanceof OperatorNode && q instanceof OperatorNode || p instanceof FunctionNode && q instanceof FunctionNode) {
      if (p instanceof OperatorNode) {
        if (p.op !== q.op || p.fn !== q.fn) {
          return false;
        }
      } else if (p instanceof FunctionNode) {
        if (p.name !== q.name) {
          return false;
        }
      }

      if (p.args.length !== q.args.length) {
        return false;
      }

      for (var i = 0; i < p.args.length; i++) {
        if (!_exactMatch(p.args[i], q.args[i])) {
          return false;
        }
      }
    } else {
      return false;
    }

    return true;
  }
Determines whether p and q (and all their children nodes) are identical.

@param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} p
@param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} q
@return {Object} Information about the match, if it exists.