feat: add range operators and iterator protocol for numeric for loops

Implement `..` and `...` infix operators on Num returning Range objects that support the iterator protocol, enabling concise numeric for loops like `for (i in 1..10)`. Add Range class with min/max properties and iterate/iteratorValue methods. Introduce TOKEN_DOTDOT and TOKEN_DOTDOTDOT lexer tokens with PREC_RANGE precedence in the compiler. Unroll method_call benchmark loops across all languages to stress dynamic dispatch instead of loop overhead, reducing iteration count from 1M to 100K with 10x unrolling. Update Wren benchmarks (binary_trees, fib, for) to use new range syntax. Add benchmark/README.md documenting each benchmark's purpose.
This commit is contained in:
Bob Nystrom
2013-12-25 23:01:45 +00:00
parent b72a42eedd
commit 6c61df3ed7
12 changed files with 209 additions and 44 deletions
+25 -1
View File
@@ -56,6 +56,8 @@ typedef enum
TOKEN_RIGHT_BRACE,
TOKEN_COLON,
TOKEN_DOT,
TOKEN_DOTDOT,
TOKEN_DOTDOTDOT,
TOKEN_COMMA,
TOKEN_STAR,
TOKEN_SLASH,
@@ -573,7 +575,24 @@ static void readRawToken(Parser* parser)
case '}': makeToken(parser, TOKEN_RIGHT_BRACE); return;
case ';': makeToken(parser, TOKEN_LINE); return;
case ':': makeToken(parser, TOKEN_COLON); return;
case '.': makeToken(parser, TOKEN_DOT); return;
case '.':
if (peekChar(parser) == '.')
{
nextChar(parser);
if (peekChar(parser) == '.')
{
nextChar(parser);
makeToken(parser, TOKEN_DOTDOTDOT);
return;
}
makeToken(parser, TOKEN_DOTDOT);
return;
}
makeToken(parser, TOKEN_DOT);
return;
case ',': makeToken(parser, TOKEN_COMMA); return;
case '*': makeToken(parser, TOKEN_STAR); return;
case '%': makeToken(parser, TOKEN_PERCENT); return;
@@ -697,6 +716,8 @@ static void nextToken(Parser* parser)
case TOKEN_LEFT_BRACKET:
case TOKEN_LEFT_BRACE:
case TOKEN_DOT:
case TOKEN_DOTDOT:
case TOKEN_DOTDOTDOT:
case TOKEN_COMMA:
case TOKEN_STAR:
case TOKEN_SLASH:
@@ -1066,6 +1087,7 @@ typedef enum
PREC_IS, // is
PREC_EQUALITY, // == !=
PREC_COMPARISON, // < > <= >=
PREC_RANGE, // .. ...
PREC_BITWISE, // | &
PREC_TERM, // + -
PREC_FACTOR, // * / %
@@ -1664,6 +1686,8 @@ GrammarRule rules[] =
/* TOKEN_RIGHT_BRACE */ UNUSED,
/* TOKEN_COLON */ UNUSED,
/* TOKEN_DOT */ INFIX(PREC_CALL, call),
/* TOKEN_DOTDOT */ INFIX_OPERATOR(PREC_RANGE, ".. "),
/* TOKEN_DOTDOTDOT */ INFIX_OPERATOR(PREC_RANGE, "... "),
/* TOKEN_COMMA */ UNUSED,
/* TOKEN_STAR */ INFIX_OPERATOR(PREC_FACTOR, "* "),
/* TOKEN_SLASH */ INFIX_OPERATOR(PREC_FACTOR, "/ "),
+45 -20
View File
@@ -70,6 +70,31 @@ const char* coreLibSource =
" result = result + \"]\"\n"
" return result\n"
" }\n"
"}\n"
"\n"
"class Range {\n"
" new(min, max) {\n"
" _min = min\n"
" _max = max\n"
" }\n"
"\n"
" min { return _min }\n"
" max { return _max }\n"
"\n"
" iterate(previous) {\n"
" if (previous == null) return _min\n"
" if (previous == _max) return false\n"
" return previous + 1\n"
" }\n"
"\n"
" iteratorValue(iterator) {\n"
" return iterator\n"
" }\n"
"}\n"
"\n"
"class Num {\n"
" .. other { return new Range(this, other) }\n"
" ... other { return new Range(this, other - 1) }\n"
"}\n";
DEF_NATIVE(bool_not)
@@ -584,26 +609,6 @@ void wrenInitializeCore(WrenVM* vm)
vm->nullClass = defineClass(vm, "Null");
NATIVE(vm->nullClass, "toString", null_toString);
vm->numClass = defineClass(vm, "Num");
NATIVE(vm->numClass, "abs", num_abs);
NATIVE(vm->numClass, "toString", num_toString)
NATIVE(vm->numClass, "-", num_negate);
NATIVE(vm->numClass, "- ", num_minus);
NATIVE(vm->numClass, "+ ", num_plus);
NATIVE(vm->numClass, "* ", num_multiply);
NATIVE(vm->numClass, "/ ", num_divide);
NATIVE(vm->numClass, "% ", num_mod);
NATIVE(vm->numClass, "< ", num_lt);
NATIVE(vm->numClass, "> ", num_gt);
NATIVE(vm->numClass, "<= ", num_lte);
NATIVE(vm->numClass, ">= ", num_gte);
NATIVE(vm->numClass, "~", num_bitwiseNot);
// These are defined just so that 0 and -0 are equal, which is specified by
// IEEE 754 even though they have different bit representations.
NATIVE(vm->numClass, "== ", num_eqeq);
NATIVE(vm->numClass, "!= ", num_bangeq);
vm->stringClass = defineClass(vm, "String");
NATIVE(vm->stringClass, "contains ", string_contains);
NATIVE(vm->stringClass, "count", string_count);
@@ -629,6 +634,26 @@ void wrenInitializeCore(WrenVM* vm)
NATIVE(vm->listClass, "[ ]", list_subscript);
NATIVE(vm->listClass, "[ ]=", list_subscriptSetter);
vm->numClass = AS_CLASS(findGlobal(vm, "Num"));
NATIVE(vm->numClass, "abs", num_abs);
NATIVE(vm->numClass, "toString", num_toString)
NATIVE(vm->numClass, "-", num_negate);
NATIVE(vm->numClass, "- ", num_minus);
NATIVE(vm->numClass, "+ ", num_plus);
NATIVE(vm->numClass, "* ", num_multiply);
NATIVE(vm->numClass, "/ ", num_divide);
NATIVE(vm->numClass, "% ", num_mod);
NATIVE(vm->numClass, "< ", num_lt);
NATIVE(vm->numClass, "> ", num_gt);
NATIVE(vm->numClass, "<= ", num_lte);
NATIVE(vm->numClass, ">= ", num_gte);
NATIVE(vm->numClass, "~", num_bitwiseNot);
// These are defined just so that 0 and -0 are equal, which is specified by
// IEEE 754 even though they have different bit representations.
NATIVE(vm->numClass, "== ", num_eqeq);
NATIVE(vm->numClass, "!= ", num_bangeq);
ObjClass* ioClass = AS_CLASS(findGlobal(vm, "IO"));
NATIVE(ioClass->metaclass, "write__native__ ", io_writeString);
}