repl.h 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #pragma once
  2. #include "compiler.h"
  3. #include "ceval.h"
  4. #ifdef _WIN32
  5. #define WIN32_LEAN_AND_MEAN
  6. #include <Windows.h>
  7. #endif
  8. namespace pkpy{
  9. #ifdef _WIN32
  10. inline std::string getline(bool* eof=nullptr) {
  11. HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
  12. std::wstringstream wss;
  13. WCHAR buf;
  14. DWORD read;
  15. while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
  16. if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z
  17. wss << buf;
  18. }
  19. std::wstring wideInput = wss.str();
  20. int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL);
  21. std::string output;
  22. output.resize(length);
  23. WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
  24. if(!output.empty() && output.back() == '\r') output.pop_back();
  25. return output;
  26. }
  27. #else
  28. inline std::string getline(bool* eof=nullptr){
  29. std::string line;
  30. if(!std::getline(std::cin, line)){
  31. if(eof) *eof = true;
  32. }
  33. return line;
  34. }
  35. #endif
  36. class REPL {
  37. protected:
  38. int need_more_lines = 0;
  39. std::string buffer;
  40. VM* vm;
  41. public:
  42. REPL(VM* vm) : vm(vm){
  43. vm->_stdout(vm, "pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
  44. vm->_stdout(vm, fmt("[", sizeof(void*)*8, " bit]" "\n"));
  45. vm->_stdout(vm, "https://github.com/blueloveTH/pocketpy" "\n");
  46. vm->_stdout(vm, "Type \"exit()\" to exit." "\n");
  47. }
  48. bool input(std::string line){
  49. CompileMode mode = REPL_MODE;
  50. if(need_more_lines){
  51. buffer += line;
  52. buffer += '\n';
  53. int n = buffer.size();
  54. if(n>=need_more_lines){
  55. for(int i=buffer.size()-need_more_lines; i<buffer.size(); i++){
  56. // no enough lines
  57. if(buffer[i] != '\n') return true;
  58. }
  59. need_more_lines = 0;
  60. line = buffer;
  61. buffer.clear();
  62. mode = CELL_MODE;
  63. }else{
  64. return true;
  65. }
  66. }
  67. try{
  68. vm->exec(line, "<stdin>", mode);
  69. }catch(NeedMoreLines& ne){
  70. buffer += line;
  71. buffer += '\n';
  72. need_more_lines = ne.is_compiling_class ? 3 : 2;
  73. if (need_more_lines) return true;
  74. }
  75. return false;
  76. }
  77. };
  78. } // namespace pkpy