anchor.diff:                                               Value /= undefined])]
       end.
   
  -decoder_params(MsgName, MsgDef, AnRes) ->
  +decoder_params(MsgName, AnRes) ->
  +    NumFields = get_num_fields(MsgName, AnRes),
       case get_field_pass(MsgName, AnRes) of
  -        pass_as_params -> [var_f_n(I) || I <- lists:seq(1, length(MsgDef))];
  +        pass_as_params -> [var_f_n(I) || I <- lists:seq(1, NumFields)];
           pass_as_record -> [?expr(Msg)]
       end.
   
  
positive.code:      format_packed_field_seq_decoder(MsgName, FieldDef, Opts)].
  
  format_vi_based_field_decoder(MsgName, FieldDef, AnRes, Opts) ->
      case get_field_pass(MsgName, AnRes) of
          pass_as_params ->
              format_vi_based_field_decoder_pap(MsgName, FieldDef, AnRes, Opts);
          pass_as_record ->
              format_vi_based_field_decoder_par(MsgName, FieldDef, Opts)
      end.
  
  format_vi_based_field_decoder_pap(MsgName, FieldDef, AnRes, Opts) ->
      NF = get_num_fields(MsgName, AnRes),
      #field{type=Type, rnum=RNum, name=FName}=FieldDef,
      Merge = classify_field_merge_action(FieldDef),
      PassFieldVars = [[", ", f("F~w", [I])] || I <- lists:seq(1, NF)],
      InFieldVars = [[", ", if I == RNum-1, Merge == overwrite -> "_";
                               I == RNum-1, Merge == seqadd    -> f("F~w", [I]);
                               I == RNum-1, Merge == msgmerge  -> f("F~w", [I]);
                               I /= RNum-1                     -> f("F~w", [I])
                            end]
                     || I <- lists:seq(1, NF)],
      MergeCode = case Merge of
                      overwrite -> "";
                      seqadd    -> f("    FValue2 = [FValue | F~w],~n", [RNum-1]);
                      msgmerge  -> {msg,FMsgName} = Type,
                                   f("    FValue2 = if F~w == undefined ->~n"
                                     "                     FValue;~n"
                                     "                 true ->~n"
                                     "                     ~p(F~w, FValue)~n"
                                     "              end,~n",
                                     [RNum-1,
                                      mk_fn(merge_msg_, FMsgName), RNum-1])
                  end,
      OutFieldVars = [[", ", if I == RNum-1, Merge == overwrite -> "FValue";
                                I == RNum-1, Merge == seqadd    -> "FValue2";
                                I == RNum-1, Merge == msgmerge  -> "FValue2";
                                I /= RNum-1                     -> f("F~w", [I])
                             end]
                      || I <- lists:seq(1, NF)],
      BValueExpr = "X bsl N + Acc",
      {FValueCode, RestVar} = mk_unpack_vi(4, "FValue", BValueExpr, Type, "Rest",
                                           Opts),
      [f("~p(<<1:1, X:7, Rest/binary>>, N, Acc~s) ->~n"
         "    ~p(Rest, N+7, X bsl N + Acc~s);~n",
         [mk_fn(d_field_, MsgName, FName), PassFieldVars,
          mk_fn(d_field_, MsgName, FName), PassFieldVars]),
       f("~p(<<0:1, X:7, Rest/binary>>, N, Acc~s) ->~n",
         [mk_fn(d_field_, MsgName, FName), InFieldVars]),
       f("~s",
         [FValueCode]),
       f("~s",
         [MergeCode]),
       f("    ~p(~s, 0, 0~s).~n",
         [mk_fn(d_read_field_def_, MsgName), RestVar, OutFieldVars])].
  
  format_vi_based_field_decoder_par(MsgName, FieldDef, Opts) ->
      #field{type=Type, name=FName}=FieldDef,
      BValueExpr = "X bsl N + Acc",
      {FValueCode, RestVar} = mk_unpack_vi(4, "FValue", BValueExpr, Type, "Rest",
                                           Opts),
      [f("~p(<<1:1, X:7, Rest/binary>>, N, Acc, Msg) ->~n"
         "    ~p(Rest, N+7, X bsl N + Acc, Msg);~n",
         [mk_fn(d_field_, MsgName, FName),
          mk_fn(d_field_, MsgName, FName)]),
       f("~p(<<0:1, X:7, Rest/binary>>, N, Acc, Msg) ->~n",
         [mk_fn(d_field_, MsgName, FName)]),
       f("~s",
         [FValueCode]),
       f("    NewMsg = ~p(FValue, Msg),~n", [mk_fn(add_field_, MsgName, FName)]),
       f("    ~p(~s, 0, 0, NewMsg).~n",
         [mk_fn(d_read_field_def_, MsgName), RestVar])].
  
  %% -> {FValueCode, Rest2Var}
  %% Produce code for setting a variable, FValueVar, depending on the
  
negative.code: index_seq([]) -> [];
  index_seq(L)  -> lists:zip(lists:seq(1,length(L)), L).
  
  %% lists_replace(N, List, New) -> NewList
  %% Like erlang:setelement, but for a list:
  %% Replace the Nth element in List with a New value.
  lists_setelement(1, [_ | Rest], New) ->
      [New | Rest];
  lists_setelement(N, [X | Rest], New) when N > 1 ->
      [X | lists_setelement(N - 1, Rest, New)].
  
  %% Parse tree transform instructions
  replace_term(Marker, NewTerm) when is_atom(Marker) ->
      {replace_term, Marker, NewTerm}.
  
  replace_tree(Marker, NewTree) when is_atom(Marker) ->
      {replace_tree, Marker, NewTree}.
  
  splice_trees(Marker, Trees) when is_atom(Marker) ->
      {splice_trees, Marker, Trees}.
  
  f(F)   -> f(F,[]).
  f(F,A) -> io_lib:format(F,A).
  
  