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:
+25
-1
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user