Commit 5269944a authored by neis's avatar neis Committed by Commit bot

[generators] Desugar yield*.

This CL deals with yield* by desugaring it in the parser.  Hence the
full-codegen implementation of it becomes obsolete and can be removed in a
future CL.

The only change in semantics should be that the results of the iterator's next
and throw methods are checked to be objects, which didn't happen before but is
required by the spec.

BUG=

Review URL: https://codereview.chromium.org/1643903003

Cr-Commit-Position: refs/heads/master@{#33735}
parent 34645da5
......@@ -263,9 +263,11 @@ class AstValue : public ZoneObject {
F(proto, "__proto__") \
F(prototype, "prototype") \
F(rest_parameter, ".rest_parameter") \
F(return, "return") \
F(set_space, "set ") \
F(this, "this") \
F(this_function, ".this_function") \
F(throw, "throw") \
F(undefined, "undefined") \
F(use_asm, "use asm") \
F(use_strong, "use strong") \
......
......@@ -1578,7 +1578,9 @@ void AstPrinter::VisitAssignment(Assignment* node) {
void AstPrinter::VisitYield(Yield* node) {
IndentedScope indent(this, "YIELD", node->position());
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "YIELD (kind %d)", node->yield_kind());
IndentedScope indent(this, buf.start(), node->position());
Visit(node->expression());
}
......
......@@ -316,10 +316,13 @@ class CallSite {
"to be non-writable is deprecated") \
T(StrongSetProto, \
"On strong object %, redefining the internal prototype is deprecated") \
T(SymbolIteratorInvalid, \
"Result of the Symbol.iterator method is not an object") \
T(SymbolKeyFor, "% is not a symbol") \
T(SymbolToNumber, "Cannot convert a Symbol value to a number") \
T(SymbolToString, "Cannot convert a Symbol value to a string") \
T(SimdToNumber, "Cannot convert a SIMD value to a number") \
T(ThrowMethodMissing, "The iterator does not provide a 'throw' method.") \
T(UndefinedOrNullToObject, "Cannot convert undefined or null to object") \
T(ValueAndAccessor, \
"Invalid property descriptor. Cannot both specify accessors and a value " \
......
......@@ -2160,10 +2160,7 @@ ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier,
}
}
if (kind == Yield::kDelegating) {
// var iterator = subject[Symbol.iterator]();
// Hackily disambiguate o from o.next and o [Symbol.iterator]().
// TODO(verwaest): Come up with a better solution.
expression = this->GetIterator(expression, factory(), pos + 1);
return Traits::RewriteYieldStar(generator_object, expression, pos);
}
// Hackily disambiguate o from o.next and o [Symbol.iterator]().
// TODO(verwaest): Come up with a better solution.
......
This diff is collapsed.
......@@ -656,8 +656,14 @@ class ParserTraits {
ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
bool* ok);
Expression* RewriteYieldStar(
Expression* generator, Expression* expression, int pos);
private:
Parser* parser_;
void BuildIteratorClose(ZoneList<Statement*>* statements, Variable* iterator,
Maybe<Variable*> input);
};
......@@ -754,6 +760,7 @@ class Parser : public ParserBase<ParserTraits> {
ZoneList<const AstRawString*>* names,
bool* ok);
DoExpression* ParseDoExpression(bool* ok);
Expression* ParseYieldStarExpression(bool* ok);
struct DeclarationDescriptor {
enum Kind { NORMAL, PARAMETER };
......
......@@ -941,6 +941,9 @@ class PreParserTraits {
PreParserExpression property, const ExpressionClassifier* classifier,
bool* ok);
inline PreParserExpression RewriteYieldStar(
PreParserExpression generator, PreParserExpression expr, int pos);
private:
PreParser* pre_parser_;
};
......@@ -1138,6 +1141,13 @@ PreParserExpression PreParserTraits::RewriteNonPatternObjectLiteralProperty(
}
PreParserExpression PreParserTraits::RewriteYieldStar(
PreParserExpression generator, PreParserExpression expression, int pos) {
return pre_parser_->factory()->NewYield(
generator, expression, Yield::kDelegating, pos);
}
PreParserStatementList PreParser::ParseEagerFunctionBody(
PreParserIdentifier function_name, int pos,
const PreParserFormalParameters& parameters, FunctionKind kind,
......
......@@ -225,6 +225,7 @@ void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
// at the end again: ".backup = .result; ...; .result = .backup"
// This is necessary because the finally block does not normally contribute
// to the completion value.
CHECK(scope() != nullptr);
Variable* backup = scope()->NewTemporary(
factory()->ast_value_factory()->dot_result_string());
Expression* backup_proxy = factory()->NewVariableProxy(backup);
......
......@@ -397,39 +397,17 @@ TestGenerator(
"foo",
[42, undefined]);
// Test that yield* re-yields received results without re-boxing.
function TestDelegatingYield() {
function results(results) {
var i = 0;
function next() {
return results[i++];
}
var iter = { next: next };
var ret = {};
ret[Symbol.iterator] = function() { return iter; };
return ret;
}
function* yield_results(expected) {
return yield* results(expected);
}
function collect_results(iterable) {
var iter = iterable[Symbol.iterator]();
var ret = [];
var result;
do {
result = iter.next();
ret.push(result);
} while (!result.done);
return ret;
}
// We have to put a full result for the end, because the return will re-box.
var expected = [{value: 1}, 13, "foo", {value: 34, done: true}];
// Sanity check.
assertEquals(expected, collect_results(results(expected)));
assertEquals(expected, collect_results(yield_results(expected)));
// Test that yield* validates iterator results.
function TestDelegatingYield(junk) {
var iterator = {next: () => junk};
var iterable = {[Symbol.iterator]: () => iterator};
function* g() { return yield* iterable };
assertThrows(() => g().next(), TypeError);
}
TestDelegatingYield();
TestDelegatingYield(null);
TestDelegatingYield(42);
TestDelegatingYield(true);
function TestTryCatch(instantiate) {
function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; }
......@@ -681,3 +659,16 @@ function TestRecursion() {
assertThrows(TestThrowRecursion, Error);
}
TestRecursion();
// Test yield* on non-iterable objects.
function* g(junk) { return yield* junk }
var non_iterables = [
42,
{[Symbol.iterator]: 42},
{[Symbol.iterator]: () => 42},
{[Symbol.iterator]: () => ({next: 42})},
];
for (let junk of non_iterables) {
assertThrows(() => g(junk).next(), TypeError);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment