• 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 * as ts from "typescript";
17import { Compiler } from "../compiler";
18import * as jshelpers from "../jshelpers";
19import { LiteralTag, Literal, LiteralBuffer } from "../base/literal";
20import { isConstantExpr } from "../base/properties";
21import { PandaGen } from "../pandagen";
22import { isInteger } from "./numericLiteral";
23import { VReg } from "../irnodes";
24
25export function compileArrayLiteralExpression(compiler: Compiler, node: ts.ArrayLiteralExpression) {
26    let pandaGen = compiler.getPandaGen();
27    let arrayObj = pandaGen.getTemp();
28    createArrayFromElements(node, compiler, node.elements, arrayObj);
29    pandaGen.freeTemps(arrayObj);
30}
31
32export function createArrayFromElements(node: ts.Node, compiler: Compiler, elements: ts.NodeArray<ts.Expression>, arrayObj: VReg) {
33    let pandaGen = compiler.getPandaGen();
34    // empty Array
35    if (elements.length == 0) {
36        pandaGen.createEmptyArray(node);
37        pandaGen.storeAccumulator(node, arrayObj);
38        return;
39    }
40
41    let literalBuffer = new LiteralBuffer();
42    let indexReg = pandaGen.getTemp();
43    let arrayCreated: boolean = false;
44    let hasSpread: boolean = false;
45
46    for (let i = 0; i < elements.length; i++) {
47        let element = elements[i];
48
49        if (isConstantExpr(element)) {
50            let elem = parseConstantExpr(element);
51
52            if (!arrayCreated) {
53                literalBuffer.addLiterals(elem);
54                if (i == elements.length - 1) {
55                    emitCreateArrayWithBuffer(pandaGen, literalBuffer, element);
56                    pandaGen.storeAccumulator(element, arrayObj);
57                    arrayCreated = true;
58                }
59                continue;
60            }
61
62            compiler.compileExpression(element);
63            if (hasSpread) {
64                storeElementIfSpreadExisted(pandaGen, element, arrayObj, indexReg);
65            } else {
66                pandaGen.storeOwnProperty(element, arrayObj, i);
67            }
68            continue;
69        }
70
71        if (ts.isSpreadElement(element)) {
72            if (!arrayCreated) {
73                emitCreateArrayWithBuffer(pandaGen, literalBuffer, element);
74                pandaGen.storeAccumulator(element, arrayObj);
75                arrayCreated = true;
76            }
77
78            if (hasSpread) {
79                storeSpreadElement(compiler, pandaGen, element, arrayObj, indexReg);
80            } else {
81                hasSpread = true;
82                pandaGen.loadAccumulatorInt(element, i);
83                pandaGen.storeAccumulator(element, indexReg);
84                storeSpreadElement(compiler, pandaGen, element, arrayObj, indexReg);
85            }
86            continue;
87        }
88
89        if (ts.isOmittedExpression(element)) {
90            if (!arrayCreated) {
91                emitCreateArrayWithBuffer(pandaGen, literalBuffer, element);
92                pandaGen.storeAccumulator(element, arrayObj);
93                arrayCreated = true;
94            }
95
96            if (i == elements.length - 1) {
97                // omittedExpression is the last element, we need to set the length of the array
98                if (hasSpread) {
99                    pandaGen.loadAccumulator(element, indexReg);
100                    pandaGen.storeObjProperty(element, arrayObj, "length");
101                    // no need to increment index since it's the last element
102                } else {
103                    pandaGen.loadAccumulatorInt(element, elements.length);
104                    pandaGen.storeObjProperty(element, arrayObj, "length");
105                }
106            }
107            continue;
108        }
109
110        // non-constant elements
111        if (!arrayCreated) {
112            emitCreateArrayWithBuffer(pandaGen, literalBuffer, element);
113            pandaGen.storeAccumulator(element, arrayObj);
114            arrayCreated = true;
115        }
116
117        compiler.compileExpression(element);
118
119        if (hasSpread) {
120            storeElementIfSpreadExisted(pandaGen, element, arrayObj, indexReg);
121        } else {
122            pandaGen.storeOwnProperty(element, arrayObj, i);
123        }
124    }
125
126    pandaGen.loadAccumulator(node, arrayObj);
127    pandaGen.freeTemps(indexReg);
128}
129
130function parseConstantExpr(element: ts.Expression): Literal {
131    let elem: Literal;
132    switch (element.kind) {
133        case ts.SyntaxKind.FalseKeyword:
134            elem = new Literal(LiteralTag.BOOLEAN, false);
135            break;
136        case ts.SyntaxKind.TrueKeyword:
137            elem = new Literal(LiteralTag.BOOLEAN, true);
138            break;
139        case ts.SyntaxKind.StringLiteral:
140            elem = new Literal(LiteralTag.STRING, jshelpers.getTextOfIdentifierOrLiteral(element));
141            break;
142        case ts.SyntaxKind.NumericLiteral: {
143            let value = Number.parseFloat(jshelpers.getTextOfIdentifierOrLiteral(element));
144            if (isInteger(value)) {
145                elem = new Literal(LiteralTag.INTEGER, value);
146            } else {
147                elem = new Literal(LiteralTag.DOUBLE, value);
148            }
149            break;
150        }
151        case ts.SyntaxKind.NullKeyword:
152            elem = new Literal(LiteralTag.NULLVALUE, null);
153            break;
154        default:
155            throw new Error("invalid constant expression");
156    }
157
158    return elem;
159}
160
161function emitCreateArrayWithBuffer(pandaGen: PandaGen, literalBuffer: LiteralBuffer, element: ts.Expression) {
162    if (literalBuffer.isEmpty()) {
163        pandaGen.createEmptyArray(element);
164    } else {
165        let bufferId = PandaGen.appendLiteralArrayBuffer(literalBuffer);
166        pandaGen.createArrayWithBuffer(element, bufferId);
167    }
168}
169
170function storeElementIfSpreadExisted(pandaGen: PandaGen, element: ts.Expression, arrayObj: VReg, indexReg: VReg) {
171    pandaGen.storeOwnProperty(element, arrayObj, indexReg);
172    pandaGen.unary(element, ts.SyntaxKind.PlusPlusToken, indexReg);
173    pandaGen.storeAccumulator(element, indexReg);
174}
175
176function storeSpreadElement(compiler: Compiler, pandaGen: PandaGen, element: ts.SpreadElement, arrayObj: VReg, indexReg: VReg) {
177    compiler.compileExpression(element.expression);
178    pandaGen.storeArraySpreadElement(element, arrayObj, indexReg);
179    pandaGen.storeAccumulator(element, indexReg);
180}