* parse.y (words, qwords): word list literal rules.

* parse.y (parse_string): ditto.

* parse.y (yylex): %W: word list literal with interpolation. [new]


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2598 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2002-06-26 08:01:00 +00:00
parent 6037d1cf3d
commit 0fdfc0bbef
4 changed files with 150 additions and 126 deletions

View File

@ -1,3 +1,11 @@
Wed Jun 26 15:40:00 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net>
* parse.y (words, qwords): word list literal rules.
* parse.y (parse_string): ditto.
* parse.y (yylex): %W: word list literal with interpolation. [new]
Tue Jun 25 18:53:34 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net> Tue Jun 25 18:53:34 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net>
* parse.y (string1, xstring, regexp): moved lex_strnest * parse.y (string1, xstring, regexp): moved lex_strnest

View File

@ -1,3 +1,14 @@
: parser
%W(...) notation, word list literal like %w(...) with the
exception that #{} interpolation is allowed.
: parser
Now arbitrary statements are allowed inside #{} interpolation
without escapes. In other hand, they can no longer access to
variables defined in eval.
: parser : parser
Digits preceded minus sign is a literal integer. Digits preceded minus sign is a literal integer.

253
parse.y
View File

@ -161,6 +161,9 @@ static void top_local_setup();
#define NODE_STRTERM NODE_ZARRAY /* nothing to gc */ #define NODE_STRTERM NODE_ZARRAY /* nothing to gc */
#define NODE_HEREDOC NODE_ARRAY /* 1, 3 to gc */ #define NODE_HEREDOC NODE_ARRAY /* 1, 3 to gc */
#define nd_func u1.id
#define nd_term u2.id
#define nd_paren u3.id
%} %}
@ -222,11 +225,12 @@ static void top_local_setup();
%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR %token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR
%token <val> tINTEGER tFLOAT tSTRING_CONTENT %token <val> tINTEGER tFLOAT tSTRING_CONTENT
%token <node> tNTH_REF tBACK_REF tQWORDS %token <node> tNTH_REF tBACK_REF
%token <num> tREGEXP_END %token <num> tREGEXP_END
%type <node> singleton strings string string1 xstring regexp %type <node> singleton strings string string1 xstring regexp
%type <node> string_contents xstring_contents string_content %type <node> string_contents xstring_contents string_content
%type <node> words qwords word_list qword_list word
%type <val> literal numeric %type <val> literal numeric
%type <node> bodystmt compstmt stmts stmt expr arg primary command command_call method_call %type <node> bodystmt compstmt stmts stmt expr arg primary command command_call method_call
%type <node> expr_value arg_value primary_value block_call_value %type <node> expr_value arg_value primary_value block_call_value
@ -267,7 +271,7 @@ static void top_local_setup();
%token tLBRACE_ARG /* { */ %token tLBRACE_ARG /* { */
%token tSTAR /* * */ %token tSTAR /* * */
%token tAMPER /* & */ %token tAMPER /* & */
%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG %token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG
%token tSTRING_DBEG tSTRING_DVAR tSTRING_END %token tSTRING_DBEG tSTRING_DVAR tSTRING_END
/* /*
@ -1292,7 +1296,8 @@ primary : literal
| strings | strings
| xstring | xstring
| regexp | regexp
| tQWORDS | words
| qwords
| var_ref | var_ref
| backref | backref
| tFID | tFID
@ -1851,6 +1856,54 @@ regexp : tREGEXP_BEG xstring_contents tREGEXP_END
} }
; ;
words : tWORDS_BEG ' ' tSTRING_END
{
$$ = NEW_ZARRAY();
}
| tWORDS_BEG word_list tSTRING_END
{
$$ = $2;
}
;
word_list : /* none */
{
lex_strnest = 0;
$$ = 0;
}
| word_list word ' '
{
$$ = list_append($1, $2);
}
;
word : string_content
| word string_content
{
$$ = literal_concat($1, $2);
}
qwords : tQWORDS_BEG ' ' tSTRING_END
{
$$ = NEW_ZARRAY();
}
| tQWORDS_BEG qword_list tSTRING_END
{
$$ = $2;
}
;
qword_list : /* none */
{
lex_strnest = 0;
$$ = 0;
}
| qword_list tSTRING_CONTENT ' '
{
$$ = list_append($1, NEW_STR($2));
}
;
string_contents : /* none */ string_contents : /* none */
{ {
lex_strnest = 0; lex_strnest = 0;
@ -1916,8 +1969,8 @@ term_push : /* none */
{ {
if (($$ = quoted_term) == -1 && if (($$ = quoted_term) == -1 &&
nd_type(lex_strterm) == NODE_STRTERM && nd_type(lex_strterm) == NODE_STRTERM &&
!lex_strterm->u3.id) { !lex_strterm->nd_paren) {
quoted_term = lex_strterm->u2.id; quoted_term = lex_strterm->nd_term;
} }
} }
; ;
@ -2739,6 +2792,21 @@ regx_options()
return options | kcode; return options | kcode;
} }
#define STR_FUNC_ESCAPE 0x01
#define STR_FUNC_EXPAND 0x02
#define STR_FUNC_REGEXP 0x04
#define STR_FUNC_QWORDS 0x08
#define STR_FUNC_INDENT 0x20
enum string_type {
str_squote = (0),
str_dquote = (STR_FUNC_EXPAND),
str_xquote = (STR_FUNC_ESCAPE|STR_FUNC_EXPAND),
str_regexp = (STR_FUNC_REGEXP|STR_FUNC_ESCAPE|STR_FUNC_EXPAND),
str_sword = (STR_FUNC_QWORDS),
str_dword = (STR_FUNC_QWORDS|STR_FUNC_EXPAND),
};
static int static int
tokadd_string(func, term, paren) tokadd_string(func, term, paren)
int func, term, paren; int func, term, paren;
@ -2756,7 +2824,7 @@ tokadd_string(func, term, paren)
} }
--lex_strnest; --lex_strnest;
} }
else if (func != '\'' && c == '#' && lex_p < lex_pend) { else if ((func & STR_FUNC_EXPAND) && c == '#' && lex_p < lex_pend) {
int c2 = *lex_p; int c2 = *lex_p;
if (c2 == '$' || c2 == '@' || c2 == '{') { if (c2 == '$' || c2 == '@' || c2 == '{') {
pushback(c); pushback(c);
@ -2774,19 +2842,19 @@ tokadd_string(func, term, paren)
continue; continue;
case '\\': case '\\':
if (func == '/') tokadd(c); if (func & STR_FUNC_ESCAPE) tokadd(c);
break; break;
default: default:
if (func == '/') { if (func & STR_FUNC_REGEXP) {
pushback(c); pushback(c);
if (tokadd_escape(term) < 0) if (tokadd_escape(term) < 0)
return -1; return -1;
continue; continue;
} }
else if (func != '\'') { else if (func & STR_FUNC_EXPAND) {
pushback(c); pushback(c);
if (func != '"') tokadd('\\'); if (func & STR_FUNC_ESCAPE) tokadd('\\');
c = read_escape(); c = read_escape();
} }
else if (c != term && !(paren && c == paren)) { else if (c != term && !(paren && c == paren)) {
@ -2802,93 +2870,15 @@ tokadd_string(func, term, paren)
c = nextc(); c = nextc();
} }
} }
else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
pushback(c);
break;
}
tokadd(c); tokadd(c);
} }
return c; return c;
} }
static int
parse_quotedwords(term, paren)
int term, paren;
{
NODE *qwords = 0;
int strstart;
int c;
int nest = 0;
strstart = ruby_sourceline;
newtok();
while (c = nextc(),ISSPACE(c))
; /* skip preceding spaces */
pushback(c);
while ((c = nextc()) != term || nest > 0) {
if (c == -1) {
ruby_sourceline = strstart;
rb_compile_error("unterminated string meets end of file");
return 0;
}
if (paren) {
if (c == paren) nest++;
if (c == term && nest-- == 0) break;
}
if (ismbchar(c)) {
int i, len = mbclen(c)-1;
for (i = 0; i < len; i++) {
tokadd(c);
c = nextc();
}
}
else if (c == '\\') {
c = nextc();
if (QUOTED_TERM_P(c)) break;
switch (c) {
case '\n':
continue;
case '\\':
c = '\\';
break;
default:
if (c == term || (paren && c == paren)) {
tokadd(c);
continue;
}
if (!ISSPACE(c))
tokadd('\\');
break;
}
}
else if (ISSPACE(c)) {
NODE *str;
tokfix();
str = NEW_STR(rb_str_new(tok(), toklen()));
newtok();
if (!qwords) qwords = NEW_LIST(str);
else list_append(qwords, str);
while (c = nextc(),ISSPACE(c))
; /* skip continuous spaces */
pushback(c);
continue;
}
tokadd(c);
}
tokfix();
if (toklen() > 0) {
NODE *str;
str = NEW_STR(rb_str_new(tok(), toklen()));
if (!qwords) qwords = NEW_LIST(str);
else list_append(qwords, str);
}
if (!qwords) qwords = NEW_ZARRAY();
yylval.node = qwords;
lex_state = EXPR_END;
return tQWORDS;
}
#define NEW_STRTERM(func, term, paren) \ #define NEW_STRTERM(func, term, paren) \
rb_node_newnode(NODE_STRTERM, (func), (term), (paren)) rb_node_newnode(NODE_STRTERM, (func), (term), (paren))
@ -2896,17 +2886,25 @@ static int
parse_string(quote) parse_string(quote)
NODE *quote; NODE *quote;
{ {
int func = quote->u1.id; int func = quote->nd_func;
int term = quote->u2.id; int term = quote->nd_term;
int paren = quote->u3.id; int paren = quote->nd_paren;
int c; int c, space = 0;
if (func == -1) return tSTRING_END; if (func == -1) return tSTRING_END;
c = nextc(); c = nextc();
if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
do {c = nextc();} while (ISSPACE(c));
space = 1;
}
if (c == term) { if (c == term) {
if (!lex_strnest) { if (!lex_strnest) {
eos: eos:
if (func != '/') return tSTRING_END; if (func & STR_FUNC_QWORDS) {
quote->nd_func = -1;
return ' ';
}
if (!(func & STR_FUNC_REGEXP)) return tSTRING_END;
yylval.num = regx_options(); yylval.num = regx_options();
return tREGEXP_END; return tREGEXP_END;
} }
@ -2914,8 +2912,12 @@ parse_string(quote)
if (c == '\\' && WHEN_QUOTED_TERM(peek(quoted_term_char))) { if (c == '\\' && WHEN_QUOTED_TERM(peek(quoted_term_char))) {
if ((c = nextc()) == term) goto eos; if ((c = nextc()) == term) goto eos;
} }
if (space) {
pushback(c);
return ' ';
}
newtok(); newtok();
if (func != '\'' && c == '#') { if ((func & STR_FUNC_EXPAND) && c == '#') {
switch (c = nextc()) { switch (c = nextc()) {
case '$': case '$':
case '@': case '@':
@ -2938,12 +2940,10 @@ parse_string(quote)
return tSTRING_CONTENT; return tSTRING_CONTENT;
} }
#define INDENTED_HEREDOC 0x20
static int static int
heredoc_identifier() heredoc_identifier()
{ {
int c = nextc(), term, indent = 0, len; int c = nextc(), term, func = 0, len;
if (c == '-') { if (c == '-') {
c = nextc(); c = nextc();
@ -2952,7 +2952,7 @@ heredoc_identifier()
pushback('-'); pushback('-');
return 0; return 0;
} }
indent = INDENTED_HEREDOC; func = STR_FUNC_INDENT;
} }
else if (ISSPACE(c)) { else if (ISSPACE(c)) {
not_heredoc: not_heredoc:
@ -2961,10 +2961,14 @@ heredoc_identifier()
} }
switch (c) { switch (c) {
case '\'': case '\'':
func |= str_squote; goto qutoed;
case '"': case '"':
func |= str_dquote; goto qutoed;
case '`': case '`':
func |= str_xquote;
qutoed:
newtok(); newtok();
tokadd(c ^ indent); tokadd(func);
term = c; term = c;
while ((c = nextc()) != -1 && c != term) { while ((c = nextc()) != -1 && c != term) {
len = mbclen(c); len = mbclen(c);
@ -2980,7 +2984,7 @@ heredoc_identifier()
if (!is_identchar(c)) goto not_heredoc; if (!is_identchar(c)) goto not_heredoc;
newtok(); newtok();
term = '"'; term = '"';
tokadd(term ^ indent); tokadd(func |= str_dquote);
do { do {
len = mbclen(c); len = mbclen(c);
do {tokadd(c);} while (--len > 0 && (c = nextc()) != -1); do {tokadd(c);} while (--len > 0 && (c = nextc()) != -1);
@ -3040,15 +3044,7 @@ here_document(here)
eos = RSTRING(here->nd_lit)->ptr; eos = RSTRING(here->nd_lit)->ptr;
len = RSTRING(here->nd_lit)->len - 1; len = RSTRING(here->nd_lit)->len - 1;
switch (func = *eos++) { indent = (func = *eos++) & STR_FUNC_INDENT;
case '\'': case '"': case '`':
indent = 0;
break;
default:
func ^= INDENTED_HEREDOC;
indent = 1;
break;
}
if ((c = nextc()) == -1) { if ((c = nextc()) == -1) {
error: error:
@ -3062,7 +3058,7 @@ here_document(here)
return tSTRING_END; return tSTRING_END;
} }
if (func == '\'') { if (!(func & STR_FUNC_EXPAND)) {
do { do {
line = lex_lastline; line = lex_lastline;
if (str) if (str)
@ -3334,7 +3330,7 @@ yylex()
return '>'; return '>';
case '"': case '"':
lex_strterm = NEW_STRTERM('"', '"', 0); lex_strterm = NEW_STRTERM(str_dquote, '"', 0);
return tSTRING_BEG; return tSTRING_BEG;
case '`': case '`':
@ -3349,11 +3345,11 @@ yylex()
lex_state = EXPR_ARG; lex_state = EXPR_ARG;
return c; return c;
} }
lex_strterm = NEW_STRTERM('`', '`', 0); lex_strterm = NEW_STRTERM(str_xquote, '`', 0);
return tXSTRING_BEG; return tXSTRING_BEG;
case '\'': case '\'':
lex_strterm = NEW_STRTERM('\'', '\'', 0); lex_strterm = NEW_STRTERM(str_squote, '\'', 0);
return tSTRING_BEG; return tSTRING_BEG;
case '?': case '?':
@ -3755,7 +3751,7 @@ yylex()
case '/': case '/':
if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
lex_strterm = NEW_STRTERM('/', '/', 0); lex_strterm = NEW_STRTERM(str_regexp, '/', 0);
return tREGEXP_BEG; return tREGEXP_BEG;
} }
if ((c = nextc()) == '=') { if ((c = nextc()) == '=') {
@ -3767,7 +3763,7 @@ yylex()
if (IS_ARG() && space_seen) { if (IS_ARG() && space_seen) {
if (!ISSPACE(c)) { if (!ISSPACE(c)) {
arg_ambiguous(); arg_ambiguous();
lex_strterm = NEW_STRTERM('/', '/', 0); lex_strterm = NEW_STRTERM(str_regexp, '/', 0);
return tREGEXP_BEG; return tREGEXP_BEG;
} }
} }
@ -3924,22 +3920,31 @@ yylex()
switch (c) { switch (c) {
case 'Q': case 'Q':
lex_strterm = NEW_STRTERM('"', term, paren); lex_strterm = NEW_STRTERM(str_dquote, term, paren);
return tSTRING_BEG; return tSTRING_BEG;
case 'q': case 'q':
lex_strterm = NEW_STRTERM('\'', term, paren); lex_strterm = NEW_STRTERM(str_squote, term, paren);
return tSTRING_BEG; return tSTRING_BEG;
case 'W':
lex_strterm = NEW_STRTERM(str_dquote | STR_FUNC_QWORDS, term, paren);
do {c = nextc();} while (ISSPACE(c));
pushback(c);
return tWORDS_BEG;
case 'w': case 'w':
return parse_quotedwords(term, paren); lex_strterm = NEW_STRTERM(str_squote | STR_FUNC_QWORDS, term, paren);
do {c = nextc();} while (ISSPACE(c));
pushback(c);
return tQWORDS_BEG;
case 'x': case 'x':
lex_strterm = NEW_STRTERM('`', term, paren); lex_strterm = NEW_STRTERM(str_xquote, term, paren);
return tXSTRING_BEG; return tXSTRING_BEG;
case 'r': case 'r':
lex_strterm = NEW_STRTERM('/', term, paren); lex_strterm = NEW_STRTERM(str_regexp, term, paren);
return tREGEXP_BEG; return tREGEXP_BEG;
default: default:

View File

@ -1,4 +1,4 @@
#define RUBY_VERSION "1.7.2" #define RUBY_VERSION "1.7.2"
#define RUBY_RELEASE_DATE "2002-06-25" #define RUBY_RELEASE_DATE "2002-06-26"
#define RUBY_VERSION_CODE 172 #define RUBY_VERSION_CODE 172
#define RUBY_RELEASE_CODE 20020625 #define RUBY_RELEASE_CODE 20020626