Skip to content

Commit e70915f

Browse files
committed
Add R_GetBindingType() and related accessors and constructors
1 parent 133b9f5 commit e70915f

File tree

2 files changed

+145
-1
lines changed

2 files changed

+145
-1
lines changed

src/include/Rinternals.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,23 @@ SEXP R_UnwindProtect(SEXP (*fun)(void *data), void *data,
691691
void *cleandata, SEXP cont); // context.c
692692

693693
/* Environment and Binding Features */
694+
typedef enum {
695+
// Unbound in this environment
696+
R_BindingTypeUnbound = 0,
697+
// Direct value binding
698+
R_BindingTypeValue = 1,
699+
// Missing argument
700+
R_BindingTypeMissing = 2,
701+
// Delayed (promise)
702+
R_BindingTypeDelayed = 3,
703+
// Forced (promise)
704+
R_BindingTypeForced = 4,
705+
// Active binding
706+
R_BindingTypeActive = 5,
707+
} R_BindingType;
708+
709+
R_BindingType R_GetBindingType(SEXP sym, SEXP env);
710+
694711
SEXP R_NewEnv(SEXP, int, int);
695712
Rboolean R_IsPackageEnv(SEXP rho); // envir.c
696713
SEXP R_PackageEnvName(SEXP rho);
@@ -703,9 +720,15 @@ Rboolean R_EnvironmentIsLocked(SEXP env); // envir.c
703720
void R_LockBinding(SEXP sym, SEXP env);
704721
void R_unLockBinding(SEXP sym, SEXP env);
705722
void R_MakeActiveBinding(SEXP sym, SEXP fun, SEXP env);
723+
void R_MakeDelayedBinding(SEXP sym, SEXP expr, SEXP evalEnv, SEXP env);
724+
void R_MakeForcedBinding(SEXP sym, SEXP expr, SEXP value, SEXP env);
725+
void R_MakeMissingBinding(SEXP sym, SEXP env);
706726
Rboolean R_BindingIsLocked(SEXP sym, SEXP env); // envir.c
707727
Rboolean R_BindingIsActive(SEXP sym, SEXP env); // envir.c
708728
SEXP R_ActiveBindingFunction(SEXP sym, SEXP env);
729+
SEXP R_DelayedBindingExpression(SEXP sym, SEXP env);
730+
SEXP R_DelayedBindingEnvironment(SEXP sym, SEXP env);
731+
SEXP R_ForcedBindingExpression(SEXP sym, SEXP env);
709732
Rboolean R_HasFancyBindings(SEXP rho); // envir.c
710733

711734

src/main/envir.c

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,48 @@ static SEXP R_GetGlobalCacheLoc(SEXP symbol)
773773
}
774774
#endif /* USE_GLOBAL_CACHE */
775775

