blob: 6520efd45572f27b8929e6f5e2accec353ffbc1c [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_string_resource.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
// static
ScriptIterator ScriptIterator::FromIterable(v8::Isolate* isolate,
v8::Local<v8::Object> value,
ExceptionState& exception_state) {
// First, call the GetMethod(V, @@iterator) abstract ES operation.
const v8::Local<v8::Function> iterator_method =
GetEsIteratorMethod(isolate, value, exception_state);
if (exception_state.HadException())
return ScriptIterator();
if (iterator_method.IsEmpty())
return ScriptIterator();
// Use the method returned above to invoke the GetIterator(V, sync, method)
// abstract ES operation.
const v8::Local<v8::Object> iterator =
GetEsIteratorWithMethod(isolate, iterator_method, value, exception_state);
if (exception_state.HadException())
return ScriptIterator();
return ScriptIterator(isolate, iterator);
}
ScriptIterator::ScriptIterator(v8::Isolate* isolate,
v8::Local<v8::Object> iterator)
: isolate_(isolate),
iterator_(iterator),
next_key_(V8AtomicString(isolate, "next")),
done_key_(V8AtomicString(isolate, "done")),
value_key_(V8AtomicString(isolate, "value")),
done_(false) {
DCHECK(!iterator.IsEmpty());
}
bool ScriptIterator::Next(ExecutionContext* execution_context,
ExceptionState& exception_state,
v8::Local<v8::Value> next_value) {
DCHECK(!IsNull());
v8::TryCatch try_catch(isolate_);
v8::Local<v8::Context> context = isolate_->GetCurrentContext();
v8::Local<v8::Value> next;
if (!iterator_->Get(context, next_key_).ToLocal(&next)) {
CHECK(!try_catch.Exception().IsEmpty());
exception_state.RethrowV8Exception(try_catch.Exception());
done_ = true;
return false;
}
if (!next->IsFunction()) {
exception_state.ThrowTypeError("Expected next() function on iterator.");
done_ = true;
return false;
}
Vector<v8::Local<v8::Value>, 1> argv;
if (!next_value.IsEmpty())
argv = {next_value};
v8::Local<v8::Value> result;
if (!V8ScriptRunner::CallFunction(v8::Local<v8::Function>::Cast(next),
execution_context, iterator_, argv.size(),
argv.data(), isolate_)
.ToLocal(&result)) {
CHECK(!try_catch.Exception().IsEmpty());
exception_state.RethrowV8Exception(try_catch.Exception());
done_ = true;
return false;
}
if (!result->IsObject()) {
exception_state.ThrowTypeError(
"Expected iterator.next() to return an Object.");
done_ = true;
return false;
}
v8::Local<v8::Object> result_object = v8::Local<v8::Object>::Cast(result);
value_ = result_object->Get(context, value_key_);
if (value_.IsEmpty()) {
CHECK(!try_catch.Exception().IsEmpty());
exception_state.RethrowV8Exception(try_catch.Exception());
}
v8::Local<v8::Value> done;
if (!result_object->Get(context, done_key_).ToLocal(&done)) {
CHECK(!try_catch.Exception().IsEmpty());
exception_state.RethrowV8Exception(try_catch.Exception());
done_ = true;
return false;
}
done_ = done->BooleanValue(isolate_);
return !done_;
}
} // namespace blink