-
Notifications
You must be signed in to change notification settings - Fork 170
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
Changes from all commits
e49eaa0
cc9bf94
a0991ec
9e938f7
fa57b76
3f8111a
3a5f0f5
d5b21d6
File filter
Filter by extension
Conversations
Jump to
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; | ||
} | ||
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 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 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 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. |
||
} | ||
|
||
|
||
|
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_label
orgoto name_of_the_label
. So we need the name to be stored in both GoTo and GoToTarget.