diff --git a/benchmark/loop.sh b/benchmark/loop.sh new file mode 100755 index 00000000..f58e5344 --- /dev/null +++ b/benchmark/loop.sh @@ -0,0 +1,8 @@ +#!/bin/sh +scons --quiet + +./tora -V + +time ./tora benchmark/loop/for-range.tra +time perl benchmark/loop/for-range.pl + diff --git a/benchmark/loop/for-range.tra b/benchmark/loop/for-range.tra index 78ee9b81..4cf78689 100644 --- a/benchmark/loop/for-range.tra +++ b/benchmark/loop/for-range.tra @@ -1,6 +1,8 @@ +my $max = $ARGV.size() > 0 ? 0+$ARGV[0] : 30000000; +say($max); my $foo; -for (1..30000000) { - $foo = $_ +for (1..$max) { + $foo = $_; } say($foo); diff --git a/src/frame.h b/src/frame.h index 097558a6..5a9f05f1 100644 --- a/src/frame.h +++ b/src/frame.h @@ -65,7 +65,7 @@ class LexicalVarsFrame { template Y* upcast() { - return dynamic_cast(&(*(this))); + return static_cast(&(*(this))); } }; diff --git a/src/parser.yy b/src/parser.yy index 8a1e230f..d8416a7b 100644 --- a/src/parser.yy +++ b/src/parser.yy @@ -484,7 +484,7 @@ primary_expression(A) ::= int(B). { A = B; } primary_expression(A) ::= DOUBLE_LITERAL(B). { A = B; } -primary_expression(A) ::= int(B) DOTDOT int(C). { +primary_expression(A) ::= primary_expression(B) DOTDOT primary_expression(C). { A = new BinaryNode(NODE_RANGE, B, C); } primary_expression(A) ::= FALSE. { diff --git a/t/tra/range.tra b/t/tra/range.tra new file mode 100644 index 00000000..dfce4e07 --- /dev/null +++ b/t/tra/range.tra @@ -0,0 +1,10 @@ +use Test::More *; + +my $n = 0+'10'; +my $r = 0; +for (1..$n) { + $r += $_; +} +is($r, 55); + +done_testing; diff --git a/vm.inc b/vm.inc index ec67d6b6..cc88e0c2 100644 --- a/vm.inc +++ b/vm.inc @@ -49,8 +49,12 @@ OP_PUSH_VALUE { OP_NEW_RANGE { SharedPtr l = stack.back(); stack.pop_back(); - SharedPtr r = stack.back(); stack.pop_back(); - stack.push_back(new RangeValue(l->upcast(), r->upcast())); + SharedPtr r = stack.back(); + stack.pop_back(); + + SharedPtr l2 = l->value_type == VALUE_TYPE_INT ? l->upcast() : new IntValue(l->to_int()); + SharedPtr r2 = r->value_type == VALUE_TYPE_INT ? r->upcast() : new IntValue(r->to_int()); + stack.push_back(new RangeValue(l2, r2)); } OP_FUNCDEF { @@ -850,8 +854,9 @@ OP_FOR_ITER { auto fframe = frame_stack->back()->upcast(); assert(fframe->type == FRAME_TYPE_FOREACH); stack.resize(fframe->top); - SharedPtr iter = fframe->iter; - if (iter->value_type == VALUE_TYPE_ARRAY_ITERATOR) { + const SharedPtr & iter = fframe->iter; + switch (iter->value_type) { + case VALUE_TYPE_ARRAY_ITERATOR: { SharedPtr aiter = iter->upcast(); if (aiter->counter < aiter->parent->size()) { SharedPtr val = aiter->parent->at(aiter->counter); @@ -862,16 +867,19 @@ OP_FOR_ITER { } else { stack.push_back(new StopIterationExceptionValue()); } - } else if (iter->value_type == VALUE_TYPE_RANGE_ITERATOR) { - SharedPtr riter = iter->upcast(); + break; + } + case VALUE_TYPE_RANGE_ITERATOR: { + RangeValue::iterator* riter = static_cast(iter.get()); if (riter->counter <= riter->parent->right->int_value) { - SharedPtr val = new IntValue(riter->counter); + stack.push_back(new IntValue(riter->counter)); riter->counter++; - stack.push_back(val); } else { stack.push_back(new StopIterationExceptionValue()); } - } else if (iter->value_type == VALUE_TYPE_HASH_ITERATOR) { + break; + } + case VALUE_TYPE_HASH_ITERATOR: { SharedPtr riter = iter->upcast(); if (!riter->finished()) { SharedPtr key = riter->getkey(); @@ -884,7 +892,9 @@ OP_FOR_ITER { } else { stack.push_back(new StopIterationExceptionValue()); } - } else if (iter->value_type == VALUE_TYPE_OBJECT) { + break; + } + case VALUE_TYPE_OBJECT: { ObjectValue * o = iter->upcast(); Package *pkg = this->find_package(o->package_id()); auto iter = pkg->find(this->symbol_table->get_id("__next__")); @@ -910,7 +920,9 @@ OP_FOR_ITER { } else { this->die("'%s' does not have a '__next__' method.", symbol_table->id2name(o->package_id()).c_str()); } - } else { + break; + } + default: this->die("[BUG] TOS is not a iterator object: %s.", iter->type_str()); } }