1 /* 2 * RCntxt.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 R_CONTEXT_HPP 17 #define R_CONTEXT_HPP 18 19 #include "RSexp.hpp" 20 #include "RCntxtInterface.hpp" 21 22 #include <shared_core/Error.hpp> 23 24 #include <boost/iterator/iterator_facade.hpp> 25 26 namespace rstudio { 27 namespace r { 28 namespace context { 29 30 // RCnxt is a public-facing class which wraps entries from the R context 31 // stack (RCNXT* in the R headers), which keeps track of execution contexts 32 // during the evaluation of R code. Unfortunately, the memory layout 33 // in the RCNXT* struct is not identical in all R versions, and consequently 34 // it's necessary to wrap them in a layer of abstraction, which this class 35 // supplies. 36 // 37 // It has value semantics; its only data member is a shared pointer to the class 38 // managing the RNCTXT* interface. It also implements simple iteration over 39 // entries in the context stack. RCnxt::begin() returns an iterator beginning 40 // at R_GlobalContext; RCnxt::end() returns a null context entry. 41 class RCntxt: public RCntxtInterface 42 { 43 public: 44 // copy/equality testing 45 RCntxt(); 46 explicit RCntxt(void *rawCntxt); 47 bool operator==(const RCntxt& other) const; 48 bool operator!=(const RCntxt& other) const; 49 50 // safe coercion to boolean operator bool() const51 explicit operator bool() const 52 { 53 return pCntxt_ != nullptr; 54 } 55 56 // utility/accessor functions 57 bool hasSourceRefs() const; 58 bool isDebugHidden() const; 59 bool isErrorHandler() const; 60 61 // retrieve the source references associated with the context 62 // (the source reference where this context originated) 63 SEXP contextSourceRefs() const; 64 65 // retrieve source references associated with the calling function 66 // (where that calling function was actually defined in source) 67 SEXP callFunSourceRefs() const; 68 69 // for traced functions, the 'real' function will be replaced by 70 // a wrapper function -- use this to find the original function 71 SEXP originalFunctionCall() const; 72 73 std::string shinyFunctionLabel() const; 74 75 core::Error functionName(std::string* pFunctionName) const; 76 core::Error fileName(std::string* pFileName) const; 77 core::Error callSummary(std::string* pCallSummary) const; 78 79 // implemented by R version specific internal context classes 80 // 81 // NOTE: 'srcref()' attribute may be set to <in-bc-interp> 82 // symbol for contexts associated with bytecode evaluation! 83 bool isNull() const; 84 SEXP callfun() const; 85 int callflag() const; 86 int evaldepth() const; 87 SEXP call() const; 88 SEXP srcref() const; 89 SEXP cloenv() const; 90 RCntxt nextcontext() const; 91 92 // define an iterator for easy traversal of the context stack 93 template <class Value> 94 class cntxt_iterator: public boost::iterator_facade< 95 cntxt_iterator<Value>, 96 Value, // value type 97 boost::forward_traversal_tag, 98 const Value&> // reference type 99 { 100 public: cntxt_iterator()101 cntxt_iterator(): 102 context_() 103 { } 104 cntxt_iterator(Value pCntxt)105 explicit cntxt_iterator(Value pCntxt): 106 context_(pCntxt) 107 { } 108 109 private: 110 friend class boost::iterator_core_access; 111 increment()112 void increment() 113 { 114 context_ = context_.nextcontext(); 115 } 116 equal(cntxt_iterator<Value> const & other) const117 bool equal(cntxt_iterator<Value> const& other) const 118 { 119 return context_ == other.context_; 120 } 121 dereference() const122 const Value& dereference() const 123 { 124 return context_; 125 } 126 127 Value context_; 128 }; 129 130 typedef cntxt_iterator<RCntxt> iterator; 131 typedef cntxt_iterator<RCntxt const> const_iterator; 132 133 static iterator begin(); 134 static iterator end(); 135 136 private: 137 boost::shared_ptr<RCntxtInterface> pCntxt_; 138 139 core::Error invokeFunctionOnCall(const char* rFunction, 140 std::string* pResult) const; 141 }; 142 143 } // namespace context 144 } // namespace r 145 } // namespace rstudio 146 147 #endif 148