Skip to content

Commit 07095ef

Browse files
Initial interactive shell implementation
1 parent dfeacbc commit 07095ef

File tree

1 file changed

+125
-4
lines changed

1 file changed

+125
-4
lines changed

src/bin/lpython.cpp

Lines changed: 125 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <lpython/python_serialization.h>
3434
#include <lpython/parser/tokenizer.h>
3535
#include <lpython/parser/parser.h>
36+
#include <libasr/exception.h>
3637

3738
#include <cpp-terminal/terminal.h>
3839
#include <cpp-terminal/prompt0.h>
@@ -792,6 +793,123 @@ int emit_llvm(const std::string &infile,
792793
return 0;
793794
}
794795

796+
int interactive_python_repl(
797+
LCompilers::PassManager& pass_manager,
798+
CompilerOptions &compiler_options,
799+
bool time_report)
800+
{
801+
Allocator al(4*1024);
802+
803+
LCompilers::diag::Diagnostics diagnostics;
804+
LCompilers::LocationManager lm;
805+
std::vector<std::pair<std::string, double>> times;
806+
std::string infile;
807+
808+
std::string code_string;
809+
std::cout << ">>> ";
810+
size_t cell_count = 0;
811+
for (std::string input; std::getline(std::cin, input);) {
812+
813+
if (input == "exit" || input == "quit") // exit condition
814+
return 0;
815+
816+
if ((input.rfind("def", 0) == 0) ||
817+
(input.rfind("for", 0) == 0) ||
818+
(input.rfind("if", 0) == 0) ||
819+
(input.rfind("else", 0) == 0) ||
820+
(input.rfind("elif", 0) == 0) ||
821+
(input.rfind("class", 0) == 0) ||
822+
(input.rfind(' ', 0) == 0) ||
823+
(input.rfind('\t', 0) == 0)) {
824+
// start of a block
825+
code_string += input + "\n";
826+
std::cout << "... ";
827+
continue;
828+
}
829+
code_string += input + "\n";
830+
831+
// std::cout << "code block: \n" << code_string;
832+
833+
{
834+
cell_count++;
835+
LCompilers::LocationManager::FileLocations fl;
836+
infile = "stdin" + std::to_string(cell_count);
837+
fl.in_filename = infile;
838+
lm.files.push_back(fl);
839+
lm.init_simple(code_string);
840+
lm.file_ends.push_back(code_string.size());
841+
}
842+
843+
/* parse and run */
844+
// parsing string to AST
845+
auto parsing_start = std::chrono::high_resolution_clock::now();
846+
// ???: change `parse_python_file` to `parse` or `parse_string`
847+
LCompilers::Result<LCompilers::LPython::AST::Module_t*> r = LCompilers::LPython::parse(al, code_string, 0, diagnostics);
848+
auto parsing_end = std::chrono::high_resolution_clock::now();
849+
times.push_back(std::make_pair("Parsing", std::chrono::duration<double, std::milli>(parsing_end - parsing_start).count()));
850+
std::cerr << diagnostics.render(lm, compiler_options);
851+
if (!r.ok) {
852+
LCOMPILERS_ASSERT(diagnostics.has_error())
853+
print_time_report(times, time_report);
854+
return 1;
855+
}
856+
857+
// AST -> ASR
858+
LCompilers::LPython::AST::ast_t* ast = (LCompilers::LPython::AST::ast_t*)r.result;
859+
diagnostics.diagnostics.clear();
860+
auto ast_to_asr_start = std::chrono::high_resolution_clock::now();
861+
LCompilers::Result<LCompilers::ASR::TranslationUnit_t*>
862+
r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options,
863+
!(false && compiler_options.po.disable_main), "__main__", infile);
864+
865+
auto ast_to_asr_end = std::chrono::high_resolution_clock::now();
866+
times.push_back(std::make_pair("AST to ASR", std::chrono::duration<double, std::milli>(ast_to_asr_end - ast_to_asr_start).count()));
867+
std::cerr << diagnostics.render(lm, compiler_options);
868+
if (!r1.ok) {
869+
LCOMPILERS_ASSERT(diagnostics.has_error())
870+
print_time_report(times, time_report);
871+
return 2;
872+
}
873+
LCompilers::ASR::TranslationUnit_t* asr = r1.result;
874+
diagnostics.diagnostics.clear();
875+
876+
LCompilers::PythonCompiler fe(compiler_options);
877+
LCompilers::LLVMEvaluator e(compiler_options.target);
878+
std::unique_ptr<LCompilers::LLVMModule> m;
879+
auto asr_to_llvm_start = std::chrono::high_resolution_clock::now();
880+
LCompilers::Result<std::unique_ptr<LCompilers::LLVMModule>>
881+
res = fe.get_llvm3(*asr, pass_manager, diagnostics, infile);
882+
auto asr_to_llvm_end = std::chrono::high_resolution_clock::now();
883+
times.push_back(std::make_pair("ASR to LLVM", std::chrono::duration<double, std::milli>(asr_to_llvm_end - asr_to_llvm_start).count()));
884+
885+
std::cerr << diagnostics.render(lm, compiler_options);
886+
if (!res.ok) {
887+
LCOMPILERS_ASSERT(diagnostics.has_error())
888+
print_time_report(times, time_report);
889+
return 3;
890+
}
891+
m = std::move(res.result);
892+
893+
bool call_init = false;
894+
bool call_stmts = false;
895+
if (m->get_return_type("__module___main_____main__global_init") == "void")
896+
call_init = true;
897+
if (m->get_return_type("__module___main_____main__global_stmts") == "void")
898+
call_stmts = true;
899+
900+
e.add_module(std::move(m));
901+
if (call_init)
902+
e.voidfn("__module___main_____main__global_init");
903+
if (call_stmts)
904+
e.voidfn("__module___main_____main__global_stmts");
905+
/* end parse and run */
906+
907+
code_string = "";
908+
std::cout << ">>> ";
909+
}
910+
return 0;
911+
}
912+
795913
/*
796914
Compiles python to object file, if `to_jit` is false
797915
otherwise execute python code using llvm JIT
@@ -1785,6 +1903,9 @@ int main(int argc, char *argv[])
17851903
compiler_options.use_colors = !arg_no_color;
17861904
compiler_options.indent = !arg_no_indent;
17871905

1906+
lpython_pass_manager.parse_pass_arg(arg_pass, skip_pass);
1907+
lpython_pass_manager.use_default_passes();
1908+
17881909
// if (fmt) {
17891910
// return format(arg_fmt_file, arg_fmt_inplace, !arg_fmt_no_color,
17901911
// arg_fmt_indent, arg_fmt_indent_unit, compiler_options);
@@ -1831,8 +1952,10 @@ int main(int argc, char *argv[])
18311952
}
18321953

18331954
if (arg_files.size() == 0) {
1834-
std::cerr << "Interactive prompt is not implemented yet in LPython" << std::endl;
1835-
return 1;
1955+
compiler_options.po.disable_main = true;
1956+
compiler_options.emit_debug_line_column = false;
1957+
compiler_options.generate_object_code = false;
1958+
return interactive_python_repl(lpython_pass_manager, compiler_options, time_report);
18361959
}
18371960

18381961
// TODO: for now we ignore the other filenames, only handle
@@ -1875,7 +1998,6 @@ int main(int argc, char *argv[])
18751998
// return emit_c_preprocessor(arg_file, compiler_options);
18761999
// }
18772000

1878-
lpython_pass_manager.parse_pass_arg(arg_pass, skip_pass);
18792001
if (show_tokens) {
18802002
return emit_tokens(arg_file, true, compiler_options);
18812003
}
@@ -1917,7 +2039,6 @@ int main(int argc, char *argv[])
19172039
return 1;
19182040
#endif
19192041
}
1920-
lpython_pass_manager.use_default_passes();
19212042
if (show_llvm) {
19222043
#ifdef HAVE_LFORTRAN_LLVM
19232044
return emit_llvm(arg_file, runtime_library_dir, lpython_pass_manager, compiler_options);

0 commit comments

Comments
 (0)