summaryrefslogtreecommitdiff
path: root/parse.y
diff options
context:
space:
mode:
Diffstat (limited to 'parse.y')
-rw-r--r--parse.y345
1 files changed, 180 insertions, 165 deletions
diff --git a/parse.y b/parse.y
index d1f1a32321..29557aa90b 100644
--- a/parse.y
+++ b/parse.y
@@ -6,7 +6,7 @@
$Date$
created at: Fri May 28 18:02:42 JST 1993
- Copyright (C) 1993-2000 Yukihiro Matsumoto
+ Copyright (C) 1993-2001 Yukihiro Matsumoto
**********************************************************************/
@@ -49,7 +49,6 @@ static int yyerror();
static enum lex_state {
EXPR_BEG, /* ignore newline, +/- is a sign. */
EXPR_END, /* newline significant, +/- is a operator. */
- EXPR_PAREN, /* almost like EXPR_END, `do' works as `{'. */
EXPR_ARG, /* newline significant, +/- is a operator. */
EXPR_MID, /* newline significant, +/- is a operator. */
EXPR_FNAME, /* ignore newline, no reserved words. */
@@ -57,8 +56,16 @@ static enum lex_state {
EXPR_CLASS, /* immediate after `class', no here document. */
} lex_state;
+#if SIZEOF_LONG_LONG > 0
+typedef unsigned long long stack_type;
+#elif SIZEOF___INT64 > 0
+typedef unsigned __int64 stack_type;
+#else
+typedef unsigned long stack_type;
+#endif
+
static int cond_nest = 0;
-static unsigned long cond_stack = 0;
+static stack_type cond_stack = 0;
#define COND_PUSH do {\
cond_nest++;\
cond_stack = (cond_stack<<1)|1;\
@@ -67,10 +74,20 @@ static unsigned long cond_stack = 0;
cond_nest--;\
cond_stack >>= 1;\
} while (0)
-#define IN_COND (cond_nest > 0 && (cond_stack&1))
+#define COND_P() (cond_nest > 0 && (cond_stack&1))
+
+static stack_type cmdarg_stack = 0;
+#define CMDARG_PUSH do {\
+ cmdarg_stack = (cmdarg_stack<<1)|1;\
+} while(0)
+#define CMDARG_POP do {\
+ cmdarg_stack >>= 1;\
+} while (0)
+#define CMDARG_P() (cmdarg_stack && (cmdarg_stack&1))
static int class_nest = 0;
static int in_single = 0;
+static int in_def = 0;
static int compile_for_eval = 0;
static ID cur_mid = 0;
@@ -155,7 +172,8 @@ static void top_local_setup();
kRETRY
kIN
kDO
- kDO2
+ kDO_COND
+ kDO_BLOCK
kRETURN
kYIELD
kSUPER
@@ -184,11 +202,11 @@ static void top_local_setup();
%type <node> singleton string
%type <val> literal numeric
-%type <node> compstmt stmts stmt expr arg primary command_call method_call
+%type <node> compstmt stmts stmt expr arg primary command command_call method_call
%type <node> if_tail opt_else case_body cases rescue exc_list exc_var ensure
-%type <node> opt_call_args call_args ret_args args when_args
-%type <node> aref_args opt_block_arg block_arg stmt_rhs
-%type <node> mrhs mrhs_basic superclass generic_call block_call var_ref
+%type <node> args ret_args when_args call_args paren_args opt_paren_args
+%type <node> command_args aref_args opt_block_arg block_arg var_ref
+%type <node> mrhs mrhs_basic superclass block_call block_command
%type <node> f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg
%type <node> assoc_list assocs assoc undef_list backref
%type <node> block_var opt_block_var brace_block do_block lhs none
@@ -295,16 +313,15 @@ stmts : none
$$ = $2;
}
-stmt : block_call
- | kALIAS fitem {lex_state = EXPR_FNAME;} fitem
+stmt : kALIAS fitem {lex_state = EXPR_FNAME;} fitem
{
- if (cur_mid || in_single)
+ if (in_def || in_single)
yyerror("alias within method");
$$ = NEW_ALIAS($2, $4);
}
| kALIAS tGVAR tGVAR
{
- if (cur_mid || in_single)
+ if (in_def || in_single)
yyerror("alias within method");
$$ = NEW_VALIAS($2, $3);
}
@@ -312,7 +329,7 @@ stmt : block_call
{
char buf[3];
- if (cur_mid || in_single)
+ if (in_def || in_single)
yyerror("alias within method");
sprintf(buf, "$%c", $3->nd_nth);
$$ = NEW_VALIAS($2, rb_intern(buf));
@@ -324,7 +341,7 @@ stmt : block_call
}
| kUNDEF undef_list
{
- if (cur_mid || in_single)
+ if (in_def || in_single)
yyerror("undef within method");
$$ = $2;
}
@@ -343,31 +360,21 @@ stmt : block_call
| stmt kWHILE_MOD expr
{
value_expr($3);
- if ($1) {
- if (nd_type($1) == NODE_BEGIN) {
- $$ = NEW_WHILE(cond($3), $1->nd_body, 0);
- }
- else {
- $$ = NEW_WHILE(cond($3), $1, 1);
- }
+ if ($1 && nd_type($1) == NODE_BEGIN) {
+ $$ = NEW_WHILE(cond($3), $1->nd_body, 0);
}
else {
- $$ = 0;
+ $$ = NEW_WHILE(cond($3), $1, 1);
}
}
| stmt kUNTIL_MOD expr
{
value_expr($3);
- if ($1) {
- if (nd_type($1) == NODE_BEGIN) {
- $$ = NEW_UNTIL(cond($3), $1->nd_body, 0);
- }
- else {
- $$ = NEW_UNTIL(cond($3), $1, 1);
- }
+ if ($1 && nd_type($1) == NODE_BEGIN) {
+ $$ = NEW_UNTIL(cond($3), $1->nd_body, 0);
}
else {
- $$ = 0;
+ $$ = NEW_UNTIL(cond($3), $1, 1);
}
}
| stmt kRESCUE_MOD stmt
@@ -376,7 +383,7 @@ stmt : block_call
}
| klBEGIN
{
- if (cur_mid || in_single) {
+ if (in_def || in_single) {
yyerror("BEGIN in method");
}
local_push();
@@ -390,18 +397,18 @@ stmt : block_call
}
| klEND '{' compstmt '}'
{
- if (compile_for_eval && (cur_mid || in_single)) {
+ if (compile_for_eval && (in_def || in_single)) {
yyerror("END in method; use at_exit");
}
$$ = NEW_ITER(0, NEW_POSTEXE(), $3);
}
- | lhs '=' stmt_rhs
+ | lhs '=' command_call
{
value_expr($3);
$$ = node_assign($1, $3);
}
- | mlhs '=' stmt_rhs
+ | mlhs '=' command_call
{
value_expr($3);
$1->nd_value = $3;
@@ -421,7 +428,7 @@ expr : mlhs '=' mrhs
}
| kRETURN ret_args
{
- if (!compile_for_eval && !cur_mid && !in_single)
+ if (!compile_for_eval && !in_def && !in_single)
yyerror("return appeared outside of method");
$$ = NEW_RETURN($2);
}
@@ -445,26 +452,41 @@ expr : mlhs '=' mrhs
}
| arg
-command_call : operation call_args
+command_call : command
+ | block_command
+
+block_command : block_call
+ | block_call '.' operation2 command_args
+ {
+ value_expr($1);
+ $$ = new_call($1, $3, $4);
+ }
+ | block_call tCOLON2 operation2 command_args
+ {
+ value_expr($1);
+ $$ = new_call($1, $3, $4);
+ }
+
+command : operation command_args
{
$$ = new_fcall($1, $2);
fixpos($$, $2);
}
- | primary '.' operation2 call_args
+ | primary '.' operation2 command_args
{
value_expr($1);
$$ = new_call($1, $3, $4);
fixpos($$, $1);
}
- | primary tCOLON2 operation2 call_args
+ | primary tCOLON2 operation2 command_args
{
value_expr($1);
$$ = new_call($1, $3, $4);
fixpos($$, $1);
}
- | kSUPER call_args
+ | kSUPER command_args
{
- if (!compile_for_eval && !cur_mid && !in_single)
+ if (!compile_for_eval && !in_def && !in_single)
yyerror("super called outside of method");
$$ = new_super($2);
fixpos($$, $2);
@@ -475,7 +497,6 @@ command_call : operation call_args
fixpos($$, $2);
}
-
mlhs : mlhs_basic
| tLPAREN mlhs_entry ')'
{
@@ -897,14 +918,6 @@ aref_args : none
{
$$ = list_append($1, $3);
}
- | block_call opt_nl
- {
- $$ = NEW_LIST($1);
- }
- | args ',' block_call opt_nl
- {
- $$ = list_append($1, $3);
- }
| args trailer
{
$$ = $1;
@@ -924,22 +937,31 @@ aref_args : none
$$ = NEW_RESTARGS($2);
}
-opt_call_args : none
- | call_args opt_nl
- | block_call opt_nl
+paren_args : '(' none ')'
{
- $$ = NEW_LIST($1);
+ $$ = $2;
}
- | args ',' block_call
+ | '(' call_args opt_nl ')'
{
- $$ = list_append($1, $3);
+ $$ = $2;
+ }
+ | '(' block_call opt_nl ')'
+ {
+ $$ = NEW_LIST($2);
}
+ | '(' args ',' block_call opt_nl ')'
+ {
+ $$ = list_append($2, $4);
+ }
+
+opt_paren_args : none
+ | paren_args
-call_args : command_call
+call_args : command
{
$$ = NEW_LIST($1);
}
- | args ',' command_call
+ | args ',' command
{
$$ = list_append($1, $3);
}
@@ -953,10 +975,6 @@ call_args : command_call
$$ = arg_concat($1, $4);
$$ = arg_blk_pass($$, $5);
}
- | assocs ','
- {
- $$ = NEW_LIST(NEW_HASH($1));
- }
| assocs opt_block_arg
{
$$ = NEW_LIST(NEW_HASH($1));
@@ -973,10 +991,6 @@ call_args : command_call
$$ = list_append($1, NEW_HASH($3));
$$ = arg_blk_pass($$, $4);
}
- | args ',' assocs ','
- {
- $$ = list_append($1, NEW_HASH($3));
- }
| args ',' assocs ',' tSTAR arg opt_block_arg
{
value_expr($6);
@@ -990,6 +1004,12 @@ call_args : command_call
}
| block_arg
+command_args : {CMDARG_PUSH;} call_args
+ {
+ CMDARG_POP;
+ $$ = $2;
+ }
+
block_arg : tAMPER arg
{
value_expr($2);
@@ -1119,20 +1139,20 @@ primary : literal
}
| kRETURN '(' ret_args ')'
{
- if (!compile_for_eval && !cur_mid && !in_single)
+ if (!compile_for_eval && !in_def && !in_single)
yyerror("return appeared outside of method");
value_expr($3);
$$ = NEW_RETURN($3);
}
| kRETURN '(' ')'
{
- if (!compile_for_eval && !cur_mid && !in_single)
+ if (!compile_for_eval && !in_def && !in_single)
yyerror("return appeared outside of method");
$$ = NEW_RETURN(0);
}
| kRETURN
{
- if (!compile_for_eval && !cur_mid && !in_single)
+ if (!compile_for_eval && !in_def && !in_single)
yyerror("return appeared outside of method");
$$ = NEW_RETURN(0);
}
@@ -1225,9 +1245,8 @@ primary : literal
}
| kCLASS cname superclass
{
- if (cur_mid || in_single)
+ if (in_def || in_single)
yyerror("class definition in method body");
-
class_nest++;
cref_push();
local_push();
@@ -1242,8 +1261,15 @@ primary : literal
cref_pop();
class_nest--;
}
- | kCLASS tLSHFT expr term
+ | kCLASS tLSHFT expr
{
+ $<num>$ = in_def;
+ in_def = 0;
+ }
+ term
+ {
+ $<num>$ = in_single;
+ in_single = 0;
class_nest++;
cref_push();
local_push();
@@ -1251,15 +1277,17 @@ primary : literal
compstmt
kEND
{
- $$ = NEW_SCLASS($3, $6);
+ $$ = NEW_SCLASS($3, $7);
fixpos($$, $3);
local_pop();
cref_pop();
class_nest--;
+ in_def = $<num>4;
+ in_single = $<num>6;
}
| kMODULE cname
{
- if (cur_mid || in_single)
+ if (in_def || in_single)
yyerror("module definition in method body");
class_nest++;
cref_push();
@@ -1277,9 +1305,11 @@ primary : literal
}
| kDEF fname
{
- if (cur_mid || in_single)
+ if (in_def || in_single)
yyerror("nested method definition");
+ $<id>$ = cur_mid;
cur_mid = $2;
+ in_def++;
local_push();
}
f_arglist
@@ -1301,7 +1331,8 @@ primary : literal
if (is_attrset_id($2)) $$->nd_noex = NOEX_PUBLIC;
fixpos($$, $4);
local_pop();
- cur_mid = 0;
+ in_def--;
+ cur_mid = $<id>3;
}
| kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} fname
{
@@ -1312,8 +1343,18 @@ primary : literal
}
f_arglist
compstmt
+ rescue
+ opt_else
+ ensure
kEND
{
+ if ($9) $8 = NEW_RESCUE($8, $9, $10);
+ else if ($10) {
+ rb_warn("else without rescue is useless");
+ $8 = block_append($8, $10);
+ }
+ if ($11) $8 = NEW_ENSURE($8, $11);
+
$$ = NEW_DEFS($2, $5, $7, $8);
fixpos($$, $2);
local_pop();
@@ -1341,7 +1382,7 @@ then : term
| term kTHEN
do : term
- | kDO
+ | kDO_COND
if_tail : opt_else
| kELSIF expr then
@@ -1377,7 +1418,7 @@ opt_block_var : none
}
-do_block : kDO
+do_block : kDO_BLOCK
{
$<vars>$ = dyna_push();
}
@@ -1390,47 +1431,7 @@ do_block : kDO
dyna_pop($<vars>2);
}
-brace_block : '{'
- {
- $<vars>$ = dyna_push();
- }
- opt_block_var
- compstmt '}'
- {
- $$ = NEW_ITER($3, 0, $4);
- fixpos($$, $4);
- dyna_pop($<vars>2);
- }
- | kDO2
- {
- $<vars>$ = dyna_push();
- }
- opt_block_var
- compstmt
- kEND
- {
- $$ = NEW_ITER($3, 0, $4);
- fixpos($$, $4);
- dyna_pop($<vars>2);
- }
-
-
-generic_call : tIDENTIFIER
- {
- $$ = NEW_VCALL($1);
- }
- | tCONSTANT
- {
- $$ = NEW_VCALL($1);
- }
- | tFID
- {
- $$ = NEW_VCALL($1);
- }
- | method_call
- | command_call
-
-block_call : generic_call do_block
+block_call : command do_block
{
if ($1 && nd_type($1) == NODE_BLOCK_PASS) {
rb_compile_error("both block arg and actual block given");
@@ -1439,28 +1440,32 @@ block_call : generic_call do_block
$$ = $2;
fixpos($$, $2);
}
-
-method_call : operation '(' opt_call_args close_paren
+ | block_call '.' operation2 opt_paren_args
{
- $$ = new_fcall($1, $3);
- fixpos($$, $3);
+ value_expr($1);
+ $$ = new_call($1, $3, $4);
}
- | primary '.' operation2 '(' opt_call_args close_paren
+ | block_call tCOLON2 operation2 opt_paren_args
{
value_expr($1);
- $$ = new_call($1, $3, $5);
- fixpos($$, $1);
+ $$ = new_call($1, $3, $4);
}
- | primary '.' operation2
+
+method_call : operation paren_args
+ {
+ $$ = new_fcall($1, $2);
+ fixpos($$, $2);
+ }
+ | primary '.' operation2 opt_paren_args
{
value_expr($1);
- $$ = new_call($1, $3, 0);
+ $$ = new_call($1, $3, $4);
fixpos($$, $1);
}
- | primary tCOLON2 operation2 '(' opt_call_args close_paren
+ | primary tCOLON2 operation2 paren_args
{
value_expr($1);
- $$ = new_call($1, $3, $5);
+ $$ = new_call($1, $3, $4);
fixpos($$, $1);
}
| primary tCOLON2 operation3
@@ -1468,28 +1473,43 @@ method_call : operation '(' opt_call_args close_paren
value_expr($1);
$$ = new_call($1, $3, 0);
}
- | kSUPER '(' opt_call_args close_paren
+ | kSUPER paren_args
{
- if (!compile_for_eval && !cur_mid &&
+ if (!compile_for_eval && !in_def &&
!in_single && !in_defined)
yyerror("super called outside of method");
- $$ = new_super($3);
+ $$ = new_super($2);
}
| kSUPER
{
- if (!compile_for_eval && !cur_mid &&
+ if (!compile_for_eval && !in_def &&
!in_single && !in_defined)
yyerror("super called outside of method");
$$ = NEW_ZSUPER();
}
-close_paren : ')'
+brace_block : '{'
{
- if (!IN_COND) lex_state = EXPR_PAREN;
+ $<vars>$ = dyna_push();
+ }
+ opt_block_var
+ compstmt '}'
+ {
+ $$ = NEW_ITER($3, 0, $4);
+ fixpos($$, $4);
+ dyna_pop($<vars>2);
+ }
+ | kDO
+ {
+ $<vars>$ = dyna_push();
+ }
+ opt_block_var
+ compstmt kEND
+ {
+ $$ = NEW_ITER($3, 0, $4);
+ fixpos($$, $4);
+ dyna_pop($<vars>2);
}
-
-stmt_rhs : block_call
- | command_call
case_body : kWHEN when_args then
compstmt
@@ -1967,6 +1987,7 @@ yycompile(f, line)
cond_stack = 0;
class_nest = 0;
in_single = 0;
+ in_def = 0;
cur_mid = 0;
if (n == 0) node = ruby_eval_tree;
@@ -2043,10 +2064,7 @@ rb_compile_file(f, file, start)
return yycompile(strdup(f), start);
}
-#if defined(__GNUC__) && __GNUC__ >= 2
-__inline__
-#endif
-static int
+static inline int
nextc()
{
int c;
@@ -2542,13 +2560,12 @@ parse_qstring(term, paren)
c = '\\';
break;
- case '\'':
- if (term == '\'') {
- c = '\'';
- break;
- }
- /* fall through */
default:
+ /* fall through */
+ if (c == term || (paren && c == paren)) {
+ tokadd(c);
+ continue;
+ }
tokadd('\\');
}
}
@@ -2603,7 +2620,7 @@ parse_quotedwords(term, paren)
c = '\\';
break;
default:
- if (c == term) {
+ if (c == term || (paren && c == paren)) {
tokadd(c);
continue;
}
@@ -2794,7 +2811,7 @@ arg_ambiguous()
rb_warning("ambiguous first argument; make sure");
}
-#ifndef strtod
+#if !defined(strtod) && !defined(HAVE_STDLIB_H)
double strtod ();
#endif
@@ -2919,8 +2936,7 @@ yylex()
case '<':
c = nextc();
if (c == '<' &&
- lex_state != EXPR_END && lex_state != EXPR_PAREN &&
- lex_state != EXPR_CLASS &&
+ lex_state != EXPR_END && lex_state != EXPR_CLASS &&
(lex_state != EXPR_ARG || space_seen)) {
int c2 = nextc();
int indent = 0;
@@ -2979,7 +2995,7 @@ yylex()
return parse_qstring(c,0);
case '?':
- if (lex_state == EXPR_END || lex_state == EXPR_PAREN) {
+ if (lex_state == EXPR_END) {
lex_state = EXPR_BEG;
return '?';
}
@@ -3306,7 +3322,7 @@ yylex()
return tCOLON2;
}
pushback(c);
- if (lex_state == EXPR_END || lex_state == EXPR_PAREN || ISSPACE(c)) {
+ if (lex_state == EXPR_END || ISSPACE(c)) {
lex_state = EXPR_BEG;
return ':';
}
@@ -3390,9 +3406,7 @@ yylex()
return c;
case '{':
- if (lex_state != EXPR_END &&
- lex_state != EXPR_PAREN &&
- lex_state != EXPR_ARG)
+ if (lex_state != EXPR_END && lex_state != EXPR_ARG)
c = tLBRACE;
lex_state = EXPR_BEG;
return c;
@@ -3616,10 +3630,10 @@ yylex()
if (state == EXPR_FNAME) {
yylval.id = rb_intern(kw->name);
}
- if (kw->id[0] == kDO &&
- (state == EXPR_PAREN ||
- (!IN_COND && state == EXPR_ARG))) {
- return kDO2;
+ if (kw->id[0] == kDO) {
+ if (COND_P()) return kDO_COND;
+ if (CMDARG_P()) return kDO_BLOCK;
+ return kDO;
}
return kw->id[state != EXPR_BEG];
}
@@ -4121,7 +4135,7 @@ assignable(id, val)
return NEW_IASGN(id, val);
}
else if (is_const_id(id)) {
- if (cur_mid || in_single)
+ if (in_def || in_single)
yyerror("dynamic constant assignment");
return NEW_CDECL(id, val);
}
@@ -4375,6 +4389,9 @@ void_expr(node)
}
}
+
+static NODE *cond2 _((NODE*));
+
static void
void_stmts(node)
NODE *node;
@@ -4390,8 +4407,6 @@ void_stmts(node)
}
}
-static NODE *cond2();
-
static int
assign_in_cond(node)
NODE *node;