From: Rafael Garcia-Suarez Date: Sun, 25 Aug 2002 18:42:46 +0000 (+0000) Subject: Fix parsing problems with the // operator. X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=6f33ba736d46c2f5bfdb2405fd09d82ec18a1d07;p=p5sagit%2Fp5-mst-13.2.git Fix parsing problems with the // operator. Make // able to follow various unary operators used without arguments or parens (shift, pop, getc, pos, readline, readlink, undef, umask, and the filetest operators), as well as the operator. p4raw-id: //depot/perl@17777 --- diff --git a/perl.h b/perl.h index e5e97b8..d1b369d 100644 --- a/perl.h +++ b/perl.h @@ -3178,7 +3178,8 @@ typedef enum { XBLOCK, XATTRBLOCK, XATTRTERM, - XTERMBLOCK + XTERMBLOCK, + XTERMORDORDOR /* evil hack */ } expectation; enum { /* pass one of these to get_vtbl */ diff --git a/t/op/dor.t b/t/op/dor.t index 56920c2..2f918fc 100644 --- a/t/op/dor.t +++ b/t/op/dor.t @@ -10,7 +10,7 @@ BEGIN { package main; require './test.pl'; -plan( tests => 9 ); +plan( tests => 25 ); my($x); @@ -42,3 +42,20 @@ is($x, 1, ' //=: left-hand operand defined'); $x = ''; $x //= 0; is($x, '', ' //=: left-hand operand defined but empty'); + +@ARGV = (undef, 0, 3); +is(shift // 7, 7, 'shift // ... works'); +is(shift() // 7, 0, 'shift() // ... works'); +is(shift @ARGV // 7, 3, 'shift @array // ... works'); + +@ARGV = (3, 0, undef); +is(pop // 7, 7, 'pop // ... works'); +is(pop() // 7, 0, 'pop() // ... works'); +is(pop @ARGV // 7, 3, 'pop @array // ... works'); + +# Test that various syntaxes are allowed + +for (qw(getc pos readline readlink undef umask <> <$foo> -f)) { + eval "sub { $_ // 0 }"; + is($@, '', "$_ // ... compiles"); +} diff --git a/toke.c b/toke.c index f0f15b9..0e1e65a 100644 --- a/toke.c +++ b/toke.c @@ -149,7 +149,7 @@ int yyactlevel = -1; #define PREREF(retval) return (REPORT2("preref",retval) PL_expect = XREF,PL_bufptr = s,(int)retval) #define TERM(retval) return (CLINE, REPORT2("term",retval) PL_expect = XOPERATOR, PL_bufptr = s,(int)retval) #define LOOPX(f) return(yylval.ival=f, REPORT("loopx",f) PL_expect = XTERM,PL_bufptr = s,(int)LOOPEX) -#define FTST(f) return(yylval.ival=f, REPORT("ftst",f) PL_expect = XTERM,PL_bufptr = s,(int)UNIOP) +#define FTST(f) return(yylval.ival=f, REPORT("ftst",f) PL_expect = XTERMORDORDOR,PL_bufptr = s,(int)UNIOP) #define FUN0(f) return(yylval.ival = f, REPORT("fun0",f) PL_expect = XOPERATOR,PL_bufptr = s,(int)FUNC0) #define FUN1(f) return(yylval.ival = f, REPORT("fun1",f) PL_expect = XOPERATOR,PL_bufptr = s,(int)FUNC1) #define BOop(f) return ao((yylval.ival=f, REPORT("bitorop",f) PL_expect = XTERM,PL_bufptr = s,(int)BITOROP)) @@ -164,14 +164,18 @@ int yyactlevel = -1; /* This bit of chicanery makes a unary function followed by * a parenthesis into a function with one argument, highest precedence. + * The UNIDOR macro is for unary functions that can be followed by the // + * operator (such as C). */ -#define UNI(f) return(yylval.ival = f, \ +#define UNI2(f,x) return(yylval.ival = f, \ REPORT("uni",f) \ - PL_expect = XTERM, \ + PL_expect = x, \ PL_bufptr = s, \ PL_last_uni = PL_oldbufptr, \ PL_last_lop_op = f, \ (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) ) +#define UNI(f) UNI2(f,XTERM) +#define UNIDOR(f) UNI2(f,XTERMORDORDOR) #define UNIBRACK(f) return(yylval.ival = f, \ REPORT("uni",f) \ @@ -997,6 +1001,9 @@ S_sublex_start(pTHX) } yylval.opval = (OP*)newSVOP(op_type, 0, sv); PL_lex_stuff = Nullsv; + /* Allow // "foo" */ + if (op_type == OP_READLINE) + PL_expect = XTERMORDORDOR; return THING; } @@ -3597,6 +3604,10 @@ Perl_yylex(pTHX) TERM('@'); case '/': /* may be division, defined-or, or pattern */ + if (PL_expect == XTERMORDORDOR && s[1] == '/') { + s += 2; + AOPERATOR(DORDOR); + } case '?': /* may either be conditional or pattern */ if(PL_expect == XOPERATOR) { tmp = *s++; @@ -3745,7 +3756,9 @@ Perl_yylex(pTHX) TERM(THING); } /* avoid v123abc() or $h{v1}, allow C */ - else if (!isALPHA(*start) && (PL_expect == XTERM || PL_expect == XREF || PL_expect == XSTATE)) { + else if (!isALPHA(*start) && (PL_expect == XTERM + || PL_expect == XREF || PL_expect == XSTATE + || PL_expect == XTERMORDORDOR)) { char c = *start; GV *gv; *start = '\0'; @@ -4427,7 +4440,7 @@ Perl_yylex(pTHX) UNI(OP_GMTIME); case KEY_getc: - UNI(OP_GETC); + UNIDOR(OP_GETC); case KEY_getppid: FUN0(OP_GETPPID); @@ -4677,10 +4690,10 @@ Perl_yylex(pTHX) LOP(OP_PUSH,XTERM); case KEY_pop: - UNI(OP_POP); + UNIDOR(OP_POP); case KEY_pos: - UNI(OP_POS); + UNIDOR(OP_POS); case KEY_pack: LOP(OP_PACK,XTERM); @@ -4820,7 +4833,7 @@ Perl_yylex(pTHX) case KEY_readline: set_csh(); - UNI(OP_READLINE); + UNIDOR(OP_READLINE); case KEY_readpipe: set_csh(); @@ -4836,7 +4849,7 @@ Perl_yylex(pTHX) LOP(OP_REVERSE,XTERM); case KEY_readlink: - UNI(OP_READLINK); + UNIDOR(OP_READLINK); case KEY_ref: UNI(OP_REF); @@ -4903,7 +4916,7 @@ Perl_yylex(pTHX) LOP(OP_SSOCKOPT,XTERM); case KEY_shift: - UNI(OP_SHIFT); + UNIDOR(OP_SHIFT); case KEY_shmctl: LOP(OP_SHMCTL,XTERM); @@ -5133,7 +5146,7 @@ Perl_yylex(pTHX) LOP(OP_UNLINK,XTERM); case KEY_undef: - UNI(OP_UNDEF); + UNIDOR(OP_UNDEF); case KEY_unpack: LOP(OP_UNPACK,XTERM); @@ -5142,7 +5155,7 @@ Perl_yylex(pTHX) LOP(OP_UTIME,XTERM); case KEY_umask: - UNI(OP_UMASK); + UNIDOR(OP_UMASK); case KEY_unshift: LOP(OP_UNSHIFT,XTERM);