Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 176
Implement goto in LPython#1163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
e49eaa0cc9bf94a0991ec9e938f7fa57b763f8111a3a5f0f5d5b21d6File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| from ltypes import with_goto, i32 | ||
| @with_goto | ||
| def f() -> i32: | ||
| i:i32 | ||
| for i in range(10): | ||
| if i == 5: | ||
| goto .end | ||
| label .end | ||
| assert i == 5 | ||
| return i | ||
| @with_goto | ||
| def g(size: i32) -> i32: | ||
| i:i32 | ||
| i = 0 | ||
| label .loop | ||
| if i >= size: | ||
| goto .end | ||
| i += 1 | ||
| goto .loop | ||
| label .end | ||
| return i | ||
| def test_goto(): | ||
| print(f()) | ||
| print(g(10)) | ||
| print(g(20)) | ||
| assert g(30) == 30 | ||
| assert g(40) == 40 | ||
| test_goto() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| #include <fstream> | ||
| #include <iostream> | ||
| #include <map> | ||
| #include <set> | ||
| #include <memory> | ||
| #include <string> | ||
| #include <cmath> | ||
| @@ -2843,7 +2844,6 @@ class SymbolTableVisitor : public CommonVisitor<SymbolTableVisitor> { | ||
| bool current_procedure_interface = false; | ||
| bool overload = false; | ||
| bool vectorize = false, is_inline = false, is_static = false; | ||
| Vec<ASR::ttype_t*> tps; | ||
| tps.reserve(al, x.m_args.n_args); | ||
| bool is_restriction = false; | ||
| @@ -2866,6 +2866,8 @@ class SymbolTableVisitor : public CommonVisitor<SymbolTableVisitor> { | ||
| vectorize = true; | ||
| } else if (name == "restriction") { | ||
| is_restriction = true; | ||
| } else if (name == "with_goto") { | ||
| // TODO: Use goto attribute in function? | ||
| } else if (name == "inline") { | ||
| is_inline = true; | ||
| } else if (name == "static") { | ||
| @@ -3211,11 +3213,14 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> { | ||
| public: | ||
| ASR::asr_t *asr; | ||
| std::map<std::string, std::tuple<int64_t, bool, Location>> goto_name2id; | ||
| int64_t gotoids; | ||
| BodyVisitor(Allocator &al, ASR::asr_t *unit, diag::Diagnostics &diagnostics, | ||
| bool main_module, std::map<int, ASR::symbol_t*> &ast_overload) | ||
| : CommonVisitor(al, nullptr, diagnostics, main_module, ast_overload, ""), asr{unit} | ||
| : CommonVisitor(al, nullptr, diagnostics, main_module, ast_overload, ""), asr{unit}, | ||
| gotoids{0} | ||
| {} | ||
| // Transforms statements to a list of ASR statements | ||
| @@ -3300,6 +3305,8 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> { | ||
| } | ||
| void visit_FunctionDef(const AST::FunctionDef_t &x) { | ||
| goto_name2id.clear(); | ||
| gotoids = 0; | ||
| SymbolTable *old_scope = current_scope; | ||
| ASR::symbol_t *t = current_scope->get_symbol(x.m_name); | ||
| if (ASR::is_a<ASR::Function_t>(*t)) { | ||
| @@ -3320,6 +3327,13 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> { | ||
| } | ||
| current_scope = old_scope; | ||
| tmp = nullptr; | ||
| for( auto itr: goto_name2id ) { | ||
| if( !std::get<1>(itr.second) ) { | ||
| throw SemanticError("Label '" + itr.first + "' is not defined in '" | ||
| + std::string(x.m_name) + "'", std::get<2>(itr.second)); | ||
| } | ||
| } | ||
| } | ||
| void visit_Import(const AST::Import_t &/*x*/) { | ||
| @@ -3969,7 +3983,36 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> { | ||
| void visit_Attribute(const AST::Attribute_t &x) { | ||
| if (AST::is_a<AST::Name_t>(*x.m_value)) { | ||
| std::string value = AST::down_cast<AST::Name_t>(x.m_value)->m_id; | ||
| if( value == "label" ) { | ||
| std::string labelname = x.m_attr; | ||
| if( goto_name2id.find(labelname) == goto_name2id.end() ) { | ||
| goto_name2id[labelname] = std::make_tuple(gotoids, true, x.base.base.loc); | ||
| gotoids += 1; | ||
| } else if( !std::get<1>(goto_name2id[labelname]) ) { | ||
| goto_name2id[labelname] = std::make_tuple( | ||
| std::get<0>(goto_name2id[labelname]), | ||
| true, | ||
| std::get<2>(goto_name2id[labelname]) | ||
| ); | ||
| } | ||
| int id = std::get<0>(goto_name2id[labelname]); | ||
| tmp = ASR::make_GoToTarget_t(al, x.base.base.loc, id, x.m_attr); | ||
| return ; | ||
| } | ||
| if (value == "goto"){ | ||
| std::string labelname = std::string(x.m_attr); | ||
| if( goto_name2id.find(labelname) == goto_name2id.end() ) { | ||
| goto_name2id[labelname] = std::make_tuple(gotoids, false, x.base.base.loc); | ||
| gotoids += 1; | ||
| } | ||
| int id = std::get<0>(goto_name2id[labelname]); | ||
| tmp = ASR::make_GoTo_t(al, x.base.base.loc, id, x.m_attr); | ||
| return ; | ||
| } | ||
| ASR::symbol_t *t = current_scope->resolve_symbol(value); | ||
| if (!t) { | ||
| throw SemanticError("'" + value + "' is not defined in the scope", | ||
| x.base.base.loc); | ||
| @@ -4543,8 +4586,14 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> { | ||
| return; | ||
| } | ||
| this->visit_expr(*x.m_value); | ||
| ASRUtils::EXPR(tmp); | ||
| tmp = nullptr; | ||
| // If tmp is a statement and not an expression | ||
| // never cast into expression using ASRUtils::EXPR | ||
| // Just ignore and exit the function naturally. | ||
| if( !ASR::is_a<ASR::stmt_t>(*tmp) ) { | ||
| LFORTRAN_ASSERT(ASR::is_a<ASR::expr_t>(*tmp)); | ||
| tmp = nullptr; | ||
| } | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of these lines, both the original and the new ones? Are we checking that the result is an expression? If so, you can use an assert for Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the scene is that Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Assert with Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please document this as a comment? Next person to see that code will have the same question, including me tomorrow. | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think GoTo should just reference using an ID. The name should go into GoToTarget.
Or am I missing something?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well in C backend we need the name to produce,
label name_of_the_labelorgoto name_of_the_label. So we need the name to be stored in both GoTo and GoToTarget.