diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index d5af2946f7..0adf602c97 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -1523,8 +1523,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_ListItem(const ASR::ListItem_t& x) { - ASR::ttype_t* el_type = ASRUtils::get_contained_type( - ASRUtils::expr_type(x.m_a)); + /* Check whether the `list` is a `Const[list[data_type]]`: + - If true, set the list `el_type` to `data_type` by first going to `Const`, then `list`. + - If false, we have a normal list - `list[data_type]`, go to `list` and get `data_type`. + + We do the type checking through strings because `ASR::is_a` throws an error. + */ + ASR::ttype_t *el_type = ASRUtils::type_to_str(ASRUtils::expr_type(x.m_a)) == "list const" + ? ASRUtils::get_contained_type(ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_a))) + : ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_a)); int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); @@ -1540,8 +1547,16 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_DictItem(const ASR::DictItem_t& x) { - ASR::Dict_t* dict_type = ASR::down_cast( - ASRUtils::expr_type(x.m_a)); + /* Check whether the `dict` is a `Const[dict[key_type, value_type]]`: + - If true, set the `dict_type` to `dict[key_type, value_type]' by going to `Const`. + - If false, we have a normal dict - `dict[key_type, value_type]`. + + We do the type checking through strings because `ASR::is_a` throws an error. + */ + ASR::Dict_t *dict_type = ASRUtils::type_to_str(ASRUtils::expr_type(x.m_a)) == "dict const" + ? ASR::down_cast(ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_a))) + : ASR::down_cast(ASRUtils::expr_type(x.m_a)); + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 4e11fe01ed..71d412cc14 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -1750,7 +1750,13 @@ class CommonVisitor : public AST::BaseVisitor { } else if (var_annotation == "Const") { ASR::ttype_t *type = ast_expr_to_asr_type(loc, *s->m_slice, is_allocatable, raise_error, abi, is_argument); - return ASRUtils::TYPE(ASR::make_Const_t(al, loc, type)); + if (ASRUtils::type_to_str(type) == "tuple") { + throw SemanticError("'Const' not required as tuples are already immutable", loc); + } + else if (ASRUtils::type_to_str(type) == "character") { + throw SemanticError("'Const' not required as strings are already immutable", loc); + } + return ASRUtils::TYPE(ASR::make_Const_t(al, loc, type)); } else { AST::expr_t* dim_info = s->m_slice; @@ -3680,7 +3686,8 @@ class CommonVisitor : public AST::BaseVisitor { ai.m_left = nullptr; ai.m_right = nullptr; ai.m_step = nullptr; - if (AST::is_a(*m_slice)) { + if (AST::is_a(*m_slice)) + { AST::Slice_t *sl = AST::down_cast(m_slice); if (sl->m_lower != nullptr) { this->visit_expr(*sl->m_lower); @@ -3720,7 +3727,14 @@ class CommonVisitor : public AST::BaseVisitor { ai.m_step == nullptr && ai.m_right != nullptr); } - if (ASR::is_a(*type)) { + if (ASR::is_a(*type)) + { + if (ASRUtils::type_to_str(ASRUtils::get_contained_type(type)) == "list") + { + throw SemanticError("slicing on a const list is not implemented till now", loc); + } + } + else if (ASR::is_a(*type)) { tmp = ASR::make_ListSection_t(al, loc, value, ai, type, nullptr); return false; } else if (ASR::is_a(*type)) { @@ -3730,8 +3744,9 @@ class CommonVisitor : public AST::BaseVisitor { } else if (ASR::is_a(*type)) { throw SemanticError("unhashable type in dict: 'slice'", loc); } - } else if(AST::is_a(*m_slice) && - ASRUtils::is_array(type)) { + } + else if (AST::is_a(*m_slice) && + ASRUtils::is_array(type)) { bool final_result = true; AST::Tuple_t* indices = AST::down_cast(m_slice); for( size_t i = 0; i < indices->n_elts; i++ ) { @@ -3739,8 +3754,45 @@ class CommonVisitor : public AST::BaseVisitor { value, type, is_item, loc); } return final_result; - } else { + } + else + { + ASR::expr_t *index = nullptr; this->visit_expr(*m_slice); + if (ASR::is_a(*type)) + { + ASR::ttype_t *contained_type = ASRUtils::type_get_past_const(type); + if (ASR::is_a(*contained_type)) + { + index = ASRUtils::EXPR(tmp); + ASR::ttype_t *key_type = ASR::down_cast(contained_type)->m_key_type; + if (!ASRUtils::check_equal_type(ASRUtils::expr_type(index), key_type)) + { + throw SemanticError("Key type should be '" + ASRUtils::type_to_str_python(key_type) + + "' instead of '" + + ASRUtils::type_to_str_python(ASRUtils::expr_type(index)) + "'", + index->base.loc); + } + tmp = ASR::make_DictItem_t(al, loc, value, index, nullptr, ASR::down_cast(contained_type)->m_value_type, nullptr); + return false; + } + else if (ASR::is_a(*contained_type)) + { + this->visit_expr(*m_slice); + index = ASRUtils::EXPR(tmp); + tmp = make_ListItem_t(al, loc, value, index, + ASR::down_cast(contained_type)->m_type, nullptr); + return false; + } + else if (ASR::is_a(*contained_type)) + { + throw SemanticError("Const not required as strings are already immutable", loc); + } + else if (ASR::is_a(*contained_type)) + { + throw SemanticError("Const not required as tuples are already immutable", loc); + } + } if (!ASR::is_a(*type) && !ASRUtils::is_integer(*ASRUtils::expr_type(ASRUtils::EXPR(tmp)))) { std::string fnd = ASRUtils::type_to_str_python(ASRUtils::expr_type(ASRUtils::EXPR(tmp))); @@ -3753,8 +3805,8 @@ class CommonVisitor : public AST::BaseVisitor { ); throw SemanticAbort(); } - ASR::expr_t *index = nullptr; if (ASR::is_a(*type)) { + this->visit_expr(*m_slice); index = ASRUtils::EXPR(tmp); ASR::ttype_t *key_type = ASR::down_cast(type)->m_key_type; if (!ASRUtils::check_equal_type(ASRUtils::expr_type(index), key_type)) { @@ -3830,7 +3882,8 @@ class CommonVisitor : public AST::BaseVisitor { void visit_Subscript(const AST::Subscript_t &x) { this->visit_expr(*x.m_value); if (using_args_attr) { - if (AST::is_a(*x.m_value)){ + if (AST::is_a(*x.m_value)) + { AST::Attribute_t *attr = AST::down_cast(x.m_value); if (AST::is_a(*attr->m_value)) { AST::Name_t *var_name = AST::down_cast(attr->m_value); @@ -6577,6 +6630,26 @@ class BodyVisitor : public CommonVisitor { arg.loc = loc; arg.m_value = s_var; fn_args.push_back(al, arg); + } else if (attr_name == "isalpha") { + if (args.size() != 0) { + throw SemanticError("str.isalpha() takes no arguments", + loc); + } + fn_call_name = "_lpython_str_isalpha"; + ASR::call_arg_t arg; + arg.loc = loc; + arg.m_value = s_var; + fn_args.push_back(al, arg); + } else if (attr_name == "istitle") { + if (args.size() != 0) { + throw SemanticError("str.istitle() takes no arguments", + loc); + } + fn_call_name = "_lpython_str_istitle"; + ASR::call_arg_t arg; + arg.loc = loc; + arg.m_value = s_var; + fn_args.push_back(al, arg); } else if (attr_name == "title") { if (args.size() != 0) { throw SemanticError("str.title() takes no arguments", @@ -6793,7 +6866,7 @@ class BodyVisitor : public CommonVisitor { /* String Validation Methods i.e all "is" based functions are handled here */ - std::vector validation_methods{"lower", "upper", "decimal", "ascii", "space", "alpha", "title"}; // Database of validation methods supported + std::vector validation_methods{"lower", "upper", "decimal", "ascii", "space"}; // Database of validation methods supported std::string method_name = attr_name.substr(2); if(std::find(validation_methods.begin(),validation_methods.end(), method_name) == validation_methods.end()) { @@ -7096,7 +7169,7 @@ class BodyVisitor : public CommonVisitor { * islower() method is limited to English Alphabets currently * TODO: We can support other characters from Unicode Library */ - std::vector validation_methods{"lower", "upper", "decimal", "ascii", "space", "alpha", "title"}; // Database of validation methods supported + std::vector validation_methods{"lower", "upper", "decimal", "ascii", "space"}; // Database of validation methods supported std::string method_name = attr_name.substr(2); if(std::find(validation_methods.begin(),validation_methods.end(), method_name) == validation_methods.end()) { throw SemanticError("String method not implemented: " + attr_name, loc); @@ -7194,57 +7267,6 @@ we will have to use something else. tmp = ASR::make_LogicalConstant_t(al, loc, is_space, ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4))); return; - } else if (attr_name == "isalpha") { - /* - * Specification - - Return True if all characters in the string are alphabets, - and there is at least one character in the string. - */ - bool is_alpha = (s_var.size() != 0); - for (auto &i : s_var) { - if (!((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z'))) { - is_alpha = false; - break; - } - } - tmp = ASR::make_LogicalConstant_t(al, loc, is_alpha, - ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4))); - return; - } else if (attr_name == "istitle") { - /* - * Specification - - Returns True if all words in the string are in title case, - and there is at least one character in the string. - */ - bool is_title = (s_var.size() != 0); - - bool in_word = false; // Represents if we are in a word or not - bool is_alpha_present = false; - for (auto &i : s_var) { - if (i >= 'A' && i <= 'Z') { - is_alpha_present = true; - if (in_word) { - // We have come across an uppercase character in the middle of a word - is_title = false; - break; - } else { - in_word = true; - } - } else if (i >= 'a' && i <= 'z') { - is_alpha_present = true; - if (!in_word) { - //We have come across a lowercase character at the start of a word - is_title = false; - break; - } - } else { - in_word = false; - } - } - is_title = is_title && is_alpha_present; - tmp = ASR::make_LogicalConstant_t(al, loc, is_title, - ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4))); - return; } else { throw SemanticError("'str' object has no attribute '" + attr_name + "'", loc); }