diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index 36f298a5c956b33adb488c35aa260f28d51c15e7..87f42dd5763b3c7e20722065504b739510d0780d 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -29,6 +29,7 @@ #include "ir/expressions/assignmentExpression.h" #include "ir/expressions/identifier.h" #include "ir/expressions/objectExpression.h" +#include "ir/expressions/literals/numberLiteral.h" #include "ir/module/exportNamedDeclaration.h" #include "ir/module/exportSpecifier.h" #include "ir/statements/blockStatement.h" @@ -312,6 +313,10 @@ void Binder::LookupIdentReference(ir::Identifier *ident) !res.variable->HasFlag(VariableFlags::INITIALIZED)) { ident->SetTdz(); } + // in release mode, replace const reference with its initialization + if (!this->Program()->IsDebug() && decl->IsConstDecl()) { + ReplaceConstReferenceWithInitialization(ident, decl); + } ident->SetVariable(res.variable); } @@ -935,4 +940,44 @@ std::vector Binder::FindIdentifierTSVariables(const ir::Identifier * return findRes; } +void Binder::ReplaceConstReferenceWithInitialization(const ir::Identifier *ident, const Decl *decl) +{ + bool isValidAssignmentExpr = ident->Parent()->IsAssignmentExpression() && + ident->Parent()->AsAssignmentExpression()->Right() == ident; + bool isBinaryExpr = ident->Parent()->IsBinaryExpression(); + bool isVariableDecl = ident->Parent()->IsVariableDeclarator() && + ident->Parent()->AsVariableDeclarator()->Init() == ident; + if (!isValidAssignmentExpr && !isBinaryExpr && !isVariableDecl) { + return; + } + + if (decl->Node() == nullptr || decl->Node()->Parent() == nullptr || + !decl->Node()->Parent()->IsVariableDeclarator()) { + return; + } + + const ir::AstNode *initialization = static_cast( + decl->Node()->Parent()->AsVariableDeclarator()->Init()); + if (initialization == nullptr || !initialization->IsNumberLiteral()) { + return; + } + + auto newNode = Allocator()->New(initialization->AsNumberLiteral()->Number()); + if (newNode == nullptr) { + throw Error(ErrorType::GENERIC, "Unsuccessful allocation during replacing const reference node"); + } + // Make sure the new node get the correct line number + // Column number may be incorrect, but it doesn't matter in release mode + newNode->SetRange(ident->Range()); + + auto *parentNode = const_cast(ident->Parent()); + // update the reference node with initialization node + parentNode->UpdateSelf([=](auto *childNode) { + if (childNode == ident) { + return static_cast(newNode); + } + return childNode; + }, this); +} + } // namespace panda::es2panda::binder diff --git a/es2panda/binder/binder.h b/es2panda/binder/binder.h index 8b383a6e18a495bacc7ea8a3750938bcc3c12608..1f51a5ed9eb334293b93800f12abfe9b3a7c574a 100644 --- a/es2panda/binder/binder.h +++ b/es2panda/binder/binder.h @@ -212,6 +212,7 @@ private: void ResolveReferences(const ir::AstNode *parent); void ValidateExportDecl(const ir::ExportNamedDeclaration *exportDecl); void StoreAndCheckSpecialFunctionName(std::string &internalNameStr, std::string recordName); + void ReplaceConstReferenceWithInitialization(const ir::Identifier *ident, const Decl *decl); // TypeScript specific functions void BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode); diff --git a/es2panda/es2panda.cpp b/es2panda/es2panda.cpp index 13bde8798416ab7b8bf121cdf0a798289df6e496..18d8b16d62ef3553ec6d693cd2083b4546227d2a 100644 --- a/es2panda/es2panda.cpp +++ b/es2panda/es2panda.cpp @@ -74,6 +74,7 @@ panda::pandasm::Program *Compiler::Compile(const SourceFile &input, const Compil } try { + parser_->SetDebug(options.isDebug); auto ast = parser_->Parse(fname, src, rname, kind); ast.Binder()->SetProgram(&ast); diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index dce95144f822681725d7c5ae65b909bd06b7a26c..45e49d7ab2930381a502b5035cb7972e36d2d8e7 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -190,6 +190,10 @@ public: return program_.Allocator(); } bool IsDtsFile() const; + void SetDebug(bool isDebug) + { + program_.SetDebug(isDebug); + } private: bool IsStartOfMappedType() const; diff --git a/es2panda/parser/program/program.h b/es2panda/parser/program/program.h index f1f8602239a380331367c5423be75f0590009745..a7e896776c31837c4bea6b2ba17f94b375ee9798 100644 --- a/es2panda/parser/program/program.h +++ b/es2panda/parser/program/program.h @@ -154,6 +154,16 @@ public: { return isDtsFile_; } + + bool IsDebug() const + { + return isDebug_; + } + + void SetDebug(bool isDebug) + { + isDebug_ = isDebug; + } std::string Dump() const; void SetKind(ScriptKind kind); @@ -173,6 +183,7 @@ private: SourceTextModuleRecord *typeModuleRecord_ {nullptr}; util::PatchFix *patchFixHelper_ {nullptr}; bool isDtsFile_ {false}; + bool isDebug_ {false}; }; } // namespace panda::es2panda::parser diff --git a/es2panda/test/parser/js/test-const-replacement-expected.txt b/es2panda/test/parser/js/test-const-replacement-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..8097db68f3677ef19456ee69e46b6bea40dc6b50 --- /dev/null +++ b/es2panda/test/parser/js/test-const-replacement-expected.txt @@ -0,0 +1,795 @@ +{ + "type": "Program", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 17, + "column": 12 + } + } + } + ], + "kind": "const", + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 13 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "b", + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 6 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 10 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 11 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "c", + "loc": { + "start": { + "line": 20, + "column": 7 + }, + "end": { + "line": 20, + "column": 8 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 7 + }, + "end": { + "line": 20, + "column": 12 + } + } + } + ], + "kind": "const", + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + { + "type": "FunctionDeclaration", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "A", + "loc": { + "start": { + "line": 21, + "column": 10 + }, + "end": { + "line": 21, + "column": 11 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "b", + "loc": { + "start": { + "line": 22, + "column": 3 + }, + "end": { + "line": 22, + "column": 4 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 22, + "column": 7 + }, + "end": { + "line": 22, + "column": 8 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 3 + }, + "end": { + "line": 22, + "column": 8 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 3 + }, + "end": { + "line": 22, + "column": 9 + } + } + } + ], + "loc": { + "start": { + "line": 21, + "column": 14 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 1 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 1 + }, + "end": { + "line": 23, + "column": 2 + } + } + }, + { + "type": "FunctionDeclaration", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "B", + "loc": { + "start": { + "line": 25, + "column": 10 + }, + "end": { + "line": 25, + "column": 11 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "d", + "loc": { + "start": { + "line": 26, + "column": 9 + }, + "end": { + "line": 26, + "column": 10 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 26, + "column": 13 + }, + "end": { + "line": 26, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 26, + "column": 9 + }, + "end": { + "line": 26, + "column": 14 + } + } + } + ], + "kind": "const", + "loc": { + "start": { + "line": 26, + "column": 3 + }, + "end": { + "line": 26, + "column": 15 + } + } + }, + { + "type": "ForUpdateStatement", + "init": { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "e", + "loc": { + "start": { + "line": 27, + "column": 12 + }, + "end": { + "line": 27, + "column": 13 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 27, + "column": 16 + }, + "end": { + "line": 27, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 12 + }, + "end": { + "line": 27, + "column": 17 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 27, + "column": 8 + }, + "end": { + "line": 27, + "column": 17 + } + } + }, + "test": { + "type": "BinaryExpression", + "operator": "<", + "left": { + "type": "Identifier", + "name": "e", + "loc": { + "start": { + "line": 27, + "column": 19 + }, + "end": { + "line": 27, + "column": 20 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 27, + "column": 23 + }, + "end": { + "line": 27, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 19 + }, + "end": { + "line": 27, + "column": 24 + } + } + }, + "update": { + "type": "UpdateExpression", + "operator": "++", + "prefix": false, + "argument": { + "type": "Identifier", + "name": "e", + "loc": { + "start": { + "line": 27, + "column": 26 + }, + "end": { + "line": 27, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 26 + }, + "end": { + "line": 27, + "column": 29 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "e", + "loc": { + "start": { + "line": 28, + "column": 5 + }, + "end": { + "line": 28, + "column": 6 + } + } + }, + "right": { + "type": "BinaryExpression", + "operator": "+", + "left": { + "type": "Identifier", + "name": "e", + "loc": { + "start": { + "line": 28, + "column": 9 + }, + "end": { + "line": 28, + "column": 10 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 28, + "column": 13 + }, + "end": { + "line": 28, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 9 + }, + "end": { + "line": 28, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 5 + }, + "end": { + "line": 28, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 5 + }, + "end": { + "line": 28, + "column": 15 + } + } + } + ], + "loc": { + "start": { + "line": 27, + "column": 31 + }, + "end": { + "line": 29, + "column": 4 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 3 + }, + "end": { + "line": 29, + "column": 4 + } + } + } + ], + "loc": { + "start": { + "line": 25, + "column": 14 + }, + "end": { + "line": 30, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 1 + }, + "end": { + "line": 30, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 1 + }, + "end": { + "line": 30, + "column": 2 + } + } + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 32, + "column": 1 + }, + "end": { + "line": 32, + "column": 2 + } + } + }, + "right": { + "type": "NumberLiteral", + "value": 2, + "loc": { + "start": { + "line": 32, + "column": 5 + }, + "end": { + "line": 32, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 32, + "column": 1 + }, + "end": { + "line": 32, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 32, + "column": 1 + }, + "end": { + "line": 32, + "column": 7 + } + } + }, + { + "type": "IfStatement", + "test": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 34, + "column": 5 + }, + "end": { + "line": 34, + "column": 6 + } + } + }, + "consequent": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "UpdateExpression", + "operator": "++", + "prefix": false, + "argument": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 35, + "column": 3 + }, + "end": { + "line": 35, + "column": 4 + } + } + }, + "loc": { + "start": { + "line": 35, + "column": 3 + }, + "end": { + "line": 35, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 35, + "column": 3 + }, + "end": { + "line": 35, + "column": 7 + } + } + } + ], + "loc": { + "start": { + "line": 34, + "column": 8 + }, + "end": { + "line": 36, + "column": 2 + } + } + }, + "alternate": null, + "loc": { + "start": { + "line": 34, + "column": 1 + }, + "end": { + "line": 36, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 36, + "column": 2 + } + } +} diff --git a/es2panda/test/parser/js/test-const-replacement.js b/es2panda/test/parser/js/test-const-replacement.js new file mode 100644 index 0000000000000000000000000000000000000000..ba0dff1677e942bdbfe22c22a473991205a57250 --- /dev/null +++ b/es2panda/test/parser/js/test-const-replacement.js @@ -0,0 +1,36 @@ +/* + * 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. + */ + + +const a = 1; +let b = a; + +const c = 1; +function A() { + b = c; +} + +function B() { + const d = 1; + for (let e = 1; e < d; e++) { + e = e + a; + } +} + +a = 2; + +if (a) { + a++; +} \ No newline at end of file