From 2392f889bfb773839eb4f522e1cc4664a8318dbc Mon Sep 17 00:00:00 2001 From: Smit-create Date: Sun, 15 May 2022 11:58:38 +0530 Subject: [PATCH 01/15] Add asr to C conversion file --- src/libasr/CMakeLists.txt | 1 + src/libasr/codegen/asr_to_c.cpp | 1104 +++++++++++++++++++++++++++++++ src/libasr/codegen/asr_to_c.h | 13 + 3 files changed, 1118 insertions(+) create mode 100644 src/libasr/codegen/asr_to_c.cpp create mode 100644 src/libasr/codegen/asr_to_c.h diff --git a/src/libasr/CMakeLists.txt b/src/libasr/CMakeLists.txt index 96334a860f..a106faad38 100644 --- a/src/libasr/CMakeLists.txt +++ b/src/libasr/CMakeLists.txt @@ -16,6 +16,7 @@ configure_file(config.h.in config.h) set(SRC codegen/asr_to_cpp.cpp + codegen/asr_to_c.cpp codegen/asr_to_py.cpp codegen/x86_assembler.cpp codegen/asr_to_x86.cpp diff --git a/src/libasr/codegen/asr_to_c.cpp b/src/libasr/codegen/asr_to_c.cpp new file mode 100644 index 0000000000..37a6b0112e --- /dev/null +++ b/src/libasr/codegen/asr_to_c.cpp @@ -0,0 +1,1104 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace LFortran { + +namespace { + + // Local exception that is only used in this file to exit the visitor + // pattern and caught later (not propagated outside) + class CodeGenError + { + public: + diag::Diagnostic d; + public: + CodeGenError(const std::string &msg) + : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} + { } + }; + + class Abort {}; + +} + +// Platform dependent fast unique hash: +uint64_t get_hash_c(ASR::asr_t *node) +{ + return (uint64_t)node; +} + +struct SymbolInfoC +{ + bool needs_declaration = true; + bool intrinsic_function = false; +}; + +std::string convert_dims_c(size_t n_dims, ASR::dimension_t *m_dims) +{ + std::string dims; + for (size_t i=0; i(*start) && ASR::is_a(*end)) { + ASR::IntegerConstant_t *s = ASR::down_cast(start); + ASR::IntegerConstant_t *e = ASR::down_cast(end); + if (s->m_n == 1) { + dims += "[" + std::to_string(e->m_n) + "]"; + } else { + throw CodeGenError("Lower dimension must be 1 for now"); + } + } else { + dims += "[ /* FIXME symbolic dimensions */ ]"; + } + } else { + throw CodeGenError("Dimension type not supported"); + } + } + return dims; +} + +std::string format_type_c(const std::string &dims, const std::string &type, + const std::string &name, bool use_ref, bool /*dummy*/) +{ + std::string fmt; + if (dims.size() == 0) { + std::string ref; + if (use_ref) ref = "&"; + fmt = type + " " + ref + name; + } else { + throw CodeGenError("Dimensions is not supported yet."); + } + return fmt; +} + +class ASRToCVisitor : public ASR::BaseVisitor +{ +public: + diag::Diagnostics &diag; + std::map sym_info; + std::string src; + int indentation_level; + int indentation_spaces; + // The precedence of the last expression, using the table: + // https://en.cppreference.com/w/cpp/language/operator_precedence + int last_expr_precedence; + bool intrinsic_module = false; + const ASR::Function_t *current_function = nullptr; + + ASRToCVisitor(diag::Diagnostics &diag) : diag{diag} {} + + std::string convert_variable_decl(const ASR::Variable_t &v) + { + std::string sub; + bool use_ref = (v.m_intent == LFortran::ASRUtils::intent_out || v.m_intent == LFortran::ASRUtils::intent_inout); + bool dummy = LFortran::ASRUtils::is_arg_dummy(v.m_intent); + if (ASRUtils::is_pointer(v.m_type)) { + ASR::ttype_t *t2 = ASR::down_cast(v.m_type)->m_type; + if (ASRUtils::is_integer(*t2)) { + ASR::Integer_t *t = ASR::down_cast(t2); + std::string dims = convert_dims_c(t->n_dims, t->m_dims); + sub = format_type_c(dims, "int *", v.m_name, use_ref, dummy); + } else { + diag.codegen_error_label("Type number '" + + std::to_string(v.m_type->type) + + "' not supported", {v.base.base.loc}, ""); + throw Abort(); + } + } else { + if (ASRUtils::is_integer(*v.m_type)) { + ASR::Integer_t *t = ASR::down_cast(v.m_type); + std::string dims = convert_dims_c(t->n_dims, t->m_dims); + std::string type_name = "int"; + if (t->m_kind == 8) type_name = "long long"; + sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy); + } else if (ASRUtils::is_real(*v.m_type)) { + ASR::Real_t *t = ASR::down_cast(v.m_type); + std::string dims = convert_dims_c(t->n_dims, t->m_dims); + std::string type_name = "float"; + if (t->m_kind == 8) type_name = "double"; + sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy); + } else if (ASRUtils::is_complex(*v.m_type)) { + ASR::Complex_t *t = ASR::down_cast(v.m_type); + std::string dims = convert_dims_c(t->n_dims, t->m_dims); + std::string type_name = "float complex"; + if (t->m_kind == 8) type_name = "double complex"; + sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy); + } else if (ASRUtils::is_logical(*v.m_type)) { + ASR::Logical_t *t = ASR::down_cast(v.m_type); + std::string dims = convert_dims_c(t->n_dims, t->m_dims); + sub = format_type_c(dims, "bool", v.m_name, use_ref, dummy); + } else if (ASRUtils::is_character(*v.m_type)) { + // TODO + } else if (ASR::is_a(*v.m_type)) { + ASR::Derived_t *t = ASR::down_cast(v.m_type); + std::string dims = convert_dims_c(t->n_dims, t->m_dims); + sub = format_type_c(dims, "struct", v.m_name, use_ref, dummy); + if (v.m_symbolic_value) { + this->visit_expr(*v.m_symbolic_value); + std::string init = src; + sub += "=" + init; + } + } else { + diag.codegen_error_label("Type number '" + + std::to_string(v.m_type->type) + + "' not supported", {v.base.base.loc}, ""); + throw Abort(); + } + } + return sub; + } + + + void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { + // All loose statements must be converted to a function, so the items + // must be empty: + LFORTRAN_ASSERT(x.n_items == 0); + std::string unit_src = ""; + indentation_level = 0; + indentation_spaces = 4; + + std::string headers = +R"(#include +#include +#include +#include +)"; + unit_src += headers; + + + // TODO: We need to pre-declare all functions first, then generate code + // Otherwise some function might not be found. + + { + // Process intrinsic modules in the right order + std::vector build_order + = LFortran::ASRUtils::determine_module_dependencies(x); + for (auto &item : build_order) { + LFORTRAN_ASSERT(x.m_global_scope->get_scope().find(item) + != x.m_global_scope->get_scope().end()); + if (startswith(item, "lfortran_intrinsic")) { + ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); + visit_symbol(*mod); + unit_src += src; + } + } + } + + // Process procedures first: + for (auto &item : x.m_global_scope->get_scope()) { + if (ASR::is_a(*item.second) + || ASR::is_a(*item.second)) { + visit_symbol(*item.second); + unit_src += src; + } + } + + // Then do all the modules in the right order + std::vector build_order + = LFortran::ASRUtils::determine_module_dependencies(x); + for (auto &item : build_order) { + LFORTRAN_ASSERT(x.m_global_scope->get_scope().find(item) + != x.m_global_scope->get_scope().end()); + if (!startswith(item, "lfortran_intrinsic")) { + ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); + visit_symbol(*mod); + unit_src += src; + } + } + + // Then the main program: + for (auto &item : x.m_global_scope->get_scope()) { + if (ASR::is_a(*item.second)) { + visit_symbol(*item.second); + unit_src += src; + } + } + + src = unit_src; + } + + void visit_Module(const ASR::Module_t &x) { + if (startswith(x.m_name, "lfortran_intrinsic_")) { + intrinsic_module = true; + } else { + intrinsic_module = false; + } + // Generate code for nested subroutines and functions first: + std::string contains; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Subroutine_t *s = ASR::down_cast(item.second); + visit_Subroutine(*s); + contains += src; + } + if (ASR::is_a(*item.second)) { + ASR::Function_t *s = ASR::down_cast(item.second); + visit_Function(*s); + contains += src; + } + } + src = contains; + intrinsic_module = false; + } + + void visit_Program(const ASR::Program_t &x) { + // Generate code for nested subroutines and functions first: + std::string contains; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Subroutine_t *s = ASR::down_cast(item.second); + visit_Subroutine(*s); + contains += src; + } + if (ASR::is_a(*item.second)) { + ASR::Function_t *s = ASR::down_cast(item.second); + visit_Function(*s); + contains += src; + } + } + + // Generate code for the main program + indentation_level += 1; + std::string indent1(indentation_level*indentation_spaces, ' '); + indentation_level += 1; + std::string indent(indentation_level*indentation_spaces, ' '); + std::string decl; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast(item.second); + decl += convert_variable_decl(*v) + ";\n"; + } + } + + std::string body; + for (size_t i=0; ivisit_stmt(*x.m_body[i]); + body += src; + } + + src = contains + + "int main(int argc, char* argv[])\n{\n" + + decl + body + + indent1 + "return 0;\n}\n"; + indentation_level -= 2; + } + + void visit_Subroutine(const ASR::Subroutine_t &x) { + indentation_level += 1; + std::string sub = "void " + std::string(x.m_name) + "("; + for (size_t i=0; im_intent)); + sub += convert_variable_decl(*arg); + if (i < x.n_args-1) sub += ", "; + } + sub += ")\n"; + + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast(item.second); + if (v->m_intent == LFortran::ASRUtils::intent_local) { + SymbolInfoC s; + s.needs_declaration = true; + sym_info[get_hash_c((ASR::asr_t*)v)] = s; + } + } + } + + std::string body; + for (size_t i=0; ivisit_stmt(*x.m_body[i]); + body += src; + } + + std::string decl; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast(item.second); + if (v->m_intent == LFortran::ASRUtils::intent_local) { + if (sym_info[get_hash_c((ASR::asr_t*) v)].needs_declaration) { + std::string indent(indentation_level*indentation_spaces, ' '); + decl += indent; + decl += convert_variable_decl(*v) + ";\n"; + } + } + } + } + + sub += "{\n" + decl + body + "}\n\n"; + src = sub; + indentation_level -= 1; + } + + void visit_Function(const ASR::Function_t &x) { + if (std::string(x.m_name) == "size" && intrinsic_module ) { + // Intrinsic function `size` + SymbolInfoC s; + s.intrinsic_function = true; + sym_info[get_hash_c((ASR::asr_t*)&x)] = s; + src = ""; + return; + } else if (( + std::string(x.m_name) == "int" || + std::string(x.m_name) == "char" || + std::string(x.m_name) == "present" || + std::string(x.m_name) == "len" || + std::string(x.m_name) == "not" + ) && intrinsic_module) { + // Intrinsic function `int` + SymbolInfoC s; + s.intrinsic_function = true; + sym_info[get_hash_c((ASR::asr_t*)&x)] = s; + src = ""; + return; + } else { + SymbolInfoC s; + s.intrinsic_function = false; + sym_info[get_hash_c((ASR::asr_t*)&x)] = s; + } + std::string sub; + ASR::Variable_t *return_var = LFortran::ASRUtils::EXPR2VAR(x.m_return_var); + if (ASRUtils::is_integer(*return_var->m_type)) { + bool is_int = ASR::down_cast(return_var->m_type)->m_kind == 4; + if (is_int) { + sub = "int "; + } else { + sub = "long long "; + } + } else if (ASRUtils::is_real(*return_var->m_type)) { + bool is_float = ASR::down_cast(return_var->m_type)->m_kind == 4; + if (is_float) { + sub = "float "; + } else { + sub = "double "; + } + } else if (ASRUtils::is_logical(*return_var->m_type)) { + sub = "bool "; + } else if (ASRUtils::is_character(*return_var->m_type)) { + sub = "char * "; + } else if (ASRUtils::is_complex(*return_var->m_type)) { + bool is_float = ASR::down_cast(return_var->m_type)->m_kind == 4; + if (is_float) { + sub = "float complex "; + } else { + sub = "double complex "; + } + } else { + throw CodeGenError("Return type not supported"); + } + sub = sub + std::string(x.m_name) + "("; + for (size_t i=0; im_intent)); + sub += convert_variable_decl(*arg); + if (i < x.n_args-1) sub += ", "; + } + sub += ")"; + if (x.m_abi == ASR::abiType::BindC) { + sub += ";\n"; + } else { + sub += "\n"; + + indentation_level += 1; + std::string indent(indentation_level*indentation_spaces, ' '); + std::string decl; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast(item.second); + if (v->m_intent == LFortran::ASRUtils::intent_local || v->m_intent == LFortran::ASRUtils::intent_return_var) { + decl += indent + convert_variable_decl(*v) + ";\n"; + } + } + } + + current_function = &x; + std::string body; + + for (size_t i=0; ivisit_stmt(*x.m_body[i]); + body += src; + } + current_function = nullptr; + bool visited_return = false; + + if (x.n_body > 0 && ASR::is_a(*x.m_body[x.n_body-1])) { + visited_return = true; + } + + if(!visited_return) { + body += indent + "return " + + LFortran::ASRUtils::EXPR2VAR(x.m_return_var)->m_name + + ";\n"; + } + + if (decl.size() > 0 || body.size() > 0) { + sub += "{\n" + decl + body + "}\n"; + } else { + sub[sub.size()-1] = ';'; + sub += "\n"; + } + indentation_level -= 1; + } + sub += "\n"; + src = sub; + } + + void visit_FunctionCall(const ASR::FunctionCall_t &x) { + ASR::Function_t *fn = ASR::down_cast( + LFortran::ASRUtils::symbol_get_past_external(x.m_name)); + std::string fn_name = fn->m_name; + if (sym_info[get_hash_c((ASR::asr_t*)fn)].intrinsic_function) { + if (fn_name == "size") { + LFORTRAN_ASSERT(x.n_args > 0); + visit_expr(*x.m_args[0].m_value); + std::string var_name = src; + std::string args; + if (x.n_args == 1) { + args = "0"; + } else { + for (size_t i=1; i 0); + visit_expr(*x.m_args[0].m_value); + src = "(int)" + src; + } else if (fn_name == "not") { + LFORTRAN_ASSERT(x.n_args > 0); + visit_expr(*x.m_args[0].m_value); + src = "!(" + src + ")"; + } else { + throw CodeGenError("Intrinsic function '" + fn_name + + "' not implemented"); + } + } else { + std::string args; + for (size_t i=0; i(*x.m_target)) { + target = LFortran::ASRUtils::EXPR2VAR(x.m_target)->m_name; + } else if (ASR::is_a(*x.m_target)) { + visit_ArrayRef(*ASR::down_cast(x.m_target)); + target = src; + } else { + LFORTRAN_ASSERT(false) + } + this->visit_expr(*x.m_value); + std::string value = src; + std::string indent(indentation_level*indentation_spaces, ' '); + src = indent + target + " = " + value + ";\n"; + } + + void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { + src = std::to_string(x.m_n); + last_expr_precedence = 2; + } + + void visit_RealConstant(const ASR::RealConstant_t &x) { + src = std::to_string(x.m_r); + last_expr_precedence = 2; + } + + + void visit_StringConstant(const ASR::StringConstant_t &x) { + src = "\"" + std::string(x.m_s) + "\""; + last_expr_precedence = 2; + } + + void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { + if (x.m_value == true) { + src = "true"; + } else { + src = "false"; + } + last_expr_precedence = 2; + } + + void visit_Var(const ASR::Var_t &x) { + const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); + src = ASR::down_cast(s)->m_name; + last_expr_precedence = 2; + } + + void visit_ArrayRef(const ASR::ArrayRef_t &x) { + const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); + std::string out = ASR::down_cast(s)->m_name; + out += "["; + for (size_t i=0; i long long explicitly: + // src = src; + break; + } + case (ASR::cast_kindType::ComplexToComplex) : { + break; + } + case (ASR::cast_kindType::ComplexToReal) : { + src = "creal(" + src + ")"; + break; + } + case (ASR::cast_kindType::LogicalToInteger) : { + src = "(int)(" + src + ")"; + break; + } + default : throw CodeGenError("Cast kind " + std::to_string(x.m_kind) + " not implemented"); + } + last_expr_precedence = 2; + } + + void visit_Compare(const ASR::Compare_t &x) { + this->visit_expr(*x.m_left); + std::string left = std::move(src); + int left_precedence = last_expr_precedence; + this->visit_expr(*x.m_right); + std::string right = std::move(src); + int right_precedence = last_expr_precedence; + switch (x.m_op) { + case (ASR::cmpopType::Eq) : { last_expr_precedence = 10; break; } + case (ASR::cmpopType::Gt) : { last_expr_precedence = 9; break; } + case (ASR::cmpopType::GtE) : { last_expr_precedence = 9; break; } + case (ASR::cmpopType::Lt) : { last_expr_precedence = 9; break; } + case (ASR::cmpopType::LtE) : { last_expr_precedence = 9; break; } + case (ASR::cmpopType::NotEq): { last_expr_precedence = 10; break; } + default : LFORTRAN_ASSERT(false); // should never happen + } + if (left_precedence <= last_expr_precedence) { + src += left; + } else { + src += "(" + left + ")"; + } + src += ASRUtils::cmpop_to_str(x.m_op); + if (right_precedence <= last_expr_precedence) { + src += right; + } else { + src += "(" + right + ")"; + } + } + + void visit_UnaryOp(const ASR::UnaryOp_t &x) { + this->visit_expr(*x.m_operand); + int expr_precedence = last_expr_precedence; + if (x.m_type->type == ASR::ttypeType::Integer) { + if (x.m_op == ASR::unaryopType::UAdd) { + // src = src; + // Skip unary plus, keep the previous precedence + } else if (x.m_op == ASR::unaryopType::USub) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "-" + src; + } else { + src = "-(" + src + ")"; + } + } else if (x.m_op == ASR::unaryopType::Invert) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "~" + src; + } else { + src = "~(" + src + ")"; + } + + } else if (x.m_op == ASR::unaryopType::Not) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "!" + src; + } else { + src = "!(" + src + ")"; + } + } else { + throw CodeGenError("Unary type not implemented yet for Integer"); + } + return; + } else if (x.m_type->type == ASR::ttypeType::Real) { + if (x.m_op == ASR::unaryopType::UAdd) { + // src = src; + // Skip unary plus, keep the previous precedence + } else if (x.m_op == ASR::unaryopType::USub) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "-" + src; + } else { + src = "-(" + src + ")"; + } + } else if (x.m_op == ASR::unaryopType::Not) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "!" + src; + } else { + src = "!(" + src + ")"; + } + } else { + throw CodeGenError("Unary type not implemented yet for Real"); + } + return; + } else if (x.m_type->type == ASR::ttypeType::Logical) { + if (x.m_op == ASR::unaryopType::Not) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "!" + src; + } else { + src = "!(" + src + ")"; + } + return; + } else { + throw CodeGenError("Unary type not implemented yet for Logical"); + } + } else { + throw CodeGenError("UnaryOp: type not supported yet"); + } + } + + void visit_BinOp(const ASR::BinOp_t &x) { + this->visit_expr(*x.m_left); + std::string left = std::move(src); + int left_precedence = last_expr_precedence; + this->visit_expr(*x.m_right); + std::string right = std::move(src); + int right_precedence = last_expr_precedence; + switch (x.m_op) { + case (ASR::binopType::Add) : { last_expr_precedence = 6; break; } + case (ASR::binopType::Sub) : { last_expr_precedence = 6; break; } + case (ASR::binopType::Mul) : { last_expr_precedence = 5; break; } + case (ASR::binopType::Div) : { last_expr_precedence = 5; break; } + default: throw CodeGenError("BinOp: operator not implemented yet"); + } + src = ""; + if (left_precedence == 3) { + src += "(" + left + ")"; + } else { + if (left_precedence <= last_expr_precedence) { + src += left; + } else { + src += "(" + left + ")"; + } + } + src += ASRUtils::binop_to_str(x.m_op); + if (right_precedence == 3) { + src += "(" + right + ")"; + } else if (x.m_op == ASR::binopType::Sub) { + if (right_precedence < last_expr_precedence) { + src += right; + } else { + src += "(" + right + ")"; + } + } else { + if (right_precedence <= last_expr_precedence) { + src += right; + } else { + src += "(" + right + ")"; + } + } + } + + void visit_BoolOp(const ASR::BoolOp_t &x) { + this->visit_expr(*x.m_left); + std::string left = std::move(src); + int left_precedence = last_expr_precedence; + this->visit_expr(*x.m_right); + std::string right = std::move(src); + int right_precedence = last_expr_precedence; + switch (x.m_op) { + case (ASR::boolopType::And): { + last_expr_precedence = 14; + break; + } + case (ASR::boolopType::Or): { + last_expr_precedence = 15; + break; + } + case (ASR::boolopType::NEqv): { + last_expr_precedence = 10; + break; + } + case (ASR::boolopType::Eqv): { + last_expr_precedence = 10; + break; + } + default : throw CodeGenError("Unhandled switch case"); + } + + if (left_precedence <= last_expr_precedence) { + src += left; + } else { + src += "(" + left + ")"; + } + src += ASRUtils::boolop_to_str(x.m_op); + if (right_precedence <= last_expr_precedence) { + src += right; + } else { + src += "(" + right + ")"; + } + } + + std::string get_print_type(ASR::ttype_t *t) { + switch (t->type) { + case ASR::ttypeType::Integer: { + ASR::Integer_t *i = (ASR::Integer_t*)t; + switch (i->m_kind) { + case 1: { return "%d"; } + case 2: { return "%d"; } + case 4: { return "%d"; } + case 8: { return "%lli"; } + default: { throw LFortranException("Integer kind not supported"); } + } + } + case ASR::ttypeType::Real: { + ASR::Real_t *r = (ASR::Real_t*)t; + switch (r->m_kind) { + case 4: { return "%f"; } + case 8: { return "%lf"; } + default: { throw LFortranException("Float kind not supported"); } + } + } + case ASR::ttypeType::Logical: { + return "%d"; + } + case ASR::ttypeType::Character: { + return "%s"; + } + default : throw LFortranException("Not implemented"); + } + } + + void visit_Print(const ASR::Print_t &x) { + std::string indent(indentation_level*indentation_spaces, ' '); + std::string out = indent + "printf(\""; + std::vector v; + for (size_t i=0; ivisit_expr(*x.m_values[i]); + out += get_print_type(ASRUtils::expr_type(x.m_values[i])); + if (i+1!=x.n_values) { + out += " "; + } + v.push_back(src); + } + out += "\\n\""; + if (!v.empty()) { + for (auto s: v) { + out += ", " + s; + } + } + out += ");\n"; + src = out; + } + + void visit_Allocate(const ASR::Allocate_t &x) { + std::string indent(indentation_level*indentation_spaces, ' '); + std::string out = indent + "// FIXME: allocate("; + for (size_t i=0; ivisit_stmt(*x.m_body[i]); + out += src; + } + out += indent + "}\n"; + indentation_level -= 1; + src = out; + } + + void visit_Exit(const ASR::Exit_t & /* x */) { + std::string indent(indentation_level*indentation_spaces, ' '); + src = indent + "break;\n"; + } + + void visit_Cycle(const ASR::Cycle_t & /* x */) { + std::string indent(indentation_level*indentation_spaces, ' '); + src = indent + "continue;\n"; + } + + void visit_Return(const ASR::Return_t & /* x */) { + std::string indent(indentation_level*indentation_spaces, ' '); + if (current_function) { + src = indent + "return " + + LFortran::ASRUtils::EXPR2VAR(current_function->m_return_var)->m_name + + ";\n"; + } else { + src = indent + "return;\n"; + } + } + + void visit_GoToTarget(const ASR::GoToTarget_t & /* x */) { + // Ignore for now + src = ""; + } + + void visit_Stop(const ASR::Stop_t & /* x */) { + std::string indent(indentation_level*indentation_spaces, ' '); + src = indent + "exit(0);\n"; + } + + void visit_ImpliedDoLoop(const ASR::ImpliedDoLoop_t &/*x*/) { + std::string indent(indentation_level*indentation_spaces, ' '); + std::string out = indent + " /* FIXME: implied do loop */ "; + src = out; + last_expr_precedence = 2; + } + + void visit_DoLoop(const ASR::DoLoop_t &x) { + std::string indent(indentation_level*indentation_spaces, ' '); + std::string out = indent + "for ("; + ASR::Variable_t *loop_var = LFortran::ASRUtils::EXPR2VAR(x.m_head.m_v); + std::string lvname=loop_var->m_name; + ASR::expr_t *a=x.m_head.m_start; + ASR::expr_t *b=x.m_head.m_end; + ASR::expr_t *c=x.m_head.m_increment; + LFORTRAN_ASSERT(a); + LFORTRAN_ASSERT(b); + int increment; + if (!c) { + increment = 1; + } else { + if (c->type == ASR::exprType::IntegerConstant) { + increment = ASR::down_cast(c)->m_n; + } else if (c->type == ASR::exprType::UnaryOp) { + ASR::UnaryOp_t *u = ASR::down_cast(c); + LFORTRAN_ASSERT(u->m_op == ASR::unaryopType::USub); + LFORTRAN_ASSERT(u->m_operand->type == ASR::exprType::IntegerConstant); + increment = - ASR::down_cast(u->m_operand)->m_n; + } else { + throw CodeGenError("Do loop increment type not supported"); + } + } + std::string cmp_op; + if (increment > 0) { + cmp_op = "<="; + } else { + cmp_op = ">="; + } + + out += lvname + "="; + visit_expr(*a); + out += src + "; " + lvname + cmp_op; + visit_expr(*b); + out += src + "; " + lvname; + if (increment == 1) { + out += "++"; + } else if (increment == -1) { + out += "--"; + } else { + out += "+=" + std::to_string(increment); + } + out += ") {\n"; + indentation_level += 1; + for (size_t i=0; ivisit_stmt(*x.m_body[i]); + out += src; + } + out += indent + "}\n"; + indentation_level -= 1; + src = out; + } + + void visit_ErrorStop(const ASR::ErrorStop_t & /* x */) { + std::string indent(indentation_level*indentation_spaces, ' '); + src = indent + "fprintf(stderr, \"ERROR STOP\");\n"; + src += indent + "exit(1);\n"; + } + + void visit_If(const ASR::If_t &x) { + std::string indent(indentation_level*indentation_spaces, ' '); + std::string out = indent + "if ("; + visit_expr(*x.m_test); + out += src + ") {\n"; + indentation_level += 1; + for (size_t i=0; ivisit_stmt(*x.m_body[i]); + out += src; + } + out += indent + "}"; + if (x.n_orelse == 0) { + out += "\n"; + } else { + out += " else {\n"; + for (size_t i=0; ivisit_stmt(*x.m_orelse[i]); + out += src; + } + out += indent + "}\n"; + } + indentation_level -= 1; + src = out; + } + + void visit_IfExp(const ASR::IfExp_t &x) { + // IfExp is like a ternary operator in c++ + // test ? body : orelse; + std::string out = "("; + visit_expr(*x.m_test); + out += src + ") ? ("; + visit_expr(*x.m_body); + out += src + ") : ("; + visit_expr(*x.m_orelse); + out += src + ")"; + src = out; + last_expr_precedence = 16; + } + + void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { + std::string indent(indentation_level*indentation_spaces, ' '); + ASR::Subroutine_t *s = ASR::down_cast( + LFortran::ASRUtils::symbol_get_past_external(x.m_name)); + std::string out = indent + s->m_name + "("; + for (size_t i=0; i(*x.m_args[i].m_value)) { + ASR::Variable_t *arg = LFortran::ASRUtils::EXPR2VAR(x.m_args[i].m_value); + std::string arg_name = arg->m_name; + out += arg_name; + } else { + this->visit_expr(*x.m_args[i].m_value); + out += src; + } + if (i < x.n_args-1) out += ", "; + } + out += ");\n"; + src = out; + } + +}; + +Result asr_to_c(Allocator &al, ASR::TranslationUnit_t &asr, + diag::Diagnostics &diagnostics) +{ + pass_unused_functions(al, asr); + ASRToCVisitor v(diagnostics); + try { + v.visit_asr((ASR::asr_t &)asr); + } catch (const CodeGenError &e) { + diagnostics.diagnostics.push_back(e.d); + return Error(); + } catch (const Abort &) { + return Error(); + } + return v.src; +} + +} // namespace LFortran diff --git a/src/libasr/codegen/asr_to_c.h b/src/libasr/codegen/asr_to_c.h new file mode 100644 index 0000000000..1ab27dff06 --- /dev/null +++ b/src/libasr/codegen/asr_to_c.h @@ -0,0 +1,13 @@ +#ifndef LFORTRAN_ASR_TO_C_H +#define LFORTRAN_ASR_TO_C_H + +#include + +namespace LFortran { + + Result asr_to_c(Allocator &al, ASR::TranslationUnit_t &asr, + diag::Diagnostics &diagnostics); + +} // namespace LFortran + +#endif // LFORTRAN_ASR_TO_C_H From c49d6ffab9b7c92cb1ca73f7c1675e5b073074e6 Mon Sep 17 00:00:00 2001 From: Smit-create Date: Sun, 15 May 2022 11:58:53 +0530 Subject: [PATCH 02/15] Add --show-c option for ASR to C --- src/bin/lpython.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/bin/lpython.cpp b/src/bin/lpython.cpp index 4a12b71d01..5e3e298ac2 100644 --- a/src/bin/lpython.cpp +++ b/src/bin/lpython.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -223,6 +224,46 @@ int emit_cpp(const std::string &infile, return 0; } +int emit_c(const std::string &infile, + const std::string &runtime_library_dir, + CompilerOptions &compiler_options) +{ + Allocator al(4*1024); + LFortran::diag::Diagnostics diagnostics; + LFortran::LocationManager lm; + lm.in_filename = infile; + std::string input = LFortran::read_file(infile); + lm.init_simple(input); + LFortran::Result r = parse_python_file( + al, runtime_library_dir, infile, diagnostics, compiler_options.new_parser); + std::cerr << diagnostics.render(input, lm, compiler_options); + if (!r.ok) { + return 1; + } + LFortran::LPython::AST::ast_t* ast = r.result; + + diagnostics.diagnostics.clear(); + LFortran::Result + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, true, + compiler_options.symtab_only); + std::cerr << diagnostics.render(input, lm, compiler_options); + if (!r1.ok) { + LFORTRAN_ASSERT(diagnostics.has_error()) + return 2; + } + LFortran::ASR::TranslationUnit_t* asr = r1.result; + + diagnostics.diagnostics.clear(); + auto res = LFortran::asr_to_c(al, *asr, diagnostics); + std::cerr << diagnostics.render(input, lm, compiler_options); + if (!res.ok) { + LFORTRAN_ASSERT(diagnostics.has_error()) + return 3; + } + std::cout << res.result; + return 0; +} + #ifdef HAVE_LFORTRAN_LLVM int emit_llvm(const std::string &infile, @@ -542,6 +583,7 @@ int main(int argc, char *argv[]) bool show_ast = false; bool show_asr = false; bool show_cpp = false; + bool show_c = false; bool with_intrinsic_modules = false; std::string arg_pass; bool arg_no_color = false; @@ -595,6 +637,7 @@ int main(int argc, char *argv[]) app.add_flag("--show-asr", show_asr, "Show ASR for the given python file and exit"); app.add_flag("--show-llvm", show_llvm, "Show LLVM IR for the given file and exit"); app.add_flag("--show-cpp", show_cpp, "Show C++ translation source for the given python file and exit"); + app.add_flag("--show-c", show_c, "Show C translation source for the given python file and exit"); app.add_flag("--show-asm", show_asm, "Show assembly for the given file and exit"); app.add_flag("--show-stacktrace", compiler_options.show_stacktrace, "Show internal stacktrace on compiler errors"); app.add_flag("--with-intrinsic-mods", with_intrinsic_modules, "Show intrinsic modules in ASR"); @@ -787,6 +830,9 @@ int main(int argc, char *argv[]) if (show_cpp) { return emit_cpp(arg_file, runtime_library_dir, compiler_options); } + if (show_c) { + return emit_c(arg_file, runtime_library_dir, compiler_options); + } if (show_llvm) { #ifdef HAVE_LFORTRAN_LLVM return emit_llvm(arg_file, runtime_library_dir, compiler_options); From ab3cc35a2a1f036200570a6d8e419d476a86e2ef Mon Sep 17 00:00:00 2001 From: Smit-create Date: Sun, 15 May 2022 12:23:36 +0530 Subject: [PATCH 03/15] Add and modify tests --- run_tests.py | 5 +++++ tests/loop1.py | 1 + tests/tests.toml | 1 + 3 files changed, 7 insertions(+) diff --git a/run_tests.py b/run_tests.py index 53d4a5ea38..de83f8d2f3 100755 --- a/run_tests.py +++ b/run_tests.py @@ -49,6 +49,7 @@ def main(): mod_to_asr = test.get("mod_to_asr", False) llvm = test.get("llvm", False) cpp = test.get("cpp", False) + c = test.get("c", False) obj = test.get("obj", False) x86 = test.get("x86", False) bin_ = test.get("bin", False) @@ -83,6 +84,10 @@ def main(): run_test("cpp", "lpython --no-color --show-cpp {infile}", filename, update_reference, extra_args) + if c: + run_test("c", "lpython --no-color --show-c {infile}", + filename, update_reference, extra_args) + if tokens: run_test("tokens", "lpython --no-color --show-tokens {infile} -o {outfile}", filename, update_reference, extra_args) diff --git a/tests/loop1.py b/tests/loop1.py index 976639d586..c57e481e4a 100644 --- a/tests/loop1.py +++ b/tests/loop1.py @@ -35,5 +35,6 @@ def main0(): i = test_factorial_2(4) j: i64 j = test_factorial_3(5) + print(i, j) main0() diff --git a/tests/tests.toml b/tests/tests.toml index 4ab74ac229..15bd932bdc 100644 --- a/tests/tests.toml +++ b/tests/tests.toml @@ -144,6 +144,7 @@ filename = "loop1.py" ast = true asr = true cpp = true +c = true [[test]] filename = "loop2.py" From 61ec07009985ef801bd59895e867c4727b308e4c Mon Sep 17 00:00:00 2001 From: Smit-create Date: Sun, 15 May 2022 12:25:11 +0530 Subject: [PATCH 04/15] Update tests --- tests/reference/asr-loop1-10d3109.json | 4 +- tests/reference/asr-loop1-10d3109.stdout | 2 +- tests/reference/ast-loop1-194a137.json | 4 +- tests/reference/ast-loop1-194a137.stdout | 2 +- tests/reference/c-loop1-3e341c7.json | 13 +++++ tests/reference/c-loop1-3e341c7.stdout | 71 ++++++++++++++++++++++++ tests/reference/cpp-loop1-0a8cf3b.json | 4 +- tests/reference/cpp-loop1-0a8cf3b.stdout | 1 + 8 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 tests/reference/c-loop1-3e341c7.json create mode 100644 tests/reference/c-loop1-3e341c7.stdout diff --git a/tests/reference/asr-loop1-10d3109.json b/tests/reference/asr-loop1-10d3109.json index bba8d1ea0c..8d9932597e 100644 --- a/tests/reference/asr-loop1-10d3109.json +++ b/tests/reference/asr-loop1-10d3109.json @@ -2,11 +2,11 @@ "basename": "asr-loop1-10d3109", "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", "infile": "tests/loop1.py", - "infile_hash": "e50c7161122d599991fafb072d5db8fe7e54d017d56a5c1951a210ca", + "infile_hash": "a27a0e48b7c6291be0b0847f5e7a30c591c7168a9004395156d57dbd", "outfile": null, "outfile_hash": null, "stdout": "asr-loop1-10d3109.stdout", - "stdout_hash": "5d36cb7c4513f77c3490bbc704a8a965aba5caca2d0ab82c35f52c3b", + "stdout_hash": "78b22cbace48a9537748d96d36191446a7713ee8a39e80a67f20e0dd", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/asr-loop1-10d3109.stdout b/tests/reference/asr-loop1-10d3109.stdout index a36fb3e5c1..bce2dbe504 100644 --- a/tests/reference/asr-loop1-10d3109.stdout +++ b/tests/reference/asr-loop1-10d3109.stdout @@ -1 +1 @@ -(TranslationUnit (SymbolTable 1 {_lpython_main_program: (Subroutine (SymbolTable 7 {}) _lpython_main_program [] [(SubroutineCall 1 main0 () [] ())] Source Public Implementation () .false. .false.), main0: (Subroutine (SymbolTable 5 {i: (Variable 5 i Local () () Default (Integer 4 []) Source Public Required .false.), j: (Variable 5 j Local () () Default (Integer 8 []) Source Public Required .false.)}) main0 [] [(= (Var 5 i) (FunctionCall 1 test_factorial_1 () [((IntegerConstant 4 (Integer 4 [])))] (Integer 4 []) () ()) ()) (= (Var 5 i) (FunctionCall 1 test_factorial_2 () [((IntegerConstant 4 (Integer 4 [])))] (Integer 4 []) () ()) ()) (= (Var 5 j) (FunctionCall 1 test_factorial_3 () [((IntegerConstant 5 (Integer 4 [])))] (Integer 8 []) () ()) ())] Source Public Implementation () .false. .false.), main_program: (Program (SymbolTable 6 {}) main_program [] [(SubroutineCall 1 _lpython_main_program () [] ())]), test_factorial_1: (Function (SymbolTable 2 {_lpython_return_variable: (Variable 2 _lpython_return_variable ReturnVar () () Default (Integer 4 []) Source Public Required .false.), result: (Variable 2 result Local () () Default (Integer 4 []) Source Public Required .false.), x: (Variable 2 x In () () Default (Integer 4 []) Source Public Required .false.)}) test_factorial_1 [(Var 2 x)] [(If (Compare (Var 2 x) Lt (IntegerConstant 0 (Integer 4 [])) (Logical 4 []) () ()) [(= (Var 2 _lpython_return_variable) (IntegerConstant 0 (Integer 4 [])) ()) (Return)] []) (= (Var 2 result) (IntegerConstant 1 (Integer 4 [])) ()) (WhileLoop (Compare (Var 2 x) Gt (IntegerConstant 0 (Integer 4 [])) (Logical 4 []) () ()) [(= (Var 2 result) (BinOp (Var 2 result) Mul (Var 2 x) (Integer 4 []) () ()) ()) (= (Var 2 x) (BinOp (Var 2 x) Sub (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) () ()) ())]) (= (Var 2 _lpython_return_variable) (Var 2 result) ()) (Return)] (Var 2 _lpython_return_variable) Source Public Implementation ()), test_factorial_2: (Function (SymbolTable 3 {_lpython_return_variable: (Variable 3 _lpython_return_variable ReturnVar () () Default (Integer 4 []) Source Public Required .false.), i: (Variable 3 i Local () () Default (Integer 4 []) Source Public Required .false.), result: (Variable 3 result Local () () Default (Integer 4 []) Source Public Required .false.), x: (Variable 3 x In () () Default (Integer 4 []) Source Public Required .false.)}) test_factorial_2 [(Var 3 x)] [(= (Var 3 result) (IntegerConstant 1 (Integer 4 [])) ()) (DoLoop ((Var 3 i) (IntegerConstant 1 (Integer 4 [])) (BinOp (BinOp (Var 3 x) Add (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) () ()) Sub (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) () ()) (IntegerConstant 1 (Integer 4 []))) [(= (Var 3 result) (BinOp (Var 3 result) Mul (Var 3 i) (Integer 4 []) () ()) ())]) (= (Var 3 _lpython_return_variable) (Var 3 result) ()) (Return)] (Var 3 _lpython_return_variable) Source Public Implementation ()), test_factorial_3: (Function (SymbolTable 4 {_lpython_return_variable: (Variable 4 _lpython_return_variable ReturnVar () () Default (Integer 8 []) Source Public Required .false.), result: (Variable 4 result Local () () Default (Integer 8 []) Source Public Required .false.), x: (Variable 4 x In () () Default (Integer 4 []) Source Public Required .false.)}) test_factorial_3 [(Var 4 x)] [(If (Compare (Var 4 x) Lt (IntegerConstant 0 (Integer 4 [])) (Logical 4 []) () ()) [(= (Var 4 _lpython_return_variable) (Cast (IntegerConstant 0 (Integer 4 [])) IntegerToInteger (Integer 8 []) ()) ()) (Return)] []) (= (Var 4 result) (Cast (IntegerConstant 1 (Integer 4 [])) IntegerToInteger (Integer 8 []) ()) ()) (WhileLoop (Compare (Var 4 x) Gt (IntegerConstant 0 (Integer 4 [])) (Logical 4 []) () ()) [(= (Var 4 result) (BinOp (Var 4 result) Mul (Cast (Var 4 x) IntegerToInteger (Integer 8 []) ()) (Integer 8 []) () ()) ()) (= (Var 4 x) (BinOp (Var 4 x) Sub (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) () ()) ())]) (= (Var 4 _lpython_return_variable) (Var 4 result) ()) (Return)] (Var 4 _lpython_return_variable) Source Public Implementation ())}) []) +(TranslationUnit (SymbolTable 1 {_lpython_main_program: (Subroutine (SymbolTable 7 {}) _lpython_main_program [] [(SubroutineCall 1 main0 () [] ())] Source Public Implementation () .false. .false.), main0: (Subroutine (SymbolTable 5 {i: (Variable 5 i Local () () Default (Integer 4 []) Source Public Required .false.), j: (Variable 5 j Local () () Default (Integer 8 []) Source Public Required .false.)}) main0 [] [(= (Var 5 i) (FunctionCall 1 test_factorial_1 () [((IntegerConstant 4 (Integer 4 [])))] (Integer 4 []) () ()) ()) (= (Var 5 i) (FunctionCall 1 test_factorial_2 () [((IntegerConstant 4 (Integer 4 [])))] (Integer 4 []) () ()) ()) (= (Var 5 j) (FunctionCall 1 test_factorial_3 () [((IntegerConstant 5 (Integer 4 [])))] (Integer 8 []) () ()) ()) (Print () [(Var 5 i) (Var 5 j)])] Source Public Implementation () .false. .false.), main_program: (Program (SymbolTable 6 {}) main_program [] [(SubroutineCall 1 _lpython_main_program () [] ())]), test_factorial_1: (Function (SymbolTable 2 {_lpython_return_variable: (Variable 2 _lpython_return_variable ReturnVar () () Default (Integer 4 []) Source Public Required .false.), result: (Variable 2 result Local () () Default (Integer 4 []) Source Public Required .false.), x: (Variable 2 x In () () Default (Integer 4 []) Source Public Required .false.)}) test_factorial_1 [(Var 2 x)] [(If (Compare (Var 2 x) Lt (IntegerConstant 0 (Integer 4 [])) (Logical 4 []) () ()) [(= (Var 2 _lpython_return_variable) (IntegerConstant 0 (Integer 4 [])) ()) (Return)] []) (= (Var 2 result) (IntegerConstant 1 (Integer 4 [])) ()) (WhileLoop (Compare (Var 2 x) Gt (IntegerConstant 0 (Integer 4 [])) (Logical 4 []) () ()) [(= (Var 2 result) (BinOp (Var 2 result) Mul (Var 2 x) (Integer 4 []) () ()) ()) (= (Var 2 x) (BinOp (Var 2 x) Sub (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) () ()) ())]) (= (Var 2 _lpython_return_variable) (Var 2 result) ()) (Return)] (Var 2 _lpython_return_variable) Source Public Implementation ()), test_factorial_2: (Function (SymbolTable 3 {_lpython_return_variable: (Variable 3 _lpython_return_variable ReturnVar () () Default (Integer 4 []) Source Public Required .false.), i: (Variable 3 i Local () () Default (Integer 4 []) Source Public Required .false.), result: (Variable 3 result Local () () Default (Integer 4 []) Source Public Required .false.), x: (Variable 3 x In () () Default (Integer 4 []) Source Public Required .false.)}) test_factorial_2 [(Var 3 x)] [(= (Var 3 result) (IntegerConstant 1 (Integer 4 [])) ()) (DoLoop ((Var 3 i) (IntegerConstant 1 (Integer 4 [])) (BinOp (BinOp (Var 3 x) Add (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) () ()) Sub (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) () ()) (IntegerConstant 1 (Integer 4 []))) [(= (Var 3 result) (BinOp (Var 3 result) Mul (Var 3 i) (Integer 4 []) () ()) ())]) (= (Var 3 _lpython_return_variable) (Var 3 result) ()) (Return)] (Var 3 _lpython_return_variable) Source Public Implementation ()), test_factorial_3: (Function (SymbolTable 4 {_lpython_return_variable: (Variable 4 _lpython_return_variable ReturnVar () () Default (Integer 8 []) Source Public Required .false.), result: (Variable 4 result Local () () Default (Integer 8 []) Source Public Required .false.), x: (Variable 4 x In () () Default (Integer 4 []) Source Public Required .false.)}) test_factorial_3 [(Var 4 x)] [(If (Compare (Var 4 x) Lt (IntegerConstant 0 (Integer 4 [])) (Logical 4 []) () ()) [(= (Var 4 _lpython_return_variable) (Cast (IntegerConstant 0 (Integer 4 [])) IntegerToInteger (Integer 8 []) ()) ()) (Return)] []) (= (Var 4 result) (Cast (IntegerConstant 1 (Integer 4 [])) IntegerToInteger (Integer 8 []) ()) ()) (WhileLoop (Compare (Var 4 x) Gt (IntegerConstant 0 (Integer 4 [])) (Logical 4 []) () ()) [(= (Var 4 result) (BinOp (Var 4 result) Mul (Cast (Var 4 x) IntegerToInteger (Integer 8 []) ()) (Integer 8 []) () ()) ()) (= (Var 4 x) (BinOp (Var 4 x) Sub (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) () ()) ())]) (= (Var 4 _lpython_return_variable) (Var 4 result) ()) (Return)] (Var 4 _lpython_return_variable) Source Public Implementation ())}) []) diff --git a/tests/reference/ast-loop1-194a137.json b/tests/reference/ast-loop1-194a137.json index 6247241ab5..dee5dc4f67 100644 --- a/tests/reference/ast-loop1-194a137.json +++ b/tests/reference/ast-loop1-194a137.json @@ -2,11 +2,11 @@ "basename": "ast-loop1-194a137", "cmd": "lpython --show-ast --no-color {infile} -o {outfile}", "infile": "tests/loop1.py", - "infile_hash": "e50c7161122d599991fafb072d5db8fe7e54d017d56a5c1951a210ca", + "infile_hash": "a27a0e48b7c6291be0b0847f5e7a30c591c7168a9004395156d57dbd", "outfile": null, "outfile_hash": null, "stdout": "ast-loop1-194a137.stdout", - "stdout_hash": "0cc09fa5ddfef0db3b9115837fa64f543e814e01e7e4d1c94ebc7b78", + "stdout_hash": "fe2925f8d0ffd327d1626c46f2c6681d1a83ff5cd15011ef25f25d6d", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/ast-loop1-194a137.stdout b/tests/reference/ast-loop1-194a137.stdout index cfedd9abb8..2e84c72c75 100644 --- a/tests/reference/ast-loop1-194a137.stdout +++ b/tests/reference/ast-loop1-194a137.stdout @@ -1 +1 @@ -(Module [(FunctionDef test_factorial_1 ([] [(x (Name i32 Load) ())] [] [] [] [] []) [(If (Compare (Name x Load) Lt [(ConstantInt 0 ())]) [(Return (ConstantInt 0 ()))] []) (AnnAssign (Name result Store) (Name i32 Load) () 1) (Assign [(Name result Store)] (ConstantInt 1 ()) ()) (While (Compare (Name x Load) Gt [(ConstantInt 0 ())]) [(Assign [(Name result Store)] (BinOp (Name result Load) Mult (Name x Load)) ()) (AugAssign (Name x Store) Sub (ConstantInt 1 ()))] []) (Return (Name result Load))] [] (Name i32 Load) ()) (FunctionDef test_factorial_2 ([] [(x (Name i32 Load) ())] [] [] [] [] []) [(AnnAssign (Name result Store) (Name i32 Load) () 1) (Assign [(Name result Store)] (ConstantInt 1 ()) ()) (AnnAssign (Name i Store) (Name i32 Load) () 1) (For (Name i Store) (Call (Name range Load) [(ConstantInt 1 ()) (BinOp (Name x Load) Add (ConstantInt 1 ()))] []) [(Assign [(Name result Store)] (BinOp (Name result Load) Mult (Name i Load)) ())] [] ()) (Return (Name result Load))] [] (Name i32 Load) ()) (FunctionDef test_factorial_3 ([] [(x (Name i32 Load) ())] [] [] [] [] []) [(If (Compare (Name x Load) Lt [(ConstantInt 0 ())]) [(Return (ConstantInt 0 ()))] []) (AnnAssign (Name result Store) (Name i64 Load) () 1) (Assign [(Name result Store)] (ConstantInt 1 ()) ()) (While (Compare (Name x Load) Gt [(ConstantInt 0 ())]) [(Assign [(Name result Store)] (BinOp (Name result Load) Mult (Name x Load)) ()) (AugAssign (Name x Store) Sub (ConstantInt 1 ()))] []) (Return (Name result Load))] [] (Name i64 Load) ()) (FunctionDef main0 ([] [] [] [] [] [] []) [(AnnAssign (Name i Store) (Name i32 Load) () 1) (Assign [(Name i Store)] (Call (Name test_factorial_1 Load) [(ConstantInt 4 ())] []) ()) (Assign [(Name i Store)] (Call (Name test_factorial_2 Load) [(ConstantInt 4 ())] []) ()) (AnnAssign (Name j Store) (Name i64 Load) () 1) (Assign [(Name j Store)] (Call (Name test_factorial_3 Load) [(ConstantInt 5 ())] []) ())] [] () ()) (Expr (Call (Name main0 Load) [] []))] []) +(Module [(FunctionDef test_factorial_1 ([] [(x (Name i32 Load) ())] [] [] [] [] []) [(If (Compare (Name x Load) Lt [(ConstantInt 0 ())]) [(Return (ConstantInt 0 ()))] []) (AnnAssign (Name result Store) (Name i32 Load) () 1) (Assign [(Name result Store)] (ConstantInt 1 ()) ()) (While (Compare (Name x Load) Gt [(ConstantInt 0 ())]) [(Assign [(Name result Store)] (BinOp (Name result Load) Mult (Name x Load)) ()) (AugAssign (Name x Store) Sub (ConstantInt 1 ()))] []) (Return (Name result Load))] [] (Name i32 Load) ()) (FunctionDef test_factorial_2 ([] [(x (Name i32 Load) ())] [] [] [] [] []) [(AnnAssign (Name result Store) (Name i32 Load) () 1) (Assign [(Name result Store)] (ConstantInt 1 ()) ()) (AnnAssign (Name i Store) (Name i32 Load) () 1) (For (Name i Store) (Call (Name range Load) [(ConstantInt 1 ()) (BinOp (Name x Load) Add (ConstantInt 1 ()))] []) [(Assign [(Name result Store)] (BinOp (Name result Load) Mult (Name i Load)) ())] [] ()) (Return (Name result Load))] [] (Name i32 Load) ()) (FunctionDef test_factorial_3 ([] [(x (Name i32 Load) ())] [] [] [] [] []) [(If (Compare (Name x Load) Lt [(ConstantInt 0 ())]) [(Return (ConstantInt 0 ()))] []) (AnnAssign (Name result Store) (Name i64 Load) () 1) (Assign [(Name result Store)] (ConstantInt 1 ()) ()) (While (Compare (Name x Load) Gt [(ConstantInt 0 ())]) [(Assign [(Name result Store)] (BinOp (Name result Load) Mult (Name x Load)) ()) (AugAssign (Name x Store) Sub (ConstantInt 1 ()))] []) (Return (Name result Load))] [] (Name i64 Load) ()) (FunctionDef main0 ([] [] [] [] [] [] []) [(AnnAssign (Name i Store) (Name i32 Load) () 1) (Assign [(Name i Store)] (Call (Name test_factorial_1 Load) [(ConstantInt 4 ())] []) ()) (Assign [(Name i Store)] (Call (Name test_factorial_2 Load) [(ConstantInt 4 ())] []) ()) (AnnAssign (Name j Store) (Name i64 Load) () 1) (Assign [(Name j Store)] (Call (Name test_factorial_3 Load) [(ConstantInt 5 ())] []) ()) (Expr (Call (Name print Load) [(Name i Load) (Name j Load)] []))] [] () ()) (Expr (Call (Name main0 Load) [] []))] []) diff --git a/tests/reference/c-loop1-3e341c7.json b/tests/reference/c-loop1-3e341c7.json new file mode 100644 index 0000000000..cd02588b9e --- /dev/null +++ b/tests/reference/c-loop1-3e341c7.json @@ -0,0 +1,13 @@ +{ + "basename": "c-loop1-3e341c7", + "cmd": "lpython --no-color --show-c {infile}", + "infile": "tests/loop1.py", + "infile_hash": "a27a0e48b7c6291be0b0847f5e7a30c591c7168a9004395156d57dbd", + "outfile": null, + "outfile_hash": null, + "stdout": "c-loop1-3e341c7.stdout", + "stdout_hash": "ca5ae2d44ccd8b76aa54ec6c9523f8ae90205238f0b99dc14d6c0e71", + "stderr": null, + "stderr_hash": null, + "returncode": 0 +} \ No newline at end of file diff --git a/tests/reference/c-loop1-3e341c7.stdout b/tests/reference/c-loop1-3e341c7.stdout new file mode 100644 index 0000000000..2c37ca0c2f --- /dev/null +++ b/tests/reference/c-loop1-3e341c7.stdout @@ -0,0 +1,71 @@ +#include +#include +#include +#include +void _lpython_main_program() +{ + main0(); +} + +void main0() +{ + int i; + long long j; + i = test_factorial_1(4); + i = test_factorial_2(4); + j = test_factorial_3(5); + printf("%d %lli\n", i, j); +} + +int test_factorial_1(int x) +{ + int _lpython_return_variable; + int result; + if (x < 0) { + _lpython_return_variable = 0; + return _lpython_return_variable; + } + result = 1; + while (x > 0) { + result = result*x; + x = x - 1; + } + _lpython_return_variable = result; + return _lpython_return_variable; +} + +int test_factorial_2(int x) +{ + int _lpython_return_variable; + int i; + int result; + result = 1; + for (i=1; i<=x + 1 - 1; i++) { + result = result*i; + } + _lpython_return_variable = result; + return _lpython_return_variable; +} + +long long test_factorial_3(int x) +{ + long long _lpython_return_variable; + long long result; + if (x < 0) { + _lpython_return_variable = 0; + return _lpython_return_variable; + } + result = 1; + while (x > 0) { + result = result*x; + x = x - 1; + } + _lpython_return_variable = result; + return _lpython_return_variable; +} + +int main(int argc, char* argv[]) +{ + _lpython_main_program(); + return 0; +} diff --git a/tests/reference/cpp-loop1-0a8cf3b.json b/tests/reference/cpp-loop1-0a8cf3b.json index 964faa5b04..baf322f4af 100644 --- a/tests/reference/cpp-loop1-0a8cf3b.json +++ b/tests/reference/cpp-loop1-0a8cf3b.json @@ -2,11 +2,11 @@ "basename": "cpp-loop1-0a8cf3b", "cmd": "lpython --no-color --show-cpp {infile}", "infile": "tests/loop1.py", - "infile_hash": "e50c7161122d599991fafb072d5db8fe7e54d017d56a5c1951a210ca", + "infile_hash": "a27a0e48b7c6291be0b0847f5e7a30c591c7168a9004395156d57dbd", "outfile": null, "outfile_hash": null, "stdout": "cpp-loop1-0a8cf3b.stdout", - "stdout_hash": "79bcbb41c038ebb668a632a270d4ef7247bca02ceba219d7c9212b8f", + "stdout_hash": "c66205b4ecb49a0230d42af74e349dc313754f650801a9420008f99e", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/cpp-loop1-0a8cf3b.stdout b/tests/reference/cpp-loop1-0a8cf3b.stdout index 754ec73bbc..a94e7ee986 100644 --- a/tests/reference/cpp-loop1-0a8cf3b.stdout +++ b/tests/reference/cpp-loop1-0a8cf3b.stdout @@ -29,6 +29,7 @@ void main0() i = test_factorial_1(4); i = test_factorial_2(4); j = test_factorial_3(5); + std::cout << i << j << std::endl; } int test_factorial_1(int x) From fed1c9fbaf1e1e43cab183c5cf3683e04f6cad0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Tue, 17 May 2022 09:47:39 -0600 Subject: [PATCH 05/15] Parse strings of the "a" "b" "c" kind --- src/lpython/parser/parser.yy | 9 +++++++-- src/lpython/parser/semantics.h | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/lpython/parser/parser.yy b/src/lpython/parser/parser.yy index 9076e33cee..5ce75a7298 100644 --- a/src/lpython/parser/parser.yy +++ b/src/lpython/parser/parser.yy @@ -235,6 +235,7 @@ void yyerror(YYLTYPE *yyloc, LFortran::Parser &p, const std::string &msg) %type primary %type sep %type sep_one +%type string // Precedence @@ -664,10 +665,14 @@ function_call | primary "(" keyword_items ")" { $$ = CALL_03($1, $3, @$); } ; +string + : string TK_STRING { $$ = STRING2($1, $2, @$); } // TODO + | TK_STRING { $$ = STRING1($1, @$); } + expr : id { $$ = $1; } | TK_INTEGER { $$ = INTEGER($1, @$); } - | TK_STRING { $$ = STRING($1, @$); } + | string { $$ = $1; } | TK_REAL { $$ = FLOAT($1, @$); } | TK_IMAG_NUM { $$ = COMPLEX($1, @$); } | TK_TRUE { $$ = BOOL(true, @$); } @@ -679,7 +684,7 @@ expr | "{" expr_list "}" { $$ = SET($2, @$); } | "{" expr_list "," "}" { $$ = SET($2, @$); } | id "[" tuple_list "]" { $$ = SUBSCRIPT_01($1, $3, @$); } - | TK_STRING "[" tuple_list "]" { $$ = SUBSCRIPT_02($1, $3, @$); } + | string "[" tuple_list "]" { $$ = SUBSCRIPT_02($1, $3, @$); } | expr "." id { $$ = ATTRIBUTE_REF($1, $3, @$); } | "{" "}" { $$ = DICT_01(@$); } | "{" dict_list "}" { $$ = DICT_02($2, @$); } diff --git a/src/lpython/parser/semantics.h b/src/lpython/parser/semantics.h index 93cbd2451e..63daaef0d7 100644 --- a/src/lpython/parser/semantics.h +++ b/src/lpython/parser/semantics.h @@ -389,11 +389,17 @@ Vec MERGE_EXPR(Allocator &al, ast_t *x, ast_t *y) { #define COMPARE(x, op, y, l) make_Compare_t(p.m_a, l, \ EXPR(x), cmpopType::op, EXPRS(A2LIST(p.m_a, y)), 1) +char* concat_string(Allocator &al, ast_t *a, char *b) { + char *s = down_cast2(a)->m_value; + return LFortran::s2c(al, std::string(s) + std::string(b)); +} + #define SYMBOL(x, l) make_Name_t(p.m_a, l, \ x.c_str(p.m_a), expr_contextType::Load) // `x.int_n` is of type BigInt but we store the int64_t directly in AST #define INTEGER(x, l) make_ConstantInt_t(p.m_a, l, x, nullptr) -#define STRING(x, l) make_ConstantStr_t(p.m_a, l, x.c_str(p.m_a), nullptr) +#define STRING1(x, l) make_ConstantStr_t(p.m_a, l, x.c_str(p.m_a), nullptr) +#define STRING2(x, y, l) make_ConstantStr_t(p.m_a, l, concat_string(p.m_a, x, y.c_str(p.m_a)), nullptr) #define FLOAT(x, l) make_ConstantFloat_t(p.m_a, l, x, nullptr) #define COMPLEX(x, l) make_ConstantComplex_t(p.m_a, l, 0, x, nullptr) #define BOOL(x, l) make_ConstantBool_t(p.m_a, l, x, nullptr) @@ -432,7 +438,7 @@ expr_t* CHECK_TUPLE(expr_t *x) { #define SUBSCRIPT_01(value, slice, l) make_Subscript_t(p.m_a, l, \ EXPR(value), CHECK_TUPLE(EXPR(slice)), expr_contextType::Load) #define SUBSCRIPT_02(s, slice, l) make_Subscript_t(p.m_a, l, \ - EXPR(STRING(s, l)), CHECK_TUPLE(EXPR(slice)), expr_contextType::Load) + EXPR(s), CHECK_TUPLE(EXPR(slice)), expr_contextType::Load) static inline ast_t* SLICE(Allocator &al, Location &l, ast_t *lower, ast_t *upper, ast_t *_step) { From f0e48f0736efac883776f4e7a6087a5cd8fccc4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Tue, 17 May 2022 09:57:00 -0600 Subject: [PATCH 06/15] Parse ellipsis (...) in the old parser --- grammar/Python.asdl | 1 + src/runtime/lpython_parser.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/grammar/Python.asdl b/grammar/Python.asdl index b0720ded01..1cdf8b5e5f 100644 --- a/grammar/Python.asdl +++ b/grammar/Python.asdl @@ -83,6 +83,7 @@ module LPython | ConstantBool(bool value, string? kind) | ConstantFloat(float value, string? kind) | ConstantComplex(float re, float im, string? kind) + | ConstantEllipsis(string? kind) -- the following expression can appear in assignment context | Attribute(expr value, identifier attr, expr_context ctx) diff --git a/src/runtime/lpython_parser.py b/src/runtime/lpython_parser.py index 2ad5ad90a3..d369e8b8b9 100644 --- a/src/runtime/lpython_parser.py +++ b/src/runtime/lpython_parser.py @@ -50,6 +50,8 @@ def visit_Constant(self, node): elif isinstance(node.value, complex): new_node = python_ast.ConstantComplex(node.value.real, node.value.imag, node.kind) + elif isinstance(node.value, Ellipsis.__class__): + new_node = python_ast.ConstantEllipsis(node.kind) else: print(type(node.value)) raise Exception("Unsupported Constant type") From 68e9f58a41c591969197b5c75ac9e33bd6a92703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Tue, 17 May 2022 09:59:24 -0600 Subject: [PATCH 07/15] Parse None in the old parser --- grammar/Python.asdl | 1 + src/runtime/lpython_parser.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/grammar/Python.asdl b/grammar/Python.asdl index 1cdf8b5e5f..85fb170651 100644 --- a/grammar/Python.asdl +++ b/grammar/Python.asdl @@ -84,6 +84,7 @@ module LPython | ConstantFloat(float value, string? kind) | ConstantComplex(float re, float im, string? kind) | ConstantEllipsis(string? kind) + | ConstantNone(string? kind) -- the following expression can appear in assignment context | Attribute(expr value, identifier attr, expr_context ctx) diff --git a/src/runtime/lpython_parser.py b/src/runtime/lpython_parser.py index d369e8b8b9..02e9c37bd0 100644 --- a/src/runtime/lpython_parser.py +++ b/src/runtime/lpython_parser.py @@ -52,6 +52,8 @@ def visit_Constant(self, node): node.value.imag, node.kind) elif isinstance(node.value, Ellipsis.__class__): new_node = python_ast.ConstantEllipsis(node.kind) + elif isinstance(node.value, None.__class__): + new_node = python_ast.ConstantNone(node.kind) else: print(type(node.value)) raise Exception("Unsupported Constant type") From d13bd36572f8de461a7ac1cb295c0d00fa69bb76 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Wed, 18 May 2022 11:28:56 +0530 Subject: [PATCH 08/15] Parse Comments after decorators --- src/lpython/parser/parser.yy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lpython/parser/parser.yy b/src/lpython/parser/parser.yy index 9076e33cee..aa7ca09829 100644 --- a/src/lpython/parser/parser.yy +++ b/src/lpython/parser/parser.yy @@ -516,8 +516,8 @@ decorators_opt ; decorators - : decorators "@" expr TK_NEWLINE { $$ = $1; LIST_ADD($$, $3); } - | "@" expr TK_NEWLINE { LIST_NEW($$); LIST_ADD($$, $2); } + : decorators "@" expr sep { $$ = $1; LIST_ADD($$, $3); } + | "@" expr sep { LIST_NEW($$); LIST_ADD($$, $2); } ; parameter @@ -606,7 +606,7 @@ slice_item | expr ":" { $$ = SLICE_01( $1, nullptr, nullptr, @$); } | ":" expr { $$ = SLICE_01(nullptr, $2, nullptr, @$); } | expr ":" expr { $$ = SLICE_01( $1, $3, nullptr, @$); } - | ":" ":" { $$ = SLICE_01(nullptr, nullptr, nullptr, @$); } + | ":" ":" { $$ = SLICE_01(nullptr, nullptr, nullptr, @$); } | ":" ":" expr { $$ = SLICE_01(nullptr, nullptr, $3, @$); } | expr ":" ":" { $$ = SLICE_01( $1, nullptr, nullptr, @$); } | ":" expr ":" { $$ = SLICE_01(nullptr, $2, nullptr, @$); } From 43a395ef1d9308304967db39545434e7cf27717e Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Wed, 18 May 2022 11:30:03 +0530 Subject: [PATCH 09/15] Update tests --- tests/parser/function_def1.py | 5 +++++ tests/reference/ast_new-function_def1-1a872df.json | 4 ++-- tests/reference/ast_new-function_def1-1a872df.stdout | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/parser/function_def1.py b/tests/parser/function_def1.py index 063ef83683..c3f2b4726b 100644 --- a/tests/parser/function_def1.py +++ b/tests/parser/function_def1.py @@ -33,6 +33,11 @@ def tri_recursion(k): def test(a: i32) -> i32: return a + 10 +@overload +# Comment +def test(a: i64) -> i64: + return a + 10 + @overload def test(a: bool) -> i32: if a: diff --git a/tests/reference/ast_new-function_def1-1a872df.json b/tests/reference/ast_new-function_def1-1a872df.json index c484665423..013bebf758 100644 --- a/tests/reference/ast_new-function_def1-1a872df.json +++ b/tests/reference/ast_new-function_def1-1a872df.json @@ -2,11 +2,11 @@ "basename": "ast_new-function_def1-1a872df", "cmd": "lpython --show-ast --new-parser --no-color {infile} -o {outfile}", "infile": "tests/parser/function_def1.py", - "infile_hash": "4224c0bffeb39c449abfeba907eba690ee5ff15f9514c9a0c0922a92", + "infile_hash": "9dc3cbaa399b8013e99cf165c76d468cf48edde757daafc4069cda40", "outfile": null, "outfile_hash": null, "stdout": "ast_new-function_def1-1a872df.stdout", - "stdout_hash": "19677f67c936f188ba070291048c6dd20a815c5fe66c13570051b3e7", + "stdout_hash": "62bdf27fa9795b9cad94f2747ac48dfac223ef7401dc9af0b445c5a8", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/ast_new-function_def1-1a872df.stdout b/tests/reference/ast_new-function_def1-1a872df.stdout index d5823785ed..d383b67a1c 100644 --- a/tests/reference/ast_new-function_def1-1a872df.stdout +++ b/tests/reference/ast_new-function_def1-1a872df.stdout @@ -3,4 +3,4 @@ the person passed in as a parameter " ())) (Expr (Call (Name print Load) [(BinOp (BinOp (ConstantStr "Hello, " ()) Add (Name name Load)) Add (ConstantStr ". Good morning!" ()))] []))] [] () ()) (FunctionDef absolute_value ([] [(num () ())] [] [] [] [] []) [(Expr (ConstantStr "This function returns the absolute - value of the entered number" ())) (If (Compare (Name num Load) GtE [(ConstantInt 0 ())]) [(Return (Name num Load))] [(Return (UnaryOp USub (Name num Load)))])] [] () ()) (FunctionDef combine ([] [(fname () ()) (lname () ())] [] [] [] [] []) [(Expr (Call (Name print Load) [(BinOp (BinOp (Name fname Load) Add (ConstantStr " " ())) Add (Name lname Load))] []))] [] () ()) (FunctionDef tri_recursion ([] [(k () ())] [] [] [] [] []) [(If (Compare (Name k Load) Gt [(ConstantInt 0 ())]) [(Assign [(Name result Store)] (BinOp (Name k Load) Add (Call (Name tri_recursion Load) [(BinOp (Name k Load) Sub (ConstantInt 1 ()))] [])) ()) (Expr (Call (Name print Load) [(Name result Load)] []))] [(Assign [(Name result Store)] (ConstantInt 0 ()) ())]) (Return (Name result Load))] [] () ()) (FunctionDef test ([] [(a (Name i32 Load) ())] [] [] [] [] []) [(Return (BinOp (Name a Load) Add (ConstantInt 10 ())))] [(Name overload Load)] (Name i32 Load) ()) (FunctionDef test ([] [(a (Name bool Load) ())] [] [] [] [] []) [(If (Name a Load) [(Return (ConstantInt 10 ()))] []) (Return (UnaryOp USub (ConstantInt 10 ())))] [(Name overload Load)] (Name i32 Load) ()) (FunctionDef check ([] [] [] [] [] [] []) [(Expr (Call (Name greet Load) [(ConstantStr "Xyz" ())] [])) (Expr (Call (Name print Load) [(Call (Name absolute_value Load) [(ConstantInt 2 ())] [])] [])) (Expr (Call (Name combine Load) [(ConstantStr "LPython" ()) (ConstantStr "Compiler" ())] [])) (Expr (Call (Name print Load) [(ConstantStr "Recursion Example Results: " ())] [])) (Expr (Call (Name tri_recursion Load) [(ConstantInt 6 ())] [])) (Expr (Call (Name print Load) [(Call (Name test Load) [(ConstantInt 15 ())] [])] [])) (Expr (Call (Name print Load) [(Call (Name test Load) [(ConstantBool .true. ())] [])] []))] [] () ()) (Expr (Call (Name check Load) [] []))] []) + value of the entered number" ())) (If (Compare (Name num Load) GtE [(ConstantInt 0 ())]) [(Return (Name num Load))] [(Return (UnaryOp USub (Name num Load)))])] [] () ()) (FunctionDef combine ([] [(fname () ()) (lname () ())] [] [] [] [] []) [(Expr (Call (Name print Load) [(BinOp (BinOp (Name fname Load) Add (ConstantStr " " ())) Add (Name lname Load))] []))] [] () ()) (FunctionDef tri_recursion ([] [(k () ())] [] [] [] [] []) [(If (Compare (Name k Load) Gt [(ConstantInt 0 ())]) [(Assign [(Name result Store)] (BinOp (Name k Load) Add (Call (Name tri_recursion Load) [(BinOp (Name k Load) Sub (ConstantInt 1 ()))] [])) ()) (Expr (Call (Name print Load) [(Name result Load)] []))] [(Assign [(Name result Store)] (ConstantInt 0 ()) ())]) (Return (Name result Load))] [] () ()) (FunctionDef test ([] [(a (Name i32 Load) ())] [] [] [] [] []) [(Return (BinOp (Name a Load) Add (ConstantInt 10 ())))] [(Name overload Load)] (Name i32 Load) ()) (FunctionDef test ([] [(a (Name i64 Load) ())] [] [] [] [] []) [(Return (BinOp (Name a Load) Add (ConstantInt 10 ())))] [(Name overload Load)] (Name i64 Load) ()) (FunctionDef test ([] [(a (Name bool Load) ())] [] [] [] [] []) [(If (Name a Load) [(Return (ConstantInt 10 ()))] []) (Return (UnaryOp USub (ConstantInt 10 ())))] [(Name overload Load)] (Name i32 Load) ()) (FunctionDef check ([] [] [] [] [] [] []) [(Expr (Call (Name greet Load) [(ConstantStr "Xyz" ())] [])) (Expr (Call (Name print Load) [(Call (Name absolute_value Load) [(ConstantInt 2 ())] [])] [])) (Expr (Call (Name combine Load) [(ConstantStr "LPython" ()) (ConstantStr "Compiler" ())] [])) (Expr (Call (Name print Load) [(ConstantStr "Recursion Example Results: " ())] [])) (Expr (Call (Name tri_recursion Load) [(ConstantInt 6 ())] [])) (Expr (Call (Name print Load) [(Call (Name test Load) [(ConstantInt 15 ())] [])] [])) (Expr (Call (Name print Load) [(Call (Name test Load) [(ConstantBool .true. ())] [])] []))] [] () ()) (Expr (Call (Name check Load) [] []))] []) From c57fa7b398ccd3cbda125f59e93bbeaa7fee3749 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Wed, 18 May 2022 11:54:46 +0530 Subject: [PATCH 10/15] Add tests and Update the references --- tests/parser/ellipsis1.py | 37 ++++++++++++++++++++ tests/reference/ast-ellipsis1-4f6c4dd.json | 13 +++++++ tests/reference/ast-ellipsis1-4f6c4dd.stdout | 1 + tests/tests.toml | 4 +++ 4 files changed, 55 insertions(+) create mode 100644 tests/parser/ellipsis1.py create mode 100644 tests/reference/ast-ellipsis1-4f6c4dd.json create mode 100644 tests/reference/ast-ellipsis1-4f6c4dd.stdout diff --git a/tests/parser/ellipsis1.py b/tests/parser/ellipsis1.py new file mode 100644 index 0000000000..23f4436da8 --- /dev/null +++ b/tests/parser/ellipsis1.py @@ -0,0 +1,37 @@ +import numpy as np +from typing import Callable + +array = np.random.rand(2, 2, 2, 2) +print(array[..., 0]) +print(array[Ellipsis, 0]) + +def inject(get_next_item: Callable[..., str]) -> None: + ... + +def foo(x: ...) -> None: + ... + +class flow: + def __understand__(self, name: str, value: ...) -> None: ... + +def foo(x = ...): + return x + +def test(): + ... + +class Todo: + ... + +x = [1, [2, [...], 3]] +l = [..., 1, 2, 3] + +if x is ...: + pass + +def partial(func: Callable[..., str], *args) -> Callable[..., str]: + pass + +class xyz: + abc: str = ... + def __init__(self, name: str=...) -> None: ... diff --git a/tests/reference/ast-ellipsis1-4f6c4dd.json b/tests/reference/ast-ellipsis1-4f6c4dd.json new file mode 100644 index 0000000000..0e042fd21c --- /dev/null +++ b/tests/reference/ast-ellipsis1-4f6c4dd.json @@ -0,0 +1,13 @@ +{ + "basename": "ast-ellipsis1-4f6c4dd", + "cmd": "lpython --show-ast --no-color {infile} -o {outfile}", + "infile": "tests/parser/ellipsis1.py", + "infile_hash": "24df29cba718c679016f3758a2eccafbeb9cfebd56265fd8da16bee1", + "outfile": null, + "outfile_hash": null, + "stdout": "ast-ellipsis1-4f6c4dd.stdout", + "stdout_hash": "99ae0e12fd8efcd71433e66f10ba7ba5b59e165ddd5ded0072593b12", + "stderr": null, + "stderr_hash": null, + "returncode": 0 +} \ No newline at end of file diff --git a/tests/reference/ast-ellipsis1-4f6c4dd.stdout b/tests/reference/ast-ellipsis1-4f6c4dd.stdout new file mode 100644 index 0000000000..51aa9eb229 --- /dev/null +++ b/tests/reference/ast-ellipsis1-4f6c4dd.stdout @@ -0,0 +1 @@ +(Module [(Import [(numpy np)]) (ImportFrom typing [(Callable ())] 0) (Assign [(Name array Store)] (Call (Attribute (Attribute (Name np Load) random Load) rand Load) [(ConstantInt 2 ()) (ConstantInt 2 ()) (ConstantInt 2 ()) (ConstantInt 2 ())] []) ()) (Expr (Call (Name print Load) [(Subscript (Name array Load) (Tuple [(ConstantEllipsis ()) (ConstantInt 0 ())] Load) Load)] [])) (Expr (Call (Name print Load) [(Subscript (Name array Load) (Tuple [(Name Ellipsis Load) (ConstantInt 0 ())] Load) Load)] [])) (FunctionDef inject ([] [(get_next_item (Subscript (Name Callable Load) (Tuple [(ConstantEllipsis ()) (Name str Load)] Load) Load) ())] [] [] [] [] []) [(Expr (ConstantEllipsis ()))] [] (ConstantNone ()) ()) (FunctionDef foo ([] [(x (ConstantEllipsis ()) ())] [] [] [] [] []) [(Expr (ConstantEllipsis ()))] [] (ConstantNone ()) ()) (ClassDef flow [] [] [(FunctionDef __understand__ ([] [(self () ()) (name (Name str Load) ()) (value (ConstantEllipsis ()) ())] [] [] [] [] []) [(Expr (ConstantEllipsis ()))] [] (ConstantNone ()) ())] []) (FunctionDef foo ([] [(x () ())] [] [] [] [] [(ConstantEllipsis ())]) [(Return (Name x Load))] [] () ()) (FunctionDef test ([] [] [] [] [] [] []) [(Expr (ConstantEllipsis ()))] [] () ()) (ClassDef Todo [] [] [(Expr (ConstantEllipsis ()))] []) (Assign [(Name x Store)] (List [(ConstantInt 1 ()) (List [(ConstantInt 2 ()) (List [(ConstantEllipsis ())] Load) (ConstantInt 3 ())] Load)] Load) ()) (Assign [(Name l Store)] (List [(ConstantEllipsis ()) (ConstantInt 1 ()) (ConstantInt 2 ()) (ConstantInt 3 ())] Load) ()) (If (Compare (Name x Load) Is [(ConstantEllipsis ())]) [(Pass)] []) (FunctionDef partial ([] [(func (Subscript (Name Callable Load) (Tuple [(ConstantEllipsis ()) (Name str Load)] Load) Load) ())] [(args () ())] [] [] [] []) [(Pass)] [] (Subscript (Name Callable Load) (Tuple [(ConstantEllipsis ()) (Name str Load)] Load) Load) ()) (ClassDef xyz [] [] [(AnnAssign (Name abc Store) (Name str Load) (ConstantEllipsis ()) 1) (FunctionDef __init__ ([] [(self () ()) (name (Name str Load) ())] [] [] [] [] [(ConstantEllipsis ())]) [(Expr (ConstantEllipsis ()))] [] (ConstantNone ()) ())] [])] []) diff --git a/tests/tests.toml b/tests/tests.toml index e0f45a8a2a..d2b205f55d 100644 --- a/tests/tests.toml +++ b/tests/tests.toml @@ -318,6 +318,10 @@ ast_new = true filename = "parser/slice1.py" ast_new = true +[[test]] +filename = "parser/ellipsis1.py" +ast = true + # tests/errors [[test]] From 62df3f00f96000be695599f592b6d3e340e747b5 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Wed, 18 May 2022 12:10:44 +0530 Subject: [PATCH 11/15] Add tests and Update the references --- tests/parser/statements1.py | 14 ++++++++++++++ tests/reference/ast_new-statements1-e081093.json | 4 ++-- tests/reference/ast_new-statements1-e081093.stdout | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/parser/statements1.py b/tests/parser/statements1.py index 6e07eb39e6..1241e0ef4e 100644 --- a/tests/parser/statements1.py +++ b/tests/parser/statements1.py @@ -51,6 +51,20 @@ 12+3j .12+.001j "String" +"String " "String" +'String ' 'String' +'String ' "String" +"String " "String"[1:] +x = ("String " +"String") +x = ("String " + +"String") +x = ("String " \ +"String") +x = "String " \ +"String" +x = "String " +"String" True False diff --git a/tests/reference/ast_new-statements1-e081093.json b/tests/reference/ast_new-statements1-e081093.json index b53ed8873b..a5e3aae4dc 100644 --- a/tests/reference/ast_new-statements1-e081093.json +++ b/tests/reference/ast_new-statements1-e081093.json @@ -2,11 +2,11 @@ "basename": "ast_new-statements1-e081093", "cmd": "lpython --show-ast --new-parser --no-color {infile} -o {outfile}", "infile": "tests/parser/statements1.py", - "infile_hash": "4aaaf4ec5106c798f6b639b7dab587b4b9c8412b2029b384445e4b20", + "infile_hash": "9110211f2f42a7add5e5f1d8d27205c9b52f90a922e82c5f1c47fabc", "outfile": null, "outfile_hash": null, "stdout": "ast_new-statements1-e081093.stdout", - "stdout_hash": "6fa494880a0bec62c30b15379701a5d5c277817940419d8379312bb6", + "stdout_hash": "fbd2a56fb302bc7ecc52f37193f7646e3eb3c0e78d18d19c451b7427", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/ast_new-statements1-e081093.stdout b/tests/reference/ast_new-statements1-e081093.stdout index 4b84ca47d0..dc3802a524 100644 --- a/tests/reference/ast_new-statements1-e081093.stdout +++ b/tests/reference/ast_new-statements1-e081093.stdout @@ -1 +1 @@ -(Module [(Pass) (Break) (Continue) (Raise () ()) (Raise (Call (Name NameError Load) [(ConstantStr "String" ())] []) ()) (Raise (Name RuntimeError Load) (Name exc Load)) (Assert (Compare (Call (Name len Load) [(Name marks Load)] []) NotEq [(ConstantInt 0 ())]) (ConstantStr "List is empty." ())) (Assert (Compare (Name x Load) Eq [(ConstantStr "String" ())]) ()) (Assign [(Name x Store)] (ConstantInt 1 ()) ()) (Assign [(Tuple [(Name x Store) (Name y Store)] Store)] (Call (Name x Load) [] []) ()) (Assign [(Name x Store) (Name y Store)] (ConstantInt 1 ()) ()) (Assign [(Tuple [(Name x Store) (Name y Store)] Store)] (Tuple [(ConstantInt 1 ()) (ConstantInt 2 ())] Store) ()) (Assign [(Subscript (Name x Load) (Name i Load) Store)] (Tuple [(ConstantInt 1 ()) (ConstantInt 2 ())] Store) ()) (AugAssign (Name x Store) Add (ConstantInt 1 ())) (AnnAssign (Name x Store) (Name i64 Load) () 1) (AnnAssign (Name y Store) (Name i32 Load) (ConstantInt 1 ()) 1) (Delete [(Name x Del)]) (Delete [(Name x Del) (Name y Del)]) (Return ()) (Return (BinOp (Name a Load) Add (Name b Load))) (Return (Call (Name x Load) [(Name a Load)] [])) (Return (Tuple [(Name x Store) (Name y Store)] Store)) (Global [a]) (Global [a b]) (Nonlocal [a]) (Nonlocal [a b]) (Expr (ConstantInt 123 ())) (Expr (UnaryOp USub (ConstantInt 123 ()))) (Expr (UnaryOp USub (ConstantInt 291 ()))) (Expr (ConstantInt 6844 ())) (Expr (UnaryOp USub (ConstantInt 83 ()))) (Expr (ConstantInt 87 ())) (Expr (UnaryOp USub (ConstantInt 13 ()))) (Expr (ConstantInt 13 ())) (Expr (ConstantFloat 123.000000 ())) (Expr (ConstantFloat 123.450000 ())) (Expr (ConstantFloat 123400000000.000000 ())) (Expr (BinOp (ConstantInt 12 ()) Add (ConstantComplex 0.000000 3.000000 ()))) (Expr (BinOp (ConstantFloat 0.120000 ()) Add (ConstantComplex 0.000000 0.001000 ()))) (Expr (ConstantStr "String" ())) (Expr (ConstantBool .true. ())) (Expr (ConstantBool .false. ())) (Expr (BinOp (BinOp (Name x Load) Add (Name y Load)) Mult (Name z Load))) (Expr (BinOp (Name x Load) Sub (Name y Load))) (Expr (BinOp (Name x Load) Mult (Name y Load))) (Expr (BinOp (Name x Load) Div (Name y Load))) (Expr (BinOp (Name x Load) Mod (Name y Load))) (Expr (UnaryOp USub (Name y Load))) (Expr (UnaryOp UAdd (Name y Load))) (Expr (UnaryOp Invert (Name y Load))) (Expr (BinOp (Name x Load) Pow (Name y Load))) (Expr (BinOp (Name x Load) FloorDiv (Name y Load))) (Expr (BinOp (Name x Load) MatMult (Name y Load))) (Expr (BinOp (Name x Load) BitAnd (Name y Load))) (Expr (BinOp (Name x Load) BitOr (Name y Load))) (Expr (BinOp (Name x Load) BitXor (Name y Load))) (Expr (BinOp (Name x Load) LShift (Name y Load))) (Expr (BinOp (Name x Load) RShift (Name y Load))) (Expr (Compare (Name x Load) Eq [(Name y Load)])) (Expr (Compare (Name x Load) NotEq [(Name y Load)])) (Expr (Compare (Name x Load) Lt [(Name y Load)])) (Expr (Compare (Name x Load) LtE [(Name y Load)])) (Expr (Compare (Name x Load) Gt [(Name y Load)])) (Expr (Compare (Name x Load) GtE [(Name y Load)])) (AnnAssign (Name i Store) (Name i32 Load) (ConstantInt 4 ()) 1) (If (Compare (ConstantInt 2 ()) Gt [(Name i Load)]) [(Pass)] []) (If (Compare (Name i Load) Gt [(ConstantInt 5 ())]) [(Break)] []) (If (BoolOp And [(Compare (Name i Load) Eq [(ConstantInt 5 ())]) (Compare (Name i Load) Lt [(ConstantInt 10 ())])]) [(Assign [(Name i Store)] (ConstantInt 3 ()) ())] []) (For (Name i Store) (Call (Name range Load) [(Name N Load)] []) [(Assign [(Subscript (Name c Load) (Name i Load) Store)] (BinOp (Subscript (Name a Load) (Name i Load) Load) Add (BinOp (Name scalar Load) Mult (Subscript (Name b Load) (Name i Load) Load))) ())] [] ()) (Assign [(Name x Store)] (NamedExpr (Name y Store) (ConstantInt 0 ())) ()) (If (NamedExpr (Name a Store) (Call (Name ord Load) [(ConstantStr "3" ())] [])) [(Assign [(Name x Store)] (ConstantInt 1 ()) ())] []) (Assign [(Name a Store)] (Set [(ConstantInt 1 ()) (ConstantInt 2 ()) (ConstantInt 3 ())]) ())] []) +(Module [(Pass) (Break) (Continue) (Raise () ()) (Raise (Call (Name NameError Load) [(ConstantStr "String" ())] []) ()) (Raise (Name RuntimeError Load) (Name exc Load)) (Assert (Compare (Call (Name len Load) [(Name marks Load)] []) NotEq [(ConstantInt 0 ())]) (ConstantStr "List is empty." ())) (Assert (Compare (Name x Load) Eq [(ConstantStr "String" ())]) ()) (Assign [(Name x Store)] (ConstantInt 1 ()) ()) (Assign [(Tuple [(Name x Store) (Name y Store)] Store)] (Call (Name x Load) [] []) ()) (Assign [(Name x Store) (Name y Store)] (ConstantInt 1 ()) ()) (Assign [(Tuple [(Name x Store) (Name y Store)] Store)] (Tuple [(ConstantInt 1 ()) (ConstantInt 2 ())] Store) ()) (Assign [(Subscript (Name x Load) (Name i Load) Store)] (Tuple [(ConstantInt 1 ()) (ConstantInt 2 ())] Store) ()) (AugAssign (Name x Store) Add (ConstantInt 1 ())) (AnnAssign (Name x Store) (Name i64 Load) () 1) (AnnAssign (Name y Store) (Name i32 Load) (ConstantInt 1 ()) 1) (Delete [(Name x Del)]) (Delete [(Name x Del) (Name y Del)]) (Return ()) (Return (BinOp (Name a Load) Add (Name b Load))) (Return (Call (Name x Load) [(Name a Load)] [])) (Return (Tuple [(Name x Store) (Name y Store)] Store)) (Global [a]) (Global [a b]) (Nonlocal [a]) (Nonlocal [a b]) (Expr (ConstantInt 123 ())) (Expr (UnaryOp USub (ConstantInt 123 ()))) (Expr (UnaryOp USub (ConstantInt 291 ()))) (Expr (ConstantInt 6844 ())) (Expr (UnaryOp USub (ConstantInt 83 ()))) (Expr (ConstantInt 87 ())) (Expr (UnaryOp USub (ConstantInt 13 ()))) (Expr (ConstantInt 13 ())) (Expr (ConstantFloat 123.000000 ())) (Expr (ConstantFloat 123.450000 ())) (Expr (ConstantFloat 123400000000.000000 ())) (Expr (BinOp (ConstantInt 12 ()) Add (ConstantComplex 0.000000 3.000000 ()))) (Expr (BinOp (ConstantFloat 0.120000 ()) Add (ConstantComplex 0.000000 0.001000 ()))) (Expr (ConstantStr "String" ())) (Expr (ConstantStr "String String" ())) (Expr (ConstantStr "String String" ())) (Expr (ConstantStr "String String" ())) (Expr (Subscript (ConstantStr "String String" ()) (Slice (ConstantInt 1 ()) () ()) Load)) (Assign [(Name x Store)] (ConstantStr "String String" ()) ()) (Assign [(Name x Store)] (BinOp (ConstantStr "String " ()) Add (ConstantStr "String" ())) ()) (Assign [(Name x Store)] (ConstantStr "String String" ()) ()) (Assign [(Name x Store)] (ConstantStr "String String" ()) ()) (Assign [(Name x Store)] (ConstantStr "String " ()) ()) (Expr (ConstantStr "String" ())) (Expr (ConstantBool .true. ())) (Expr (ConstantBool .false. ())) (Expr (BinOp (BinOp (Name x Load) Add (Name y Load)) Mult (Name z Load))) (Expr (BinOp (Name x Load) Sub (Name y Load))) (Expr (BinOp (Name x Load) Mult (Name y Load))) (Expr (BinOp (Name x Load) Div (Name y Load))) (Expr (BinOp (Name x Load) Mod (Name y Load))) (Expr (UnaryOp USub (Name y Load))) (Expr (UnaryOp UAdd (Name y Load))) (Expr (UnaryOp Invert (Name y Load))) (Expr (BinOp (Name x Load) Pow (Name y Load))) (Expr (BinOp (Name x Load) FloorDiv (Name y Load))) (Expr (BinOp (Name x Load) MatMult (Name y Load))) (Expr (BinOp (Name x Load) BitAnd (Name y Load))) (Expr (BinOp (Name x Load) BitOr (Name y Load))) (Expr (BinOp (Name x Load) BitXor (Name y Load))) (Expr (BinOp (Name x Load) LShift (Name y Load))) (Expr (BinOp (Name x Load) RShift (Name y Load))) (Expr (Compare (Name x Load) Eq [(Name y Load)])) (Expr (Compare (Name x Load) NotEq [(Name y Load)])) (Expr (Compare (Name x Load) Lt [(Name y Load)])) (Expr (Compare (Name x Load) LtE [(Name y Load)])) (Expr (Compare (Name x Load) Gt [(Name y Load)])) (Expr (Compare (Name x Load) GtE [(Name y Load)])) (AnnAssign (Name i Store) (Name i32 Load) (ConstantInt 4 ()) 1) (If (Compare (ConstantInt 2 ()) Gt [(Name i Load)]) [(Pass)] []) (If (Compare (Name i Load) Gt [(ConstantInt 5 ())]) [(Break)] []) (If (BoolOp And [(Compare (Name i Load) Eq [(ConstantInt 5 ())]) (Compare (Name i Load) Lt [(ConstantInt 10 ())])]) [(Assign [(Name i Store)] (ConstantInt 3 ()) ())] []) (For (Name i Store) (Call (Name range Load) [(Name N Load)] []) [(Assign [(Subscript (Name c Load) (Name i Load) Store)] (BinOp (Subscript (Name a Load) (Name i Load) Load) Add (BinOp (Name scalar Load) Mult (Subscript (Name b Load) (Name i Load) Load))) ())] [] ()) (Assign [(Name x Store)] (NamedExpr (Name y Store) (ConstantInt 0 ())) ()) (If (NamedExpr (Name a Store) (Call (Name ord Load) [(ConstantStr "3" ())] [])) [(Assign [(Name x Store)] (ConstantInt 1 ()) ())] []) (Assign [(Name a Store)] (Set [(ConstantInt 1 ()) (ConstantInt 2 ()) (ConstantInt 3 ())]) ())] []) From 0adddd79526d30aa797d4bd828b0a1d8af8fb775 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Thu, 19 May 2022 00:15:02 +0530 Subject: [PATCH 12/15] Parse Tuple as target in for statement --- src/lpython/parser/parser.yy | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lpython/parser/parser.yy b/src/lpython/parser/parser.yy index aa7ca09829..9cd23b5a8e 100644 --- a/src/lpython/parser/parser.yy +++ b/src/lpython/parser/parser.yy @@ -468,9 +468,10 @@ if_statement ; for_statement - : KW_FOR expr KW_IN expr ":" sep statements { $$ = FOR_01($2, $4, $7, @$); } - | KW_FOR expr KW_IN expr ":" sep statements KW_ELSE ":" sep statements { - $$ = FOR_02($2, $4, $7, $11, @$); } + : KW_FOR tuple_item KW_IN expr ":" sep statements { + $$ = FOR_01($2, $4, $7, @$); } + | KW_FOR tuple_item KW_IN expr ":" sep statements KW_ELSE ":" + sep statements { $$ = FOR_02($2, $4, $7, $11, @$); } ; except_statement @@ -584,9 +585,9 @@ async_func_def ; async_for_stmt - : KW_ASYNC KW_FOR expr KW_IN expr ":" sep statements { + : KW_ASYNC KW_FOR tuple_item KW_IN expr ":" sep statements { $$ = ASYNC_FOR_01($3, $5, $8, @$); } - | KW_ASYNC KW_FOR expr KW_IN expr ":" sep statements KW_ELSE ":" sep + | KW_ASYNC KW_FOR tuple_item KW_IN expr ":" sep statements KW_ELSE ":" sep statements { $$ = ASYNC_FOR_02($3, $5, $8, $12, @$); } ; From bf3fd6d8ebd53a8d8c52bf63af159d084d49adfa Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Thu, 19 May 2022 00:15:12 +0530 Subject: [PATCH 13/15] Update tests --- tests/parser/for1.py | 9 +++++++++ tests/reference/ast_new-for1-887432e.json | 4 ++-- tests/reference/ast_new-for1-887432e.stdout | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/parser/for1.py b/tests/parser/for1.py index 3a5b12d165..24d7e87f23 100644 --- a/tests/parser/for1.py +++ b/tests/parser/for1.py @@ -31,3 +31,12 @@ sum: i32 = 0 for j in range(5): sum += j + +for _, x in y: + pass + +for (x, y) in z: + pass + +for i, a in enumerate([4, 5, 6, 7]): + print(i, ": ", a) diff --git a/tests/reference/ast_new-for1-887432e.json b/tests/reference/ast_new-for1-887432e.json index 8d7d022088..c09bcbb01c 100644 --- a/tests/reference/ast_new-for1-887432e.json +++ b/tests/reference/ast_new-for1-887432e.json @@ -2,11 +2,11 @@ "basename": "ast_new-for1-887432e", "cmd": "lpython --show-ast --new-parser --no-color {infile} -o {outfile}", "infile": "tests/parser/for1.py", - "infile_hash": "60515a1800d4a8b1a2cad5ad7b23f75f2510e1d369e94065f01c0844", + "infile_hash": "a05c8da4019ead83ba9840212112e467f7a8968896b55d0122962b7f", "outfile": null, "outfile_hash": null, "stdout": "ast_new-for1-887432e.stdout", - "stdout_hash": "438c7ad856655fd2f666faab754e58f11179a800975359501be7b8fa", + "stdout_hash": "616164b90733fae6f26818243182810e9864ad8499e1d2c591b27cf3", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/ast_new-for1-887432e.stdout b/tests/reference/ast_new-for1-887432e.stdout index 2c953bb81a..27482121ff 100644 --- a/tests/reference/ast_new-for1-887432e.stdout +++ b/tests/reference/ast_new-for1-887432e.stdout @@ -1 +1 @@ -(Module [(ImportFrom ltypes [(i32 ())] 0) (For (Name x Store) (Name fruits Load) [(Expr (Call (Name print Load) [(Name x Load)] []))] [] ()) (For (Name x Store) (Name fruits Load) [(Expr (Call (Name print Load) [(Name x Load)] [])) (If (Compare (Name x Load) Eq [(ConstantStr "banana" ())]) [(Break)] [])] [] ()) (For (Name x Store) (ConstantStr "banana" ()) [(Expr (Call (Name print Load) [(Name x Load)] []))] [] ()) (For (Name i Store) (Call (Name range Load) [(ConstantInt 6 ())] []) [(Expr (Call (Name print Load) [(Name i Load)] []))] [] ()) (For (Name i Store) (Call (Name range Load) [(ConstantInt 2 ()) (ConstantInt 30 ()) (ConstantInt 3 ())] []) [(Expr (Call (Name print Load) [(Name i Load)] []))] [] ()) (For (Name i Store) (Call (Name range Load) [(ConstantInt 5 ())] []) [(If (Compare (Name i Load) Eq [(ConstantInt 3 ())]) [(Continue)] []) (Expr (Call (Name print Load) [(Name i Load)] []))] [(Expr (Call (Name print Load) [(ConstantStr "Finally Completed!" ())] []))] ()) (For (Name i Store) (Call (Name range Load) [(ConstantInt 5 ())] []) [(For (Name j Store) (Call (Name range Load) [(ConstantInt 5 ())] []) [(Expr (Call (Name print Load) [(Name i Load) (Name j Load)] []))] [] ())] [] ()) (AnnAssign (Name sum Store) (Name i32 Load) (ConstantInt 0 ()) 1) (For (Name j Store) (Call (Name range Load) [(ConstantInt 5 ())] []) [(AugAssign (Name sum Store) Add (Name j Load))] [] ())] []) +(Module [(ImportFrom ltypes [(i32 ())] 0) (For (Name x Store) (Name fruits Load) [(Expr (Call (Name print Load) [(Name x Load)] []))] [] ()) (For (Name x Store) (Name fruits Load) [(Expr (Call (Name print Load) [(Name x Load)] [])) (If (Compare (Name x Load) Eq [(ConstantStr "banana" ())]) [(Break)] [])] [] ()) (For (Name x Store) (ConstantStr "banana" ()) [(Expr (Call (Name print Load) [(Name x Load)] []))] [] ()) (For (Name i Store) (Call (Name range Load) [(ConstantInt 6 ())] []) [(Expr (Call (Name print Load) [(Name i Load)] []))] [] ()) (For (Name i Store) (Call (Name range Load) [(ConstantInt 2 ()) (ConstantInt 30 ()) (ConstantInt 3 ())] []) [(Expr (Call (Name print Load) [(Name i Load)] []))] [] ()) (For (Name i Store) (Call (Name range Load) [(ConstantInt 5 ())] []) [(If (Compare (Name i Load) Eq [(ConstantInt 3 ())]) [(Continue)] []) (Expr (Call (Name print Load) [(Name i Load)] []))] [(Expr (Call (Name print Load) [(ConstantStr "Finally Completed!" ())] []))] ()) (For (Name i Store) (Call (Name range Load) [(ConstantInt 5 ())] []) [(For (Name j Store) (Call (Name range Load) [(ConstantInt 5 ())] []) [(Expr (Call (Name print Load) [(Name i Load) (Name j Load)] []))] [] ())] [] ()) (AnnAssign (Name sum Store) (Name i32 Load) (ConstantInt 0 ()) 1) (For (Name j Store) (Call (Name range Load) [(ConstantInt 5 ())] []) [(AugAssign (Name sum Store) Add (Name j Load))] [] ()) (For (Tuple [(Name _ Store) (Name x Store)] Store) (Name y Load) [(Pass)] [] ()) (For (Tuple [(Name x Store) (Name y Store)] Store) (Name z Load) [(Pass)] [] ()) (For (Tuple [(Name i Store) (Name a Store)] Store) (Call (Name enumerate Load) [(List [(ConstantInt 4 ()) (ConstantInt 5 ()) (ConstantInt 6 ()) (ConstantInt 7 ())] Load)] []) [(Expr (Call (Name print Load) [(Name i Load) (ConstantStr ": " ()) (Name a Load)] []))] [] ())] []) From e72528ebefc6e59b28ced05242c8cebc2961fa68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Wed, 18 May 2022 15:20:12 -0600 Subject: [PATCH 14/15] Old Parser: serialize negative integers correctly --- src/runtime/lpython_parser.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runtime/lpython_parser.py b/src/runtime/lpython_parser.py index 02e9c37bd0..4f3f8adb77 100644 --- a/src/runtime/lpython_parser.py +++ b/src/runtime/lpython_parser.py @@ -120,9 +120,13 @@ def __init__(self): self.s = "0 " def write_int8(self, i): + assert i >= 0 self.s += str(i) + " " def write_int64(self, i): + if i < 0: + i += 2**64 + assert i >= 0 self.s += str(i) + " " def write_float64(self, f): From cf9504e8b637142239cebd569c2419d1cf7ea6b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Wed, 18 May 2022 16:48:26 -0600 Subject: [PATCH 15/15] C/CPP: Extract common code into a base class --- src/libasr/codegen/asr_to_c.cpp | 652 +------------------ src/libasr/codegen/asr_to_c_cpp.h | 1007 +++++++++++++++++++++++++++++ src/libasr/codegen/asr_to_cpp.cpp | 648 +------------------ 3 files changed, 1019 insertions(+), 1288 deletions(-) create mode 100644 src/libasr/codegen/asr_to_c_cpp.h diff --git a/src/libasr/codegen/asr_to_c.cpp b/src/libasr/codegen/asr_to_c.cpp index 37a6b0112e..8854922069 100644 --- a/src/libasr/codegen/asr_to_c.cpp +++ b/src/libasr/codegen/asr_to_c.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -12,36 +13,6 @@ namespace LFortran { -namespace { - - // Local exception that is only used in this file to exit the visitor - // pattern and caught later (not propagated outside) - class CodeGenError - { - public: - diag::Diagnostic d; - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} - { } - }; - - class Abort {}; - -} - -// Platform dependent fast unique hash: -uint64_t get_hash_c(ASR::asr_t *node) -{ - return (uint64_t)node; -} - -struct SymbolInfoC -{ - bool needs_declaration = true; - bool intrinsic_function = false; -}; - std::string convert_dims_c(size_t n_dims, ASR::dimension_t *m_dims) { std::string dims; @@ -83,21 +54,11 @@ std::string format_type_c(const std::string &dims, const std::string &type, return fmt; } -class ASRToCVisitor : public ASR::BaseVisitor +class ASRToCVisitor : public BaseCCPPVisitor { public: - diag::Diagnostics &diag; - std::map sym_info; - std::string src; - int indentation_level; - int indentation_spaces; - // The precedence of the last expression, using the table: - // https://en.cppreference.com/w/cpp/language/operator_precedence - int last_expr_precedence; - bool intrinsic_module = false; - const ASR::Function_t *current_function = nullptr; - ASRToCVisitor(diag::Diagnostics &diag) : diag{diag} {} + ASRToCVisitor(diag::Diagnostics &diag) : BaseCCPPVisitor(diag) {} std::string convert_variable_decl(const ASR::Variable_t &v) { @@ -229,30 +190,6 @@ R"(#include src = unit_src; } - void visit_Module(const ASR::Module_t &x) { - if (startswith(x.m_name, "lfortran_intrinsic_")) { - intrinsic_module = true; - } else { - intrinsic_module = false; - } - // Generate code for nested subroutines and functions first: - std::string contains; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Subroutine_t *s = ASR::down_cast(item.second); - visit_Subroutine(*s); - contains += src; - } - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - visit_Function(*s); - contains += src; - } - } - src = contains; - intrinsic_module = false; - } - void visit_Program(const ASR::Program_t &x) { // Generate code for nested subroutines and functions first: std::string contains; @@ -295,59 +232,12 @@ R"(#include indentation_level -= 2; } - void visit_Subroutine(const ASR::Subroutine_t &x) { - indentation_level += 1; - std::string sub = "void " + std::string(x.m_name) + "("; - for (size_t i=0; im_intent)); - sub += convert_variable_decl(*arg); - if (i < x.n_args-1) sub += ", "; - } - sub += ")\n"; - - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t *v = ASR::down_cast(item.second); - if (v->m_intent == LFortran::ASRUtils::intent_local) { - SymbolInfoC s; - s.needs_declaration = true; - sym_info[get_hash_c((ASR::asr_t*)v)] = s; - } - } - } - - std::string body; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - body += src; - } - - std::string decl; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t *v = ASR::down_cast(item.second); - if (v->m_intent == LFortran::ASRUtils::intent_local) { - if (sym_info[get_hash_c((ASR::asr_t*) v)].needs_declaration) { - std::string indent(indentation_level*indentation_spaces, ' '); - decl += indent; - decl += convert_variable_decl(*v) + ";\n"; - } - } - } - } - - sub += "{\n" + decl + body + "}\n\n"; - src = sub; - indentation_level -= 1; - } - void visit_Function(const ASR::Function_t &x) { if (std::string(x.m_name) == "size" && intrinsic_module ) { // Intrinsic function `size` - SymbolInfoC s; + SymbolInfo s; s.intrinsic_function = true; - sym_info[get_hash_c((ASR::asr_t*)&x)] = s; + sym_info[get_hash((ASR::asr_t*)&x)] = s; src = ""; return; } else if (( @@ -358,15 +248,15 @@ R"(#include std::string(x.m_name) == "not" ) && intrinsic_module) { // Intrinsic function `int` - SymbolInfoC s; + SymbolInfo s; s.intrinsic_function = true; - sym_info[get_hash_c((ASR::asr_t*)&x)] = s; + sym_info[get_hash((ASR::asr_t*)&x)] = s; src = ""; return; } else { - SymbolInfoC s; + SymbolInfo s; s.intrinsic_function = false; - sym_info[get_hash_c((ASR::asr_t*)&x)] = s; + sym_info[get_hash((ASR::asr_t*)&x)] = s; } std::string sub; ASR::Variable_t *return_var = LFortran::ASRUtils::EXPR2VAR(x.m_return_var); @@ -455,100 +345,6 @@ R"(#include src = sub; } - void visit_FunctionCall(const ASR::FunctionCall_t &x) { - ASR::Function_t *fn = ASR::down_cast( - LFortran::ASRUtils::symbol_get_past_external(x.m_name)); - std::string fn_name = fn->m_name; - if (sym_info[get_hash_c((ASR::asr_t*)fn)].intrinsic_function) { - if (fn_name == "size") { - LFORTRAN_ASSERT(x.n_args > 0); - visit_expr(*x.m_args[0].m_value); - std::string var_name = src; - std::string args; - if (x.n_args == 1) { - args = "0"; - } else { - for (size_t i=1; i 0); - visit_expr(*x.m_args[0].m_value); - src = "(int)" + src; - } else if (fn_name == "not") { - LFORTRAN_ASSERT(x.n_args > 0); - visit_expr(*x.m_args[0].m_value); - src = "!(" + src + ")"; - } else { - throw CodeGenError("Intrinsic function '" + fn_name - + "' not implemented"); - } - } else { - std::string args; - for (size_t i=0; i(*x.m_target)) { - target = LFortran::ASRUtils::EXPR2VAR(x.m_target)->m_name; - } else if (ASR::is_a(*x.m_target)) { - visit_ArrayRef(*ASR::down_cast(x.m_target)); - target = src; - } else { - LFORTRAN_ASSERT(false) - } - this->visit_expr(*x.m_value); - std::string value = src; - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + target + " = " + value + ";\n"; - } - - void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { - src = std::to_string(x.m_n); - last_expr_precedence = 2; - } - - void visit_RealConstant(const ASR::RealConstant_t &x) { - src = std::to_string(x.m_r); - last_expr_precedence = 2; - } - - - void visit_StringConstant(const ASR::StringConstant_t &x) { - src = "\"" + std::string(x.m_s) + "\""; - last_expr_precedence = 2; - } - void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { if (x.m_value == true) { src = "true"; @@ -558,30 +354,6 @@ R"(#include last_expr_precedence = 2; } - void visit_Var(const ASR::Var_t &x) { - const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); - src = ASR::down_cast(s)->m_name; - last_expr_precedence = 2; - } - - void visit_ArrayRef(const ASR::ArrayRef_t &x) { - const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); - std::string out = ASR::down_cast(s)->m_name; - out += "["; - for (size_t i=0; i last_expr_precedence = 2; } - void visit_Compare(const ASR::Compare_t &x) { - this->visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - this->visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { last_expr_precedence = 10; break; } - case (ASR::cmpopType::Gt) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::GtE) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::Lt) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::LtE) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::NotEq): { last_expr_precedence = 10; break; } - default : LFORTRAN_ASSERT(false); // should never happen - } - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - src += ASRUtils::cmpop_to_str(x.m_op); - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - - void visit_UnaryOp(const ASR::UnaryOp_t &x) { - this->visit_expr(*x.m_operand); - int expr_precedence = last_expr_precedence; - if (x.m_type->type == ASR::ttypeType::Integer) { - if (x.m_op == ASR::unaryopType::UAdd) { - // src = src; - // Skip unary plus, keep the previous precedence - } else if (x.m_op == ASR::unaryopType::USub) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "-" + src; - } else { - src = "-(" + src + ")"; - } - } else if (x.m_op == ASR::unaryopType::Invert) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "~" + src; - } else { - src = "~(" + src + ")"; - } - - } else if (x.m_op == ASR::unaryopType::Not) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "!" + src; - } else { - src = "!(" + src + ")"; - } - } else { - throw CodeGenError("Unary type not implemented yet for Integer"); - } - return; - } else if (x.m_type->type == ASR::ttypeType::Real) { - if (x.m_op == ASR::unaryopType::UAdd) { - // src = src; - // Skip unary plus, keep the previous precedence - } else if (x.m_op == ASR::unaryopType::USub) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "-" + src; - } else { - src = "-(" + src + ")"; - } - } else if (x.m_op == ASR::unaryopType::Not) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "!" + src; - } else { - src = "!(" + src + ")"; - } - } else { - throw CodeGenError("Unary type not implemented yet for Real"); - } - return; - } else if (x.m_type->type == ASR::ttypeType::Logical) { - if (x.m_op == ASR::unaryopType::Not) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "!" + src; - } else { - src = "!(" + src + ")"; - } - return; - } else { - throw CodeGenError("Unary type not implemented yet for Logical"); - } - } else { - throw CodeGenError("UnaryOp: type not supported yet"); - } - } - - void visit_BinOp(const ASR::BinOp_t &x) { - this->visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - this->visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::binopType::Add) : { last_expr_precedence = 6; break; } - case (ASR::binopType::Sub) : { last_expr_precedence = 6; break; } - case (ASR::binopType::Mul) : { last_expr_precedence = 5; break; } - case (ASR::binopType::Div) : { last_expr_precedence = 5; break; } - default: throw CodeGenError("BinOp: operator not implemented yet"); - } - src = ""; - if (left_precedence == 3) { - src += "(" + left + ")"; - } else { - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - } - src += ASRUtils::binop_to_str(x.m_op); - if (right_precedence == 3) { - src += "(" + right + ")"; - } else if (x.m_op == ASR::binopType::Sub) { - if (right_precedence < last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } else { - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - } - - void visit_BoolOp(const ASR::BoolOp_t &x) { - this->visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - this->visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::boolopType::And): { - last_expr_precedence = 14; - break; - } - case (ASR::boolopType::Or): { - last_expr_precedence = 15; - break; - } - case (ASR::boolopType::NEqv): { - last_expr_precedence = 10; - break; - } - case (ASR::boolopType::Eqv): { - last_expr_precedence = 10; - break; - } - default : throw CodeGenError("Unhandled switch case"); - } - - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - src += ASRUtils::boolop_to_str(x.m_op); - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - std::string get_print_type(ASR::ttype_t *t) { switch (t->type) { case ASR::ttypeType::Integer: { @@ -854,235 +443,12 @@ R"(#include src = out; } - void visit_Allocate(const ASR::Allocate_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "// FIXME: allocate("; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "}\n"; - indentation_level -= 1; - src = out; - } - - void visit_Exit(const ASR::Exit_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + "break;\n"; - } - - void visit_Cycle(const ASR::Cycle_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + "continue;\n"; - } - - void visit_Return(const ASR::Return_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - if (current_function) { - src = indent + "return " - + LFortran::ASRUtils::EXPR2VAR(current_function->m_return_var)->m_name - + ";\n"; - } else { - src = indent + "return;\n"; - } - } - - void visit_GoToTarget(const ASR::GoToTarget_t & /* x */) { - // Ignore for now - src = ""; - } - - void visit_Stop(const ASR::Stop_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + "exit(0);\n"; - } - - void visit_ImpliedDoLoop(const ASR::ImpliedDoLoop_t &/*x*/) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + " /* FIXME: implied do loop */ "; - src = out; - last_expr_precedence = 2; - } - - void visit_DoLoop(const ASR::DoLoop_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "for ("; - ASR::Variable_t *loop_var = LFortran::ASRUtils::EXPR2VAR(x.m_head.m_v); - std::string lvname=loop_var->m_name; - ASR::expr_t *a=x.m_head.m_start; - ASR::expr_t *b=x.m_head.m_end; - ASR::expr_t *c=x.m_head.m_increment; - LFORTRAN_ASSERT(a); - LFORTRAN_ASSERT(b); - int increment; - if (!c) { - increment = 1; - } else { - if (c->type == ASR::exprType::IntegerConstant) { - increment = ASR::down_cast(c)->m_n; - } else if (c->type == ASR::exprType::UnaryOp) { - ASR::UnaryOp_t *u = ASR::down_cast(c); - LFORTRAN_ASSERT(u->m_op == ASR::unaryopType::USub); - LFORTRAN_ASSERT(u->m_operand->type == ASR::exprType::IntegerConstant); - increment = - ASR::down_cast(u->m_operand)->m_n; - } else { - throw CodeGenError("Do loop increment type not supported"); - } - } - std::string cmp_op; - if (increment > 0) { - cmp_op = "<="; - } else { - cmp_op = ">="; - } - - out += lvname + "="; - visit_expr(*a); - out += src + "; " + lvname + cmp_op; - visit_expr(*b); - out += src + "; " + lvname; - if (increment == 1) { - out += "++"; - } else if (increment == -1) { - out += "--"; - } else { - out += "+=" + std::to_string(increment); - } - out += ") {\n"; - indentation_level += 1; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "}\n"; - indentation_level -= 1; - src = out; - } - void visit_ErrorStop(const ASR::ErrorStop_t & /* x */) { std::string indent(indentation_level*indentation_spaces, ' '); src = indent + "fprintf(stderr, \"ERROR STOP\");\n"; src += indent + "exit(1);\n"; } - void visit_If(const ASR::If_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "if ("; - visit_expr(*x.m_test); - out += src + ") {\n"; - indentation_level += 1; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "}"; - if (x.n_orelse == 0) { - out += "\n"; - } else { - out += " else {\n"; - for (size_t i=0; ivisit_stmt(*x.m_orelse[i]); - out += src; - } - out += indent + "}\n"; - } - indentation_level -= 1; - src = out; - } - - void visit_IfExp(const ASR::IfExp_t &x) { - // IfExp is like a ternary operator in c++ - // test ? body : orelse; - std::string out = "("; - visit_expr(*x.m_test); - out += src + ") ? ("; - visit_expr(*x.m_body); - out += src + ") : ("; - visit_expr(*x.m_orelse); - out += src + ")"; - src = out; - last_expr_precedence = 16; - } - - void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - ASR::Subroutine_t *s = ASR::down_cast( - LFortran::ASRUtils::symbol_get_past_external(x.m_name)); - std::string out = indent + s->m_name + "("; - for (size_t i=0; i(*x.m_args[i].m_value)) { - ASR::Variable_t *arg = LFortran::ASRUtils::EXPR2VAR(x.m_args[i].m_value); - std::string arg_name = arg->m_name; - out += arg_name; - } else { - this->visit_expr(*x.m_args[i].m_value); - out += src; - } - if (i < x.n_args-1) out += ", "; - } - out += ");\n"; - src = out; - } - }; Result asr_to_c(Allocator &al, ASR::TranslationUnit_t &asr, diff --git a/src/libasr/codegen/asr_to_c_cpp.h b/src/libasr/codegen/asr_to_c_cpp.h new file mode 100644 index 0000000000..66841557e1 --- /dev/null +++ b/src/libasr/codegen/asr_to_c_cpp.h @@ -0,0 +1,1007 @@ +#ifndef LFORTRAN_ASR_TO_C_CPP_H +#define LFORTRAN_ASR_TO_C_CPP_H + +/* + * Common code to be used in both of: + * + * * asr_to_cpp.cpp + * * asr_to_c.cpp + * + * In particular, a common base class visitor with visitors that are identical + * for both C and C++ code generation. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace LFortran { + +namespace { + + // Local exception that is only used in this file to exit the visitor + // pattern and caught later (not propagated outside) + class CodeGenError + { + public: + diag::Diagnostic d; + public: + CodeGenError(const std::string &msg) + : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} + { } + }; + + class Abort {}; + +} + +// Platform dependent fast unique hash: +static uint64_t get_hash(ASR::asr_t *node) +{ + return (uint64_t)node; +} + +struct SymbolInfo +{ + bool needs_declaration = true; + bool intrinsic_function = false; +}; + +template +class BaseCCPPVisitor : public ASR::BaseVisitor +{ +private: + Derived& self() { return static_cast(*this); } +public: + diag::Diagnostics &diag; + std::string src; + int indentation_level; + int indentation_spaces; + // The precedence of the last expression, using the table: + // https://en.cppreference.com/w/cpp/language/operator_precedence + int last_expr_precedence; + bool intrinsic_module = false; + const ASR::Function_t *current_function = nullptr; + std::map sym_info; + + BaseCCPPVisitor(diag::Diagnostics &diag) : diag{diag} {} + + void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { + // All loose statements must be converted to a function, so the items + // must be empty: + LFORTRAN_ASSERT(x.n_items == 0); + std::string unit_src = ""; + indentation_level = 0; + indentation_spaces = 4; + + std::string headers = +R"(#include +#include +#include +#include +)"; + unit_src += headers; + + + // TODO: We need to pre-declare all functions first, then generate code + // Otherwise some function might not be found. + + { + // Process intrinsic modules in the right order + std::vector build_order + = LFortran::ASRUtils::determine_module_dependencies(x); + for (auto &item : build_order) { + LFORTRAN_ASSERT(x.m_global_scope->get_scope().find(item) + != x.m_global_scope->get_scope().end()); + if (startswith(item, "lfortran_intrinsic")) { + ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); + self().visit_symbol(*mod); + unit_src += src; + } + } + } + + // Process procedures first: + for (auto &item : x.m_global_scope->get_scope()) { + if (ASR::is_a(*item.second) + || ASR::is_a(*item.second)) { + self().visit_symbol(*item.second); + unit_src += src; + } + } + + // Then do all the modules in the right order + std::vector build_order + = LFortran::ASRUtils::determine_module_dependencies(x); + for (auto &item : build_order) { + LFORTRAN_ASSERT(x.m_global_scope->get_scope().find(item) + != x.m_global_scope->get_scope().end()); + if (!startswith(item, "lfortran_intrinsic")) { + ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); + self().visit_symbol(*mod); + unit_src += src; + } + } + + // Then the main program: + for (auto &item : x.m_global_scope->get_scope()) { + if (ASR::is_a(*item.second)) { + self().visit_symbol(*item.second); + unit_src += src; + } + } + + src = unit_src; + } + + void visit_Module(const ASR::Module_t &x) { + if (startswith(x.m_name, "lfortran_intrinsic_")) { + intrinsic_module = true; + } else { + intrinsic_module = false; + } + // Generate code for nested subroutines and functions first: + std::string contains; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Subroutine_t *s = ASR::down_cast(item.second); + self().visit_Subroutine(*s); + contains += src; + } + if (ASR::is_a(*item.second)) { + ASR::Function_t *s = ASR::down_cast(item.second); + self().visit_Function(*s); + contains += src; + } + } + src = contains; + intrinsic_module = false; + } + + void visit_Program(const ASR::Program_t &x) { + // Generate code for nested subroutines and functions first: + std::string contains; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Subroutine_t *s = ASR::down_cast(item.second); + visit_Subroutine(*s); + contains += src; + } + if (ASR::is_a(*item.second)) { + ASR::Function_t *s = ASR::down_cast(item.second); + visit_Function(*s); + contains += src; + } + } + + // Generate code for the main program + indentation_level += 1; + std::string indent1(indentation_level*indentation_spaces, ' '); + indentation_level += 1; + std::string indent(indentation_level*indentation_spaces, ' '); + std::string decl; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast(item.second); + decl += self().convert_variable_decl(*v) + ";\n"; + } + } + + std::string body; + for (size_t i=0; im_intent)); + sub += self().convert_variable_decl(*arg); + if (i < x.n_args-1) sub += ", "; + } + sub += ")\n"; + + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast(item.second); + if (v->m_intent == LFortran::ASRUtils::intent_local) { + SymbolInfo s; + s.needs_declaration = true; + sym_info[get_hash((ASR::asr_t*)v)] = s; + } + } + } + + std::string body; + for (size_t i=0; iget_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast(item.second); + if (v->m_intent == LFortran::ASRUtils::intent_local) { + if (sym_info[get_hash((ASR::asr_t*) v)].needs_declaration) { + std::string indent(indentation_level*indentation_spaces, ' '); + decl += indent; + decl += self().convert_variable_decl(*v) + ";\n"; + } + } + } + } + + sub += "{\n" + decl + body + "}\n\n"; + src = sub; + indentation_level -= 1; + } + + void visit_Function(const ASR::Function_t &x) { + if (std::string(x.m_name) == "size" && intrinsic_module ) { + // Intrinsic function `size` + SymbolInfo s; + s.intrinsic_function = true; + sym_info[get_hash((ASR::asr_t*)&x)] = s; + src = ""; + return; + } else if (( + std::string(x.m_name) == "int" || + std::string(x.m_name) == "char" || + std::string(x.m_name) == "present" || + std::string(x.m_name) == "len" || + std::string(x.m_name) == "not" + ) && intrinsic_module) { + // Intrinsic function `int` + SymbolInfo s; + s.intrinsic_function = true; + sym_info[get_hash((ASR::asr_t*)&x)] = s; + src = ""; + return; + } else { + SymbolInfo s; + s.intrinsic_function = false; + sym_info[get_hash((ASR::asr_t*)&x)] = s; + } + std::string sub; + ASR::Variable_t *return_var = LFortran::ASRUtils::EXPR2VAR(x.m_return_var); + if (ASRUtils::is_integer(*return_var->m_type)) { + bool is_int = ASR::down_cast(return_var->m_type)->m_kind == 4; + if (is_int) { + sub = "int "; + } else { + sub = "long long "; + } + } else if (ASRUtils::is_real(*return_var->m_type)) { + bool is_float = ASR::down_cast(return_var->m_type)->m_kind == 4; + if (is_float) { + sub = "float "; + } else { + sub = "double "; + } + } else if (ASRUtils::is_logical(*return_var->m_type)) { + sub = "bool "; + } else if (ASRUtils::is_character(*return_var->m_type)) { + sub = "char * "; + } else if (ASRUtils::is_complex(*return_var->m_type)) { + bool is_float = ASR::down_cast(return_var->m_type)->m_kind == 4; + if (is_float) { + sub = "float complex "; + } else { + sub = "double complex "; + } + } else { + throw CodeGenError("Return type not supported"); + } + sub = sub + std::string(x.m_name) + "("; + for (size_t i=0; im_intent)); + sub += self().convert_variable_decl(*arg); + if (i < x.n_args-1) sub += ", "; + } + sub += ")"; + if (x.m_abi == ASR::abiType::BindC) { + sub += ";\n"; + } else { + sub += "\n"; + + indentation_level += 1; + std::string indent(indentation_level*indentation_spaces, ' '); + std::string decl; + for (auto &item : x.m_symtab->get_scope()) { + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast(item.second); + if (v->m_intent == LFortran::ASRUtils::intent_local || v->m_intent == LFortran::ASRUtils::intent_return_var) { + decl += indent + self().convert_variable_decl(*v) + ";\n"; + } + } + } + + current_function = &x; + std::string body; + + for (size_t i=0; i 0 && ASR::is_a(*x.m_body[x.n_body-1])) { + visited_return = true; + } + + if(!visited_return) { + body += indent + "return " + + LFortran::ASRUtils::EXPR2VAR(x.m_return_var)->m_name + + ";\n"; + } + + if (decl.size() > 0 || body.size() > 0) { + sub += "{\n" + decl + body + "}\n"; + } else { + sub[sub.size()-1] = ';'; + sub += "\n"; + } + indentation_level -= 1; + } + sub += "\n"; + src = sub; + } + + void visit_FunctionCall(const ASR::FunctionCall_t &x) { + ASR::Function_t *fn = ASR::down_cast( + LFortran::ASRUtils::symbol_get_past_external(x.m_name)); + std::string fn_name = fn->m_name; + if (sym_info[get_hash((ASR::asr_t*)fn)].intrinsic_function) { + if (fn_name == "size") { + LFORTRAN_ASSERT(x.n_args > 0); + self().visit_expr(*x.m_args[0].m_value); + std::string var_name = src; + std::string args; + if (x.n_args == 1) { + args = "0"; + } else { + for (size_t i=1; i 0); + self().visit_expr(*x.m_args[0].m_value); + src = "(int)" + src; + } else if (fn_name == "not") { + LFORTRAN_ASSERT(x.n_args > 0); + self().visit_expr(*x.m_args[0].m_value); + src = "!(" + src + ")"; + } else { + throw CodeGenError("Intrinsic function '" + fn_name + + "' not implemented"); + } + } else { + std::string args; + for (size_t i=0; i(*x.m_target)) { + target = LFortran::ASRUtils::EXPR2VAR(x.m_target)->m_name; + } else if (ASR::is_a(*x.m_target)) { + visit_ArrayRef(*ASR::down_cast(x.m_target)); + target = src; + } else { + LFORTRAN_ASSERT(false) + } + self().visit_expr(*x.m_value); + std::string value = src; + std::string indent(indentation_level*indentation_spaces, ' '); + src = indent + target + " = " + value + ";\n"; + } + + void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { + src = std::to_string(x.m_n); + last_expr_precedence = 2; + } + + void visit_RealConstant(const ASR::RealConstant_t &x) { + src = std::to_string(x.m_r); + last_expr_precedence = 2; + } + + + void visit_StringConstant(const ASR::StringConstant_t &x) { + src = "\"" + std::string(x.m_s) + "\""; + last_expr_precedence = 2; + } + + void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { + if (x.m_value == true) { + src = "true"; + } else { + src = "false"; + } + last_expr_precedence = 2; + } + + void visit_Var(const ASR::Var_t &x) { + const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); + src = ASR::down_cast(s)->m_name; + last_expr_precedence = 2; + } + + void visit_ArrayRef(const ASR::ArrayRef_t &x) { + const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); + std::string out = ASR::down_cast(s)->m_name; + out += "["; + for (size_t i=0; i long long explicitly: + // src = src; + break; + } + case (ASR::cast_kindType::ComplexToComplex) : { + break; + } + case (ASR::cast_kindType::ComplexToReal) : { + src = "creal(" + src + ")"; + break; + } + case (ASR::cast_kindType::LogicalToInteger) : { + src = "(int)(" + src + ")"; + break; + } + default : throw CodeGenError("Cast kind " + std::to_string(x.m_kind) + " not implemented"); + } + last_expr_precedence = 2; + } + + void visit_Compare(const ASR::Compare_t &x) { + self().visit_expr(*x.m_left); + std::string left = std::move(src); + int left_precedence = last_expr_precedence; + self().visit_expr(*x.m_right); + std::string right = std::move(src); + int right_precedence = last_expr_precedence; + switch (x.m_op) { + case (ASR::cmpopType::Eq) : { last_expr_precedence = 10; break; } + case (ASR::cmpopType::Gt) : { last_expr_precedence = 9; break; } + case (ASR::cmpopType::GtE) : { last_expr_precedence = 9; break; } + case (ASR::cmpopType::Lt) : { last_expr_precedence = 9; break; } + case (ASR::cmpopType::LtE) : { last_expr_precedence = 9; break; } + case (ASR::cmpopType::NotEq): { last_expr_precedence = 10; break; } + default : LFORTRAN_ASSERT(false); // should never happen + } + if (left_precedence <= last_expr_precedence) { + src += left; + } else { + src += "(" + left + ")"; + } + src += ASRUtils::cmpop_to_str(x.m_op); + if (right_precedence <= last_expr_precedence) { + src += right; + } else { + src += "(" + right + ")"; + } + } + + void visit_UnaryOp(const ASR::UnaryOp_t &x) { + self().visit_expr(*x.m_operand); + int expr_precedence = last_expr_precedence; + if (x.m_type->type == ASR::ttypeType::Integer) { + if (x.m_op == ASR::unaryopType::UAdd) { + // src = src; + // Skip unary plus, keep the previous precedence + } else if (x.m_op == ASR::unaryopType::USub) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "-" + src; + } else { + src = "-(" + src + ")"; + } + } else if (x.m_op == ASR::unaryopType::Invert) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "~" + src; + } else { + src = "~(" + src + ")"; + } + + } else if (x.m_op == ASR::unaryopType::Not) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "!" + src; + } else { + src = "!(" + src + ")"; + } + } else { + throw CodeGenError("Unary type not implemented yet for Integer"); + } + return; + } else if (x.m_type->type == ASR::ttypeType::Real) { + if (x.m_op == ASR::unaryopType::UAdd) { + // src = src; + // Skip unary plus, keep the previous precedence + } else if (x.m_op == ASR::unaryopType::USub) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "-" + src; + } else { + src = "-(" + src + ")"; + } + } else if (x.m_op == ASR::unaryopType::Not) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "!" + src; + } else { + src = "!(" + src + ")"; + } + } else { + throw CodeGenError("Unary type not implemented yet for Real"); + } + return; + } else if (x.m_type->type == ASR::ttypeType::Logical) { + if (x.m_op == ASR::unaryopType::Not) { + last_expr_precedence = 3; + if (expr_precedence <= last_expr_precedence) { + src = "!" + src; + } else { + src = "!(" + src + ")"; + } + return; + } else { + throw CodeGenError("Unary type not implemented yet for Logical"); + } + } else { + throw CodeGenError("UnaryOp: type not supported yet"); + } + } + + void visit_BinOp(const ASR::BinOp_t &x) { + self().visit_expr(*x.m_left); + std::string left = std::move(src); + int left_precedence = last_expr_precedence; + self().visit_expr(*x.m_right); + std::string right = std::move(src); + int right_precedence = last_expr_precedence; + switch (x.m_op) { + case (ASR::binopType::Add) : { last_expr_precedence = 6; break; } + case (ASR::binopType::Sub) : { last_expr_precedence = 6; break; } + case (ASR::binopType::Mul) : { last_expr_precedence = 5; break; } + case (ASR::binopType::Div) : { last_expr_precedence = 5; break; } + case (ASR::binopType::Pow) : { + src = "std::pow(" + left + ", " + right + ")"; + return; + } + default: throw CodeGenError("BinOp: operator not implemented yet"); + } + src = ""; + if (left_precedence == 3) { + src += "(" + left + ")"; + } else { + if (left_precedence <= last_expr_precedence) { + src += left; + } else { + src += "(" + left + ")"; + } + } + src += ASRUtils::binop_to_str(x.m_op); + if (right_precedence == 3) { + src += "(" + right + ")"; + } else if (x.m_op == ASR::binopType::Sub) { + if (right_precedence < last_expr_precedence) { + src += right; + } else { + src += "(" + right + ")"; + } + } else { + if (right_precedence <= last_expr_precedence) { + src += right; + } else { + src += "(" + right + ")"; + } + } + } + + void visit_BoolOp(const ASR::BoolOp_t &x) { + self().visit_expr(*x.m_left); + std::string left = std::move(src); + int left_precedence = last_expr_precedence; + self().visit_expr(*x.m_right); + std::string right = std::move(src); + int right_precedence = last_expr_precedence; + switch (x.m_op) { + case (ASR::boolopType::And): { + last_expr_precedence = 14; + break; + } + case (ASR::boolopType::Or): { + last_expr_precedence = 15; + break; + } + case (ASR::boolopType::NEqv): { + last_expr_precedence = 10; + break; + } + case (ASR::boolopType::Eqv): { + last_expr_precedence = 10; + break; + } + default : throw CodeGenError("Unhandled switch case"); + } + + if (left_precedence <= last_expr_precedence) { + src += left; + } else { + src += "(" + left + ")"; + } + src += ASRUtils::boolop_to_str(x.m_op); + if (right_precedence <= last_expr_precedence) { + src += right; + } else { + src += "(" + right + ")"; + } + } + + std::string get_print_type(ASR::ttype_t *t) { + switch (t->type) { + case ASR::ttypeType::Integer: { + ASR::Integer_t *i = (ASR::Integer_t*)t; + switch (i->m_kind) { + case 1: { return "%d"; } + case 2: { return "%d"; } + case 4: { return "%d"; } + case 8: { return "%lli"; } + default: { throw LFortranException("Integer kind not supported"); } + } + } + case ASR::ttypeType::Real: { + ASR::Real_t *r = (ASR::Real_t*)t; + switch (r->m_kind) { + case 4: { return "%f"; } + case 8: { return "%lf"; } + default: { throw LFortranException("Float kind not supported"); } + } + } + case ASR::ttypeType::Logical: { + return "%d"; + } + case ASR::ttypeType::Character: { + return "%s"; + } + default : throw LFortranException("Not implemented"); + } + } + + void visit_Print(const ASR::Print_t &x) { + std::string indent(indentation_level*indentation_spaces, ' '); + std::string out = indent + "printf(\""; + std::vector v; + for (size_t i=0; im_return_var)->m_name + + ";\n"; + } else { + src = indent + "return;\n"; + } + } + + void visit_GoToTarget(const ASR::GoToTarget_t & /* x */) { + // Ignore for now + src = ""; + } + + void visit_Stop(const ASR::Stop_t & /* x */) { + std::string indent(indentation_level*indentation_spaces, ' '); + src = indent + "exit(0);\n"; + } + + void visit_ImpliedDoLoop(const ASR::ImpliedDoLoop_t &/*x*/) { + std::string indent(indentation_level*indentation_spaces, ' '); + std::string out = indent + " /* FIXME: implied do loop */ "; + src = out; + last_expr_precedence = 2; + } + + void visit_DoLoop(const ASR::DoLoop_t &x) { + std::string indent(indentation_level*indentation_spaces, ' '); + std::string out = indent + "for ("; + ASR::Variable_t *loop_var = LFortran::ASRUtils::EXPR2VAR(x.m_head.m_v); + std::string lvname=loop_var->m_name; + ASR::expr_t *a=x.m_head.m_start; + ASR::expr_t *b=x.m_head.m_end; + ASR::expr_t *c=x.m_head.m_increment; + LFORTRAN_ASSERT(a); + LFORTRAN_ASSERT(b); + int increment; + if (!c) { + increment = 1; + } else { + if (c->type == ASR::exprType::IntegerConstant) { + increment = ASR::down_cast(c)->m_n; + } else if (c->type == ASR::exprType::UnaryOp) { + ASR::UnaryOp_t *u = ASR::down_cast(c); + LFORTRAN_ASSERT(u->m_op == ASR::unaryopType::USub); + LFORTRAN_ASSERT(u->m_operand->type == ASR::exprType::IntegerConstant); + increment = - ASR::down_cast(u->m_operand)->m_n; + } else { + throw CodeGenError("Do loop increment type not supported"); + } + } + std::string cmp_op; + if (increment > 0) { + cmp_op = "<="; + } else { + cmp_op = ">="; + } + + out += lvname + "="; + self().visit_expr(*a); + out += src + "; " + lvname + cmp_op; + self().visit_expr(*b); + out += src + "; " + lvname; + if (increment == 1) { + out += "++"; + } else if (increment == -1) { + out += "--"; + } else { + out += "+=" + std::to_string(increment); + } + out += ") {\n"; + indentation_level += 1; + for (size_t i=0; i( + LFortran::ASRUtils::symbol_get_past_external(x.m_name)); + std::string out = indent + s->m_name + "("; + for (size_t i=0; i(*x.m_args[i].m_value)) { + ASR::Variable_t *arg = LFortran::ASRUtils::EXPR2VAR(x.m_args[i].m_value); + std::string arg_name = arg->m_name; + out += arg_name; + } else { + self().visit_expr(*x.m_args[i].m_value); + out += src; + } + if (i < x.n_args-1) out += ", "; + } + out += ");\n"; + src = out; + } + +}; + +} // namespace LFortran + +#endif // LFORTRAN_ASR_TO_C_CPP_H diff --git a/src/libasr/codegen/asr_to_cpp.cpp b/src/libasr/codegen/asr_to_cpp.cpp index 6899b9c9c8..5ee51e0e30 100644 --- a/src/libasr/codegen/asr_to_cpp.cpp +++ b/src/libasr/codegen/asr_to_cpp.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -12,36 +13,6 @@ namespace LFortran { -namespace { - - // Local exception that is only used in this file to exit the visitor - // pattern and caught later (not propagated outside) - class CodeGenError - { - public: - diag::Diagnostic d; - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} - { } - }; - - class Abort {}; - -} - -// Platform dependent fast unique hash: -uint64_t get_hash(ASR::asr_t *node) -{ - return (uint64_t)node; -} - -struct SymbolInfo -{ - bool needs_declaration = true; - bool intrinsic_function = false; -}; - std::string convert_dims(size_t n_dims, ASR::dimension_t *m_dims) { std::string dims; @@ -90,21 +61,10 @@ std::string format_type(const std::string &dims, const std::string &type, return fmt; } -class ASRToCPPVisitor : public ASR::BaseVisitor +class ASRToCPPVisitor : public BaseCCPPVisitor { public: - diag::Diagnostics &diag; - std::map sym_info; - std::string src; - int indentation_level; - int indentation_spaces; - // The precedence of the last expression, using the table: - // https://en.cppreference.com/w/cpp/language/operator_precedence - int last_expr_precedence; - bool intrinsic_module = false; - const ASR::Function_t *current_function = nullptr; - - ASRToCPPVisitor(diag::Diagnostics &diag) : diag{diag} {} + ASRToCPPVisitor(diag::Diagnostics &diag) : BaseCCPPVisitor(diag) {} std::string convert_variable_decl(const ASR::Variable_t &v) { @@ -258,30 +218,6 @@ Kokkos::View from_std_vector(const std::vector &v) src = unit_src; } - void visit_Module(const ASR::Module_t &x) { - if (startswith(x.m_name, "lfortran_intrinsic_")) { - intrinsic_module = true; - } else { - intrinsic_module = false; - } - // Generate code for nested subroutines and functions first: - std::string contains; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Subroutine_t *s = ASR::down_cast(item.second); - visit_Subroutine(*s); - contains += src; - } - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - visit_Function(*s); - contains += src; - } - } - src = contains; - intrinsic_module = false; - } - void visit_Program(const ASR::Program_t &x) { // Generate code for nested subroutines and functions first: std::string contains; @@ -332,53 +268,6 @@ Kokkos::View from_std_vector(const std::vector &v) indentation_level -= 2; } - void visit_Subroutine(const ASR::Subroutine_t &x) { - indentation_level += 1; - std::string sub = "void " + std::string(x.m_name) + "("; - for (size_t i=0; im_intent)); - sub += convert_variable_decl(*arg); - if (i < x.n_args-1) sub += ", "; - } - sub += ")\n"; - - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t *v = ASR::down_cast(item.second); - if (v->m_intent == LFortran::ASRUtils::intent_local) { - SymbolInfo s; - s.needs_declaration = true; - sym_info[get_hash((ASR::asr_t*)v)] = s; - } - } - } - - std::string body; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - body += src; - } - - std::string decl; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t *v = ASR::down_cast(item.second); - if (v->m_intent == LFortran::ASRUtils::intent_local) { - if (sym_info[get_hash((ASR::asr_t*) v)].needs_declaration) { - std::string indent(indentation_level*indentation_spaces, ' '); - decl += indent; - decl += convert_variable_decl(*v) + ";\n"; - } - } - } - } - - sub += "{\n" + decl + body + "}\n\n"; - src = sub; - indentation_level -= 1; - } - void visit_Function(const ASR::Function_t &x) { if (std::string(x.m_name) == "size" && intrinsic_module ) { // Intrinsic function `size` @@ -492,98 +381,6 @@ Kokkos::View from_std_vector(const std::vector &v) src = sub; } - void visit_FunctionCall(const ASR::FunctionCall_t &x) { - ASR::Function_t *fn = ASR::down_cast( - LFortran::ASRUtils::symbol_get_past_external(x.m_name)); - std::string fn_name = fn->m_name; - if (sym_info[get_hash((ASR::asr_t*)fn)].intrinsic_function) { - if (fn_name == "size") { - LFORTRAN_ASSERT(x.n_args > 0); - visit_expr(*x.m_args[0].m_value); - std::string var_name = src; - std::string args; - if (x.n_args == 1) { - args = "0"; - } else { - for (size_t i=1; i 0); - visit_expr(*x.m_args[0].m_value); - src = "(int)" + src; - } else if (fn_name == "not") { - LFORTRAN_ASSERT(x.n_args > 0); - visit_expr(*x.m_args[0].m_value); - src = "!(" + src + ")"; - } else if (fn_name == "len") { - LFORTRAN_ASSERT(x.n_args > 0); - visit_expr(*x.m_args[0].m_value); - src = "(" + src + ").size()"; - } else { - throw CodeGenError("Intrinsic function '" + fn_name - + "' not implemented"); - } - } else { - std::string args; - for (size_t i=0; i(*x.m_target)) { - target = LFortran::ASRUtils::EXPR2VAR(x.m_target)->m_name; - } else if (ASR::is_a(*x.m_target)) { - visit_ArrayRef(*ASR::down_cast(x.m_target)); - target = src; - } else { - LFORTRAN_ASSERT(false) - } - this->visit_expr(*x.m_value); - std::string value = src; - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + target + " = " + value + ";\n"; - } - - void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { - src = std::to_string(x.m_n); - last_expr_precedence = 2; - } - - void visit_RealConstant(const ASR::RealConstant_t &x) { - src = std::to_string(x.m_r); - last_expr_precedence = 2; - } - void visit_ComplexConstructor(const ASR::ComplexConstructor_t &x) { this->visit_expr(*x.m_re); std::string re = src; @@ -596,11 +393,6 @@ Kokkos::View from_std_vector(const std::vector &v) last_expr_precedence = 2; } - void visit_StringConstant(const ASR::StringConstant_t &x) { - src = "\"" + std::string(x.m_s) + "\""; - last_expr_precedence = 2; - } - void visit_ComplexConstant(const ASR::ComplexConstant_t &x) { std::string re = std::to_string(x.m_re); std::string im = std::to_string(x.m_im); @@ -633,30 +425,6 @@ Kokkos::View from_std_vector(const std::vector &v) last_expr_precedence = 2; } - void visit_Var(const ASR::Var_t &x) { - const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); - src = ASR::down_cast(s)->m_name; - last_expr_precedence = 2; - } - - void visit_ArrayRef(const ASR::ArrayRef_t &x) { - const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); - std::string out = ASR::down_cast(s)->m_name; - out += "["; - for (size_t i=0; i from_std_vector(const std::vector &v) last_expr_precedence = 2; } - void visit_Compare(const ASR::Compare_t &x) { - this->visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - this->visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { last_expr_precedence = 10; break; } - case (ASR::cmpopType::Gt) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::GtE) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::Lt) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::LtE) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::NotEq): { last_expr_precedence = 10; break; } - default : LFORTRAN_ASSERT(false); // should never happen - } - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - src += ASRUtils::cmpop_to_str(x.m_op); - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - - void visit_UnaryOp(const ASR::UnaryOp_t &x) { - this->visit_expr(*x.m_operand); - int expr_precedence = last_expr_precedence; - if (x.m_type->type == ASR::ttypeType::Integer) { - if (x.m_op == ASR::unaryopType::UAdd) { - // src = src; - // Skip unary plus, keep the previous precedence - } else if (x.m_op == ASR::unaryopType::USub) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "-" + src; - } else { - src = "-(" + src + ")"; - } - } else if (x.m_op == ASR::unaryopType::Invert) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "~" + src; - } else { - src = "~(" + src + ")"; - } - - } else if (x.m_op == ASR::unaryopType::Not) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "!" + src; - } else { - src = "!(" + src + ")"; - } - } else { - throw CodeGenError("Unary type not implemented yet for Integer"); - } - return; - } else if (x.m_type->type == ASR::ttypeType::Real) { - if (x.m_op == ASR::unaryopType::UAdd) { - // src = src; - // Skip unary plus, keep the previous precedence - } else if (x.m_op == ASR::unaryopType::USub) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "-" + src; - } else { - src = "-(" + src + ")"; - } - } else if (x.m_op == ASR::unaryopType::Not) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "!" + src; - } else { - src = "!(" + src + ")"; - } - } else { - throw CodeGenError("Unary type not implemented yet for Real"); - } - return; - } else if (x.m_type->type == ASR::ttypeType::Logical) { - if (x.m_op == ASR::unaryopType::Not) { - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "!" + src; - } else { - src = "!(" + src + ")"; - } - return; - } else { - throw CodeGenError("Unary type not implemented yet for Logical"); - } - } else { - throw CodeGenError("UnaryOp: type not supported yet"); - } - } - - void visit_BinOp(const ASR::BinOp_t &x) { - this->visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - this->visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::binopType::Add) : { last_expr_precedence = 6; break; } - case (ASR::binopType::Sub) : { last_expr_precedence = 6; break; } - case (ASR::binopType::Mul) : { last_expr_precedence = 5; break; } - case (ASR::binopType::Div) : { last_expr_precedence = 5; break; } - case (ASR::binopType::Pow) : { - src = "std::pow(" + left + ", " + right + ")"; - return; - } - default: throw CodeGenError("BinOp: operator not implemented yet"); - } - src = ""; - if (left_precedence == 3) { - src += "(" + left + ")"; - } else { - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - } - src += ASRUtils::binop_to_str(x.m_op); - if (right_precedence == 3) { - src += "(" + right + ")"; - } else if (x.m_op == ASR::binopType::Sub) { - if (right_precedence < last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } else { - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - } - void visit_StringConcat(const ASR::StringConcat_t &x) { this->visit_expr(*x.m_left); std::string left = std::move(src); @@ -882,46 +503,6 @@ Kokkos::View from_std_vector(const std::vector &v) } } - void visit_BoolOp(const ASR::BoolOp_t &x) { - this->visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - this->visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::boolopType::And): { - last_expr_precedence = 14; - break; - } - case (ASR::boolopType::Or): { - last_expr_precedence = 15; - break; - } - case (ASR::boolopType::NEqv): { - last_expr_precedence = 10; - break; - } - case (ASR::boolopType::Eqv): { - last_expr_precedence = 10; - break; - } - default : throw CodeGenError("Unhandled switch case"); - } - - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - src += ASRUtils::boolop_to_str(x.m_op); - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - void visit_ArrayConstant(const ASR::ArrayConstant_t &x) { std::string out = "from_std_vector({"; for (size_t i=0; i from_std_vector(const std::vector &v) src = out; } - void visit_Allocate(const ASR::Allocate_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "// FIXME: allocate("; - for (size_t i=0; i from_std_vector(const std::vector &v) src = out; } - void visit_WhileLoop(const ASR::WhileLoop_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "while ("; - visit_expr(*x.m_test); - out += src + ") {\n"; - indentation_level += 1; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "}\n"; - indentation_level -= 1; - src = out; - } - - void visit_Exit(const ASR::Exit_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + "break;\n"; - } - - void visit_Cycle(const ASR::Cycle_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + "continue;\n"; - } - - void visit_Return(const ASR::Return_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - if (current_function) { - src = indent + "return " - + LFortran::ASRUtils::EXPR2VAR(current_function->m_return_var)->m_name - + ";\n"; - } else { - src = indent + "return;\n"; - } - } - - void visit_GoToTarget(const ASR::GoToTarget_t & /* x */) { - // Ignore for now - src = ""; - } - - void visit_Stop(const ASR::Stop_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + "exit(0);\n"; - } - - void visit_ImpliedDoLoop(const ASR::ImpliedDoLoop_t &/*x*/) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + " /* FIXME: implied do loop */ "; - src = out; - last_expr_precedence = 2; - } - - void visit_DoLoop(const ASR::DoLoop_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "for ("; - ASR::Variable_t *loop_var = LFortran::ASRUtils::EXPR2VAR(x.m_head.m_v); - std::string lvname=loop_var->m_name; - ASR::expr_t *a=x.m_head.m_start; - ASR::expr_t *b=x.m_head.m_end; - ASR::expr_t *c=x.m_head.m_increment; - LFORTRAN_ASSERT(a); - LFORTRAN_ASSERT(b); - int increment; - if (!c) { - increment = 1; - } else { - if (c->type == ASR::exprType::IntegerConstant) { - increment = ASR::down_cast(c)->m_n; - } else if (c->type == ASR::exprType::UnaryOp) { - ASR::UnaryOp_t *u = ASR::down_cast(c); - LFORTRAN_ASSERT(u->m_op == ASR::unaryopType::USub); - LFORTRAN_ASSERT(u->m_operand->type == ASR::exprType::IntegerConstant); - increment = - ASR::down_cast(u->m_operand)->m_n; - } else { - throw CodeGenError("Do loop increment type not supported"); - } - } - std::string cmp_op; - if (increment > 0) { - cmp_op = "<="; - } else { - cmp_op = ">="; - } - - out += lvname + "="; - visit_expr(*a); - out += src + "; " + lvname + cmp_op; - visit_expr(*b); - out += src + "; " + lvname; - if (increment == 1) { - out += "++"; - } else if (increment == -1) { - out += "--"; - } else { - out += "+=" + std::to_string(increment); - } - out += ") {\n"; - indentation_level += 1; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "}\n"; - indentation_level -= 1; - src = out; - } - void visit_DoConcurrentLoop(const ASR::DoConcurrentLoop_t &x) { std::string indent(indentation_level*indentation_spaces, ' '); std::string out = indent + "Kokkos::parallel_for("; @@ -1159,65 +576,6 @@ Kokkos::View from_std_vector(const std::vector &v) src += indent + "exit(1);\n"; } - void visit_If(const ASR::If_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "if ("; - visit_expr(*x.m_test); - out += src + ") {\n"; - indentation_level += 1; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "}"; - if (x.n_orelse == 0) { - out += "\n"; - } else { - out += " else {\n"; - for (size_t i=0; ivisit_stmt(*x.m_orelse[i]); - out += src; - } - out += indent + "}\n"; - } - indentation_level -= 1; - src = out; - } - - void visit_IfExp(const ASR::IfExp_t &x) { - // IfExp is like a ternary operator in c++ - // test ? body : orelse; - std::string out = "("; - visit_expr(*x.m_test); - out += src + ") ? ("; - visit_expr(*x.m_body); - out += src + ") : ("; - visit_expr(*x.m_orelse); - out += src + ")"; - src = out; - last_expr_precedence = 16; - } - - void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - ASR::Subroutine_t *s = ASR::down_cast( - LFortran::ASRUtils::symbol_get_past_external(x.m_name)); - std::string out = indent + s->m_name + "("; - for (size_t i=0; i(*x.m_args[i].m_value)) { - ASR::Variable_t *arg = LFortran::ASRUtils::EXPR2VAR(x.m_args[i].m_value); - std::string arg_name = arg->m_name; - out += arg_name; - } else { - this->visit_expr(*x.m_args[i].m_value); - out += src; - } - if (i < x.n_args-1) out += ", "; - } - out += ");\n"; - src = out; - } - }; Result asr_to_cpp(Allocator &al, ASR::TranslationUnit_t &asr,