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