anchor.diff:                   zone_ids :: list(doko_doc:zone_id())}).
   
   %% Type definitions
  --type q() :: {and_q,  q(), q()} |
  -             {or_q,   q(), q()} |
  -             {not_q,  q()     } |
  +-type q() :: {and_q, q(), q()} |
  +             {or_q,  q(), q()} |
  +             {not_q, q()} |
                {term_q, string(), list(string())}.
   
   %%----------------------------------------------------------------------------
  
positive.code:                         dict:fetch(any, Dict);
                      _ ->
                          gb_sets:union(
                            [element(2, Y)
                             || Y <- [dict:find(X, Dict) || X <- ZoneIds],
                                Y /= error])
                  end
          end,
      DocIds =
  
negative.code: not_element(#not_q{}) ->
      false.
  
  depth({and_q, L, R}) ->
      1 + max(depth(L), depth(R));
  depth({or_q,L,R}) ->
      1 + max(depth(L), depth(R));
  depth({not_q,Q}) ->
      1 + depth(Q);
  depth(_) ->
      0.
  
  prop_no_nested_or() ->
      ?FORALL(X, q(), not nested_or(dnf({X, depth(X)}))).
  
  nested_or({and_q, L, R}) ->
      (is_record(L, or_q) or is_record(R, or_q))
          orelse (nested_or(L) or nested_or(R));
  nested_or({or_q, L, R}) ->
      nested_or(L) or nested_or(R);
  nested_or({not_q, Q}) ->
      nested_or(Q);
  nested_or(_) ->
      false.
  