diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 87fc469310256e6f5cdb6c2ae77fe7c722b4cd85..a1cb041edbde0334b4985367672118ce4b578d86 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -402,6 +402,8 @@ public: bool IsNullLikeOrVoidExpression(const ir::Expression *expr) const; bool IsConstantExpression(ir::Expression *expr, Type *type); void ValidateUnaryOperatorOperand(varbinder::Variable *variable); + bool TestUnionType(Type *type, TypeFlag test); + bool CheckPossibilityPromotion(Type *left, Type *right, TypeFlag test); std::tuple ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test, bool do_promotion = true); checker::Type *ApplyConditionalOperatorPromotion(checker::ETSChecker *checker, checker::Type *unboxed_l, diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 73311393661a09964e961fe4673159a8a0ac6b8a..736944edb43ddd78edd97614a6e918f9dbed1d5b 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -750,8 +750,13 @@ Type *ETSChecker::HandleBooleanLogicalOperatorsExtended(Type *left_type, Type *r IsNullLikeOrVoidExpression(expr->Right()) ? std::make_tuple(true, false) : right_type->ResolveConditionExpr(); if (!resolve_left) { - // return the UNION type when it is implemented - return IsTypeIdenticalTo(left_type, right_type) ? left_type : GlobalETSBooleanType(); + if (IsTypeIdenticalTo(left_type, right_type)) { + return left_type; + } + ArenaVector types(Allocator()->Adapter()); + types.push_back(left_type); + types.push_back(right_type); + return CreateETSUnionType(std::move(types)); } switch (expr->OperatorType()) { @@ -1057,8 +1062,11 @@ void ETSChecker::SetPropertiesForModuleObject(checker::ETSObjectType *module_obj { auto *ets_binder = static_cast(VarBinder()); - auto res = ets_binder->GetGlobalRecordTable()->Program()->ExternalSources().find(import_path); - + auto ext_records = ets_binder->GetGlobalRecordTable()->Program()->ExternalSources(); + auto res = [ets_binder, ext_records, import_path]() { + auto r = ext_records.find(import_path); + return r != ext_records.end() ? r : ext_records.find(ets_binder->GetResolvedImportPath(import_path)); + }(); for (auto [_, var] : res->second.front()->GlobalClassScope()->StaticFieldScope()->Bindings()) { (void)_; if (var->AsLocalVariable()->Declaration()->Node()->IsExported()) { @@ -1446,18 +1454,6 @@ Type *ETSChecker::ETSBuiltinTypeAsConditionalType(Type *object_type) return nullptr; } - if (object_type->IsETSObjectType()) { - if (!object_type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNBOXABLE_TYPE)) { - return object_type; - } - auto saved_result = Relation()->IsTrue(); - Relation()->Result(false); - - UnboxingConverter converter = UnboxingConverter(AsETSChecker(), Relation(), object_type, object_type); - Relation()->Result(saved_result); - return converter.Result(); - } - return object_type; } diff --git a/ets2panda/checker/types/ets/etsEnumType.h b/ets2panda/checker/types/ets/etsEnumType.h index fb9cc0debb0d67eb05482c3e70aaa8cb8b3a9d14..094790cab810693b05b43465b02c8f352890d96a 100644 --- a/ets2panda/checker/types/ets/etsEnumType.h +++ b/ets2panda/checker/types/ets/etsEnumType.h @@ -138,6 +138,11 @@ public: from_int_method_ = method; } + std::tuple ResolveConditionExpr() const override + { + return {true, !GetMembers().empty()}; + } + private: const ir::TSEnumDeclaration *decl_; const UType ordinal_; diff --git a/ets2panda/checker/types/ets/etsObjectType.h b/ets2panda/checker/types/ets/etsObjectType.h index a083979f86ffc07384e9df0e89b9a2a70409e337..391f54588ce9e0207ca381430e9c5e70461a690b 100644 --- a/ets2panda/checker/types/ets/etsObjectType.h +++ b/ets2panda/checker/types/ets/etsObjectType.h @@ -512,11 +512,7 @@ public: std::tuple ResolveConditionExpr() const override { - if (IsNullish() || IsETSStringType()) { - return {false, false}; - } - - return {true, true}; + return {false, false}; } protected: diff --git a/ets2panda/checker/types/ets/etsUnionType.h b/ets2panda/checker/types/ets/etsUnionType.h index 728c05665b8f285a32825e73fbd3df81cc61080d..3572aae06026d9cd39d67d887ed2f3942267400b 100644 --- a/ets2panda/checker/types/ets/etsUnionType.h +++ b/ets2panda/checker/types/ets/etsUnionType.h @@ -81,6 +81,16 @@ public: static Type *HandleUnionType(ETSUnionType *union_type); + std::tuple ResolveConditionExpr() const override + { + for (auto tp : ConstituentTypes()) { + if (!tp->IsConditionalExprType()) { + return {true, false}; + } + } + return {true, true}; + } + private: static bool EachTypeRelatedToSomeType(TypeRelation *relation, ETSUnionType *source, ETSUnionType *target); static bool TypeRelatedToSomeType(TypeRelation *relation, Type *source, ETSUnionType *target); diff --git a/ets2panda/checker/types/typeFlag.h b/ets2panda/checker/types/typeFlag.h index 7a26628209dce4b89f47d4dae61efbe9f2ad3963..58c04f812f895b62dc8f44893f4577fea54021ad 100644 --- a/ets2panda/checker/types/typeFlag.h +++ b/ets2panda/checker/types/typeFlag.h @@ -128,8 +128,8 @@ enum class TypeFlag : uint64_t { VALID_ARITHMETIC_TYPE = ANY | NUMBER_LIKE | BIGINT_LIKE | ENUM, UNIT = LITERAL | UNIQUE_SYMBOL | NULLISH, GETTER_SETTER = GETTER | SETTER, - CONDITION_EXPRESSION_TYPE = - NULLISH | CONSTANT | ETS_OBJECT | BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | ETS_BOOLEAN | ETS_ARRAY + CONDITION_EXPRESSION_TYPE = NULLISH | CONSTANT | ETS_OBJECT | BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | + ETS_BOOLEAN | ETS_ARRAY | ETS_ENUM | ETS_STRING_ENUM }; DEFINE_BITOPS(TypeFlag) diff --git a/ets2panda/compiler/base/condition.cpp b/ets2panda/compiler/base/condition.cpp index 0331d9342c7c84029588065ec0bf8aeb442ec5be..d2abcf956930a75c6c9c30f7dae2f79f52208806 100644 --- a/ets2panda/compiler/base/condition.cpp +++ b/ets2panda/compiler/base/condition.cpp @@ -126,6 +126,67 @@ Condition::Result Condition::CheckConstantExpr(ETSGen *etsg, const ir::Expressio return Result::UNKNOWN; } +void Condition::CompileLogicalOrExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label) +{ + auto ttctx = TargetTypeContext(etsg, bin_expr->OperationType()); + RegScope rs(etsg); + VReg lhs = etsg->AllocReg(); + VReg rhs = etsg->AllocReg(); + auto *return_left_label = etsg->AllocLabel(); + auto *return_right_true_label = etsg->AllocLabel(); + auto *return_right_false_label = etsg->AllocLabel(); + + bin_expr->Left()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(bin_expr->Left(), lhs, bin_expr->OperationType()); + etsg->ResolveConditionalResultIfTrue(bin_expr->Left(), return_left_label); + etsg->BranchIfTrue(bin_expr, return_left_label); + + bin_expr->Right()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(bin_expr->Right(), rhs, bin_expr->OperationType()); + etsg->ResolveConditionalResultIfFalse(bin_expr->Right(), return_right_false_label); + etsg->BranchIfFalse(bin_expr, return_right_false_label); + etsg->LoadAccumulator(bin_expr, rhs); + etsg->Branch(bin_expr, return_right_true_label); + + etsg->SetLabel(bin_expr, return_right_false_label); + etsg->LoadAccumulator(bin_expr, rhs); + etsg->Branch(bin_expr, false_label); + etsg->SetLabel(bin_expr, return_left_label); + etsg->LoadAccumulator(bin_expr, lhs); + etsg->SetLabel(bin_expr, return_right_true_label); +} + +void Condition::CompileLogicalAndExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label) +{ + auto ttctx = TargetTypeContext(etsg, bin_expr->OperationType()); + RegScope rs(etsg); + VReg lhs = etsg->AllocReg(); + VReg rhs = etsg->AllocReg(); + auto *return_left_label = etsg->AllocLabel(); + auto *return_right_true_label = etsg->AllocLabel(); + auto *return_right_false_label = etsg->AllocLabel(); + + bin_expr->Left()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(bin_expr->Left(), lhs, bin_expr->OperationType()); + etsg->ResolveConditionalResultIfFalse(bin_expr->Left(), return_left_label); + etsg->BranchIfFalse(bin_expr, return_left_label); + + bin_expr->Right()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(bin_expr->Right(), rhs, bin_expr->OperationType()); + etsg->ResolveConditionalResultIfFalse(bin_expr->Right(), return_right_false_label); + etsg->BranchIfFalse(bin_expr, return_right_false_label); + etsg->LoadAccumulator(bin_expr, rhs); + etsg->Branch(bin_expr, return_right_true_label); + + etsg->SetLabel(bin_expr, return_left_label); + etsg->LoadAccumulator(bin_expr, lhs); + etsg->Branch(bin_expr, false_label); + etsg->SetLabel(bin_expr, return_right_false_label); + etsg->LoadAccumulator(bin_expr, rhs); + etsg->Branch(bin_expr, false_label); + etsg->SetLabel(bin_expr, return_right_true_label); +} + bool Condition::CompileBinaryExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label) { switch (bin_expr->OperatorType()) { @@ -149,30 +210,11 @@ bool Condition::CompileBinaryExpr(ETSGen *etsg, const ir::BinaryExpression *bin_ return true; } case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { - bin_expr->Left()->Compile(etsg); - etsg->ApplyConversion(bin_expr->Left(), bin_expr->OperationType()); - etsg->ResolveConditionalResultIfFalse(bin_expr->Left(), false_label); - etsg->BranchIfFalse(bin_expr, false_label); - - bin_expr->Right()->Compile(etsg); - etsg->ApplyConversion(bin_expr->Right(), bin_expr->OperationType()); - etsg->ResolveConditionalResultIfFalse(bin_expr->Right(), false_label); - etsg->BranchIfFalse(bin_expr, false_label); + CompileLogicalAndExpr(etsg, bin_expr, false_label); return true; } case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { - auto *end_label = etsg->AllocLabel(); - - bin_expr->Left()->Compile(etsg); - etsg->ApplyConversion(bin_expr->Left(), bin_expr->OperationType()); - etsg->ResolveConditionalResultIfTrue(bin_expr->Left(), end_label); - etsg->BranchIfTrue(bin_expr, end_label); - - bin_expr->Right()->Compile(etsg); - etsg->ApplyConversion(bin_expr->Right(), bin_expr->OperationType()); - etsg->ResolveConditionalResultIfFalse(bin_expr->Right(), false_label); - etsg->BranchIfFalse(bin_expr, false_label); - etsg->SetLabel(bin_expr, end_label); + CompileLogicalOrExpr(etsg, bin_expr, false_label); return true; } default: { diff --git a/ets2panda/compiler/base/condition.h b/ets2panda/compiler/base/condition.h index 11ed9e8670ccb054d15c950f11338de275f11aa9..6380ba538ea054cc711217737c042649cfcc5ba7 100644 --- a/ets2panda/compiler/base/condition.h +++ b/ets2panda/compiler/base/condition.h @@ -40,6 +40,8 @@ public: private: static bool CompileBinaryExpr(PandaGen *pg, const ir::BinaryExpression *bin_expr, Label *false_label); static bool CompileBinaryExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label); + static void CompileLogicalAndExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label); + static void CompileLogicalOrExpr(ETSGen *etsg, const ir::BinaryExpression *bin_expr, Label *false_label); }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 6ee70ad191040eb3ba06d358f357beeb3794599e..4b4770078a6d4dc618dda25c0505428ca1408283 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -317,33 +317,33 @@ static void CompileLogical(compiler::ETSGen *etsg, const ir::BinaryExpression *e auto ttctx = compiler::TargetTypeContext(etsg, expr->OperationType()); compiler::RegScope rs(etsg); auto lhs = etsg->AllocReg(); - auto rhs = etsg->AllocReg(); + expr->Left()->Compile(etsg); etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType()); auto *end_label = etsg->AllocLabel(); - auto left_false_label = etsg->AllocLabel(); + auto return_left_label = etsg->AllocLabel(); if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { - etsg->ResolveConditionalResultIfFalse(expr->Left(), left_false_label); - etsg->BranchIfFalse(expr, left_false_label); + etsg->ResolveConditionalResultIfFalse(expr->Left(), return_left_label); + etsg->BranchIfFalse(expr, return_left_label); expr->Right()->Compile(etsg); - etsg->ApplyConversionAndStoreAccumulator(expr->Right(), rhs, expr->OperationType()); + etsg->ApplyConversion(expr->Right(), expr->OperationType()); etsg->Branch(expr, end_label); - etsg->SetLabel(expr, left_false_label); + etsg->SetLabel(expr, return_left_label); etsg->LoadAccumulator(expr, lhs); } else { - etsg->ResolveConditionalResultIfFalse(expr->Left(), left_false_label); - etsg->BranchIfFalse(expr, left_false_label); + etsg->ResolveConditionalResultIfTrue(expr->Left(), return_left_label); + etsg->BranchIfTrue(expr, return_left_label); - etsg->LoadAccumulator(expr, lhs); + expr->Right()->Compile(etsg); + etsg->ApplyConversion(expr->Right(), expr->OperationType()); etsg->Branch(expr, end_label); - etsg->SetLabel(expr, left_false_label); - expr->Right()->Compile(etsg); - etsg->ApplyConversionAndStoreAccumulator(expr->Right(), rhs, expr->OperationType()); + etsg->SetLabel(expr, return_left_label); + etsg->LoadAccumulator(expr, lhs); } etsg->SetLabel(expr, end_label); diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 30b85196537359b852c43094dea5fbb21599e6f6..89f048ece15f7b8cff81cd0fd1d5cb7d9b6be55c 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -2160,6 +2160,7 @@ void ETSGen::LogicalNot(const ir::AstNode *node) ASSERT(GetAccumulatorType()->IsConditionalExprType()); ResolveConditionalResultIfFalse(node); Sa().Emit(node, 1); + SetAccumulatorType(Checker()->GlobalETSBooleanType()); } void ETSGen::Unary(const ir::AstNode *node, lexer::TokenType op) diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 7ee98c5619fb31522e9ada5358b7e9b7f720d1c2..f09b7301e9dc15c6b9719dd5f2467793174b681f 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -102,10 +102,11 @@ public: bool TryLoadConstantExpression(const ir::Expression *node); void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *if_false); - template - void ResolveConditionalResultFloat(const ir::AstNode *node, [[maybe_unused]] Label *if_false, Label *end) + template + void ResolveConditionalResultFloat(const ir::AstNode *node, Label *real_end_label) { - auto type = node->IsExpression() ? node->AsExpression()->TsType() : GetAccumulatorType(); + auto type = node->IsExpression() && !node->AsExpression()->IsUnaryExpression() ? node->AsExpression()->TsType() + : GetAccumulatorType(); VReg tmp_reg = AllocReg(); StoreAccumulator(node, tmp_reg); if (type->IsFloatType()) { @@ -113,17 +114,8 @@ public: } else { DoubleIsNaN(node); } - Sa().Emit(node, 1); - auto real_end_label = [](Label *end_label, Label *if_false_label, ETSGen *etsgn, bool use_false_label) { - if (use_false_label) { - return if_false_label; - } - if (end_label == nullptr) { - end_label = etsgn->AllocLabel(); - } - return end_label; - }(end, if_false, this, USE_FALSE_LABEL); + BranchIfFalse(node, real_end_label); LoadAccumulator(node, tmp_reg); VReg zero_reg = AllocReg(); @@ -138,39 +130,40 @@ public: } template - void ResolveConditionalResultNumeric(const ir::AstNode *node, [[maybe_unused]] Label *if_false, Label *end) + void ResolveConditionalResultNumeric(const ir::AstNode *node, [[maybe_unused]] Label *if_false, Label **end) { - auto type = node->IsExpression() ? node->AsExpression()->TsType() : GetAccumulatorType(); - switch (type->TypeFlags()) { - case checker::TypeFlag::LONG: { - CastToInt(node); - [[fallthrough]]; - } - case checker::TypeFlag::BYTE: - case checker::TypeFlag::CHAR: - case checker::TypeFlag::SHORT: - case checker::TypeFlag::INT: { - if constexpr (BEFORE_LOGICAL_NOT) { - Label *zero_primitive = AllocLabel(); - BranchIfFalse(node, zero_primitive); - ToBinaryResult(node, zero_primitive); - } - break; + auto type = node->IsExpression() && !node->AsExpression()->IsUnaryExpression() ? node->AsExpression()->TsType() + : GetAccumulatorType(); + + auto real_end_label = [end, if_false, this](bool use_false_label) { + if (use_false_label) { + return if_false; } - case checker::TypeFlag::DOUBLE: - case checker::TypeFlag::FLOAT: { - ResolveConditionalResultFloat(node, if_false, end); - break; + if ((*end) == nullptr) { + (*end) = AllocLabel(); } - default: - break; + return (*end); + }(USE_FALSE_LABEL); + if (type->IsDoubleType() || type->IsFloatType()) { + ResolveConditionalResultFloat(node, real_end_label); + } + if (type->IsLongType()) { + VReg zero_reg = AllocReg(); + MoveImmediateToRegister(node, zero_reg, checker::TypeFlag::LONG, 0); + BinaryNumberComparison(node, zero_reg, real_end_label); + } + if constexpr (BEFORE_LOGICAL_NOT) { + Label *zero_primitive = AllocLabel(); + BranchIfFalse(node, zero_primitive); + ToBinaryResult(node, zero_primitive); } } - template - void ResolveConditionalResultObject(const ir::AstNode *node, [[maybe_unused]] Label *if_false) + template + void ResolveConditionalResultObject(const ir::AstNode *node) { - auto type = node->IsExpression() ? node->AsExpression()->TsType() : GetAccumulatorType(); + auto type = node->IsExpression() && !node->AsExpression()->IsUnaryExpression() ? node->AsExpression()->TsType() + : GetAccumulatorType(); if (type->IsETSStringType()) { LoadStringLength(node); if constexpr (BEFORE_LOGICAL_NOT) { @@ -178,6 +171,27 @@ public: BranchIfFalse(node, zero_lenth); ToBinaryResult(node, zero_lenth); } + } else if (node->IsExpression() && node->AsExpression()->IsIdentifier() && + node->AsExpression()->AsIdentifier()->Variable()->HasFlag(varbinder::VariableFlags::VAR)) { + Label *is_string = AllocLabel(); + Label *end = AllocLabel(); + compiler::VReg obj_reg = AllocReg(); + StoreAccumulator(node, obj_reg); + + Sa().Emit(node, Checker()->GlobalBuiltinETSStringType()->AsETSStringType()->AssemblerName()); + BranchIfTrue(node, is_string); + Sa().Emit(node, 1); + Branch(node, end); + SetLabel(node, is_string); + LoadAccumulator(node, obj_reg); + CastToString(node); + LoadStringLength(node); + if constexpr (BEFORE_LOGICAL_NOT) { + Label *zero_lenth = AllocLabel(); + BranchIfFalse(node, zero_lenth); + ToBinaryResult(node, zero_lenth); + } + SetLabel(node, end); } else { Sa().Emit(node, 1); } @@ -200,11 +214,8 @@ public: template void ResolveConditionalResult(const ir::AstNode *node, [[maybe_unused]] Label *if_false) { - auto type = node->IsExpression() ? node->AsExpression()->TsType() : GetAccumulatorType(); - if (type->IsETSObjectType() && - type->AsETSObjectType()->HasObjectFlag(panda::es2panda::checker::ETSObjectFlags::UNBOXABLE_TYPE)) { - type = GetAccumulatorType(); - } + auto type = node->IsExpression() && !node->AsExpression()->IsUnaryExpression() ? node->AsExpression()->TsType() + : GetAccumulatorType(); if (type->IsETSBooleanType()) { return; } @@ -228,9 +239,9 @@ public: StoreAccumulator(node, obj_reg); LoadArrayLength(node, obj_reg); } else if (type->IsETSObjectType()) { - ResolveConditionalResultObject(node, if_false); + ResolveConditionalResultObject(node); } else { - ResolveConditionalResultNumeric(node, if_false, end); + ResolveConditionalResultNumeric(node, if_false, &end); } if (if_nullish != nullptr) { Branch(node, end); @@ -248,10 +259,10 @@ public: ResolveConditionalResult(node, if_false); } - template + template void ResolveConditionalResultIfTrue(const ir::AstNode *node, Label *if_false = nullptr) { - ResolveConditionalResult(node, if_false); + ResolveConditionalResult(node, if_false); } void BranchIfFalse(const ir::AstNode *node, Label *if_false) diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 0d33af9dd5f188d697279484eade4585c5a1668e..858ca20a05ae825f2e0c312cf3951fca9a26db04 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -115,7 +115,10 @@ static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const Phase context.SetParser(&parser); parser.ParseScript(unit.input, unit.options.compilation_mode == CompilationMode::GEN_STD_LIB); - + if constexpr (std::is_same_v && std::is_same_v) { + reinterpret_cast(varbinder)->FillResolvedImportPathes(parser.ResolvedParsedSourcesMap(), + &allocator); + } for (auto *phase : get_phases()) { if (!phase->Apply(&context, &program)) { return nullptr; diff --git a/ets2panda/ir/expressions/unaryExpression.cpp b/ets2panda/ir/expressions/unaryExpression.cpp index a73cbef0771f745f05549cd07d211661f5374add..b9e2579f6586d106b32a2d6c45ce53ac3ee82c64 100644 --- a/ets2panda/ir/expressions/unaryExpression.cpp +++ b/ets2panda/ir/expressions/unaryExpression.cpp @@ -283,7 +283,7 @@ checker::Type *UnaryExpression::Check(checker::ETSChecker *checker) break; } - SetTsType(operand_type); + SetTsType(checker->GlobalETSBooleanType()); break; } case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: { diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 1100af3be59744c72fa13015407b4cf5ab5d647c..0becad25294bf53e8bcda4f99f13d840b8cade28 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -173,11 +173,21 @@ void ETSParser::ParseETSGlobalScript(lexer::SourcePosition start_loc, ArenaVecto // remove external sources from paths because already parsed them paths.erase(remove_if(begin(paths), end(paths), [this](auto x) { - return find(begin(parsed_sources_), end(parsed_sources_), x) != end(parsed_sources_); + auto resolved = ResolveImportPath(x); + auto path_iter = + std::find_if(resolved_parsed_sources_.begin(), resolved_parsed_sources_.end(), + [resolved](const auto &p) { return p.second == resolved; }); + auto found = path_iter != resolved_parsed_sources_.end(); + if (found) { + resolved_parsed_sources_.emplace(x, resolved); + } + return found; }), end(paths)); - parsed_sources_.insert(parsed_sources_.end(), paths.begin(), paths.end()); + for (const auto &path : paths) { + parsed_sources_.push_back(ResolveImportPath(path)); + } ParseSources(paths, false); ParseTopLevelDeclaration(statements); @@ -231,9 +241,12 @@ ArenaVector ETSParser::PrepareExternalGlobalClass([[maybe_unuse if (!statements.empty()) { res = ext_sources.find(name); } else { - const util::UString source_file_path( - GetProgram()->SourceFilePath().Mutf8() + GetProgram()->GetPackageName().Mutf8(), Allocator()); - GetProgram()->SetSource(GetProgram()->SourceCode(), GetProgram()->SourceFile(), source_file_path.View()); + auto path = GetProgram()->SourceFilePath().Mutf8() + panda::os::file::File::GetPathDelim().at(0) + + GetProgram()->GetPackageName().Mutf8(); + auto resolved = ResolveImportPath(path); + resolved_parsed_sources_.emplace(path, resolved); + GetProgram()->SetSource(GetProgram()->SourceCode(), GetProgram()->SourceFile(), + util::UString(resolved, Allocator()).View()); } if (res == ext_sources.end()) { @@ -344,14 +357,30 @@ ETSParser::ImportData ETSParser::GetImportData(const std::string &path) return {ToLanguage(Extension()), path, true}; } +std::string ETSParser::ResolveFullPathFromRelative(const std::string &path) +{ + char path_delimiter = panda::os::file::File::GetPathDelim().at(0); + auto resolved_fp = GetProgram()->ResolvedFilePath().Mutf8(); + auto source_fp = GetProgram()->SourceFilePath().Mutf8(); + if (resolved_fp.empty()) { + auto fp = source_fp + path_delimiter + path; + return util::Helpers::IsRealPath(fp) ? fp : path; + } + auto fp = resolved_fp + path_delimiter + path; + if (util::Helpers::IsRealPath(fp)) { + return fp; + } + if (path.find(source_fp) == 0) { + return resolved_fp + path_delimiter + path.substr(source_fp.size()); + } + return path; +} + std::string ETSParser::ResolveImportPath(const std::string &path) { char path_delimiter = panda::os::file::File::GetPathDelim().at(0); if (util::Helpers::IsRelativePath(path)) { - if (GetProgram()->ResolvedFilePath().Mutf8().empty()) { - return GetProgram()->SourceFilePath().Mutf8() + path_delimiter + path; - } - return GetProgram()->ResolvedFilePath().Mutf8() + path_delimiter + path; + return util::Helpers::GetAbsPath(ResolveFullPathFromRelative(path)); } std::string base_url; @@ -395,11 +424,29 @@ std::string ETSParser::ResolveImportPath(const std::string &path) return base_url; } +std::tuple ETSParser::GetSourceRegularPath(const std::string &path, const std::string &resolved_path) +{ + if (!panda::os::file::File::IsRegularFile(resolved_path)) { + std::string import_extension = ".ets"; + + if (!panda::os::file::File::IsRegularFile(resolved_path + import_extension)) { + import_extension = ".ts"; + + if (!panda::os::file::File::IsRegularFile(resolved_path + import_extension)) { + ThrowSyntaxError("Incorrect path: " + resolved_path); + } + } + return {path + import_extension, true}; + } + return {path, false}; +} + std::tuple, bool> ETSParser::CollectUserSources(const std::string &path) { std::vector user_paths; const std::string resolved_path = ResolveImportPath(path); + resolved_parsed_sources_.emplace(path, resolved_path); const auto data = GetImportData(resolved_path); if (!data.has_decl) { @@ -407,23 +454,11 @@ std::tuple, bool> ETSParser::CollectUserSources(const s } if (!panda::os::file::File::IsDirectory(resolved_path)) { - if (!panda::os::file::File::IsRegularFile(resolved_path)) { - std::string import_extension = ".ets"; - - if (!panda::os::file::File::IsRegularFile(resolved_path + import_extension)) { - import_extension = ".ts"; - - if (!panda::os::file::File::IsRegularFile(resolved_path + import_extension)) { - ThrowSyntaxError("Incorrect path: " + resolved_path); - } - } - - user_paths.emplace_back(path + import_extension); - return {user_paths, true}; - } - - user_paths.emplace_back(path); - return {user_paths, false}; + std::string regular_path; + bool is_module = false; + std::tie(regular_path, is_module) = GetSourceRegularPath(path, resolved_path); + user_paths.emplace_back(regular_path); + return {user_paths, is_module}; } #ifdef USE_UNIX_SYSCALL @@ -479,6 +514,8 @@ void ETSParser::ParseSources(const std::vector &paths, bool is_exte const std::size_t path_count = paths.size(); for (std::size_t idx = 0; idx < path_count; idx++) { std::string resolved_path = ResolveImportPath(paths[idx]); + resolved_parsed_sources_.emplace(paths[idx], resolved_path); + const auto data = GetImportData(resolved_path); if (!data.has_decl) { @@ -2862,6 +2899,7 @@ std::tuple> ETSParser::ParseFromCla bool is_module = false; auto import_path = Lexer()->GetToken().Ident(); auto resolved_import_path = ResolveImportPath(import_path.Mutf8()); + resolved_parsed_sources_.emplace(import_path.Mutf8(), resolved_import_path); ir::StringLiteral *resolved_source; if (*import_path.Bytes() == '/') { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index d1eb419aa82dbb2f77527a06167cf6a8af77ef07..cf643c0d57e554d45034d31099ddbbd86937189b 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -41,7 +41,10 @@ inline constexpr char const DEFAULT_SOURCE_FILE[] = ".ets"; class ETSParser final : public TypedParser { public: ETSParser(Program *program, const CompilerOptions &options, ParserStatus status = ParserStatus::NO_OPTS) - : TypedParser(program, options, status), global_program_(GetProgram()), parsed_sources_({}) + : TypedParser(program, options, status), + global_program_(GetProgram()), + parsed_sources_({}), + resolved_parsed_sources_({}) { } @@ -109,8 +112,10 @@ private: void ParseTopLevelDeclaration(ArenaVector &statements); void CollectDefaultSources(); std::string ResolveImportPath(const std::string &path); + std::string ResolveFullPathFromRelative(const std::string &path); ImportData GetImportData(const std::string &path); std::tuple, bool> CollectUserSources(const std::string &path); + std::tuple GetSourceRegularPath(const std::string &path, const std::string &resolved_path); void ParseSources(const std::vector &paths, bool is_external = true); std::tuple> ParseFromClause(bool require_from); void ParseNamedImportSpecifiers(ArenaVector *specifiers); @@ -328,10 +333,17 @@ private: friend class ExternalSourceParser; friend class InnerSourceParser; +public: + const std::unordered_map &ResolvedParsedSourcesMap() const + { + return resolved_parsed_sources_; + } + private: parser::Program *global_program_; std::vector parsed_sources_; std::vector inserting_nodes_ {}; + std::unordered_map resolved_parsed_sources_; }; class ExternalSourceParser { diff --git a/ets2panda/test/CMakeLists.txt b/ets2panda/test/CMakeLists.txt index a602e480e52b0af635d8bcf31cb82414f9adcf08..ba88fb843fdd08bd7be30b2cd223938012cc7ab1 100644 --- a/ets2panda/test/CMakeLists.txt +++ b/ets2panda/test/CMakeLists.txt @@ -118,3 +118,5 @@ if(PANDA_WITH_ETS) add_subdirectory(tsconfig) endif() + +add_subdirectory(options) diff --git a/ets2panda/test/compiler/ets/extended_conditional_expression_not-expected.txt b/ets2panda/test/compiler/ets/extended_conditional_expression_not-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..60a0330b805d2c13451cd7090c33072d4984b1f5 --- /dev/null +++ b/ets2panda/test/compiler/ets/extended_conditional_expression_not-expected.txt @@ -0,0 +1,444 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "number", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 12 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 12 + }, + "end": { + "line": 16, + "column": 22 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 24 + }, + "end": { + "line": 16, + "column": 27 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "IfStatement", + "test": { + "type": "UnaryExpression", + "operator": "!", + "prefix": true, + "argument": { + "type": "Identifier", + "name": "n", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 11 + } + } + }, + "consequent": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 0, + "loc": { + "start": { + "line": 18, + "column": 16 + }, + "end": { + "line": 18, + "column": 17 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 13 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "alternate": null, + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 20, + "column": 12 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 14 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 28 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 21, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 22, + "column": 1 + } + } +} diff --git a/ets2panda/test/compiler/ets/extended_conditional_expression_not.ets b/ets2panda/test/compiler/ets/extended_conditional_expression_not.ets new file mode 100644 index 0000000000000000000000000000000000000000..a012fda36c85d881ae7b426a4f8b4911515bcc87 --- /dev/null +++ b/ets2panda/test/compiler/ets/extended_conditional_expression_not.ets @@ -0,0 +1,21 @@ +/* + * 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. + */ + +function f(n: number): int { + if (!n) { + return 0; + } + return 1; +} diff --git a/ets2panda/test/compiler/ets/extended_conditional_expression_not_return_type-expected.txt b/ets2panda/test/compiler/ets/extended_conditional_expression_not_return_type-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..80a89ecb8f07b6a5a888052b2eb833e17e1edcc3 --- /dev/null +++ b/ets2panda/test/compiler/ets/extended_conditional_expression_not_return_type-expected.txt @@ -0,0 +1,374 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 15 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 12 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 12 + }, + "end": { + "line": 16, + "column": 22 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 16, + "column": 24 + }, + "end": { + "line": 16, + "column": 31 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "UnaryExpression", + "operator": "!", + "prefix": true, + "argument": { + "type": "Identifier", + "name": "n", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 13 + }, + "end": { + "line": 17, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 12 + }, + "end": { + "line": 17, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 15 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 32 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 18, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 18, + "column": 2 + } + } +} diff --git a/ets2panda/test/compiler/ets/extended_conditional_expression_not_return_type.ets b/ets2panda/test/compiler/ets/extended_conditional_expression_not_return_type.ets new file mode 100644 index 0000000000000000000000000000000000000000..1462fb5522085e9cb34fd2819dad2f339b6a8c23 --- /dev/null +++ b/ets2panda/test/compiler/ets/extended_conditional_expression_not_return_type.ets @@ -0,0 +1,18 @@ +/* + * 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. + */ + +function f(n: string): boolean { + return !n; +} \ No newline at end of file diff --git a/ets2panda/test/options/CMakeLists.txt b/ets2panda/test/options/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd46aabd24b3a973ddc8c820bc2c5ce49e6e2a7f --- /dev/null +++ b/ets2panda/test/options/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) 2021-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. + +if(CMAKE_CROSSCOMPILING) + return() +endif() + +add_custom_target(es2panda_tests_options) +add_dependencies(es2panda_tests es2panda_tests_options) + +function(check_option_help_otput target_name INPUT_ARGS OUTPUT_HELP_LINE) + separate_arguments(INPUT_ARGS) + add_custom_target(es2panda_check_opts_${target_name} + COMMENT "es2panda: checking option ${INPUT_ARGS}" + COMMAND es2panda ${INPUT_ARGS} 2> ${CMAKE_BINARY_DIR}/es2panda_check_opts_${target_name}.out || true + COMMAND grep -q ${OUTPUT_HELP_LINE} ${CMAKE_BINARY_DIR}/es2panda_check_opts_${target_name}.out + DEPENDS es2panda + ) + + add_dependencies(es2panda_tests_options es2panda_check_opts_${target_name}) +endfunction() + +check_option_help_otput(bco_opt "--help" "bco-optimizer:") +check_option_help_otput(bco_opt_help "--bco-optimizer --help" "bytecode-opt-peepholes:") +check_option_help_otput(comp_opt "--help" "bco-compiler:") +check_option_help_otput(comp_opt_help "--bco-compiler --help" "compiler-disasm-dump:") diff --git a/ets2panda/test/parser/ets/import_tests/import_diff_paths-expected.txt b/ets2panda/test/parser/ets/import_tests/import_diff_paths-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..36509b55153e8311516dca72e239119504b13963 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_diff_paths-expected.txt @@ -0,0 +1,491 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./modules", + "loc": { + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 16, + "column": 40 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "imported": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 40 + } + } + }, + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./modules", + "loc": { + "start": { + "line": 17, + "column": 19 + }, + "end": { + "line": 17, + "column": 40 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 11 + } + } + }, + "imported": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 40 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 10 + }, + "end": { + "line": 19, + "column": 14 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 10 + }, + "end": { + "line": 19, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 6 + } + } + }, + "arguments": [ + { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 13 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 20, + "column": 7 + }, + "end": { + "line": 20, + "column": 15 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 5 + }, + "end": { + "line": 20, + "column": 16 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 14 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 14 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 21, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 21, + "column": 2 + } + } +} diff --git a/ets2panda/test/parser/ets/import_tests/import_diff_paths.ets b/ets2panda/test/parser/ets/import_tests/import_diff_paths.ets new file mode 100644 index 0000000000000000000000000000000000000000..b768dbc1fc517af0a86ca3eb0b19f77873d6b0cf --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/import_diff_paths.ets @@ -0,0 +1,21 @@ +/* + * 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 { C } from "./modules/test_lib1" +import { f } from "./modules/test_lib2" + +function main() { + f(new C()); +} \ No newline at end of file diff --git a/ets2panda/test/parser/ets/import_tests/modules/test_lib1-expected.txt b/ets2panda/test/parser/ets/import_tests/modules/test_lib1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..8386d8940fdfa9763ec4838ac085a8774aca2486 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/modules/test_lib1-expected.txt @@ -0,0 +1,290 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 14 + }, + "end": { + "line": 16, + "column": 15 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 16 + }, + "end": { + "line": 16, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 8 + }, + "end": { + "line": 16, + "column": 18 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 18, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/import_tests/modules/test_lib1.ets b/ets2panda/test/parser/ets/import_tests/modules/test_lib1.ets new file mode 100644 index 0000000000000000000000000000000000000000..03521fe13593e1469c909510dd335ce508a94cc4 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/modules/test_lib1.ets @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export class C {} + diff --git a/ets2panda/test/parser/ets/import_tests/modules/test_lib2-expected.txt b/ets2panda/test/parser/ets/import_tests/modules/test_lib2-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..51e505772ffa256ffde70ae899396377f0748de7 --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/modules/test_lib2-expected.txt @@ -0,0 +1,389 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./", + "loc": { + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "imported": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + }, + "loc": { + "start": { + "line": 16, + "column": 10 + }, + "end": { + "line": 16, + "column": 11 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 32 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "f", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "ETSParameterExpression", + "name": { + "type": "Identifier", + "name": "c", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 19 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 19 + }, + "end": { + "line": 17, + "column": 24 + } + } + } + ], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 17, + "column": 25 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 17, + "column": 27 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 19, + "column": 1 + } + } +} diff --git a/ets2panda/test/parser/ets/import_tests/modules/test_lib2.ets b/ets2panda/test/parser/ets/import_tests/modules/test_lib2.ets new file mode 100644 index 0000000000000000000000000000000000000000..858acdc0f8047a12b81fb01915405adba4fa3b0a --- /dev/null +++ b/ets2panda/test/parser/ets/import_tests/modules/test_lib2.ets @@ -0,0 +1,18 @@ +/* + * 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 { C } from "./test_lib1" +export function f(c: C) {} + diff --git a/ets2panda/test/runtime/ets/StringBase64.ets b/ets2panda/test/runtime/ets/StringBase64.ets index 17e894db3d19df9f7cf25ab5aa797c8f813d13d0..ebca0d923bae6144cba88c3a8c91888ddf41cc3d 100644 --- a/ets2panda/test/runtime/ets/StringBase64.ets +++ b/ets2panda/test/runtime/ets/StringBase64.ets @@ -67,7 +67,7 @@ export class StringBase64 { } return result.toString(); } - n1 : int = 8192; + n1 : int = 4096; n2 : int = 16384; public run(): void { let str : String = ""; diff --git a/ets2panda/test/runtime/ets/condition-with-boolean-reference.ets b/ets2panda/test/runtime/ets/condition-with-boolean-reference.ets index afeab4d42883c20242e0282d38709e2920672987..1acb9754930406a5667c16a6545c776d8dec84ac 100644 --- a/ets2panda/test/runtime/ets/condition-with-boolean-reference.ets +++ b/ets2panda/test/runtime/ets/condition-with-boolean-reference.ets @@ -14,7 +14,7 @@ */ function main() : void { - let cond: Boolean = true; + let cond: boolean = true; // Check conditional expression let a: String = "foo"; @@ -39,13 +39,14 @@ function main() : void { assert(i == 3); // Check while statement - while (cond) { - cond = false; + let while_cond = true + while (while_cond) { + while_cond = !cond; } - assert (cond == false); + assert (while_cond == false); // Check do-while statement do { - assert (cond == false); - } while (cond); + assert (while_cond == false); + } while (while_cond); } diff --git a/ets2panda/test/runtime/ets/conversion-char-boolean.ets b/ets2panda/test/runtime/ets/conversion-char-boolean.ets index baa0ddaf614ab8e97a99219405246df2547f0e43..76f9ea8e29cc817dac783009e3bda81123d9b699 100644 --- a/ets2panda/test/runtime/ets/conversion-char-boolean.ets +++ b/ets2panda/test/runtime/ets/conversion-char-boolean.ets @@ -20,7 +20,7 @@ function check(): Boolean { function main(): void { let x: Boolean = false; - assert !(x && check()); + assert (x || check()); let y: Char = c'a'; assert (y != c'b'); diff --git a/ets2panda/test/runtime/ets/exdended_conditional_expression_float.ets b/ets2panda/test/runtime/ets/exdended_conditional_expression_float.ets new file mode 100644 index 0000000000000000000000000000000000000000..1d07e495518354a1bbedce318bfb96313ac43886 --- /dev/null +++ b/ets2panda/test/runtime/ets/exdended_conditional_expression_float.ets @@ -0,0 +1,19 @@ +/* + * 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. + */ + +function main(): int { + let res: int = 0.1 ? 0 : 1 + return res +} \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/extended_conditional_expression_string.ets b/ets2panda/test/runtime/ets/extended_conditional_expression_string.ets new file mode 100644 index 0000000000000000000000000000000000000000..f02379770060f14cd733ca1f152b4bf454508f46 --- /dev/null +++ b/ets2panda/test/runtime/ets/extended_conditional_expression_string.ets @@ -0,0 +1,32 @@ +/* + * 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. + */ + +function fun(s: Object) : boolean { + if (s) { + return true; + } else { + return false; + } +} + + +function main(): int { + let emptyString = ""; + if (fun(emptyString)) { + return 1; + } else { + return 0 + } +} \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/unboxingBooleanConversion.ets b/ets2panda/test/runtime/ets/unboxingBooleanConversion.ets index 4ee6904ae13e4915f4f2a1e0a5dd715bec9705a6..23ae74c084ab06775be988e3359841dcce893b3c 100644 --- a/ets2panda/test/runtime/ets/unboxingBooleanConversion.ets +++ b/ets2panda/test/runtime/ets/unboxingBooleanConversion.ets @@ -24,7 +24,7 @@ function returnRefBool(a: boolean): Boolean { function main(): void { let a: Boolean = false; - let b: Boolean = a || returnTrue(); + let b: Boolean = a && returnTrue(); assert b == true let c: Boolean = returnRefBool(a || returnRefBool(returnTrue() && returnRefBool(a))); diff --git a/ets2panda/util/helpers.cpp b/ets2panda/util/helpers.cpp index aafd8d43e718abdef49471b48b332b09d574e6cc..b1f4abe0f922c5c9d3b8254d34c7016f3ec9581a 100644 --- a/ets2panda/util/helpers.cpp +++ b/ets2panda/util/helpers.cpp @@ -43,6 +43,7 @@ #include "ir/module/importDeclaration.h" #include "lexer/token/letters.h" #include "libpandabase/utils/utf.h" +#include "libpandabase/os/filesystem.h" namespace panda::es2panda::util { // Helpers @@ -169,6 +170,40 @@ bool Helpers::IsRelativePath(const std::string &path) return ((path.find(current_dir_reference) == 0) || (path.find(parent_dir_reference) == 0)); } +std::string Helpers::GetAbsPath(const std::string &path) +{ + std::string full_file_path = path; + std::string import_extension; + if (!panda::os::file::File::IsRegularFile(path) && (panda::os::GetAbsolutePath(path).empty())) { + import_extension = ".ets"; + full_file_path = path + import_extension; + if (!panda::os::file::File::IsRegularFile(full_file_path)) { + import_extension = ".ts"; + full_file_path = path + import_extension; + if (!panda::os::file::File::IsRegularFile(full_file_path)) { + return path; + } + } + } + std::string abs_file_path = panda::os::GetAbsolutePath(full_file_path); + abs_file_path.erase(abs_file_path.find(import_extension), import_extension.size()); + return abs_file_path; +} + +bool Helpers::IsRealPath(const std::string &path) +{ + if (!panda::os::file::File::IsRegularFile(path) && (panda::os::GetAbsolutePath(path).empty())) { + auto import_extension = ".ets"; + if (!panda::os::file::File::IsRegularFile(path + import_extension)) { + import_extension = ".ts"; + if (!panda::os::file::File::IsRegularFile(path + import_extension)) { + return false; + } + } + } + return true; +} + const ir::ScriptFunction *Helpers::GetContainingConstructor(const ir::AstNode *node) { const ir::ScriptFunction *iter = GetContainingFunction(node); diff --git a/ets2panda/util/helpers.h b/ets2panda/util/helpers.h index 2611e7914153a1febb170e0ce3c5d93883de6292..bd32ed03a52f53ddab63ad9ec57bdb8bb4cf6f15 100644 --- a/ets2panda/util/helpers.h +++ b/ets2panda/util/helpers.h @@ -79,6 +79,8 @@ public: static util::StringView ToStringView(ArenaAllocator *allocator, int32_t number); static util::StringView ToStringView(ArenaAllocator *allocator, uint32_t number); static bool IsRelativePath(const std::string &path); + static bool IsRealPath(const std::string &path); + static std::string GetAbsPath(const std::string &path); static const ir::ScriptFunction *GetContainingConstructor(const ir::AstNode *node); static const ir::ScriptFunction *GetContainingConstructor(const ir::ClassProperty *node); diff --git a/ets2panda/util/options.cpp b/ets2panda/util/options.cpp index c7f2350ca873daa63d904e6b08960356591d56f9..60e35b3075d7159197182ee00774dec4786a07f9 100644 --- a/ets2panda/util/options.cpp +++ b/ets2panda/util/options.cpp @@ -19,6 +19,11 @@ #include +#ifdef PANDA_WITH_BYTECODE_OPTIMIZER +#include "bytecode_optimizer/bytecodeopt_options.h" +#include "compiler/compiler_options.h" +#endif + namespace panda::es2panda::util { template T RemoveExtension(T const &filename) @@ -55,9 +60,84 @@ static std::unordered_set StringToStringSet(const std::string &str) return res; } +// NOLINTNEXTLINE(modernize-avoid-c-arrays, hicpp-avoid-c-arrays) +static void SplitArgs(int argc, const char *argv[], std::vector &es2panda_args, + std::vector &bco_compiler_args, std::vector &bytecodeopt_args) +{ + constexpr std::string_view COMPILER_PREFIX = "--bco-compiler"; + constexpr std::string_view OPTIMIZER_PREFIX = "--bco-optimizer"; + + enum class OptState { ES2PANDA, JIT_COMPILER, OPTIMIZER }; + OptState opt_state = OptState::ES2PANDA; + + std::unordered_map *> args_map = {{OptState::ES2PANDA, &es2panda_args}, + {OptState::JIT_COMPILER, &bco_compiler_args}, + {OptState::OPTIMIZER, &bytecodeopt_args}}; + + for (int i = 1; i < argc; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + const char *arg_i = argv[i]; + if (COMPILER_PREFIX == arg_i) { + opt_state = OptState::JIT_COMPILER; + continue; + } + + if (OPTIMIZER_PREFIX == arg_i) { + opt_state = OptState::OPTIMIZER; + continue; + } + + args_map[opt_state]->emplace_back(arg_i); + opt_state = OptState::ES2PANDA; + } +} + +template +static bool ParseComponentArgs(const std::vector &args, T &options) +{ + panda::PandArgParser parser; + options.AddOptions(&parser); + if (!parser.Parse(args)) { + std::cerr << parser.GetErrorString(); + std::cerr << parser.GetHelpString(); + return false; + } + + if (auto options_err = options.Validate(); options_err) { + std::cerr << "Error: " << options_err.value().GetMessage() << std::endl; + return false; + } + + return true; +} + +static bool ParseBCOCompilerOptions([[maybe_unused]] const std::vector &compiler_args, + [[maybe_unused]] const std::vector &bytecodeopt_args) +{ +#ifdef PANDA_WITH_BYTECODE_OPTIMIZER + if (!ParseComponentArgs(compiler_args, panda::compiler::OPTIONS)) { + return false; + } + if (!ParseComponentArgs(bytecodeopt_args, panda::bytecodeopt::OPTIONS)) { + return false; + } +#endif + + return true; +} + // NOLINTNEXTLINE(readability-function-size) bool Options::Parse(int argc, const char **argv) { + std::vector es2panda_args; + std::vector bco_compiler_args; + std::vector bytecodeopt_args; + + SplitArgs(argc, argv, es2panda_args, bco_compiler_args, bytecodeopt_args); + if (!ParseBCOCompilerOptions(bco_compiler_args, bytecodeopt_args)) { + return false; + } + panda::PandArg op_help("help", false, "Print this message and exit"); // parser @@ -128,7 +208,7 @@ bool Options::Parse(int argc, const char **argv) argparser_->EnableTail(); argparser_->EnableRemainder(); - if (!argparser_->Parse(argc, argv) || op_help.GetValue()) { + if (!argparser_->Parse(es2panda_args) || op_help.GetValue()) { std::stringstream ss; ss << argparser_->GetErrorString() << std::endl; @@ -139,6 +219,12 @@ bool Options::Parse(int argc, const char **argv) ss << "optional arguments:" << std::endl; ss << argparser_->GetHelpString() << std::endl; + ss << std::endl; + ss << "--bco-optimizer: Argument directly to bytecode optimizer can be passed after this prefix" << std::endl; + ss << "--bco-compiler: Argument directly to jit-compiler inside bytecode optimizer can be passed after this " + "prefix" + << std::endl; + error_msg_ = ss.str(); return false; } diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index d12f33d16ebc46442351abaf4cbce8080d666b16..61c93cd5b95543c6bf55f05b30c6d8353eeb0630 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -582,6 +582,23 @@ varbinder::Variable *ETSBinder::FindStaticBinding(const ArenaVectorsecond; } +ArenaVector ETSBinder::GetExternalProgram(const util::StringView &source_name, + const ir::StringLiteral *import_path) +{ + const auto &ext_records = global_record_table_.Program()->ExternalSources(); + auto record_res = [this, ext_records, source_name]() { + auto res = ext_records.find(source_name); + return (res != ext_records.end()) ? res : ext_records.find(GetResolvedImportPath(source_name)); + }(); + if (record_res == ext_records.end()) { + ThrowError(import_path->Start(), "Cannot find import: " + std::string(source_name)); + } + + ASSERT(!record_res->second.empty()); + + return record_res->second; +} + void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const ir::ETSImportDeclaration *const import) { const ir::StringLiteral *const import_path = import->Source(); @@ -591,18 +608,20 @@ void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const i return; } - const auto &ext_records = global_record_table_.Program()->ExternalSources(); - const util::StringView source_name = - (import->Module() == nullptr) - ? import_path->Str() - : util::UString(import_path->Str().Mutf8() + import->Module()->Str().Mutf8(), Allocator()).View(); - const auto record_res = ext_records.find(source_name); - if (record_res == ext_records.end()) { - ThrowError(import_path->Start(), "Cannot find import: " + std::string(source_name)); - } + const util::StringView source_name = [import, import_path, this]() { + if (import->Module() == nullptr) { + return import_path->Str(); + } + char path_delimiter = panda::os::file::File::GetPathDelim().at(0); + auto str_import_path = import_path->Str().Mutf8(); + if (str_import_path.find(path_delimiter) == (str_import_path.size() - 1)) { + return util::UString(str_import_path + import->Module()->Str().Mutf8(), Allocator()).View(); + } + return util::UString(str_import_path + path_delimiter + import->Module()->Str().Mutf8(), Allocator()).View(); + }(); - ASSERT(!record_res->second.empty()); - const auto *const import_program = record_res->second.front(); + auto record = GetExternalProgram(source_name, import_path); + const auto *const import_program = record.front(); const auto *const import_global_scope = import_program->GlobalScope(); const auto &global_bindings = import_global_scope->Bindings(); @@ -618,7 +637,7 @@ void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const i return; } - if (AddImportSpecifiersToTopBindings(specifier, global_bindings, import, record_res->second)) { + if (AddImportSpecifiersToTopBindings(specifier, global_bindings, import, record)) { return; } @@ -628,7 +647,7 @@ void ETSBinder::AddSpecifiersToTopBindings(ir::AstNode *const specifier, const i auto item = std::find_if(global_bindings.begin(), global_bindings.end(), predicate_func); if (item == global_bindings.end()) { insert_foreign_binding(specifier->AsImportDefaultSpecifier()->Local()->Name(), - FindStaticBinding(record_res->second, import_path)); + FindStaticBinding(record, import_path)); return; } diff --git a/ets2panda/varbinder/ETSBinder.h b/ets2panda/varbinder/ETSBinder.h index 82f49cd9ae5f2af13edfb44d2e5ef50da9a4109b..48d7cf964ec457b0a99015b9c082b3f6925b2ac5 100644 --- a/ets2panda/varbinder/ETSBinder.h +++ b/ets2panda/varbinder/ETSBinder.h @@ -43,7 +43,8 @@ public: dynamic_imports_(Allocator()->Adapter()), lambda_objects_(Allocator()->Adapter()), dynamic_import_vars_(Allocator()->Adapter()), - import_specifiers_(Allocator()->Adapter()) + import_specifiers_(Allocator()->Adapter()), + resolved_import_pathes_map_(Allocator()->Adapter()) { InitImplicitThisParam(); } @@ -119,6 +120,8 @@ public: void BuildImportDeclaration(ir::ETSImportDeclaration *decl); void BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *class_instance); void AddSpecifiersToTopBindings(ir::AstNode *specifier, const ir::ETSImportDeclaration *import); + ArenaVector GetExternalProgram(const util::StringView &source_name, + const ir::StringLiteral *import_path); bool AddImportNamespaceSpecifiersToTopBindings(ir::AstNode *specifier, const varbinder::Scope::VariableMap &global_bindings, const parser::Program *import_program, @@ -184,6 +187,26 @@ public: default_export_ = default_export; } + const ArenaUnorderedMap &ResolvedImportPathesMap() const + { + return resolved_import_pathes_map_; + } + + const util::StringView &GetResolvedImportPath(const util::StringView &path) const + { + ASSERT(resolved_import_pathes_map_.find(path) != resolved_import_pathes_map_.end()); + + return resolved_import_pathes_map_.find(path)->second; + } + + void FillResolvedImportPathes(const std::unordered_map &map, ArenaAllocator *allocator) + { + for (const auto &path : map) { + resolved_import_pathes_map_.emplace(util::UString(path.first, allocator).View(), + util::UString(path.second, allocator).View()); + } + } + bool IsDynamicModuleVariable(const Variable *var) const; bool IsDynamicNamespaceVariable(const Variable *var) const; const DynamicImportData *DynamicImportDataForVar(const Variable *var) const; @@ -218,6 +241,7 @@ private: DynamicImportVariables dynamic_import_vars_; ir::Identifier *this_param_ {}; ArenaVector> import_specifiers_; + ArenaUnorderedMap resolved_import_pathes_map_; ir::AstNode *default_export_ {}; };