87 lines
2.6 KiB
Rust
87 lines
2.6 KiB
Rust
use std::fmt;
|
||
|
||
/// ソースコード位置情報 - エラー報告とデバッグの革命
|
||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||
pub struct Span {
|
||
pub start: usize, // 開始位置(バイトオフセット)
|
||
pub end: usize, // 終了位置(バイトオフセット)
|
||
pub line: usize, // 行番号(1から開始)
|
||
pub column: usize, // 列番号(1から開始)
|
||
}
|
||
|
||
impl Span {
|
||
/// 新しいSpanを作成
|
||
pub fn new(start: usize, end: usize, line: usize, column: usize) -> Self {
|
||
Self {
|
||
start,
|
||
end,
|
||
line,
|
||
column,
|
||
}
|
||
}
|
||
|
||
/// デフォルトのSpan(不明な位置)
|
||
pub fn unknown() -> Self {
|
||
Self {
|
||
start: 0,
|
||
end: 0,
|
||
line: 1,
|
||
column: 1,
|
||
}
|
||
}
|
||
|
||
/// 2つのSpanを結合(開始位置から終了位置まで)
|
||
pub fn merge(&self, other: Span) -> Span {
|
||
Span {
|
||
start: self.start.min(other.start),
|
||
end: self.end.max(other.end),
|
||
line: self.line,
|
||
column: self.column,
|
||
}
|
||
}
|
||
|
||
/// ソースコードから該当箇所を抽出してエラー表示用文字列を生成
|
||
pub fn error_context(&self, source: &str) -> String {
|
||
let lines: Vec<&str> = source.lines().collect();
|
||
if self.line == 0 || self.line > lines.len() {
|
||
return format!("line {}, column {}", self.line, self.column);
|
||
}
|
||
|
||
let line_content = lines[self.line - 1];
|
||
let mut context = String::new();
|
||
|
||
// 行番号とソース行を表示
|
||
context.push_str(&format!(" |\n{:3} | {}\n", self.line, line_content));
|
||
|
||
// カーソル位置を表示(簡易版)
|
||
if self.column > 0 && self.column <= line_content.len() + 1 {
|
||
context.push_str(" | ");
|
||
for _ in 1..self.column {
|
||
context.push(' ');
|
||
}
|
||
let span_length = if self.end > self.start {
|
||
(self.end - self.start).min(line_content.len() - self.column + 1)
|
||
} else {
|
||
1
|
||
};
|
||
for _ in 0..span_length.max(1) {
|
||
context.push('^');
|
||
}
|
||
context.push('\n');
|
||
}
|
||
|
||
context
|
||
}
|
||
|
||
/// 位置情報の文字列表現
|
||
pub fn location_string(&self) -> String {
|
||
format!("line {}, column {}", self.line, self.column)
|
||
}
|
||
}
|
||
|
||
impl fmt::Display for Span {
|
||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
write!(f, "line {}, column {}", self.line, self.column)
|
||
}
|
||
}
|