#define PL_multi_start (PL_parser->multi_start)
#define PL_multi_open (PL_parser->multi_open)
#define PL_multi_close (PL_parser->multi_close)
-#define PL_pending_ident (PL_parser->pending_ident)
#define PL_preambled (PL_parser->preambled)
#define PL_sublex_info (PL_parser->sublex_info)
#define PL_linestr (PL_parser->linestr)
# define PL_nextval (PL_parser->nextval)
#endif
-/* This can't be done with embed.fnc, because struct yy_parser contains a
- member named pending_ident, which clashes with the generated #define */
-static int
-S_pending_ident(pTHX);
+#define force_ident_maybe_lex(p) \
+ (PL_bufptr = s, S_force_ident_maybe_lex(aTHX_ p))
static const char ident_too_long[] = "Identifier too long";
{ METHOD, TOKENTYPE_OPVAL, "METHOD" },
{ MULOP, TOKENTYPE_OPNUM, "MULOP" },
{ MY, TOKENTYPE_IVAL, "MY" },
- { MYSUB, TOKENTYPE_NONE, "MYSUB" },
{ NOAMP, TOKENTYPE_NONE, "NOAMP" },
{ NOTOP, TOKENTYPE_NONE, "NOTOP" },
{ OROP, TOKENTYPE_IVAL, "OROP" },
}
if (name)
Perl_sv_catpv(aTHX_ report, name);
- else if ((char)rv > ' ' && (char)rv < '~')
+ else if ((char)rv > ' ' && (char)rv <= '~')
Perl_sv_catpvf(aTHX_ report, "'%c'", (char)rv);
else if (!rv)
sv_catpvs(report, "EOF");
linestart_pos = PL_parser->linestart - buf;
last_uni_pos = PL_parser->last_uni ? PL_parser->last_uni - buf : 0;
last_lop_pos = PL_parser->last_lop ? PL_parser->last_lop - buf : 0;
- re_eval_start_pos = PL_sublex_info.re_eval_start ?
- PL_sublex_info.re_eval_start - buf : 0;
+ re_eval_start_pos = PL_parser->lex_shared->re_eval_start ?
+ PL_parser->lex_shared->re_eval_start - buf : 0;
buf = sv_grow(linestr, len);
PL_parser->last_uni = buf + last_uni_pos;
if (PL_parser->last_lop)
PL_parser->last_lop = buf + last_lop_pos;
- if (PL_sublex_info.re_eval_start)
- PL_sublex_info.re_eval_start = buf + re_eval_start_pos;
+ if (PL_parser->lex_shared->re_eval_start)
+ PL_parser->lex_shared->re_eval_start = buf + re_eval_start_pos;
return buf;
}
SAVEI32(PL_lex_starts);
SAVEI8(PL_lex_state);
SAVESPTR(PL_lex_repl);
- SAVEPPTR(PL_sublex_info.re_eval_start);
- SAVESPTR(PL_sublex_info.re_eval_str);
- SAVEPPTR(PL_sublex_info.super_bufptr);
SAVEVPTR(PL_lex_inpat);
SAVEI16(PL_lex_inwhat);
SAVECOPLINE(PL_curcop);
SAVEGENERICPV(PL_parser->lex_shared);
/* The here-doc parser needs to be able to peek into outer lexing
- scopes to find the body of the here-doc. We use SvIVX(PL_linestr)
- to store the outer PL_bufptr and SvNVX to store the outer
- PL_linestr. Since SvIVX already means something else, we use
- PL_sublex_info.super_bufptr for the innermost scope (the one we are
- now entering), and a localised SvIVX for outer scopes.
+ scopes to find the body of the here-doc. So we put PL_linestr and
+ PL_bufptr into lex_shared, to ‘share’ those values.
*/
- SvUPGRADE(PL_linestr, SVt_PVIV);
- /* A null super_bufptr means the outer lexing scope is not peekable,
- because it is a single line from an input stream. */
- SAVEIV(SvIVX(PL_linestr));
- SvIVX(PL_linestr) = PTR2IV(PL_sublex_info.super_bufptr);
- PL_sublex_info.super_bufptr =
- (SvTYPE(PL_linestr) < SVt_PVNV || !SvNVX(PL_linestr))
- && (PL_rsfp || PL_parser->filtered)
- ? NULL
- : PL_bufptr;
- SvUPGRADE(PL_lex_stuff, SVt_PVNV);
- SvNVX(PL_lex_stuff) = PTR2NV(PL_linestr);
+ PL_parser->lex_shared->ls_linestr = PL_linestr;
+ PL_parser->lex_shared->ls_bufptr = PL_bufptr;
PL_linestr = PL_lex_stuff;
PL_lex_repl = PL_sublex_info.repl;
PL_lex_stuff = NULL;
PL_sublex_info.repl = NULL;
- PL_sublex_info.re_eval_start = NULL;
- PL_sublex_info.re_eval_str = NULL;
PL_bufend = PL_bufptr = PL_oldbufptr = PL_oldoldbufptr = PL_linestart
= SvPVX(PL_linestr);
/* Is there a right-hand side to take care of? (s//RHS/ or tr//RHS/) */
assert(PL_lex_inwhat != OP_TRANSR);
if (PL_lex_repl && (PL_lex_inwhat == OP_SUBST || PL_lex_inwhat == OP_TRANS)) {
- SvUPGRADE(PL_lex_repl, SVt_PVNV);
- SvNVX(PL_lex_repl) = SvNVX(PL_linestr);
PL_linestr = PL_lex_repl;
PL_lex_inpat = 0;
PL_bufend = PL_bufptr = PL_oldbufptr = PL_oldoldbufptr = PL_linestart = SvPVX(PL_linestr);
PL_thiswhite = 0;
PL_thismad = 0;
- /* just do what yylex would do on pending identifier; leave PL_thiswhite alone */
- if (PL_lex_state != LEX_KNOWNEXT && PL_pending_ident)
- return S_pending_ident(aTHX);
-
/* previous token ate up our whitespace? */
if (!PL_lasttoke && PL_nextwhite) {
PL_thiswhite = PL_nextwhite;
pv_display(tmp, s, strlen(s), 0, 60));
SvREFCNT_dec(tmp);
} );
- /* check if there's an identifier for us to look at */
- if (PL_lex_state != LEX_KNOWNEXT && PL_pending_ident)
- return REPORT(S_pending_ident(aTHX));
-
- /* no identifier pending identification */
switch (PL_lex_state) {
#ifdef COMMENTARY
}
/* Convert (?{...}) and friends to 'do {...}' */
if (PL_lex_inpat && *PL_bufptr == '(') {
- PL_sublex_info.re_eval_start = PL_bufptr;
+ PL_parser->lex_shared->re_eval_start = PL_bufptr;
PL_bufptr += 2;
if (*PL_bufptr != '{')
PL_bufptr++;
re_eval_str. If the here-doc body’s length equals the previous
value of re_eval_start, re_eval_start will now be null. So
check re_eval_str as well. */
- if (PL_sublex_info.re_eval_start || PL_sublex_info.re_eval_str) {
+ if (PL_parser->lex_shared->re_eval_start
+ || PL_parser->lex_shared->re_eval_str) {
SV *sv;
if (*PL_bufptr != ')')
Perl_croak(aTHX_ "Sequence (?{...}) not terminated with ')'");
PL_bufptr++;
/* having compiled a (?{..}) expression, return the original
* text too, as a const */
- if (PL_sublex_info.re_eval_str) {
- sv = PL_sublex_info.re_eval_str;
- PL_sublex_info.re_eval_str = NULL;
- SvCUR_set(sv, PL_bufptr - PL_sublex_info.re_eval_start);
+ if (PL_parser->lex_shared->re_eval_str) {
+ sv = PL_parser->lex_shared->re_eval_str;
+ PL_parser->lex_shared->re_eval_str = NULL;
+ SvCUR_set(sv,
+ PL_bufptr - PL_parser->lex_shared->re_eval_start);
SvPV_shrink_to_cur(sv);
}
- else sv = newSVpvn(PL_sublex_info.re_eval_start,
- PL_bufptr - PL_sublex_info.re_eval_start);
+ else sv = newSVpvn(PL_parser->lex_shared->re_eval_start,
+ PL_bufptr - PL_parser->lex_shared->re_eval_start);
start_force(PL_curforce);
/* XXX probably need a CURMAD(something) here */
NEXTVAL_NEXTTOKE.opval =
(OP*)newSVOP(OP_CONST, 0,
sv);
force_next(THING);
- PL_sublex_info.re_eval_start = NULL;
+ PL_parser->lex_shared->re_eval_start = NULL;
PL_expect = XTERM;
return REPORT(',');
}
incline(s);
}
else {
+ const bool in_comment = *s == '#';
d = s;
while (d < PL_bufend && *d != '\n')
d++;
PL_thiswhite = newSVpvn(s, d - s);
#endif
s = d;
- incline(s);
+ if (in_comment && d == PL_bufend
+ && PL_lex_state == LEX_INTERPNORMAL
+ && PL_lex_inwhat == OP_SUBST && PL_lex_repl == PL_linestr
+ && SvEVALED(PL_lex_repl) && d[-1] == '}') s--;
+ else incline(s);
}
if (PL_lex_formbrack && PL_lex_brackets <= PL_lex_formbrack) {
PL_lex_state = LEX_FORMLINE;
if (!PL_tokenbuf[1]) {
PREREF('%');
}
- PL_pending_ident = '%';
+ PL_expect = XOPERATOR;
+ force_ident_maybe_lex('%');
TERM('%');
case '^':
}
switch (PL_expect) {
case XTERM:
- if (PL_oldoldbufptr == PL_last_lop)
- PL_lex_brackstack[PL_lex_brackets++] = XTERM;
- else
- PL_lex_brackstack[PL_lex_brackets++] = XOPERATOR;
+ PL_lex_brackstack[PL_lex_brackets++] = XOPERATOR;
PL_lex_allbrackets++;
OPERATOR(HASHBRACK);
case XOPERATOR:
#endif
return yylex(); /* ignore fake brackets */
}
- if (*s == '-' && s[1] == '>')
+ if (PL_lex_inwhat == OP_SUBST && PL_lex_repl == PL_linestr
+ && SvEVALED(PL_lex_repl))
+ PL_lex_state = LEX_INTERPEND;
+ else if (*s == '-' && s[1] == '>')
PL_lex_state = LEX_INTERPENDMAYBE;
else if (*s != '[' && *s != '{')
PL_lex_state = LEX_INTERPEND;
BAop(OP_BIT_AND);
}
- s = scan_ident(s - 1, PL_bufend, PL_tokenbuf, sizeof PL_tokenbuf, TRUE);
- if (*PL_tokenbuf) {
+ PL_tokenbuf[0] = '&';
+ s = scan_ident(s - 1, PL_bufend, PL_tokenbuf + 1,
+ sizeof PL_tokenbuf - 1, TRUE);
+ if (PL_tokenbuf[1]) {
PL_expect = XOPERATOR;
- force_ident(PL_tokenbuf, '&');
+ force_ident_maybe_lex('&');
}
else
PREREF('&');
if (!PL_tokenbuf[1])
PREREF(DOLSHARP);
PL_expect = XOPERATOR;
- PL_pending_ident = '#';
+ force_ident_maybe_lex('#');
TOKEN(DOLSHARP);
}
PL_expect = XTERM; /* print $fh <<"EOF" */
}
}
- PL_pending_ident = '$';
+ force_ident_maybe_lex('$');
TOKEN('$');
case '@':
}
}
}
- PL_pending_ident = '@';
+ PL_expect = XOPERATOR;
+ force_ident_maybe_lex('@');
TERM('@');
case '/': /* may be division, defined-or, or pattern */
keylookup: {
bool anydelim;
+ bool lex;
I32 tmp;
+ SV *sv;
+ CV *cv;
+ PADOFFSET off;
+ OP *rv2cv_op;
+ lex = FALSE;
orig_keyword = 0;
+ off = 0;
+ sv = NULL;
+ cv = NULL;
gv = NULL;
gvp = NULL;
+ rv2cv_op = NULL;
PL_bufptr = s;
s = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, FALSE, &len);
TOKEN(LABEL);
}
+ /* Check for lexical sub */
+ if (PL_expect != XOPERATOR) {
+ char tmpbuf[sizeof PL_tokenbuf + 1];
+ *tmpbuf = '&';
+ Copy(PL_tokenbuf, tmpbuf+1, len, char);
+ off = pad_findmy_pvn(tmpbuf, len+1, UTF ? SVf_UTF8 : 0);
+ if (off != NOT_IN_PAD) {
+ assert(off); /* we assume this is boolean-true below */
+ if (PAD_COMPNAME_FLAGS_isOUR(off)) {
+ HV * const stash = PAD_COMPNAME_OURSTASH(off);
+ HEK * const stashname = HvNAME_HEK(stash);
+ sv = newSVhek(stashname);
+ sv_catpvs(sv, "::");
+ sv_catpvn_flags(sv, PL_tokenbuf, len,
+ (UTF ? SV_CATUTF8 : SV_CATBYTES));
+ gv = gv_fetchsv(sv, GV_NOADD_NOINIT | SvUTF8(sv),
+ SVt_PVCV);
+ off = 0;
+ }
+ else {
+ rv2cv_op = newOP(OP_PADANY, 0);
+ rv2cv_op->op_targ = off;
+ rv2cv_op = (OP*)newCVREF(0, rv2cv_op);
+ cv = (CV *)PAD_SV(off);
+ }
+ lex = TRUE;
+ goto just_a_word;
+ }
+ off = 0;
+ }
+
if (tmp < 0) { /* second-class keyword? */
GV *ogv = NULL; /* override (winner) */
GV *hgv = NULL; /* hidden (loser) */
earlier ':' case doesn't bypass the initialisation. */
if (0) {
just_a_word_zero_gv:
+ sv = NULL;
+ cv = NULL;
gv = NULL;
gvp = NULL;
+ rv2cv_op = NULL;
orig_keyword = 0;
+ lex = 0;
+ off = 0;
}
just_a_word: {
- SV *sv;
int pkgname = 0;
const char lastchar = (PL_bufptr == PL_oldoldbufptr ? 0 : PL_bufptr[-1]);
- OP *rv2cv_op;
- CV *cv;
#ifdef PERL_MAD
SV *nextPL_nextwhite = 0;
#endif
}
/* Look for a subroutine with this name in current package,
- unless name is "Foo::", in which case Foo is a bareword
+ unless this is a lexical sub, or name is "Foo::",
+ in which case Foo is a bareword
(and a package name). */
if (len > 2 && !PL_madskills &&
gvp = 0;
}
else {
- if (!gv) {
+ if (!lex && !gv) {
/* Mustn't actually add anything to a symbol table.
But also don't want to "initialise" any placeholder
constants that might already be there into full
/* if we saw a global override before, get the right name */
- sv = S_newSV_maybe_utf8(aTHX_ PL_tokenbuf,
+ if (!sv)
+ sv = S_newSV_maybe_utf8(aTHX_ PL_tokenbuf,
len ? len : strlen(PL_tokenbuf));
if (gvp) {
SV * const tmp_sv = sv;
if (len)
goto safe_bareword;
+ if (!off)
{
OP *const_op = newSVOP(OP_CONST, 0, SvREFCNT_inc_NN(sv));
const_op->op_private = OPpCONST_BARE;
rv2cv_op = newCVREF(0, const_op);
+ cv = lex ? GvCV(gv) : rv2cv_op_cv(rv2cv_op, 0);
}
- cv = rv2cv_op_cv(rv2cv_op, 0);
/* See if it's the indirect object for a list operator. */
}
start_force(PL_curforce);
#endif
- NEXTVAL_NEXTTOKE.opval = pl_yylval.opval;
+ NEXTVAL_NEXTTOKE.opval =
+ off ? rv2cv_op : pl_yylval.opval;
PL_expect = XOPERATOR;
#ifdef PERL_MAD
if (PL_madskills) {
PL_thistoken = newSVpvs("");
}
#endif
- op_free(rv2cv_op);
- force_next(WORD);
+ if (off)
+ op_free(pl_yylval.opval), force_next(PRIVATEREF);
+ else op_free(rv2cv_op), force_next(WORD);
pl_yylval.ival = 0;
TOKEN('&');
}
curmad('X', PL_thistoken);
PL_thistoken = newSVpvs("");
}
- force_next(WORD);
+ force_next(off ? PRIVATEREF : WORD);
if (!PL_lex_allbrackets &&
PL_lex_fakeeof > LEX_FAKEEOF_LOWLOGIC)
PL_lex_fakeeof = LEX_FAKEEOF_LOWLOGIC;
PL_nextwhite = nextPL_nextwhite;
curmad('X', PL_thistoken);
PL_thistoken = newSVpvs("");
- force_next(WORD);
+ force_next(off ? PRIVATEREF : WORD);
if (!PL_lex_allbrackets &&
PL_lex_fakeeof > LEX_FAKEEOF_LOWLOGIC)
PL_lex_fakeeof = LEX_FAKEEOF_LOWLOGIC;
#else
NEXTVAL_NEXTTOKE.opval = pl_yylval.opval;
PL_expect = XTERM;
- force_next(WORD);
+ force_next(off ? PRIVATEREF : WORD);
if (!PL_lex_allbrackets &&
PL_lex_fakeeof > LEX_FAKEEOF_LOWLOGIC)
PL_lex_fakeeof = LEX_FAKEEOF_LOWLOGIC;
if (*s == '{')
PRETERMBLOCK(DO);
if (*s != '\'') {
- d = scan_word(s, PL_tokenbuf, sizeof PL_tokenbuf, 1, &len);
- if (len) {
+ *PL_tokenbuf = '&';
+ d = scan_word(s, PL_tokenbuf + 1, sizeof PL_tokenbuf - 1,
+ 1, &len);
+ if (len && !keyword(PL_tokenbuf + 1, len, 0)) {
d = SKIPSPACE1(d);
- if (*d == '(') s = force_word(s,WORD,TRUE,TRUE,FALSE);
+ if (*d == '(') {
+ force_ident_maybe_lex('&');
+ s = d;
+ }
}
}
if (orig_keyword == KEY_do) {
case KEY_sub:
really_sub:
{
- char tmpbuf[sizeof PL_tokenbuf];
+ char * const tmpbuf = PL_tokenbuf + 1;
SSize_t tboffset = 0;
expectation attrful;
bool have_name, have_proto;
d = s;
s = SKIPSPACE2(s,tmpwhite);
#else
+ d = s;
s = skipspace(s);
#endif
attrful = XATTRBLOCK;
/* remember buffer pos'n for later force_word */
tboffset = s - PL_oldbufptr;
- d = scan_word(s, tmpbuf, sizeof tmpbuf, TRUE, &len);
+ d = scan_word(s, tmpbuf, sizeof PL_tokenbuf - 1, TRUE,
+ &len);
#ifdef PERL_MAD
if (PL_madskills)
nametoke = newSVpvn_flags(s, d - s, SvUTF8(PL_linestr));
#endif
- if (memchr(tmpbuf, ':', len))
+ *PL_tokenbuf = '&';
+ if (memchr(tmpbuf, ':', len) || key != KEY_sub
+ || pad_findmy_pvn(
+ PL_tokenbuf, len + 1, UTF ? SVf_UTF8 : 0
+ ) != NOT_IN_PAD)
sv_setpvn(PL_subname, tmpbuf, len);
else {
sv_setsv(PL_subname,PL_curstname);
SvUTF8_on(PL_subname);
have_name = TRUE;
-#ifdef PERL_MAD
+#ifdef PERL_MAD
start_force(0);
CURMAD('X', nametoke);
CURMAD('_', tmpwhite);
- (void) force_word(PL_oldbufptr + tboffset, WORD,
- FALSE, TRUE, TRUE);
+ force_ident_maybe_lex('&');
s = SKIPSPACE2(d,tmpwhite);
#else
#endif
}
else {
- if (key == KEY_my)
- Perl_croak(aTHX_ "Missing name in \"my sub\"");
+ if (key == KEY_my || key == KEY_our || key==KEY_state)
+ {
+ *d = '\0';
+ /* diag_listed_as: Missing name in "%s sub" */
+ Perl_croak(aTHX_
+ "Missing name in \"%s\"", PL_bufptr);
+ }
PL_expect = XTERMBLOCK;
attrful = XATTRTERM;
sv_setpvs(PL_subname,"?");
TOKEN(ANONSUB);
}
#ifndef PERL_MAD
- (void) force_word(PL_oldbufptr + tboffset, WORD,
- FALSE, TRUE, TRUE);
+ force_ident_maybe_lex('&');
#endif
- if (key == KEY_my)
- TOKEN(MYSUB);
TOKEN(SUB);
}
#pragma segment Main
#endif
-static int
-S_pending_ident(pTHX)
+static void
+S_force_ident_maybe_lex(pTHX_ char pit)
{
dVAR;
+ OP *o;
+ int force_type;
PADOFFSET tmp = 0;
- /* pit holds the identifier we read and pending_ident is reset */
- char pit = PL_pending_ident;
const STRLEN tokenbuf_len = strlen(PL_tokenbuf);
/* All routes through this function want to know if there is a colon. */
const char *const has_colon = (const char*) memchr (PL_tokenbuf, ':', tokenbuf_len);
- PL_pending_ident = 0;
- /* PL_realtokenstart = realtokenend = PL_bufptr - SvPVX(PL_linestr); */
- DEBUG_T({ PerlIO_printf(Perl_debug_log,
- "### Pending identifier '%s'\n", PL_tokenbuf); });
+ start_force(PL_curforce);
/* if we're in a my(), we can't allow dynamics here.
$foo'bar has already been turned into $foo::bar, so
PL_in_my == KEY_my ? "my" : "state", PL_tokenbuf),
UTF ? SVf_UTF8 : 0);
- pl_yylval.opval = newOP(OP_PADANY, 0);
- pl_yylval.opval->op_targ = allocmy(PL_tokenbuf, tokenbuf_len,
+ o = newOP(OP_PADANY, 0);
+ o->op_targ = allocmy(PL_tokenbuf, tokenbuf_len,
UTF ? SVf_UTF8 : 0);
- return PRIVATEREF;
+ force_type = PRIVATEREF;
+ goto doforce;
}
}
SV * const sym = newSVhek(stashname);
sv_catpvs(sym, "::");
sv_catpvn_flags(sym, PL_tokenbuf+1, tokenbuf_len - 1, (UTF ? SV_CATUTF8 : SV_CATBYTES ));
- pl_yylval.opval = (OP*)newSVOP(OP_CONST, 0, sym);
- pl_yylval.opval->op_private = OPpCONST_ENTERED;
- gv_fetchsv(sym,
+ o = (OP*)newSVOP(OP_CONST, 0, sym);
+ o->op_private = OPpCONST_ENTERED;
+ if (pit != '&')
+ gv_fetchsv(sym,
(PL_in_eval
? (GV_ADDMULTI | GV_ADDINEVAL)
: GV_ADDMULTI
((PL_tokenbuf[0] == '$') ? SVt_PV
: (PL_tokenbuf[0] == '@') ? SVt_PVAV
: SVt_PVHV));
- return WORD;
+ force_type = WORD;
+ goto doforce;
}
- pl_yylval.opval = newOP(OP_PADANY, 0);
- pl_yylval.opval->op_targ = tmp;
- return PRIVATEREF;
+ o = newOP(OP_PADANY, 0);
+ o->op_targ = tmp;
+ force_type = PRIVATEREF;
+ goto doforce;
}
}
}
/* build ops for a bareword */
- pl_yylval.opval = (OP*)newSVOP(OP_CONST, 0, newSVpvn_flags(PL_tokenbuf + 1,
+ o = (OP*)newSVOP(OP_CONST, 0, newSVpvn_flags(PL_tokenbuf + 1,
tokenbuf_len - 1,
UTF ? SVf_UTF8 : 0 ));
- pl_yylval.opval->op_private = OPpCONST_ENTERED;
- gv_fetchpvn_flags(PL_tokenbuf+1, tokenbuf_len - 1,
+ o->op_private = OPpCONST_ENTERED;
+ if (pit != '&')
+ gv_fetchpvn_flags(PL_tokenbuf+1, tokenbuf_len - 1,
(PL_in_eval ? (GV_ADDMULTI | GV_ADDINEVAL) : GV_ADD)
| ( UTF ? SVf_UTF8 : 0 ),
((PL_tokenbuf[0] == '$') ? SVt_PV
: (PL_tokenbuf[0] == '@') ? SVt_PVAV
: SVt_PVHV));
- return WORD;
+ force_type = WORD;
+
+ doforce:
+ NEXTVAL_NEXTTOKE.opval = o;
+ force_next(force_type);
}
STATIC void
}
sv_catpvs(repl, "{");
sv_catsv(repl, PL_sublex_info.repl);
- if (strchr(SvPVX(PL_sublex_info.repl), '#'))
- sv_catpvs(repl, "\n");
sv_catpvs(repl, "}");
SvEVALED_on(repl);
SvREFCNT_dec(PL_sublex_info.repl);
a whole string being evalled, or the contents of the current quote-
like operator.
- The three methods are:
- - Steal lines from the input stream (stream)
- - Scan the heredoc in PL_linestr and remove it therefrom (linestr)
- - Peek at the PL_linestr of outer lexing scopes (peek)
-
- They are used in these cases:
- file scope or filtered eval stream
- string eval linestr
- multiline quoted construct linestr
- single-line quoted construct in file stream
- single-line quoted construct in eval or quote peek
+ The two basic methods are:
+ - Steal lines from the input stream
+ - Scan the heredoc in PL_linestr and remove it therefrom
- Single-line also applies to heredocs that begin on the last line of a
- quote-like operator.
+ In a file scope or filtered eval, the first method is used; in a
+ string eval, the second.
- Peeking within a quote also involves falling back to the stream method,
- if the outer quote-like operators are all on one line (or the heredoc
- marker is on the last line).
+ In a quote-like operator, we have to choose between the two,
+ depending on where we can find a newline. We peek into outer lex-
+ ing scopes until we find one with a newline in it. If we reach the
+ outermost lexing scope and it is a file, we use the stream method.
+ Otherwise it is treated as an eval.
*/
STATIC char *
S_scan_heredoc(pTHX_ register char *s)
{
dVAR;
- SV *herewas;
I32 op_type = OP_SCALAR;
I32 len;
SV *tmpstr;
char term;
- const char *found_newline = 0;
char *d;
char *e;
char *peek;
s = olds;
}
#endif
- if ((infile && !PL_lex_inwhat)
- || !(found_newline = (char*)memchr((void*)s, '\n', PL_bufend - s))) {
- herewas = newSVpvn(s,PL_bufend-s);
- }
- else {
-#ifdef PERL_MAD
- herewas = newSVpvn(s-1,found_newline-s+1);
-#else
- s--;
- herewas = newSVpvn(s,found_newline-s);
-#endif
- }
#ifdef PERL_MAD
if (PL_madskills) {
tstart = SvPVX(PL_linestr) + stuffstart;
else
PL_thisstuff = newSVpvn(tstart, s - tstart);
}
-#endif
- s += SvCUR(herewas);
-#ifdef PERL_MAD
stuffstart = s - SvPVX(PL_linestr);
-
- if (found_newline)
- s--;
#endif
tmpstr = newSV_type(SVt_PVIV);
PL_multi_start = CopLINE(PL_curcop) + 1;
PL_multi_open = PL_multi_close = '<';
- if (PL_lex_inwhat && !found_newline) {
- /* Peek into the line buffer of the parent lexing scope, going up
- as many levels as necessary to find one with a newline after
- bufptr. See the comments in sublex_push for how IVX and NVX
- are abused.
- */
- SV *linestr = NUM2PTR(SV *, SvNVX(PL_linestr));
- char *bufptr = PL_sublex_info.super_bufptr;
- char *bufend = SvEND(linestr);
- char * const olds = s - SvCUR(herewas);
- char * const real_olds = s;
+ /* inside a string eval or quote-like operator */
+ if (!infile || PL_lex_inwhat) {
+ SV *linestr;
+ char *bufend;
+ char * const olds = s;
PERL_CONTEXT * const cx = &cxstack[cxstack_ix];
- shared = shared->ls_prev;
- if (!bufptr) {
- s = real_olds;
- goto streaming;
- }
- while (!(s = (char *)memchr((void *)bufptr, '\n', bufend-bufptr))){
- if (SvIVX(linestr)) {
- bufptr = INT2PTR(char *, SvIVX(linestr));
- linestr = NUM2PTR(SV *, SvNVX(linestr));
- bufend = SvEND(linestr);
- shared = shared->ls_prev;
- }
- else if (infile) {
- s = real_olds;
+ /* These two fields are not set until an inner lexing scope is
+ entered. But we need them set here. */
+ shared->ls_bufptr = s;
+ shared->ls_linestr = PL_linestr;
+ if (PL_lex_inwhat)
+ /* Look for a newline. If the current buffer does not have one,
+ peek into the line buffer of the parent lexing scope, going
+ up as many levels as necessary to find one with a newline
+ after bufptr.
+ */
+ while (!(s = (char *)memchr(
+ (void *)shared->ls_bufptr, '\n',
+ SvEND(shared->ls_linestr)-shared->ls_bufptr
+ ))) {
+ shared = shared->ls_prev;
+ /* shared is only null if we have gone beyond the outermost
+ lexing scope. In a file, we will have broken out of the
+ loop in the previous iteration. In an eval, the string buf-
+ fer ends with "\n;", so the while condition below will have
+ evaluated to false. So shared can never be null. */
+ assert(shared);
+ /* A LEXSHARED struct with a null ls_prev pointer is the outer-
+ most lexing scope. In a file, shared->ls_linestr at that
+ level is just one line, so there is no body to steal. */
+ if (infile && !shared->ls_prev) {
+ s = olds;
goto streaming;
}
- else {
- s = bufend;
- break;
- }
+ }
+ else { /* eval */
+ s = (char*)memchr((void*)s, '\n', PL_bufend - s);
+ assert(s);
}
+ linestr = shared->ls_linestr;
+ bufend = SvEND(linestr);
d = s;
while (s < bufend &&
(*s != '\n' || memNE(s,PL_tokenbuf,len)) ) {
++shared->herelines;
}
if (s >= bufend) {
- SvREFCNT_dec(herewas);
- SvREFCNT_dec(tmpstr);
- CopLINE_set(PL_curcop, (line_t)PL_multi_start-1);
- missingterm(PL_tokenbuf + 1);
- }
- if (CxTYPE(cx) == CXt_EVAL && CxOLD_OP_TYPE(cx) == OP_ENTEREVAL
- && cx->blk_eval.cur_text == linestr) {
- cx->blk_eval.cur_text = newSVsv(linestr);
- SvSCREAM_on(cx->blk_eval.cur_text);
- }
- sv_setpvn(herewas,bufptr,d-bufptr+1);
- sv_setpvn(tmpstr,d+1,s-d);
- s += len - 1;
- sv_catpvn(herewas,s,bufend-s);
- Copy(SvPVX_const(herewas),bufptr,SvCUR(herewas) + 1,char);
- SvCUR_set(linestr,
- bufptr-SvPVX_const(linestr)
- + SvCUR(herewas));
-
- s = olds;
- goto retval;
- }
- else if (!infile || found_newline) {
- char * const olds = s - SvCUR(herewas);
- PERL_CONTEXT * const cx = &cxstack[cxstack_ix];
- d = s;
- while (s < PL_bufend &&
- (*s != '\n' || memNE(s,PL_tokenbuf,len)) ) {
- if (*s++ == '\n')
- ++shared->herelines;
- }
- if (s >= PL_bufend) {
- SvREFCNT_dec(herewas);
- SvREFCNT_dec(tmpstr);
- CopLINE_set(PL_curcop, (line_t)PL_multi_start-1);
- missingterm(PL_tokenbuf + 1);
+ goto interminable;
}
sv_setpvn(tmpstr,d+1,s-d);
#ifdef PERL_MAD
/* s now points to the newline after the heredoc terminator.
d points to the newline before the body of the heredoc.
*/
+
+ /* We are going to modify linestr in place here, so set
+ aside copies of the string if necessary for re-evals or
+ (caller $n)[6]. */
/* See the Paranoia note in case LEX_INTERPEND in yylex, for why we
- check PL_sublex_info.re_eval_str. */
- if (PL_sublex_info.re_eval_start || PL_sublex_info.re_eval_str) {
+ check shared->re_eval_str. */
+ if (shared->re_eval_start || shared->re_eval_str) {
/* Set aside the rest of the regexp */
- if (!PL_sublex_info.re_eval_str)
- PL_sublex_info.re_eval_str =
- newSVpvn(PL_sublex_info.re_eval_start,
- PL_bufend - PL_sublex_info.re_eval_start);
- PL_sublex_info.re_eval_start -= s-d;
+ if (!shared->re_eval_str)
+ shared->re_eval_str =
+ newSVpvn(shared->re_eval_start,
+ bufend - shared->re_eval_start);
+ shared->re_eval_start -= s-d;
}
if (CxTYPE(cx) == CXt_EVAL && CxOLD_OP_TYPE(cx) == OP_ENTEREVAL
- && cx->blk_eval.cur_text == PL_linestr) {
- cx->blk_eval.cur_text = newSVsv(PL_linestr);
+ && cx->blk_eval.cur_text == linestr) {
+ cx->blk_eval.cur_text = newSVsv(linestr);
SvSCREAM_on(cx->blk_eval.cur_text);
}
/* Copy everything from s onwards back to d. */
- Move(s,d,PL_bufend-s + 1,char);
- SvCUR_set(PL_linestr, SvCUR(PL_linestr) - (s-d));
- PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
+ Move(s,d,bufend-s + 1,char);
+ SvCUR_set(linestr, SvCUR(linestr) - (s-d));
+ /* Setting PL_bufend only applies when we have not dug deeper
+ into other scopes, because sublex_done sets PL_bufend to
+ SvEND(PL_linestr). */
+ if (shared == PL_parser->lex_shared) PL_bufend = SvEND(linestr);
s = olds;
}
else
- sv_setpvs(tmpstr,""); /* avoid "uninitialized" warning */
- streaming:
- term = PL_tokenbuf[1];
- len--;
- while (s >= PL_bufend) { /* multiple line string? */
+ {
+ SV *linestr_save;
+ streaming:
+ sv_setpvs(tmpstr,""); /* avoid "uninitialized" warning */
+ term = PL_tokenbuf[1];
+ len--;
+ linestr_save = PL_linestr; /* must restore this afterwards */
+ d = s; /* and this */
+ PL_linestr = newSVpvs("");
+ PL_bufend = SvPVX(PL_linestr);
+ while (1) {
#ifdef PERL_MAD
if (PL_madskills) {
tstart = SvPVX(PL_linestr) + stuffstart;
PL_thisstuff = newSVpvn(tstart, PL_bufend - tstart);
}
#endif
- PL_bufptr = s;
+ PL_bufptr = PL_bufend;
CopLINE_set(PL_curcop,
PL_multi_start + shared->herelines);
if (!lex_next_chunk(LEX_NO_TERM)
&& (!SvCUR(tmpstr) || SvEND(tmpstr)[-1] != '\n')) {
- SvREFCNT_dec(herewas);
- SvREFCNT_dec(tmpstr);
- CopLINE_set(PL_curcop, (line_t)PL_multi_start - 1);
- missingterm(PL_tokenbuf + 1);
+ SvREFCNT_dec(linestr_save);
+ goto interminable;
}
CopLINE_set(PL_curcop, (line_t)PL_multi_start - 1);
if (!SvCUR(PL_linestr) || PL_bufend[-1] != '\n') {
stuffstart = s - SvPVX(PL_linestr);
#endif
shared->herelines++;
- PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
PL_last_lop = PL_last_uni = NULL;
#ifndef PERL_STRICT_CR
if (PL_bufend - PL_linestart >= 2) {
PL_bufend[-1] = '\n';
#endif
if (*s == term && memEQ(s,PL_tokenbuf + 1,len)) {
- STRLEN off = PL_bufend - 1 - SvPVX_const(PL_linestr);
- *(SvPVX(PL_linestr) + off ) = ' ';
- lex_grow_linestr(SvCUR(PL_linestr) + SvCUR(herewas) + 1);
- sv_catsv(PL_linestr,herewas);
+ SvREFCNT_dec(PL_linestr);
+ PL_linestr = linestr_save;
+ PL_linestart = SvPVX(linestr_save);
PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
- s = SvPVX(PL_linestr) + off; /* In case PV of PL_linestr moved. */
+ s = d;
+ break;
}
else {
- s = PL_bufend;
sv_catsv(tmpstr,PL_linestr);
}
+ }
}
- s++;
-retval:
PL_multi_end = CopLINE(PL_curcop);
if (SvCUR(tmpstr) + 5 < SvLEN(tmpstr)) {
SvPV_shrink_to_cur(tmpstr);
}
- SvREFCNT_dec(herewas);
if (!IN_BYTES) {
if (UTF && is_utf8_string((U8*)SvPVX_const(tmpstr), SvCUR(tmpstr)))
SvUTF8_on(tmpstr);
PL_lex_stuff = tmpstr;
pl_yylval.ival = op_type;
return s;
+
+ interminable:
+ SvREFCNT_dec(tmpstr);
+ CopLINE_set(PL_curcop, (line_t)PL_multi_start - 1);
+ missingterm(PL_tokenbuf + 1);
}
/* scan_inputsymbol