Skip to content

Commit cb3ef74

Browse files
author
luke
committed
Add R_GetBindingType based on proposals in PR18928.
git-svn-id: https://svn.r-project.org/R/trunk@89610 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent b678984 commit cb3ef74

File tree

7 files changed

+113
-2
lines changed

7 files changed

+113
-2
lines changed

doc/NEWS.Rd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@
429429
\code{SET_HASHTAB}, \code{SET_NAMED}, \code{SET_S4_OBJECT},
430430
\code{SET_TRUELENGTH}, \code{STDVEC_DATAPTR}, \code{TRUELENGTH},
431431
\code{UNSET_S4_OBJECT}, \code{XTRUELENGTH}.
432+
433+
\item New experimental function \code{R_GetBindingType} to support
434+
inspecting environments without forcing delayed or active bindings.
432435
}
433436
}
434437

doc/manual/R-exts.texi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17875,8 +17875,8 @@ most uses the functions @code{R_getVar} and @code{R_getVarEx} added in
1787517875

1787617876
In rare cases package @R{} or C code may want to obtain more detailed
1787717877
information on a binding, such as whether the binding is delayed or
17878-
not. This is currently not possible within the API, but is under
17879-
consideration.
17878+
not. An experimental function @code{R_GetBindingType} is now available.
17879+
@eapifun R_GetBindingType
1788017880

1788117881
@node Some backports
1788217882
@subsection Some backports

src/include/Internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ SEXP do_bcprofstop(SEXP, SEXP, SEXP, SEXP);
8383
SEXP do_begin(SEXP, SEXP, SEXP, SEXP);
8484
SEXP do_bincode(SEXP, SEXP, SEXP, SEXP);
8585
SEXP do_bind(SEXP, SEXP, SEXP, SEXP);
86+
SEXP do_bindingType(SEXP, SEXP, SEXP, SEXP);
8687
SEXP do_bindtextdomain(SEXP, SEXP, SEXP, SEXP);
8788
SEXP do_bitwise(SEXP, SEXP, SEXP, SEXP);
8889
SEXP do_body(SEXP, SEXP, SEXP, SEXP);

src/include/Rinternals.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,17 @@ SEXP R_UnwindProtect(SEXP (*fun)(void *data), void *data,
660660
void *cleandata, SEXP cont); // context.c
661661

662662
/* Environment and Binding Features */
663+
typedef enum {
664+
R_BindingTypeUnbound = 0, // Unbound in this environment
665+
R_BindingTypeValue = 1, // Direct value binding
666+
R_BindingTypeMissing = 2, // Missing argument
667+
R_BindingTypeDelayed = 3, // Delayed (promise)
668+
R_BindingTypeForced = 4, // Forced (promise)
669+
R_BindingTypeActive = 5, // Active binding
670+
} R_BindingType_t;
671+
672+
R_BindingType_t R_GetBindingType(SEXP sym, SEXP env);
673+
663674
SEXP R_NewEnv(SEXP, int, int);
664675
Rboolean R_IsPackageEnv(SEXP rho); // envir.c
665676
SEXP R_PackageEnvName(SEXP rho);

src/main/envir.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,78 @@ static SEXP R_GetGlobalCacheLoc(SEXP symbol)
775775
}
776776
#endif /* USE_GLOBAL_CACHE */
777777

