• 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) {
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, objReg: VReg, propReg: VReg, compiler: Compiler) {
48    let pandaGen = compiler.getPandaGen();
49    let obj = objReg;
50    let prop: VReg | string | number = propReg;
51
52    // get obj first;
53    if (!jshelpers.isSuperProperty(node)) {
54        compiler.compileExpression(node.expression);
55        pandaGen.storeAccumulator(node.expression, objReg);
56    }
57
58    if (ts.isPropertyAccessExpression(node)) {
59        if (node.name.kind != ts.SyntaxKind.Identifier) {
60            throw new Error("Property name of type private Identifier is unimplemented");
61        }
62
63        prop = jshelpers.getTextOfIdentifierOrLiteral(node.name);
64    } else {
65        if (ts.isStringLiteral(node.argumentExpression)) {
66            prop = jshelpers.getTextOfIdentifierOrLiteral(node.argumentExpression);
67            // deal with case like a["1"]
68            let temp = Number(prop);
69            if (!isNaN(Number.parseFloat(prop)) && !isNaN(temp) && isValidIndex(temp) && String(temp) == prop) {
70                prop = temp;
71            }
72        } else if (ts.isNumericLiteral(node.argumentExpression)) {
73            prop = parseFloat(jshelpers.getTextOfIdentifierOrLiteral(node.argumentExpression));
74            if (!isValidIndex(prop)) {
75                prop = prop.toString();
76            }
77        } else if (ts.isPrefixUnaryExpression(node.argumentExpression) && ts.isNumericLiteral(node.argumentExpression.operand) &&
78            (node.argumentExpression.operator == ts.SyntaxKind.MinusToken || node.argumentExpression.operator == ts.SyntaxKind.PlusToken)) {
79            let expr = node.argumentExpression;
80            let temp = parseFloat(jshelpers.getTextOfIdentifierOrLiteral(expr.operand));
81            if (expr.operator == ts.SyntaxKind.MinusToken) {
82                prop = temp === 0 ? temp : "-" + temp.toString();
83            } else {
84                if (!isValidIndex(temp)) {
85                    prop = "+" + temp.toString();
86                } else {
87                    prop = temp;
88                }
89            }
90        } else {
91            compiler.compileExpression(node.argumentExpression);
92            pandaGen.storeAccumulator(node.argumentExpression, propReg);
93            prop = propReg;
94        }
95    }
96
97    return { obj: obj, prop: prop };
98}
99
100export function isValidIndex(num: number) {
101    if ((num >= 0) && (num < MAX_LENGTH) && (Number.isInteger(num))) {
102        return true;
103    }
104
105    return false;
106}
107