• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { IteratorType } from "../statement/forOfStatement";
17import * as ts from "typescript";
18import {
19    Label,
20    VReg
21} from "../irnodes";
22import { PandaGen } from "../pandagen";
23import { CatchTable, LabelPair } from "../statement/tryStatement";
24import { FunctionBuilder } from "../function/functionBuilder";
25import { AsyncGeneratorFunctionBuilder } from "../function/asyncGeneratorFunctionBuilder";
26import { CacheList, getVregisterCache } from "./vregisterCache";
27
28export class Iterator {
29    private iterRecord: { iterator: VReg, nextMethod: VReg };
30    private iterDone: VReg;
31    private iterValue: VReg;
32    private pandaGen: PandaGen;
33    private node: ts.Node;
34    private kind: IteratorType = IteratorType.Normal;
35    private funcBuilder: FunctionBuilder | undefined = undefined;
36
37    constructor(iterRecord: {iterator: VReg, nextMethod: VReg}, iterDone: VReg, iterValue: VReg,
38                pandaGen: PandaGen, node: ts.Node, kind ? : IteratorType, funcBuilder ? : FunctionBuilder) {
39        this.iterRecord = iterRecord;
40        this.iterDone = iterDone;
41        this.iterValue = iterValue;
42        this.pandaGen = pandaGen;
43        this.node = node;
44        if (kind) {
45            this.kind = kind;
46        }
47
48        if (funcBuilder) {
49            this.funcBuilder = funcBuilder;
50        }
51    }
52
53    getIterator() {
54        let pandaGen = this.pandaGen;
55        let iterator = this.iterRecord.iterator;
56
57        // get iterator
58        this.kind == IteratorType.Normal ? pandaGen.getIterator(this.node) : pandaGen.getAsyncIterator(this.node);
59        pandaGen.storeAccumulator(this.node, iterator);
60
61        // get the next method
62        pandaGen.loadObjProperty(this.node, iterator, "next");
63        pandaGen.storeAccumulator(this.node, this.iterRecord.nextMethod);
64    }
65
66    method(): VReg {
67        return this.iterRecord.nextMethod;
68    }
69
70    getMethod(id: string) {
71        this.pandaGen.loadObjProperty(this.node, this.iterRecord.iterator, id);
72        this.pandaGen.storeAccumulator(this.node, this.iterRecord.nextMethod);
73    }
74
75    /**
76     *  iterResult = nextMethod.call(iterator);
77     *  if (!isObject(iterResult)) {
78     *      throw TypeError
79     *  }
80     */
81    callNext(iterResult: VReg) {
82        this.pandaGen.call(this.node, [this.iterRecord.nextMethod, this.iterRecord.iterator], true);
83        this.pandaGen.storeAccumulator(this.node, iterResult);
84    }
85
86    callMethodwithValue(value: VReg) {
87        this.pandaGen.call(this.node, [this.iterRecord.nextMethod, this.iterRecord.iterator, value], true);
88    }
89
90    iteratorComplete(iterResult: VReg) {
91        this.pandaGen.loadObjProperty(this.node, iterResult, "done");
92        this.pandaGen.storeAccumulator(this.node, this.iterDone);
93    }
94
95    iteratorValue(iterResult: VReg) {
96        this.pandaGen.loadObjProperty(this.node, iterResult, "value");
97        this.pandaGen.storeAccumulator(this.node, this.iterValue);
98    }
99
100    close() {
101        let pg = this.pandaGen;
102        if (this.kind == IteratorType.Normal) {
103            pg.closeIterator(this.node, this.iterRecord.iterator);
104            return;
105        }
106
107        let completion = pg.getTemp();
108        let res = pg.getTemp();
109        let exception = pg.getTemp();
110        let noReturn = new Label();
111
112        let tryBeginLabel = new Label();
113        let tryEndLabel = new Label();
114        let catchBeginLabel = new Label();
115        let catchEndLabel = new Label();
116        new CatchTable(
117            pg,
118            catchBeginLabel,
119            new LabelPair(tryBeginLabel, tryEndLabel)
120        );
121
122        pg.storeAccumulator(this.node, completion);
123        pg.storeConst(this.node, exception, CacheList.HOLE);
124
125
126        pg.label(this.node, tryBeginLabel);
127
128        // 4. Let innerResult be GetMethod(iterator, "return").
129        this.getMethod("return");
130
131        // 5. If innerResult.[[Type]] is normal, then
132        // a. Let return be innerResult.[[Value]].
133        // b. If return is undefined, return Completion(completion).
134        pg.branchIfUndefined(this.node, noReturn);
135        this.callNext(res);
136
137        // if (this.kind == IteratorType.Async) {
138        //     if (!this.funcBuilder) {
139        //         throw new Error("function builder are not supposed to be undefined");
140        //     }
141
142        //     (<AsyncGeneratorFunctionBuilder>this.funcBuilder).await(this.node);
143        // }
144        (<AsyncGeneratorFunctionBuilder>this.funcBuilder).await(this.node);
145        pg.storeAccumulator(this.node, res);
146
147        pg.label(this.node, tryEndLabel);
148        pg.branch(this.node, catchEndLabel);
149
150        pg.label(this.node, catchBeginLabel);
151        pg.storeAccumulator(this.node, exception);
152        pg.label(this.node, catchEndLabel);
153
154        let skipThrow = new Label();
155        let doThrow = new Label();
156        pg.loadAccumulator(this.node, getVregisterCache(pg, CacheList.HOLE));
157        pg.condition(this.node, ts.SyntaxKind.ExclamationEqualsToken, exception, skipThrow);
158
159        pg.label(this.node, doThrow);
160        pg.loadAccumulator(this.node, exception);
161        pg.throw(this.node);
162
163        pg.label(this.node, skipThrow);
164
165        pg.loadAccumulator(this.node, res);
166        pg.throwIfNotObject(this.node, res);
167
168        pg.label(this.node, noReturn);
169        pg.loadAccumulator(this.node, completion);
170
171        pg.freeTemps(completion, res, exception)
172    }
173
174    getCurrentValue() {
175        return this.iterValue;
176    }
177
178    getCurrrentDone() {
179        return this.iterDone;
180    }
181}