remove toke_on_crack.c.inc
Lukas Mai [Wed, 18 Jul 2012 06:19:13 +0000 (08:19 +0200)]
MANIFEST
Parameters.xs
t/unicode.t [new file with mode: 0644]
toke_on_crack.c.inc [deleted file]

index a698862..0ef2b6e 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -39,4 +39,4 @@ t/strict_2.fail
 t/strict_3.fail
 t/strict_4.fail
 t/strict_5.fail
-toke_on_crack.c.inc
+t/unicode.t
index 1a4e58e..bb30693 100644 (file)
@@ -156,9 +156,6 @@ static int kw_flags(pTHX_ const char *kw_ptr, STRLEN kw_len, KWSpec *spec) {
 }
 
 
-#include "toke_on_crack.c.inc"
-
-
 static void free_defspec(pTHX_ void *vp) {
        DefaultParamSpec *dp = vp;
        op_free(dp->init);
@@ -216,6 +213,229 @@ enum {
        MY_ATTR_SPECIAL = 0x04
 };
 
+static void my_sv_cat_c(pTHX_ SV *sv, U32 c) {
+       char ds[UTF8_MAXBYTES + 1], *d;
+       d = uvchr_to_utf8(ds, c);
+       if (d - ds > 1) {
+               sv_utf8_upgrade(sv);
+       }
+       sv_catpvn(sv, ds, d - ds);
+}
+
+static bool my_is_uni_xidfirst(pTHX_ UV c) {
+       U8 tmpbuf[UTF8_MAXBYTES + 1];
+       uvchr_to_utf8(tmpbuf, c);
+       return is_utf8_xidfirst(tmpbuf);
+}
+
+static bool my_is_uni_xidcont(pTHX_ UV c) {
+       U8 tmpbuf[UTF8_MAXBYTES + 1];
+       uvchr_to_utf8(tmpbuf, c);
+       return is_utf8_xidcont(tmpbuf);
+}
+
+static SV *my_scan_word(pTHX_ bool allow_package) {
+       bool at_start, at_substart;
+       I32 c;
+       SV *sv = sv_2mortal(newSVpvs(""));
+       if (lex_bufutf8()) {
+               SvUTF8_on(sv);
+       }
+
+       at_start = at_substart = TRUE;
+       c = lex_peek_unichar(0);
+
+       while (c != -1) {
+               if (at_substart ? my_is_uni_xidfirst(aTHX_ c) : my_is_uni_xidcont(aTHX_ c)) {
+                       lex_read_unichar(0);
+                       my_sv_cat_c(aTHX_ sv, c);
+                       at_substart = FALSE;
+                       c = lex_peek_unichar(0);
+               } else if (allow_package && !at_substart && c == '\'') {
+                       lex_read_unichar(0);
+                       c = lex_peek_unichar(0);
+                       if (!my_is_uni_xidfirst(aTHX_ c)) {
+                               lex_stuff_pvs("'", 0);
+                               break;
+                       }
+                       sv_catpvs(sv, "'");
+                       at_substart = TRUE;
+               } else if (allow_package && (at_start || !at_substart) && c == ':') {
+                       lex_read_unichar(0);
+                       if (lex_peek_unichar(0) != ':') {
+                               lex_stuff_pvs(":", 0);
+                               break;
+                       }
+                       lex_read_unichar(0);
+                       c = lex_peek_unichar(0);
+                       if (!my_is_uni_xidfirst(aTHX_ c)) {
+                               lex_stuff_pvs("::", 0);
+                               break;
+                       }
+                       sv_catpvs(sv, "::");
+                       at_substart = TRUE;
+               } else {
+                       break;
+               }
+               at_start = FALSE;
+       }
+
+       return SvCUR(sv) ? sv : NULL;
+}
+
+static SV *my_scan_parens_tail(pTHX_ bool keep_backslash) {
+       I32 c, nesting;
+       SV *sv;
+       line_t start;
+
+       start = CopLINE(PL_curcop);
+
+       sv = sv_2mortal(newSVpvs(""));
+       if (lex_bufutf8()) {
+               SvUTF8_on(sv);
+       }
+
+       nesting = 0;
+       for (;;) {
+               c = lex_read_unichar(0);
+               if (c == EOF) {
+                       CopLINE_set(PL_curcop, start);
+                       return NULL;
+               }
+
+               if (c == '\\') {
+                       c = lex_read_unichar(0);
+                       if (c == EOF) {
+                               CopLINE_set(PL_curcop, start);
+                               return NULL;
+                       }
+                       if (keep_backslash || (c != '(' && c != ')')) {
+                               sv_catpvs(sv, "\\");
+                       }
+               } else if (c == '(') {
+                       nesting++;
+               } else if (c == ')') {
+                       if (!nesting) {
+                               break;
+                       }
+                       nesting--;
+               }
+
+               my_sv_cat_c(aTHX_ sv, c);
+       }
+
+       return sv;
+}
+
+static void my_check_prototype(pTHX_ const SV *declarator, SV *proto) {
+       char *start, *r, *w, *end;
+       STRLEN len;
+
+       /* strip spaces */
+       start = SvPV(proto, len);
+       end = start + len;
+
+       for (w = r = start; r < end; r++) {
+               if (!isSPACE(*r)) {
+                       *w++ = *r;
+               }
+       }
+       *w = '\0';
+       SvCUR_set(proto, w - start);
+       end = w;
+       len = end - start;
+
+       if (!ckWARN(WARN_ILLEGALPROTO)) {
+               return;
+       }
+
+       /* check for bad characters */
+       if (strspn(start, "$@%*;[]&\\_+") != len) {
+               SV *dsv = newSVpvs_flags("", SVs_TEMP);
+               warner(
+                       packWARN(WARN_ILLEGALPROTO),
+                       "Illegal character in prototype for %"SVf" : %s",
+                       SVfARG(declarator),
+                       SvUTF8(proto)
+                               ? sv_uni_display(
+                                       dsv,
+                                       proto,
+                                       len,
+                                       UNI_DISPLAY_ISPRINT
+                               )
+                               : pv_pretty(dsv, start, len, 60, NULL, NULL,
+                                       PERL_PV_ESCAPE_NONASCII
+                               )
+               );
+               return;
+       }
+
+       for (r = start; r < end; r++) {
+               switch (*r) {
+                       default:
+                               warner(
+                                       packWARN(WARN_ILLEGALPROTO),
+                                       "Illegal character in prototype for %"SVf" : %s",
+                                       SVfARG(declarator), r
+                               );
+                               return;
+
+                       case '_':
+                               if (r[1] && !strchr(";@%", *r)) {
+                                       warner(
+                                               packWARN(WARN_ILLEGALPROTO),
+                                               "Illegal character after '_' in prototype for %"SVf" : %s",
+                                               SVfARG(declarator), r
+                                       );
+                                       return;
+                               }
+                               break;
+
+                       case '@':
+                       case '%':
+                               if (r[1]) {
+                                       warner(
+                                               packWARN(WARN_ILLEGALPROTO),
+                                               "prototype after '%c' for %"SVf": %s",
+                                               *r, SVfARG(declarator), r + 1
+                                       );
+                                       return;
+                               }
+                               break;
+
+                       case '\\':
+                               r++;
+                               if (strchr("$@%&*", *r)) {
+                                       break;
+                               }
+                               if (*r == '[') {
+                                       r++;
+                                       for (; r < end && *r != ']'; r++) {
+                                               if (!strchr("$@%&*", *r)) {
+                                                       break;
+                                               }
+                                       }
+                                       if (*r == ']' && r[-1] != '[') {
+                                               break;
+                                       }
+                               }
+                               warner(
+                                       packWARN(WARN_ILLEGALPROTO),
+                                       "Illegal character after '\\' in prototype for %"SVf" : %s",
+                                       SVfARG(declarator), r
+                               );
+                               return;
+
+                       case '$':
+                       case '*':
+                       case '&':
+                       case ';':
+                       case '+':
+                               break;
+               }
+       }
+}
+
 static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len, const KWSpec *spec) {
        SV *declarator;
        I32 floor_ix;
@@ -229,7 +449,6 @@ static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len
        OP **attrs_sentinel, *body;
        unsigned builtin_attrs;
        STRLEN len;
-       char *s;
        I32 c;
 
        declarator = sv_2mortal(newSVpvn(keyword_ptr, keyword_len));
@@ -240,9 +459,7 @@ static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len
 
        /* function name */
        saw_name = NULL;
-       s = PL_parser->bufptr;
-       if ((spec->flags & FLAG_NAME_OK) && (len = S_scan_word(aTHX_ s, TRUE))) {
-               saw_name = sv_2mortal(newSVpvn_flags(s, len, PARSING_UTF ? SVf_UTF8 : 0));
+       if ((spec->flags & FLAG_NAME_OK) && (saw_name = my_scan_word(aTHX_ TRUE))) {
 
                if (PL_parser->expect != XSTATE) {
                        /* bail out early so we don't predeclare $saw_name */
@@ -262,10 +479,9 @@ static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len
                        builtin_attrs |= MY_ATTR_SPECIAL;
                }
 
-               lex_read_to(s + len);
                lex_read_space(0);
        } else if (!(spec->flags & FLAG_ANON_OK)) {
-               croak("I was expecting a function name, not \"%.*s\"", (int)(PL_parser->bufend - s), s);
+               croak("I was expecting a function name, not \"%.*s\"", (int)(PL_parser->bufend - PL_parser->bufptr), PL_parser->bufptr);
        } else {
                sv_catpvs(declarator, " (anon)");
        }
@@ -322,11 +538,10 @@ static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len
                                lex_read_unichar(0);
                                lex_read_space(0);
 
-                               s = PL_parser->bufptr;
-                               if (!(len = S_scan_word(aTHX_ s, FALSE))) {
+                               if (!(param = my_scan_word(aTHX_ FALSE))) {
                                        croak("In %"SVf": missing identifier", SVfARG(declarator));
                                }
-                               param = sv_2mortal(newSVpvf("%c%.*s", sigil, (int)len, s));
+                               sv_insert(param, 0, 0, &sigil, 1);
                                if (saw_slurpy) {
                                        croak("In %"SVf": I was expecting \")\" after \"%"SVf"\", not \"%"SVf"\"", SVfARG(declarator), SVfARG(saw_slurpy), SVfARG(param));
                                }
@@ -337,7 +552,6 @@ static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len
                                        saw_slurpy = param;
                                }
                                av_push(params, SvREFCNT_inc_simple_NN(param));
-                               lex_read_to(s + len);
                                lex_read_space(0);
 
                                c = lex_peek_unichar(0);
@@ -414,11 +628,11 @@ static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len
                        lex_stuff_pvs(":", 0);
                        c = ':';
                } else {
-                       proto = sv_2mortal(newSVpvs(""));
-                       if (!S_scan_str(aTHX_ proto, FALSE, FALSE)) {
+                       lex_read_unichar(0);
+                       if (!(proto = my_scan_parens_tail(aTHX_ FALSE))) {
                                croak("In %"SVf": prototype not terminated", SVfARG(declarator));
                        }
-                       S_check_prototype(aTHX_ declarator, proto);
+                       my_check_prototype(aTHX_ declarator, proto);
                        lex_read_space(0);
                        c = lex_peek_unichar(0);
                }
@@ -445,14 +659,10 @@ static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len
                        for (;;) {
                                SV *attr;
 
-                               s = PL_parser->bufptr;
-                               if (!(len = S_scan_word(aTHX_ s, FALSE))) {
+                               if (!(attr = my_scan_word(aTHX_ FALSE))) {
                                        break;
                                }
 
-                               attr = sv_2mortal(newSVpvn_flags(s, len, PARSING_UTF ? SVf_UTF8 : 0));
-
-                               lex_read_to(s + len);
                                lex_read_space(0);
                                c = lex_peek_unichar(0);
 
@@ -465,11 +675,14 @@ static int parse_fun(pTHX_ OP **pop, const char *keyword_ptr, STRLEN keyword_len
                                                attr = NULL;
                                        }
                                } else {
-                                       SV *sv = sv_2mortal(newSVpvs(""));
-                                       if (!S_scan_str(aTHX_ sv, TRUE, TRUE)) {
+                                       SV *sv;
+                                       lex_read_unichar(0);
+                                       if (!(sv = my_scan_parens_tail(aTHX_ TRUE))) {
                                                croak("In %"SVf": unterminated attribute parameter in attribute list", SVfARG(declarator));
                                        }
+                                       sv_catpvs(attr, "(");
                                        sv_catsv(attr, sv);
+                                       sv_catpvs(attr, ")");
 
                                        lex_read_space(0);
                                        c = lex_peek_unichar(0);
diff --git a/t/unicode.t b/t/unicode.t
new file mode 100644 (file)
index 0000000..6b1088e
--- /dev/null
@@ -0,0 +1,40 @@
+#!perl
+use utf8;
+use Test::More tests => 19;
+
+use warnings FATAL => 'all';
+use strict;
+
+use Function::Parameters;
+
+fun hörps($x) { $x * 2 }
+fun drau($spın̈al_tap) { $spın̈al_tap * 3 }
+fun ääää($éééééé) { $éééééé * 4 }
+
+is hörps(10), 20;
+is drau(11), 33;
+is ääää(12), 48;
+
+is eval('fun á(){} 1'), 1;
+is á(42), undef;
+
+is eval('fun ́(){} 1'), undef;
+like $@, qr/ function body/;
+
+is eval(q<fun 'hi(){} 1>), undef;
+like $@, qr/ function body/;
+
+is eval('fun ::hi(){} 1'), 1;
+is hi(42), undef;
+
+is eval('fun 123(){} 1'), undef;
+like $@, qr/ function body/;
+
+is eval('fun main::234(){} 1'), undef;
+like $@, qr/ function body/;
+
+is eval('fun m123(){} 1'), 1;
+is m123(42), undef;
+
+is eval('fun ::m234(){} 1'), 1;
+is m234(42), undef;
diff --git a/toke_on_crack.c.inc b/toke_on_crack.c.inc
deleted file mode 100644 (file)
index 1607c78..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * This code was copied from perl/toke.c and subsequently butchered
- * by Lukas Mai (2012).
- */
-/* vi: set ft=c: */
-
-/* vvvvvvvvvvvvvvvvvvvvv I HAVE NO IDEA WHAT I'M DOING vvvvvvvvvvvvvvvvvvvv */
-#define PL_linestr              (PL_parser->linestr)
-#define PL_copline              (PL_parser->copline)
-#define PL_bufptr               (PL_parser->bufptr)
-#define PL_bufend               (PL_parser->bufend)
-#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_multi_end            (PL_parser->multi_end)
-#define PL_rsfp                 (PL_parser->rsfp)
-
-#define CLINE (PL_copline = (CopLINE(PL_curcop) < PL_copline ? CopLINE(PL_curcop) : PL_copline))
-
-#ifdef USE_UTF8_SCRIPTS
-#   define PARSING_UTF (!IN_BYTES)
-#else
-#   define PARSING_UTF ((PL_linestr && DO_UTF8(PL_linestr)) || (PL_hints & HINT_UTF8))
-#endif
-
-static STRLEN S_scan_word(pTHX_ const char *start, int allow_package) {
-       const char *s = start;
-       for (;;) {
-               if (isALNUM(*s) || (!PARSING_UTF && isALNUMC_L1(*s))) {  /* UTF handled below */
-                       s++;
-               } else if (allow_package && s > start && *s == '\'' && isIDFIRST_lazy_if(s+1, PARSING_UTF)) {
-                       s++;
-               } else if (allow_package && s[0] == ':' && s[1] == ':' && isIDFIRST_lazy_if(s+2, PARSING_UTF)) {
-                       s += 2;
-               } else if (PARSING_UTF && UTF8_IS_START(*s) && isALNUM_utf8((U8*)s)) {
-                       do {
-                               s += UTF8SKIP(s);
-                       } while (UTF8_IS_CONTINUED(*s) && is_utf8_mark((U8*)s));
-               } else {
-                       return s - start;
-               }
-       }
-}
-
-static char *S_scan_str(pTHX_ SV *sv, int keep_quoted, int keep_delims) {
-       dVAR;
-       char *start = PL_bufptr;
-       const char *tmps;                   /* temp string, used for delimiter matching */
-       char *s = start;                    /* current position in the buffer */
-       char term;                          /* terminating character */
-       char *to;                           /* current position in the sv's data */
-       I32 brackets = 1;                   /* bracket nesting level */
-       bool has_utf8 = FALSE;              /* is there any utf8 content? */
-       I32 termcode;                       /* terminating char. code */
-       U8 termstr[UTF8_MAXBYTES];          /* terminating string */
-       STRLEN termlen;                     /* length of terminating string */
-       int last_off = 0;                   /* last position for nesting bracket */
-
-       /* XXX ATTENTION: we don't skip whitespace! */
-
-       /* mark where we are, in case we need to report errors */
-       CLINE;
-
-       /* after skipping whitespace, the next character is the terminator */
-       term = *s;
-       if (!PARSING_UTF) {
-               termcode = termstr[0] = term;
-               termlen = 1;
-       }
-       else {
-               termcode = IF_HAVE_PERL_5_16(
-                       utf8_to_uvchr_buf((U8*)s, (U8*)PL_bufend, &termlen),
-                       utf8_to_uvchr((U8*)s, &termlen)
-               );
-               Copy(s, termstr, termlen, U8);
-               if (!UTF8_IS_INVARIANT(term))
-                       has_utf8 = TRUE;
-       }
-
-       /* mark where we are */
-       PL_multi_start = CopLINE(PL_curcop);
-       PL_multi_open = term;
-
-       /* find corresponding closing delimiter */
-       if (term && (tmps = strchr("([{< )]}> )]}>",term)))
-               termcode = termstr[0] = term = tmps[5];
-
-       PL_multi_close = term;
-
-       {
-               STRLEN dummy;
-               SvPV_force(sv, dummy);
-               sv_setpvs(sv, "");
-               SvGROW(sv, 80);
-       }
-
-       /* move past delimiter and try to read a complete string */
-       if (keep_delims)
-               sv_catpvn(sv, s, termlen);
-       s += termlen;
-       for (;;) {
-               if (PL_encoding && !PARSING_UTF) {
-                       bool cont = TRUE;
-
-                       while (cont) {
-                               int offset = s - SvPVX_const(PL_linestr);
-                               const bool found = sv_cat_decode(sv, PL_encoding, PL_linestr,
-                                                                &offset, (char*)termstr, termlen);
-                               const char * const ns = SvPVX_const(PL_linestr) + offset;
-                               char * const svlast = SvEND(sv) - 1;
-
-                               for (; s < ns; s++) {
-                                       if (*s == '\n' && !PL_rsfp &&
-                                               IF_HAVE_PERL_5_16(
-                                                       !PL_parser->filtered,
-                                                       TRUE
-                                               )
-                                       )
-                                               CopLINE_inc(PL_curcop);
-                               }
-                               if (!found)
-                                       goto read_more_line;
-                               else {
-                                       /* handle quoted delimiters */
-                                       if (SvCUR(sv) > 1 && *(svlast-1) == '\\') {
-                                               const char *t;
-                                               for (t = svlast-2; t >= SvPVX_const(sv) && *t == '\\';)
-                                                       t--;
-                                               if ((svlast-1 - t) % 2) {
-                                                       if (!keep_quoted) {
-                                                               *(svlast-1) = term;
-                                                               *svlast = '\0';
-                                                               SvCUR_set(sv, SvCUR(sv) - 1);
-                                                       }
-                                                       continue;
-                                               }
-                                       }
-                                       if (PL_multi_open == PL_multi_close) {
-                                               cont = FALSE;
-                                       }
-                                       else {
-                                               const char *t;
-                                               char *w;
-                                               for (t = w = SvPVX(sv)+last_off; t < svlast; w++, t++) {
-                                                       /* At here, all closes are "was quoted" one,
-                                                          so we don't check PL_multi_close. */
-                                                       if (*t == '\\') {
-                                                               if (!keep_quoted && *(t+1) == PL_multi_open)
-                                                                       t++;
-                                                               else
-                                                                       *w++ = *t++;
-                                                       }
-                                                       else if (*t == PL_multi_open)
-                                                               brackets++;
-
-                                                       *w = *t;
-                                               }
-                                               if (w < t) {
-                                                       *w++ = term;
-                                                       *w = '\0';
-                                                       SvCUR_set(sv, w - SvPVX_const(sv));
-                                               }
-                                               last_off = w - SvPVX(sv);
-                                               if (--brackets <= 0)
-                                                       cont = FALSE;
-                                       }
-                               }
-                       }
-                       if (!keep_delims) {
-                               SvCUR_set(sv, SvCUR(sv) - 1);
-                               *SvEND(sv) = '\0';
-                       }
-                       break;
-               }
-
-               /* extend sv if need be */
-               SvGROW(sv, SvCUR(sv) + (PL_bufend - s) + 1);
-               /* set 'to' to the next character in the sv's string */
-               to = SvPVX(sv)+SvCUR(sv);
-
-               /* if open delimiter is the close delimiter read unbridle */
-               if (PL_multi_open == PL_multi_close) {
-                       for (; s < PL_bufend; s++,to++) {
-                               /* embedded newlines increment the current line number */
-                               if (*s == '\n' && !PL_rsfp &&
-                                       IF_HAVE_PERL_5_16(
-                                               !PL_parser->filtered,
-                                               1
-                                       )
-                               )
-                                       CopLINE_inc(PL_curcop);
-                               /* handle quoted delimiters */
-                               if (*s == '\\' && s+1 < PL_bufend && term != '\\') {
-                                       if (!keep_quoted && s[1] == term)
-                                               s++;
-                               /* any other quotes are simply copied straight through */
-                                       else
-                                               *to++ = *s++;
-                               }
-                               /* terminate when run out of buffer (the for() condition), or
-                                  have found the terminator */
-                               else if (*s == term) {
-                                       if (termlen == 1)
-                                               break;
-                                       if (s+termlen <= PL_bufend && memEQ(s, (char*)termstr, termlen))
-                                               break;
-                               }
-                               else if (!has_utf8 && !UTF8_IS_INVARIANT((U8)*s) && PARSING_UTF)
-                                       has_utf8 = TRUE;
-                               *to = *s;
-                       }
-               }
-
-               /* if the terminator isn't the same as the start character (e.g.,
-                  matched brackets), we have to allow more in the quoting, and
-                  be prepared for nested brackets.
-               */
-               else {
-                       /* read until we run out of string, or we find the terminator */
-                       for (; s < PL_bufend; s++,to++) {
-                               /* embedded newlines increment the line count */
-                               if (*s == '\n' && !PL_rsfp &&
-                                       IF_HAVE_PERL_5_16(
-                                               !PL_parser->filtered,
-                                               1
-                                       )
-                               )
-                                       CopLINE_inc(PL_curcop);
-                               /* backslashes can escape the open or closing characters */
-                               if (*s == '\\' && s+1 < PL_bufend) {
-                                       if (!keep_quoted &&
-                                               ((s[1] == PL_multi_open) || (s[1] == PL_multi_close)))
-                                               s++;
-                                       else
-                                               *to++ = *s++;
-                               }
-                               /* allow nested opens and closes */
-                               else if (*s == PL_multi_close && --brackets <= 0)
-                                       break;
-                               else if (*s == PL_multi_open)
-                                       brackets++;
-                               else if (!has_utf8 && !UTF8_IS_INVARIANT((U8)*s) && PARSING_UTF)
-                                       has_utf8 = TRUE;
-                               *to = *s;
-                       }
-               }
-               /* terminate the copied string and update the sv's end-of-string */
-               *to = '\0';
-               SvCUR_set(sv, to - SvPVX_const(sv));
-
-               /*
-                * this next chunk reads more into the buffer if we're not done yet
-                */
-
-               if (s < PL_bufend)
-                       break;              /* handle case where we are done yet :-) */
-
-#ifndef PERL_STRICT_CR
-               if (to - SvPVX_const(sv) >= 2) {
-                       if ((to[-2] == '\r' && to[-1] == '\n') ||
-                           (to[-2] == '\n' && to[-1] == '\r'))
-                       {
-                               to[-2] = '\n';
-                               to--;
-                               SvCUR_set(sv, to - SvPVX_const(sv));
-                       }
-                       else if (to[-1] == '\r')
-                               to[-1] = '\n';
-               }
-               else if (to - SvPVX_const(sv) == 1 && to[-1] == '\r')
-                       to[-1] = '\n';
-#endif
-
-        read_more_line:
-               /* if we're out of file, or a read fails, bail and reset the current
-                  line marker so we can report where the unterminated string began
-               */
-               CopLINE_inc(PL_curcop);
-               PL_bufptr = PL_bufend;
-               if (!lex_next_chunk(0)) {
-                       CopLINE_set(PL_curcop, (line_t)PL_multi_start);
-                       return NULL;
-               }
-               s = PL_bufptr;
-       }
-
-       /* at this point, we have successfully read the delimited string */
-
-       if (!PL_encoding || PARSING_UTF) {
-               if (keep_delims)
-                       sv_catpvn(sv, s, termlen);
-               s += termlen;
-       }
-       if (has_utf8 || PL_encoding)
-               SvUTF8_on(sv);
-
-       PL_multi_end = CopLINE(PL_curcop);
-
-       /* if we allocated too much space, give some back */
-       if (SvCUR(sv) + 5 < SvLEN(sv)) {
-               SvLEN_set(sv, SvCUR(sv) + 1);
-               SvPV_renew(sv, SvLEN(sv));
-       }
-
-       PL_bufptr = s;
-       return s;
-}
-
-static void S_check_prototype(pTHX_ const SV *declarator, SV *proto) {
-       bool bad_proto = FALSE;
-       bool in_brackets = FALSE;
-       char greedy_proto = ' ';
-       bool proto_after_greedy_proto = FALSE;
-       bool must_be_last = FALSE;
-       bool underscore = FALSE;
-       bool seen_underscore = FALSE;
-       const bool warnillegalproto = ckWARN(WARN_ILLEGALPROTO);
-       char *d, *p;
-       STRLEN tmp, tmplen;
-
-       /* strip spaces and check for bad characters */
-       d = SvPV(proto, tmplen);
-       tmp = 0;
-       for (p = d; tmplen; tmplen--, ++p) {
-               if (!isSPACE(*p)) {
-                       d[tmp++] = *p;
-
-                       if (warnillegalproto) {
-                               if (must_be_last) {
-                                       proto_after_greedy_proto = TRUE;
-                               }
-                               if (!strchr("$@%*;[]&\\_+", *p) || *p == '\0') {
-                                       bad_proto = TRUE;
-                               } else {
-                                       if (underscore) {
-                                               if (!strchr(";@%", *p)) {
-                                                       bad_proto = TRUE;
-                                               }
-                                               underscore = FALSE;
-                                       }
-                                       if (*p == '[') {
-                                               in_brackets = TRUE;
-                                       } else if (*p == ']') {
-                                               in_brackets = FALSE;
-                                       } else if (
-                                               (*p == '@' || *p == '%') &&
-                                               (tmp < 2 || d[tmp - 2] != '\\') &&
-                                               !in_brackets
-                                       ) {
-                                               must_be_last = TRUE;
-                                               greedy_proto = *p;
-                                       } else if (*p == '_') {
-                                               underscore = seen_underscore = TRUE;
-                                       }
-                               }
-                       }
-               }
-       }
-       d[tmp] = '\0';
-       SvCUR_set(proto, tmp);
-       if (proto_after_greedy_proto) {
-               Perl_warner(aTHX_ packWARN(WARN_ILLEGALPROTO),
-                       "In %"SVf": prototype after '%c': %s",
-                        SVfARG(declarator), greedy_proto, d
-               );
-       }
-       if (bad_proto) {
-               SV *dsv = newSVpvs_flags("", SVs_TEMP);
-               Perl_warner(aTHX_ packWARN(WARN_ILLEGALPROTO),
-                       "In %"SVf": illegal character %sin prototype: %s",
-                       SVfARG(declarator),
-                       seen_underscore ? "after '_' " : "",
-                       SvUTF8(proto)
-                               ? sv_uni_display(dsv,
-                                       newSVpvn_flags(d, tmp, SVs_TEMP | SVf_UTF8),
-                                       tmp,
-                                       UNI_DISPLAY_ISPRINT
-                               )
-                               : pv_pretty(dsv, d, tmp, 60, NULL, NULL,
-                                       PERL_PV_ESCAPE_NONASCII
-                               )
-               );
-       }
-       SvCUR_set(proto, tmp);
-}
-
-#undef CLINE
-/* ^^^^^^^^^^^^^^^^^^^^^ I HAVE NO IDEA WHAT I'M DOING ^^^^^^^^^^^^^^^^^^^^ */