sourcedata.cpp 2.3 KB

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