diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 3bfaa37676..39d72d6154 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -280,6 +280,7 @@ RUN(NAME variable_decl_02 LABELS cpython llvm c) RUN(NAME variable_decl_03 LABELS cpython llvm c) RUN(NAME array_expr_01 LABELS cpython llvm c) RUN(NAME array_expr_02 LABELS cpython llvm c) +RUN(NAME array_size_01 LABELS cpython llvm c) RUN(NAME array_01 LABELS cpython llvm wasm c) RUN(NAME array_02 LABELS cpython wasm c) RUN(NAME bindc_01 LABELS cpython llvm c) diff --git a/integration_tests/array_size_01.py b/integration_tests/array_size_01.py new file mode 100644 index 0000000000..bfa33f9eac --- /dev/null +++ b/integration_tests/array_size_01.py @@ -0,0 +1,23 @@ +from lpython import i32, f64, c32, c64 +from numpy import empty + +def main0(): + x: i32[4, 5, 2] = empty([4, 5, 2]) + y: f64[24, 100, 2, 5] = empty([24, 100, 2, 5]) + print(x.size) + print(y.size) + + assert x.size == 40 + assert y.size == 24000 + +def main1(): + a: c32[12] = empty([12]) + b: c64[15, 15, 10] = empty([15, 15, 10]) + print(a.size) + print(b.size) + + assert a.size == 12 + assert b.size == 2250 + +main0() +main1() diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index df6cf54bb6..c954ef6405 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -5137,7 +5137,13 @@ class BodyVisitor : public CommonVisitor { void visit_AttributeUtil(ASR::ttype_t* type, char* attr_char, ASR::symbol_t *t, const Location& loc) { - if (ASRUtils::is_complex(*type)) { + if (ASRUtils::is_array(type)) { + std::string attr = attr_char; + ASR::expr_t *se = ASR::down_cast(ASR::make_Var_t(al, loc, t)); + Vec args; + args.reserve(al, 0); + handle_attribute(se, attr, loc, args); + } else if (ASRUtils::is_complex(*type)) { std::string attr = attr_char; if (attr == "imag") { ASR::expr_t *val = ASR::down_cast(ASR::make_Var_t(al, loc, t)); @@ -6705,7 +6711,7 @@ class BodyVisitor : public CommonVisitor { ASRUtils::IntrinsicFunctionRegistry::get_create_function(call_name); Vec args_; args_.reserve(al, x.n_args); visit_expr_list(x.m_args, x.n_args, args_); - if (ASRUtils::is_array(ASRUtils::expr_type(args_[0])) && + if (ASRUtils::is_array(ASRUtils::expr_type(args_[0])) && imported_functions[call_name] == "math" ) { throw SemanticError("Function '" + call_name + "' does not accept vector values", x.base.base.loc); @@ -6737,21 +6743,19 @@ class BodyVisitor : public CommonVisitor { // This will all be removed once we port it to intrinsic functions // Intrinsic functions if (call_name == "size") { - // TODO: size should be part of ASR. That way - // ASR itself does not need a runtime library - // a runtime library thus becomes optional --- can either be - // implemented using ASR, or the backend can link it at runtime - ASR::ttype_t *a_type = ASRUtils::TYPE(ASR::make_Integer_t(al, x.base.base.loc, - 4, nullptr, 0)); - /* - ASR::symbol_t *a_name = nullptr; - throw SemanticError("TODO: add the size() function and look it up", - x.base.base.loc); - tmp = ASR::make_FunctionCall_t(al, x.base.base.loc, a_name, - nullptr, args.p, args.size(), nullptr, 0, a_type, nullptr, nullptr); - */ - - tmp = ASR::make_IntegerConstant_t(al, x.base.base.loc, 1234, a_type); + parse_args(); + if( args.size() < 1 || args.size() > 2 ) { + throw SemanticError("array accepts only 1 (arr) or 2 (arr, axis) arguments, got " + + std::to_string(args.size()) + " arguments instead.", + x.base.base.loc); + } + ASR::expr_t *var = args[0].m_value; + ASR::expr_t *dim = nullptr; + if (args.size() == 2) { + dim = args[1].m_value; + } + ASR::ttype_t *int_type = ASRUtils::TYPE(ASR::make_Integer_t(al, x.base.base.loc, 4, nullptr, 0)); + tmp = ASR::make_ArraySize_t(al, x.base.base.loc, var, dim, int_type, nullptr); return; } else if (call_name == "empty") { // TODO: check that the `empty` arguments are compatible diff --git a/src/lpython/semantics/python_attribute_eval.h b/src/lpython/semantics/python_attribute_eval.h index 14348ce91f..80d8181400 100644 --- a/src/lpython/semantics/python_attribute_eval.h +++ b/src/lpython/semantics/python_attribute_eval.h @@ -20,6 +20,7 @@ struct AttributeHandler { AttributeHandler() { attribute_map = { {"int@bit_length", &eval_int_bit_length}, + {"array@size", &eval_array_size}, {"list@append", &eval_list_append}, {"list@remove", &eval_list_remove}, {"list@count", &eval_list_count}, @@ -42,6 +43,8 @@ struct AttributeHandler { return "set"; } else if (ASR::is_a(*t)) { return "dict"; + } else if (ASRUtils::is_array(t)) { + return "array"; } else if (ASR::is_a(*t)) { return "int"; } @@ -55,7 +58,7 @@ struct AttributeHandler { if (class_name == "") { throw SemanticError("Type name is not implemented yet.", loc); } - std::string key = get_type_name(type) + "@" + attr_name; + std::string key = class_name + "@" + attr_name; auto search = attribute_map.find(key); if (search != attribute_map.end()) { attribute_eval_callback cb = search->second; @@ -77,6 +80,15 @@ struct AttributeHandler { return ASR::make_IntegerBitLen_t(al, loc, s, int_type, nullptr); } + static ASR::asr_t* eval_array_size(ASR::expr_t *s, Allocator &al, const Location &loc, + Vec &args, diag::Diagnostics &/*diag*/) { + if (args.size() != 0) { + throw SemanticError("array.size() takes no arguments", loc); + } + ASR::ttype_t *int_type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, 4, nullptr, 0)); + return ASR::make_ArraySize_t(al, loc, s, nullptr, int_type, nullptr); + } + static ASR::asr_t* eval_list_append(ASR::expr_t *s, Allocator &al, const Location &loc, Vec &args, diag::Diagnostics &diag) { if (args.size() != 1) { diff --git a/tests/reference/asr-doconcurrentloop_01-7b9a7d3.json b/tests/reference/asr-doconcurrentloop_01-7b9a7d3.json index 264a2b31c2..2172b53c7b 100644 --- a/tests/reference/asr-doconcurrentloop_01-7b9a7d3.json +++ b/tests/reference/asr-doconcurrentloop_01-7b9a7d3.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "asr-doconcurrentloop_01-7b9a7d3.stdout", - "stdout_hash": "dffb1f7233f48b1711345ac6d1649bfdc6d8244f5596e9a2a9144904", + "stdout_hash": "9519c801f6f3612439fef115f1c30385234060565a7dd07e125685a4", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/asr-doconcurrentloop_01-7b9a7d3.stdout b/tests/reference/asr-doconcurrentloop_01-7b9a7d3.stdout index a9da9d9d91..81ce8cdc3c 100644 --- a/tests/reference/asr-doconcurrentloop_01-7b9a7d3.stdout +++ b/tests/reference/asr-doconcurrentloop_01-7b9a7d3.stdout @@ -179,7 +179,12 @@ ) (= (Var 3 nsize) - (IntegerConstant 1234 (Integer 4 [])) + (ArraySize + (Var 3 a) + () + (Integer 4 []) + () + ) () ) (DoConcurrentLoop @@ -394,7 +399,12 @@ (Var 2 c)] [(= (Var 2 N) - (IntegerConstant 1234 (Integer 4 [])) + (ArraySize + (Var 2 a) + () + (Integer 4 []) + () + ) () ) (DoConcurrentLoop diff --git a/tests/reference/cpp-doconcurrentloop_01-4e9f274.json b/tests/reference/cpp-doconcurrentloop_01-4e9f274.json index 54fae042ca..90dec8ce2a 100644 --- a/tests/reference/cpp-doconcurrentloop_01-4e9f274.json +++ b/tests/reference/cpp-doconcurrentloop_01-4e9f274.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "cpp-doconcurrentloop_01-4e9f274.stdout", - "stdout_hash": "ee58f996458bdf91f906f012b009681a568ad314c5907d9a698e41b8", + "stdout_hash": "79dc6e24e5f0c768ebbadd5b3bd466b53e1b89608b2d1e1a4a0d4caf", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/cpp-doconcurrentloop_01-4e9f274.stdout b/tests/reference/cpp-doconcurrentloop_01-4e9f274.stdout index 1c630b6cb0..d8612b3a9e 100644 --- a/tests/reference/cpp-doconcurrentloop_01-4e9f274.stdout +++ b/tests/reference/cpp-doconcurrentloop_01-4e9f274.stdout @@ -48,7 +48,7 @@ void triad(T0* a, T1* b, float scalar, T2* c) { int32_t N; int32_t i; - N = 1234; + N = a->data->extent(0); Kokkos::parallel_for(Kokkos::RangePolicy(0, N - 1+1), KOKKOS_LAMBDA(const long i) { c->data->operator[](i - c->dims[0].lower_bound) = a->data->operator[](i - a->dims[0].lower_bound) + scalar*b->data->operator[](i - b->dims[0].lower_bound); }); @@ -75,7 +75,7 @@ void main0() int32_t nsize; float scalar; scalar = 1.00000000000000000e+01; - nsize = 1234; + nsize = a->data->extent(0); Kokkos::parallel_for(Kokkos::RangePolicy(0, nsize - 1+1), KOKKOS_LAMBDA(const long i) { a->data->operator[](i - a->dims[0].lower_bound) = 5.00000000000000000e+00; b->data->operator[](i - b->dims[0].lower_bound) = 5.00000000000000000e+00;