Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:35020 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 65740 invoked by uid 1010); 30 Jan 2008 13:41:37 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 65720 invoked from network); 30 Jan 2008 13:41:37 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 30 Jan 2008 13:41:37 -0000 Authentication-Results: pb1.pair.com header.from=dmitry@zend.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=dmitry@zend.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain zend.com designates 212.25.124.162 as permitted sender) X-PHP-List-Original-Sender: dmitry@zend.com X-Host-Fingerprint: 212.25.124.162 mail.zend.com Linux 2.5 (sometimes 2.4) (4) Received: from [212.25.124.162] ([212.25.124.162:62035] helo=mail.zend.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id EB/6C-47977-C8E70A74 for ; Wed, 30 Jan 2008 08:41:36 -0500 Received: (qmail 6800 invoked from network); 30 Jan 2008 13:41:26 -0000 Received: from mail.zend.net (HELO ?127.0.0.1?) (10.1.1.1) by cvs.zend.com with SMTP; 30 Jan 2008 13:41:26 -0000 Message-ID: <47A07E86.4010008@zend.com> Date: Wed, 30 Jan 2008 16:41:26 +0300 User-Agent: Thunderbird 2.0.0.9 (Windows/20071031) MIME-Version: 1.0 To: Stanislav Malyshev CC: 'PHP Internals' References: <479114FD.6010005@zend.com> In-Reply-To: <479114FD.6010005@zend.com> Content-Type: multipart/mixed; boundary="------------040507000102050707090403" Subject: Re: [PHP-DEV] nowdocs again From: dmitry@zend.com (Dmitry Stogov) --------------040507000102050707090403 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit The final nowdoc patches are attached. I'm going to commit them on Thursday in case of no objections. Thanks. Dmitry. Stanislav Malyshev wrote: > Hi all! > > I remember the topic of 'nowdocs' (if you don't remember what it is, > read on) was already discussed, but nothing really happened about it. > For those who just recently woke up from cryogenic sleep :), "nowdocs" > are heredocs extension that does not interpret the content (think single > quotes instead of double quotes). Should look something like: > $foo = <<<'END' > blah$fooblah > END > unline regular heredocs, $foo would be left as-is. I think now it's good > to add it to 5.3 (and I like 'FOO' syntax best of all variants). > > Any objections to this? --------------040507000102050707090403 Content-Type: text/plain; name="nowdoc-53.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="nowdoc-53.diff" Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.647.2.27.2.41.2.39 diff -u -p -d -r1.647.2.27.2.41.2.39 zend_compile.c --- Zend/zend_compile.c 29 Jan 2008 00:07:26 -0000 1.647.2.27.2.41.2.39 +++ Zend/zend_compile.c 30 Jan 2008 12:13:07 -0000 @@ -4641,6 +4641,7 @@ again: retval = T_ECHO; break; case T_END_HEREDOC: + case T_END_NOWDOC: efree(Z_STRVAL(zendlval->u.constant)); break; case EOF: Index: Zend/zend_highlight.c =================================================================== RCS file: /repository/ZendEngine2/zend_highlight.c,v retrieving revision 1.49.2.3.2.2.2.1 diff -u -p -d -r1.49.2.3.2.2.2.1 zend_highlight.c --- Zend/zend_highlight.c 31 Dec 2007 07:17:04 -0000 1.49.2.3.2.2.2.1 +++ Zend/zend_highlight.c 30 Jan 2008 12:13:07 -0000 @@ -150,6 +150,7 @@ ZEND_API void zend_highlight(zend_syntax } switch (token_type) { case T_END_HEREDOC: + case T_END_NOWDOC: zend_html_puts(token.value.str.val, token.value.str.len TSRMLS_CC); break; default: @@ -172,7 +173,7 @@ ZEND_API void zend_highlight(zend_syntax efree(token.value.str.val); break; } - } else if (token_type == T_END_HEREDOC) { + } else if (token_type == T_END_HEREDOC || token_type == T_END_NOWDOC) { efree(token.value.str.val); } token.type = 0; @@ -222,6 +223,7 @@ ZEND_API void zend_strip(TSRMLS_D) return; case T_END_HEREDOC: + case T_END_NOWDOC: zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng)); efree(token.value.str.val); /* read the following character, either newline or ; */ Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.160.2.4.2.8.2.13 diff -u -p -d -r1.160.2.4.2.8.2.13 zend_language_parser.y --- Zend/zend_language_parser.y 28 Dec 2007 13:22:00 -0000 1.160.2.4.2.8.2.13 +++ Zend/zend_language_parser.y 30 Jan 2008 12:13:07 -0000 @@ -145,6 +145,8 @@ %token T_PAAMAYIM_NEKUDOTAYIM %token T_NAMESPACE %token T_NS_C +%token T_START_NOWDOC +%token T_END_NOWDOC %% /* Rules */ @@ -719,6 +721,7 @@ common_scalar: | T_METHOD_C { $$ = $1; } | T_FUNC_C { $$ = $1; } | T_NS_C { $$ = $1; } + | T_START_NOWDOC T_ENCAPSED_AND_WHITESPACE T_END_NOWDOC { $$ = $2; } ; Index: Zend/zend_language_scanner.l =================================================================== RCS file: /repository/ZendEngine2/zend_language_scanner.l,v retrieving revision 1.131.2.11.2.13.2.4 diff -u -p -d -r1.131.2.11.2.13.2.4 zend_language_scanner.l --- Zend/zend_language_scanner.l 21 Jan 2008 19:39:55 -0000 1.131.2.11.2.13.2.4 +++ Zend/zend_language_scanner.l 30 Jan 2008 12:13:07 -0000 @@ -39,6 +39,9 @@ %x ST_HEREDOC %x ST_START_HEREDOC %x ST_END_HEREDOC +%x ST_NOWDOC +%x ST_START_NOWDOC +%x ST_END_NOWDOC %x ST_LOOKING_FOR_PROPERTY %x ST_LOOKING_FOR_VARNAME %x ST_VAR_OFFSET @@ -963,6 +966,8 @@ DOUBLE_QUOTES_CHARS ("{"*([^$"\\{]|("\\" BACKQUOTE_CHARS ("{"*([^$`\\{]|("\\"{ANY_CHAR}))|{BACKQUOTE_LITERAL_DOLLAR}) HEREDOC_CHARS ("{"*([^$\n\r\\{]|("\\"[^\n\r]))|{HEREDOC_LITERAL_DOLLAR}|({HEREDOC_NEWLINE}+({HEREDOC_NON_LABEL}|{HEREDOC_LABEL_NO_NEWLINE}))) +NOWDOC_CHARS ({NEWLINE}*(([^a-zA-Z_\x7f-\xff\n\r][^\n\r]*)|({LABEL}[^a-zA-Z0-9_\x7f-\xff;\n\r][^\n\r]*)|({LABEL}[;][^\n\r]+))) + %option noyylineno %option noyywrap %% @@ -2036,6 +2041,101 @@ HEREDOC_CHARS ("{"*([^$\n\r\\{]|(" } +%{ +/* BEGIN nowdoc */ +%} +b?"<<<"{TABS_AND_SPACES}[']{LABEL}[']{NEWLINE} { + int bprefix = (yytext[0] != '<') ? 1 : 0; + char *s; + CG(zend_lineno)++; + /* 3 is <<<, 2 is quotes, 1 is newline */ + CG(heredoc_len) = yyleng-bprefix-3-2-1-(yytext[yyleng-2]=='\r'?1:0); + s = yytext+bprefix+3; + while ((*s == ' ') || (*s == '\t')) { + s++; + CG(heredoc_len)--; + } + s++; /* first quote */ + CG(heredoc) = estrndup(s, CG(heredoc_len)); + BEGIN(ST_START_NOWDOC); + return T_START_NOWDOC; +} + +{ANY_CHAR} { + yyless(0); + BEGIN(ST_NOWDOC); +} + +{LABEL}";"?[\r\n] { + int label_len = yyleng - 1; + + if (yytext[label_len-1]==';') { + label_len--; + } + + if (label_len==CG(heredoc_len) && !memcmp(yytext, CG(heredoc), label_len)) { + yyless(label_len-1); + yyleng = 0; + BEGIN(ST_END_NOWDOC); + ZVAL_EMPTY_STRING(zendlval); + return T_ENCAPSED_AND_WHITESPACE; + } else { + yyless(label_len); + yymore(); + BEGIN(ST_NOWDOC); + } +} + +{NOWDOC_CHARS}*{NEWLINE}+{LABEL}";"?[\n\r] { + char *end = yytext + yyleng - 1; + + if (end[-1] == ';') { + end--; + yyleng--; + } + + if (yyleng > CG(heredoc_len) && !memcmp(end - CG(heredoc_len), CG(heredoc), CG(heredoc_len))) { + int len = yyleng - CG(heredoc_len) - 2; /* 2 for newline before and after label */ + + if (len > 0 && yytext[len - 1] == '\r' && yytext[len] == '\n') { + len--; + } + + /* Go back before last label char, to match in ST_END_HEREDOC state */ + yyless(yyleng - 2); + + /* Subtract the remaining label length. yyleng must include newline + * before label, for zend_highlight/strip, tokenizer, etc. */ + yyleng -= CG(heredoc_len) - 1; + + CG(increment_lineno) = 1; /* For newline before label */ + BEGIN(ST_END_NOWDOC); + + HANDLE_NEWLINES(yytext, len); + ZVAL_STRINGL(zendlval, yytext, len, 1); + return T_ENCAPSED_AND_WHITESPACE; + } else { + /* Go back to end of label, so the next match works correctly in case of + * a variable or another label at the beginning of the next line */ + yyless(yyleng - 1); + yymore(); + } +} + +{ANY_CHAR} { + Z_STRVAL_P(zendlval) = CG(heredoc); + Z_STRLEN_P(zendlval) = CG(heredoc_len); + yytext = CG(heredoc); + yyleng = CG(heredoc_len); + CG(heredoc) = NULL; + CG(heredoc_len) = 0; + BEGIN(ST_IN_SCRIPTING); + return T_END_NOWDOC; +} +%{ +/* END nowdoc */ +%} + ["] { BEGIN(ST_IN_SCRIPTING); return '"'; Index: Zend/tests/nowdoc.inc =================================================================== RCS file: Zend/tests/nowdoc.inc diff -N Zend/tests/nowdoc.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc.inc 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,11 @@ + 3, ); +class d { public function __construct() { $this->d = 4; } }; +$d = new d; + +?> + Index: Zend/tests/nowdoc_001.phpt =================================================================== RCS file: Zend/tests/nowdoc_001.phpt diff -N Zend/tests/nowdoc_001.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_001.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,24 @@ +--TEST-- +basic nowdoc syntax +--FILE-- + +--EXPECT-- +This is a nowdoc test. +This is another nowdoc test. +With another line in it. Index: Zend/tests/nowdoc_002.phpt =================================================================== RCS file: Zend/tests/nowdoc_002.phpt diff -N Zend/tests/nowdoc_002.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_002.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,23 @@ +--TEST-- +basic binary nowdoc syntax +--FILE-- + +--EXPECT-- +This is a nowdoc test. +This is another nowdoc test. Index: Zend/tests/nowdoc_003.phpt =================================================================== RCS file: Zend/tests/nowdoc_003.phpt diff -N Zend/tests/nowdoc_003.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_003.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,23 @@ +--TEST-- +simple variable replacement test (nowdoc) +--FILE-- + +--EXPECT-- +This is nowdoc test #$a. +This is nowdoc test #$b. Index: Zend/tests/nowdoc_004.phpt =================================================================== RCS file: Zend/tests/nowdoc_004.phpt diff -N Zend/tests/nowdoc_004.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_004.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,23 @@ +--TEST-- +braces variable replacement test (nowdoc) +--FILE-- + +--EXPECT-- +This is nowdoc test #{$a}. +This is nowdoc test #{$b}. Index: Zend/tests/nowdoc_005.phpt =================================================================== RCS file: Zend/tests/nowdoc_005.phpt diff -N Zend/tests/nowdoc_005.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_005.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,23 @@ +--TEST-- +unbraced complex variable replacement test (nowdoc) +--FILE-- +d. + +ENDOFNOWDOC; + +$x = <<<'ENDOFNOWDOC' +This is nowdoc test #s $a, $b, $c['c'], and $d->d. + +ENDOFNOWDOC; + +print "{$x}"; + +?> +--EXPECT-- +This is nowdoc test #s $a, $b, $c['c'], and $d->d. +This is nowdoc test #s $a, $b, $c['c'], and $d->d. Index: Zend/tests/nowdoc_006.phpt =================================================================== RCS file: Zend/tests/nowdoc_006.phpt diff -N Zend/tests/nowdoc_006.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_006.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,23 @@ +--TEST-- +braced complex variable replacement test (nowdoc) +--FILE-- +d}. + +ENDOFNOWDOC; + +$x = <<<'ENDOFNOWDOC' +This is nowdoc test #s {$a}, {$b}, {$c['c']}, and {$d->d}. + +ENDOFNOWDOC; + +print "{$x}"; + +?> +--EXPECT-- +This is nowdoc test #s {$a}, {$b}, {$c['c']}, and {$d->d}. +This is nowdoc test #s {$a}, {$b}, {$c['c']}, and {$d->d}. Index: Zend/tests/nowdoc_007.phpt =================================================================== RCS file: Zend/tests/nowdoc_007.phpt diff -N Zend/tests/nowdoc_007.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_007.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,23 @@ +--TEST-- +braced and unbraced complex variable replacement test (nowdoc) +--FILE-- +d}. + +ENDOFNOWDOC; + +$x = <<<'ENDOFNOWDOC' +This is nowdoc test #s $a, {$b}, {$c['c']}, and {$d->d}. + +ENDOFNOWDOC; + +print "{$x}"; + +?> +--EXPECT-- +This is nowdoc test #s $a, {$b}, {$c['c']}, and {$d->d}. +This is nowdoc test #s $a, {$b}, {$c['c']}, and {$d->d}. Index: Zend/tests/nowdoc_008.phpt =================================================================== RCS file: Zend/tests/nowdoc_008.phpt diff -N Zend/tests/nowdoc_008.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_008.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,17 @@ +--TEST-- +empty doc test (nowdoc) +--FILE-- + +--EXPECT-- Index: Zend/tests/nowdoc_009.phpt =================================================================== RCS file: Zend/tests/nowdoc_009.phpt diff -N Zend/tests/nowdoc_009.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_009.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,40 @@ +--TEST-- +Torture the T_END_NOWDOC rules (nowdoc) +--FILE-- + +--EXPECT-- +ENDOFNOWDOC ; + ENDOFNOWDOC; +ENDOFNOWDOC + ENDOFNOWDOC +$ENDOFNOWDOC; +ENDOFNOWDOC ; + ENDOFNOWDOC; +ENDOFNOWDOC + ENDOFNOWDOC +$ENDOFNOWDOC; + Index: Zend/tests/nowdoc_010.phpt =================================================================== RCS file: Zend/tests/nowdoc_010.phpt diff -N Zend/tests/nowdoc_010.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_010.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,33 @@ +--TEST-- +Torture the T_END_NOWDOC rules with variable expansions (nowdoc) +--FILE-- + +--EXPECT-- +{$fooledYou}ENDOFNOWDOC{$fooledYou} +ENDOFNOWDOC{$fooledYou} +{$fooledYou}ENDOFNOWDOC +{$fooledYou}ENDOFNOWDOC{$fooledYou} +ENDOFNOWDOC{$fooledYou} +{$fooledYou}ENDOFNOWDOC + Index: Zend/tests/nowdoc_011.phpt =================================================================== RCS file: Zend/tests/nowdoc_011.phpt diff -N Zend/tests/nowdoc_011.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_011.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,20 @@ +--TEST-- +Nowdocs CAN be used as static scalars. +--FILE-- + +--EXPECTF-- +If you DON'T see this, something's wrong. Index: Zend/tests/nowdoc_012.phpt =================================================================== RCS file: Zend/tests/nowdoc_012.phpt diff -N Zend/tests/nowdoc_012.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_012.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,25 @@ +--TEST-- +Test false labels +--FILE-- + +--EXPECT-- +This is a nowdoc test. +NOTREALLYEND; +Another line +NOTENDEITHER; +ENDOFNOWDOCWILLBESOON +Now let's finish it Index: Zend/tests/nowdoc_013.phpt =================================================================== RCS file: Zend/tests/nowdoc_013.phpt diff -N Zend/tests/nowdoc_013.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_013.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,26 @@ +--TEST-- +Test whitespace following end of nowdoc +--INI-- +highlight.string = #DD0000 +highlight.comment = #FF8000 +highlight.keyword = #007700 +highlight.bg = #FFFFFF +highlight.default = #0000BB +highlight.html = #000000 +--FILE-- + +EOF; +highlight_string($code); +?> +--EXPECT-- + +<?php
  $x 
= <<<'EOT'
some string    
EOT
  
$y 2;
?> +
+
Index: Zend/tests/nowdoc_014.phpt =================================================================== RCS file: Zend/tests/nowdoc_014.phpt diff -N Zend/tests/nowdoc_014.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_014.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,25 @@ +--TEST-- +Highliting empty nowdoc +--INI-- +highlight.string = #DD0000 +highlight.comment = #FF8000 +highlight.keyword = #007700 +highlight.bg = #FFFFFF +highlight.default = #0000BB +highlight.html = #000000 +--FILE-- + +EOF; +highlight_string($code); +?> +--EXPECT-- + +<?php
  $x 
= <<<'EOT'
EOT
  
$y 2;
?> +
+
Index: Zend/tests/nowdoc_015.phpt =================================================================== RCS file: Zend/tests/nowdoc_015.phpt diff -N Zend/tests/nowdoc_015.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_015.phpt 30 Jan 2008 12:13:07 -0000 @@ -0,0 +1,74 @@ +--TEST-- +Test nowdoc and line numbering +--FILE-- + +--EXPECT-- +6 +string(0) "" +10 +string(0) "" +14 +string(4) "test" +19 +string(4) "test" +24 +string(20) "test1 +test2 + +test3 + +" +34 +string(20) "test1 +test2 + +test3 + +" +44 +ok Index: ext/tokenizer/tokenizer.c =================================================================== RCS file: /repository/php-src/ext/tokenizer/tokenizer.c,v retrieving revision 1.31.2.5.2.7.2.2 diff -u -p -d -r1.31.2.5.2.7.2.2 tokenizer.c --- ext/tokenizer/tokenizer.c 31 Dec 2007 07:17:16 -0000 1.31.2.5.2.7.2.2 +++ ext/tokenizer/tokenizer.c 30 Jan 2008 12:13:07 -0000 @@ -178,7 +178,7 @@ static void tokenize(zval *return_value MAKE_STD_ZVAL(keyword); array_init(keyword); add_next_index_long(keyword, token_type); - if (token_type == T_END_HEREDOC) { + if (token_type == T_END_HEREDOC || token_type == T_END_NOWDOC) { if (CG(increment_lineno)) { token_line = ++CG(zend_lineno); CG(increment_lineno) = 0; --------------040507000102050707090403 Content-Type: text/plain; name="nowdoc-6.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="nowdoc-6.diff" Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.799 diff -u -p -d -r1.799 zend_compile.c --- Zend/zend_compile.c 29 Jan 2008 00:06:42 -0000 1.799 +++ Zend/zend_compile.c 30 Jan 2008 13:14:17 -0000 @@ -5010,6 +5010,7 @@ again: retval = T_ECHO; break; case T_END_HEREDOC: + case T_END_NOWDOC: efree(Z_STRVAL(zendlval->u.constant)); break; } Index: Zend/zend_highlight.c =================================================================== RCS file: /repository/ZendEngine2/zend_highlight.c,v retrieving revision 1.61 diff -u -p -d -r1.61 zend_highlight.c --- Zend/zend_highlight.c 31 Dec 2007 07:12:07 -0000 1.61 +++ Zend/zend_highlight.c 30 Jan 2008 13:14:17 -0000 @@ -134,6 +134,7 @@ ZEND_API void zend_highlight(zend_syntax } switch (token_type) { case T_END_HEREDOC: + case T_END_NOWDOC: zend_html_puts(Z_STRVAL(token), Z_STRLEN(token) TSRMLS_CC); break; default: @@ -155,7 +156,7 @@ ZEND_API void zend_highlight(zend_syntax efree(Z_UNIVAL(token).v); break; } - } else if (token_type == T_END_HEREDOC) { + } else if (token_type == T_END_HEREDOC || token_type == T_END_NOWDOC) { efree(Z_UNIVAL(token).v); } Z_TYPE(token) = 0; @@ -207,6 +208,7 @@ ZEND_API void zend_strip(TSRMLS_D) /* {{ return; case T_END_HEREDOC: + case T_END_NOWDOC: zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng)); efree(Z_STRVAL(token)); /* read the following character, either newline or ; */ Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.199 diff -u -p -d -r1.199 zend_language_parser.y --- Zend/zend_language_parser.y 31 Dec 2007 07:12:07 -0000 1.199 +++ Zend/zend_language_parser.y 30 Jan 2008 13:14:17 -0000 @@ -148,6 +148,8 @@ %token T_BINARY_HEREDOC %token T_NAMESPACE %token T_NS_C +%token T_START_NOWDOC +%token T_END_NOWDOC %% /* Rules */ @@ -725,6 +727,7 @@ common_scalar: | T_METHOD_C { $$ = $1; } | T_FUNC_C { $$ = $1; } | T_NS_C { $$ = $1; } + | T_START_NOWDOC T_ENCAPSED_AND_WHITESPACE T_END_NOWDOC { $$ = $2; } ; Index: Zend/zend_language_scanner.l =================================================================== RCS file: /repository/ZendEngine2/zend_language_scanner.l,v retrieving revision 1.176 diff -u -p -d -r1.176 zend_language_scanner.l --- Zend/zend_language_scanner.l 24 Jan 2008 18:08:06 -0000 1.176 +++ Zend/zend_language_scanner.l 30 Jan 2008 13:14:17 -0000 @@ -39,6 +39,9 @@ %x ST_HEREDOC %x ST_START_HEREDOC %x ST_END_HEREDOC +%x ST_NOWDOC +%x ST_START_NOWDOC +%x ST_END_NOWDOC %x ST_LOOKING_FOR_PROPERTY %x ST_LOOKING_FOR_VARNAME %x ST_VAR_OFFSET @@ -1409,6 +1412,8 @@ DOUBLE_QUOTES_CHARS ("{"*([^$"\\{]|("\\" BACKQUOTE_CHARS ("{"*([^$`\\{]|("\\"{ANY_CHAR}))|{BACKQUOTE_LITERAL_DOLLAR}) HEREDOC_CHARS ("{"*([^$\n\r\\{]|("\\"[^\n\r]))|{HEREDOC_LITERAL_DOLLAR}|({HEREDOC_NEWLINE}+({HEREDOC_NON_LABEL}|{HEREDOC_LABEL_NO_NEWLINE}))) +NOWDOC_CHARS ({NEWLINE}*(([^a-zA-Z_\x7f-\xff\n\r][^\n\r]*)|({LABEL}[^a-zA-Z0-9_\x7f-\xff;\n\r][^\n\r]*)|({LABEL}[;][^\n\r]+))) + %option noyylineno %option noyywrap %% @@ -2560,6 +2565,109 @@ HEREDOC_CHARS ("{"*([^$\n\r\\{]|(" } +%{ +/* BEGIN nowdoc */ +%} +b?"<<<"{TABS_AND_SPACES}[']{LABEL}[']{NEWLINE} { + int bprefix = (yytext[0] != '<') ? 1 : 0; + char *s; + CG(zend_lineno)++; + /* 3 is <<<, 2 is quotes, 1 is newline */ + CG(heredoc_len) = yyleng-bprefix-3-2-1-(yytext[yyleng-2]=='\r'?1:0); + s = yytext+bprefix+3; + while ((*s == ' ') || (*s == '\t')) { + s++; + CG(heredoc_len)--; + } + s++; /* first quote */ + CG(heredoc) = estrndup(s, CG(heredoc_len)); + + CG(literal_type) = bprefix?IS_STRING:ZEND_STR_TYPE; + BEGIN(ST_START_NOWDOC); + return T_START_NOWDOC; +} + +{ANY_CHAR} { + yyless(0); + BEGIN(ST_NOWDOC); +} + +{LABEL}";"?[\r\n] { + int label_len = yyleng - 1; + + if (yytext[label_len-1]==';') { + label_len--; + } + + if (label_len==CG(heredoc_len) && !memcmp(yytext, CG(heredoc), label_len)) { + yyless(label_len-1); + yyleng = 0; + BEGIN(ST_END_NOWDOC); + if (CG(literal_type) == IS_UNICODE) { + ZVAL_EMPTY_UNICODE(zendlval); + } else { + ZVAL_EMPTY_STRING(zendlval); + } + return T_ENCAPSED_AND_WHITESPACE; + } else { + yyless(label_len); + yymore(); + BEGIN(ST_NOWDOC); + } +} + +{NOWDOC_CHARS}*{NEWLINE}+{LABEL}";"?[\n\r] { + char *end = yytext + yyleng - 1; + + if (end[-1] == ';') { + end--; + yyleng--; + } + + if (yyleng > CG(heredoc_len) && !memcmp(end - CG(heredoc_len), CG(heredoc), CG(heredoc_len))) { + int len = yyleng - CG(heredoc_len) - 2; /* 2 for newline before and after label */ + + if (len > 0 && yytext[len - 1] == '\r' && yytext[len] == '\n') { + len--; + } + + /* Go back before last label char, to match in ST_END_HEREDOC state */ + yyless(yyleng - 2); + + /* Subtract the remaining label length. yyleng must include newline + * before label, for zend_highlight/strip, tokenizer, etc. */ + yyleng -= CG(heredoc_len) - 1; + + CG(increment_lineno) = 1; /* For newline before label */ + BEGIN(ST_END_NOWDOC); + + HANDLE_NEWLINES(yytext, len); + if (!zend_copy_scanner_string(zendlval, yytext, len, CG(literal_type), SCNG(output_conv) TSRMLS_CC)) { + return 0; + } + return T_ENCAPSED_AND_WHITESPACE; + } else { + /* Go back to end of label, so the next match works correctly in case of + * a variable or another label at the beginning of the next line */ + yyless(yyleng - 1); + yymore(); + } +} + +{ANY_CHAR} { + Z_STRVAL_P(zendlval) = CG(heredoc); + Z_STRLEN_P(zendlval) = CG(heredoc_len); + yytext = CG(heredoc); + yyleng = CG(heredoc_len); + CG(heredoc) = NULL; + CG(heredoc_len) = 0; + BEGIN(ST_IN_SCRIPTING); + return T_END_NOWDOC; +} +%{ +/* END nowdoc */ +%} + ["] { BEGIN(ST_IN_SCRIPTING); return '"'; Index: Zend/tests/nowdoc.inc =================================================================== RCS file: Zend/tests/nowdoc.inc diff -N Zend/tests/nowdoc.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc.inc 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,11 @@ + 3, ); +class d { public function __construct() { $this->d = 4; } }; +$d = new d; + +?> + Index: Zend/tests/nowdoc_001.phpt =================================================================== RCS file: Zend/tests/nowdoc_001.phpt diff -N Zend/tests/nowdoc_001.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_001.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,24 @@ +--TEST-- +basic nowdoc syntax +--FILE-- + +--EXPECT-- +This is a nowdoc test. +This is another nowdoc test. +With another line in it. Index: Zend/tests/nowdoc_002.phpt =================================================================== RCS file: Zend/tests/nowdoc_002.phpt diff -N Zend/tests/nowdoc_002.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_002.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,23 @@ +--TEST-- +basic binary nowdoc syntax +--FILE-- + +--EXPECT-- +This is a nowdoc test. +This is another nowdoc test. Index: Zend/tests/nowdoc_003.phpt =================================================================== RCS file: Zend/tests/nowdoc_003.phpt diff -N Zend/tests/nowdoc_003.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_003.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,23 @@ +--TEST-- +simple variable replacement test (nowdoc) +--FILE-- + +--EXPECT-- +This is nowdoc test #$a. +This is nowdoc test #$b. Index: Zend/tests/nowdoc_004.phpt =================================================================== RCS file: Zend/tests/nowdoc_004.phpt diff -N Zend/tests/nowdoc_004.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_004.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,23 @@ +--TEST-- +braces variable replacement test (nowdoc) +--FILE-- + +--EXPECT-- +This is nowdoc test #{$a}. +This is nowdoc test #{$b}. Index: Zend/tests/nowdoc_005.phpt =================================================================== RCS file: Zend/tests/nowdoc_005.phpt diff -N Zend/tests/nowdoc_005.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_005.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,23 @@ +--TEST-- +unbraced complex variable replacement test (nowdoc) +--FILE-- +d. + +ENDOFNOWDOC; + +$x = <<<'ENDOFNOWDOC' +This is nowdoc test #s $a, $b, $c['c'], and $d->d. + +ENDOFNOWDOC; + +print "{$x}"; + +?> +--EXPECT-- +This is nowdoc test #s $a, $b, $c['c'], and $d->d. +This is nowdoc test #s $a, $b, $c['c'], and $d->d. Index: Zend/tests/nowdoc_006.phpt =================================================================== RCS file: Zend/tests/nowdoc_006.phpt diff -N Zend/tests/nowdoc_006.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_006.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,23 @@ +--TEST-- +braced complex variable replacement test (nowdoc) +--FILE-- +d}. + +ENDOFNOWDOC; + +$x = <<<'ENDOFNOWDOC' +This is nowdoc test #s {$a}, {$b}, {$c['c']}, and {$d->d}. + +ENDOFNOWDOC; + +print "{$x}"; + +?> +--EXPECT-- +This is nowdoc test #s {$a}, {$b}, {$c['c']}, and {$d->d}. +This is nowdoc test #s {$a}, {$b}, {$c['c']}, and {$d->d}. Index: Zend/tests/nowdoc_007.phpt =================================================================== RCS file: Zend/tests/nowdoc_007.phpt diff -N Zend/tests/nowdoc_007.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_007.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,23 @@ +--TEST-- +braced and unbraced complex variable replacement test (nowdoc) +--FILE-- +d}. + +ENDOFNOWDOC; + +$x = <<<'ENDOFNOWDOC' +This is nowdoc test #s $a, {$b}, {$c['c']}, and {$d->d}. + +ENDOFNOWDOC; + +print "{$x}"; + +?> +--EXPECT-- +This is nowdoc test #s $a, {$b}, {$c['c']}, and {$d->d}. +This is nowdoc test #s $a, {$b}, {$c['c']}, and {$d->d}. Index: Zend/tests/nowdoc_008.phpt =================================================================== RCS file: Zend/tests/nowdoc_008.phpt diff -N Zend/tests/nowdoc_008.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_008.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,17 @@ +--TEST-- +empty doc test (nowdoc) +--FILE-- + +--EXPECT-- Index: Zend/tests/nowdoc_009.phpt =================================================================== RCS file: Zend/tests/nowdoc_009.phpt diff -N Zend/tests/nowdoc_009.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_009.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,40 @@ +--TEST-- +Torture the T_END_NOWDOC rules (nowdoc) +--FILE-- + +--EXPECT-- +ENDOFNOWDOC ; + ENDOFNOWDOC; +ENDOFNOWDOC + ENDOFNOWDOC +$ENDOFNOWDOC; +ENDOFNOWDOC ; + ENDOFNOWDOC; +ENDOFNOWDOC + ENDOFNOWDOC +$ENDOFNOWDOC; + Index: Zend/tests/nowdoc_010.phpt =================================================================== RCS file: Zend/tests/nowdoc_010.phpt diff -N Zend/tests/nowdoc_010.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_010.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,33 @@ +--TEST-- +Torture the T_END_NOWDOC rules with variable expansions (nowdoc) +--FILE-- + +--EXPECT-- +{$fooledYou}ENDOFNOWDOC{$fooledYou} +ENDOFNOWDOC{$fooledYou} +{$fooledYou}ENDOFNOWDOC +{$fooledYou}ENDOFNOWDOC{$fooledYou} +ENDOFNOWDOC{$fooledYou} +{$fooledYou}ENDOFNOWDOC + Index: Zend/tests/nowdoc_011.phpt =================================================================== RCS file: Zend/tests/nowdoc_011.phpt diff -N Zend/tests/nowdoc_011.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_011.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,20 @@ +--TEST-- +Nowdocs CAN be used as static scalars. +--FILE-- + +--EXPECTF-- +If you DON'T see this, something's wrong. Index: Zend/tests/nowdoc_012.phpt =================================================================== RCS file: Zend/tests/nowdoc_012.phpt diff -N Zend/tests/nowdoc_012.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_012.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,25 @@ +--TEST-- +Test false labels +--FILE-- + +--EXPECT-- +This is a nowdoc test. +NOTREALLYEND; +Another line +NOTENDEITHER; +ENDOFNOWDOCWILLBESOON +Now let's finish it Index: Zend/tests/nowdoc_013.phpt =================================================================== RCS file: Zend/tests/nowdoc_013.phpt diff -N Zend/tests/nowdoc_013.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_013.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,26 @@ +--TEST-- +Test whitespace following end of nowdoc +--INI-- +highlight.string = #DD0000 +highlight.comment = #FF8000 +highlight.keyword = #007700 +highlight.bg = #FFFFFF +highlight.default = #0000BB +highlight.html = #000000 +--FILE-- + +EOF; +highlight_string($code); +?> +--EXPECT-- + +<?php
  $x 
= <<<'EOT'
some string    
EOT
  
$y 2;
?> +
+
Index: Zend/tests/nowdoc_014.phpt =================================================================== RCS file: Zend/tests/nowdoc_014.phpt diff -N Zend/tests/nowdoc_014.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_014.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,25 @@ +--TEST-- +Highliting empty nowdoc +--INI-- +highlight.string = #DD0000 +highlight.comment = #FF8000 +highlight.keyword = #007700 +highlight.bg = #FFFFFF +highlight.default = #0000BB +highlight.html = #000000 +--FILE-- + +EOF; +highlight_string($code); +?> +--EXPECT-- + +<?php
  $x 
= <<<'EOT'
EOT
  
$y 2;
?> +
+
Index: Zend/tests/nowdoc_015.phpt =================================================================== RCS file: Zend/tests/nowdoc_015.phpt diff -N Zend/tests/nowdoc_015.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/nowdoc_015.phpt 30 Jan 2008 13:14:17 -0000 @@ -0,0 +1,99 @@ +--TEST-- +Test nowdoc and line numbering +--FILE-- + +--EXPECT-- +6 +string(0) "" +10 +string(0) "" +14 +string(4) "test" +19 +string(4) "test" +24 +string(20) "test1 +test2 + +test3 + +" +34 +string(20) "test1 +test2 + +test3 + +" +44 +ok +--UEXPECT-- +6 +unicode(0) "" +10 +unicode(0) "" +14 +unicode(4) "test" +19 +unicode(4) "test" +24 +unicode(20) "test1 +test2 + +test3 + +" +34 +unicode(20) "test1 +test2 + +test3 + +" +44 +ok Index: ext/tokenizer/tokenizer.c =================================================================== RCS file: /repository/php-src/ext/tokenizer/tokenizer.c,v retrieving revision 1.45 diff -u -p -d -r1.45 tokenizer.c --- ext/tokenizer/tokenizer.c 31 Dec 2007 07:12:17 -0000 1.45 +++ ext/tokenizer/tokenizer.c 30 Jan 2008 13:14:18 -0000 @@ -180,7 +180,7 @@ static void tokenize(zval *return_value MAKE_STD_ZVAL(keyword); array_init(keyword); add_next_index_long(keyword, token_type); - if (token_type == T_END_HEREDOC) { + if (token_type == T_END_HEREDOC || token_type == T_END_NOWDOC) { if (CG(increment_lineno)) { token_line = ++CG(zend_lineno); CG(increment_lineno) = 0; --------------040507000102050707090403--