* Copyright (c) 2021-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/js_generator_object.h"
#include "ecmascript/generator_helper.h"
#include "ecmascript/js_iterator.h"
#include "ecmascript/js_object-inl.h"
#include "ecmascript/js_tagged_value_wrapper-inl.h"
namespace panda::ecmascript {
JSGeneratorState JSGeneratorObject::GeneratorValidate(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
{
if (!obj->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is not object",
JSGeneratorState::UNDEFINED);
}
JSHandle<JSObject> toObj = JSTaggedValue::ToObject(thread, obj);
if (!toObj->IsGeneratorObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is not generator object", JSGeneratorState::UNDEFINED);
}
JSHandle<JSGeneratorObject> generator(thread, JSGeneratorObject::Cast(*(toObj)));
JSGeneratorState state = generator->GetGeneratorState();
if (state == JSGeneratorState::EXECUTING) {
THROW_TYPE_ERROR_AND_RETURN(thread, "State is executing", JSGeneratorState::UNDEFINED);
}
return state;
}
JSHandle<JSObject> JSGeneratorObject::GeneratorResume(JSThread *thread, const JSHandle<JSGeneratorObject> &generator,
JSTaggedValue value)
{
JSHandle<JSTaggedValue> gen(thread, generator.GetTaggedValue());
JSGeneratorState state = GeneratorValidate(thread, gen);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread);
if (state == JSGeneratorState::COMPLETED) {
JSHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
return JSIterator::CreateIterResultObject(thread, valueHandle, true);
}
ASSERT_PRINT(state == JSGeneratorState::SUSPENDED_START ||
state == JSGeneratorState::SUSPENDED_YIELD,
"state is neither suspendedStart nor suspendedYield");
JSHandle<GeneratorContext> genContext(thread, generator->GetGeneratorContext(thread));
generator->SetGeneratorState(JSGeneratorState::EXECUTING);
JSHandle<JSObject> result = GeneratorHelper::Next(thread, genContext, value);
return result;
}
JSHandle<JSObject> JSGeneratorObject::GeneratorResumeAbrupt(JSThread *thread,
const JSHandle<JSGeneratorObject> &generator,
const JSHandle<CompletionRecord> &abruptCompletion)
{
JSHandle<JSTaggedValue> gen(thread, generator.GetTaggedValue());
JSGeneratorState state = GeneratorValidate(thread, gen);
RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread);
if (state == JSGeneratorState::SUSPENDED_START) {
state = JSGeneratorState::COMPLETED;
generator->SetGeneratorState(state);
}
if (state == JSGeneratorState::COMPLETED) {
JSHandle<JSTaggedValue> valueHandle(thread, abruptCompletion->GetValue(thread));
JSHandle<JSObject> result = JSIterator::CreateIterResultObject(thread, valueHandle, true);
if (abruptCompletion->GetType() == CompletionRecordType::RETURN) {
return result;
}
THROW_NEW_ERROR_AND_RETURN_VALUE(thread, valueHandle.GetTaggedValue(), result);
}
ASSERT_PRINT(state == JSGeneratorState::SUSPENDED_YIELD, "state is not suspendedYield");
JSHandle<GeneratorContext> genContext(thread, generator->GetGeneratorContext(thread));
generator->SetGeneratorState(JSGeneratorState::EXECUTING);
JSHandle<JSObject> result;
if (abruptCompletion->GetType() == CompletionRecordType::RETURN) {
result = GeneratorHelper::Return(thread, genContext, abruptCompletion->GetValue(thread));
} else {
result = GeneratorHelper::Throw(thread, genContext, abruptCompletion->GetValue(thread));
}
return result;
}
}