anchor.diff:  
     {comments, ""}.
   
  -eval(_Config) ->
  +eval(Config) when is_list(Config) ->
  +  eval(fun read/1),
  +  eval(fun read_io/1);
  +eval(ReadFun) ->
     ct:comment("Read eval 1"),
  -  1 = clj_reader:read(<<"#=1">>),
  +  1 = ReadFun(<<"#=1">>),
   
     ct:comment("Read eval (do 1)"),
  -  1 = clj_reader:read(<<"#=(do 1)">>),
  +  1 = ReadFun(<<"#=(do 1)">>),
   
     ct:comment("Read eval (str 1)"),
  -  <<"1">> = clj_reader:read(<<"#=(clj_core/str.e 1)">>),
  -
  -  {comments, ""}.
  -
  -var(_Config) ->
  +  <<"1">> = ReadFun(<<"#=(clj_core/str.e 1)">>),
  +
  +  {comments, ""}.
  +
  +var(Config) when is_list(Config) ->
  +  var(fun read/1),
  +  var(fun read_io/1);
  +var(ReadFun) ->
     VarSymbol = clj_core:symbol(<<"var">>),
     ListSymbol = clj_core:symbol(<<"list">>),
   
     ct:comment(""),
     List = clj_core:list([VarSymbol, ListSymbol]),
  -  true = clj_core:equiv(clj_reader:read(<<"#'list">>), List),
  -
  -  {comments, ""}.
  -
  -regex(_Config) ->
  +  true = clj_core:equiv(ReadFun(<<"#'list">>), List),
  +
  +  {comments, ""}.
  +
  +regex(Config) when is_list(Config) ->
  +  regex(fun read/1, fun read_all/1),
  +  regex(fun read_io/1, fun read_all_io/1).
  +
  +regex(ReadFun, ReadAllFun) ->
     Regex = 'erlang.util.Regex':?CONSTRUCTOR(<<".?el\\.lo">>),
  -  Regex = clj_reader:read(<<"#\".?el\\.lo\"">>),
  +  Regex = ReadFun(<<"#\".?el\\.lo\"">>),
   
     ct:comment("EOF: unterminated regex"),
  -  ok = try read_all(<<"#\"a*">>)
  -       catch _:_ -> ok
  -       end,
  -
  -  {comments, ""}.
  -
  -unreadable_form(_Config) ->
  +  ok = try ReadAllFun(<<"#\"a*">>)
  +       catch _:_ -> ok
  +       end,
  +
  +  {comments, ""}.
  +
  +unreadable_form(Config) when is_list(Config) ->
  +  unreadable_form(fun read/1),
  +  unreadable_form(fun read_io/1);
  +unreadable_form(ReadFun) ->
     ct:comment("Read unreadable"),
  -  ok = try clj_reader:read(<<"#<1>">>)
  +  ok = try ReadFun(<<"#<1>">>)
          catch _:<<"?:1:1: Unreadable form">> -> ok
          end,
   
     {comments, ""}.
   
  -discard(_Config) ->
  -  [1] = read_all(<<"#_ :hello 1">>),
  -
  -  1 = clj_reader:read(<<"#_ :hello 1">>),
  -
  -  1 = clj_reader:read(<<"1 #_ :hello">>),
  +discard(Config) when is_list(Config) ->
  +  discard(fun read/1, fun read_all/1),
  +  discard(fun read_io/1, fun read_all_io/1).
  +
  +discard(ReadFun, ReadAllFun) ->
  +  [1] = ReadAllFun(<<"#_ :hello 1">>),
  +
  +  1 = ReadFun(<<"#_ :hello 1">>),
  +
  +  1 = ReadFun(<<"1 #_ :hello">>),
   
     StrSym = clj_core:symbol(<<"str">>),
     ByeKeyword = clj_core:keyword(<<"bye">>),
     List = clj_core:list([StrSym, ByeKeyword]),
  -  true = clj_core:equiv(clj_reader:read(<<"(str  #_ :hello :bye)">>), List),
  -
  -  {comments, ""}.
  -
  -'cond'(_Config) ->
  +  true = clj_core:equiv(ReadFun(<<"(str  #_ :hello :bye)">>), List),
  +
  +  {comments, ""}.
  +
  +'cond'(Config) when is_list(Config) ->
  +  'cond'(fun read/1, fun read/2),
  +  'cond'(fun read_io/1, fun read_io/2).
  +
  +'cond'(ReadFun, ReadFun2) ->
     AllowOpts = #{'read-cond' => allow},
     AllowCljFeatureOpts = #{'read-cond' => allow,
  -                          features => clj_reader:read(<<"#{:clj}">>)},
  +                          features => ReadFun(<<"#{:clj}">>)},
     AllowClrFeatureOpts = #{'read-cond' => allow,
  -                          features => clj_reader:read(<<"#{:clr}">>)},
  +                          features => ReadFun(<<"#{:clr}">>)},
     HelloKeyword = clj_core:keyword(<<"hello">>),
   
     ct:comment("Allow with no features"),
  -  HelloKeyword = clj_reader:read(<<"#?(:one 2) :hello">>, AllowOpts),
  +  HelloKeyword = ReadFun2(<<"#?(:one 2) :hello">>, AllowOpts),
   
     ct:comment("Allow with feature match"),
  -  2 = clj_reader:read(<<"#?(:clj 2) :hello">>, AllowCljFeatureOpts),
  +  2 = ReadFun2(<<"#?(:clj 2) :hello">>, AllowCljFeatureOpts),
   
     ct:comment("Allow with no feature match"),
  -  HelloKeyword = clj_reader:read(<<"#?(:clj 2 :cljs [3]) :hello">>,
  -                                 AllowClrFeatureOpts),
  +  HelloKeyword = ReadFun2( <<"#?(:clj 2 :cljs [3]) :hello">>
  +                         , AllowClrFeatureOpts
  +                         ),
   
     ct:comment("Cond splice vector"),
  -  OneTwoThreeVector = clj_reader:read(<<"[:one :two :three]">>),
  -  OneTwoThreeVector = clj_reader:read(<<"[:one #?@(:clj :three"
  -                                        " :clr [:two]) :three]">>,
  -                                      AllowClrFeatureOpts),
  -
  -  OneTwoThreeVector = clj_reader:read(<<"[:one #? @  (:clj :three"
  -                                        " :clr [:two]) :three]">>,
  -                                      AllowClrFeatureOpts),
  -
  -  OneTwoThreeFourVector = clj_reader:read(<<"[:one :two :three :four]">>),
  +  OneTwoThreeVector = ReadFun(<<"[:one :two :three]">>),
  +  OneTwoThreeVector = ReadFun2( <<"[:one #?@(:clj :three"
  +                                  " :clr [:two]) :three]">>
  +                              , AllowClrFeatureOpts
  +                              ),
  +
  +  OneTwoThreeVector = ReadFun2( <<"[:one #? @  (:clj :three"
  +                                  " :clr [:two]) :three]">>
  +                              , AllowClrFeatureOpts
  +                              ),
  +
  +  OneTwoThreeFourVector = ReadFun(<<"[:one :two :three :four]">>),
     OneTwoThreeFourVector =
  -    clj_reader:read(<<"[:one #?@(:clj :three :clr"
  -                      " [:two :three] :cljs :five) :four]">>,
  -                    AllowClrFeatureOpts),
  +    ReadFun2( <<"[:one #?@(:clj :three :clr"
  +                " [:two :three] :cljs :five) :four]">>
  +            , AllowClrFeatureOpts
  +            ),
   
     ct:comment("Cond splice list"),
  -  OneTwoThreeVector = clj_reader:read(<<"[:one #?@(:clj :three"
  -                                        " :clr (:two)) :three]">>,
  -                                      AllowClrFeatureOpts),
  -  OneTwoThreeFourVector =
  -    clj_reader:read(<<"[:one #?@(:clj :three :clr"
  -                     " (:two :three) :cljs :five) :four]">>,
  -                    AllowClrFeatureOpts),
  +  OneTwoThreeVector = ReadFun2( <<"[:one #?@(:clj :three"
  +                                  " :clr (:two)) :three]">>
  +                              , AllowClrFeatureOpts
  +                              ),
  +  OneTwoThreeFourVector = ReadFun2( <<"[:one #?@(:clj :three :clr"
  +                                      " (:two :three) :cljs :five) :four]">>
  +                                  , AllowClrFeatureOpts
  +                                  ),
   
     ct:comment("Preserve read"),
     PreserveOpts = #{'read-cond' => preserve},
     ReaderCond   =
       'clojerl.reader.ReaderConditional':?CONSTRUCTOR(
  -                                          clj_reader:read(<<"(1 2)">>), false
  +                                          ReadFun(<<"(1 2)">>), false
                                            ),
     [ReaderCondCheck, HelloKeyword] =
       read_all(<<"#?(1 2) :hello">>, PreserveOpts),
  