778+
779+
/*----------------------------------------------------------------------
780+
R_GetBindingType
781+
*/
782+
783+
static R_BindingType_t BINDING_TYPE(SEXP cell)
784+
{
785+
if (BNDCELL_TAG(cell))
786+
// avoid expanding immediate values
787+
return R_BindingTypeValue;
788+
else if (IS_ACTIVE_BINDING(cell))
789+
return R_BindingTypeActive;
790+
else {
791+
SEXP value = CAR(cell);
792+
if (value == R_MissingArg)
793+
return R_BindingTypeMissing;
794+
else if (TYPEOF(value) == PROMSXP) {
795+
if (PROMISE_IS_EVALUATED(value))
796+
return R_BindingTypeForced;
797+
else
798+
return R_BindingTypeDelayed;
799+
}
800+
else
801+
return R_BindingTypeValue;
802+
}
803+
}
804+
805+
static R_BindingType_t SYMBOL_BINDING_TYPE(SEXP cell)
806+
{
807+
// probably no need to support symbol bindings
808+
error("symbol bindings not supported yet");
809+
}
810+
811+
attribute_hidden
812+
R_BindingType_t R_GetVarLocType(R_varloc_t vl)
813+
{
814+
SEXP cell = vl.cell;
815+
if (cell == NULL || cell == R_UnboundValue)
816+
return R_BindingTypeUnbound;
817+
else if (TYPEOF(cell) == SYMSXP)
818+
return SYMBOL_BINDING_TYPE(cell);
819+
else
820+
return BINDING_TYPE(cell);
821+
}
822+
823+
R_BindingType_t R_GetBindingType(SEXP sym, SEXP env) {
824+
if (TYPEOF(sym) != SYMSXP)
825+
error(_("not a symbol"));
826+
if (TYPEOF(env) != ENVSXP)
827+
error(_("not an environment"));
828+
829+
R_varloc_t loc = R_findVarLocInFrame(env, sym);
830+
return R_GetVarLocType(loc);
831+
}
832+
833+
attribute_hidden SEXP do_bindingType(SEXP call, SEXP op, SEXP args, SEXP rho)
834+
{
835+
checkArity(op, args);
836+
SEXP sym = CAR(args);
837+
SEXP env = CADR(args);
838+
switch(R_GetBindingType(sym, env)) {
839+
case R_BindingTypeUnbound: return mkString("unbound");
840+
case R_BindingTypeValue: return mkString("value");
841+
case R_BindingTypeMissing: return mkString("missing");
842+
case R_BindingTypeDelayed: return mkString("delayed");
843+
case R_BindingTypeForced: return mkString("forced");
844+
case R_BindingTypeActive: return mkString("active");
845+
default: error("unknown binding type; should not happen");
846+
}
847+
}
848+
849+
778850
/*----------------------------------------------------------------------
779851
780852
unbindVar

src/main/names.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,7 @@ FUNTAB R_FunTab[] =
922922
{"makeActiveBinding", do_mkActiveBnd, 0, 111, 3, {PP_FUNCALL, PREC_FN, 0}},
923923
{"bindingIsActive", do_bndIsActive, 0, 11, 2, {PP_FUNCALL, PREC_FN, 0}},
924924
{"activeBindingFunction", do_activeBndFun, 0, 11, 2, {PP_FUNCALL, PREC_FN, 0}},
925+
{"getBindingType", do_bindingType, 0, 11, 2, {PP_FUNCALL, PREC_FN, 0}},
925926
{"mkUnbound", do_mkUnbound, 0, 111, 1, {PP_FUNCALL, PREC_FN, 0}},
926927
{"isNamespaceEnv",do_isNSEnv, 0, 11, 1, {PP_FUNCALL, PREC_FN, 0}},
927928
{"registerNamespace",do_regNS, 0, 11, 2, {PP_FUNCALL, PREC_FN, 0}},

tests/reg-tests-1e.R

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2614,6 +2614,29 @@ stopifnot(identical(strX2 , strX2. ), noListof(strX2. ),
26142614
identical(strXs2, strXs2.), noListof(strXs2.))
26152615
## strXs?2. did have 'List of' in R <= 4.5.z
26162616

2617+
## simple test for R_GetBindingType
2618+
local({
2619+
getBindingType <- function(sym, env) {
2620+
if (is.character(sym))
2621+
sym <- as.name(sym)
2622+
.Internal(getBindingType(sym, env))
2623+
}
2624+
f0 <- function() getBindingType("x", environment())
2625+
stopifnot(f0() == "unbound")
2626+
f1 <- function() { x <- 1; getBindingType("x", environment())}
2627+
stopifnot(f1() == "value")
2628+
f2 <- function(x) getBindingType("x", environment())
2629+
stopifnot(f2() == "missing")
2630+
f3 <- function(x) getBindingType("x", environment())
2631+
stopifnot(f3(1) == "delayed")
2632+
f4 <- function(x) { x; getBindingType("x", environment())}
2633+
stopifnot(f4(1) == "forced")
2634+
f5 <- function() {
2635+
makeActiveBinding("x", \(x) 1, environment())
2636+
getBindingType("x", environment())
2637+
}
2638+
stopifnot(f5() == "active")
2639+
})
26172640

26182641

26192642
## keep at end

0 commit comments

Comments
 (0)