From a3056f0a744acf40c2b3673bb4d81bb46fa5b656 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Date: Wed, 28 Feb 2024 00:22:44 +0530 Subject: [PATCH 1/5] Add support for accessing values from `Const dict` and `Const list`. --- src/lpython/semantics/python_ast_to_asr.cpp | 121 ++++++++++---------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 4e11fe01ed..c929256fdb 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -3680,7 +3680,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); @@ -3730,8 +3731,10 @@ 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 +3742,40 @@ class CommonVisitor : public AST::BaseVisitor { value, type, is_item, loc); } return final_result; - } else { - this->visit_expr(*m_slice); + } + else + { + ASR::expr_t *index = nullptr; + if (ASR::is_a(*type)) + { + std::cout << "Const: Yes" << std::endl; + ASR::ttype_t *contained_type = ASRUtils::get_contained_type(type); + // Check whether the contained type is a dictionary + if (ASR::is_a(*contained_type)) { + this->visit_expr(*m_slice); + index = ASRUtils::EXPR(tmp); + std::cout << "Dict: Yes" << std::endl; + 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); + }; + std::cout << "value: " << ASRUtils::type_to_str_python(ASRUtils::expr_type(value)) << std::endl; + tmp = 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)) + { + std::cout << "List: Yes" << std::endl; + index = ASRUtils::EXPR(tmp); + tmp = ASR::make_ListSection_t(al, loc, value, ai, type, nullptr); + return false; + } + } 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,7 +3788,6 @@ class CommonVisitor : public AST::BaseVisitor { ); throw SemanticAbort(); } - ASR::expr_t *index = nullptr; if (ASR::is_a(*type)) { index = ASRUtils::EXPR(tmp); ASR::ttype_t *key_type = ASR::down_cast(type)->m_key_type; @@ -6577,6 +6611,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 +6847,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 +7150,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 +7248,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); } From 4776ba90f4b53b8e815f3b214b9bbe93a7e3ea02 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Date: Thu, 29 Feb 2024 20:23:33 +0530 Subject: [PATCH 2/5] Implement item access on `Const dict` & `Const list`, throw error for immutable types like `tuple` and `string`. --- src/libasr/codegen/asr_to_llvm.cpp | 23 +++++++-- src/lpython/semantics/python_ast_to_asr.cpp | 55 +++++++++++++++------ 2 files changed, 59 insertions(+), 19 deletions(-) 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 c929256fdb..0293991f69 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; @@ -3721,7 +3727,19 @@ class CommonVisitor : public AST::BaseVisitor { ai.m_step == nullptr && ai.m_right != nullptr); } - if (ASR::is_a(*type)) { + if (ASR::is_a(*type)) + { + std::cout << ASRUtils::type_to_str(ASRUtils::get_contained_type(type)) << std::endl; + 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 (ASRUtils::type_to_str(ASRUtils::get_contained_type(type)) == "character") + { + throw SemanticError("slicing on a const string 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)) { @@ -3746,15 +3764,13 @@ class CommonVisitor : public AST::BaseVisitor { else { ASR::expr_t *index = nullptr; + this->visit_expr(*m_slice); if (ASR::is_a(*type)) { - std::cout << "Const: Yes" << std::endl; - ASR::ttype_t *contained_type = ASRUtils::get_contained_type(type); - // Check whether the contained type is a dictionary - if (ASR::is_a(*contained_type)) { - this->visit_expr(*m_slice); + ASR::ttype_t *contained_type = ASRUtils::type_get_past_const(type); + if (ASR::is_a(*contained_type)) + { index = ASRUtils::EXPR(tmp); - std::cout << "Dict: Yes" << std::endl; ASR::ttype_t *key_type = ASR::down_cast(contained_type)->m_key_type; if (!ASRUtils::check_equal_type(ASRUtils::expr_type(index), key_type)) { @@ -3762,19 +3778,26 @@ class CommonVisitor : public AST::BaseVisitor { "' instead of '" + ASRUtils::type_to_str_python(ASRUtils::expr_type(index)) + "'", index->base.loc); - }; - std::cout << "value: " << ASRUtils::type_to_str_python(ASRUtils::expr_type(value)) << std::endl; - tmp = make_DictItem_t(al, loc, value, index, nullptr, - ASR::down_cast(contained_type)->m_value_type, nullptr); + } + 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)) { - std::cout << "List: Yes" << std::endl; + this->visit_expr(*m_slice); index = ASRUtils::EXPR(tmp); - tmp = ASR::make_ListSection_t(al, loc, value, ai, type, nullptr); + 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)))) { @@ -3789,6 +3812,7 @@ class CommonVisitor : public AST::BaseVisitor { throw SemanticAbort(); } 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)) { @@ -3864,7 +3888,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); From 2563dc202ad6b991e3b52c14acc4e02f678ed2ec Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Date: Thu, 29 Feb 2024 20:46:37 +0530 Subject: [PATCH 3/5] Remove print statements. --- src/lpython/semantics/python_ast_to_asr.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 0293991f69..7445fad5b1 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -3729,7 +3729,6 @@ class CommonVisitor : public AST::BaseVisitor { } if (ASR::is_a(*type)) { - std::cout << ASRUtils::type_to_str(ASRUtils::get_contained_type(type)) << std::endl; if (ASRUtils::type_to_str(ASRUtils::get_contained_type(type)) == "list") { throw SemanticError("slicing on a const list is not implemented till now", loc); From b4ad727fb779c804e61eef14329fe7ed71dd2504 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar <151380951+kmr-srbh@users.noreply.github.com> Date: Thu, 29 Feb 2024 20:58:58 +0530 Subject: [PATCH 4/5] Trivial code formatting --- src/lpython/semantics/python_ast_to_asr.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 7445fad5b1..104e20721c 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -3750,8 +3750,7 @@ class CommonVisitor : public AST::BaseVisitor { } } else if (AST::is_a(*m_slice) && - ASRUtils::is_array(type)) - { + 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++ ) { From b2c44e9399c61052248e194488d7f15aaf8a26c3 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar <151380951+kmr-srbh@users.noreply.github.com> Date: Thu, 29 Feb 2024 21:03:36 +0530 Subject: [PATCH 5/5] Remove unnecesary error message for slicing on `Const str` --- src/lpython/semantics/python_ast_to_asr.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 104e20721c..71d412cc14 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -3733,10 +3733,6 @@ class CommonVisitor : public AST::BaseVisitor { { throw SemanticError("slicing on a const list is not implemented till now", loc); } - else if (ASRUtils::type_to_str(ASRUtils::get_contained_type(type)) == "character") - { - throw SemanticError("slicing on a const string is not implemented till now", loc); - } } else if (ASR::is_a(*type)) { tmp = ASR::make_ListSection_t(al, loc, value, ai, type, nullptr);