sourcedata.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. #include "pocketpy/objects/sourcedata.hpp"
  2. namespace pkpy{
  3. SourceData::SourceData(std::string_view source, const Str& filename, CompileMode mode): filename(filename), mode(mode) {
  4. int index = 0;
  5. // Skip utf8 BOM if there is any.
  6. if (strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) index += 3;
  7. // Drop all '\r'
  8. SStream ss(source.size() + 1);
  9. while(index < source.size()){
  10. if(source[index] != '\r') ss << source[index];
  11. index++;
  12. }
  13. this->source = ss.str();
  14. if(this->source.size>5 && this->source.sv().substr(0, 5)=="pkpy:"){
  15. this->is_precompiled = true;
  16. }else{
  17. this->is_precompiled = false;
  18. }
  19. line_starts.push_back(this->source.c_str());
  20. }
  21. SourceData::SourceData(const Str& filename, CompileMode mode): filename(filename), mode(mode) {
  22. line_starts.push_back(this->source.c_str());
  23. }
  24. std::pair<const char*,const char*> SourceData::_get_line(int lineno) const {
  25. if(is_precompiled || lineno == -1) return {nullptr, nullptr};
  26. lineno -= 1;
  27. if(lineno < 0) lineno = 0;
  28. const char* _start = line_starts[lineno];
  29. const char* i = _start;
  30. // max 300 chars
  31. while(*i != '\n' && *i != '\0' && i-_start < 300) i++;
  32. return {_start, i};
  33. }
  34. std::string_view SourceData::get_line(int lineno) const{
  35. auto [_0, _1] = _get_line(lineno);
  36. if(_0 && _1) return std::string_view(_0, _1-_0);
  37. return "<?>";
  38. }
  39. Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const{
  40. SStream ss;
  41. ss << " " << "File \"" << filename << "\", line " << lineno;
  42. if(!name.empty()) ss << ", in " << name;
  43. if(!is_precompiled){
  44. ss << '\n';
  45. std::pair<const char*,const char*> pair = _get_line(lineno);
  46. Str line = "<?>";
  47. int removed_spaces = 0;
  48. if(pair.first && pair.second){
  49. line = Str(pair.first, pair.second-pair.first).lstrip();
  50. removed_spaces = pair.second - pair.first - line.length();
  51. if(line.empty()) line = "<?>";
  52. }
  53. ss << " " << line;
  54. if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second){
  55. auto column = cursor - pair.first - removed_spaces;
  56. if(column >= 0) ss << "\n " << std::string(column, ' ') << "^";
  57. }
  58. }
  59. return ss.str();
  60. }
  61. } // namespace pkpy