File: RNonStandardEvaluation.h

package info (click to toggle)
r-cran-sourcetools 0.1.7-1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 308 kB
  • sloc: cpp: 1,985; ansic: 505; sh: 10; makefile: 2
file content (149 lines) | stat: -rw-r--r-- 2,863 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#ifndef SOURCETOOLS_R_R_NON_STANDARD_EVALUATION_H
#define SOURCETOOLS_R_R_NON_STANDARD_EVALUATION_H

#include <set>
#include <map>

#include <sourcetools/r/RHeaders.h>
#include <sourcetools/r/RCallRecurser.h>

namespace sourcetools {
namespace r {
namespace nse {

namespace detail {

inline std::set<std::string> makeNsePrimitives()
{
  std::set<std::string> instance;

  instance.insert("quote");
  instance.insert("substitute");
  instance.insert("eval");
  instance.insert("evalq");
  instance.insert("lazy_dots");

  return instance;
}

inline std::set<std::string>& nsePrimitives()
{
  static std::set<std::string> instance = makeNsePrimitives();
  return instance;
}

class PerformsNonStandardEvaluationOperation
  : public r::CallRecurser::Operation
{
public:

  PerformsNonStandardEvaluationOperation()
    : status_(false)
  {
  }

  virtual void apply(SEXP dataSEXP)
  {
    if (status_ || TYPEOF(dataSEXP) != LANGSXP)
      return;

    if ((status_ = checkCall(dataSEXP)))
      return;

    SEXP fnSEXP = CAR(dataSEXP);
    if (TYPEOF(fnSEXP) == SYMSXP)
      status_ = nsePrimitives().count(CHAR(PRINTNAME(fnSEXP)));
    else if (TYPEOF(fnSEXP) == STRSXP)
      status_ = nsePrimitives().count(CHAR(STRING_ELT(fnSEXP, 0)));

  }

  bool status() const { return status_; }

private:

  bool checkCall(SEXP callSEXP)
  {
    std::size_t n = Rf_length(callSEXP);
    if (n == 0)
      return false;

    SEXP fnSEXP = CAR(callSEXP);
    if (fnSEXP == Rf_install("::") || fnSEXP == Rf_install(":::"))
    {
      SEXP lhsSEXP = CADR(callSEXP);
      SEXP rhsSEXP = CADDR(callSEXP);

      if (lhsSEXP == Rf_install("lazyeval") && rhsSEXP == Rf_install("lazy_dots"))
        return true;
    }

    return false;
  }

private:
  bool status_;
};

} // namespace detail

class Database
{
public:
  bool check(SEXP dataSEXP)
  {
    if (contains(dataSEXP))
      return get(dataSEXP);

    typedef detail::PerformsNonStandardEvaluationOperation Operation;
    scoped_ptr<Operation> operation(new Operation);

    r::CallRecurser recurser(dataSEXP);
    recurser.add(operation);
    recurser.run();

    set(dataSEXP, operation->status());
    return operation->status();
  }

private:

  bool contains(SEXP dataSEXP)
  {
    return map_.count(address(dataSEXP));
  }

  bool get(SEXP dataSEXP)
  {
    return map_[address(dataSEXP)];
  }

  void set(SEXP dataSEXP, bool value)
  {
    map_[address(dataSEXP)] = value;
  }

  std::size_t address(SEXP dataSEXP)
  {
    return reinterpret_cast<std::size_t>(dataSEXP);
  }

  std::map<std::size_t, bool> map_;
};

inline Database& database()
{
  static Database instance;
  return instance;
}

inline bool performsNonStandardEvaluation(SEXP fnSEXP)
{
  return database().check(fnSEXP);
}

} // namespace nse
} // namespace r
} // namespace sourcetools

#endif /* SOURCETOOLS_R_R_NON_STANDARD_EVALUATION_H */