positive.code:              ),
  
    ct:comment("Use default readers"),
    <<"2016">> = clj_reader:read(<<"#inst \"2016\"">>),
    <<"de305d54-75b4-431b-adb2-eb6b9e546014">> =
      clj_reader:read(<<"#uuid \"de305d54-75b4-431b-adb2-eb6b9e546014\"">>),
  
    ct:comment("Use *default-data-reader-fn*"),
    DefaultReaderFunVar =
  
negative.code: 
    ReaderCondSplice =
      'clojerl.reader.ReaderConditional':?CONSTRUCTOR(
                                            ReadFun(<<"(1 2)">>), true
                                           ),
    ReaderCondSpliceVector = clj_core:vector([ReaderCondSplice, HelloKeyword]),
    ReaderCondSpliceVectorCheck = ReadFun2(<<"[#?@(1 2) :hello]">>, PreserveOpts),
    true = clj_core:equiv(ReaderCondSpliceVector, ReaderCondSpliceVectorCheck),
    false = clj_core:equiv(ReaderCond, ReaderCondSpliceVector),
  
    ct:comment("EOF while reading cond"),
    ok = try ReadFun2(<<"#?">>, AllowOpts)
         catch _:<<"?:1:3: EOF while reading cond">> -> ok
         end,
  
    ct:comment("Reader conditional not allowed"),
    ok = try ReadFun(<<"#?(:clj :whatever :clr :whateverrrr)">>)
         catch _:<<"?:1:3: Conditional read not allowed">> -> ok
         end,
  
    ct:comment("No list"),
    ok = try ReadFun2(<<"#?:clj">>, AllowOpts)
         catch _:<<"?:1:3: read-cond body must be a list">> -> ok
         end,
  
    ct:comment("EOF: no feature matched"),
    ok = try ReadFun2(<<"#?(:clj :whatever :clr :whateverrrr)">>, AllowOpts)
         catch _:<<"?:1:37: EOF">> -> ok
         end,
  
    ct:comment("Uneven number of forms"),
    ok = try ReadFun2(<<"#?(:one :two :three)">>, AllowOpts)
         catch _:<<"?:1:21: read-cond requires an even number of forms">> -> ok
         end,
  
    ct:comment("Splice at the top level"),
    ok = try ReadFun2(<<"#?@(:clje [:two])">>, AllowOpts)
         catch _:<<"?:1:5: Reader conditional splicing not allowed "
                   "at the top level">> -> ok
         end,
  
    ct:comment("Splice in list but not sequential"),
    ok = try ReadFun2(<<"[#?@(:clr :a :cljs :b) :c :d]">>,
                             AllowClrFeatureOpts)
         catch _:<<"?:1:13: Spliced form list in read-cond-splicing must "
                    "extend clojerl.ISequential">> -> ok
         end,
  
    ct:comment("Feature is not a keyword"),
    ok = try ReadFun2(<<"#?(1 2) :hello">>, AllowOpts)
         catch _:<<"?:1:4: Feature should be a keyword">> -> ok
         end,
  
    {comments, ""}.
  
  unsupported_reader(Config) when is_list(Config) ->
    unsupported_reader(fun read/1),
    unsupported_reader(fun read_io/1);
  unsupported_reader(ReadFun) ->
    ct:comment("Try unsupported reader"),
    ok = try ReadFun(<<"#-:something">>)
         catch _:_ -> ok
         end,
  
    {comments, ""}.
  
  tuple(Config) when is_list(Config) ->
    tuple(fun read/1),
    tuple(fun read_io/1);
  tuple(ReadFun) ->
    ct:comment("Read an empty tuple"),
    {} = ReadFun(<<"#[]">>),
  
    ct:comment("Read a tuple with a single element"),
    {42} = ReadFun(<<"#[42]">>),
  
    ct:comment("Read a tuple with many elements"),
    HelloKeyword = clj_core:keyword(<<"hello">>),
  