14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/js_generator_object.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/generator_helper.h"
194514f5e3Sopenharmony_ci#include "ecmascript/js_iterator.h"
204514f5e3Sopenharmony_ci#include "ecmascript/js_object-inl.h"
214514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value-inl.h"
224514f5e3Sopenharmony_ci
234514f5e3Sopenharmony_cinamespace panda::ecmascript {
244514f5e3Sopenharmony_ciJSGeneratorState JSGeneratorObject::GeneratorValidate(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
254514f5e3Sopenharmony_ci{
264514f5e3Sopenharmony_ci    // 1.Perform ? RequireInternalSlot(generator, [[GeneratorState]]).
274514f5e3Sopenharmony_ci    // 2.Assert: generator also has a [[GeneratorContext]] internal slot.
284514f5e3Sopenharmony_ci    if (!obj->IsECMAObject()) {
294514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Is not object",
304514f5e3Sopenharmony_ci            JSGeneratorState::UNDEFINED);
314514f5e3Sopenharmony_ci    }
324514f5e3Sopenharmony_ci    JSHandle<JSObject> toObj = JSTaggedValue::ToObject(thread, obj);
334514f5e3Sopenharmony_ci    if (!toObj->IsGeneratorObject()) {
344514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "Is not generator object", JSGeneratorState::UNDEFINED);
354514f5e3Sopenharmony_ci    }
364514f5e3Sopenharmony_ci
374514f5e3Sopenharmony_ci    // 3.Let state be generator.[[GeneratorState]].
384514f5e3Sopenharmony_ci    JSHandle<JSGeneratorObject> generator(thread, JSGeneratorObject::Cast(*(toObj)));
394514f5e3Sopenharmony_ci    JSGeneratorState state = generator->GetGeneratorState();
404514f5e3Sopenharmony_ci    // 4.If state is executing, throw a TypeError exception.
414514f5e3Sopenharmony_ci    if (state == JSGeneratorState::EXECUTING) {
424514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "State is executing", JSGeneratorState::UNDEFINED);
434514f5e3Sopenharmony_ci    }
444514f5e3Sopenharmony_ci    // 5.Return state.
454514f5e3Sopenharmony_ci    return state;
464514f5e3Sopenharmony_ci}
474514f5e3Sopenharmony_ci
484514f5e3Sopenharmony_ciJSHandle<JSObject> JSGeneratorObject::GeneratorResume(JSThread *thread, const JSHandle<JSGeneratorObject> &generator,
494514f5e3Sopenharmony_ci                                                      JSTaggedValue value)
504514f5e3Sopenharmony_ci{
514514f5e3Sopenharmony_ci    // 1.Let state be ? GeneratorValidate(generator).
524514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> gen(thread, generator.GetTaggedValue());
534514f5e3Sopenharmony_ci    JSGeneratorState state = GeneratorValidate(thread, gen);
544514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread);
554514f5e3Sopenharmony_ci
564514f5e3Sopenharmony_ci    // 2.If state is completed, return CreateIterResultObject(undefined, true).
574514f5e3Sopenharmony_ci    if (state == JSGeneratorState::COMPLETED) {
584514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
594514f5e3Sopenharmony_ci        return JSIterator::CreateIterResultObject(thread, valueHandle, true);
604514f5e3Sopenharmony_ci    }
614514f5e3Sopenharmony_ci
624514f5e3Sopenharmony_ci    // 3.Assert: state is either suspendedStart or suspendedYield.
634514f5e3Sopenharmony_ci    ASSERT_PRINT(state == JSGeneratorState::SUSPENDED_START ||
644514f5e3Sopenharmony_ci                     state == JSGeneratorState::SUSPENDED_YIELD,
654514f5e3Sopenharmony_ci                 "state is neither suspendedStart nor suspendedYield");
664514f5e3Sopenharmony_ci
674514f5e3Sopenharmony_ci    // 4.Let genContext be generator.[[GeneratorContext]].
684514f5e3Sopenharmony_ci    JSHandle<GeneratorContext> genContext(thread, generator->GetGeneratorContext());
694514f5e3Sopenharmony_ci
704514f5e3Sopenharmony_ci    // 5.Let methodContext be the running execution context.
714514f5e3Sopenharmony_ci    // 6.Suspend methodContext.
724514f5e3Sopenharmony_ci
734514f5e3Sopenharmony_ci    // 7.Set generator.[[GeneratorState]] to executing.
744514f5e3Sopenharmony_ci    generator->SetGeneratorState(JSGeneratorState::EXECUTING);
754514f5e3Sopenharmony_ci
764514f5e3Sopenharmony_ci    // 8.Push genContext onto the execution context stack; genContext is now the running execution context.
774514f5e3Sopenharmony_ci    // 9.Resume the suspended evaluation of genContext using NormalCompletion(value) as the result of the operation
784514f5e3Sopenharmony_ci    //   that suspended it. Let result be the value returned by the resumed computation.
794514f5e3Sopenharmony_ci    // 10.Assert: When we return here, genContext has already been removed from the execution context stack and
804514f5e3Sopenharmony_ci    //    methodContext is the currently running execution context.
814514f5e3Sopenharmony_ci    // 11.Return Completion(result).
824514f5e3Sopenharmony_ci    JSHandle<JSObject> result = GeneratorHelper::Next(thread, genContext, value);
834514f5e3Sopenharmony_ci    return result;
844514f5e3Sopenharmony_ci}
854514f5e3Sopenharmony_ci
864514f5e3Sopenharmony_ciJSHandle<JSObject> JSGeneratorObject::GeneratorResumeAbrupt(JSThread *thread,
874514f5e3Sopenharmony_ci                                                            const JSHandle<JSGeneratorObject> &generator,
884514f5e3Sopenharmony_ci                                                            const JSHandle<CompletionRecord> &abruptCompletion)
894514f5e3Sopenharmony_ci{
904514f5e3Sopenharmony_ci    // 1.Let state be ? GeneratorValidate(generator).
914514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> gen(thread, generator.GetTaggedValue());
924514f5e3Sopenharmony_ci    JSGeneratorState state = GeneratorValidate(thread, gen);
934514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread);
944514f5e3Sopenharmony_ci
954514f5e3Sopenharmony_ci    // 2.If state is suspendedStart, then
964514f5e3Sopenharmony_ci    //     a.Set generator.[[GeneratorState]] to completed.
974514f5e3Sopenharmony_ci    //     b.Once a generator enters the completed state it never leaves it and its associated execution context is
984514f5e3Sopenharmony_ci    //       never resumed. Any execution state associated with generator can be discarded at this point.
994514f5e3Sopenharmony_ci    //     c.Set state to completed.
1004514f5e3Sopenharmony_ci    if (state == JSGeneratorState::SUSPENDED_START) {
1014514f5e3Sopenharmony_ci        state = JSGeneratorState::COMPLETED;
1024514f5e3Sopenharmony_ci        generator->SetGeneratorState(state);
1034514f5e3Sopenharmony_ci    }
1044514f5e3Sopenharmony_ci
1054514f5e3Sopenharmony_ci    // 3.If state is completed, then
1064514f5e3Sopenharmony_ci    //     a.If abruptCompletion.[[Type]] is return, then
1074514f5e3Sopenharmony_ci    //         i.Return CreateIterResultObject(abruptCompletion.[[Value]], true).
1084514f5e3Sopenharmony_ci    //     b.Return Completion(abruptCompletion).
1094514f5e3Sopenharmony_ci    if (state == JSGeneratorState::COMPLETED) {
1104514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> valueHandle(thread, abruptCompletion->GetValue());
1114514f5e3Sopenharmony_ci        JSHandle<JSObject> result = JSIterator::CreateIterResultObject(thread, valueHandle, true);
1124514f5e3Sopenharmony_ci        if (abruptCompletion->GetType() == CompletionRecordType::RETURN) {
1134514f5e3Sopenharmony_ci            return result;
1144514f5e3Sopenharmony_ci        }
1154514f5e3Sopenharmony_ci        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, valueHandle.GetTaggedValue(), result);
1164514f5e3Sopenharmony_ci    }
1174514f5e3Sopenharmony_ci
1184514f5e3Sopenharmony_ci    // 4.Assert: state is suspendedYield.
1194514f5e3Sopenharmony_ci    ASSERT_PRINT(state == JSGeneratorState::SUSPENDED_YIELD, "state is not suspendedYield");
1204514f5e3Sopenharmony_ci
1214514f5e3Sopenharmony_ci    // 5.Let genContext be generator.[[GeneratorContext]].
1224514f5e3Sopenharmony_ci    JSHandle<GeneratorContext> genContext(thread, generator->GetGeneratorContext());
1234514f5e3Sopenharmony_ci
1244514f5e3Sopenharmony_ci    // 6.Let methodContext be the running execution context.
1254514f5e3Sopenharmony_ci    // 7.Suspend methodContext.
1264514f5e3Sopenharmony_ci
1274514f5e3Sopenharmony_ci    // 8.Set generator.[[GeneratorState]] to executing.
1284514f5e3Sopenharmony_ci    generator->SetGeneratorState(JSGeneratorState::EXECUTING);
1294514f5e3Sopenharmony_ci
1304514f5e3Sopenharmony_ci    // 9.Push genContext onto the execution context stack; genContext is now the running execution context.
1314514f5e3Sopenharmony_ci    // 10.Resume the suspended evaluation of genContext using abruptCompletion as the result of the operation that
1324514f5e3Sopenharmony_ci    //    suspended it. Let result be the completion record returned by the resumed computation.
1334514f5e3Sopenharmony_ci    // 11.Assert: When we return here, genContext has already been removed from the execution context stack and
1344514f5e3Sopenharmony_ci    //    methodContext is the currently running execution context.
1354514f5e3Sopenharmony_ci    // 12.Return Completion(result).
1364514f5e3Sopenharmony_ci    JSHandle<JSObject> result;
1374514f5e3Sopenharmony_ci    if (abruptCompletion->GetType() == CompletionRecordType::RETURN) {
1384514f5e3Sopenharmony_ci        result = GeneratorHelper::Return(thread, genContext, abruptCompletion->GetValue());
1394514f5e3Sopenharmony_ci    } else {
1404514f5e3Sopenharmony_ci        result = GeneratorHelper::Throw(thread, genContext, abruptCompletion->GetValue());
1414514f5e3Sopenharmony_ci    }
1424514f5e3Sopenharmony_ci    return result;
1434514f5e3Sopenharmony_ci}
1444514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
145