• 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 { VReg } from "../irnodes";
19import * as jshelpers from "../jshelpers";
20import { compileSuperProperty } from "../statement/classStatement";
21
22const MAX_LENGTH = 2 ** 32 - 1;
23
24export function compileMemberAccessExpression(node: ts.ElementAccessExpression | ts.PropertyAccessExpression, compiler: Compiler): void {
25    let pandaGen = compiler.getPandaGen();
26    let objReg = pandaGen.getTemp();
27    let propReg = pandaGen.getTemp();
28
29    let { obj: obj, prop: property } = getObjAndProp(node, objReg, propReg, compiler);
30
31    if (jshelpers.isSuperProperty(node)) {
32        // make sure "this" is stored in lexical env if needed
33        let thisReg = pandaGen.getTemp();
34        compileSuperProperty(compiler, node, thisReg, property);
35        pandaGen.freeTemps(thisReg);
36    } else {
37        pandaGen.loadObjProperty(
38            ts.isPropertyAccessExpression(node) ? node.name : node.argumentExpression,
39            obj,
40            property
41        );
42    }
43
44    pandaGen.freeTemps(objReg, propReg);
45}
46
47export function getObjAndProp(node: ts.ElementAccessExpression | ts.PropertyAccessExpression,
48                              objReg: VReg, propReg: VReg, compiler: Compiler): { obj: VReg; prop: any; } {
49    let pandaGen = compiler.getPandaGen();
50    let obj = objReg;
51    let prop: VReg | string | number = propReg;
52
53    // get obj first;
54    if (!jshelpers.isSuperProperty(node)) {
55        compiler.compileExpression(node.expression);
56        pandaGen.storeAccumulator(node.expression, objReg);
57    }
58
59    if (ts.isPropertyAccessExpression(node)) {
60        if (node.name.kind != ts.SyntaxKind.Identifier) {
61            throw new Error("Property name of type private Identifier is unimplemented");
62        }
63
64        prop = jshelpers.getTextOfIdentifierOrLiteral(node.name);
65    } else {
66        if (ts.isStringLiteral(node.argumentExpression)) {
67            prop = jshelpers.getTextOfIdentifierOrLiteral(node.argumentExpression);
68            // deal with case like a["1"]
69            let temp = Number(prop);
70            if (!isNaN(Number.parseFloat(prop)) && !isNaN(temp) && isValidIndex(temp) && String(temp) === prop) {
71                prop = temp;
72            }
73        } else if (ts.isNumericLiteral(node.argumentExpression)) {
74            prop = parseFloat(jshelpers.getTextOfIdentifierOrLiteral(node.argumentExpression));
75            if (!isValidIndex(prop)) {
76                prop = prop.toString();
77            }
78        } else if (ts.isPrefixUnaryExpression(node.argumentExpression) && ts.isNumericLiteral(node.argumentExpression.operand) &&
79            (node.argumentExpression.operator === ts.SyntaxKind.MinusToken || node.argumentExpression.operator === ts.SyntaxKind.PlusToken)) {
80            let expr = node.argumentExpression;
81            let temp = parseFloat(jshelpers.getTextOfIdentifierOrLiteral(expr.operand));
82            if (expr.operator === ts.SyntaxKind.MinusToken) {
83                prop = temp === 0 ? temp : "-" + temp.toString();
84            } else {
85                if (!isValidIndex(temp)) {
86                    prop = "+" + temp.toString();
87                } else {
88                    prop = temp;
89                }
90            }
91        } else {
92            compiler.compileExpression(node.argumentExpression);
93            pandaGen.storeAccumulator(node.argumentExpression, propReg);
94            prop = propReg;
95        }
96    }
97
98    return { obj: obj, prop: prop };
99}
100
101export function isValidIndex(num: number): boolean {
102    if ((num >= 0) && (num < MAX_LENGTH) && (Number.isInteger(num))) {
103        return true;
104    }
105
106    return false;
107}
108