rewrite the parser to produce an AST
This commit is contained in:
parent
e69dcdc197
commit
0a185250da
13 changed files with 344 additions and 162 deletions
107
crates/treehouse-format/src/pull.rs
Normal file
107
crates/treehouse-format/src/pull.rs
Normal file
|
@ -0,0 +1,107 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use crate::{ParseError, ParseErrorKind};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BranchKind {
|
||||
/// Expanded by default.
|
||||
Expanded,
|
||||
/// Folded by default.
|
||||
Collapsed,
|
||||
}
|
||||
|
||||
impl BranchKind {
|
||||
pub fn char(&self) -> char {
|
||||
match self {
|
||||
BranchKind::Expanded => '-',
|
||||
BranchKind::Collapsed => '+',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct BranchEvent {
|
||||
pub indent_level: usize,
|
||||
pub attributes: Range<usize>,
|
||||
pub kind: BranchKind,
|
||||
pub kind_span: Range<usize>,
|
||||
pub content: Range<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Parser<'a> {
|
||||
pub input: &'a str,
|
||||
pub position: usize,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn current(&self) -> Option<char> {
|
||||
self.input[self.position..].chars().next()
|
||||
}
|
||||
|
||||
fn advance(&mut self) {
|
||||
self.position += self.current().map(|c| c.len_utf8()).unwrap_or(0);
|
||||
}
|
||||
|
||||
fn eat_as_long_as(&mut self, c: char) -> usize {
|
||||
let mut count = 0;
|
||||
while self.current() == Some(c) {
|
||||
count += 1;
|
||||
self.advance();
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn eat_until(&mut self, c: char) {
|
||||
while self.current() != Some(c) {
|
||||
self.advance();
|
||||
}
|
||||
self.advance();
|
||||
}
|
||||
|
||||
pub fn peek_indent_level(&mut self) -> usize {
|
||||
let position = self.position;
|
||||
let indent_level = self.eat_as_long_as(' ');
|
||||
self.position = position;
|
||||
indent_level
|
||||
}
|
||||
|
||||
pub fn next_branch(&mut self) -> Result<Option<BranchEvent>, ParseError> {
|
||||
if self.current().is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let indent_level = self.eat_as_long_as(' ');
|
||||
|
||||
// TODO: Configs
|
||||
let config_start = self.position;
|
||||
let config_end = self.position;
|
||||
|
||||
let kind_start = self.position;
|
||||
let kind = match self.current() {
|
||||
Some('-') => BranchKind::Expanded,
|
||||
Some('+') => BranchKind::Collapsed,
|
||||
_ => return Err(ParseErrorKind::BranchKindExpected.at(kind_start..kind_start + 1)),
|
||||
};
|
||||
self.advance();
|
||||
let kind_end = self.position;
|
||||
|
||||
let content_start = self.position;
|
||||
loop {
|
||||
self.eat_until('\n');
|
||||
if let Some('\n') | None = self.current() {
|
||||
self.advance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
let content_end = self.position;
|
||||
|
||||
Ok(Some(BranchEvent {
|
||||
indent_level,
|
||||
attributes: config_start..config_end,
|
||||
kind,
|
||||
kind_span: kind_start..kind_end,
|
||||
content: content_start..content_end,
|
||||
}))
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue