1 /*
2 * RFunctionInformation.hpp
3 *
4 * Copyright (C) 2021 by RStudio, PBC
5 *
6 * Unless you have received this program directly from RStudio pursuant
7 * to the terms of a commercial license agreement with RStudio, then
8 * this program is licensed to you under the terms of version 3 of the
9 * GNU Affero General Public License. This program is distributed WITHOUT
10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13 *
14 */
15
16 #ifndef CORE_R_UTIL_R_FUNCTION_INFORMATION_HPP
17 #define CORE_R_UTIL_R_FUNCTION_INFORMATION_HPP
18
19 // Utility classes used for collecting information about R packages
20 // (their functions and what they do)
21
22 #include <vector>
23 #include <string>
24 #include <map>
25
26 #include <core/Log.hpp>
27 #include <core/collection/Position.hpp>
28
29 #include <boost/optional.hpp>
30 #include <boost/logic/tribool.hpp>
31
32 namespace rstudio {
33 namespace core {
34 namespace r_util {
35
36 struct Binding
37 {
Bindingrstudio::core::r_util::Binding38 Binding(const std::string& name,
39 const std::string& origin)
40 : name(name), origin(origin)
41 {}
42
operator <<(std::ostream & os,const Binding & self)43 friend std::ostream& operator <<(std::ostream& os,
44 const Binding& self)
45 {
46 os << "[" << self.origin << "::" << self.name << "]";
47 return os;
48 }
49
50 std::string name;
51 std::string origin;
52 };
53
54 class FormalInformation
55 {
56 public:
57
58 // ctor -- must be initialized with a name;
59 // all other information is optional
FormalInformation(const std::string & name)60 explicit FormalInformation(const std::string& name)
61 : name_(name)
62 {}
63
setDefaultValue(const std::string & defaultValue)64 void setDefaultValue(const std::string& defaultValue)
65 {
66 hasDefault_ = true;
67 defaultValue_ = defaultValue;
68 }
69
setHasDefaultValue(bool value)70 void setHasDefaultValue(bool value)
71 {
72 hasDefault_ = value;
73 }
74
name() const75 const std::string& name() const { return name_; }
defaultValue() const76 const boost::optional<std::string>& defaultValue() const { return defaultValue_; }
hasDefault() const77 boost::tribool hasDefault() const { return hasDefault_; }
isUsed() const78 bool isUsed() const { return bool(isUsed_); }
setIsUsed(bool value)79 void setIsUsed(bool value) { isUsed_ = value; }
isMissingnessHandled() const80 bool isMissingnessHandled() const { return bool(isMissingnessHandled_); }
setMissingnessHandled(bool value)81 void setMissingnessHandled(bool value) { isMissingnessHandled_ = value; }
82
83 private:
84 std::string name_;
85
86 // NOTE: It is possible for us to know that a particular
87 // function has a default value, but not what that default
88 // value is, hence why we have separate fields here.
89 boost::optional<std::string> defaultValue_;
90 boost::tribool hasDefault_;
91
92 // Whether this formal is used in the body of its associated function
93 boost::tribool isUsed_;
94
95 // Whether this formal is tested in a `missing()` call
96 boost::tribool isMissingnessHandled_;
97
98 // private c-tor used as dummy 'no such formal', for friend classes
99 friend class FunctionInformation;
FormalInformation()100 FormalInformation() {}
101 };
102
103 class FunctionInformation
104 {
105 public:
106
107 // default ctor: we may not know the original binding
108 // for this function
FunctionInformation()109 FunctionInformation()
110 {}
111
112 // binding ctor: gives the 'origin' of this function name
113 // (name + 'origin', which could be a package, namespace, env, ...)
FunctionInformation(const std::string & name,const std::string & origin)114 FunctionInformation(const std::string& name,
115 const std::string& origin)
116 : binding_(Binding(name, origin))
117 {}
118
addFormal(const std::string & name)119 void addFormal(const std::string& name)
120 {
121 formals_.push_back(FormalInformation(name));
122 formalNames_.push_back(name);
123 }
124
addFormal(const FormalInformation & info)125 void addFormal(const FormalInformation& info)
126 {
127 formals_.push_back(info);
128 formalNames_.push_back(info.name());
129 }
130
isPrimitive()131 bool isPrimitive()
132 {
133 return bool(isPrimitive_);
134 }
135
setIsPrimitive(bool isPrimitive)136 void setIsPrimitive(bool isPrimitive)
137 {
138 isPrimitive_ = isPrimitive;
139 }
140
formals() const141 const std::vector<FormalInformation>& formals() const
142 {
143 return formals_;
144 }
145
formals()146 std::vector<FormalInformation>& formals()
147 {
148 return formals_;
149 }
150
151
getFormalNames() const152 const std::vector<std::string>& getFormalNames() const
153 {
154 return formalNames_;
155 }
156
defaultValueForFormal(const std::string & formalName)157 const boost::optional<std::string>& defaultValueForFormal(
158 const std::string& formalName)
159 {
160 return infoForFormal(formalName).defaultValue();
161 }
162
infoForFormal(const std::string & formalName)163 FormalInformation& infoForFormal(const std::string& formalName)
164 {
165 std::size_t n = formals_.size();
166 for (std::size_t i = 0; i < n; ++i)
167 if (formals_[i].name() == formalName)
168 return formals_[i];
169
170 LOG_WARNING_MESSAGE("No such formal '" + formalName + "'");
171 return noSuchFormal_;
172 }
173
binding() const174 const boost::optional<Binding>& binding() const
175 {
176 return binding_;
177 }
178
setPerformsNse(bool performsNse)179 void setPerformsNse(bool performsNse) { performsNse_ = performsNse; }
performsNse() const180 boost::tribool performsNse() const { return performsNse_; }
181
182 private:
183 boost::optional<Binding> binding_;
184 std::vector<FormalInformation> formals_;
185 std::vector<std::string> formalNames_;
186 boost::tribool isPrimitive_;
187 boost::tribool performsNse_;
188
189 // Provided so that 'infoForFormal' can return by reference
190 FormalInformation noSuchFormal_;
191 };
192
193 typedef std::string FunctionName;
194 typedef std::map<FunctionName, FunctionInformation> FunctionInformationMap;
195
196 struct PackageInformation
197 {
198 std::string package;
199 std::vector<std::string> exports;
200 std::vector<int> types;
201 std::vector<std::string> datasets;
202 FunctionInformationMap functionInfo;
203 };
204
infoToFormalMap(const std::map<std::string,FunctionInformation> & info)205 inline std::map<std::string, std::vector<std::string> > infoToFormalMap(
206 const std::map<std::string, FunctionInformation>& info)
207 {
208 std::map<std::string, std::vector<std::string> > result;
209 typedef std::map<std::string, FunctionInformation>::const_iterator const_iterator;
210 for (const_iterator it = info.begin(); it != info.end(); ++it)
211 result[it->first] = it->second.getFormalNames();
212 return result;
213 }
214
215 } // namespace r_util
216 } // namespace core
217 } // namespace rstudio
218
219 #endif // CORE_R_UTIL_R_FUNCTION_INFORMATION_HPP
220