-
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
Interactive shell implementation #2617
Conversation
I want to know how should I proceed with the first to-do point "Remember global functions and variables declared". The problem is as follows >>> def f():
... print("called function f")
...
>>> f()
semantic error: Function 'f' is not declared and not intrinsic
--> input:1:1
|
1 | f()
| ^ Another example: >>> x: i32 = 10
>>> print(x)
semantic error: Variable 'x' not declared
--> input:1:1
|
1 | print(x)
| ^ The declared function I want to know if there are existing methods to do this. Or should I implement it myself. I want something like. |
I think the idea to solve this is to keep updating the original ASR on every new interactive query run by the user. On every run, the functions or variables defined in the previous run need to be updated. We remove the body of functions and set their LFortran already supports interactive compilation. You can look into it for reference. Since the ASR passes and backends are shared with LFortran, I think we will mostly need interactive support for AST->ASR in LPython. |
5b9a184
to
a18035d
Compare
Let's build this iteratively. For this PR, let's get something that works with the interactive shell, add tests for the implemented support and ensure the CI passes. After that, you can send more PRs to improve the existing support and/or add more features as planned in #2617 (comment). Ideally, small and frequent PRs that just focus on one particular support with robust tests are preferable. For tests, you can look into how lfortran does it https://github.com/lfortran/lfortran/blob/582db3d4379eee26cfeb0721d5fda21971aaae3d/src/lfortran/tests/test_llvm.cpp#L439-L455. Feel free to reach out if you need any help. |
Please mark this as "Ready for review" when ready. |
It makes more sense to have multiple smaller PR than a large one. I will finish up the work with remembering context from the previous cells, i.e. remembering global functions and variables. |
src/lpython/python_evaluator.cpp
Outdated
Result<std::unique_ptr<LCompilers::LLVMModule>> res | ||
= asr_to_llvm(asr, diagnostics, | ||
e->get_context(), al, lpm, compiler_options, | ||
run_fn, infile); | ||
"", infile); // ??? What about run function |
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 argument ""
is the run_fn
. The run_fn
is not used here. In LFortran all global statements are compiled into 1 function, but in LPython it is compiled into two different functions one for global initialization and the other to execute global 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.
I see. Do you need the above change of run_fn
to ""
for the interactivity to run/work? Or is the above just a refactoring change?
If it is a refactoring change (which it seems to be), I suggest we do it in a separate PR.
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.
Now that we have merged global_init
and global_stmts
, we can assign run_fn
to global_stmts
and use it.
Then that change would be part of this PR. You can have a look at it in successive commits.
static size_t interactive_execution_count = 0; // ???: should this be a class member variable | ||
// interactive_execution_count should be the same as eval_count in PythonCompiler |
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.
Any suggestions on this?
Should we create run_fn1
and run_fn2
and share it through the PassOptions
?
But even that may not be straightforward.
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.
Another option would be to combine the init
and stmts
functions. Look at #2573
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 saw the linked issue. If combining init
and stmt
function solves your issue, then you can try it. Submit it as a separate PR and we can rebase this after that is merged.
I guess we can merge the work done till this point. The redefinition of symbols is not yet supported. It looks more complicated than initially thought. We can add support for the redefinition of symbols in a later PR. Not sure why the tests are failing. I have left 2 comments please have a look at it. |
You need to update the reference tests. You can do |
At a high level, it looks good. I will review in detail in evening today. |
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 shared a couple comments.
Mainly:
- Let's reuse
Module
, that way we get to reuse a lot of other existing code - We can merge
global_init
andglobal_stmts
in a separate PR. I think we need it to solve [Bug] All global variable assignments should not go to__main__global_init
#2573 - Minor refactoring
Apart from that, it looks good. Great start! Amazing work!
src/lpython/python_evaluator.cpp
Outdated
Result<std::unique_ptr<LCompilers::LLVMModule>> res | ||
= asr_to_llvm(asr, diagnostics, | ||
e->get_context(), al, lpm, compiler_options, | ||
run_fn, infile); | ||
"", infile); // ??? What about run function |
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 see. Do you need the above change of run_fn
to ""
for the interactivity to run/work? Or is the above just a refactoring change?
If it is a refactoring change (which it seems to be), I suggest we do it in a separate PR.
@@ -8,7 +8,7 @@ namespace LCompilers::LPython { | |||
|
|||
Result<ASR::TranslationUnit_t*> python_ast_to_asr(Allocator &al, LocationManager &lm, SymbolTable* symtab, | |||
LPython::AST::ast_t &ast, diag::Diagnostics &diagnostics, CompilerOptions &compiler_options, | |||
bool main_module, std::string module_name, std::string file_path, bool allow_implicit_casting=false); | |||
bool main_module, std::string module_name, std::string file_path, bool allow_implicit_casting=false, bool is_interactive=false); |
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.
You can also pass the eval_count
here and have it as a class member. Then for body visitor
inside visit_Module
(assuming we are reusing this instead of defining visit_Interactive
), you can use the eval_count
for naming global_init
and global_stmts
if interactive = true
. (For example simply append the eval_count to the end if interactive is true).
Please mark as "Ready for review" when ready. |
a36d692
to
b61eccf
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.
Good! Few more minor comments. I think it will be good to merge after that. We can add tests in a separate PR.
src/lpython/python_evaluator.cpp
Outdated
#include "libasr/asr_scopes.h" | ||
#include "lpython/python_ast.h" |
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 use <>
instead of ""
here and place this along with other similar includes below.
src/bin/lpython.cpp
Outdated
@@ -1778,6 +1935,7 @@ int main(int argc, char *argv[]) | |||
compiler_options.use_colors = !arg_no_color; | |||
compiler_options.indent = !arg_no_indent; | |||
|
|||
|
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.
src/lpython/python_evaluator.cpp
Outdated
#include <libasr/codegen/asr_to_cpp.h> | ||
#include <libasr/exception.h> | ||
#include <libasr/asr.h> | ||
#include <lpython/pickle.h> | ||
#include <lpython/parser/parser.h> | ||
#include <string> |
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 this should be included with other system headers at the top. I am unsure if system headers should be listed first and then the custom headers or the other way round. But let's atleast place them together.
eval_count++; | ||
run_fn = "__lfortran_evaluate_" + std::to_string(eval_count); | ||
|
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.
We later plan to move the interactivity support into the LibASR so that it is shared between LFortran, LPython and LC. So, it is better that we have/use as common/generic code as possible which easily gets shared across all LCompilers.
Assuming it does not affect the newly added interactivity, I think for now it is better to have it.
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 we keep this as part of the next PR? It may require changes in more than one place.
I was working towards "print the value of the evaluated expression" (#2617 (comment)) goal, and I think there might be some obstacles to doing this. But is doable.
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 we keep this as part of the next PR?
We can do that.
src/lpython/python_evaluator.h
Outdated
@@ -59,10 +71,10 @@ class PythonCompiler | |||
Allocator al; | |||
#ifdef HAVE_LFORTRAN_LLVM | |||
std::unique_ptr<LLVMEvaluator> e; | |||
int eval_count; | |||
size_t eval_count; |
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.
This is passed as argument to python_ast_to_asr()
. The call to python_ast_to_asr()
is also used by other backends. So, this should be declared outside of #ifdef HAVE_LFORTRAN_LLVM
.
PS: The above will fix the CI failure.
I have made the suggested changes. Please have a look. I have also left a comment on one of your suggestions. |
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.
It looks good! Thanks for this! Great work!
eval_count++; | ||
run_fn = "__lfortran_evaluate_" + std::to_string(eval_count); | ||
|
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 we keep this as part of the next PR?
We can do that.
Let's add some tests for this in the next PR! |
Fixes #329
TODOs
symengine
andnumpy
supportlist
,tuple
anddict
Got the following things to work: