From 11ee9dd668c24ff655cfec47610c8939e74a8506 Mon Sep 17 00:00:00 2001 From: Steffen Mueller Date: Fri, 21 Feb 2014 18:58:04 +0100 Subject: [PATCH] Macro for common OP checks: "is this X or was it before NULLing?" For example, if (OP_TYPE_IS_OR_WAS(o, OP_LIST)) ... is now available instead of either of the following: if ( o && ( o->op_type == OP_LIST || (o->op_type == OP_NULL && o->op_targ == OP_LIST) ) ) ... if ( o && (o->op_type == OP_NULL ? o->op_targ ? o->op_type) == OP_LIST ) ... In case the above logic is a bit unclear: It checks whether that OP is an OP_LIST or used to be one before being NULLed using op_null. (FTR, the resulting OP_NULLs have their op_targ set to the old OP type). This sort of check (and it's reverse "isn't and didn't use to be") are a relatively common pattern in the part of op.c that tries to intuit structures from optimization-mangled OP trees. Hopefully, using these macros will make some code a fair amount clearer. --- op.c | 3 +-- op.h | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/op.c b/op.c index 7bbae54..f17216c 100644 --- a/op.c +++ b/op.c @@ -5777,8 +5777,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right) o = newBINOP(OP_AASSIGN, flags, list(force_list(right)), curop); o->op_private = (U8)(0 | (flags >> 8)); - if ((left->op_type == OP_LIST - || (left->op_type == OP_NULL && left->op_targ == OP_LIST))) + if (OP_TYPE_IS_OR_WAS(left, OP_LIST)) { OP* lop = ((LISTOP*)left)->op_first; maybe_common_vars = FALSE; diff --git a/op.h b/op.h index ed9609d..a1c3c59 100644 --- a/op.h +++ b/op.h @@ -1006,8 +1006,23 @@ to the registree to ensure it is accurate. The value returned will be one of the OA_* constants from op.h. =for apidoc Am|bool|OP_TYPE_IS|OP *o, Optype type -Returns true if the given OP is not NULL and if it is of the given -type. +Returns true if the given OP is not a NULL pointer +and if it is of the given type. + +The negation of this macro, C is also available +as well as C and C which elide +the NULL pointer check. + +=for apidoc Am|bool|OP_TYPE_IS_OR_WAS|OP *o, Optype type +Returns true if the given OP is not a NULL pointer and +if it is of the given type or used to be before being +replaced by an OP of type OP_NULL. + +The negation of this macro, C +is also available as well as C +and C which elide +the NULL pointer check. + =cut */ @@ -1022,7 +1037,27 @@ type. : (PL_opargs[(o)->op_type] & OA_CLASS_MASK)) #define OP_TYPE_IS(o, type) ((o) && (o)->op_type == (type)) - +#define OP_TYPE_IS_NN(o, type) ((o)->op_type == (type)) +#define OP_TYPE_ISNT(o, type) ((o) && (o)->op_type != (type)) +#define OP_TYPE_ISNT_NN(o, type) ((o)->op_type != (type)) + +#define OP_TYPE_IS_OR_WAS_NN(o, type) \ + ( ((o)->op_type == OP_NULL \ + ? (o)->op_targ \ + : (o)->op_type) \ + == (type) ) + +#define OP_TYPE_IS_OR_WAS(o, type) \ + ( (o) && OP_TYPE_IS_OR_WAS_NN(o, type) ) + +#define OP_TYPE_ISNT_AND_WASNT_NN(o, type) \ + ( ((o)->op_type == OP_NULL \ + ? (o)->op_targ \ + : (o)->op_type) \ + != (type) ) + +#define OP_TYPE_ISNT_AND_WASNT(o, type) \ + ( (o) && OP_TYPE_ISNT_AND_WASNT_NN(o, type) ) #define newATTRSUB(f, o, p, a, b) Perl_newATTRSUB_x(aTHX_ f, o, p, a, b, FALSE) #define newSUB(f, o, p, b) newATTRSUB((f), (o), (p), NULL, (b)) -- 2.7.4