diff --git a/es2panda/compiler/base/destructuring.cpp b/es2panda/compiler/base/destructuring.cpp index 24af709a12260bfcd9baccc121e49c44c0a381e8..651292aa8a87ec120cfa5a375dee893e9c8cdbfd 100644 --- a/es2panda/compiler/base/destructuring.cpp +++ b/es2panda/compiler/base/destructuring.cpp @@ -151,7 +151,6 @@ static void GenObjectProperty(PandaGen *pg, const ir::ObjectExpression *object, const ir::Expression *element, VReg value) { RegScope propScope(pg); - VReg loadedValue = pg->AllocReg(); const ir::Property *propExpr = element->AsProperty(); @@ -166,20 +165,19 @@ static void GenObjectProperty(PandaGen *pg, const ir::ObjectExpression *object, target = assignment->Left(); } - // compile key + LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration()); + + // load obj property from rhs, return undefined if no corresponding property exists if (key->IsIdentifier()) { - pg->LoadAccumulatorString(key, key->AsIdentifier()->Name()); + pg->LoadObjByName(element, value, key->AsIdentifier()->Name()); } else { key->Compile(pg); + pg->LoadObjByValue(element, value); } - LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration()); - - // load obj property from rhs, return undefined if no corresponding property exists - pg->LoadObjByValue(element, value); - pg->StoreAccumulator(element, loadedValue); - if (init != nullptr) { + VReg loadedValue = pg->AllocReg(); + pg->StoreAccumulator(element, loadedValue); auto *getDefault = pg->AllocLabel(); auto *store = pg->AllocLabel(); @@ -213,6 +211,15 @@ static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, break; } + VReg propName = pg->AllocReg(); + const ir::Expression *key = element->AsProperty()->Key(); + if (key->IsIdentifier()) { + pg->LoadAccumulatorString(key, key->AsIdentifier()->Name()); + } else { + key->Compile(pg); + } + pg->StoreAccumulator(element, propName); + GenObjectProperty(pg, object, element, rhs); } } diff --git a/es2panda/test/compiler/js/language/destructuring/test-obj-destructuring-with-rest-element-expected.txt b/es2panda/test/compiler/js/language/destructuring/test-obj-destructuring-with-rest-element-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..f477b163f3f74ae21df232579ec583f713192c0b --- /dev/null +++ b/es2panda/test/compiler/js/language/destructuring/test-obj-destructuring-with-rest-element-expected.txt @@ -0,0 +1,6 @@ +key: _xxx +value: cccc +key: _yyy +value: dddd +key: _zzz +value: eeee diff --git a/es2panda/test/compiler/js/language/destructuring/test-obj-destructuring-with-rest-element.js b/es2panda/test/compiler/js/language/destructuring/test-obj-destructuring-with-rest-element.js new file mode 100644 index 0000000000000000000000000000000000000000..1df5ac71be2ab8fbb6d89a3994286583b5397546 --- /dev/null +++ b/es2panda/test/compiler/js/language/destructuring/test-obj-destructuring-with-rest-element.js @@ -0,0 +1,17 @@ +function foo() { + let obj = { + _times: "aaaa", + _values: "bbbb", + _xxx: "cccc", + _yyy: "dddd", + _zzz: "eeee" + } + + const {_times: times, _values: values, ...others} = obj; + + for (let prop in others) { + print("key: ", prop); + print("value: ", others[prop]) + } +} +foo() \ No newline at end of file diff --git a/ts2panda/src/compilerUtils.ts b/ts2panda/src/compilerUtils.ts index 79979cf0e04016401c0dac217158f55fbc68e78d..1d406d114bdd00c1d5406f382975d09e1a2cd9ff 100644 --- a/ts2panda/src/compilerUtils.ts +++ b/ts2panda/src/compilerUtils.ts @@ -276,12 +276,14 @@ function compileObjectDestructuring(obj: ts.ObjectBindingOrAssignmentPattern, pa } // create before to store the properties - let properties: Array = new Array(); - let excludedProp: Array = new Array(); + let propertiesReg: Array = new Array(); + let properties: Array = new Array(); + let excludedProp: Array = new Array(); for (let i = 0; i < elementsLength; i++) { let tmp = pandaGen.getTemp(); properties.push(tmp); + propertiesReg.push(tmp); } for (let i = 0; i < elementsLength; i++) { @@ -294,8 +296,6 @@ function compileObjectDestructuring(obj: ts.ObjectBindingOrAssignmentPattern, pa break; } - excludedProp.push(properties[i]); - let loadedValue: VReg = pandaGen.getTemp(); let key: ts.Expression | ts.ComputedPropertyName; let target: ts.Node = element; @@ -342,29 +342,28 @@ function compileObjectDestructuring(obj: ts.ObjectBindingOrAssignmentPattern, pa } // compile key - if (ts.isComputedPropertyName(key)) { - compiler.compileExpression(key.expression); + if (ts.isIdentifier(key)) { + let keyName: string = jshelpers.getTextOfIdentifierOrLiteral(key); + properties[i] = keyName; } else { - if (ts.isIdentifier(key)) { - let keyName = jshelpers.getTextOfIdentifierOrLiteral(key); - pandaGen.loadAccumulatorString(key, keyName); - } else { - compiler.compileExpression(key); - } + ts.isComputedPropertyName(key) ? compiler.compileExpression(key.expression) : + compiler.compileExpression(key); + pandaGen.storeAccumulator(key, properties[i]); } - pandaGen.storeAccumulator(key, properties[i]); + + excludedProp.push(properties[i]); // create left reference let lRef = LReference.generateLReference(compiler, target, isDeclaration); // load obj property from rhs, return undefined if no corresponding property exists pandaGen.loadObjProperty(element, value, properties[i]); - pandaGen.storeAccumulator(element, loadedValue); let getDefaultLabel = new Label(); let storeLabel = new Label(); if (hasInit) { + pandaGen.storeAccumulator(element, loadedValue); pandaGen.condition( element, ts.SyntaxKind.ExclamationEqualsEqualsToken, @@ -387,27 +386,37 @@ function compileObjectDestructuring(obj: ts.ObjectBindingOrAssignmentPattern, pa pandaGen.freeTemps(loadedValue); } - pandaGen.freeTemps(value, ...properties); + pandaGen.freeTemps(value, ...propertiesReg); } -function emitRestProperty(restProperty: ts.BindingElement | ts.SpreadAssignment, excludedProp: Array, +function emitRestProperty(restProperty: ts.BindingElement | ts.SpreadAssignment, excludedProp: Array, obj: VReg, pandaGen: PandaGen, compiler: Compiler) { let isDeclaration = ts.isBindingElement(restProperty) ? true : false; let target = isDeclaration ? (restProperty).name : (restProperty).expression; let lRef = LReference.generateLReference(compiler, target, true); - let undefinedReg = pandaGen.getTemp(); if (excludedProp.length == 0) { - pandaGen.loadAccumulator(restProperty, getVregisterCache(pandaGen, CacheList.undefined)); - pandaGen.storeAccumulator(restProperty, undefinedReg); - excludedProp.push(undefinedReg); + excludedProp = [getVregisterCache(pandaGen, CacheList.undefined)]; } // Create a Object with the information of excluded properties - pandaGen.createObjectWithExcludedKeys(restProperty, obj, excludedProp); + let namedPropRegs: Array = new Array(); + for (let i = 0; i < excludedProp.length; i++) { + let prop: VReg | string = excludedProp[i]; + if (prop instanceof VReg) { + continue; + } + + let propReg: VReg = pandaGen.getTemp(); + namedPropRegs.push(propReg); + pandaGen.loadAccumulatorString(restProperty, prop); + pandaGen.storeAccumulator(restProperty, propReg); + excludedProp[i] = propReg; + } + pandaGen.createObjectWithExcludedKeys(restProperty, obj, >excludedProp); lRef.setValue(); - pandaGen.freeTemps(undefinedReg); + pandaGen.freeTemps(...namedPropRegs); } function isRestElement(node: ts.BindingElement) { diff --git a/ts2panda/tests/expression/bindingPattern.test.ts b/ts2panda/tests/expression/bindingPattern.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4127dcd0ee04f248c24ac495b74e6bcbae2e3122 --- /dev/null +++ b/ts2panda/tests/expression/bindingPattern.test.ts @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 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 { + Createobjectwithexcludedkeys, + Ldobjbyname, + Returnundefined, + Imm, + Lda, + LdaStr, + Sta, + VReg, + IRNode +} from "../../src/irnodes"; +import { checkInstructions, SnippetCompiler } from "../utils/base"; +import { creatAstFromSnippet } from "../utils/asthelper"; +import { PandaGen } from '../../src/pandagen'; + +describe("object bindingPattern", function () { + it('object bindingPattern intialization', function () { + let snippetCompiler = new SnippetCompiler(); + snippetCompiler.compile(`function foo() {const {_times: times, _values: values} = this;}`); + IRNode.pg = new PandaGen( + "foo", + creatAstFromSnippet(`function foo() {const {_times: times, _values: values} = this;}`), 0, undefined); + let thisArg = new VReg(); + let temp = new VReg(); + let obj = new VReg(); + let times = new VReg(); + let values = new VReg(); + let expected = [ + new Lda(thisArg), + new Sta(temp), + new Sta(obj), + new Lda(obj), + new Ldobjbyname(new Imm(0), "_times"), + new Sta(times), + new Lda(obj), + new Ldobjbyname(new Imm(2), "_values"), + new Sta(values), + new Lda(temp), + new Returnundefined() + ]; + let functionPg = snippetCompiler.getPandaGenByName("UnitTest.foo"); + let insns = functionPg!.getInsns(); + + expect(checkInstructions(insns, expected)).to.be.true; + }); + + it('object bindingPattern has restElement', function () { + let snippetCompiler = new SnippetCompiler(); + snippetCompiler.compile(`function foo() {const {_times: times, ...values} = this;}`); + IRNode.pg = new PandaGen( + "foo", + creatAstFromSnippet(`function foo() {const {_times: times, ...values} = this;}`), 0, undefined); + let thisArg = new VReg(); + let temp = new VReg(); + let obj = new VReg(); + let times = new VReg(); + let values = new VReg(); + let arg = new VReg(); + let expected = [ + new Lda(thisArg), + new Sta(temp), + new Sta(obj), + new Lda(obj), + new Ldobjbyname(new Imm(0), "_times"), + new Sta(times), + new LdaStr("_times"), + new Sta(arg), + new Createobjectwithexcludedkeys(new Imm(0), obj, [arg]), + new Sta(values), + new Lda(temp), + new Returnundefined() + ]; + let functionPg = snippetCompiler.getPandaGenByName("UnitTest.foo"); + let insns = functionPg!.getInsns(); + + expect(checkInstructions(insns, expected)).to.be.true; + }); +});