1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import * as ts from "typescript"; 17import { Compiler } from "src/compiler"; 18import { 19 CacheList, 20 getVregisterCache 21} from "../base/vregisterCache"; 22import { LabelTarget } from "./labelTarget"; 23import { Label, VReg } from "../irnodes"; 24import { TryBuilderWithForOf } from "./tryStatement"; 25import { PandaGen } from "src/pandagen"; 26import { LoopScope } from "src/scope"; 27 28export enum IteratorType { Normal, Async } 29 30export class IteratorRecord { 31 private type: IteratorType; 32 private object: VReg; 33 private nextMethod: VReg; 34 35 constructor(object: VReg, nextMethod: VReg, type: IteratorType = IteratorType.Normal) { 36 this.type = type; 37 this.object = object; 38 this.nextMethod = nextMethod; 39 } 40 41 getType(): IteratorType { 42 return this.type; 43 } 44 45 getObject(): VReg { 46 return this.object; 47 } 48 49 getNextMethod(): VReg { 50 return this.nextMethod; 51 } 52} 53 54 55export function compileForOfStatement(stmt: ts.ForOfStatement, compiler: Compiler): void { 56 compiler.pushScope(stmt); 57 58 let pandaGen = compiler.getPandaGen(); 59 let nextLabel = new Label(); 60 let endLabel = new Label(); 61 62 let doneReg = pandaGen.getTemp(); 63 let method = pandaGen.getTemp(); 64 let object = pandaGen.getTemp(); 65 66 let loopScope = <LoopScope>compiler.getRecorder().getScopeOfNode(stmt); 67 let needCreateLoopEnv: boolean = loopScope.need2CreateLexEnv(); 68 let loopEnv = pandaGen.getTemp(); 69 70 // for now Async is not handled. 71 let type: IteratorType = stmt.awaitModifier ? IteratorType.Async : IteratorType.Normal; 72 73 if (needCreateLoopEnv) { 74 pandaGen.createLexEnv(stmt, loopScope); 75 compiler.pushEnv(loopEnv); 76 } 77 78 compiler.compileExpression(stmt.expression); 79 let iterator: IteratorRecord = getIteratorRecord(pandaGen, stmt, method, object, type); 80 81 if (needCreateLoopEnv) { 82 pandaGen.popLexicalEnv(stmt); 83 compiler.popEnv(); 84 } 85 86 pandaGen.loadAccumulator(stmt, getVregisterCache(pandaGen, CacheList.FALSE)); 87 pandaGen.storeAccumulator(stmt, doneReg); 88 89 let labelTarget = new LabelTarget(stmt, endLabel, nextLabel, needCreateLoopEnv); 90 LabelTarget.pushLabelTarget(labelTarget); 91 LabelTarget.updateName2LabelTarget(stmt.parent, labelTarget); 92 93 let tryBuilderWithForOf = new TryBuilderWithForOf(compiler, pandaGen, stmt, doneReg, iterator, labelTarget, 94 needCreateLoopEnv, needCreateLoopEnv ? loopEnv : undefined); 95 compiler.constructTry(stmt, tryBuilderWithForOf, nextLabel); 96 97 pandaGen.label(stmt, endLabel); 98 99 LabelTarget.popLabelTarget(); 100 101 if (needCreateLoopEnv) { 102 pandaGen.popLexicalEnv(stmt); 103 compiler.popEnv(); 104 } 105 106 pandaGen.freeTemps(doneReg, method, object, loopEnv); 107 compiler.popScope(); 108} 109 110export function getIteratorRecord(pandagen: PandaGen, node: ts.Node, nextMethod: VReg, object: VReg, type: IteratorType): IteratorRecord { 111 getIterator(pandagen, node, type); 112 113 pandagen.storeAccumulator(node, object); 114 pandagen.loadObjProperty(node, object, "next"); 115 pandagen.storeAccumulator(node, nextMethod); 116 117 return new IteratorRecord(object, nextMethod, type); 118} 119 120function getIterator(pandagen: PandaGen, node: ts.Node, type: IteratorType): void { 121 if (type === IteratorType.Async) { 122 pandagen.getAsyncIterator(node); 123 } else { 124 pandagen.getIterator(node); 125 } 126}