mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* compile.c (iseq_compile_each): fix next/redo stack consistency.
[ruby-dev:31373] * bootstraptest/test_syntax.rb: add tests for above. * sample/test.rb: fix to use __FILE__ instead of $0 to know basedir. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
48442d46b3
commit
571f22f5fe
4 changed files with 132 additions and 30 deletions
|
@ -1,3 +1,12 @@
|
|||
Thu Aug 16 22:10:06 2007 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* compile.c (iseq_compile_each): fix next/redo stack consistency.
|
||||
[ruby-dev:31373]
|
||||
|
||||
* bootstraptest/test_syntax.rb: add tests for above.
|
||||
|
||||
* sample/test.rb: fix to use __FILE__ instead of $0 to know basedir.
|
||||
|
||||
Thu Aug 16 21:14:06 2007 WATANABE Hirofumi <eban@ruby-lang.org>
|
||||
|
||||
* configure.in (BASERUBY): need AC_SUBST. [ruby-dev:31438]
|
||||
|
|
|
@ -523,25 +523,88 @@ assert_equal %q{1}, %q{
|
|||
end until true
|
||||
i
|
||||
}
|
||||
def assert_syntax_error expected, code
|
||||
def assert_syntax_error expected, code, message = ''
|
||||
assert_equal "#{expected}",
|
||||
"begin eval(%q{#{code}}, nil, '', 0)"'; rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end'
|
||||
"begin eval(%q{#{code}}, nil, '', 0)"'; rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end', message
|
||||
end
|
||||
assert_syntax_error "unterminated string meets end of file", '().."' # [ruby-dev:29732]
|
||||
assert_equal %q{[]}, %q{$&;[]} # [ruby-dev:31068]
|
||||
assert_syntax_error "syntax error, unexpected tSTAR, expecting '}'", %q{{*0}} # [ruby-dev:31072]
|
||||
assert_syntax_error "empty symbol literal", %q{0..:""} # [ruby-dev:31085]
|
||||
assert_syntax_error "`@0' is not allowed as an instance variable name", %q{@0..0} # [ruby-dev:31095]
|
||||
assert_syntax_error "identifier $00 is not valid to get", %q{$00..0} # [ruby-dev:31100]
|
||||
assert_syntax_error "unterminated string meets end of file", '().."', '[ruby-dev:29732]'
|
||||
assert_equal %q{[]}, %q{$&;[]}, '[ruby-dev:31068]'
|
||||
assert_syntax_error "syntax error, unexpected tSTAR, expecting '}'", %q{{*0}}, '[ruby-dev:31072]'
|
||||
assert_syntax_error "empty symbol literal", %q{0..:""}, '[ruby-dev:31085]'
|
||||
assert_syntax_error "`@0' is not allowed as an instance variable name", %q{@0..0}, '[ruby-dev:31095]'
|
||||
assert_syntax_error "identifier $00 is not valid to get", %q{$00..0}, '[ruby-dev:31100]'
|
||||
assert_syntax_error "identifier $00 is not valid to set", %q{0..$00=1}
|
||||
assert_equal %q{0}, %q{[*0];0} # [ruby-dev:31102]
|
||||
assert_syntax_error "syntax error, unexpected ')'", %q{v0,(*,v1,) = 0} # [ruby-dev:31104]
|
||||
assert_equal %q{1}, %q{class << (ary=[]); def []; 0; end; def []=(x); super(0,x);end;end; ary[]+=1} # [ruby-dev:31110]
|
||||
assert_syntax_error "Can't set variable $1", %q{0..$1=1} # [ruby-dev:31118]
|
||||
assert_syntax_error "void value expression", %q{1.times{1+(1&&next)}} # [ruby-dev:31119]
|
||||
assert_syntax_error "void value expression", %q{x=-1;loop{x+=1&&redo if (x+=1).zero?}} # [ruby-dev:31119]
|
||||
assert_syntax_error %q{syntax error, unexpected $end}, %q{!} # [ruby-dev:31243]
|
||||
assert_equal %q{0}, %q{[*0];0}, '[ruby-dev:31102]'
|
||||
assert_syntax_error "syntax error, unexpected ')'", %q{v0,(*,v1,) = 0}, '[ruby-dev:31104]'
|
||||
assert_equal %q{1}, %q{
|
||||
class << (ary=[]); def []; 0; end; def []=(x); super(0,x);end;end; ary[]+=1
|
||||
}, '[ruby-dev:31110]'
|
||||
assert_syntax_error "Can't set variable $1", %q{0..$1=1}, '[ruby-dev:31118]'
|
||||
assert_syntax_error "void value expression", %q{1.times{1+(1&&next)}}, '[ruby-dev:31119]'
|
||||
assert_syntax_error "void value expression", %q{x=-1;loop{x+=1&&redo if (x+=1).zero?}}, '[ruby-dev:31119]'
|
||||
assert_syntax_error %q{syntax error, unexpected $end}, %q{!}, '[ruby-dev:31243]'
|
||||
assert_equal %q{[nil]}, %q{[()]}, '[ruby-dev:31252]'
|
||||
assert_equal %q{true}, %q{!_=()}, '[ruby-dev:31263]'
|
||||
assert_equal 'ok', %q{while true; redo; end if 1 == 2; :ok}, '[ruby-dev:31360]'
|
||||
assert_equal 'ok', %q{
|
||||
1.times {
|
||||
begin
|
||||
ensure
|
||||
next
|
||||
end
|
||||
}; :ok
|
||||
}, '[ruby-dev:31373]'
|
||||
assert_equal 'ok', %q{
|
||||
flag = false
|
||||
1.times {
|
||||
next if flag
|
||||
flag = true
|
||||
begin
|
||||
ensure
|
||||
redo
|
||||
end
|
||||
}; :ok
|
||||
}, '[ruby-dev:31373]'
|
||||
|
||||
assert_equal 'ok', %q{
|
||||
1.times{
|
||||
p(1, (next; 2))
|
||||
}; :ok
|
||||
}
|
||||
assert_equal '3', %q{
|
||||
i = 0
|
||||
1 + (while true
|
||||
break 2 if (i+=1) > 1
|
||||
next
|
||||
end)
|
||||
}
|
||||
assert_equal '3', %q{
|
||||
i = 0
|
||||
1 + (while true
|
||||
break 2 if (i+=1) > 1
|
||||
p(1, (next; 2))
|
||||
end)
|
||||
}
|
||||
# redo
|
||||
assert_equal 'ok', %q{
|
||||
i = 0
|
||||
1.times{
|
||||
break if i>1
|
||||
i+=1
|
||||
p(1, (redo; 2))
|
||||
}; :ok
|
||||
}
|
||||
assert_equal '3', %q{
|
||||
i = 0
|
||||
1 + (while true
|
||||
break 2 if (i+=1) > 1
|
||||
redo
|
||||
end)
|
||||
}
|
||||
assert_equal '3', %q{
|
||||
i = 0
|
||||
1 + (while true
|
||||
break 2 if (i+=1) > 1
|
||||
p(1, (redo; 2))
|
||||
end)
|
||||
}
|
||||
|
|
57
compile.c
57
compile.c
|
@ -1151,6 +1151,13 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
|
|||
list = list->next;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* this check need dead code elimination */
|
||||
if (sp != 0) {
|
||||
rb_bug("SP is not 0 on %s (%d)\n", RSTRING_PTR(iseq->name), sp);
|
||||
}
|
||||
#endif
|
||||
|
||||
iseq->iseq = (void *)generated_iseq;
|
||||
iseq->iseq_size = pos;
|
||||
iseq->insn_info_table = insn_info_table;
|
||||
|
@ -2927,13 +2934,17 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
|||
}
|
||||
case NODE_NEXT:{
|
||||
unsigned long level = 0;
|
||||
int pop_after_throw = 0;
|
||||
|
||||
if (iseq->compile_data->redo_label != 0) {
|
||||
add_ensure_iseq(ret, iseq);
|
||||
ADD_INSNL(ret, nd_line(node), jump,
|
||||
iseq->compile_data->start_label);
|
||||
/* next in while loop */
|
||||
debugs("next in while\n");
|
||||
pop_after_throw = 1;
|
||||
goto next_by_throw;
|
||||
}
|
||||
else if (iseq->compile_data->end_label) {
|
||||
debugs("next in block\n");
|
||||
ADD_INSN (ret, nd_line(node), emptstack);
|
||||
COMPILE(ret, "next val", node->nd_stts);
|
||||
add_ensure_iseq(ret, iseq);
|
||||
ADD_INSNL(ret, nd_line(node), jump,
|
||||
|
@ -2943,7 +2954,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
|||
COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with next"));
|
||||
}
|
||||
else {
|
||||
rb_iseq_t *ip = iseq->parent_iseq;
|
||||
rb_iseq_t *ip;
|
||||
next_by_throw:
|
||||
ip = iseq;
|
||||
while (ip) {
|
||||
level = 0x8000;
|
||||
if (ip->type == ISEQ_TYPE_BLOCK) {
|
||||
|
@ -2957,9 +2970,11 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
|||
}
|
||||
if (ip != 0) {
|
||||
COMPILE(ret, "next val", node->nd_stts);
|
||||
add_ensure_iseq(ret, iseq);
|
||||
ADD_INSN1(ret, nd_line(node), throw,
|
||||
INT2FIX(level | 0x03) /* TAG_NEXT */ );
|
||||
if (pop_after_throw) {
|
||||
ADD_INSN(ret, nd_line(node), pop);
|
||||
}
|
||||
}
|
||||
else {
|
||||
COMPILE_ERROR((ERROR_ARGS "Illegal next"));
|
||||
|
@ -2968,18 +2983,27 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
|||
break;
|
||||
}
|
||||
case NODE_REDO:{
|
||||
int pop_after_throw = 0;
|
||||
if (iseq->compile_data->redo_label) {
|
||||
debugs("redo in while");
|
||||
#if 1
|
||||
pop_after_throw = 1;
|
||||
goto redo_by_throw;
|
||||
#else
|
||||
add_ensure_iseq(ret, iseq);
|
||||
ADD_INSNL(ret, nd_line(node), jump,
|
||||
iseq->compile_data->redo_label);
|
||||
if (!poped) { /* for stack consistency */
|
||||
ADD_INSN(ret, nd_line(node), putnil);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (iseq->type == ISEQ_TYPE_EVAL) {
|
||||
COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo"));
|
||||
}
|
||||
else if (iseq->compile_data->start_label) {
|
||||
ADD_INSN (ret, nd_line(node), emptstack);
|
||||
add_ensure_iseq(ret, iseq);
|
||||
ADD_INSNL(ret, nd_line(node), jump,
|
||||
iseq->compile_data->start_label);
|
||||
if (!poped) { /* for stack consistency */
|
||||
|
@ -2987,24 +3011,30 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
|||
}
|
||||
}
|
||||
else {
|
||||
rb_iseq_t *ip = iseq->parent_iseq;
|
||||
unsigned long level = 0x8000 | 0x4000;
|
||||
rb_iseq_t *ip;
|
||||
unsigned long level;
|
||||
redo_by_throw:
|
||||
level = 0x8000 | 0x4000;
|
||||
ip = iseq;
|
||||
while (ip) {
|
||||
if (ip->type == ISEQ_TYPE_BLOCK) {
|
||||
if (ip->compile_data->redo_label != 0) {
|
||||
break;
|
||||
}
|
||||
else if (ip->type == ISEQ_TYPE_BLOCK) {
|
||||
break;
|
||||
}
|
||||
else if (ip->type == ISEQ_TYPE_EVAL) {
|
||||
COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo"));
|
||||
}
|
||||
else if (ip->compile_data->redo_label != 0) {
|
||||
break;
|
||||
}
|
||||
ip = ip->parent_iseq;
|
||||
}
|
||||
if (ip != 0) {
|
||||
add_ensure_iseq(ret, iseq);
|
||||
ADD_INSN1(ret, nd_line(node), throw,
|
||||
INT2FIX(level | 0x05) /* TAG_REDO */ );
|
||||
|
||||
if (pop_after_throw) {
|
||||
ADD_INSN(ret, nd_line(node), pop);
|
||||
}
|
||||
}
|
||||
else {
|
||||
COMPILE_ERROR((ERROR_ARGS "Illegal redo"));
|
||||
|
@ -3716,8 +3746,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
|||
ADD_INSN(ret, nd_line(node), emptstack);
|
||||
}
|
||||
|
||||
COMPILE(ret, "return nd_stts (return val)",
|
||||
node->nd_stts);
|
||||
COMPILE(ret, "return nd_stts (return val)", node->nd_stts);
|
||||
|
||||
if (is->type == ISEQ_TYPE_METHOD) {
|
||||
add_ensure_iseq(ret, iseq);
|
||||
|
|
|
@ -1871,13 +1871,14 @@ File.unlink "script_tmp" or `/bin/rm -f "script_tmp"`
|
|||
File.unlink "script_tmp.bak" or `/bin/rm -f "script_tmp.bak"`
|
||||
|
||||
$bad = false
|
||||
if (dir = File.dirname(File.dirname($0))) == '.'
|
||||
if (dir = File.dirname(File.dirname(__FILE__))) == '.'
|
||||
dir = ""
|
||||
else
|
||||
dir << "/"
|
||||
end
|
||||
|
||||
def valid_syntax?(code, fname)
|
||||
p fname
|
||||
eval("BEGIN {return true}\n#{code}", nil, fname, 0)
|
||||
rescue Exception
|
||||
STDERR.puts $!.message
|
||||
|
|
Loading…
Add table
Reference in a new issue