use log::debug;
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::io;
use std::result::Result;
#[cfg(feature = "buf_redux")]
use buf_redux::Buffer;
#[cfg(feature = "buf_redux")]
const MAX_CAPACITY: usize = 1024 * 1024 * 1024;
pub trait Input: fmt::Debug {
fn fill_buf(&mut self) -> io::Result<()>; fn eof(&self) -> bool; fn consume(&mut self, amount: usize); fn buffer(&self) -> &[u8];
fn is_empty(&self) -> bool;
fn len(&self) -> usize;
}
impl Input for &[u8] {
#[inline]
fn fill_buf(&mut self) -> io::Result<()> {
Ok(())
}
#[inline]
fn eof(&self) -> bool {
true
}
#[inline]
fn consume(&mut self, amt: usize) {
*self = &self[amt..];
}
#[inline]
fn buffer(&self) -> &[u8] {
self
}
#[inline]
fn is_empty(&self) -> bool {
(*self).is_empty()
}
#[inline]
fn len(&self) -> usize {
(*self).len()
}
}
#[cfg(feature = "buf_redux")]
pub struct InputStream<R> {
inner: R,
buf: Buffer,
eof: bool,
}
#[cfg(feature = "buf_redux")]
impl<R: io::Read> InputStream<R> {
pub fn new(inner: R) -> Self {
Self::with_capacity(inner, 4096)
}
fn with_capacity(inner: R, capacity: usize) -> Self {
let buf = Buffer::with_capacity_ringbuf(capacity);
InputStream {
inner,
buf,
eof: false,
}
}
}
#[cfg(feature = "buf_redux")]
impl<R: io::Read> Input for InputStream<R> {
fn fill_buf(&mut self) -> io::Result<()> {
debug!(target: "scanner", "fill_buf: {}", self.buf.capacity());
if self.buf.free_space() == 0 {
let mut capacity = self.buf.capacity();
if capacity * 2 < MAX_CAPACITY {
capacity *= 2;
self.buf.make_room();
self.buf.reserve(capacity);
} else {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof)); }
} else if self.buf.usable_space() == 0 {
self.buf.make_room();
}
let sz = self.buf.read_from(&mut self.inner)?;
self.eof = sz == 0;
Ok(())
}
#[inline]
fn eof(&self) -> bool {
self.eof
}
#[inline]
fn consume(&mut self, amt: usize) {
self.buf.consume(amt);
}
#[inline]
fn buffer(&self) -> &[u8] {
self.buf.buf()
}
#[inline]
fn is_empty(&self) -> bool {
self.buf.is_empty()
}
#[inline]
fn len(&self) -> usize {
self.buf.len()
}
}
#[cfg(feature = "buf_redux")]
impl<R> fmt::Debug for InputStream<R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InputStream")
.field("input", &self.buf)
.field("eof", &self.eof)
.finish()
}
}
pub trait ScanError: Error + From<io::Error> + Sized {
fn position(&mut self, line: u64, column: usize);
}
type SplitResult<'input, TokenType, Error> =
Result<(Option<(&'input [u8], TokenType)>, usize), Error>;
pub trait Splitter: Sized {
type Error: ScanError;
type TokenType;
fn split<'input>(
&mut self,
data: &'input [u8],
eof: bool,
) -> SplitResult<'input, Self::TokenType, Self::Error>;
}
pub struct Scanner<I: Input, S: Splitter> {
input: I,
splitter: S,
line: u64,
column: usize,
}
impl<I: Input, S: Splitter> Scanner<I, S> {
pub fn new(input: I, splitter: S) -> Scanner<I, S> {
Scanner {
input,
splitter,
line: 1,
column: 1,
}
}
pub fn line(&self) -> u64 {
self.line
}
pub fn column(&self) -> usize {
self.column
}
pub fn splitter(&self) -> &S {
&self.splitter
}
pub fn reset(&mut self, input: I) {
self.input = input;
self.line = 1;
self.column = 1;
}
}
type ScanResult<'input, TokenType, Error> = Result<Option<(&'input [u8], TokenType)>, Error>;
impl<I: Input, S: Splitter> Scanner<I, S> {
pub fn scan(&mut self) -> ScanResult<'_, S::TokenType, S::Error> {
use std::mem;
debug!(target: "scanner", "scan(line: {}, column: {})", self.line, self.column);
loop {
let eof = self.input.eof();
if !self.input.is_empty() || eof {
let data = unsafe { mem::transmute(self.input.buffer()) };
match self.splitter.split(data, eof) {
Err(mut e) => {
e.position(self.line, self.column);
return Err(e);
}
Ok((None, 0)) => {
}
Ok((None, amt)) => {
self.consume(amt);
continue;
}
Ok((tok, amt)) => {
self.consume(amt);
return Ok(tok);
}
}
}
if eof {
return Ok(None);
}
self.input.fill_buf()?;
}
}
fn consume(&mut self, amt: usize) {
debug!(target: "scanner", "comsume({})", amt);
debug_assert!(amt <= self.input.len());
for byte in &self.input.buffer()[..amt] {
if *byte == b'\n' {
self.line += 1;
self.column = 1;
} else {
self.column += 1;
}
}
self.input.consume(amt);
}
}
impl<I: Input, S: Splitter> fmt::Debug for Scanner<I, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Scanner")
.field("input", &self.input)
.field("line", &self.line)
.field("column", &self.column)
.finish()
}
}