aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--bootstraptest/test_syntax.rb93
-rw-r--r--compile.c57
-rw-r--r--sample/test.rb3
4 files changed, 132 insertions, 30 deletions
diff --git a/ChangeLog b/ChangeLog
index f5a7560d78..53a802607d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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]
diff --git a/bootstraptest/test_syntax.rb b/bootstraptest/test_syntax.rb
index 1b6d0c8eab..9541d67089 100644
--- a/bootstraptest/test_syntax.rb
+++ b/bootstraptest/test_syntax.rb
@@ -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)
+}
diff --git a/compile.c b/compile.c
index 770e1cf89b..52fae34d59 100644
--- a/compile.c
+++ b/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);
diff --git a/sample/test.rb b/sample/test.rb
index 6dffa609dc..768429d951 100644
--- a/sample/test.rb
+++ b/sample/test.rb
@@ -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