anchor.diff:  f(F)   -> f(F,[]).
   f(F,A) -> io_lib:format(F,A).
   
  -%flength(F) -> iolist_size(f(F)).
  -flength(F, A) -> iolist_size(f(F, A)).
  -
   flatten_iolist(IoList) ->
       binary_to_list(iolist_to_binary(IoList)).
   
  
positive.code:        "\n",
         f("~s~n", [format_msg_merge_code(Defs, AnRes)]),
         "\n",
         f("verify_msg(Msg) ->~n" %% Option to use gpb:verify_msg??
           "    ~s.~n", [format_verifier_topcase(4, Defs, "Msg")]),
         "\n",
         f("~s~n", [format_verifiers(Defs, AnRes, Opts)]),
         "\n",
  
negative.code:     [format_msg_verifier(MsgName, MsgDef, AnRes)
       || {{msg,MsgName}, MsgDef} <- Defs].
  
  format_msg_verifier(MsgName, MsgDef, AnRes) ->
      ElseClause =
          case can_occur_as_sub_msg(MsgName, AnRes) of
              true ->
                  [gpb_codegen:fn_clause(
                     fun(X, Path) ->
                             mk_type_error({expected_msg,'<MsgName>'}, X, Path)
                     end,
                     [replace_term('<MsgName>', MsgName)])];
              false ->
                  []
          end,
      FVars = [{var_f_n(I), Field} || {I, Field} <- index_seq(MsgDef)],
      RFields = [{FName, Var} || {Var, #field{name=FName}} <- FVars],
      if MsgDef == [] ->
              gpb_codegen:format_fn(
                mk_fn(v_msg_, MsgName),
                fun('<msg-match>', _Path) -> ok;
                   ('<else-clause>', _) -> expr
                end,
                [replace_tree('<msg-match>', record_match(MsgName, RFields)),
                 splice_clauses('<else-clause>', ElseClause)]);
         MsgDef /= [] ->
              gpb_codegen:format_fn(
                mk_fn(v_msg_, MsgName),
                fun('<msg-match>', Path) -> '<field-verifications>', ok;
                   ('<else-clause>', _) -> expr
                end,
                [replace_tree('<msg-match>', record_match(MsgName, RFields)),
                 splice_trees('<field-verifications>', field_verifiers(FVars)),
                 splice_clauses('<else-clause>', ElseClause)])
      end.
  
  field_verifiers(FVars) ->
      [begin
           FVerifierFn = case Type of
                             {msg,FMsgName}  -> mk_fn(v_msg_, FMsgName);
                             {enum,EnumName} -> mk_fn(v_enum_, EnumName);
                             Type            -> mk_fn(v_type_, Type)
                         end,
           Replacements = [replace_term('<verify-fn>', FVerifierFn),
                           replace_tree('<F>', FVar),
                           replace_term('<FName>', FName),
                           replace_term('<Type>', Type)],
           case Occurrence of
               required ->
                   %% FIXME: check especially for `undefined'
                   %% and if found, error out with required_field_not_set
                   %% specifying expected type
                   ?expr('<verify-fn>'('<F>', ['<FName>' | Path]),
                         Replacements);
               repeated ->
                   ?expr(if is_list('<F>') ->
                                 ['<verify-fn>'(Elem, ['<FName>' | Path])
                                  || Elem <- '<F>'];
                            true ->
                                 mk_type_error(
                                   {invalid_list_of, '<Type>'}, '<F>', Path)
                         end,
                         Replacements);
               optional ->
                   ?expr(if '<F>' == undefined -> ok;
                            true -> '<verify-fn>'('<F>', ['<FName>', Path])
                         end,
                         Replacements)
           end
       end
       || {FVar, #field{name=FName, type=Type, occurrence=Occurrence}} <- FVars].
  
  can_occur_as_sub_msg(MsgName, #anres{used_types=UsedTypes}) ->
      sets:is_element({msg,MsgName}, UsedTypes).
  