use std::rc::{Rc};
use super::{bracket, stmt, parsers, EndOfFile, Location, Token, Stream, Characters, Parse};
fn make_parser<'a>(source: impl 'a + Stream, word_parser: &'a parsers::Word) -> impl 'a + Stream {
let stream = parsers::LEXER.parse_stream(source);
let stream = word_parser.parse_stream(stream);
parsers::brace(stream)
}
fn skip(stream: &mut impl Stream) -> Option<Location> {
loop {
let token = stream.read();
if token.is_incomplete() || token.is::<EndOfFile>() { return None; }
if token == ';' { return Some(token.location()); }
if token.is::<bracket::Brace>() { return Some(token.location()); }
if token.is::<stmt::Stmt>() {
return Some(token.location());
}
}
}
#[derive(Debug)]
pub struct Buffer {
word_parser: parsers::Word,
source: String,
is_complete: bool,
}
impl Default for Buffer {
fn default() -> Self {
Self {word_parser: parsers::word(), source: String::new(), is_complete: false}
}
}
impl Buffer {
pub fn remainder(&self) -> &str { &self.source }
pub fn clear(&mut self) { self.source.clear(); }
pub fn push_str(&mut self, source: &str) {
assert!(!self.is_complete());
self.source.push_str(source);
}
pub fn complete(&mut self) { self.is_complete = true; }
pub fn is_complete(&self) -> bool { self.is_complete }
pub fn try_parse(&mut self) -> Option<(Rc<str>, Token)> {
let (token, end) = {
let source = Characters::new(self.remainder(), self.is_complete);
let mut stream = make_parser(source, &self.word_parser);
let token = stream.read();
if token.is_incomplete() || token.is::<EndOfFile>() { return None; }
let mut end = token.location().end;
if token.result_ref().is_err() { if let Some(loc) = skip(&mut stream) { end = loc.end; } }
(token, end)
};
let s: String = self.source.drain(..std::cmp::min(end, self.source.len())).collect();
Some((s.into(), token))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn check(
source: &'static str,
is_complete: bool,
expected: impl Into<Vec<&'static str>>,
expected_remainder: &'static str,
) {
let mut buffer = Buffer::default();
buffer.push_str(source);
if is_complete { buffer.complete(); }
let mut tokens: Vec<String> = Vec::new();
while let Some((s, token)) = buffer.try_parse() {
let loc = token.location();
let span = String::from(&s[loc.start..loc.end]);
tokens.push(span);
}
assert_eq!(tokens, expected.into());
assert_eq!(buffer.remainder(), expected_remainder);
}
#[test]
fn whitespace() {
check(" ", true, [], " ");
}
#[test]
fn semicolon() {
check(" ; ", true, [";"], " ");
}
#[test]
fn five() {
check(" 5; ", true, ["5;"], " ");
}
#[test]
fn if_() {
check("if b {}", true, ["if b {}"], "");
check("if b {}", false, [], "if b {}");
check("if b {};", false, ["if b {}", ";"], "");
}
#[test]
fn if_else() {
check("if b {} else {}", true, ["if b {} else {}"], "");
check("if b {} else {}", false, ["if b {} else {}"], "");
check("if b {} else {};", false, ["if b {} else {}", ";"], "");
}
#[test]
fn fn_() {
check("fn f() {}\nx; y", true, ["fn f() {}\nx;", "y"], "");
check("fn f() {}\nx; y", false, ["fn f() {}\nx;"], " y");
check("fn f() {};\nx; y", false, ["fn f() {};", "x;"], " y");
}
}