/* * 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. */ // // desc: For-of-loop syntax is translated to the while-loop syntax by calling of special method // providing predefined 'iterator' interface: // for (let x of c) { // c is an object of 'iterable' class //
// } // ... // let_ci_=_c.$_iterator() // let_it_=_ci.next() // while_(!it.done)_{ // x_=_it.value! // // it_=_ci.next() // } // #include "objectIterator.h" #include "parser/ETSparser.h" #include "compiler/lowering/util.h" #include "compiler/lowering/scopesInit/scopesInitPhase.h" #include "checker/ETSchecker.h" namespace ark::es2panda::compiler { static constexpr std::size_t const WHILE_LOOP_POSITION = 2U; static constexpr std::size_t const WHILE_LOOP_SIZE = 2U; std::string_view ObjectIteratorLowering::Name() const { static std::string const NAME = "ObjectIteratorLowering"; return NAME; } void ObjectIteratorLowering::TransferForOfLoopBody(ir::Statement *const forBody, ir::BlockStatement *const whileBody, bool const needCleaning) const noexcept { ASSERT(forBody != nullptr && whileBody != nullptr); auto &whileStatements = whileBody->Statements(); // Currently while loop body consists of 2 statements: 'x = it.value!' and 'it = ci.next()' // We need to insert the body of original for-of-loop between them, change their parent and // probably clean types for expressions and variables for identifier for subsequent re-check. if (forBody->IsBlockStatement()) { auto &forStatements = forBody->AsBlockStatement()->Statements(); std::size_t const forSize = forStatements.size(); whileStatements.resize(WHILE_LOOP_SIZE + forSize); whileStatements[WHILE_LOOP_SIZE + forSize - 1U] = whileStatements[WHILE_LOOP_SIZE - 1U]; for (std::size_t i = 0U; i < forSize; ++i) { auto &statement = forStatements[i]; statement->SetParent(whileBody); if (needCleaning) { // Note: we don't need to clean top-level statement itself because it doesn't have type. ClearTypesVariablesAndScopes(statement); } whileStatements[WHILE_LOOP_SIZE + i - 1U] = statement; } } else { whileStatements.resize(WHILE_LOOP_SIZE + 1U); whileStatements[WHILE_LOOP_SIZE] = whileStatements[WHILE_LOOP_SIZE - 1U]; forBody->SetParent(whileBody); if (needCleaning) { ClearTypesVariablesAndScopes(forBody); } whileStatements[WHILE_LOOP_SIZE - 1U] = forBody; } } ir::Statement *ObjectIteratorLowering::ProcessObjectIterator(parser::ETSParser *parser, checker::ETSChecker *checker, varbinder::ETSBinder *varbinder, ir::ForOfStatement *forOfStatement) const { // Note! We assume that parser, varbinder and checker phases have been already passed correctly, thus the // class has required accessible iterator method and all the types and scopes are properly resolved. auto *const allocator = checker->Allocator(); auto statementScope = varbinder::LexicalScope