diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 056ee80391bc85bc0f60d4201ce6f901c42404d4..38cebd61b45ec985e3b1b8586328ed37d668820d 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -32,7 +32,7 @@ config("libes2panda_public_config") { "$ark_es2panda_root", ] if (ark_standalone_build || ark_static_standalone_build) { - include_dirs += [ + include_dirs += [ "$target_gen_dir/generated", "//third_party/icu/icu4c/source/common", "//third_party/icu/icu4c/source/i18n", @@ -116,6 +116,7 @@ libes2panda_sources = [ "checker/types/ets/etsAnyType.cpp", "checker/types/ets/etsArrayType.cpp", "checker/types/ets/etsAsyncFuncReturnType.cpp", + "checker/types/ets/etsAwaitedType.cpp", "checker/types/ets/etsBigIntType.cpp", "checker/types/ets/etsBooleanType.cpp", "checker/types/ets/etsEnumType.cpp", @@ -127,7 +128,6 @@ libes2panda_sources = [ "checker/types/ets/etsObjectType.cpp", "checker/types/ets/etsPartialTypeParameter.cpp", "checker/types/ets/etsReadonlyType.cpp", - "checker/types/ets/etsAwaitedType.cpp", "checker/types/ets/etsResizableArrayType.cpp", "checker/types/ets/etsStringType.cpp", "checker/types/ets/etsTupleType.cpp", @@ -222,6 +222,7 @@ libes2panda_sources = [ "compiler/lowering/ets/arrayLiteralLowering.cpp", "compiler/lowering/ets/asyncMethodLowering.cpp", "compiler/lowering/ets/bigintLowering.cpp", + "compiler/lowering/ets/binaryExpressionLowering.cpp", "compiler/lowering/ets/boxingForLocals.cpp", "compiler/lowering/ets/capturedVariables.cpp", "compiler/lowering/ets/cfgBuilderPhase.cpp", @@ -1299,8 +1300,8 @@ ohos_source_set("libes2panda_public_frontend_static") { "$ark_root/assembler:libarktsassembler", "$ark_root/bytecode_optimizer:libarktsbytecodeopt_package", "$ark_root/compiler:libarktscompiler", - "$ark_root/libpandabase:libarktsbase", "$ark_root/libarkfile:libarktsfile", + "$ark_root/libpandabase:libarktsbase", ] } else { external_deps += [ diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 5715dc5301447922b154e413319008abe6417f55..3fabfa521f5469940aca65c44537b0d287cccce4 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -314,6 +314,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/ambientLowering.cpp compiler/lowering/ets/asyncMethodLowering.cpp compiler/lowering/ets/bigintLowering.cpp + compiler/lowering/ets/binaryExpressionLowering.cpp compiler/lowering/ets/recordLowering.cpp compiler/lowering/ets/resizableArrayLowering.cpp compiler/lowering/ets/restArgsLowering.cpp diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index 6c807c619c2a3d87204dcd82526cb391c8b830ea..b0b13c62aa6e307cb0fbd3f8452c4003ce8269b6 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -939,6 +939,8 @@ std::map &GetCheckMap() {lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, {lexer::TokenType::PUNCTUATOR_MOD, &ETSChecker::CheckBinaryOperatorMulDivMod}, {lexer::TokenType::PUNCTUATOR_MOD_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, + {lexer::TokenType::PUNCTUATOR_EXPONENTIATION, &ETSChecker::CheckBinaryOperatorMulDivMod}, + {lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, {lexer::TokenType::PUNCTUATOR_MINUS, &ETSChecker::CheckBinaryOperatorPlus}, {lexer::TokenType::PUNCTUATOR_MINUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus}, diff --git a/ets2panda/compiler/lowering/ets/binaryExpressionLowering.cpp b/ets2panda/compiler/lowering/ets/binaryExpressionLowering.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4662d8a75e519852d0ef84bd30fc52107e802c26 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/binaryExpressionLowering.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 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. + */ + +#include + +#include "binaryExpressionLowering.h" +#include "compiler/lowering/util.h" + +namespace ark::es2panda::compiler { + +using AstNodePtr = ir::AstNode *; + +static ir::AstNode *ConvertExponentiation(ir::BinaryExpression *binaryExpr, public_lib::Context *ctx) +{ + auto *checker = ctx->GetChecker()->AsETSChecker(); + auto *parser = ctx->parser->AsETSParser(); + auto *varbinder = checker->VarBinder()->AsETSBinder(); + + std::string const str = "Math.pow(@@E1, @@E2)"; + auto *parent = binaryExpr->Parent(); + + ir::Expression *loweringResult = parser->CreateFormattedExpression(str, binaryExpr->Left(), binaryExpr->Right()); + ES2PANDA_ASSERT(loweringResult != nullptr); + + loweringResult->SetParent(parent); + loweringResult->SetRange(binaryExpr->Range()); + + auto *scope = NearestScope(parent); + auto bscope = varbinder::LexicalScope::Enter(varbinder, scope); + CheckLoweredNode(varbinder, checker, loweringResult); + return loweringResult; +} + +bool BinaryExpressionLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) +{ + program->Ast()->TransformChildrenRecursivelyPostorder( + // CC-OFFNXT(G.FMT.14-CPP) project code style + [ctx](ir::AstNode *ast) -> AstNodePtr { + if (ast->IsBinaryExpression()) { + ir::BinaryExpression *binaryExpr = ast->AsBinaryExpression(); + if (binaryExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_EXPONENTIATION) { + return ConvertExponentiation(binaryExpr, ctx); + } + } + + return ast; + }, + Name()); + + return true; +} +} // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/binaryExpressionLowering.h b/ets2panda/compiler/lowering/ets/binaryExpressionLowering.h new file mode 100644 index 0000000000000000000000000000000000000000..482ca185567bdd7f8e9191d8677e24b45ce89f0e --- /dev/null +++ b/ets2panda/compiler/lowering/ets/binaryExpressionLowering.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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. + */ + +#ifndef ES2PANDA_COMPILER_LOWERING_BINARY_EXPRESSION_LOWERING_H +#define ES2PANDA_COMPILER_LOWERING_BINARY_EXPRESSION_LOWERING_H + +#include "compiler/lowering/phase.h" + +namespace ark::es2panda::compiler { + +class BinaryExpressionLowering : public PhaseForDeclarations { +public: + std::string_view Name() const override + { + return "BinaryExpressionLowering"; + } + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; +}; + +} // namespace ark::es2panda::compiler + +#endif diff --git a/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp b/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp index 46621d1cc027e751300b63c0cae2d33e282f2d75..eb32e5f0040da45702a05a8db8b7475afe2431f9 100644 --- a/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp @@ -106,7 +106,7 @@ static bool IsMultiplicativeExpression(const ir::BinaryExpression *expr) { auto opType = expr->OperatorType(); return opType == lexer::TokenType::PUNCTUATOR_MULTIPLY || opType == lexer::TokenType::PUNCTUATOR_DIVIDE || - opType == lexer::TokenType::PUNCTUATOR_MOD; + opType == lexer::TokenType::PUNCTUATOR_MOD || opType == lexer::TokenType::PUNCTUATOR_EXPONENTIATION; } static bool IsRelationalExpression(const ir::BinaryExpression *expr) @@ -414,6 +414,14 @@ private: PerformArithmetic>(expr, leftNum, rightNum, &resNum); break; } + case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: { + if (leftNum < 0 && !std::is_integral_v) { + LogError(diagnostic::EXPONENTIATION_BASE_LESS_ZERO, {}, expr->Start()); + resNum = std::numeric_limits::quiet_NaN(); + } + resNum = std::pow(leftNum, rightNum); + break; + } default: ES2PANDA_UNREACHABLE(); } diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 47a89ade9ea2b820e11e190bceda1dd19e01aed6..b8b1ab646f4e6fe1fa3ed91ba83b32ee02ca7f09 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -23,6 +23,7 @@ #include "compiler/lowering/ets/ambientLowering.h" #include "compiler/lowering/ets/arrayLiteralLowering.h" #include "compiler/lowering/ets/bigintLowering.h" +#include "compiler/lowering/ets/binaryExpressionLowering.h" #include "compiler/lowering/ets/boxingForLocals.h" #include "compiler/lowering/ets/capturedVariables.h" #include "compiler/lowering/ets/constantExpressionLowering.h" @@ -141,6 +142,7 @@ std::vector GetETSPhaseList() new ArrayLiteralLowering, new BigIntLowering, new OpAssignmentLowering, + new BinaryExpressionLowering, // should be after BigIntLowering and OpAssignmentLowering new SetterLowering, // must be put before ObjectIndexLowering new LateInitializationConvert, new ExtensionAccessorPhase, diff --git a/ets2panda/lexer/ETSLexer.cpp b/ets2panda/lexer/ETSLexer.cpp index 58645e09fa9e7ebd9e002ed626567f1db84226bd..09ebb112982d974fccde8a068a795a75092bab36 100644 --- a/ets2panda/lexer/ETSLexer.cpp +++ b/ets2panda/lexer/ETSLexer.cpp @@ -103,22 +103,6 @@ bool ETSLexer::CheckUtf16Compatible(char32_t cp) const return true; } -void ETSLexer::ScanAsteriskPunctuator() -{ - GetToken().type_ = TokenType::PUNCTUATOR_MULTIPLY; - - switch (Iterator().Peek()) { - case LEX_CHAR_EQUALS: { - GetToken().type_ = TokenType::PUNCTUATOR_MULTIPLY_EQUAL; - Iterator().Forward(1); - break; - } - default: { - break; - } - } -} - void ETSLexer::ConvertNumber(NumberFlags const flags) { GetToken().number_ = lexer::Number(GetToken().src_, flags); diff --git a/ets2panda/lexer/ETSLexer.h b/ets2panda/lexer/ETSLexer.h index 5bb869a72f75a56021dc2e22e925ef85b924e77d..6d63d300cb5d2584c94df15af1e891bf83b2ac4c 100644 --- a/ets2panda/lexer/ETSLexer.h +++ b/ets2panda/lexer/ETSLexer.h @@ -36,7 +36,6 @@ public: void NextToken(NextTokenFlags flags = NextTokenFlags::NONE) override; void ScanHashMark() override; bool ScanCharLiteral() override; - void ScanAsteriskPunctuator() override; void ScanNumberLeadingZero(bool const leadingMinus) override { diff --git a/ets2panda/test/ast/compiler/ets/illegal_exponentiation_1.ets b/ets2panda/test/ast/compiler/ets/illegal_exponentiation_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a8329c7756d674f08a196560055221e9742f9ed4 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/illegal_exponentiation_1.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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. + */ + +function main() { + let x = -1 ** 1.0; +} + +/* @@? 17:11 Error TypeError: Exponent must be an integer if base is less than 0. */ diff --git a/ets2panda/test/runtime/ets/exponentiation_1.ets b/ets2panda/test/runtime/ets/exponentiation_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..c0d7e508d50b2ffce457b7b52ef7e18d5183e321 --- /dev/null +++ b/ets2panda/test/runtime/ets/exponentiation_1.ets @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 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. + */ + + +function main() { + let x1 = 2; + let y1 = 3; + let z1: number = x1 ** y1; + arktest.assertDoubleEQ(z1, 8, 0.00001); + let z2: number = 3 ** 3; + arktest.assertDoubleEQ(z2, 27, 0.00001); + let z3 = 4.0 ** 3; + arktest.assertDoubleEQ(z3, 64, 0.00001); + let x4 = 5; + let y4 = 3; + arktest.assertDoubleEQ(x4 ** y4, 125, 0.00001); +} diff --git a/ets2panda/test/runtime/ets/exponentiation_2.ets b/ets2panda/test/runtime/ets/exponentiation_2.ets new file mode 100644 index 0000000000000000000000000000000000000000..c0d7e508d50b2ffce457b7b52ef7e18d5183e321 --- /dev/null +++ b/ets2panda/test/runtime/ets/exponentiation_2.ets @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 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. + */ + + +function main() { + let x1 = 2; + let y1 = 3; + let z1: number = x1 ** y1; + arktest.assertDoubleEQ(z1, 8, 0.00001); + let z2: number = 3 ** 3; + arktest.assertDoubleEQ(z2, 27, 0.00001); + let z3 = 4.0 ** 3; + arktest.assertDoubleEQ(z3, 64, 0.00001); + let x4 = 5; + let y4 = 3; + arktest.assertDoubleEQ(x4 ** y4, 125, 0.00001); +} diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index b3fb4b9e6cfb36a7172b14428b11857365c5d844..e39c5d67fb093e7acee2f1417ce693e23b30f974 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -414,6 +414,10 @@ semantic: id: 274 message: "Expected at least {} type arguments, but got {}." +- name: EXPONENTIATION_BASE_LESS_ZERO + id: 22843 + message: "Exponent must be an integer if base is less than 0." + - name: EXPORT_INCORRECT id: 361 message: "Incorrect export '{}'"