use crate::lexer::{Float, Integer, Lexer, Token};
use crate::{Error, Span};
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::fmt;
use std::usize;
pub fn parse<'a, T: Parse<'a>>(buf: &'a ParseBuffer<'a>) -> Result<T> {
let parser = buf.parser();
let result = parser.parse()?;
if parser.cursor().advance_token().is_none() {
Ok(result)
} else {
Err(parser.error("extra tokens remaining after parse"))
}
}
pub trait Parse<'a>: Sized {
fn parse(parser: Parser<'a>) -> Result<Self>;
}
pub trait Peek {
fn peek(cursor: Cursor<'_>) -> bool;
fn peek2(mut cursor: Cursor<'_>) -> bool {
if cursor.advance_token().is_some() {
Self::peek(cursor)
} else {
false
}
}
fn display() -> &'static str;
}
pub type Result<T> = std::result::Result<T, Error>;
pub struct ParseBuffer<'a> {
tokens: Box<[(Token<'a>, Cell<NextTokenAt>)]>,
input: &'a str,
cur: Cell<usize>,
known_annotations: RefCell<HashMap<String, usize>>,
depth: Cell<usize>,
}
#[derive(Copy, Clone, Debug)]
enum NextTokenAt {
Unknown,
Index(usize),
Eof,
}
#[derive(Copy, Clone)]
pub struct Parser<'a> {
buf: &'a ParseBuffer<'a>,
}
pub struct Lookahead1<'a> {
parser: Parser<'a>,
attempts: Vec<&'static str>,
}
#[derive(Copy, Clone)]
pub struct Cursor<'a> {
parser: Parser<'a>,
cur: usize,
}
impl ParseBuffer<'_> {
pub fn new(input: &str) -> Result<ParseBuffer<'_>> {
let mut tokens = Vec::new();
for token in Lexer::new(input) {
tokens.push((token?, Cell::new(NextTokenAt::Unknown)));
}
let ret = ParseBuffer {
tokens: tokens.into_boxed_slice(),
cur: Cell::new(0),
depth: Cell::new(0),
input,
known_annotations: Default::default(),
};
ret.validate_annotations()?;
Ok(ret)
}
fn parser(&self) -> Parser<'_> {
Parser { buf: self }
}
fn validate_annotations(&self) -> Result<()> {
use crate::lexer::Token::*;
enum State {
None,
LParen,
Annotation { depth: usize, span: Span },
}
let mut state = State::None;
for token in self.tokens.iter() {
state = match (&token.0, state) {
(LParen(_), State::None) => State::LParen,
(_, State::None) => State::None,
(Reserved(s), State::LParen) if s.starts_with("@") && s.len() > 0 => {
let offset = self.input_pos(s);
State::Annotation {
span: Span { offset },
depth: 1,
}
}
(_, State::LParen) => State::None,
(LParen(_), State::Annotation { span, depth }) => State::Annotation {
span,
depth: depth + 1,
},
(RParen(_), State::Annotation { depth: 1, .. }) => State::None,
(RParen(_), State::Annotation { span, depth }) => State::Annotation {
span,
depth: depth - 1,
},
(_, s @ State::Annotation { .. }) => s,
};
}
if let State::Annotation { span, .. } = state {
return Err(Error::new(span, format!("unclosed annotation")));
}
Ok(())
}
fn input_pos(&self, src: &str) -> usize {
src.as_ptr() as usize - self.input.as_ptr() as usize
}
}
impl<'a> Parser<'a> {
pub fn is_empty(self) -> bool {
match self.cursor().advance_token() {
Some(Token::RParen(_)) | None => true,
Some(_) => false, }
}
pub(crate) fn has_meaningful_tokens(self) -> bool {
self.buf.tokens[self.cursor().cur..]
.iter()
.any(|(t, _)| match t {
Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_) => false,
_ => true,
})
}
pub fn parse<T: Parse<'a>>(self) -> Result<T> {
T::parse(self)
}
pub fn peek<T: Peek>(self) -> bool {
T::peek(self.cursor())
}
pub fn peek2<T: Peek>(self) -> bool {
let mut cursor = self.cursor();
if cursor.advance_token().is_some() {
T::peek(cursor)
} else {
false
}
}
pub fn lookahead1(self) -> Lookahead1<'a> {
Lookahead1 {
attempts: Vec::new(),
parser: self,
}
}
pub fn parens<T>(self, f: impl FnOnce(Parser<'a>) -> Result<T>) -> Result<T> {
self.buf.depth.set(self.buf.depth.get() + 1);
let before = self.buf.cur.get();
let res = self.step(|cursor| {
let mut cursor = match cursor.lparen() {
Some(rest) => rest,
None => return Err(cursor.error("expected `(`")),
};
cursor.parser.buf.cur.set(cursor.cur);
let result = f(cursor.parser)?;
cursor.cur = cursor.parser.buf.cur.get();
match cursor.rparen() {
Some(rest) => Ok((result, rest)),
None => Err(cursor.error("expected `)`")),
}
});
self.buf.depth.set(self.buf.depth.get() - 1);
if res.is_err() {
self.buf.cur.set(before);
}
return res;
}
pub fn parens_depth(&self) -> usize {
self.buf.depth.get()
}
fn cursor(self) -> Cursor<'a> {
Cursor {
parser: self,
cur: self.buf.cur.get(),
}
}
pub fn step<F, T>(self, f: F) -> Result<T>
where
F: FnOnce(Cursor<'a>) -> Result<(T, Cursor<'a>)>,
{
let (result, cursor) = f(self.cursor())?;
self.buf.cur.set(cursor.cur);
Ok(result)
}
pub fn error(self, msg: impl fmt::Display) -> Error {
self.error_at(self.cursor().cur_span(), &msg)
}
fn error_at(self, span: Span, msg: &dyn fmt::Display) -> Error {
Error::parse(span, self.buf.input, msg.to_string())
}
pub fn cur_span(&self) -> Span {
self.cursor().cur_span()
}
pub fn prev_span(&self) -> Span {
self.cursor().prev_span().unwrap_or(Span::from_offset(0))
}
pub fn register_annotation<'b>(self, annotation: &'b str) -> impl Drop + 'b
where
'a: 'b,
{
let mut annotations = self.buf.known_annotations.borrow_mut();
if !annotations.contains_key(annotation) {
annotations.insert(annotation.to_string(), 0);
}
*annotations.get_mut(annotation).unwrap() += 1;
return RemoveOnDrop(self, annotation);
struct RemoveOnDrop<'a>(Parser<'a>, &'a str);
impl Drop for RemoveOnDrop<'_> {
fn drop(&mut self) {
let mut annotations = self.0.buf.known_annotations.borrow_mut();
let slot = annotations.get_mut(self.1).unwrap();
*slot -= 1;
}
}
}
}
impl<'a> Cursor<'a> {
pub fn cur_span(&self) -> Span {
let offset = match self.clone().advance_token() {
Some(t) => self.parser.buf.input_pos(t.src()),
None => self.parser.buf.input.len(),
};
Span { offset }
}
pub(crate) fn prev_span(&self) -> Option<Span> {
let (token, _) = self.parser.buf.tokens.get(self.cur.checked_sub(1)?)?;
Some(Span {
offset: self.parser.buf.input_pos(token.src()),
})
}
pub fn error(&self, msg: impl fmt::Display) -> Error {
self.parser.error_at(self.cur_span(), &msg)
}
pub fn lparen(mut self) -> Option<Self> {
match self.advance_token()? {
Token::LParen(_) => Some(self),
_ => None,
}
}
pub fn rparen(mut self) -> Option<Self> {
match self.advance_token()? {
Token::RParen(_) => Some(self),
_ => None,
}
}
pub fn id(mut self) -> Option<(&'a str, Self)> {
match self.advance_token()? {
Token::Id(id) => Some((&id[1..], self)),
_ => None,
}
}
pub fn keyword(mut self) -> Option<(&'a str, Self)> {
match self.advance_token()? {
Token::Keyword(id) => Some((id, self)),
_ => None,
}
}
pub fn reserved(mut self) -> Option<(&'a str, Self)> {
match self.advance_token()? {
Token::Reserved(id) => Some((id, self)),
_ => None,
}
}
pub fn integer(mut self) -> Option<(&'a Integer<'a>, Self)> {
match self.advance_token()? {
Token::Integer(i) => Some((i, self)),
_ => None,
}
}
pub fn float(mut self) -> Option<(&'a Float<'a>, Self)> {
match self.advance_token()? {
Token::Float(f) => Some((f, self)),
_ => None,
}
}
pub fn string(mut self) -> Option<(&'a [u8], Self)> {
match self.advance_token()? {
Token::String(s) => Some((s.val(), self)),
_ => None,
}
}
pub fn annotation(self) -> Option<(&'a str, Self)> {
let (token, cursor) = self.reserved()?;
if !token.starts_with("@") || token.len() <= 1 {
return None;
}
match &self.parser.buf.tokens.get(self.cur.wrapping_sub(1))?.0 {
Token::LParen(_) => Some((&token[1..], cursor)),
_ => None,
}
}
pub fn comment(mut self) -> Option<(&'a str, Self)> {
let comment = loop {
match &self.parser.buf.tokens.get(self.cur)?.0 {
Token::LineComment(c) | Token::BlockComment(c) => {
self.cur += 1;
break c;
}
Token::Whitespace(_) => {
self.cur += 1;
}
_ => return None,
}
};
Some((comment, self))
}
fn advance_token(&mut self) -> Option<&'a Token<'a>> {
let known_annotations = self.parser.buf.known_annotations.borrow();
let is_known_annotation = |name: &str| match known_annotations.get(name) {
Some(0) | None => false,
Some(_) => true,
};
loop {
let (token, next) = self.parser.buf.tokens.get(self.cur)?;
match token {
Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_) => {}
_ => match self.annotation_start() {
Some(n) if !is_known_annotation(n) => {}
_ => {
self.cur += 1;
return Some(token);
}
},
}
match next.get() {
NextTokenAt::Unknown => match self.find_next() {
Some(i) => {
next.set(NextTokenAt::Index(i));
self.cur = i;
}
None => {
next.set(NextTokenAt::Eof);
return None;
}
},
NextTokenAt::Eof => return None,
NextTokenAt::Index(i) => self.cur = i,
}
}
}
fn annotation_start(&self) -> Option<&'a str> {
match self.parser.buf.tokens.get(self.cur).map(|p| &p.0) {
Some(Token::LParen(_)) => {}
_ => return None,
}
let reserved = match self.parser.buf.tokens.get(self.cur + 1).map(|p| &p.0) {
Some(Token::Reserved(n)) => n,
_ => return None,
};
if reserved.starts_with("@") && reserved.len() > 1 {
Some(&reserved[1..])
} else {
None
}
}
fn find_next(mut self) -> Option<usize> {
if self.annotation_start().is_some() {
let mut depth = 1;
self.cur += 1;
while depth > 0 {
match &self.parser.buf.tokens.get(self.cur)?.0 {
Token::LParen(_) => depth += 1,
Token::RParen(_) => depth -= 1,
_ => {}
}
self.cur += 1;
}
return Some(self.cur);
}
loop {
let (token, _) = self.parser.buf.tokens.get(self.cur)?;
match token {
Token::Whitespace(_) | Token::LineComment(_) | Token::BlockComment(_) => {
self.cur += 1
}
_ => return Some(self.cur),
}
}
}
}
impl Lookahead1<'_> {
pub fn peek<T: Peek>(&mut self) -> bool {
if self.parser.peek::<T>() {
true
} else {
self.attempts.push(T::display());
false
}
}
pub fn error(self) -> Error {
match self.attempts.len() {
0 => {
if self.parser.is_empty() {
self.parser.error("unexpected end of input")
} else {
self.parser.error("unexpected token")
}
}
1 => {
let message = format!("unexpected token, expected {}", self.attempts[0]);
self.parser.error(&message)
}
2 => {
let message = format!(
"unexpected token, expected {} or {}",
self.attempts[0], self.attempts[1]
);
self.parser.error(&message)
}
_ => {
let join = self.attempts.join(", ");
let message = format!("unexpected token, expected one of: {}", join);
self.parser.error(&message)
}
}
}
}
impl<'a, T: Peek + Parse<'a>> Parse<'a> for Option<T> {
fn parse(parser: Parser<'a>) -> Result<Option<T>> {
if parser.peek::<T>() {
Ok(Some(parser.parse()?))
} else {
Ok(None)
}
}
}