diff --git a/es2panda/parser/expressionParser.cpp b/es2panda/parser/expressionParser.cpp index 1e9377ffdcb0deeac767b4d3a03f326afabd28d6..058a7fb5ab6e90219250286336f597aef5cfec27 100644 --- a/es2panda/parser/expressionParser.cpp +++ b/es2panda/parser/expressionParser.cpp @@ -71,6 +71,7 @@ #include #include #include +#include #include @@ -1255,7 +1256,9 @@ ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left) lexer_->NextToken(); + parseExpressionRecursionCount_++; ir::Expression *rightExprNode = ParseExpression(ExpressionParseFlags::DISALLOW_YIELD); + parseExpressionRecursionCount_--; ir::Expression *rightExpr = rightExprNode; ir::ConditionalExpression *conditionalExpr = nullptr; @@ -1309,6 +1312,10 @@ ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left) rightExpr->SetRange({left->Start(), endPos}); } + if (parseExpressionRecursionCount_ == 0) { + rightExpr = TraverseBinaryExpression(rightExpr); + } + if (conditionalExpr != nullptr) { conditionalExpr->SetStart(rightExpr->Start()); conditionalExpr->SetTest(rightExpr); @@ -1318,6 +1325,92 @@ ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left) return rightExpr; } +ir::Expression *ParserImpl::TraverseBinaryExpression(ir::Expression *expr) +{ + if (!expr->IsBinaryExpression()) { + return expr; + } + + ir::Expression *lhsExpression = expr->AsBinaryExpression()->Left(); + ir::Expression *rhsExpression = expr->AsBinaryExpression()->Right(); + lexer::TokenType operatorType = expr->AsBinaryExpression()->OperatorType(); + // update lhsExpression and rhsExpression + lhsExpression = TraverseBinaryExpression(lhsExpression); + rhsExpression = TraverseBinaryExpression(rhsExpression); + ir::Expression *numberNode = ShortcutNumberLiteralBinaryExpression(lhsExpression, rhsExpression, operatorType); + + return (numberNode == nullptr) ? expr : numberNode; +} + +ir::Expression *ParserImpl::ShortcutNumberLiteralBinaryExpression(ir::Expression *lhsExpression, + ir::Expression *rhsExpression, + lexer::TokenType operatorType) +{ + if (!lhsExpression->IsNumberLiteral() || !rhsExpression->IsNumberLiteral()) { + return nullptr; + } + + double left = lhsExpression->AsNumberLiteral()->Number(); + double right = rhsExpression->AsNumberLiteral()->Number(); + ir::Expression *numberNode = nullptr; + + switch (operatorType) { + case lexer::TokenType::PUNCTUATOR_PLUS: { + numberNode = AllocNode(left + right); + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS: { + numberNode = AllocNode(left - right); + break; + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: { + numberNode = AllocNode(left * right); + break; + } + case lexer::TokenType::PUNCTUATOR_DIVIDE: { + numberNode = AllocNode(util::Helpers::Divide(left, right)); + break; + } + case lexer::TokenType::PUNCTUATOR_MOD: { + numberNode = AllocNode(std::fmod(left, right)); + break; + } + case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: { + numberNode = AllocNode(std::pow(left, right)); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { + numberNode = AllocNode(util::Helpers::ToUint32(left) | util::Helpers::ToUint32(right)); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { + numberNode = AllocNode(util::Helpers::ToUint32(left) & util::Helpers::ToUint32(right)); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { + numberNode = AllocNode(util::Helpers::ToUint32(left) ^ util::Helpers::ToUint32(right)); + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: { + numberNode = AllocNode(util::Helpers::ToInt32(left) << util::Helpers::ToUint32(right)); + break; + } + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: { + numberNode = AllocNode(util::Helpers::ToInt32(left) >> util::Helpers::ToUint32(right)); + break; + } + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: { + numberNode = AllocNode(util::Helpers::ToUint32(left) >> util::Helpers::ToUint32(right)); + break; + } + default: + return nullptr; + } + + numberNode->SetRange({lhsExpression->Start(), rhsExpression->End()}); + return numberNode; +} + ir::CallExpression *ParserImpl::ParseCallExpression(ir::Expression *callee, bool isOptionalChain, bool isAsync) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index af7cd5a23e8c534498a4e17f512efe718bf2fc13..037a78a217c7af37304ca61bd56a37ccdc44e8b7 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -197,6 +197,7 @@ public: } private: + uint32_t parseExpressionRecursionCount_ {0}; bool IsStartOfMappedType() const; bool IsStartOfTsTypePredicate() const; bool IsStartOfAbstractConstructorType() const; @@ -383,6 +384,9 @@ private: ir::Expression *ParseCoverParenthesizedExpressionAndArrowParameterList(); ir::Expression *ParseKeywordExpression(); ir::Expression *ParseBinaryExpression(ir::Expression *left); + ir::Expression *TraverseBinaryExpression(ir::Expression *expr); + ir::Expression *ShortcutNumberLiteralBinaryExpression(ir::Expression *lhsExpression, ir::Expression *rhsExpression, + lexer::TokenType operatorType); ir::CallExpression *ParseCallExpression(ir::Expression *callee, bool isOptionalChain = false, bool isAsync = false); ir::ArrowFunctionExpression *ParsePotentialArrowExpression(ir::Expression **returnExpression, const lexer::SourcePosition &startLoc, diff --git a/es2panda/test/parser/js/language/expressions/binary-expressions/test-simplify-numerical-calculation-expected.txt b/es2panda/test/parser/js/language/expressions/binary-expressions/test-simplify-numerical-calculation-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..af273ae8fac9d193dc8233d58e67713d4f1da490 --- /dev/null +++ b/es2panda/test/parser/js/language/expressions/binary-expressions/test-simplify-numerical-calculation-expected.txt @@ -0,0 +1,699 @@ +{ + "type": "Program", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continueAdd", + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 16 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 6, + "loc": { + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 16, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 28 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 29 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continueMinus", + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": -4, + "loc": { + "start": { + "line": 17, + "column": 21 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 30 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 31 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continueMultiply", + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 21 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 6, + "loc": { + "start": { + "line": 18, + "column": 24 + }, + "end": { + "line": 18, + "column": 33 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 33 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 34 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continueDivide", + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 19, + "column": 19 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 0.166667, + "loc": { + "start": { + "line": 19, + "column": 22 + }, + "end": { + "line": 19, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 19, + "column": 31 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 19, + "column": 32 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continuePow", + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 16 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 64, + "loc": { + "start": { + "line": 20, + "column": 19 + }, + "end": { + "line": 20, + "column": 32 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 32 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 20, + "column": 33 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continueOr", + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 21, + "column": 15 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 21, + "column": 27 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 21, + "column": 1 + }, + "end": { + "line": 21, + "column": 28 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continueAnd", + "loc": { + "start": { + "line": 22, + "column": 5 + }, + "end": { + "line": 22, + "column": 16 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 0, + "loc": { + "start": { + "line": 22, + "column": 19 + }, + "end": { + "line": 22, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 5 + }, + "end": { + "line": 22, + "column": 28 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 22, + "column": 29 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continueXor", + "loc": { + "start": { + "line": 23, + "column": 5 + }, + "end": { + "line": 23, + "column": 16 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 23, + "column": 19 + }, + "end": { + "line": 23, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 5 + }, + "end": { + "line": 23, + "column": 28 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 23, + "column": 29 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continuePositiveLeftShift", + "loc": { + "start": { + "line": 24, + "column": 5 + }, + "end": { + "line": 24, + "column": 30 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 40, + "loc": { + "start": { + "line": 24, + "column": 33 + }, + "end": { + "line": 24, + "column": 45 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 5 + }, + "end": { + "line": 24, + "column": 45 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 24, + "column": 1 + }, + "end": { + "line": 24, + "column": 46 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continuePositiveRightShift", + "loc": { + "start": { + "line": 25, + "column": 5 + }, + "end": { + "line": 25, + "column": 31 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 2, + "loc": { + "start": { + "line": 25, + "column": 34 + }, + "end": { + "line": 25, + "column": 46 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 5 + }, + "end": { + "line": 25, + "column": 46 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 25, + "column": 1 + }, + "end": { + "line": 25, + "column": 47 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "continueUnsignedRightShift", + "loc": { + "start": { + "line": 26, + "column": 5 + }, + "end": { + "line": 26, + "column": 31 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 2, + "loc": { + "start": { + "line": 26, + "column": 34 + }, + "end": { + "line": 26, + "column": 48 + } + } + }, + "loc": { + "start": { + "line": 26, + "column": 5 + }, + "end": { + "line": 26, + "column": 48 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 26, + "column": 1 + }, + "end": { + "line": 26, + "column": 49 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "diffPriority", + "loc": { + "start": { + "line": 27, + "column": 5 + }, + "end": { + "line": 27, + "column": 17 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 4, + "loc": { + "start": { + "line": 27, + "column": 20 + }, + "end": { + "line": 27, + "column": 69 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 5 + }, + "end": { + "line": 27, + "column": 69 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 27, + "column": 1 + }, + "end": { + "line": 27, + "column": 70 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 28, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/js/language/expressions/binary-expressions/test-simplify-numerical-calculation.js b/es2panda/test/parser/js/language/expressions/binary-expressions/test-simplify-numerical-calculation.js new file mode 100644 index 0000000000000000000000000000000000000000..ed3e14e45a7de8c455eb430ca9031109b5a5c974 --- /dev/null +++ b/es2panda/test/parser/js/language/expressions/binary-expressions/test-simplify-numerical-calculation.js @@ -0,0 +1,27 @@ +/* + * 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. + */ + +let continueAdd = 1 + 2 + 3; +let continueMinus = 1 - 2 - 3; +let continueMultiply = 1 * 2 * 3; +let continueDivide = 1 / 2 / 3; +let continuePow = (2 ** 3) ** 2; +let continueOr = 1 | 0 | 0; +let continueAnd = 1 & 0 & 0; +let continueXor = 1 ^ 0 ^ 0; +let continuePositiveLeftShift = 10 << 1 << 1; +let continuePositiveRightShift = 10 >> 1 >> 1; +let continueUnsignedRightShift = 10 >>> 1 >>> 1; +let diffPriority = 1 + 2 * 3 / 2 - (1 | 0) & 1 ^ 0 + (10 << 1) >>> 2; diff --git a/es2panda/test/parser/ts/test-enum-declaration-expected.txt b/es2panda/test/parser/ts/test-enum-declaration-expected.txt index d0d013bd7e63e34b2a4e80308745b3243a6bff62..6e2f7a95ac41c12701de3407a17932f246fffd2c 100644 --- a/es2panda/test/parser/ts/test-enum-declaration-expected.txt +++ b/es2panda/test/parser/ts/test-enum-declaration-expected.txt @@ -62,36 +62,8 @@ } }, "initializer": { - "type": "BinaryExpression", - "operator": "<<", - "left": { - "type": "NumberLiteral", - "value": 5, - "loc": { - "start": { - "line": 19, - "column": 9 - }, - "end": { - "line": 19, - "column": 10 - } - } - }, - "right": { - "type": "NumberLiteral", - "value": 4, - "loc": { - "start": { - "line": 19, - "column": 14 - }, - "end": { - "line": 19, - "column": 15 - } - } - }, + "type": "NumberLiteral", + "value": 80, "loc": { "start": { "line": 19, diff --git a/es2panda/test/parser/ts/test-ts-ternary-operator-3-expected.txt b/es2panda/test/parser/ts/test-ts-ternary-operator-3-expected.txt index ff367311698b0a6fa6cf6c45eb1239f500e44572..58e026476692c77468b63dc660399a1c197524b4 100644 --- a/es2panda/test/parser/ts/test-ts-ternary-operator-3-expected.txt +++ b/es2panda/test/parser/ts/test-ts-ternary-operator-3-expected.txt @@ -151,36 +151,8 @@ } }, "consequent": { - "type": "BinaryExpression", - "operator": "+", - "left": { - "type": "NumberLiteral", - "value": 2, - "loc": { - "start": { - "line": 18, - "column": 22 - }, - "end": { - "line": 18, - "column": 23 - } - } - }, - "right": { - "type": "NumberLiteral", - "value": 3, - "loc": { - "start": { - "line": 18, - "column": 26 - }, - "end": { - "line": 18, - "column": 27 - } - } - }, + "type": "NumberLiteral", + "value": 5, "loc": { "start": { "line": 18, diff --git a/es2panda/test/parser/ts/type_checker/expression_3-expected.txt b/es2panda/test/parser/ts/type_checker/expression_3-expected.txt index 91fb8015ca261cb984594c1de9b028ed592919a0..dc3ba9836cd98f26e69a97b0a221baf923c7a446 100644 --- a/es2panda/test/parser/ts/type_checker/expression_3-expected.txt +++ b/es2panda/test/parser/ts/type_checker/expression_3-expected.txt @@ -636,36 +636,8 @@ } }, "init": { - "type": "BinaryExpression", - "operator": "|", - "left": { - "type": "NumberLiteral", - "value": 1, - "loc": { - "start": { - "line": 30, - "column": 9 - }, - "end": { - "line": 30, - "column": 10 - } - } - }, - "right": { - "type": "NumberLiteral", - "value": 2, - "loc": { - "start": { - "line": 30, - "column": 13 - }, - "end": { - "line": 30, - "column": 14 - } - } - }, + "type": "NumberLiteral", + "value": 3, "loc": { "start": { "line": 30, diff --git a/es2panda/test/parser/ts/type_checker/member_expression_80-expected.txt b/es2panda/test/parser/ts/type_checker/member_expression_80-expected.txt index 8f4109d47316aad6fa56c6067fac28c3f2d7daf2..54589e0c5c6e1376af38329279d546e8b4203b7a 100644 --- a/es2panda/test/parser/ts/type_checker/member_expression_80-expected.txt +++ b/es2panda/test/parser/ts/type_checker/member_expression_80-expected.txt @@ -31,36 +31,8 @@ "shorthand": false, "computed": true, "key": { - "type": "BinaryExpression", - "operator": "+", - "left": { - "type": "NumberLiteral", - "value": 5, - "loc": { - "start": { - "line": 17, - "column": 11 - }, - "end": { - "line": 17, - "column": 12 - } - } - }, - "right": { - "type": "NumberLiteral", - "value": 4, - "loc": { - "start": { - "line": 17, - "column": 15 - }, - "end": { - "line": 17, - "column": 16 - } - } - }, + "type": "NumberLiteral", + "value": 9, "loc": { "start": { "line": 17, @@ -268,4 +240,4 @@ } } } -TypeError: Cannot assign to this property because it is readonly. [member_expression_80.ts:19:1] +TypeError: Property 5 does not exist on this type. [member_expression_80.ts:19:3] diff --git a/es2panda/test/parser/ts/type_checker/objectDestructuring-expected.txt b/es2panda/test/parser/ts/type_checker/objectDestructuring-expected.txt index 6fd777a27acb578b3d44bbcca1509886bc749e36..e1a310cecd1e54c95c623b3de65be867ec3fd712 100644 --- a/es2panda/test/parser/ts/type_checker/objectDestructuring-expected.txt +++ b/es2panda/test/parser/ts/type_checker/objectDestructuring-expected.txt @@ -6396,36 +6396,8 @@ } }, "value": { - "type": "BinaryExpression", - "operator": "+", - "left": { - "type": "NumberLiteral", - "value": 5, - "loc": { - "start": { - "line": 62, - "column": 63 - }, - "end": { - "line": 62, - "column": 64 - } - } - }, - "right": { - "type": "NumberLiteral", - "value": 6, - "loc": { - "start": { - "line": 62, - "column": 67 - }, - "end": { - "line": 62, - "column": 68 - } - } - }, + "type": "NumberLiteral", + "value": 11, "loc": { "start": { "line": 62, diff --git a/es2panda/test/runner.py b/es2panda/test/runner.py index e710c43539869b9d6dcc07d08d32a685e102ade7..7a74a966ad42ccb1362b7fb455daa0285906d959 100755 --- a/es2panda/test/runner.py +++ b/es2panda/test/runner.py @@ -1467,6 +1467,8 @@ def main(): runner.add_directory("parser/binder", "js", ["--dump-assembly"]) runner.add_directory("parser/js/emptySource", "js", ["--dump-assembly"]) runner.add_directory("parser/js/language/arguments-object", "js", ["--parse-only"]) + runner.add_directory("parser/js/language/expressions/binary-expressions", "js", + ["--parse-only", "--module", "--dump-ast"]) runners.append(runner) diff --git a/es2panda/util/helpers.cpp b/es2panda/util/helpers.cpp index 2a2ad9b4432cb8b5a8c996e345dfc5330cf3da88..5071229e75943d4ce8cec7190bc6c0e695b6fdad 100644 --- a/es2panda/util/helpers.cpp +++ b/es2panda/util/helpers.cpp @@ -143,6 +143,36 @@ int64_t Helpers::GetIndex(const util::StringView &str) return value; } +int32_t Helpers::ToInt32(double num) +{ + if (std::isnan(num) || std::isinf(num) || num == 0.0) { + return 0; + } + + double number = std::fmod(num, MAX_UINT32); + if (number >= std::numeric_limits::min() && number <= std::numeric_limits::max()) { + return number - std::fmod(number, 1); + } else if (number > std::numeric_limits::max()) { + return (number - MAX_UINT32) - std::fmod((number - MAX_UINT32), 1); + } + + return 0; +} + +uint32_t Helpers::ToUint32(double num) +{ + if (std::isnan(num) || std::isinf(num) || num == 0.0) { + return 0; + } + + double number = std::fmod(num, MAX_UINT32); + if (number >= std::numeric_limits::min() && number <= std::numeric_limits::max()) { + return number - std::fmod(number, 1); + } + + return 0; +} + bool Helpers::FileExtensionIs(std::string_view filePath, std::string_view extension) { return filePath.length() > extension.length() && Helpers::EndsWith(filePath, extension); diff --git a/es2panda/util/helpers.h b/es2panda/util/helpers.h index dc746454cbfb3e3d77c2e0d5287ab96f7a391f53..a8ef9ff6a59f10225561d0210d9f3f3e31b750ce 100644 --- a/es2panda/util/helpers.h +++ b/es2panda/util/helpers.h @@ -64,8 +64,12 @@ public: template static bool IsInteger(double number); + template + static T Divide(T left, T right); static bool IsIndex(double number); static int64_t GetIndex(const util::StringView &str); + static int32_t ToInt32(double num); + static uint32_t ToUint32(double num); static bool FileExtensionIs(std::string_view filePath, std::string_view extension); static bool EndsWith(std::string_view str, std::string_view suffix); @@ -111,6 +115,7 @@ public: static const int32_t MIN_DECIMAL_EXPONENT = -6; static const int32_t FAIL_SNPRINTF_S = -1; static const uint32_t INVALID_INDEX = 4294967295L; + static const uint64_t MAX_UINT32 = 4294967296L; static const uint32_t MAX_INT32 = 2147483647; static const uint32_t MAX_INT16 = std::numeric_limits::max(); static const uint32_t MAX_INT8 = std::numeric_limits::max(); @@ -137,6 +142,20 @@ bool Helpers::IsInteger(double number) return false; } +template +T Helpers::Divide(T left, T right) +{ + if (right != 0) { + return left / right; + } else if (left == 0 || left != left) { // for NaN + return std::numeric_limits::quiet_NaN(); + } else if ((left >= 0) == (std::signbit(right) == 0)) { + return std::numeric_limits::infinity(); + } + + return -std::numeric_limits::infinity(); +} + template T Helpers::BaseName(T const &path, T const &delims) {