diff --git a/ts2panda/src/base/util.ts b/ts2panda/src/base/util.ts index 6206b628f807a46ee6d9f9b80d0ae83e31740f02..9867a3a71e21010cf3ed29f3c88a3710c899c99b 100644 --- a/ts2panda/src/base/util.ts +++ b/ts2panda/src/base/util.ts @@ -304,4 +304,11 @@ export function setPos(node: ts.Node) { setPos(childNode); }); return node; -} \ No newline at end of file +} + +export function isBase64Str(input: string): boolean { + if (input == '' || input.trim() == '') { + return false; + } + return Buffer.from(Buffer.from(input, 'base64').toString()).toString('base64') == input; +} diff --git a/ts2panda/src/cmdOptions.ts b/ts2panda/src/cmdOptions.ts index 7b9e37bb70342e249a6a60427fb9f3299b67e357..854cf326354908081fc25193ec7ef0c7d316d67c 100644 --- a/ts2panda/src/cmdOptions.ts +++ b/ts2panda/src/cmdOptions.ts @@ -26,6 +26,7 @@ const ts2pandaOptions = [ { name: 'debug-log', alias: 'l', type: Boolean, defaultValue: false, description: "show info debug log and generate the json file."}, { name: 'dump-assembly', alias: 'a', type: Boolean, defaultValue: false, description: "dump assembly to file." }, { name: 'debug', alias: 'd', type: Boolean, defaultValue: false, description: "compile with debug info." }, + { name: 'debug-add-watch', alias: 'w', type: String, lazyMultiple: true, defaultValue: [], description: "watch expression and abc file path in debug mode." }, { name: 'show-statistics', alias: 's', type: String, lazyMultiple: true, defaultValue: "", description: "show compile statistics(ast, histogram, hoisting, all)." }, { name: 'output', alias: 'o', type: String, defaultValue: "", description: "set output file." }, { name: 'timeout', alias: 't', type: Number, defaultValue: 0, description: "js to abc timeout threshold(unit: seconds)." }, @@ -71,6 +72,24 @@ export class CmdOptions { return this.options["debug"]; } + static getAddWatchArgs(): string[] { + if (!this.options) { + return []; + } + return this.options["debug-add-watch"]; + } + + static isWatchMode(): boolean { + if (!this.options) { + return false; + } + return this.options["debug-add-watch"].length != 0; + } + + static setWatchArgs(watchArgs: string[]) { + this.options["debug-add-watch"] = watchArgs; + } + static isModules(): boolean { if (!this.options) { return false; diff --git a/ts2panda/src/compiler.ts b/ts2panda/src/compiler.ts index 9f7bc7fc8d49fd2411156d2a8793067100e05c0c..10d55afe00ca61902b21752080a92069882d1982 100644 --- a/ts2panda/src/compiler.ts +++ b/ts2panda/src/compiler.ts @@ -327,7 +327,8 @@ export class Compiler { this.funcBuilder.resolve(NodeKind.Invalid, getVregisterCache(pandaGen, CacheList.undefined)); pandaGen.return(NodeKind.Invalid); } else { - pandaGen.returnUndefined(NodeKind.Invalid); + CmdOptions.isWatchMode() ? pandaGen.return(NodeKind.Invalid) + : pandaGen.returnUndefined(NodeKind.Invalid); } } } @@ -950,8 +951,8 @@ export class Compiler { // typeof an undeclared variable will return undefined instead of throwing reference error let parent = findOuterNodeOfParenthesis(id); if ((parent.kind == ts.SyntaxKind.TypeOfExpression)) { - let obj = getVregisterCache(pandaGen, CacheList.Global); - pandaGen.loadObjProperty(id, obj, name); + CmdOptions.isWatchMode() ? pandaGen.loadByNameViaDebugger(id, name, CacheList.False) + : pandaGen.loadObjProperty(id, getVregisterCache(pandaGen, CacheList.Global), name); } else { pandaGen.tryLoadGlobalByName(id, name); } @@ -1555,8 +1556,9 @@ export class Compiler { if (variable.v.isNone()) { let parent = findOuterNodeOfParenthesis(node); if ((parent.kind == ts.SyntaxKind.TypeOfExpression)) { - let obj = getVregisterCache(this.pandaGen, CacheList.Global); - this.pandaGen.loadObjProperty(node, obj, variable.v.getName()); + CmdOptions.isWatchMode() ? this.pandaGen.loadByNameViaDebugger(node, variable.v.getName(), + CacheList.False) : this.pandaGen.loadObjProperty(node, getVregisterCache(this.pandaGen, + CacheList.Global), variable.v.getName()); } else { this.pandaGen.tryLoadGlobalByName(node, variable.v.getName()); } diff --git a/ts2panda/src/index.ts b/ts2panda/src/index.ts index 532d7dc7f59844006792ef7c54ca621f70b55ea5..2491b89dca545bbf39aae38101020ec9be2f48ef 100644 --- a/ts2panda/src/index.ts +++ b/ts2panda/src/index.ts @@ -23,7 +23,7 @@ import * as jshelpers from "./jshelpers"; import { LOGE } from "./log"; import { setGlobalDeclare, setGlobalStrict } from "./strictMode"; import { TypeChecker } from "./typeChecker"; -import { setPos } from "./base/util"; +import { setPos, isBase64Str } from "./base/util"; function checkIsGlobalDeclaration(sourceFile: ts.SourceFile) { for (let statement of sourceFile.statements) { @@ -154,6 +154,33 @@ function getDtsFiles(libDir: string): string[] { return dtsFiles; } +function parseWatch(files: string[]): string { + let watchArgs = CmdOptions.getAddWatchArgs(); + let ideIputStr = watchArgs[0]; + if (watchArgs.length != 2 || !isBase64Str(ideIputStr)) { + throw new Error("Incorrect args' format or not enter base64 string in watch mode."); + } + let fragmentSep = "\\n"; + let originExpre = Buffer.from(ideIputStr, 'base64').toString(); + let expressiones = originExpre.split(fragmentSep); + let jsFileName = watchArgs[1] + path.sep + "watch_expres.js"; + let abcFileName = watchArgs[1] + path.sep + "watch_expres.abc"; + let writeFlag: Boolean = false; + for (let index = 0; index < expressiones.length; index++) { + let expreLine = expressiones[index].trim(); + if (expreLine != "") { + if (!writeFlag) { + fs.writeFileSync(jsFileName, expreLine + "\n"); + writeFlag = true; + } else { + fs.appendFileSync(jsFileName, expreLine + "\n"); + } + } + } + files.unshift(jsFileName); + return abcFileName; +} + namespace Compiler { export namespace Options { export let Default: ts.CompilerOptions = { @@ -183,7 +210,18 @@ function run(args: string[], options?: ts.CompilerOptions): void { } try { let files: string[] = parsed.fileNames; + let abcFileName: string = ''; + if (CmdOptions.isWatchMode()) { + abcFileName = parseWatch(files); + } main(files.concat(CmdOptions.getIncludedFiles()), parsed.options); + if (CmdOptions.isWatchMode() && !CmdOptions.isAssemblyMode()) { + process.on('exit', () => { + let base64data = fs.readFileSync(abcFileName); + let watchResStr = Buffer.from(base64data).toString('base64'); + console.log(watchResStr); + }); + } } catch (err) { if (err instanceof diag.DiagnosticError) { let diagnostic = diag.getDiagnostic(err.code); diff --git a/ts2panda/src/pandagen.ts b/ts2panda/src/pandagen.ts index eae6caebd1f64ba9ffa18c3a697368667cddf0aa..9a7e4d94797cb22261e94791f7b9e7969eb3f945 100644 --- a/ts2panda/src/pandagen.ts +++ b/ts2panda/src/pandagen.ts @@ -614,17 +614,42 @@ export class PandaGen { this.add(node, storeOwnByValue(obj, value, nameSetting)); } + loadByNameViaDebugger(node: ts.Node, string_id: string, boolVal: CacheList) { + this.loadObjProperty(node, getVregisterCache(this, CacheList.Global), "debuggerGetValue"); + let getValueReg = this.getTemp(); + this.storeAccumulator(node, getValueReg); + let variableReg = this.getTemp(); + this.loadAccumulatorString(node, string_id); + this.storeAccumulator(node, variableReg); + let trueValueReg = this.getTemp(); + this.moveVreg(node, trueValueReg, getVregisterCache(this, boolVal)); + this.call(node, [getValueReg, variableReg, trueValueReg], false); + this.freeTemps(getValueReg, variableReg, trueValueReg); + } + // eg. print tryLoadGlobalByName(node: ts.Node, string_id: string) { - this.add( - node, - tryLoadGlobalByName(string_id)); + CmdOptions.isWatchMode() ? this.loadByNameViaDebugger(node, string_id, CacheList.True) + : this.add(node, tryLoadGlobalByName(string_id)); + } + + storeByNameViaDebugger(node: ts.Node, string_id: string) { + let valueReg = this.getTemp(); + this.storeAccumulator(node, valueReg); + this.loadObjProperty(node, getVregisterCache(this, CacheList.Global), "debuggerSetValue"); + let setValueReg = this.getTemp(); + this.storeAccumulator(node, setValueReg); + let variableReg = this.getTemp(); + this.loadAccumulatorString(node, string_id); + this.storeAccumulator(node, variableReg); + this.call(node, [setValueReg, variableReg, valueReg], false); + this.freeTemps(valueReg, setValueReg, variableReg); } // eg. a = 1 tryStoreGlobalByName(node: ts.Node, string_id: string) { - this.add(node, - tryStoreGlobalByName(string_id)); + CmdOptions.isWatchMode() ? this.storeByNameViaDebugger(node, string_id) + : this.add(node, tryStoreGlobalByName(string_id)); } // eg. var n; n; @@ -1257,7 +1282,7 @@ export class PandaGen { node, stClassToGlobalRecord(string_id)); } - + loadAccumulatorBigInt(node: ts.Node | NodeKind, str: string) { this.add( node, diff --git a/ts2panda/tests/utils/base.ts b/ts2panda/tests/utils/base.ts index 4b40c342d26b0c93893d17b107bacca6d3121ecd..b682c86af7b294323eb0e66730618e2d54ac30ef 100644 --- a/ts2panda/tests/utils/base.ts +++ b/ts2panda/tests/utils/base.ts @@ -31,6 +31,7 @@ import { import { setGlobalStrict } from "../../src/strictMode"; import { creatAstFromSnippet } from "./asthelper"; import { LiteralBuffer } from "../../src/base/literal"; +import { CmdOptions } from "../../src/cmdOptions"; const compileOptions = { outDir: "../tmp/build", @@ -142,7 +143,8 @@ export function checkInstructions(actual: IRNode[], expected: IRNode[], checkFn? export function compileAllSnippet(snippet: string, passes?: Pass[], literalBufferArray?: Array): PandaGen[] { let sourceFile = creatAstFromSnippet(snippet); jshelpers.bindSourceFile(sourceFile, {}); - setGlobalStrict(jshelpers.isEffectiveStrictModeSourceFile(sourceFile, compileOptions)); + CmdOptions.isWatchMode() ? setGlobalStrict(true) + : setGlobalStrict(jshelpers.isEffectiveStrictModeSourceFile(sourceFile, compileOptions)); let compilerDriver = new CompilerDriver('UnitTest'); if (!passes) { @@ -188,7 +190,7 @@ export function compileAfterSnippet(snippet: string, name:string) { let compilerDriver = new CompilerDriver('UnitTest'); compilerDriver.setCustomPasses([]); compilerDriver.compileUnitTest(sourceFile, []); - compileUnits = compilerDriver.getCompilationUnits(); + compileUnits = compilerDriver.getCompilationUnits(); return sourceFile; } } diff --git a/ts2panda/tests/watch_expression/addWatch.test.ts b/ts2panda/tests/watch_expression/addWatch.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..77edbd03078639be9b17e9c18aecf4b3a1ac4355 --- /dev/null +++ b/ts2panda/tests/watch_expression/addWatch.test.ts @@ -0,0 +1,855 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + expect +} from 'chai'; +import 'mocha'; +import { CmdOptions } from '../../src/cmdOptions'; +import { + EcmaAdd2dyn, + EcmaAsyncfunctionawaituncaught, + EcmaAsyncfunctionenter, + EcmaAsyncfunctionreject, + EcmaAsyncfunctionresolve, + EcmaCallarg0dyn, + EcmaCallarg1dyn, + EcmaCallargs2dyn, + EcmaCreatearraywithbuffer, + EcmaCreateemptyarray, + EcmaCreategeneratorobj, + EcmaCreateiterresultobj, + EcmaCreateobjectwithbuffer, + EcmaCreateregexpwithliteral, + EcmaDecdyn, + EcmaDefineclasswithbuffer, + EcmaDefinefuncdyn, + EcmaEqdyn, + EcmaGetresumemode, + EcmaIstrue, + EcmaLdobjbyindex, + EcmaLdobjbyname, + EcmaNegdyn, + EcmaNewobjdynrange, + EcmaResumegenerator, + EcmaStownbyindex, + EcmaStricteqdyn, + EcmaSuspendgenerator, + EcmaThrowdyn, + EcmaTonumber, + EcmaTypeofdyn, + FldaiDyn, + Imm, + Jeqz, + Jmp, + Label, + LdaDyn, + LdaStr, + LdaiDyn, + MovDyn, + ReturnDyn, + StaDyn, + VReg +} from "../../src/irnodes"; +import { LocalVariable } from "../../src/variable"; +import { checkInstructions, compileMainSnippet, compileAllSnippet, SnippetCompiler } from "../utils/base"; + +describe("WatchExpressions", function () { + it("watch NumericLiteral", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + a=-123.212 + `); + + let expected = [ + new FldaiDyn(new Imm(123.212)), + new StaDyn(new VReg()), + new EcmaNegdyn(new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname('debuggerSetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch StringLiteral", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + y = 'He is called \'Johnny\'' + `); + + let expected = [ + new LdaStr('He is called '), + new StaDyn(new VReg()), + new EcmaLdobjbyname('debuggerSetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('y'), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('Johnny'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new LdaStr(''), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch RegularExpressionLiteral", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + a = /abc/ + `); + + let expected = [ + new EcmaCreateregexpwithliteral('abc', new Imm(0)), + new StaDyn(new VReg()), + new EcmaLdobjbyname('debuggerSetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch Identifier", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + _awef + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('_awef'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch TrueKeyword", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + b === true + `); + + let isTrueLabel = new Label(); + let isFalseLabel = new Label(); + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('b'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new LdaDyn(new VReg()), + new EcmaStricteqdyn(new VReg()), + new Jeqz(isTrueLabel), + new LdaDyn(new VReg()), + new Jmp(isFalseLabel), + isTrueLabel, + new LdaDyn(new VReg()), + isFalseLabel, + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch FalseKeyword", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + b === false + `); + + let ifFalseLabel = new Label(); //lable0 + let ifTrueLabel = new Label(); //label1 + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('b'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new LdaDyn(new VReg()), + new EcmaStricteqdyn(new VReg()), + new Jeqz(ifFalseLabel), + new LdaDyn(new VReg()), + new Jmp(ifTrueLabel), + ifFalseLabel, + new LdaDyn(new VReg()), //lda.dyn v10 + ifTrueLabel, + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch CallExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + BigInt(10.2) + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('BigInt'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new FldaiDyn(new Imm(10.2)), + new StaDyn(new VReg()), + new EcmaCallarg1dyn(new VReg(), new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch NullKeyword", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + b === null + `); + + let isTrueLabel = new Label(); + let isFalseLabel = new Label(); + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('b'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new LdaDyn(new VReg()), + new EcmaStricteqdyn(new VReg()), + new Jeqz(isTrueLabel), + new LdaDyn(new VReg()), + new Jmp(isFalseLabel), + isTrueLabel, + new LdaDyn(new VReg()), + isFalseLabel, + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch ThisKeyword", function () { + let snippetCompiler = new SnippetCompiler(); + snippetCompiler.compile("this"); + let globalScope = snippetCompiler.getGlobalScope(); + let insns = snippetCompiler.getGlobalInsns(); + let expected = [ + new LdaDyn(new VReg()), + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + let thisVar = globalScope!.findLocal("this"); + expect(thisVar instanceof LocalVariable).to.be.true; + }); + + it("watch MetaProperty", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let pandaGens = compileAllSnippet(` + function (){ + b = new.target; + } + `); + + let expected = [ + new LdaDyn(new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname("debuggerSetValue", new VReg()), + new StaDyn(new VReg()), + new LdaStr("b"), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + pandaGens.forEach((pg) => { + if (pg.internalName == "#1#") { + expect(checkInstructions(pg.getInsns(), expected)).to.be.true; + } + }); + }); + + it("watch ArrayLiteralExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + [1,2] + `); + + let expected = [ + new EcmaCreatearraywithbuffer(new Imm(1)), + new StaDyn(new VReg()), + new LdaDyn(new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch ObjectLiteralExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + a = {key:1,value:1} + `); + + let expected = [ + new EcmaCreateobjectwithbuffer(new Imm(1)), + new StaDyn(new VReg()), + new LdaDyn(new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname('debuggerSetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch PropertyAccessExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + a.b + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname('b', new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch ElementAccessExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + a[0] + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue',new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyindex(new VReg(), new Imm(0)), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch NewExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + new Function() + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('Function'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaNewobjdynrange(new Imm(2), [new VReg(), new VReg()]), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch ParenthesizedExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + (a,b,c) + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('b'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('c'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch FunctionExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let pandaGens = compileAllSnippet(` + a = function () {} + `); + + let expected = [ + new EcmaDefinefuncdyn('a', new Imm(0), new VReg()), + new StaDyn(new VReg), + new EcmaLdobjbyname('debuggerSetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + pandaGens.forEach((pg) => { + if (pg.internalName == "func_main_0") { + expect(checkInstructions(pg.getInsns(), expected)).to.be.true; + } + }); + }); + + it("watch DeleteExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + delete[abc] + `); + + let expected = [ + new EcmaCreateemptyarray(), + new StaDyn(new VReg()), + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('abc'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new EcmaStownbyindex(new VReg(), new Imm(0)), + new LdaDyn(new VReg()), + new LdaDyn(new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch TypeOfExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + typeof(a) + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new EcmaTypeofdyn(), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch VoidExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + void doSomething() + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('doSomething'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaCallarg0dyn(new VReg()), + new LdaDyn(new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch AwaitExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let pandaGens = compileAllSnippet( + `async function a(){ + await abc; + }` + ); + + let beginLabel = new Label(); + let endLabel = new Label(); + let nextLabel = new Label(); + + let expected = [ + new EcmaAsyncfunctionenter(), + new StaDyn(new VReg()), + beginLabel, + new EcmaLdobjbyname("debuggerGetValue", new VReg()), + new StaDyn(new VReg()), + new LdaStr('abc'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaAsyncfunctionawaituncaught(new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaSuspendgenerator(new VReg(), new VReg()), + new EcmaResumegenerator(new VReg()), + new StaDyn(new VReg()), + new EcmaGetresumemode(new VReg()), + new StaDyn(new VReg()), + new LdaiDyn(new Imm(1)), + new EcmaEqdyn(new VReg()), + new Jeqz(nextLabel), + new LdaDyn(new VReg()), + new EcmaThrowdyn(), + nextLabel, + new LdaDyn(new VReg()), + new EcmaAsyncfunctionresolve(new VReg(), new VReg(), new VReg()), + new ReturnDyn(), + endLabel, + new StaDyn(new VReg()), + new EcmaAsyncfunctionreject(new VReg(), new VReg(), new VReg()), + new ReturnDyn(), + ]; + + pandaGens.forEach((pg) => { + if (pg.internalName == "a") { + expect(checkInstructions(pg.getInsns(), expected)).to.be.true; + } + }); + }); + + it("watch PrefixUnaryExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + --a + `); + + let expected = [ + new EcmaLdobjbyname("debuggerGetValue", new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaDecdyn(new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname("debuggerSetValue", new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch PostfixUnaryExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + a-- + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaDecdyn(new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname('debuggerSetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new EcmaTonumber(new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch BinaryExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + a+b + `); + + let expected = [ + new EcmaLdobjbyname("debuggerGetValue", new VReg()), + new StaDyn(new VReg()), + new LdaStr("a"), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname("debuggerGetValue", new VReg()), + new StaDyn(new VReg()), + new LdaStr("b"), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new EcmaAdd2dyn(new VReg()), + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch ConditionalExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let insns = compileMainSnippet(` + a?4:2 + `); + + let ifTrueLabel = new Label(); + let ifFalseLabel = new Label(); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new EcmaIstrue(), + new Jeqz(ifTrueLabel), + new LdaiDyn(new Imm(4)), + new Jmp(ifFalseLabel), + ifTrueLabel, + new LdaiDyn(new Imm(2)), + ifFalseLabel, + + new ReturnDyn() + ]; + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it("watch YieldExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let pandaGens = compileAllSnippet(` + function* func(){ + yield a; + }`); + + let startLabel = new Label(); + let thenLabel = new Label(); + let nextLabel = new Label(); + let endLabel = new Label(); + + let expected = [ + new EcmaCreategeneratorobj(new VReg()), + new StaDyn(new VReg()), + new EcmaSuspendgenerator(new VReg(), new VReg()), + new EcmaResumegenerator(new VReg()), + new StaDyn(new VReg()), + new EcmaGetresumemode(new VReg()), + new StaDyn(new VReg()), + new LdaiDyn(new Imm(0)), + new EcmaEqdyn(new VReg()), + new Jeqz(startLabel), + new LdaDyn(new VReg()), + new ReturnDyn(), + startLabel, + new LdaiDyn(new Imm(1)), + new EcmaEqdyn(new VReg()), + new Jeqz(thenLabel), + new LdaDyn(new VReg()), + new EcmaThrowdyn(), + thenLabel, + new LdaDyn(new VReg()), + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('a'), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + new StaDyn(new VReg()), + new EcmaCreateiterresultobj(new VReg(),new VReg()), + new StaDyn(new VReg()), + new EcmaSuspendgenerator(new VReg(), new VReg()), + new EcmaResumegenerator(new VReg()), + new StaDyn(new VReg()), + new EcmaGetresumemode(new VReg()), + new StaDyn(new VReg()), + new LdaiDyn(new Imm(0)), + new EcmaEqdyn(new VReg()), + new Jeqz(nextLabel), + new LdaDyn(new VReg()), + new ReturnDyn(), + nextLabel, + new LdaiDyn(new Imm(1)), + new EcmaEqdyn(new VReg()), + new Jeqz(endLabel), + new LdaDyn(new VReg()), + new EcmaThrowdyn(), + endLabel, + new LdaDyn(new VReg()), + + new ReturnDyn() + ]; + + pandaGens.forEach((pg) => { + if (pg.internalName == "func") { + expect(checkInstructions(pg.getInsns(), expected)).to.be.true; + } + }); + }); + + it("watch ArrowFunction", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let pandaGens = compileAllSnippet(` + a => b.length + `); + + let expected = [ + new EcmaLdobjbyname('debuggerGetValue', new VReg()), + new StaDyn(new VReg()), + new LdaStr('b'), + new StaDyn(new VReg()), + new MovDyn(new VReg(),new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(),new VReg()), + new StaDyn(new VReg()), + new EcmaLdobjbyname('length', new VReg()), + new StaDyn(new VReg()), + new LdaDyn(new VReg()), + + new ReturnDyn() + ]; + + pandaGens.forEach((pg) => { + if (pg.internalName == "#1#") { + expect(checkInstructions(pg.getInsns(), expected)).to.be.true; + } + }); + }); + + it("watch ClassExpression", function () { + CmdOptions.parseUserCmd([""]); + CmdOptions.setWatchArgs(['','']); + let pandaGens = compileAllSnippet(` + a = new class{}; + `); + + let expected = [ + new MovDyn(new VReg(), new VReg()), + new EcmaDefineclasswithbuffer("#1#", new Imm(1), new Imm(0), new VReg(), new VReg()), + new StaDyn(new VReg()), + new LdaDyn(new VReg()), + new StaDyn(new VReg()), + new MovDyn(new VReg(), new VReg()), + new EcmaNewobjdynrange(new Imm(2), [new VReg(), new VReg()]), + new StaDyn(new VReg()), + new EcmaLdobjbyname("debuggerSetValue", new VReg()), + new StaDyn(new VReg()), + new LdaStr("a"), + new StaDyn(new VReg()), + new EcmaCallargs2dyn(new VReg(), new VReg(), new VReg()), + + new ReturnDyn() + ]; + pandaGens.forEach((pg) => { + if (pg.internalName == "func_main_0") { + expect(checkInstructions(pg.getInsns(), expected)).to.be.true; + } + }); + }); +});