diff options
Diffstat (limited to 'src/parse/mod.rs')
| -rw-r--r-- | src/parse/mod.rs | 84 |
1 files changed, 80 insertions, 4 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 102b334..97a6e4a 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -3,6 +3,8 @@ use crate::{BString, PushAll, bstr}; #[cfg(test)] mod test; +mod span; + pub trait Stage: PartialEq { type Str: std::fmt::Debug + Clone + PartialEq; } @@ -908,6 +910,7 @@ impl Parse for ExpString { let mut last_delim = StringDelimiter::None; 'outer: loop { + let begin = b.loc(); let Some(delim) = StringDelimiter::try_begin(b) else { break; }; @@ -1034,6 +1037,14 @@ impl Parse for ExpString { add_char(p, x); } } + + if !delim.is_none() { + let end = b.loc_u32(); + b.highlights.push(Highlight { + span: begin.to(end), + kind: HighlightKind::String, + }); + } } if already_parsed { @@ -1285,6 +1296,18 @@ pub enum ParseMode { Completion, } +#[derive(Copy, Clone)] +pub enum HighlightKind { + Keyword(Keyword), + String, + None, +} + +pub struct Highlight { + pub span: span::Span, + pub kind: HighlightKind, +} + pub struct Cursor<'a> { buf: &'a [u8], mode: ParseMode, @@ -1293,6 +1316,13 @@ pub struct Cursor<'a> { spaced: bool, pub backtrace: bool, + + pub highlights: Vec<Highlight>, + + file: span::FileId, + + buf_start: u64, + buf_len: u32, } #[derive(Default)] @@ -1305,11 +1335,20 @@ struct SpaceStats { impl<'a> Cursor<'a> { pub fn new(buf: &'a [u8], mode: ParseMode) -> Self { + assert!( + buf.len() < u32::MAX as usize, + "cannot support larger parse buffers for now - what are you even doing." + ); + Self { buf, mode, spaced: false, backtrace: false, + highlights: Vec::new(), + file: span::FileId::new(), + buf_start: buf.as_ptr() as u64, + buf_len: buf.len() as u32, } } @@ -1377,6 +1416,18 @@ impl<'a> Cursor<'a> { } } + fn loc_u32(&self) -> u32 { + let now_loc = self.buf.as_ptr() as u64; + assert!(now_loc >= self.buf_start, "not the original buffer"); + let relative_loc = (now_loc - self.buf_start) as u32; + assert!(relative_loc <= self.buf_len, "not the original buffer"); + relative_loc + } + + fn loc(&self) -> span::SpanFrom { + self.file.from(self.loc_u32()) + } + fn spaces_stats(&mut self) -> SpaceStats { let mut stats = SpaceStats::default(); while self.has() && b" \t\n\r".contains(&self.buf[0]) { @@ -1418,7 +1469,8 @@ impl<'a> Cursor<'a> { } self.spaces(); - if self.buf.starts_with(bytes) { + let span = self.loc().with_len(bytes.len() as u32); + let result = if self.buf.starts_with(bytes) { if kw.requires_space() { if self.buf.len() > bytes.len() && self.buf[bytes.len()].is_ascii_whitespace() { self.buf = &self.buf[bytes.len() + 1..]; @@ -1439,11 +1491,20 @@ impl<'a> Cursor<'a> { } } else { Err(ParseError::ExpectedKeyword(kw)) + }; + + if result.is_ok() { + self.highlights.push(Highlight { + span, + kind: HighlightKind::Keyword(kw), + }) } + + result } } -#[derive(Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum Keyword { If, While, @@ -1546,8 +1607,8 @@ impl Parse for While { } } -impl Parse for Ast<PreExpansion> { - fn parse(b: &mut Cursor<'_>) -> Result<Self> { +impl Ast<PreExpansion> { + fn parse_inner(b: &mut Cursor<'_>) -> Result<Self> { b.spaces(); let orig_len = b.buf.len(); @@ -1586,6 +1647,21 @@ impl Parse for Ast<PreExpansion> { } } +impl Parse for Ast<PreExpansion> { + fn parse(b: &mut Cursor<'_>) -> Result<Self> { + let begin = b.loc(); + let result = Ast::parse_inner(b); + let span = begin.to(b.loc_u32()); + if result.is_ok() { + b.highlights.push(Highlight { + span, + kind: HighlightKind::None, + }); + } + result + } +} + impl Parse for Command<PreExpansion> { fn parse(b: &mut Cursor<'_>) -> Result<Self> { let path: ExpString = b.parse()?; |
