rewrite source reference to use raw offsets
This commit is contained in:
parent
fa736f2dd4
commit
10ea99e95c
@ -30,7 +30,7 @@ peg::parser! {
|
||||
stmt:statement() delimiter()+ { stmt }
|
||||
|
||||
rule statement() -> Statement =
|
||||
kind:statement_kind() { Statement { id: Default::default(), location: Default::default(), kind } }
|
||||
pos:position!() kind:statement_kind() { Statement { id: Default::default(), location: pos.into(), kind } }
|
||||
|
||||
rule statement_kind() -> StatementKind =
|
||||
__ import:import() { StatementKind::Import(import) } /
|
||||
@ -382,9 +382,9 @@ peg::parser! {
|
||||
rule condition_guard() -> Option<Expression> =
|
||||
("if" _ expr:expression() { expr } )?
|
||||
|
||||
rule expr_or_block() -> Block = block() / ex:expression() {
|
||||
rule expr_or_block() -> Block = block() / pos:position!() ex:expression() {
|
||||
Statement {
|
||||
id: Default::default(), location: Default::default(),
|
||||
id: Default::default(), location: pos.into(),
|
||||
kind: StatementKind::Expression(ex)
|
||||
}.into()
|
||||
}
|
||||
|
@ -122,24 +122,39 @@ impl<'a> Schala<'a> {
|
||||
|
||||
/// Represents lines of source code
|
||||
pub(crate) struct SourceReference {
|
||||
lines: Option<Vec<String>>,
|
||||
last_source: Option<String>,
|
||||
/// Offsets in *bytes* (not chars) representing a newline character
|
||||
newline_offsets: Vec<usize>,
|
||||
}
|
||||
|
||||
impl SourceReference {
|
||||
fn new() -> SourceReference {
|
||||
SourceReference { lines: None }
|
||||
SourceReference { last_source: None, newline_offsets: vec![]}
|
||||
}
|
||||
|
||||
fn load_new_source(&mut self, source: &str) {
|
||||
//TODO this is a lot of heap allocations - maybe there's a way to make it more efficient?
|
||||
self.lines = Some(source.lines().map(|s| s.to_string()).collect());
|
||||
|
||||
for (offset, ch) in source.as_bytes().iter().enumerate() {
|
||||
if *ch == ('\n' as u8) {
|
||||
self.newline_offsets.push(offset);
|
||||
}
|
||||
}
|
||||
self.last_source = Some(source.to_string());
|
||||
}
|
||||
|
||||
pub fn get_line(&self, line: usize) -> String {
|
||||
self.lines
|
||||
.as_ref()
|
||||
.and_then(|x| x.get(line).map(|s| s.to_string()))
|
||||
.unwrap_or_else(|| "NO LINE FOUND".to_string())
|
||||
//TODO make sure this is utf8-safe
|
||||
let start_idx = match self.newline_offsets.binary_search(&line) {
|
||||
Ok(index) | Err(index) => index,
|
||||
};
|
||||
|
||||
let last_source = self.last_source.as_ref().unwrap();
|
||||
|
||||
let start = self.newline_offsets[start_idx];
|
||||
let end = self.newline_offsets.get(start_idx + 1).cloned().unwrap_or_else(|| last_source.len());
|
||||
|
||||
let slice = &last_source.as_bytes()[start..end];
|
||||
std::str::from_utf8(slice).unwrap().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,12 @@ pub struct Location {
|
||||
pub(crate) offset: usize,
|
||||
}
|
||||
|
||||
impl From<usize> for Location {
|
||||
fn from(offset: usize) -> Self {
|
||||
Self { offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Location {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.offset)
|
||||
|
Loading…
Reference in New Issue
Block a user