core.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  2. pub struct FileRef {
  3. pub idx: usize,
  4. }
  5. /// A location in a source file
  6. #[derive(Debug, Clone, Copy)]
  7. pub struct Span {
  8. pub start: u32,
  9. pub end: u32,
  10. }
  11. #[derive(Debug, Clone, Copy)]
  12. pub struct Loc {
  13. pub span: Span,
  14. pub file: FileRef,
  15. }
  16. #[derive(Debug)]
  17. pub enum FileSource {
  18. File(String),
  19. Repl(u32),
  20. }
  21. pub struct File {
  22. pub source: FileSource,
  23. pub content: String,
  24. }
  25. pub struct FileTable {
  26. files: Vec<File>,
  27. last_repl_line: u32,
  28. }
  29. impl FileTable {
  30. pub fn new() -> FileTable {
  31. FileTable {
  32. files: Vec::new(),
  33. last_repl_line: 0,
  34. }
  35. }
  36. pub fn add_file(&mut self, path: String, content: String) -> FileRef {
  37. self.add_file_from_source(FileSource::File(path), content)
  38. }
  39. pub fn add_repl_line(&mut self, content: String) -> FileRef {
  40. let source = FileSource::Repl(self.last_repl_line);
  41. self.last_repl_line += 1;
  42. self.add_file_from_source(source, content)
  43. }
  44. fn add_file_from_source(&mut self, source: FileSource, content: String) -> FileRef {
  45. let idx = self.files.len();
  46. self.files.push(File { source, content });
  47. FileRef { idx }
  48. }
  49. pub fn get_line(&self, loc: Loc) -> String {
  50. if !loc.span.exists() {
  51. return String::new();
  52. }
  53. let mut line_number = 1;
  54. let mut start_of_line = 0;
  55. let mut end_of_line = None;
  56. let file = &self.files[loc.file.idx];
  57. let span = loc.span;
  58. let src = &file.content;
  59. for (i, ch) in src.char_indices() {
  60. if ch == '\n' {
  61. if i < span.start as usize {
  62. line_number += 1;
  63. start_of_line = i + 1;
  64. }
  65. if i >= span.end as usize && end_of_line.is_none() {
  66. end_of_line = Some(i);
  67. }
  68. }
  69. }
  70. let end_of_line = end_of_line.unwrap_or(src.len());
  71. if let FileSource::Repl(offset) = file.source {
  72. line_number += offset;
  73. }
  74. let mut result = format!("{:3} |", line_number);
  75. result.push_str(&src[start_of_line..end_of_line]);
  76. result.push_str("\n ");
  77. for _ in start_of_line..(span.start as usize) {
  78. result.push(' ');
  79. }
  80. for _ in span.start..span.end {
  81. result.push('^');
  82. }
  83. result
  84. }
  85. }
  86. impl Span {
  87. pub fn empty() -> Span {
  88. Span {
  89. start: u32::MAX,
  90. end: u32::MAX,
  91. }
  92. }
  93. pub fn exists(&self) -> bool {
  94. self.start != u32::MAX && self.end != u32::MAX
  95. }
  96. }