diff --git a/MANIFEST b/MANIFEST index eafba5ff84e0..9dc767cebc9a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -6366,6 +6366,7 @@ t/op/dor.t See if defined-or (//) works t/op/dump.t See if dump works. t/op/each.t See if hash iterators work t/op/each_array.t See if array iterators work +t/op/equ.t See if the equ operator works t/op/eval.t See if eval operator works t/op/evalbytes.t See if evalbytes operator works t/op/exec.t See if exec, system and qx work diff --git a/ext/Opcode/Opcode.pm b/ext/Opcode/Opcode.pm index 15d4d5be9bcf..6e470eab5598 100644 --- a/ext/Opcode/Opcode.pm +++ b/ext/Opcode/Opcode.pm @@ -1,4 +1,4 @@ -package Opcode 1.71; +package Opcode 1.72; use strict; @@ -319,8 +319,9 @@ invert_opset function. nbit_xor nbit_or sbit_and sbit_xor sbit_or negate i_negate not complement ncomplement scomplement - lt i_lt gt i_gt le i_le ge i_ge eq i_eq ne i_ne ncmp i_ncmp - slt sgt sle sge seq sne scmp + lt i_lt gt i_gt le i_le ge i_ge eq i_eq ne i_ne + equ i_equ neu i_neu ncmp i_ncmp + slt sgt sle sge seq sne sequ sneu scmp isa substr substr_left vec stringify study pos length index diff --git a/gv.c b/gv.c index 551794cf6fbd..d88d5be393c9 100644 --- a/gv.c +++ b/gv.c @@ -625,7 +625,7 @@ S_maybe_add_coresub(pTHX_ HV * const stash, GV *gv, case KEY_catch : case KEY_class : case KEY_cmp : case KEY_default : case KEY_defer : case KEY_do : case KEY_dump : case KEY_else : case KEY_elsif : - case KEY_eq : case KEY_eval : case KEY_field : + case KEY_eq : case KEY_equ : case KEY_eval : case KEY_field : case KEY_finally: case KEY_for : case KEY_foreach: case KEY_format: case KEY_ge : case KEY_given : case KEY_goto : case KEY_grep : case KEY_gt : @@ -633,7 +633,8 @@ S_maybe_add_coresub(pTHX_ HV * const stash, GV *gv, case KEY_last : case KEY_le : case KEY_local : case KEY_lt : case KEY_m : case KEY_map : case KEY_method : case KEY_my : - case KEY_ne : case KEY_next : case KEY_no: case KEY_or: case KEY_our: + case KEY_ne : case KEY_neu : case KEY_next : case KEY_no: + case KEY_or : case KEY_our : case KEY_package: case KEY_print: case KEY_printf: case KEY_q : case KEY_qq : case KEY_qr : case KEY_qw : case KEY_qx : case KEY_redo : case KEY_require: case KEY_return: @@ -3368,7 +3369,8 @@ Perl_gv_handler(pTHX_ HV *stash, I32 id) /* Implement tryAMAGICun_MG macro. Do get magic, then see if the stack arg is overloaded and if so call it. Flags: - AMGf_numeric apply sv_2num to the stack arg. + AMGf_numeric apply sv_2num to the stack arg. + AMGf_no_GETMAGIC do not call SvGETMAGIC on arguments */ bool @@ -3380,7 +3382,8 @@ Perl_try_amagic_un(pTHX_ int method, int flags) SV* const arg = PL_stack_sp[0]; bool is_rc = rpp_stack_is_rc(); - SvGETMAGIC(arg); + if (LIKELY(!(flags & AMGf_no_GETMAGIC))) + SvGETMAGIC(arg); if (SvAMAGIC(arg) && (tmpsv = amagic_call(arg, &PL_sv_undef, method, AMGf_noright | AMGf_unary @@ -3573,8 +3576,9 @@ Perl_amagic_applies(pTHX_ SV *sv, int method, int flags) Do get magic, then see if the two stack args are overloaded and if so call it. Flags: - AMGf_assign op may be called as mutator (eg +=) - AMGf_numeric apply sv_2num to the stack arg. + AMGf_assign op may be called as mutator (eg +=) + AMGf_numeric apply sv_2num to the stack arg. + AMGf_no_GETMAGIC do not call SvGETMAGIC on arguments */ bool @@ -3586,9 +3590,11 @@ Perl_try_amagic_bin(pTHX_ int method, int flags) SV* right = PL_stack_sp[0]; bool is_rc = rpp_stack_is_rc(); - SvGETMAGIC(left); - if (left != right) - SvGETMAGIC(right); + if (LIKELY(!(flags & AMGf_no_GETMAGIC))) { + SvGETMAGIC(left); + if (left != right) + SvGETMAGIC(right); + } if (SvAMAGIC(left) || SvAMAGIC(right)) { SV * tmpsv; diff --git a/keywords.c b/keywords.c index 12135184cf64..792d67dbaa42 100644 --- a/keywords.c +++ b/keywords.c @@ -203,7 +203,7 @@ Perl_keyword (pTHX_ const char *name, I32 len, bool all_keywords) goto unknown; } - case 3: /* 32 tokens of length 3 */ + case 3: /* 34 tokens of length 3 */ switch (name[0]) { case 'E': @@ -306,6 +306,14 @@ Perl_keyword (pTHX_ const char *name, I32 len, bool all_keywords) goto unknown; + case 'q': + if (name[2] == 'u') + { /* equ */ + return -KEY_equ; + } + + goto unknown; + case 'x': if (name[2] == 'p') { /* exp */ @@ -378,13 +386,27 @@ Perl_keyword (pTHX_ const char *name, I32 len, bool all_keywords) goto unknown; case 'n': - if (name[1] == 'o' && - name[2] == 't') - { /* not */ - return -KEY_not; - } + switch (name[1]) + { + case 'e': + if (name[2] == 'u') + { /* neu */ + return -KEY_neu; + } - goto unknown; + goto unknown; + + case 'o': + if (name[2] == 't') + { /* not */ + return -KEY_not; + } + + goto unknown; + + default: + goto unknown; + } case 'o': switch (name[1]) @@ -3590,5 +3612,5 @@ Perl_keyword (pTHX_ const char *name, I32 len, bool all_keywords) } /* Generated from: - * bdfd5529dba8257e060f7e4ed712f683cd6a533285abf8ce7ee78c4d0677ff38 regen/keywords.pl + * 6314472316769769d8176b08a4b0fe3c461bc38d52170a303f7abd00c5a56677 regen/keywords.pl * ex: set ro ft=c: */ diff --git a/keywords.h b/keywords.h index 9e480508372b..32112b8416c3 100644 --- a/keywords.h +++ b/keywords.h @@ -77,210 +77,212 @@ #define KEY_endservent 61 #define KEY_eof 62 #define KEY_eq 63 -#define KEY_eval 64 -#define KEY_evalbytes 65 -#define KEY_exec 66 -#define KEY_exists 67 -#define KEY_exit 68 -#define KEY_exp 69 -#define KEY_fc 70 -#define KEY_fcntl 71 -#define KEY_field 72 -#define KEY_fileno 73 -#define KEY_finally 74 -#define KEY_flock 75 -#define KEY_for 76 -#define KEY_foreach 77 -#define KEY_fork 78 -#define KEY_format 79 -#define KEY_formline 80 -#define KEY_ge 81 -#define KEY_getc 82 -#define KEY_getgrent 83 -#define KEY_getgrgid 84 -#define KEY_getgrnam 85 -#define KEY_gethostbyaddr 86 -#define KEY_gethostbyname 87 -#define KEY_gethostent 88 -#define KEY_getlogin 89 -#define KEY_getnetbyaddr 90 -#define KEY_getnetbyname 91 -#define KEY_getnetent 92 -#define KEY_getpeername 93 -#define KEY_getpgrp 94 -#define KEY_getppid 95 -#define KEY_getpriority 96 -#define KEY_getprotobyname 97 -#define KEY_getprotobynumber 98 -#define KEY_getprotoent 99 -#define KEY_getpwent 100 -#define KEY_getpwnam 101 -#define KEY_getpwuid 102 -#define KEY_getservbyname 103 -#define KEY_getservbyport 104 -#define KEY_getservent 105 -#define KEY_getsockname 106 -#define KEY_getsockopt 107 -#define KEY_given 108 -#define KEY_glob 109 -#define KEY_gmtime 110 -#define KEY_goto 111 -#define KEY_grep 112 -#define KEY_gt 113 -#define KEY_hex 114 -#define KEY_if 115 -#define KEY_index 116 -#define KEY_int 117 -#define KEY_ioctl 118 -#define KEY_isa 119 -#define KEY_join 120 -#define KEY_keys 121 -#define KEY_kill 122 -#define KEY_last 123 -#define KEY_lc 124 -#define KEY_lcfirst 125 -#define KEY_le 126 -#define KEY_length 127 -#define KEY_link 128 -#define KEY_listen 129 -#define KEY_local 130 -#define KEY_localtime 131 -#define KEY_lock 132 -#define KEY_log 133 -#define KEY_lstat 134 -#define KEY_lt 135 -#define KEY_m 136 -#define KEY_map 137 -#define KEY_method 138 -#define KEY_mkdir 139 -#define KEY_msgctl 140 -#define KEY_msgget 141 -#define KEY_msgrcv 142 -#define KEY_msgsnd 143 -#define KEY_my 144 -#define KEY_ne 145 -#define KEY_next 146 -#define KEY_no 147 -#define KEY_not 148 -#define KEY_oct 149 -#define KEY_open 150 -#define KEY_opendir 151 -#define KEY_or 152 -#define KEY_ord 153 -#define KEY_our 154 -#define KEY_pack 155 -#define KEY_package 156 -#define KEY_pipe 157 -#define KEY_pop 158 -#define KEY_pos 159 -#define KEY_print 160 -#define KEY_printf 161 -#define KEY_prototype 162 -#define KEY_push 163 -#define KEY_q 164 -#define KEY_qq 165 -#define KEY_qr 166 -#define KEY_quotemeta 167 -#define KEY_qw 168 -#define KEY_qx 169 -#define KEY_rand 170 -#define KEY_read 171 -#define KEY_readdir 172 -#define KEY_readline 173 -#define KEY_readlink 174 -#define KEY_readpipe 175 -#define KEY_recv 176 -#define KEY_redo 177 -#define KEY_ref 178 -#define KEY_rename 179 -#define KEY_require 180 -#define KEY_reset 181 -#define KEY_return 182 -#define KEY_reverse 183 -#define KEY_rewinddir 184 -#define KEY_rindex 185 -#define KEY_rmdir 186 -#define KEY_s 187 -#define KEY_say 188 -#define KEY_scalar 189 -#define KEY_seek 190 -#define KEY_seekdir 191 -#define KEY_select 192 -#define KEY_semctl 193 -#define KEY_semget 194 -#define KEY_semop 195 -#define KEY_send 196 -#define KEY_setgrent 197 -#define KEY_sethostent 198 -#define KEY_setnetent 199 -#define KEY_setpgrp 200 -#define KEY_setpriority 201 -#define KEY_setprotoent 202 -#define KEY_setpwent 203 -#define KEY_setservent 204 -#define KEY_setsockopt 205 -#define KEY_shift 206 -#define KEY_shmctl 207 -#define KEY_shmget 208 -#define KEY_shmread 209 -#define KEY_shmwrite 210 -#define KEY_shutdown 211 -#define KEY_sin 212 -#define KEY_sleep 213 -#define KEY_socket 214 -#define KEY_socketpair 215 -#define KEY_sort 216 -#define KEY_splice 217 -#define KEY_split 218 -#define KEY_sprintf 219 -#define KEY_sqrt 220 -#define KEY_srand 221 -#define KEY_stat 222 -#define KEY_state 223 -#define KEY_study 224 -#define KEY_sub 225 -#define KEY_substr 226 -#define KEY_symlink 227 -#define KEY_syscall 228 -#define KEY_sysopen 229 -#define KEY_sysread 230 -#define KEY_sysseek 231 -#define KEY_system 232 -#define KEY_syswrite 233 -#define KEY_tell 234 -#define KEY_telldir 235 -#define KEY_tie 236 -#define KEY_tied 237 -#define KEY_time 238 -#define KEY_times 239 -#define KEY_tr 240 -#define KEY_truncate 241 -#define KEY_try 242 -#define KEY_uc 243 -#define KEY_ucfirst 244 -#define KEY_umask 245 -#define KEY_undef 246 -#define KEY_unless 247 -#define KEY_unlink 248 -#define KEY_unpack 249 -#define KEY_unshift 250 -#define KEY_untie 251 -#define KEY_until 252 -#define KEY_use 253 -#define KEY_utime 254 -#define KEY_values 255 -#define KEY_vec 256 -#define KEY_wait 257 -#define KEY_waitpid 258 -#define KEY_wantarray 259 -#define KEY_warn 260 -#define KEY_when 261 -#define KEY_while 262 -#define KEY_write 263 -#define KEY_x 264 -#define KEY_xor 265 -#define KEY_y 266 +#define KEY_equ 64 +#define KEY_eval 65 +#define KEY_evalbytes 66 +#define KEY_exec 67 +#define KEY_exists 68 +#define KEY_exit 69 +#define KEY_exp 70 +#define KEY_fc 71 +#define KEY_fcntl 72 +#define KEY_field 73 +#define KEY_fileno 74 +#define KEY_finally 75 +#define KEY_flock 76 +#define KEY_for 77 +#define KEY_foreach 78 +#define KEY_fork 79 +#define KEY_format 80 +#define KEY_formline 81 +#define KEY_ge 82 +#define KEY_getc 83 +#define KEY_getgrent 84 +#define KEY_getgrgid 85 +#define KEY_getgrnam 86 +#define KEY_gethostbyaddr 87 +#define KEY_gethostbyname 88 +#define KEY_gethostent 89 +#define KEY_getlogin 90 +#define KEY_getnetbyaddr 91 +#define KEY_getnetbyname 92 +#define KEY_getnetent 93 +#define KEY_getpeername 94 +#define KEY_getpgrp 95 +#define KEY_getppid 96 +#define KEY_getpriority 97 +#define KEY_getprotobyname 98 +#define KEY_getprotobynumber 99 +#define KEY_getprotoent 100 +#define KEY_getpwent 101 +#define KEY_getpwnam 102 +#define KEY_getpwuid 103 +#define KEY_getservbyname 104 +#define KEY_getservbyport 105 +#define KEY_getservent 106 +#define KEY_getsockname 107 +#define KEY_getsockopt 108 +#define KEY_given 109 +#define KEY_glob 110 +#define KEY_gmtime 111 +#define KEY_goto 112 +#define KEY_grep 113 +#define KEY_gt 114 +#define KEY_hex 115 +#define KEY_if 116 +#define KEY_index 117 +#define KEY_int 118 +#define KEY_ioctl 119 +#define KEY_isa 120 +#define KEY_join 121 +#define KEY_keys 122 +#define KEY_kill 123 +#define KEY_last 124 +#define KEY_lc 125 +#define KEY_lcfirst 126 +#define KEY_le 127 +#define KEY_length 128 +#define KEY_link 129 +#define KEY_listen 130 +#define KEY_local 131 +#define KEY_localtime 132 +#define KEY_lock 133 +#define KEY_log 134 +#define KEY_lstat 135 +#define KEY_lt 136 +#define KEY_m 137 +#define KEY_map 138 +#define KEY_method 139 +#define KEY_mkdir 140 +#define KEY_msgctl 141 +#define KEY_msgget 142 +#define KEY_msgrcv 143 +#define KEY_msgsnd 144 +#define KEY_my 145 +#define KEY_ne 146 +#define KEY_neu 147 +#define KEY_next 148 +#define KEY_no 149 +#define KEY_not 150 +#define KEY_oct 151 +#define KEY_open 152 +#define KEY_opendir 153 +#define KEY_or 154 +#define KEY_ord 155 +#define KEY_our 156 +#define KEY_pack 157 +#define KEY_package 158 +#define KEY_pipe 159 +#define KEY_pop 160 +#define KEY_pos 161 +#define KEY_print 162 +#define KEY_printf 163 +#define KEY_prototype 164 +#define KEY_push 165 +#define KEY_q 166 +#define KEY_qq 167 +#define KEY_qr 168 +#define KEY_quotemeta 169 +#define KEY_qw 170 +#define KEY_qx 171 +#define KEY_rand 172 +#define KEY_read 173 +#define KEY_readdir 174 +#define KEY_readline 175 +#define KEY_readlink 176 +#define KEY_readpipe 177 +#define KEY_recv 178 +#define KEY_redo 179 +#define KEY_ref 180 +#define KEY_rename 181 +#define KEY_require 182 +#define KEY_reset 183 +#define KEY_return 184 +#define KEY_reverse 185 +#define KEY_rewinddir 186 +#define KEY_rindex 187 +#define KEY_rmdir 188 +#define KEY_s 189 +#define KEY_say 190 +#define KEY_scalar 191 +#define KEY_seek 192 +#define KEY_seekdir 193 +#define KEY_select 194 +#define KEY_semctl 195 +#define KEY_semget 196 +#define KEY_semop 197 +#define KEY_send 198 +#define KEY_setgrent 199 +#define KEY_sethostent 200 +#define KEY_setnetent 201 +#define KEY_setpgrp 202 +#define KEY_setpriority 203 +#define KEY_setprotoent 204 +#define KEY_setpwent 205 +#define KEY_setservent 206 +#define KEY_setsockopt 207 +#define KEY_shift 208 +#define KEY_shmctl 209 +#define KEY_shmget 210 +#define KEY_shmread 211 +#define KEY_shmwrite 212 +#define KEY_shutdown 213 +#define KEY_sin 214 +#define KEY_sleep 215 +#define KEY_socket 216 +#define KEY_socketpair 217 +#define KEY_sort 218 +#define KEY_splice 219 +#define KEY_split 220 +#define KEY_sprintf 221 +#define KEY_sqrt 222 +#define KEY_srand 223 +#define KEY_stat 224 +#define KEY_state 225 +#define KEY_study 226 +#define KEY_sub 227 +#define KEY_substr 228 +#define KEY_symlink 229 +#define KEY_syscall 230 +#define KEY_sysopen 231 +#define KEY_sysread 232 +#define KEY_sysseek 233 +#define KEY_system 234 +#define KEY_syswrite 235 +#define KEY_tell 236 +#define KEY_telldir 237 +#define KEY_tie 238 +#define KEY_tied 239 +#define KEY_time 240 +#define KEY_times 241 +#define KEY_tr 242 +#define KEY_truncate 243 +#define KEY_try 244 +#define KEY_uc 245 +#define KEY_ucfirst 246 +#define KEY_umask 247 +#define KEY_undef 248 +#define KEY_unless 249 +#define KEY_unlink 250 +#define KEY_unpack 251 +#define KEY_unshift 252 +#define KEY_untie 253 +#define KEY_until 254 +#define KEY_use 255 +#define KEY_utime 256 +#define KEY_values 257 +#define KEY_vec 258 +#define KEY_wait 259 +#define KEY_waitpid 260 +#define KEY_wantarray 261 +#define KEY_warn 262 +#define KEY_when 263 +#define KEY_while 264 +#define KEY_write 265 +#define KEY_x 266 +#define KEY_xor 267 +#define KEY_y 268 /* Generated from: - * bdfd5529dba8257e060f7e4ed712f683cd6a533285abf8ce7ee78c4d0677ff38 regen/keywords.pl + * 6314472316769769d8176b08a4b0fe3c461bc38d52170a303f7abd00c5a56677 regen/keywords.pl * ex: set ro ft=c: */ diff --git a/lib/B/Deparse-core.t b/lib/B/Deparse-core.t index 7fcb7d8d9ef4..858e956759f5 100644 --- a/lib/B/Deparse-core.t +++ b/lib/B/Deparse-core.t @@ -508,6 +508,7 @@ endpwent 0 - endservent 0 - eof 01 - # also tested specially eq B - +equ B - eval 01 $+ evalbytes 01 $ exec @ p1 # also tested specially @@ -582,6 +583,7 @@ msgrcv 5 p msgsnd 3 p my 123 p+ # skip with 0 args, as my() => () ne B - +neu B - # next handled specially # not handled specially oct 01 $ diff --git a/lib/B/Deparse.pm b/lib/B/Deparse.pm index 00e54221c27c..f4acc5c48b1b 100644 --- a/lib/B/Deparse.pm +++ b/lib/B/Deparse.pm @@ -7,7 +7,7 @@ # This is based on the module of the same name by Malcolm Beattie, # but essentially none of his code remains. -package B::Deparse 1.89; +package B::Deparse 1.90; use strict; use builtin qw( true false ); use Carp; @@ -3383,6 +3383,11 @@ sub pp_i_ge { binop(@_, ">=", 15) } sub pp_i_le { binop(@_, "<=", 15) } sub pp_i_ncmp { maybe_targmy(@_, \&binop, "<=>", 14) } +sub pp_equ { binop(@_, "===", 14) } +sub pp_neu { binop(@_, "!==", 14) } +sub pp_i_equ { binop(@_, "===", 14) } +sub pp_i_neu { binop(@_, "!==", 14) } + sub pp_seq { binop(@_, "eq", 14) } sub pp_sne { binop(@_, "ne", 14) } sub pp_slt { binop(@_, "lt", 15) } @@ -3391,6 +3396,9 @@ sub pp_sge { binop(@_, "ge", 15) } sub pp_sle { binop(@_, "le", 15) } sub pp_scmp { maybe_targmy(@_, \&binop, "cmp", 14) } +sub pp_sequ { binop(@_, "equ", 14) } +sub pp_sneu { binop(@_, "neu", 14) } + sub pp_isa { binop(@_, "isa", 15) } sub pp_sassign { binop(@_, "=", 7, SWAP_CHILDREN) } diff --git a/lib/B/Op_private.pm b/lib/B/Op_private.pm index 97327a9f93bd..1d147ca29a4d 100644 --- a/lib/B/Op_private.pm +++ b/lib/B/Op_private.pm @@ -346,6 +346,7 @@ $bits{enterwhen}{0} = $bf[0]; @{$bits{enterwrite}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{eof}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{eq}}{1,0} = ($bf[1], $bf[1]); +@{$bits{equ}}{1,0} = ($bf[1], $bf[1]); @{$bits{exec}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{exists}}{6,0} = ('OPpEXISTS_SUB', $bf[0]); @{$bits{exit}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @@ -418,6 +419,7 @@ $bits{hex}{0} = $bf[0]; @{$bits{i_add}}{1,0} = ($bf[1], $bf[1]); @{$bits{i_divide}}{1,0} = ($bf[1], $bf[1]); @{$bits{i_eq}}{1,0} = ($bf[1], $bf[1]); +@{$bits{i_equ}}{1,0} = ($bf[1], $bf[1]); @{$bits{i_ge}}{1,0} = ($bf[1], $bf[1]); @{$bits{i_gt}}{1,0} = ($bf[1], $bf[1]); @{$bits{i_le}}{1,0} = ($bf[1], $bf[1]); @@ -427,6 +429,7 @@ $bits{hex}{0} = $bf[0]; @{$bits{i_ncmp}}{1,0} = ($bf[1], $bf[1]); @{$bits{i_ne}}{1,0} = ($bf[1], $bf[1]); $bits{i_negate}{0} = $bf[0]; +@{$bits{i_neu}}{1,0} = ($bf[1], $bf[1]); $bits{i_postdec}{0} = $bf[0]; $bits{i_postinc}{0} = $bf[0]; $bits{i_predec}{0} = $bf[0]; @@ -488,6 +491,7 @@ $bits{multiparam}{0} = $bf[0]; @{$bits{ncmp}}{1,0} = ($bf[1], $bf[1]); @{$bits{ne}}{1,0} = ($bf[1], $bf[1]); $bits{negate}{0} = $bf[0]; +@{$bits{neu}}{1,0} = ($bf[1], $bf[1]); $bits{next}{0} = $bf[0]; $bits{not}{0} = $bf[0]; $bits{oct}{0} = $bf[0]; @@ -559,6 +563,7 @@ $bits{scomplement}{0} = $bf[0]; @{$bits{semop}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{send}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{seq}}{1,0} = ($bf[1], $bf[1]); +@{$bits{sequ}}{1,0} = ($bf[1], $bf[1]); @{$bits{setpgrp}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{setpriority}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{sge}}{1,0} = ($bf[1], $bf[1]); @@ -577,6 +582,7 @@ $bits{sin}{0} = $bf[0]; @{$bits{smartmatch}}{1,0} = ($bf[1], $bf[1]); @{$bits{sne}}{1,0} = ($bf[1], $bf[1]); $bits{snetent}{0} = $bf[0]; +@{$bits{sneu}}{1,0} = ($bf[1], $bf[1]); @{$bits{socket}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{sockpair}}{3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5]); @{$bits{sort}}{4,3,2,1,0} = ('OPpSORT_DESCEND', 'OPpSORT_INPLACE', 'OPpSORT_REVERSE', 'OPpSORT_INTEGER', 'OPpSORT_NUMERIC'); diff --git a/lib/overload.pm b/lib/overload.pm index 03ad240a9cbb..ec5dbc38f622 100644 --- a/lib/overload.pm +++ b/lib/overload.pm @@ -1,10 +1,8 @@ -package overload; +package overload 1.42; -use strict; +use v5.42; no strict 'refs'; -our $VERSION = '1.40'; - our %ops = ( with_assign => "+ - * / % ** << >> x .", assign => "+= -= *= /= %= **= <<= >>= x= .=", @@ -99,7 +97,6 @@ sub OverloadedStringify { sub Method { my $package = shift; if (ref $package) { - no warnings 'experimental::builtin'; $package = builtin::blessed($package); return undef if !defined $package; } @@ -580,6 +577,23 @@ See L>. =back +There are also some operators that perl does not allow to be directly +overloaded. + +=over 5 + +=item * I + + === !== equ neu + +The four undef-aware equality operators do not allow specific overloading. +They are internally implemented in terms of a C test (which itself +cannot be overloaded), combined with a following call to the base +non undef-aware versions of those operators. This call will use any +overloading behaviour defined by those regular operators. + +=back + =head2 Magic Autogeneration If a method for an operation is not found then Perl tries to diff --git a/opcode.h b/opcode.h index 31277f087375..ab3144412dcc 100644 --- a/opcode.h +++ b/opcode.h @@ -232,6 +232,10 @@ EXTCONST char* const PL_op_name[] INIT({ "i_eq", "ne", "i_ne", + "equ", + "i_equ", + "neu", + "i_neu", "ncmp", "i_ncmp", "slt", @@ -240,6 +244,8 @@ EXTCONST char* const PL_op_name[] INIT({ "sge", "seq", "sne", + "sequ", + "sneu", "scmp", "bit_and", "bit_xor", @@ -665,6 +671,10 @@ EXTCONST char* const PL_op_desc[] INIT({ "integer eq (==)", "numeric ne (!=)", "integer ne (!=)", + "undef-aware numeric eq (===)", + "undef-aware integer eq (===)", + "undef-aware numeric ne (!==)", + "undef-aware integer ne (!==)", "numeric comparison (<=>)", "integer comparison (<=>)", "string lt", @@ -673,6 +683,8 @@ EXTCONST char* const PL_op_desc[] INIT({ "string ge", "string eq", "string ne", + "undef-aware string eq", + "undef-aware string ne", "string comparison (cmp)", "bitwise and (&)", "bitwise xor (^)", @@ -1103,6 +1115,10 @@ INIT({ Perl_pp_i_eq, Perl_pp_ne, Perl_pp_i_ne, + Perl_pp_equ, + Perl_pp_i_equ, + Perl_pp_neu, + Perl_pp_i_neu, Perl_pp_ncmp, Perl_pp_i_ncmp, Perl_pp_slt, /* implemented by Perl_pp_sle */ @@ -1111,6 +1127,8 @@ INIT({ Perl_pp_sge, /* implemented by Perl_pp_sle */ Perl_pp_seq, Perl_pp_sne, + Perl_pp_sequ, + Perl_pp_sneu, Perl_pp_scmp, Perl_pp_bit_and, Perl_pp_bit_xor, /* implemented by Perl_pp_bit_or */ @@ -1536,6 +1554,10 @@ INIT({ Perl_ck_cmp, /* i_eq */ Perl_ck_cmp, /* ne */ Perl_ck_cmp, /* i_ne */ + Perl_ck_cmp, /* equ */ + Perl_ck_cmp, /* i_equ */ + Perl_ck_cmp, /* neu */ + Perl_ck_cmp, /* i_neu */ Perl_ck_null, /* ncmp */ Perl_ck_null, /* i_ncmp */ Perl_ck_scmp, /* slt */ @@ -1544,6 +1566,8 @@ INIT({ Perl_ck_scmp, /* sge */ Perl_ck_scmp, /* seq */ Perl_ck_scmp, /* sne */ + Perl_ck_scmp, /* sequ */ + Perl_ck_scmp, /* sneu */ Perl_ck_null, /* scmp */ Perl_ck_bitop, /* bit_and */ Perl_ck_bitop, /* bit_xor */ @@ -1897,9 +1921,9 @@ INIT({ /* Indexes into PL_check for the comparison function pointers */ #ifdef PERL_IN_PEEP_C - #define PERL_CK_NULL 429 - #define PERL_CK_EXISTS 430 - #define PERL_CK_DELETE 431 + #define PERL_CK_NULL 435 + #define PERL_CK_EXISTS 436 + #define PERL_CK_DELETE 437 #endif EXTCONST U32 PL_opargs[] INIT({ @@ -1987,6 +2011,10 @@ EXTCONST U32 PL_opargs[] INIT({ 0x00011206, /* i_eq */ 0x00011226, /* ne */ 0x00011206, /* i_ne */ + 0x00011226, /* equ */ + 0x00011206, /* i_equ */ + 0x00011226, /* neu */ + 0x00011206, /* i_neu */ 0x0001122e, /* ncmp */ 0x0001120e, /* i_ncmp */ 0x00011206, /* slt */ @@ -1995,6 +2023,8 @@ EXTCONST U32 PL_opargs[] INIT({ 0x00011206, /* sge */ 0x00011206, /* seq */ 0x00011206, /* sne */ + 0x00011206, /* sequ */ + 0x00011206, /* sneu */ 0x0001120e, /* scmp */ 0x0001120e, /* bit_and */ 0x0001120e, /* bit_xor */ @@ -2716,6 +2746,10 @@ EXTCONST I16 PL_op_private_bitdef_ix[] INIT( { 13, /* i_eq */ 13, /* ne */ 13, /* i_ne */ + 13, /* equ */ + 13, /* i_equ */ + 13, /* neu */ + 13, /* i_neu */ 13, /* ncmp */ 13, /* i_ncmp */ 13, /* slt */ @@ -2724,6 +2758,8 @@ EXTCONST I16 PL_op_private_bitdef_ix[] INIT( { 13, /* sge */ 13, /* seq */ 13, /* sne */ + 13, /* sequ */ + 13, /* sneu */ 13, /* scmp */ 105, /* bit_and */ 105, /* bit_xor */ @@ -3085,7 +3121,7 @@ EXTCONST U16 PL_op_private_bitdefs[] INIT( { 0x077e, 0x0554, 0x1b70, 0x576c, 0x5268, 0x4225, /* const */ 0x3cfc, 0x47f9, /* gvsv */ 0x19d5, /* gv */ - 0x0067, /* gelem, lt, i_lt, gt, i_gt, le, i_le, ge, i_ge, eq, i_eq, ne, i_ne, ncmp, i_ncmp, slt, sgt, sle, sge, seq, sne, scmp, smartmatch, lslice, xor, isa */ + 0x0067, /* gelem, lt, i_lt, gt, i_gt, le, i_le, ge, i_ge, eq, i_eq, ne, i_ne, equ, i_equ, neu, i_neu, ncmp, i_ncmp, slt, sgt, sle, sge, seq, sne, sequ, sneu, scmp, smartmatch, lslice, xor, isa */ 0x3cfc, 0x5618, 0x04f7, /* padsv */ 0x3cfc, 0x5618, 0x0003, /* padsv_store, lvavref */ 0x3cfc, 0x5618, 0x06d4, 0x3dec, 0x53e9, /* padav */ @@ -3255,6 +3291,10 @@ EXTCONST U8 PL_op_private_valid[] INIT( { /* I_EQ */ (OPpARG2_MASK), /* NE */ (OPpARG2_MASK), /* I_NE */ (OPpARG2_MASK), + /* EQU */ (OPpARG2_MASK), + /* I_EQU */ (OPpARG2_MASK), + /* NEU */ (OPpARG2_MASK), + /* I_NEU */ (OPpARG2_MASK), /* NCMP */ (OPpARG2_MASK), /* I_NCMP */ (OPpARG2_MASK), /* SLT */ (OPpARG2_MASK), @@ -3263,6 +3303,8 @@ EXTCONST U8 PL_op_private_valid[] INIT( { /* SGE */ (OPpARG2_MASK), /* SEQ */ (OPpARG2_MASK), /* SNE */ (OPpARG2_MASK), + /* SEQU */ (OPpARG2_MASK), + /* SNEU */ (OPpARG2_MASK), /* SCMP */ (OPpARG2_MASK), /* BIT_AND */ (OPpUSEINT), /* BIT_XOR */ (OPpUSEINT), diff --git a/opnames.h b/opnames.h index f234c328dde7..ade015289090 100644 --- a/opnames.h +++ b/opnames.h @@ -98,351 +98,357 @@ typedef enum opcode { OP_I_EQ = 81, OP_NE = 82, OP_I_NE = 83, - OP_NCMP = 84, - OP_I_NCMP = 85, - OP_SLT = 86, - OP_SGT = 87, - OP_SLE = 88, - OP_SGE = 89, - OP_SEQ = 90, - OP_SNE = 91, - OP_SCMP = 92, - OP_BIT_AND = 93, - OP_BIT_XOR = 94, - OP_BIT_OR = 95, - OP_NBIT_AND = 96, - OP_NBIT_XOR = 97, - OP_NBIT_OR = 98, - OP_SBIT_AND = 99, - OP_SBIT_XOR = 100, - OP_SBIT_OR = 101, - OP_NEGATE = 102, - OP_I_NEGATE = 103, - OP_NOT = 104, - OP_COMPLEMENT = 105, - OP_NCOMPLEMENT = 106, - OP_SCOMPLEMENT = 107, - OP_SMARTMATCH = 108, - OP_ATAN2 = 109, - OP_SIN = 110, - OP_COS = 111, - OP_RAND = 112, - OP_SRAND = 113, - OP_EXP = 114, - OP_LOG = 115, - OP_SQRT = 116, - OP_INT = 117, - OP_HEX = 118, - OP_OCT = 119, - OP_ABS = 120, - OP_LENGTH = 121, - OP_SUBSTR = 122, - OP_SUBSTR_LEFT = 123, - OP_VEC = 124, - OP_INDEX = 125, - OP_RINDEX = 126, - OP_SPRINTF = 127, - OP_FORMLINE = 128, - OP_ORD = 129, - OP_CHR = 130, - OP_CRYPT = 131, - OP_UCFIRST = 132, - OP_LCFIRST = 133, - OP_UC = 134, - OP_LC = 135, - OP_QUOTEMETA = 136, - OP_RV2AV = 137, - OP_AELEMFAST = 138, - OP_AELEMFAST_LEX = 139, - OP_AELEMFASTLEX_STORE = 140, - OP_AELEM = 141, - OP_ASLICE = 142, - OP_KVASLICE = 143, - OP_AEACH = 144, - OP_AVALUES = 145, - OP_AKEYS = 146, - OP_EACH = 147, - OP_VALUES = 148, - OP_KEYS = 149, - OP_DELETE = 150, - OP_EXISTS = 151, - OP_RV2HV = 152, - OP_HELEM = 153, - OP_HSLICE = 154, - OP_KVHSLICE = 155, - OP_MULTIDEREF = 156, - OP_UNPACK = 157, - OP_PACK = 158, - OP_SPLIT = 159, - OP_JOIN = 160, - OP_LIST = 161, - OP_LSLICE = 162, - OP_ANONLIST = 163, - OP_ANONHASH = 164, - OP_EMPTYAVHV = 165, - OP_SPLICE = 166, - OP_PUSH = 167, - OP_POP = 168, - OP_SHIFT = 169, - OP_UNSHIFT = 170, - OP_SORT = 171, - OP_REVERSE = 172, - OP_GREPSTART = 173, - OP_GREPWHILE = 174, - OP_ANYSTART = 175, - OP_ALLSTART = 176, - OP_ANYWHILE = 177, - OP_MAPSTART = 178, - OP_MAPWHILE = 179, - OP_RANGE = 180, - OP_FLIP = 181, - OP_FLOP = 182, - OP_AND = 183, - OP_OR = 184, - OP_XOR = 185, - OP_DOR = 186, - OP_COND_EXPR = 187, - OP_ANDASSIGN = 188, - OP_ORASSIGN = 189, - OP_DORASSIGN = 190, - OP_ENTERSUB = 191, - OP_LEAVESUB = 192, - OP_LEAVESUBLV = 193, - OP_ARGCHECK = 194, - OP_ARGELEM = 195, - OP_ARGDEFELEM = 196, - OP_CALLER = 197, - OP_WARN = 198, - OP_DIE = 199, - OP_RESET = 200, - OP_LINESEQ = 201, - OP_NEXTSTATE = 202, - OP_DBSTATE = 203, - OP_UNSTACK = 204, - OP_ENTER = 205, - OP_LEAVE = 206, - OP_SCOPE = 207, - OP_ENTERITER = 208, - OP_ITER = 209, - OP_ENTERLOOP = 210, - OP_LEAVELOOP = 211, - OP_RETURN = 212, - OP_LAST = 213, - OP_NEXT = 214, - OP_REDO = 215, - OP_DUMP = 216, - OP_GOTO = 217, - OP_EXIT = 218, - OP_METHOD = 219, - OP_METHOD_NAMED = 220, - OP_METHOD_SUPER = 221, - OP_METHOD_REDIR = 222, - OP_METHOD_REDIR_SUPER = 223, - OP_ENTERGIVEN = 224, - OP_LEAVEGIVEN = 225, - OP_ENTERWHEN = 226, - OP_LEAVEWHEN = 227, - OP_BREAK = 228, - OP_CONTINUE = 229, - OP_OPEN = 230, - OP_CLOSE = 231, - OP_PIPE_OP = 232, - OP_FILENO = 233, - OP_UMASK = 234, - OP_BINMODE = 235, - OP_TIE = 236, - OP_UNTIE = 237, - OP_TIED = 238, - OP_DBMOPEN = 239, - OP_DBMCLOSE = 240, - OP_SSELECT = 241, - OP_SELECT = 242, - OP_GETC = 243, - OP_READ = 244, - OP_ENTERWRITE = 245, - OP_LEAVEWRITE = 246, - OP_PRTF = 247, - OP_PRINT = 248, - OP_SAY = 249, - OP_SYSOPEN = 250, - OP_SYSSEEK = 251, - OP_SYSREAD = 252, - OP_SYSWRITE = 253, - OP_EOF = 254, - OP_TELL = 255, - OP_SEEK = 256, - OP_TRUNCATE = 257, - OP_FCNTL = 258, - OP_IOCTL = 259, - OP_FLOCK = 260, - OP_SEND = 261, - OP_RECV = 262, - OP_SOCKET = 263, - OP_SOCKPAIR = 264, - OP_BIND = 265, - OP_CONNECT = 266, - OP_LISTEN = 267, - OP_ACCEPT = 268, - OP_SHUTDOWN = 269, - OP_GSOCKOPT = 270, - OP_SSOCKOPT = 271, - OP_GETSOCKNAME = 272, - OP_GETPEERNAME = 273, - OP_LSTAT = 274, - OP_STAT = 275, - OP_FTRREAD = 276, - OP_FTRWRITE = 277, - OP_FTREXEC = 278, - OP_FTEREAD = 279, - OP_FTEWRITE = 280, - OP_FTEEXEC = 281, - OP_FTIS = 282, - OP_FTSIZE = 283, - OP_FTMTIME = 284, - OP_FTATIME = 285, - OP_FTCTIME = 286, - OP_FTROWNED = 287, - OP_FTEOWNED = 288, - OP_FTZERO = 289, - OP_FTSOCK = 290, - OP_FTCHR = 291, - OP_FTBLK = 292, - OP_FTFILE = 293, - OP_FTDIR = 294, - OP_FTPIPE = 295, - OP_FTSUID = 296, - OP_FTSGID = 297, - OP_FTSVTX = 298, - OP_FTLINK = 299, - OP_FTTTY = 300, - OP_FTTEXT = 301, - OP_FTBINARY = 302, - OP_CHDIR = 303, - OP_CHOWN = 304, - OP_CHROOT = 305, - OP_UNLINK = 306, - OP_CHMOD = 307, - OP_UTIME = 308, - OP_RENAME = 309, - OP_LINK = 310, - OP_SYMLINK = 311, - OP_READLINK = 312, - OP_MKDIR = 313, - OP_RMDIR = 314, - OP_OPEN_DIR = 315, - OP_READDIR = 316, - OP_TELLDIR = 317, - OP_SEEKDIR = 318, - OP_REWINDDIR = 319, - OP_CLOSEDIR = 320, - OP_FORK = 321, - OP_WAIT = 322, - OP_WAITPID = 323, - OP_SYSTEM = 324, - OP_EXEC = 325, - OP_KILL = 326, - OP_GETPPID = 327, - OP_GETPGRP = 328, - OP_SETPGRP = 329, - OP_GETPRIORITY = 330, - OP_SETPRIORITY = 331, - OP_TIME = 332, - OP_TMS = 333, - OP_LOCALTIME = 334, - OP_GMTIME = 335, - OP_ALARM = 336, - OP_SLEEP = 337, - OP_SHMGET = 338, - OP_SHMCTL = 339, - OP_SHMREAD = 340, - OP_SHMWRITE = 341, - OP_MSGGET = 342, - OP_MSGCTL = 343, - OP_MSGSND = 344, - OP_MSGRCV = 345, - OP_SEMOP = 346, - OP_SEMGET = 347, - OP_SEMCTL = 348, - OP_REQUIRE = 349, - OP_DOFILE = 350, - OP_HINTSEVAL = 351, - OP_ENTEREVAL = 352, - OP_LEAVEEVAL = 353, - OP_ENTERTRY = 354, - OP_LEAVETRY = 355, - OP_GHBYNAME = 356, - OP_GHBYADDR = 357, - OP_GHOSTENT = 358, - OP_GNBYNAME = 359, - OP_GNBYADDR = 360, - OP_GNETENT = 361, - OP_GPBYNAME = 362, - OP_GPBYNUMBER = 363, - OP_GPROTOENT = 364, - OP_GSBYNAME = 365, - OP_GSBYPORT = 366, - OP_GSERVENT = 367, - OP_SHOSTENT = 368, - OP_SNETENT = 369, - OP_SPROTOENT = 370, - OP_SSERVENT = 371, - OP_EHOSTENT = 372, - OP_ENETENT = 373, - OP_EPROTOENT = 374, - OP_ESERVENT = 375, - OP_GPWNAM = 376, - OP_GPWUID = 377, - OP_GPWENT = 378, - OP_SPWENT = 379, - OP_EPWENT = 380, - OP_GGRNAM = 381, - OP_GGRGID = 382, - OP_GGRENT = 383, - OP_SGRENT = 384, - OP_EGRENT = 385, - OP_GETLOGIN = 386, - OP_SYSCALL = 387, - OP_LOCK = 388, - OP_ONCE = 389, - OP_CUSTOM = 390, - OP_COREARGS = 391, - OP_AVHVSWITCH = 392, - OP_RUNCV = 393, - OP_FC = 394, - OP_PADCV = 395, - OP_INTROCV = 396, - OP_CLONECV = 397, - OP_PADRANGE = 398, - OP_REFASSIGN = 399, - OP_LVREF = 400, - OP_LVREFSLICE = 401, - OP_LVAVREF = 402, - OP_ANONCONST = 403, - OP_ISA = 404, - OP_CMPCHAIN_AND = 405, - OP_CMPCHAIN_DUP = 406, - OP_ENTERTRYCATCH = 407, - OP_LEAVETRYCATCH = 408, - OP_POPTRY = 409, - OP_CATCH = 410, - OP_PUSHDEFER = 411, - OP_IS_BOOL = 412, - OP_IS_WEAK = 413, - OP_WEAKEN = 414, - OP_UNWEAKEN = 415, - OP_BLESSED = 416, - OP_REFADDR = 417, - OP_REFTYPE = 418, - OP_CEIL = 419, - OP_FLOOR = 420, - OP_IS_TAINTED = 421, - OP_HELEMEXISTSOR = 422, - OP_METHSTART = 423, - OP_INITFIELD = 424, - OP_CLASSNAME = 425, - OP_MULTIPARAM = 426, - OP_PARAMTEST = 427, - OP_PARAMSTORE = 428, + OP_EQU = 84, + OP_I_EQU = 85, + OP_NEU = 86, + OP_I_NEU = 87, + OP_NCMP = 88, + OP_I_NCMP = 89, + OP_SLT = 90, + OP_SGT = 91, + OP_SLE = 92, + OP_SGE = 93, + OP_SEQ = 94, + OP_SNE = 95, + OP_SEQU = 96, + OP_SNEU = 97, + OP_SCMP = 98, + OP_BIT_AND = 99, + OP_BIT_XOR = 100, + OP_BIT_OR = 101, + OP_NBIT_AND = 102, + OP_NBIT_XOR = 103, + OP_NBIT_OR = 104, + OP_SBIT_AND = 105, + OP_SBIT_XOR = 106, + OP_SBIT_OR = 107, + OP_NEGATE = 108, + OP_I_NEGATE = 109, + OP_NOT = 110, + OP_COMPLEMENT = 111, + OP_NCOMPLEMENT = 112, + OP_SCOMPLEMENT = 113, + OP_SMARTMATCH = 114, + OP_ATAN2 = 115, + OP_SIN = 116, + OP_COS = 117, + OP_RAND = 118, + OP_SRAND = 119, + OP_EXP = 120, + OP_LOG = 121, + OP_SQRT = 122, + OP_INT = 123, + OP_HEX = 124, + OP_OCT = 125, + OP_ABS = 126, + OP_LENGTH = 127, + OP_SUBSTR = 128, + OP_SUBSTR_LEFT = 129, + OP_VEC = 130, + OP_INDEX = 131, + OP_RINDEX = 132, + OP_SPRINTF = 133, + OP_FORMLINE = 134, + OP_ORD = 135, + OP_CHR = 136, + OP_CRYPT = 137, + OP_UCFIRST = 138, + OP_LCFIRST = 139, + OP_UC = 140, + OP_LC = 141, + OP_QUOTEMETA = 142, + OP_RV2AV = 143, + OP_AELEMFAST = 144, + OP_AELEMFAST_LEX = 145, + OP_AELEMFASTLEX_STORE = 146, + OP_AELEM = 147, + OP_ASLICE = 148, + OP_KVASLICE = 149, + OP_AEACH = 150, + OP_AVALUES = 151, + OP_AKEYS = 152, + OP_EACH = 153, + OP_VALUES = 154, + OP_KEYS = 155, + OP_DELETE = 156, + OP_EXISTS = 157, + OP_RV2HV = 158, + OP_HELEM = 159, + OP_HSLICE = 160, + OP_KVHSLICE = 161, + OP_MULTIDEREF = 162, + OP_UNPACK = 163, + OP_PACK = 164, + OP_SPLIT = 165, + OP_JOIN = 166, + OP_LIST = 167, + OP_LSLICE = 168, + OP_ANONLIST = 169, + OP_ANONHASH = 170, + OP_EMPTYAVHV = 171, + OP_SPLICE = 172, + OP_PUSH = 173, + OP_POP = 174, + OP_SHIFT = 175, + OP_UNSHIFT = 176, + OP_SORT = 177, + OP_REVERSE = 178, + OP_GREPSTART = 179, + OP_GREPWHILE = 180, + OP_ANYSTART = 181, + OP_ALLSTART = 182, + OP_ANYWHILE = 183, + OP_MAPSTART = 184, + OP_MAPWHILE = 185, + OP_RANGE = 186, + OP_FLIP = 187, + OP_FLOP = 188, + OP_AND = 189, + OP_OR = 190, + OP_XOR = 191, + OP_DOR = 192, + OP_COND_EXPR = 193, + OP_ANDASSIGN = 194, + OP_ORASSIGN = 195, + OP_DORASSIGN = 196, + OP_ENTERSUB = 197, + OP_LEAVESUB = 198, + OP_LEAVESUBLV = 199, + OP_ARGCHECK = 200, + OP_ARGELEM = 201, + OP_ARGDEFELEM = 202, + OP_CALLER = 203, + OP_WARN = 204, + OP_DIE = 205, + OP_RESET = 206, + OP_LINESEQ = 207, + OP_NEXTSTATE = 208, + OP_DBSTATE = 209, + OP_UNSTACK = 210, + OP_ENTER = 211, + OP_LEAVE = 212, + OP_SCOPE = 213, + OP_ENTERITER = 214, + OP_ITER = 215, + OP_ENTERLOOP = 216, + OP_LEAVELOOP = 217, + OP_RETURN = 218, + OP_LAST = 219, + OP_NEXT = 220, + OP_REDO = 221, + OP_DUMP = 222, + OP_GOTO = 223, + OP_EXIT = 224, + OP_METHOD = 225, + OP_METHOD_NAMED = 226, + OP_METHOD_SUPER = 227, + OP_METHOD_REDIR = 228, + OP_METHOD_REDIR_SUPER = 229, + OP_ENTERGIVEN = 230, + OP_LEAVEGIVEN = 231, + OP_ENTERWHEN = 232, + OP_LEAVEWHEN = 233, + OP_BREAK = 234, + OP_CONTINUE = 235, + OP_OPEN = 236, + OP_CLOSE = 237, + OP_PIPE_OP = 238, + OP_FILENO = 239, + OP_UMASK = 240, + OP_BINMODE = 241, + OP_TIE = 242, + OP_UNTIE = 243, + OP_TIED = 244, + OP_DBMOPEN = 245, + OP_DBMCLOSE = 246, + OP_SSELECT = 247, + OP_SELECT = 248, + OP_GETC = 249, + OP_READ = 250, + OP_ENTERWRITE = 251, + OP_LEAVEWRITE = 252, + OP_PRTF = 253, + OP_PRINT = 254, + OP_SAY = 255, + OP_SYSOPEN = 256, + OP_SYSSEEK = 257, + OP_SYSREAD = 258, + OP_SYSWRITE = 259, + OP_EOF = 260, + OP_TELL = 261, + OP_SEEK = 262, + OP_TRUNCATE = 263, + OP_FCNTL = 264, + OP_IOCTL = 265, + OP_FLOCK = 266, + OP_SEND = 267, + OP_RECV = 268, + OP_SOCKET = 269, + OP_SOCKPAIR = 270, + OP_BIND = 271, + OP_CONNECT = 272, + OP_LISTEN = 273, + OP_ACCEPT = 274, + OP_SHUTDOWN = 275, + OP_GSOCKOPT = 276, + OP_SSOCKOPT = 277, + OP_GETSOCKNAME = 278, + OP_GETPEERNAME = 279, + OP_LSTAT = 280, + OP_STAT = 281, + OP_FTRREAD = 282, + OP_FTRWRITE = 283, + OP_FTREXEC = 284, + OP_FTEREAD = 285, + OP_FTEWRITE = 286, + OP_FTEEXEC = 287, + OP_FTIS = 288, + OP_FTSIZE = 289, + OP_FTMTIME = 290, + OP_FTATIME = 291, + OP_FTCTIME = 292, + OP_FTROWNED = 293, + OP_FTEOWNED = 294, + OP_FTZERO = 295, + OP_FTSOCK = 296, + OP_FTCHR = 297, + OP_FTBLK = 298, + OP_FTFILE = 299, + OP_FTDIR = 300, + OP_FTPIPE = 301, + OP_FTSUID = 302, + OP_FTSGID = 303, + OP_FTSVTX = 304, + OP_FTLINK = 305, + OP_FTTTY = 306, + OP_FTTEXT = 307, + OP_FTBINARY = 308, + OP_CHDIR = 309, + OP_CHOWN = 310, + OP_CHROOT = 311, + OP_UNLINK = 312, + OP_CHMOD = 313, + OP_UTIME = 314, + OP_RENAME = 315, + OP_LINK = 316, + OP_SYMLINK = 317, + OP_READLINK = 318, + OP_MKDIR = 319, + OP_RMDIR = 320, + OP_OPEN_DIR = 321, + OP_READDIR = 322, + OP_TELLDIR = 323, + OP_SEEKDIR = 324, + OP_REWINDDIR = 325, + OP_CLOSEDIR = 326, + OP_FORK = 327, + OP_WAIT = 328, + OP_WAITPID = 329, + OP_SYSTEM = 330, + OP_EXEC = 331, + OP_KILL = 332, + OP_GETPPID = 333, + OP_GETPGRP = 334, + OP_SETPGRP = 335, + OP_GETPRIORITY = 336, + OP_SETPRIORITY = 337, + OP_TIME = 338, + OP_TMS = 339, + OP_LOCALTIME = 340, + OP_GMTIME = 341, + OP_ALARM = 342, + OP_SLEEP = 343, + OP_SHMGET = 344, + OP_SHMCTL = 345, + OP_SHMREAD = 346, + OP_SHMWRITE = 347, + OP_MSGGET = 348, + OP_MSGCTL = 349, + OP_MSGSND = 350, + OP_MSGRCV = 351, + OP_SEMOP = 352, + OP_SEMGET = 353, + OP_SEMCTL = 354, + OP_REQUIRE = 355, + OP_DOFILE = 356, + OP_HINTSEVAL = 357, + OP_ENTEREVAL = 358, + OP_LEAVEEVAL = 359, + OP_ENTERTRY = 360, + OP_LEAVETRY = 361, + OP_GHBYNAME = 362, + OP_GHBYADDR = 363, + OP_GHOSTENT = 364, + OP_GNBYNAME = 365, + OP_GNBYADDR = 366, + OP_GNETENT = 367, + OP_GPBYNAME = 368, + OP_GPBYNUMBER = 369, + OP_GPROTOENT = 370, + OP_GSBYNAME = 371, + OP_GSBYPORT = 372, + OP_GSERVENT = 373, + OP_SHOSTENT = 374, + OP_SNETENT = 375, + OP_SPROTOENT = 376, + OP_SSERVENT = 377, + OP_EHOSTENT = 378, + OP_ENETENT = 379, + OP_EPROTOENT = 380, + OP_ESERVENT = 381, + OP_GPWNAM = 382, + OP_GPWUID = 383, + OP_GPWENT = 384, + OP_SPWENT = 385, + OP_EPWENT = 386, + OP_GGRNAM = 387, + OP_GGRGID = 388, + OP_GGRENT = 389, + OP_SGRENT = 390, + OP_EGRENT = 391, + OP_GETLOGIN = 392, + OP_SYSCALL = 393, + OP_LOCK = 394, + OP_ONCE = 395, + OP_CUSTOM = 396, + OP_COREARGS = 397, + OP_AVHVSWITCH = 398, + OP_RUNCV = 399, + OP_FC = 400, + OP_PADCV = 401, + OP_INTROCV = 402, + OP_CLONECV = 403, + OP_PADRANGE = 404, + OP_REFASSIGN = 405, + OP_LVREF = 406, + OP_LVREFSLICE = 407, + OP_LVAVREF = 408, + OP_ANONCONST = 409, + OP_ISA = 410, + OP_CMPCHAIN_AND = 411, + OP_CMPCHAIN_DUP = 412, + OP_ENTERTRYCATCH = 413, + OP_LEAVETRYCATCH = 414, + OP_POPTRY = 415, + OP_CATCH = 416, + OP_PUSHDEFER = 417, + OP_IS_BOOL = 418, + OP_IS_WEAK = 419, + OP_WEAKEN = 420, + OP_UNWEAKEN = 421, + OP_BLESSED = 422, + OP_REFADDR = 423, + OP_REFTYPE = 424, + OP_CEIL = 425, + OP_FLOOR = 426, + OP_IS_TAINTED = 427, + OP_HELEMEXISTSOR = 428, + OP_METHSTART = 429, + OP_INITFIELD = 430, + OP_CLASSNAME = 431, + OP_MULTIPARAM = 432, + OP_PARAMTEST = 433, + OP_PARAMSTORE = 434, OP_max } opcode; @@ -453,7 +459,7 @@ An enum of all the legal Perl opcodes, defined in F =cut */ -#define MAXO 429 +#define MAXO 435 #define OP_FREED MAXO /* the OP_IS_* macros are optimized to a simple range check because diff --git a/perly.act b/perly.act index bfd4095d083f..9b7de455d102 100644 --- a/perly.act +++ b/perly.act @@ -2320,5 +2320,5 @@ case 2: /* @1: %empty */ /* Generated from: * 783af8ff7ff42fd7313d85df8bbde58d7480e4964bb41ce7b92a5039a7286074 perly.y - * f13e9c08cea6302f0c1d1f467405bd0e0880d0ea92d0669901017a7f7e94ab28 regen_perly.pl + * 389eaa2541b0fce2983b9874b3148a5ada6056fbb1ec8bf2f6b4341dddc4a621 regen_perly.pl * ex: set ro ft=c: */ diff --git a/perly.h b/perly.h index 9e9bbc34ad8c..a8003498c1aa 100644 --- a/perly.h +++ b/perly.h @@ -199,8 +199,7 @@ extern int yydebug; /* Value type. */ #ifdef PERL_IN_TOKE_C static bool -S_is_opval_token(int type) -{ +S_is_opval_token(int type) { switch (type) { case ATTRLIST: case BAREWORD: @@ -250,5 +249,5 @@ int yyparse (void); /* Generated from: * 783af8ff7ff42fd7313d85df8bbde58d7480e4964bb41ce7b92a5039a7286074 perly.y - * f13e9c08cea6302f0c1d1f467405bd0e0880d0ea92d0669901017a7f7e94ab28 regen_perly.pl + * 389eaa2541b0fce2983b9874b3148a5ada6056fbb1ec8bf2f6b4341dddc4a621 regen_perly.pl * ex: set ro ft=c: */ diff --git a/perly.tab b/perly.tab index 7f547fa1a931..4d91f665fd75 100644 --- a/perly.tab +++ b/perly.tab @@ -1698,5 +1698,5 @@ static const toketypes yy_type_tab[] = /* Generated from: * 783af8ff7ff42fd7313d85df8bbde58d7480e4964bb41ce7b92a5039a7286074 perly.y - * f13e9c08cea6302f0c1d1f467405bd0e0880d0ea92d0669901017a7f7e94ab28 regen_perly.pl + * 389eaa2541b0fce2983b9874b3148a5ada6056fbb1ec8bf2f6b4341dddc4a621 regen_perly.pl * ex: set ro ft=c: */ diff --git a/pod/perlop.pod b/pod/perlop.pod index 3a14676f73b3..9b2fd67c834b 100644 --- a/pod/perlop.pod +++ b/pod/perlop.pod @@ -140,7 +140,7 @@ values only, not array values. nonassoc named unary operators nonassoc isa chained < > <= >= lt gt le ge - chain/na == != eq ne <=> cmp ~~ + chain/na == != eq ne === !== equ neu <=> cmp ~~ left & &. left | |. ^ ^. left && @@ -646,6 +646,25 @@ the section L. Beware that they do not chain with relational operators, which have higher precedence. +Each of these four operators has a variant whose name is one character longer, +which has different behaviour to the base operator when either (or both) of +its arguments is C. These operators, called the I, consider that C is equal to another C but not equal +to any defined value - even the number zero or the empty string. Furtheremore, +these operators will not invoke warnings when invoked on undefined values, +even when their base counterparts would. (Though other warnings are still +possible, such as C<===> warning about non-numerical values). + +Binary C<< "===" >> returns true if both arguments are C, or if both +are defined and numerically equal as according to C<< "==" >>. + +Binary C<< "equ" >> returns true if both arguments are C, or if both +are defined and stringwise equal as according to C<< "eq" >>. + +Binary C<< "!==" >> and C<< "neu" >> are the complements to these; returning +true if exactly one argument is C, or if both are defined but not +equal, either numerically or stringwise respectively. + Binary C<< "<=>" >> returns -1, 0, or 1 depending on whether the left argument is numerically less than, equal to, or greater than the right argument. If your platform supports C's (not-a-numbers) as numeric diff --git a/pp.c b/pp.c index ae682eadca05..613557a0fadf 100644 --- a/pp.c +++ b/pp.c @@ -2229,6 +2229,40 @@ PP(pp_ne) } +PP(pp_neu) +{ + SV *right = PL_stack_sp[0]; + SV *left = PL_stack_sp[-1]; + + SvGETMAGIC(left); + if(left != right) + SvGETMAGIC(right); + + bool lundef = !SvOK(left), rundef = !SvOK(right); + + if(lundef || rundef) { + rpp_replace_2_IMM_NN(boolSV(!(lundef && rundef))); + return NORMAL; + } + + if (rpp_try_AMAGIC_2(ne_amg, AMGf_numeric|AMGf_no_GETMAGIC)) + return NORMAL; + + /* a copy-paste of the logic from pp_ne */ + U32 flags_and = SvFLAGS(left) & SvFLAGS(right); + U32 flags_or = SvFLAGS(left) | SvFLAGS(right); + + rpp_replace_2_IMM_NN(boolSV( + ( (flags_and & SVf_IOK) && ((flags_or & SVf_IVisUV) ==0 ) ) + ? (SvIVX(left) != SvIVX(right)) + : (flags_and & SVf_NOK) + ? (SvNVX(left) != SvNVX(right)) + : (do_ncmp(left, right) != 0) + )); + return NORMAL; +} + + /* compare left and right SVs. Returns: * -1: < * 0: == @@ -2381,6 +2415,30 @@ PP(pp_seq) } +PP(pp_sequ) +{ + SV *right = PL_stack_sp[0]; + SV *left = PL_stack_sp[-1]; + + SvGETMAGIC(left); + if(left != right) + SvGETMAGIC(right); + + bool lundef = !SvOK(left), rundef = !SvOK(right); + + if(lundef || rundef) { + rpp_replace_2_IMM_NN(boolSV(lundef && rundef)); + return NORMAL; + } + + if (rpp_try_AMAGIC_2(seq_amg, AMGf_no_GETMAGIC)) + return NORMAL; + + rpp_replace_2_IMM_NN(boolSV(sv_eq_flags(left, right, 0)));; + return NORMAL; +} + + PP(pp_sne) { if (rpp_try_AMAGIC_2(sne_amg, 0)) @@ -2394,6 +2452,30 @@ PP(pp_sne) } +PP(pp_sneu) +{ + SV *right = PL_stack_sp[0]; + SV *left = PL_stack_sp[-1]; + + SvGETMAGIC(left); + if(left != right) + SvGETMAGIC(right); + + bool lundef = !SvOK(left), rundef = !SvOK(right); + + if(lundef || rundef) { + rpp_replace_2_IMM_NN(boolSV(!(lundef && rundef))); + return NORMAL; + } + + if (rpp_try_AMAGIC_2(sne_amg, AMGf_no_GETMAGIC)) + return NORMAL; + + rpp_replace_2_IMM_NN(boolSV(!sv_eq_flags(left, right, 0))); + return NORMAL; +} + + PP(pp_scmp) { dTARGET; @@ -2993,6 +3075,60 @@ PP(pp_i_ne) } +PP(pp_i_equ) +{ + SV *right = PL_stack_sp[0]; + SV *left = PL_stack_sp[-1]; + + SvGETMAGIC(left); + if(left != right) + SvGETMAGIC(right); + + bool lundef = !SvOK(left), rundef = !SvOK(right); + + if(lundef || rundef) { + rpp_replace_2_IMM_NN(boolSV(lundef && rundef)); + return NORMAL; + } + + if (rpp_try_AMAGIC_2(eq_amg, AMGf_numeric|AMGf_no_GETMAGIC)) + return NORMAL; + + IV ileft = SvIV_nomg(left); + IV iright = SvIV_nomg(right); + + rpp_replace_2_IMM_NN(boolSV(ileft == iright)); + return NORMAL; +} + + +PP(pp_i_neu) +{ + SV *right = PL_stack_sp[0]; + SV *left = PL_stack_sp[-1]; + + SvGETMAGIC(left); + if(left != right) + SvGETMAGIC(right); + + bool lundef = !SvOK(left), rundef = !SvOK(right); + + if(lundef || rundef) { + rpp_replace_2_IMM_NN(boolSV(!(lundef && rundef))); + return NORMAL; + } + + if (rpp_try_AMAGIC_2(ne_amg, AMGf_numeric|AMGf_no_GETMAGIC)) + return NORMAL; + + IV ileft = SvIV_nomg(left); + IV iright = SvIV_nomg(right); + + rpp_replace_2_IMM_NN(boolSV(ileft != iright)); + return NORMAL; +} + + PP(pp_i_ncmp) { dTARGET; diff --git a/pp.h b/pp.h index 232ea2d6ae06..aa6796c96fb3 100644 --- a/pp.h +++ b/pp.h @@ -663,6 +663,7 @@ Does not use C. See also C>, C> and C>. #define AMGf_numarg 0x0080 #define AMGf_force_scalar 0x0100 #define AMGf_force_overload SV_FORCE_OVERLOAD /* ignore HINTS_NO_AMAGIC */ +#define AMGf_no_GETMAGIC 0x0200 /* do SvGETMAGIC on the stack args before checking for overload */ diff --git a/pp_hot.c b/pp_hot.c index 72243263de70..4bd04c92577a 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -1691,6 +1691,40 @@ PP(pp_eq) } +PP(pp_equ) +{ + SV *right = PL_stack_sp[0]; + SV *left = PL_stack_sp[-1]; + + SvGETMAGIC(left); + if(left != right) + SvGETMAGIC(right); + + bool lundef = !SvOK(left), rundef = !SvOK(right); + + if(lundef || rundef) { + rpp_replace_2_IMM_NN(boolSV(lundef && rundef)); + return NORMAL; + } + + if (rpp_try_AMAGIC_2(eq_amg, AMGf_numeric|AMGf_no_GETMAGIC)) + return NORMAL; + + /* a copy-paste of the logic from pp_eq */ + U32 flags_and = SvFLAGS(left) & SvFLAGS(right); + U32 flags_or = SvFLAGS(left) | SvFLAGS(right); + + rpp_replace_2_IMM_NN(boolSV( + ( (flags_and & SVf_IOK) && ((flags_or & SVf_IVisUV) ==0 ) ) + ? (SvIVX(left) == SvIVX(right)) + : (flags_and & SVf_NOK) + ? (SvNVX(left) == SvNVX(right)) + : ( do_ncmp(left, right) == 0) + )); + return NORMAL; +} + + /* also used for: pp_i_preinc() */ PP(pp_preinc) diff --git a/pp_proto.h b/pp_proto.h index 8c30976c5208..e2b05480fbe8 100644 --- a/pp_proto.h +++ b/pp_proto.h @@ -78,6 +78,7 @@ PERL_CALLCONV PP(pp_enterwhen) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_enterwrite) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_eof) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_eq) __attribute__visibility__("hidden"); +PERL_CALLCONV PP(pp_equ) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_exec) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_exists) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_exit) __attribute__visibility__("hidden"); @@ -124,6 +125,7 @@ PERL_CALLCONV PP(pp_hslice) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_add) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_divide) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_eq) __attribute__visibility__("hidden"); +PERL_CALLCONV PP(pp_i_equ) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_ge) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_gt) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_le) __attribute__visibility__("hidden"); @@ -133,6 +135,7 @@ PERL_CALLCONV PP(pp_i_multiply) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_ncmp) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_ne) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_negate) __attribute__visibility__("hidden"); +PERL_CALLCONV PP(pp_i_neu) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_i_subtract) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_index) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_initfield) __attribute__visibility__("hidden"); @@ -191,6 +194,7 @@ PERL_CALLCONV PP(pp_ncmp) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_ncomplement) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_ne) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_negate) __attribute__visibility__("hidden"); +PERL_CALLCONV PP(pp_neu) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_next) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_nextstate) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_not) __attribute__visibility__("hidden"); @@ -265,6 +269,7 @@ PERL_CALLCONV PP(pp_select) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_semctl) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_semget) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_seq) __attribute__visibility__("hidden"); +PERL_CALLCONV PP(pp_sequ) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_setpgrp) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_setpriority) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_shift) __attribute__visibility__("hidden"); @@ -276,6 +281,7 @@ PERL_CALLCONV PP(pp_sle) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_sleep) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_smartmatch) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_sne) __attribute__visibility__("hidden"); +PERL_CALLCONV PP(pp_sneu) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_socket) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_sockpair) __attribute__visibility__("hidden"); PERL_CALLCONV PP(pp_sort) __attribute__visibility__("hidden"); diff --git a/regen/embed.pl b/regen/embed.pl index fef6e33818d3..ff0b89dd568b 100755 --- a/regen/embed.pl +++ b/regen/embed.pl @@ -181,6 +181,7 @@ BEGIN AMGfallNEVER AMGfallNO AMGfallYES + AMGf_no_GETMAGIC AMGf_numarg AMGf_numeric AMGf_want_list @@ -1379,6 +1380,7 @@ BEGIN KEY_endservent KEY_eof KEY_eq + KEY_equ KEY_eval KEY_evalbytes KEY_exec @@ -1463,6 +1465,7 @@ BEGIN KEY_msgsnd KEY_my KEY_ne + KEY_neu KEY_next KEY_no KEY_not @@ -2000,6 +2003,7 @@ BEGIN OPpENTERSUB_INARGS OPpENTERSUB_LVAL_MASK OPpENTERSUB_NOPAREN + OPpEQ_UNDEF OPpEVAL_BYTES OPpEVAL_COPHH OPpEVAL_EVALSV diff --git a/regen/keywords.pl b/regen/keywords.pl index fcbdb34b2676..a9868bf2ea9a 100755 --- a/regen/keywords.pl +++ b/regen/keywords.pl @@ -181,6 +181,7 @@ END -endservent -eof -eq +-equ +eval -evalbytes -exec @@ -263,6 +264,7 @@ END -msgsnd +my -ne +-neu +next +no -not diff --git a/regen/opcodes b/regen/opcodes index 97db7446fb67..8a807d9036c3 100644 --- a/regen/opcodes +++ b/regen/opcodes @@ -151,6 +151,10 @@ eq numeric eq (==) ck_cmp Iifs2 S S< i_eq integer eq (==) ck_cmp ifs2 S S< ne numeric ne (!=) ck_cmp Iifs2 S S< i_ne integer ne (!=) ck_cmp ifs2 S S< +equ undef-aware numeric eq (===) ck_cmp Iifs2 S S< +i_equ undef-aware integer eq (===) ck_cmp ifs2 S S< +neu undef-aware numeric ne (!==) ck_cmp Iifs2 S S< +i_neu undef-aware integer ne (!==) ck_cmp ifs2 S S< ncmp numeric comparison (<=>) ck_null Iifst2 S S< i_ncmp integer comparison (<=>) ck_null ifst2 S S< @@ -160,6 +164,8 @@ sle string le ck_scmp ifs2 S S sge string ge ck_scmp ifs2 S S seq string eq ck_scmp ifs2 S S sne string ne ck_scmp ifs2 S S +sequ undef-aware string eq ck_scmp ifs2 S S +sneu undef-aware string ne ck_scmp ifs2 S S scmp string comparison (cmp) ck_null ifst2 S S bit_and bitwise and (&) ck_bitop fst2 S S| diff --git a/regen_perly.pl b/regen_perly.pl index cb6feacab777..a57cbecb3b2d 100644 --- a/regen_perly.pl +++ b/regen_perly.pl @@ -29,21 +29,20 @@ # it may work elsewhere but no specific attempt has been made to make it # portable. -use 5.006; -sub usage { die "usage: $0 [ -b bison_executable ] [ file.y ]\n" } - +use v5.12; use warnings; -use strict; +sub usage { die "usage: $0 [ -b bison_executable ] [ file.y ]\n" } our $Verbose; BEGIN { require './regen/regen_lib.pl'; } -my $bison = 'bison'; +use Getopt::Long; +Getopt::Long::Configure(qw( bundling bundling_values no_ignore_case )); -if (@ARGV >= 2 and $ARGV[0] eq '-b') { - shift; - $bison = shift; -} +GetOptions( + 'b|bison=s' => \(my $bison = 'bison'), + 'W=s' => \my @bison_warnings, +) or usage; my $y_file = shift || 'perly.y'; @@ -90,7 +89,8 @@ $version = $1; # creates $tmpc_file and $tmph_file -my_system("$bison -d -o $tmpc_file $y_file"); +my_system("$bison -d -o $tmpc_file $y_file " . + join(" ", map { "-W$_" } @bison_warnings)); open my $ctmp_fh, '<', $tmpc_file or die "Can't open $tmpc_file: $!\n"; my $clines; diff --git a/t/op/coreamp.t b/t/op/coreamp.t index 82a6fd88b59b..e8da88085dc7 100644 --- a/t/op/coreamp.t +++ b/t/op/coreamp.t @@ -1190,10 +1190,11 @@ like $@, qr'^Undefined format "STDOUT" called', ADJUST AUTOLOAD BEGIN CHECK CORE DESTROY END INIT UNITCHECK __DATA__ __END__ all and any catch class cmp default defer do dump else elsif - eq eval field finally + eq equ eval field finally for foreach format ge given goto grep gt if isa last le local lt m map - method my ne next no or our package print printf q qq qr qw qx redo require - return s say sort state sub tr try unless until use when while x xor y + method my ne neu next no or our package print printf q qq qr qw qx + redo require return s say sort state sub tr try unless until use + when while x xor y ); open my $kh, $keywords_file or die "$0 cannot open $keywords_file: $!"; diff --git a/t/op/coresubs.t b/t/op/coresubs.t index 2d49711c8af7..fd2b16b6e6d9 100644 --- a/t/op/coresubs.t +++ b/t/op/coresubs.t @@ -18,9 +18,9 @@ use B; my %unsupported = map +($_=>1), qw ( __DATA__ __END__ ADJUST AUTOLOAD BEGIN UNITCHECK CORE DESTROY END INIT CHECK - all and any catch class cmp default defer do dump else elsif eq eval field - finally for foreach format ge given goto grep gt if isa last le local - lt m map method my ne next no or our package print printf q qq qr qw qx + all and any catch class cmp default defer do dump else elsif eq equ eval + field finally for foreach format ge given goto grep gt if isa last le local + lt m map method my ne neu next no or our package print printf q qq qr qw qx redo require return s say sort state sub tr try unless until use when while x xor y ); diff --git a/t/op/equ.t b/t/op/equ.t new file mode 100644 index 000000000000..03693dd640d7 --- /dev/null +++ b/t/op/equ.t @@ -0,0 +1,234 @@ +#!./perl + +use strict; +use warnings; + +BEGIN { + chdir 't' if -d 't'; + require './test.pl'; + set_up_inc('../lib'); +} + +# So many tests are easier to write as not_ok(FOO) rather than extra parens +sub not_ok +{ + my ($not_pass, $name, @mess) = @_; + ::_ok(!$not_pass, ::_where(), $name, @mess); +} + +# equ behaves like eq on defined strings +ok ("abc" equ "abc", 'equ on identical values'); +ok ("" equ "", 'equ on empty/empty'); +not_ok("abc" equ "def", 'equ on different values'); + +# equ treats undef as distinct, equal to itself, with no warnings +{ + my $warnings = 0; + local $SIG{__WARN__} = sub { $warnings++; }; + + ok (undef equ undef, 'equ on undef/undef'); + not_ok(undef equ "", 'equ on undef/empty'); + + is($warnings, 0, 'no warnings were produced by use of undef'); +} + +# equ is chainable +foreach my ( $x, $y, $z ) + ( "abc", "abc", "abc", + "abc", "abc", "def", + "abc", "", "", + "abc", "", undef, + "", undef, "" ) +{ + no warnings 'uninitialized'; + + is($x equ $y equ $z, ($x equ $y) && ($y equ $z), + 'equ chains correctly for ' . join("/", map { defined ? qq("$_") : 'undef' } $x, $y, $z )); + + # equ chaining with eq behaves as expected + is($x equ $y eq $z, ($x equ $y) && ($y eq $z), + 'equ and eq chain correctly for ' . join("/", map { defined ? qq("$_") : 'undef' } $x, $y, $z )); + is($x eq $y equ $z, ($x eq $y) && ($y equ $z), + 'eq and equ chain correctly for ' . join("/", map { defined ? qq("$_") : 'undef' } $x, $y, $z )); +} + +# equ still compares references like strings +{ + my $arr = []; + my $arrstr = "$arr"; + ok($arr equ $arrstr, 'equ stringifies defined references'); +} + +# neu is inverted equ +foreach my ( $left, $right ) + ( "abc", "abc", + "abc", "def", + "", undef, + undef, undef ) +{ + is(not($left neu $right), ($left equ $right), 'neu is a synonym for not(equ)'); +} + +# equ overload is synthesized from eq +{ + my $overload_called = 0; + + package EquToGreen { + use overload 'eq' => sub { + my ($this, $that, $swap) = @_; + $overload_called++; + return $that eq "green"; + }, + fallback => 1; + + sub new { bless [], shift } + } + + ok (EquToGreen->new equ "green", 'overloaded equ on LHS uses eq true'); + ok ("green" equ EquToGreen->new, 'overloaded equ on RHS uses eq true'); + not_ok(EquToGreen->new equ "NO", 'overloaded equ on LHS uses eq false'); + not_ok("NO" equ EquToGreen->new, 'overloaded equ on RHS uses eq false'); + not_ok(EquToGreen->new equ undef, 'overloaded equ on LHS for undef'); + not_ok(undef equ EquToGreen->new, 'overloaded equ on RHS for undef'); + + is($overload_called, 4, 'overloaded eq is not invoked with undef arg'); +} + +# equ overload is synthesized from cmp if eq is missing +{ + my $overload_called = 0; + + package EquToBlue { + use overload 'cmp' => sub { + my ($this, $that, $swap) = @_; + $overload_called++; + return "blue" cmp $that; + }, + fallback => 1; + + sub new { bless [], shift } + } + + ok (EquToBlue->new equ "blue", 'overloaded equ on LHS uses cmp true'); + ok ("blue" equ EquToBlue->new, 'overloaded equ on RHS uses cmp true'); + not_ok(EquToBlue->new equ "NO", 'overloaded equ on LHS uses cmp false'); + not_ok("NO" equ EquToBlue->new, 'overloaded equ on RHS uses cmp false'); + not_ok(EquToBlue->new equ undef, 'overloaded equ on LHS for undef'); + not_ok(undef equ EquToBlue->new, 'overloaded equ on RHS for undef'); + + is($overload_called, 4, 'overloaded cmp is not invoked with undef arg'); +} + +# === behaves like == on defined numbers +ok(123 === 123, '=== on identical values'); +ok(0 === 0, '=== on zero/zero'); +ok(not(123 === 456), '=== on different values'); + +# === treats undef as distinct, equal to itself, with no warnings +{ + my $warnings = 0; + local $SIG{__WARN__} = sub { $warnings++; }; + + ok(undef === undef, '=== on undef/undef'); + ok(not(undef === 0), '=== on undef/zero'); + + is($warnings, 0, 'no warnings were produced by use of undef'); +} + +# === is chainable +foreach my ( $x, $y, $z ) + ( 123, 123, 123, + 123, 123, 456, + 123, 0, 0, + 123, 0, undef, + 0, undef, "" ) +{ + no warnings 'uninitialized'; + + is($x === $y === $z, ($x === $y) && ($y === $z), + '=== chains correctly for ' . join("/", map { defined ? qq("$_") : 'undef' } $x, $y, $z )); + + # === chaining with == behaves as expected + is($x === $y == $z, ($x === $y) && ($y == $z), + '=== and == chain correctly for ' . join("/", map { $_ // 'undef' } $x, $y, $z )); + is($x == $y === $z, ($x == $y) && ($y === $z), + '== and === chain correctly for ' . join("/", map { $_ // 'undef' } $x, $y, $z )); +} + +# !== is inverted === +foreach my ( $left, $right ) + ( 123, 123, + 123, 456, + 0, undef, + undef, undef ) +{ + is(not($left !== $right), ($left === $right), '!== is a synonym for not(===)'); +} + +# === respects 'use integer' +{ + use integer; + my $x = 123.1; + ok ($x === 123, '=== respects use integer'); + not_ok($x !== 123, '!== respects use integer'); + + my $nearzero = 0.1; + ok ($nearzero === 0, '=== works under use integer'); + not_ok($nearzero !== 0, '!== works under use integer'); + not_ok($nearzero === 1, '=== works under use integer'); + ok ($nearzero !== 1, '!== works under use integer'); + not_ok($nearzero === undef, '=== works under use integer'); + ok ($nearzero !== undef, '!== works under use integer'); +} + +# === overload is synthesized from == +{ + my $overload_called = 0; + + package EqualToTwenty { + use overload '==' => sub { + my ($this, $that, $swap) = @_; + $overload_called++; + return $that == 20; + }, + fallback => 1; + + sub new { bless [], shift } + } + + ok (EqualToTwenty->new === 20, 'overloaded === on LHS true'); + ok (20 === EqualToTwenty->new, 'overloaded === on RHS true'); + not_ok(EqualToTwenty->new === 123, 'overloaded === on LHS false'); + not_ok(123 === EqualToTwenty->new, 'overloaded === on RHS false'); + not_ok(EqualToTwenty->new === undef, 'overloaded === on LHS false for undef'); + not_ok(undef === EqualToTwenty->new, 'overloaded === on RHS false for undef'); + + is($overload_called, 4, 'overloaded === invoked with undef arg'); +} + +# === overload is synthesized from <=> if == is missing +{ + my $overload_called = 0; + + package EqualToThirty { + use overload '<=>' => sub { + my ($this, $that, $swap) = @_; + $overload_called++; + return 30 <=> $that; + }, + fallback => 1; + + sub new { bless [], shift } + } + + ok (EqualToThirty->new === 30, 'overloaded === on LHS true'); + ok (30 === EqualToThirty->new, 'overloaded === on RHS true'); + not_ok(EqualToThirty->new === 123, 'overloaded === on LHS false'); + not_ok(123 === EqualToThirty->new, 'overloaded === on RHS false'); + not_ok(EqualToThirty->new === undef, 'overloaded === on LHS false for undef'); + not_ok(undef === EqualToThirty->new, 'overloaded === on RHS false for undef'); + + is($overload_called, 4, 'overloaded === invoked with undef arg'); +} + +done_testing(); diff --git a/t/op/tie_fetch_count.t b/t/op/tie_fetch_count.t index 86505f6eba85..eda2ae9a2524 100644 --- a/t/op/tie_fetch_count.t +++ b/t/op/tie_fetch_count.t @@ -9,7 +9,7 @@ BEGIN { set_up_inc('../lib'); } -plan (tests => 343); +plan (tests => 347); use strict; use warnings; @@ -85,6 +85,8 @@ $dummy = $var >= 1 ; check_count '>='; $dummy = $var > 1 ; check_count '>'; $dummy = $var != 1 ; check_count '!='; $dummy = $var <=> 1 ; check_count '<=>'; +$dummy = $var === 1 ; check_count '==='; +$dummy = $var !== 1 ; check_count '!=='; # String comparison $dummy = $var lt 1 ; check_count 'lt'; @@ -94,6 +96,8 @@ $dummy = $var ge 1 ; check_count 'ge'; $dummy = $var gt 1 ; check_count 'gt'; $dummy = $var ne 1 ; check_count 'ne'; $dummy = $var cmp 1 ; check_count 'cmp'; +$dummy = $var equ 1 ; check_count 'equ'; +$dummy = $var neu 1 ; check_count 'neu'; # Bitwise operators $dummy = $var & 1 ; check_count '&'; diff --git a/toke.c b/toke.c index 81043823c9ef..dc3189a59cec 100644 --- a/toke.c +++ b/toke.c @@ -7011,6 +7011,12 @@ yyl_bang(pTHX_ char *s) TOKEN(0); } + if (s[0] == '=') { + /* TODO: feature guard? */ + s++; + ChEop(OP_NEU); + } + ChEop(OP_NE); } @@ -8483,6 +8489,12 @@ yyl_word_or_keyword(pTHX_ char *s, STRLEN len, I32 key, I32 orig_keyword, struct return REPORT(0); ChEop(OP_SEQ); + case KEY_equ: + /* TODO: feature guard? */ + if (!PL_lex_allbrackets && PL_lex_fakeeof >= LEX_FAKEEOF_COMPARE) + return REPORT(0); + ChEop(OP_SEQU); + case KEY_exists: UNI(OP_EXISTS); @@ -8783,6 +8795,12 @@ yyl_word_or_keyword(pTHX_ char *s, STRLEN len, I32 key, I32 orig_keyword, struct return REPORT(0); ChEop(OP_SNE); + case KEY_neu: + /* TODO: feature guard? */ + if (!PL_lex_allbrackets && PL_lex_fakeeof >= LEX_FAKEEOF_COMPARE) + return REPORT(0); + ChEop(OP_SNEU); + case KEY_no: s = tokenize_use(0, s); TOKEN(KW_USE_or_NO); @@ -9707,6 +9725,11 @@ yyl_try(pTHX_ char *s) s -= 2; TOKEN(0); } + if (s[0] == '=') { + /* TODO: feature guard? */ + s++; + ChEop(OP_EQU); + } ChEop(OP_EQ); } if (tmp == '>') {