• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 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 { CompilerDriver } from "../../src/compilerDriver";
18import {
19    Imm,
20    IRNode,
21    Label,
22    OperandType,
23    VReg
24} from "../../src/irnodes";
25import * as jshelpers from "../../src/jshelpers";
26import { PandaGen } from "../../src/pandagen";
27import { Pass } from "../../src/pass";
28import {
29    Scope
30} from "../../src/scope";
31import { setGlobalStrict } from "../../src/strictMode";
32import { creatAstFromSnippet } from "./asthelper";
33import { LiteralBuffer } from "../../src/base/literal";
34import { CmdOptions } from "../../src/cmdOptions";
35import {
36    transformCommonjsModule,
37    makeNameForGeneratedNode,
38    resetUniqueNameIndex
39} from "../../src/base/util";
40
41const compileOptions = {
42    outDir: "../tmp/build",
43    allowJs: true,
44    noEmitOnError: true,
45    noImplicitAny: true,
46    target: ts.ScriptTarget.ES5,
47    module: ts.ModuleKind.CommonJS,
48    strictNullChecks: true
49};
50
51function isVReg(node: OperandType): node is VReg {
52    return (node instanceof VReg);
53}
54
55function isImm(node: OperandType): node is Imm {
56    return (node instanceof Imm);
57}
58
59function isId(node: OperandType): node is string {
60    return (typeof node === "string");
61}
62
63function isLabel(node: OperandType): node is Label {
64    return (node instanceof Label);
65}
66
67function isSameOperandType(left: OperandType, right: OperandType): boolean {
68    return (left.constructor === right.constructor);
69}
70
71function object2String(obj: any): string {
72    let retval = "";
73    retval += obj.constructor.name + '\n';
74    retval += JSON.stringify(obj) + '\n';
75    return retval;
76}
77
78function basicOperandsEqual(left: OperandType, right: OperandType): boolean {
79    if (!isSameOperandType(left, right)) {
80        return false;
81    }
82
83    if (isVReg(left) && isVReg(right)) {
84        return true;
85    }
86
87    if (isImm(left) && isImm(right)) {
88        return left.value === right.value;
89    }
90
91    if (isLabel(left) && isLabel(right)) {
92        return true;
93    }
94
95    if (isId(left) && isId(right)) {
96        // string compare
97        return left === right;
98    }
99
100    let str = "operandsEqual: operands are not one of this types: VReg | Imm | Label | BuiltIns | string\n";
101    str += object2String(left);
102    str += object2String(right);
103
104    throw new Error(str);
105}
106
107export function basicChecker(left: IRNode, right: IRNode): boolean {
108    if (left.kind !== right.kind) {
109        console.log("left.kind:" + left.kind + " right.kind:" + right.kind);
110        return false;
111    }
112
113    const operandCount = left.operands.length;
114    for (let i = 0; i < operandCount; ++i) {
115        const lop = left.operands[i];
116        const rop = right.operands[i];
117        if (!basicOperandsEqual(lop, rop)) {
118            console.log("left.operands:");
119            console.log(left.operands[i]);
120            console.log("right.operands:");
121            console.log(right.operands[i]);
122            return false;
123        }
124    }
125
126    return true;
127}
128
129export function checkInstructions(actual: IRNode[], expected: IRNode[], checkFn?: Function): boolean {
130    if (!checkFn) {
131        checkFn = basicChecker;
132    }
133
134    if (actual.length !== expected.length) {
135        console.log("actual.length:" + actual.length + " expected.length:" + expected.length);
136        return false;
137    }
138
139    for (let i = 0; i < actual.length; ++i) {
140        if (!checkFn(actual[i], expected[i])) {
141            return false;
142        }
143    }
144
145    return true;
146}
147
148export function compileAllSnippet(snippet: string, passes?: Pass[], literalBufferArray?: Array<LiteralBuffer>,
149                                  isWatchEvaluateExpressionMode?: boolean): PandaGen[] {
150    let sourceFile = creatAstFromSnippet(snippet);
151    jshelpers.bindSourceFile(sourceFile, {});
152    CmdOptions.parseUserCmd([""]);
153    if (isWatchEvaluateExpressionMode) {
154        CmdOptions.setWatchEvaluateExpressionArgs(['','']);
155    }
156    CmdOptions.setMergeAbc(true);
157    CmdOptions.isWatchEvaluateExpressionMode() ? setGlobalStrict(true) :
158        setGlobalStrict(jshelpers.isEffectiveStrictModeSourceFile(sourceFile, compileOptions));
159    let compilerDriver = new CompilerDriver('UnitTest', 'UnitTest');
160    CompilerDriver.srcNode = sourceFile;
161
162    if (!passes) {
163        passes = [];
164    }
165    compilerDriver.setCustomPasses(passes);
166    compilerDriver.compileUnitTest(sourceFile, literalBufferArray);
167    return compilerDriver.getCompilationUnits();
168}
169
170export function compileMainSnippet(snippet: string, pandaGen?: PandaGen, scope?: Scope, passes?: Pass[],
171                                   compileFunc?: boolean, isWatchEvaluateExpressionMode?: boolean): IRNode[] {
172    let compileUnits = compileAllSnippet(snippet, passes, undefined, isWatchEvaluateExpressionMode);
173
174    if (compileUnits.length != 1 && !compileFunc) {
175        throw new Error("Error: please use compileMainSnippet1 for multi function compile");
176    }
177
178    // only return main function
179    if (compileFunc) {
180        compileUnits.filter((pg) => {
181            return (pg.internalName === "UnitTest.func_main_0");
182        })
183    }
184
185    return compileUnits[0].getInsns();
186}
187
188export function compileAfterSnippet(snippet: string, name:string, isCommonJs: boolean = false): any {
189    let compileUnits = null;
190    CmdOptions.parseUserCmd([""]);
191    CmdOptions.setMergeAbc(true);
192    ts.transpileModule(
193        snippet,
194        {
195        compilerOptions : {
196            "target": ts.ScriptTarget.ES2015,
197            "experimentalDecorators": true
198        },
199        fileName : name,
200        transformers : {
201            after : [
202                (ctx: ts.TransformationContext) => {
203                    return (sourceFile: ts.SourceFile) => {
204                        resetUniqueNameIndex();
205                        makeNameForGeneratedNode(sourceFile);
206                        if (isCommonJs) {
207                            sourceFile = transformCommonjsModule(sourceFile);
208                        }
209                        jshelpers.bindSourceFile(sourceFile, {});
210                        setGlobalStrict(jshelpers.isEffectiveStrictModeSourceFile(sourceFile, compileOptions));
211                        let compilerDriver = new CompilerDriver('UnitTest', 'UnitTest');
212                        CompilerDriver.srcNode = sourceFile;
213                        compilerDriver.setCustomPasses([]);
214                        compilerDriver.compileUnitTest(sourceFile, []);
215                        compileUnits = compilerDriver.getCompilationUnits();
216                        return sourceFile;
217                    }
218                }
219            ]
220        }
221        }
222    );
223
224    return compileUnits;
225}
226
227export function getCompileOptions(): ts.CompilerOptions {
228    return compileOptions;
229}
230
231export class SnippetCompiler {
232    pandaGens: PandaGen[] = [];
233    compile(snippet: string, passes?: Pass[], literalBufferArray?: Array<LiteralBuffer>): PandaGen[] {
234        this.pandaGens = compileAllSnippet(snippet, passes, literalBufferArray);
235        return this.pandaGens;
236    }
237
238    compileAfter(snippet: string, name: string, passes?: Pass[], literalBufferArray?: Array<LiteralBuffer>): PandaGen[] {
239        this.pandaGens = compileAfterSnippet(snippet, name);
240        return this.pandaGens;
241    }
242
243    compileCommonjs(snippet: string, name: string): PandaGen[] {
244        this.pandaGens = compileAfterSnippet(snippet, name, true);
245        return this.pandaGens;
246    }
247
248    getGlobalInsns(): IRNode[] {
249        let root = this.getPandaGenByName("UnitTest.func_main_0");
250        if (root) {
251            return root.getInsns();
252        } else {
253            return [];
254        }
255    }
256
257    getGlobalScope(): Scope | undefined {
258        let globalPandaGen = this.getPandaGenByName("UnitTest.func_main_0");
259
260        return globalPandaGen ? globalPandaGen.getScope()!.getNearestVariableScope() : undefined;
261    }
262
263    getPandaGenByName(name: string): PandaGen | undefined {
264        let pgs = this.pandaGens.filter(pg => {
265            return (pg.internalName === name);
266        })
267        return pgs[0];
268    }
269}