776+
777+
/*----------------------------------------------------------------------
778+
R_GetBindingType
779+
*/
780+
781+
R_BindingType R_GetBindingType(SEXP sym, SEXP env) {
782+
/* We are currently getting the location in the environment twice:
783+
* - In `R_BindingIsActive()`
784+
* - In `Rf_findVarInFrame3()`
785+
* Ideally we'd do it once, which would require manually walking
786+
* over the environment frame / hashtable and get the location to
787+
* inspect. */
788+
789+
if (TYPEOF(sym) != SYMSXP)
790+
error(_("not a symbol"));
791+
if (TYPEOF(env) != ENVSXP)
792+
error(_("not an environment"));
793+
794+
/* This check must be before `Rf_findVarInFrame3()` because that
795+
* forces active bindings */
796+
if (R_BindingIsActive(sym, env))
797+
return R_BindingTypeActive;
798+
799+
SEXP value = Rf_findVarInFrame3(env, sym, FALSE);
800+
801+
if (value == R_UnboundValue)
802+
return R_BindingTypeUnbound;
803+
804+
if (value == R_MissingArg)
805+
return R_BindingTypeMissing;
806+
807+
if (TYPEOF(value) == PROMSXP) {
808+
if (PROMISE_IS_EVALUATED(value))
809+
return R_BindingTypeForced;
810+
else
811+
return R_BindingTypeDelayed;
812+
}
813+
814+
return R_BindingTypeValue;
815+
}
816+
817+
776818
/*----------------------------------------------------------------------
777819
778820
unbindVar
@@ -3457,6 +3499,32 @@ void R_unLockBinding(SEXP sym, SEXP env)
34573499
}
34583500
}
34593501

3502+
void R_MakeDelayedBinding(SEXP sym, SEXP expr, SEXP evalEnv, SEXP env) {
3503+
if (TYPEOF(sym) != SYMSXP)
3504+
error(_("not a symbol"));
3505+
if (TYPEOF(env) != ENVSXP)
3506+
error(_("not an environment"));
3507+
if (TYPEOF(evalEnv) != ENVSXP)
3508+
error(_("not an environment"));
3509+
defineVar(sym, Rf_mkPROMISE(expr, evalEnv), env);
3510+
}
3511+
3512+
void R_MakeForcedBinding(SEXP sym, SEXP expr, SEXP value, SEXP env) {
3513+
if (TYPEOF(sym) != SYMSXP)
3514+
error(_("not a symbol"));
3515+
if (TYPEOF(env) != ENVSXP)
3516+
error(_("not an environment"));
3517+
defineVar(sym, R_mkEVPROMISE(expr, value), env);
3518+
}
3519+
3520+
void R_MakeMissingBinding(SEXP sym, SEXP env) {
3521+
if (TYPEOF(sym) != SYMSXP)
3522+
error(_("not a symbol"));
3523+
if (TYPEOF(env) != ENVSXP)
3524+
error(_("not an environment"));
3525+
defineVar(sym, R_MissingArg, env);
3526+
}
3527+
34603528
void R_MakeActiveBinding(SEXP sym, SEXP fun, SEXP env)
34613529
{
34623530
if (TYPEOF(sym) != SYMSXP)
@@ -3562,6 +3630,60 @@ attribute_hidden Rboolean R_HasFancyBindings(SEXP rho)
35623630
}
35633631
}
35643632

3633+
/* Equivalent to `substitute()`, but only supports promises */
3634+
SEXP R_DelayedBindingExpression(SEXP sym, SEXP env) {
3635+
if (TYPEOF(sym) != SYMSXP)
3636+
error(_("not a symbol"));
3637+
if (TYPEOF(env) != ENVSXP)
3638+
error(_("not an environment"));
3639+
3640+
SEXP value = Rf_findVarInFrame3(env, sym, FALSE);
3641+
3642+
if (TYPEOF(value) != PROMSXP)
3643+
error(_("not a promise"));
3644+
3645+
if (PROMISE_IS_EVALUATED(value))
3646+
error(_("not a delayed promise"));
3647+
3648+
/* This has special handling for bytecode, unlike `PREXPR()` */
3649+
return R_PromiseExpr(value);
3650+
}
3651+
3652+
SEXP R_DelayedBindingEnvironment(SEXP sym, SEXP env) {
3653+
if (TYPEOF(sym) != SYMSXP)
3654+
error(_("not a symbol"));
3655+
if (TYPEOF(env) != ENVSXP)
3656+
error(_("not an environment"));
3657+
3658+
SEXP value = Rf_findVarInFrame3(env, sym, FALSE);
3659+
3660+
if (TYPEOF(value) != PROMSXP)
3661+
error(_("not a promise"));
3662+
3663+
if (PROMISE_IS_EVALUATED(value))
3664+
error(_("not a delayed promise"));
3665+
3666+
return PRENV(value);
3667+
}
3668+
3669+
SEXP R_ForcedBindingExpression(SEXP sym, SEXP env) {
3670+
if (TYPEOF(sym) != SYMSXP)
3671+
error(_("not a symbol"));
3672+
if (TYPEOF(env) != ENVSXP)
3673+
error(_("not an environment"));
3674+
3675+
SEXP value = Rf_findVarInFrame3(env, sym, FALSE);
3676+
3677+
if (TYPEOF(value) != PROMSXP)
3678+
error(_("not a promise"));
3679+
3680+
if (!PROMISE_IS_EVALUATED(value))
3681+
error(_("not a forced promise"));
3682+
3683+
/* This has special handling for bytecode, unlike `PREXPR()` */
3684+
return R_PromiseExpr(value);
3685+
}
3686+
35653687
SEXP R_ActiveBindingFunction(SEXP sym, SEXP env)
35663688
{
35673689
if (TYPEOF(sym) != SYMSXP)
@@ -4633,4 +4755,3 @@ attribute_hidden void findFunctionForBody(SEXP body) {
46334755
}
46344756
}
46354757
}
4636-

0 commit comments

Comments
 (0)