diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 10957e7a47..a18c06df40 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -580,6 +580,8 @@ RUN(NAME structs_26 LABELS cpython llvm c) RUN(NAME structs_27 LABELS cpython llvm c) RUN(NAME symbolics_01 LABELS cpython_sym c_sym) +RUN(NAME symbolics_02 LABELS cpython_sym c_sym) +RUN(NAME symbolics_03 LABELS cpython_sym c_sym) RUN(NAME sizeof_01 LABELS llvm c EXTRAFILES sizeof_01b.c) diff --git a/integration_tests/symbolics_02.py b/integration_tests/symbolics_02.py new file mode 100644 index 0000000000..2bc24e8511 --- /dev/null +++ b/integration_tests/symbolics_02.py @@ -0,0 +1,34 @@ +from sympy import Symbol +from lpython import S + +def test_symbolic_operations(): + x: S = Symbol('x') + y: S = Symbol('y') + + # Addition + z: S = x + y + print(z) # Expected: x + y + + # Subtraction + w: S = x - y + print(w) # Expected: x - y + + # Multiplication + u: S = x * y + print(u) # Expected: x*y + + # Division + v: S = x / y + print(v) # Expected: x/y + + # Power + p: S = x ** y + print(p) # Expected: x**y + + # Casting + a: S = S(100) + b: S = S(-100) + c: S = a + b + print(c) # Expected: 0 + +test_symbolic_operations() diff --git a/integration_tests/symbolics_03.py b/integration_tests/symbolics_03.py new file mode 100644 index 0000000000..12295fd0e7 --- /dev/null +++ b/integration_tests/symbolics_03.py @@ -0,0 +1,21 @@ +from sympy import Symbol, pi +from lpython import S + +def test_operator_chaining(): + w: S = S(2) + x: S = Symbol('x') + y: S = Symbol('y') + z: S = Symbol('z') + Pi: S = Symbol('pi') + + a: S = x * w + b: S = a + Pi + c: S = b / z + d: S = c ** w + + print(a) # Expected: 2*x + print(b) # Expected: pi + 2*x + print(c) # Expected: (pi + 2*x)/z + print(d) # Expected: (pi + 2*x)**2/z**2 + +test_operator_chaining() \ No newline at end of file diff --git a/src/libasr/ASR.asdl b/src/libasr/ASR.asdl index cdd61a49d3..6d92af736d 100644 --- a/src/libasr/ASR.asdl +++ b/src/libasr/ASR.asdl @@ -432,6 +432,7 @@ cast_kind | RealToUnsignedInteger | CPtrToUnsignedInteger | UnsignedIntegerToCPtr + | IntegerToSymbolicExpression dimension = (expr? start, expr? length) diff --git a/src/libasr/asr_utils.cpp b/src/libasr/asr_utils.cpp index f45d232820..00dbbeb540 100644 --- a/src/libasr/asr_utils.cpp +++ b/src/libasr/asr_utils.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace LCompilers { @@ -1196,6 +1197,15 @@ ASR::asr_t* make_Cast_t_value(Allocator &al, const Location &a_loc, double real = value_complex->m_re; value = ASR::down_cast( ASR::make_RealConstant_t(al, a_loc, real, a_type)); + } else if (a_kind == ASR::cast_kindType::IntegerToSymbolicExpression) { + Vec args; + args.reserve(al, 1); + args.push_back(al, a_arg); + LCompilers::ASRUtils::create_intrinsic_function create_function = + LCompilers::ASRUtils::IntrinsicFunctionRegistry::get_create_function("SymbolicInteger"); + value = ASR::down_cast(create_function(al, a_loc, args, + [](const std::string&, const Location&) { + })); } } diff --git a/src/libasr/codegen/asr_to_c_cpp.h b/src/libasr/codegen/asr_to_c_cpp.h index eed27b53cf..903ed5eee9 100644 --- a/src/libasr/codegen/asr_to_c_cpp.h +++ b/src/libasr/codegen/asr_to_c_cpp.h @@ -1634,6 +1634,9 @@ R"(#include last_expr_precedence = 2; break; } + case (ASR::cast_kindType::IntegerToSymbolicExpression): { + break; + } default : throw CodeGenError("Cast kind " + std::to_string(x.m_kind) + " not implemented", x.base.base.loc); } @@ -2382,8 +2385,13 @@ R"(#include SET_INTRINSIC_NAME(Exp2, "exp2"); SET_INTRINSIC_NAME(Expm1, "expm1"); SET_INTRINSIC_NAME(SymbolicSymbol, "Symbol"); + SET_INTRINSIC_NAME(SymbolicInteger, "Integer"); SET_INTRINSIC_NAME(SymbolicPi, "pi"); - case (static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd)): { + case (static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd)): + case (static_cast(ASRUtils::IntrinsicFunctions::SymbolicSub)): + case (static_cast(ASRUtils::IntrinsicFunctions::SymbolicMul)): + case (static_cast(ASRUtils::IntrinsicFunctions::SymbolicDiv)): + case (static_cast(ASRUtils::IntrinsicFunctions::SymbolicPow)): { LCOMPILERS_ASSERT(x.n_args == 2); this->visit_expr(*x.m_args[0]); std::string arg1 = src; @@ -2404,7 +2412,8 @@ R"(#include src = out; } else if (x.n_args == 1) { this->visit_expr(*x.m_args[0]); - if (x.m_intrinsic_id != static_cast(ASRUtils::IntrinsicFunctions::SymbolicSymbol)) { + if ((x.m_intrinsic_id != static_cast(ASRUtils::IntrinsicFunctions::SymbolicSymbol)) && + (x.m_intrinsic_id != static_cast(ASRUtils::IntrinsicFunctions::SymbolicInteger))) { out += "(" + src + ")"; src = out; } diff --git a/src/libasr/codegen/c_utils.h b/src/libasr/codegen/c_utils.h index a8623ff9fe..6b4cfbd601 100644 --- a/src/libasr/codegen/c_utils.h +++ b/src/libasr/codegen/c_utils.h @@ -632,6 +632,14 @@ class CCPPDSUtils { return result; } + std::string generate_binary_operator_code(std::string value, std::string target, std::string operatorName) { + size_t delimiterPos = value.find(","); + std::string leftPart = value.substr(0, delimiterPos); + std::string rightPart = value.substr(delimiterPos + 1); + std::string result = operatorName + "(" + target + ", " + leftPart + ", " + rightPart + ");"; + return result; + } + std::string get_deepcopy_symbolic(ASR::expr_t *value_expr, std::string value, std::string target) { std::string result; if (ASR::is_a(*value_expr)) { @@ -645,22 +653,43 @@ class CCPPDSUtils { break; } case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicAdd: { - size_t delimiterPos = value.find(","); - std::string leftPart = value.substr(0, delimiterPos); - std::string rightPart = value.substr(delimiterPos + 1); - result = "basic_add(" + target + ", " + leftPart + ", " + rightPart + ");"; + result = generate_binary_operator_code(value, target, "basic_add"); + break; + } + case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicSub: { + result = generate_binary_operator_code(value, target, "basic_sub"); + break; + } + case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicMul: { + result = generate_binary_operator_code(value, target, "basic_mul"); + break; + } + case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicDiv: { + result = generate_binary_operator_code(value, target, "basic_div"); + break; + } + case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicPow: { + result = generate_binary_operator_code(value, target, "basic_pow"); break; } case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicPi: { result = "basic_const_pi(" + target + ");"; break; } + case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicInteger: { + result = "integer_set_si(" + target + ", " + value + ");"; + break; + } default: { throw LCompilersException("IntrinsicFunction: `" + LCompilers::ASRUtils::get_intrinsic_name(intrinsic_id) + "` is not implemented"); } } + } else if (ASR::is_a(*value_expr)) { + ASR::Cast_t* cast_expr = ASR::down_cast(value_expr); + std::string cast_value_expr = get_deepcopy_symbolic(cast_expr->m_value, value, target); + return cast_value_expr; } return result; } diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index c52c5fef32..c8914dc736 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -66,7 +66,12 @@ enum class IntrinsicFunctions : int64_t { ListPop, SymbolicSymbol, SymbolicAdd, + SymbolicSub, + SymbolicMul, + SymbolicDiv, + SymbolicPow, SymbolicPi, + SymbolicInteger, Sum, // ... }; @@ -2037,72 +2042,115 @@ namespace SymbolicSymbol { } // namespace SymbolicSymbol -namespace SymbolicAdd { +#define create_symbolic_binop_macro(X) \ +namespace X{ \ + \ + static inline void verify_args(const ASR::IntrinsicFunction_t& x, \ + diag::Diagnostics& diagnostics) { \ + ASRUtils::require_impl(x.n_args == 2, "Intrinsic function `"#X"` accepts \ + exactly 2 arguments", x.base.base.loc, diagnostics); \ + \ + ASR::ttype_t* left_type = ASRUtils::expr_type(x.m_args[0]); \ + ASR::ttype_t* right_type = ASRUtils::expr_type(x.m_args[1]); \ + \ + ASRUtils::require_impl(ASR::is_a(*left_type) && \ + ASR::is_a(*right_type), \ + "Both arguments of `"#X"` must be of type SymbolicExpression", \ + x.base.base.loc, diagnostics); \ + } \ + \ + static inline ASR::expr_t* eval_##X(Allocator &/*al*/, const Location &/*loc*/, \ + Vec &/*args*/) { \ + /*TODO*/ \ + return nullptr; \ + } \ + \ + static inline ASR::asr_t* create_##X(Allocator& al, const Location& loc, \ + Vec& args, \ + const std::function err) { \ + if (args.size() != 2) { \ + err("Intrinsic function `"#X"` accepts exactly 2 arguments", loc); \ + } \ + \ + for (size_t i = 0; i < args.size(); i++) { \ + ASR::ttype_t* argtype = ASRUtils::expr_type(args[i]); \ + if(!ASR::is_a(*argtype)) { \ + err("Arguments of `"#X"` function must be of type SymbolicExpression", \ + args[i]->base.loc); \ + } \ + } \ + \ + Vec arg_values; \ + arg_values.reserve(al, args.size()); \ + for( size_t i = 0; i < args.size(); i++ ) { \ + arg_values.push_back(al, ASRUtils::expr_value(args[i])); \ + } \ + ASR::expr_t* compile_time_value = eval_##X(al, loc, arg_values); \ + ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); \ + return ASR::make_IntrinsicFunction_t(al, loc, \ + static_cast(ASRUtils::IntrinsicFunctions::X), \ + args.p, args.size(), 0, to_type, compile_time_value); \ + } \ +} // namespace X - static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { - ASRUtils::require_impl(x.n_args == 2, "SymbolicAdd must have exactly two arguments", - x.base.base.loc, diagnostics); +create_symbolic_binop_macro(SymbolicAdd) +create_symbolic_binop_macro(SymbolicSub) +create_symbolic_binop_macro(SymbolicMul) +create_symbolic_binop_macro(SymbolicDiv) +create_symbolic_binop_macro(SymbolicPow) - ASR::ttype_t* left_type = ASRUtils::expr_type(x.m_args[0]); - ASR::ttype_t* right_type = ASRUtils::expr_type(x.m_args[1]); +namespace SymbolicPi { - ASRUtils::require_impl(ASR::is_a(*left_type) && - ASR::is_a(*right_type), - "Both arguments of SymbolicAdd must be of type SymbolicExpression", + static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { + ASRUtils::require_impl(x.n_args == 0, "SymbolicPi does not take arguments", x.base.base.loc, diagnostics); } - static inline ASR::expr_t *eval_SymbolicAdd(Allocator &/*al*/, + static inline ASR::expr_t *eval_SymbolicPi(Allocator &/*al*/, const Location &/*loc*/, Vec& /*args*/) { // TODO return nullptr; } - static inline ASR::asr_t* create_SymbolicAdd(Allocator& al, const Location& loc, + static inline ASR::asr_t* create_SymbolicPi(Allocator& al, const Location& loc, Vec& args, - const std::function err) { - if (args.size() != 2) { - err("Intrinsic Symbol Add operator accepts exactly 2 arguments", loc); - } - - Vec arg_values; - arg_values.reserve(al, args.size()); - for( size_t i = 0; i < args.size(); i++ ) { - arg_values.push_back(al, ASRUtils::expr_value(args[i])); - } - ASR::expr_t* compile_time_value = eval_SymbolicAdd(al, loc, arg_values); + const std::function /*err*/) { + ASR::expr_t* compile_time_value = eval_SymbolicPi(al, loc, args); ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); return ASR::make_IntrinsicFunction_t(al, loc, - static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd), - args.p, args.size(), 0, to_type, compile_time_value); + static_cast(ASRUtils::IntrinsicFunctions::SymbolicPi), + nullptr, 0, 0, to_type, compile_time_value); } -} // namespace SymbolicAdd +} // namespace SymbolicPi -namespace SymbolicPi { +namespace SymbolicInteger { static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { - ASRUtils::require_impl(x.n_args == 0, "SymbolicPi does not take arguments", + ASRUtils::require_impl(x.n_args == 1, + "SymbolicInteger intrinsic must have exactly 1 input argument", + x.base.base.loc, diagnostics); + + ASR::ttype_t* input_type = ASRUtils::expr_type(x.m_args[0]); + ASRUtils::require_impl(ASR::is_a(*input_type), + "SymbolicInteger intrinsic expects an integer input argument", x.base.base.loc, diagnostics); } - static inline ASR::expr_t *eval_SymbolicPi(Allocator &/*al*/, + static inline ASR::expr_t* eval_SymbolicInteger(Allocator &/*al*/, const Location &/*loc*/, Vec& /*args*/) { // TODO return nullptr; } - static inline ASR::asr_t* create_SymbolicPi(Allocator& al, const Location& loc, + static inline ASR::asr_t* create_SymbolicInteger(Allocator& al, const Location& loc, Vec& args, const std::function /*err*/) { - ASR::expr_t* compile_time_value = eval_SymbolicPi(al, loc, args); ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); - return ASR::make_IntrinsicFunction_t(al, loc, - static_cast(ASRUtils::IntrinsicFunctions::SymbolicPi), - nullptr, 0, 0, to_type, compile_time_value); + return UnaryIntrinsicFunction::create_UnaryFunction(al, loc, args, eval_SymbolicInteger, + static_cast(ASRUtils::IntrinsicFunctions::SymbolicInteger), 0, to_type); } - -} // namespace SymbolicPi +} // namespace SymbolicInteger namespace IntrinsicFunctionRegistry { @@ -2154,8 +2202,18 @@ namespace IntrinsicFunctionRegistry { {nullptr, &SymbolicSymbol::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd), {nullptr, &SymbolicAdd::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicSub), + {nullptr, &SymbolicSub::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicMul), + {nullptr, &SymbolicMul::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicDiv), + {nullptr, &SymbolicDiv::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicPow), + {nullptr, &SymbolicPow::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicPi), {nullptr, &SymbolicPi::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicInteger), + {nullptr, &SymbolicInteger::verify_args}}, }; static const std::map& intrinsic_function_id_to_name = { @@ -2198,8 +2256,18 @@ namespace IntrinsicFunctionRegistry { "Symbol"}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd), "SymbolicAdd"}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicSub), + "SymbolicSub"}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicMul), + "SymbolicMul"}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicDiv), + "SymbolicDiv"}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicPow), + "SymbolicPow"}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicPi), "pi"}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicInteger), + "SymbolicInteger"}, {static_cast(ASRUtils::IntrinsicFunctions::Any), "any"}, {static_cast(ASRUtils::IntrinsicFunctions::Sum), @@ -2231,7 +2299,12 @@ namespace IntrinsicFunctionRegistry { {"list.pop", {&ListPop::create_ListPop, &ListPop::eval_list_pop}}, {"Symbol", {&SymbolicSymbol::create_SymbolicSymbol, &SymbolicSymbol::eval_SymbolicSymbol}}, {"SymbolicAdd", {&SymbolicAdd::create_SymbolicAdd, &SymbolicAdd::eval_SymbolicAdd}}, + {"SymbolicSub", {&SymbolicSub::create_SymbolicSub, &SymbolicSub::eval_SymbolicSub}}, + {"SymbolicMul", {&SymbolicMul::create_SymbolicMul, &SymbolicMul::eval_SymbolicMul}}, + {"SymbolicDiv", {&SymbolicDiv::create_SymbolicDiv, &SymbolicDiv::eval_SymbolicDiv}}, + {"SymbolicPow", {&SymbolicPow::create_SymbolicPow, &SymbolicPow::eval_SymbolicPow}}, {"pi", {&SymbolicPi::create_SymbolicPi, &SymbolicPi::eval_SymbolicPi}}, + {"SymbolicInteger", {&SymbolicInteger::create_SymbolicInteger, &SymbolicInteger::eval_SymbolicInteger}}, }; static inline bool is_intrinsic_function(const std::string& name) { @@ -2340,7 +2413,12 @@ inline std::string get_intrinsic_name(int x) { INTRINSIC_NAME_CASE(ListPop) INTRINSIC_NAME_CASE(SymbolicSymbol) INTRINSIC_NAME_CASE(SymbolicAdd) + INTRINSIC_NAME_CASE(SymbolicSub) + INTRINSIC_NAME_CASE(SymbolicMul) + INTRINSIC_NAME_CASE(SymbolicDiv) + INTRINSIC_NAME_CASE(SymbolicPow) INTRINSIC_NAME_CASE(SymbolicPi) + INTRINSIC_NAME_CASE(SymbolicInteger) INTRINSIC_NAME_CASE(Sum) default : { throw LCompilersException("pickle: intrinsic_id not implemented"); diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 1df7debf4f..b5b4ed7794 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -63,7 +63,8 @@ namespace CastingUtil { {std::make_pair(ASR::ttypeType::Logical, ASR::ttypeType::Real), ASR::cast_kindType::LogicalToReal}, {std::make_pair(ASR::ttypeType::Logical, ASR::ttypeType::Integer), ASR::cast_kindType::LogicalToInteger}, {std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Integer), ASR::cast_kindType::UnsignedIntegerToInteger}, - {std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Real), ASR::cast_kindType::UnsignedIntegerToReal} + {std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Real), ASR::cast_kindType::UnsignedIntegerToReal}, + {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::SymbolicExpression), ASR::cast_kindType::IntegerToSymbolicExpression} }; // Data structure which contains casting rules for equal intrinsic @@ -1012,7 +1013,31 @@ class CommonVisitor : public AST::BaseVisitor { AST::expr_t** m_args=nullptr, size_t n_args=0, bool raise_error=true) { ASR::ttype_t* type = nullptr; - if (var_annotation == "i8") { + ASR::symbol_t *s = current_scope->resolve_symbol(var_annotation); + if (s) { + if (ASR::is_a(*s)) { + ASR::Variable_t *var_sym = ASR::down_cast(s); + if (var_sym->m_type->type == ASR::ttypeType::TypeParameter) { + ASR::TypeParameter_t *type_param = ASR::down_cast(var_sym->m_type); + type = ASRUtils::TYPE(ASR::make_TypeParameter_t(al, loc, type_param->m_param)); + return ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); + } + } else { + ASR::symbol_t *der_sym = ASRUtils::symbol_get_past_external(s); + if( der_sym ) { + if ( ASR::is_a(*der_sym) ) { + type = ASRUtils::TYPE(ASR::make_Struct_t(al, loc, s)); + return ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); + } else if( ASR::is_a(*der_sym) ) { + type = ASRUtils::TYPE(ASR::make_Enum_t(al, loc, s)); + return ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); + } else if( ASR::is_a(*der_sym) ) { + type = ASRUtils::TYPE(ASR::make_Union_t(al, loc, s)); + return ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); + } + } + } + } else if (var_annotation == "i8") { type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, 1)); type = ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); } else if (var_annotation == "i16") { @@ -1062,34 +1087,8 @@ class CommonVisitor : public AST::BaseVisitor { bool is_allocatable = false; type = ast_expr_to_asr_type(underlying_type->base.loc, *underlying_type, is_allocatable); type = ASRUtils::TYPE(ASR::make_Pointer_t(al, loc, type)); - } else { - ASR::symbol_t *s = current_scope->resolve_symbol(var_annotation); - if (s) { - if (ASR::is_a(*s)) { - ASR::Variable_t *var_sym = ASR::down_cast(s); - if (var_sym->m_type->type == ASR::ttypeType::TypeParameter) { - ASR::TypeParameter_t *type_param = ASR::down_cast(var_sym->m_type); - type = ASRUtils::TYPE(ASR::make_TypeParameter_t(al, loc, type_param->m_param)); - type = ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); - } - } else { - ASR::symbol_t *der_sym = ASRUtils::symbol_get_past_external(s); - if( der_sym ) { - if ( ASR::is_a(*der_sym) ) { - type = ASRUtils::TYPE(ASR::make_Struct_t(al, loc, s)); - type = ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); - } else if( ASR::is_a(*der_sym) ) { - type = ASRUtils::TYPE(ASR::make_Enum_t(al, loc, s)); - type = ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); - } else if( ASR::is_a(*der_sym) ) { - type = ASRUtils::TYPE(ASR::make_Union_t(al, loc, s)); - type = ASRUtils::make_Array_t_util(al, loc, type, dims.p, dims.size()); - } - } - } - } else if (var_annotation == "S") { - type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); - } + } else if (var_annotation == "S") { + type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); } if( !type && raise_error ) { @@ -1967,7 +1966,8 @@ class CommonVisitor : public AST::BaseVisitor { bool left_is_int = ASRUtils::is_integer(*left_type) && ASRUtils::is_character(*right_type); // Handle normal division in python with reals - if (op == ASR::binopType::Div) { + if (op == ASR::binopType::Div && ((!ASR::is_a(*left_type)) || + (!ASR::is_a(*right_type)))) { if (ASRUtils::is_character(*left_type) || ASRUtils::is_character(*right_type)) { diag.add(diag::Diagnostic( "Division is not supported for string type", @@ -2048,7 +2048,6 @@ class CommonVisitor : public AST::BaseVisitor { args.push_back(al, arg2); tmp = make_call_helper(al, fn_div, current_scope, args, "_lpython_floordiv", loc); return; - } else { // real division in python using (`/`) ASR::ttype_t* left_type = ASRUtils::expr_type(left); ASR::ttype_t* right_type = ASRUtils::expr_type(right); @@ -2246,24 +2245,41 @@ class CommonVisitor : public AST::BaseVisitor { return; } else if (ASR::is_a(*left_type) && ASR::is_a(*right_type)) { + Vec args_with_symbolic; + args_with_symbolic.reserve(al, 2); + args_with_symbolic.push_back(al, left); + args_with_symbolic.push_back(al, right); + ASRUtils::create_intrinsic_function create_function; switch (op) { - case ASR::binopType::Add: { - Vec args_with_symbolic; - args_with_symbolic.reserve(al, 2); - args_with_symbolic.push_back(al, left); - args_with_symbolic.push_back(al, right); - ASRUtils::create_intrinsic_function create_function = - ASRUtils::IntrinsicFunctionRegistry::get_create_function("SymbolicAdd"); - tmp = create_function(al, loc, args_with_symbolic, [&](const std::string& msg, const Location& loc) { - throw SemanticError(msg, loc); - }); - return; + case (ASR::binopType::Add): { + create_function = ASRUtils::IntrinsicFunctionRegistry::get_create_function("SymbolicAdd"); + break; + } + case (ASR::binopType::Sub): { + create_function = ASRUtils::IntrinsicFunctionRegistry::get_create_function("SymbolicSub"); + break; + } + case (ASR::binopType::Mul): { + create_function = ASRUtils::IntrinsicFunctionRegistry::get_create_function("SymbolicMul"); + break; + } + case (ASR::binopType::Div): { + create_function = ASRUtils::IntrinsicFunctionRegistry::get_create_function("SymbolicDiv"); + break; + } + case (ASR::binopType::Pow): { + create_function = ASRUtils::IntrinsicFunctionRegistry::get_create_function("SymbolicPow"); + break; } default: { throw SemanticError("Not implemented: The following symbolic binary operator has not been implemented", loc); break; } } + tmp = create_function(al, loc, args_with_symbolic, [&](const std::string& msg, const Location& loc) { + throw SemanticError(msg, loc); + }); + return; } else { std::string ltype = ASRUtils::type_to_str_python(ASRUtils::expr_type(left)); std::string rtype = ASRUtils::type_to_str_python(ASRUtils::expr_type(right)); @@ -7396,7 +7412,8 @@ class BodyVisitor : public CommonVisitor { call_name == "u16" || call_name == "u8" || call_name == "c32" || - call_name == "c64" + call_name == "c64" || + call_name == "S" ) { parse_args(x, args); ASR::ttype_t* target_type = nullptr; @@ -7424,6 +7441,8 @@ class BodyVisitor : public CommonVisitor { target_type = ASRUtils::TYPE(ASR::make_Complex_t(al, x.base.base.loc, 4)); } else if( call_name == "c64" ) { target_type = ASRUtils::TYPE(ASR::make_Complex_t(al, x.base.base.loc, 8)); + } else if( call_name == "S" ) { + target_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, x.base.base.loc)); } ASR::expr_t* arg = args[0].m_value; cast_helper(target_type, arg, x.base.base.loc, true);