-
Notifications
You must be signed in to change notification settings - Fork 166
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
Printing top-level Expressions #2716
Printing top-level Expressions #2716
Conversation
c384731
to
d7e9451
Compare
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.
Shared some comments below.
result.type = EvalResult::none; | ||
} else { | ||
throw LCompilersException("FortranEvaluator::evaluate(): Return type not supported"); | ||
} |
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.
Did we previously add all the above code somewhere else? (It feels like we added it somewhere before).
If this is being duplicated then I think we should create a function out of it and call that function here.
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 had initially implemented this in #2698, but we did not merge. That PR lacked tests. We also merged other changes between that PR and this. I was thinking of closing that PR without merging it once we merge this PR.
@@ -608,7 +608,7 @@ define float @f() | |||
CHECK(std::abs(r - 8) < 1e-6); | |||
} | |||
|
|||
TEST_CASE("PythonCompiler 1") { | |||
TEST_CASE("PythonCompiler i32 expressions") { |
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.
Let's add this as a separate test and not change the existing test.
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.
Ok. I can do that.
if ((tmp) && (!ASR::is_a<ASR::expr_t>(*tmp))) { | ||
LCOMPILERS_ASSERT(ASR::is_a<ASR::expr_t>(*tmp)); | ||
tmp = nullptr; |
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 did not quite get the logic here. It says if tmp exists and it is not an expression
, then right inside the if
, we have assert that tmp is an expression
. tmp is not an expresssion
in if
and tmp is an expression
in the assert are contradicting, right?
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.
Yes. It does not make sense. I should remove that assertion.
Please mark as "Ready for review" when ready. |
Also, I think we have some previous discussion about printing top-level expressions. Would you mind linking that PR here so that others can have a better context about this? |
We discussed this in #2698. |
if ((tmp) && (!ASR::is_a<ASR::expr_t>(*tmp))) { | ||
tmp = nullptr; | ||
} |
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 am a bit confused here. We make tmp
as nullptr
everytime it is not an expression. But, why do we do so? I think this means, if tmp
is a statement, then we are skipping it. Any specific reason to skip statements @Vipul-Cariappa ?
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.
If tmp
is an expression then we return it. So that we can print it. The pass_wrap_global_stmts
function uses this tmp
expression and returns the evaluated result of the expression for us to print it later using PythonCompiler::evaluate
and interactive_python_repl
.
If tmp
is a statement, for example, an assignment x = 5
then we would not want to print anything, so we set tmp
to nullptr
.
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.
x = 5 then we would not want to print anything, so we set tmp to nullptr
Although we do not want to print anything, but we do want x
to be updated to 5
. I am unsure, but if we skip the whole x = 5
statement, then would the value of x
be updated to 5
?
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.
The pass_wrap_global_stmts function uses this tmp expression and returns the evaluated result of the expression for us
Does it actually return an evaluated result? Or does it simply convert expressions into assignment statements?
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.
Yes. The statement will be executed and x
will be updated to 5
.
❯ lp
>>> x: i32
>>> x
0
>>> x = 5
>>> x
5
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.
Does it actually return an evaluated result? Or does it simply convert expressions into assignment statements?
It returns the evaluated result. You can run the interactive in verbose mode with -v
flag to see the AST, ASR, and the LLVM IR generated. Doing so, you can see that it returns the result.
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.
With the current approach, I doubt that we are/would-be skipping some stmts like empty()
and c_p_pointer()
lpython/src/lpython/semantics/python_ast_to_asr.cpp
Lines 5220 to 5221 in 13bb54e
// This happens for c_p_pointer() and | |
// empty() (if target is of type allocatable) |
See my comment below https://github.com/lcompilers/lpython/pull/2716/files#r1614616838 which I think would avoid this.
r = e.evaluate2("i: i32"); | ||
CHECK(r.ok); | ||
CHECK(r.result.type == PythonCompiler::EvalResult::none); | ||
r = e.evaluate2("i = 5"); | ||
CHECK(r.ok); | ||
CHECK(r.result.type == PythonCompiler::EvalResult::statement); | ||
r = e.evaluate2("i"); | ||
CHECK(r.ok); | ||
CHECK(r.result.type == PythonCompiler::EvalResult::integer4); | ||
CHECK(r.result.i32 == 5); |
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.
The test here makes sure that the execution of statements is not skipped.
if (eval_count > 0) { | ||
// In Interactive mode | ||
if ((tmp) && (!ASR::is_a<ASR::expr_t>(*tmp))) { | ||
tmp = nullptr; | ||
} | ||
} else if (tmp && !ASR::is_a<ASR::stmt_t>(*tmp)) { |
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.
Can you check if doing the following works?
if (eval_count > 0) { | |
// In Interactive mode | |
if ((tmp) && (!ASR::is_a<ASR::expr_t>(*tmp))) { | |
tmp = nullptr; | |
} | |
} else if (tmp && !ASR::is_a<ASR::stmt_t>(*tmp)) { | |
if (eval_count == 0 && tmp && !ASR::is_a<ASR::stmt_t>(*tmp)) { |
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.
These changes work. I have committed it.
Co-authored-by: Shaikh Ubaid <[email protected]>
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.
LGTM, Thanks! Nice work!
Example:
I have rebased this branch of #2713.