Reputation: 74234
In Ruby, the redo
keyword can be used to go back to the beginning of a loop without consuming input. I'd like to do the same with a for...of
loop in JavaScript.
const scan = lexer => function* (string) {
let [token, table] = lexer;
for (const character of string) {
const next = table.get(character);
if (next) {
[token, table] = next.value;
} else if (token) {
yield token.value;
[token, table] = lexer;
// redo the current iteration without consuming input
} else {
throw new SyntaxError("Unexpected character", character);
}
}
if (token) yield token.value;
else throw new SyntaxError("Unexpected end of input");
}
Normally, you'd do this by simply not incrementing the index of a regular for
loop. However, I have to use a for...of
loop because it loops over the Unicode code points of the string, whereas the regular for
loop would loop over the UTF-16 code units of the string.
How do I go back to the beginning of the loop without duplication of code?
Upvotes: 0
Views: 1049
Reputation: 138487
Just use an inner loop:
for (const character of string) {
while(true) {
const next = table.get(character);
if (next) {
[token, table] = next.value;
break;
} else if (token) {
yield token.value;
[token, table] = lexer;
// don't break, redo
} else {
throw new SyntaxError("Unexpected character", character);
break;
}
}
}
To restart the whole loop:
In your case it's actually quite straightforward:
yield* scan(lexer)(string);
return;
For sure if you don't want to restart the whole function, add an IIFE and recall that:
yield* (function redo*() {
//...
yield* redo();
return;
})();
If you really need jumps, use labels (please don't):
restart: while(true) {
// do stuff
continue restart;
//...
break;
}
Upvotes: 1