|
Rcpp Version 0.9.10
|
00001 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- 00002 // 00003 // Environment.cpp: Rcpp R/C++ interface class library -- Environments 00004 // 00005 // Copyright (C) 2009 - 2011 Dirk Eddelbuettel and Romain Francois 00006 // 00007 // This file is part of Rcpp. 00008 // 00009 // Rcpp is free software: you can redistribute it and/or modify it 00010 // under the terms of the GNU General Public License as published by 00011 // the Free Software Foundation, either version 2 of the License, or 00012 // (at your option) any later version. 00013 // 00014 // Rcpp is distributed in the hope that it will be useful, but 00015 // WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 // GNU General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU General Public License 00020 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>. 00021 00022 #include <Rcpp/Environment.h> 00023 00024 namespace Rcpp { 00025 00026 Environment::Environment() : RObject(R_NilValue){} 00027 00028 Environment::Environment( SEXP x = R_GlobalEnv) : RObject(x){ 00029 if( ! Rf_isEnvironment(x) ) { 00030 /* not an environment, but maybe convertible to one using as.environment, try that */ 00031 SEXP res ; 00032 try { 00033 SEXP asEnvironmentSym = Rf_install("as.environment"); // cannot be gc()'ed once in symbol table 00034 res = Evaluator::run( Rf_lang2(asEnvironmentSym, x ) ) ; 00035 } catch( const eval_error& ex){ 00036 throw not_compatible( "cannot convert to environment" ) ; 00037 } 00038 setSEXP( res ) ; 00039 } 00040 } 00041 00042 Environment::Environment( const std::string& name) : RObject(R_EmptyEnv){ 00043 /* similar to matchEnvir@envir.c */ 00044 if( name == ".GlobalEnv" ) { 00045 setSEXP( R_GlobalEnv ) ; 00046 } else if( name == "package:base" ){ 00047 setSEXP( R_BaseEnv ) ; 00048 } else{ 00049 SEXP res = R_NilValue ; 00050 try{ 00051 SEXP asEnvironmentSym = Rf_install("as.environment"); // cannot be gc()'ed once in symbol table 00052 res = Evaluator::run(Rf_lang2( asEnvironmentSym, Rf_mkString(name.c_str()) ) ) ; 00053 } catch( const eval_error& ex){ 00054 throw no_such_env(name) ; 00055 } 00056 setSEXP( res ) ; 00057 } 00058 } 00059 00060 Environment::Environment(int pos) : RObject(R_GlobalEnv){ 00061 SEXP res ; 00062 try{ 00063 SEXP asEnvironmentSym = Rf_install("as.environment"); // cannot be gc()'ed once in symbol table 00064 res = Evaluator::run( Rf_lang2( asEnvironmentSym, Rf_ScalarInteger(pos) ) ) ; 00065 } catch( const eval_error& ex){ 00066 throw no_such_env(pos) ; 00067 } 00068 setSEXP( res ) ; 00069 } 00070 00071 Environment::Environment( const Environment& other ) { 00072 setSEXP( other.asSexp() ) ; 00073 } 00074 00075 Environment& Environment::operator=(const Environment& other) { 00076 setSEXP( other.asSexp() ) ; 00077 return *this ; 00078 } 00079 00080 Environment::~Environment(){ 00081 logTxt( "~Environment" ) ; 00082 } 00083 00084 SEXP Environment::ls( bool all = true) const { 00085 if( is_user_database() ){ 00086 R_ObjectTable *tb = (R_ObjectTable*) 00087 R_ExternalPtrAddr(HASHTAB(m_sexp)); 00088 return tb->objects(tb) ; 00089 } else{ 00090 Rboolean get_all = all ? TRUE : FALSE ; 00091 return R_lsInternal( m_sexp, get_all ) ; 00092 } 00093 return R_NilValue ; 00094 } 00095 00096 SEXP Environment::get( const std::string& name) const { 00097 SEXP nameSym = Rf_install(name.c_str()); // cannot be gc()'ed once in symbol table 00098 SEXP res = Rf_findVarInFrame( m_sexp, nameSym ) ; 00099 00100 if( res == R_UnboundValue ) return R_NilValue ; 00101 00102 /* We need to evaluate if it is a promise */ 00103 if( TYPEOF(res) == PROMSXP){ 00104 res = Rf_eval( res, m_sexp ) ; 00105 } 00106 return res ; 00107 } 00108 00109 SEXP Environment::find( const std::string& name) const { 00110 SEXP nameSym = Rf_install(name.c_str()); // cannot be gc()'ed once in symbol table 00111 SEXP res = Rf_findVar( nameSym, m_sexp ) ; 00112 00113 if( res == R_UnboundValue ) throw binding_not_found(name) ; 00114 00115 /* We need to evaluate if it is a promise */ 00116 if( TYPEOF(res) == PROMSXP){ 00117 res = Rf_eval( res, m_sexp ) ; 00118 } 00119 return res ; 00120 } 00121 00122 bool Environment::exists( const std::string& name) const{ 00123 SEXP nameSym = Rf_install(name.c_str()); // cannot be gc()'ed once in symbol table 00124 SEXP res = Rf_findVarInFrame( m_sexp, nameSym ) ; 00125 return res != R_UnboundValue ; 00126 } 00127 00128 bool Environment::assign( const std::string& name, SEXP x = R_NilValue) const { 00129 if( exists( name) && bindingIsLocked(name) ) throw binding_is_locked(name) ; 00130 SEXP nameSym = Rf_install(name.c_str()); // cannot be gc()'ed once in symbol table 00131 Rf_defineVar( nameSym, x, m_sexp ); 00132 return true ; 00133 } 00134 00135 bool Environment::remove( const std::string& name) { 00136 if( exists(name) ){ 00137 if( bindingIsLocked(name) ){ 00138 throw binding_is_locked(name) ; 00139 } else{ 00140 /* unless we want to copy all of do_remove, 00141 we have to go back to R to do this operation */ 00142 SEXP internalSym = Rf_install( ".Internal" ); 00143 SEXP removeSym = Rf_install( "remove" ); 00144 SEXP call = PROTECT( Rf_lang2(internalSym, Rf_lang4(removeSym, Rf_mkString(name.c_str()), 00145 m_sexp, Rf_ScalarLogical( FALSE ))) ); 00146 Rf_eval( call, R_GlobalEnv ) ; 00147 UNPROTECT(1) ; 00148 } 00149 } else{ 00150 throw no_such_binding(name) ; 00151 } 00152 return true; // to make g++ -Wall happy 00153 } 00154 00155 bool Environment::isLocked() const{ 00156 return R_EnvironmentIsLocked(m_sexp); 00157 } 00158 00159 bool Environment::bindingIsActive(const std::string& name) const { 00160 if( !exists( name) ) throw no_such_binding(name) ; 00161 SEXP nameSym = Rf_install(name.c_str()); // cannot be gc()'ed once in symbol table 00162 return R_BindingIsActive(nameSym, m_sexp) ; 00163 } 00164 00165 bool Environment::bindingIsLocked(const std::string& name) const { 00166 if( !exists( name) ) throw no_such_binding(name) ; 00167 SEXP nameSym = Rf_install(name.c_str()); // cannot be gc()'ed once in symbol table 00168 return R_BindingIsLocked(nameSym, m_sexp) ; 00169 } 00170 00171 void Environment::lock( bool bindings = false ) { 00172 R_LockEnvironment( m_sexp, bindings ? TRUE: FALSE ) ; 00173 } 00174 00175 void Environment::lockBinding(const std::string& name) { 00176 if( !exists( name) ) throw no_such_binding(name) ; 00177 SEXP nameSym = Rf_install(name.c_str()); // cannot be gc()'ed once in symbol table 00178 R_LockBinding( nameSym, m_sexp ); 00179 } 00180 00181 void Environment::unlockBinding(const std::string& name) { 00182 if( !exists( name) ) throw no_such_binding(name) ; 00183 SEXP nameSym = Rf_install(name.c_str()); // cannot be gc()'ed once in symbol table 00184 R_unLockBinding( nameSym, m_sexp ); 00185 } 00186 00187 bool Environment::is_user_database() const { 00188 return OBJECT(m_sexp) && Rf_inherits(m_sexp, "UserDefinedDatabase") ; 00189 } 00190 00191 /* static */ 00192 00193 Environment Environment::global_env() { 00194 return Environment(R_GlobalEnv) ; 00195 } 00196 00197 Environment Environment::empty_env() { 00198 return Environment(R_EmptyEnv) ; 00199 } 00200 00201 Environment Environment::base_env() { 00202 return Environment(R_BaseEnv) ; 00203 } 00204 00205 Environment Environment::base_namespace() { 00206 return Environment(R_BaseNamespace) ; 00207 } 00208 00209 Environment Environment::namespace_env(const std::string& package) { 00210 00211 SEXP env = R_NilValue ; 00212 try{ 00213 SEXP getNamespaceSym = Rf_install("getNamespace"); 00214 env = Evaluator::run( Rf_lang2(getNamespaceSym, Rf_mkString(package.c_str()) ) ) ; 00215 } catch( const eval_error& ex){ 00216 throw no_such_namespace( package ) ; 00217 } 00218 return Environment( env ) ; 00219 } 00220 00221 Environment Environment::parent() const { 00222 return Environment( ENCLOS(m_sexp) ) ; 00223 } 00224 00225 Environment::Binding::Binding( Environment& env_, const std::string& name_): 00226 env(env_), name(name_){} 00227 00228 bool Environment::Binding::active() const{ 00229 return env.bindingIsActive( name ) ; 00230 } 00231 00232 bool Environment::Binding::exists() const{ 00233 return env.exists( name ) ; 00234 } 00235 00236 bool Environment::Binding::locked() const{ 00237 return env.bindingIsLocked( name ) ; 00238 } 00239 00240 void Environment::Binding::lock() { 00241 env.lockBinding( name ) ; 00242 } 00243 00244 void Environment::Binding::unlock() { 00245 env.unlockBinding( name ) ; 00246 } 00247 00248 Environment::Binding& Environment::Binding::operator=( SEXP rhs ){ 00249 env.assign( name, rhs ) ; 00250 return *this ; 00251 } 00252 00253 Environment::Binding& Environment::Binding::operator=( const Binding& rhs){ 00254 env.assign( name, rhs.env.get(rhs.name) ) ; 00255 return *this ; 00256 } 00257 00258 const Environment::Binding Environment::operator[]( const std::string& name) const{ 00259 return Binding( const_cast<Environment&>(*this), name ); 00260 } 00261 00262 Environment::Binding Environment::operator[]( const std::string& name) { 00263 return Binding( *this, name ) ; 00264 } 00265 00266 Environment Environment::Rcpp_namespace() { 00267 return Rcpp::internal::get_Rcpp_namespace() ; 00268 } 00269 00270 Environment Environment::new_child(bool hashed) { 00271 SEXP newEnvSym = Rf_install("new.env"); 00272 return Environment( Evaluator::run(Rf_lang3( newEnvSym, Rf_ScalarLogical(hashed), m_sexp )) ); 00273 } 00274 00275 00276 } // namespace Rcpp 00277