use crate::ast::*;
use crate::lexer::Keyword;
use crate::lexer::Position;
use crate::lexer::{Token, TokenKind};
use crate::parser::infer::infer;
use crate::util::string_util::highlight_position_in_file;
use std::convert::TryFrom;
use std::iter::Peekable;
use std::vec::IntoIter;
pub struct Parser {
pub path: String,
tokens: Peekable<IntoIter<Token>>,
peeked: Vec<Token>,
current: Option<Token>,
prev: Option<Token>,
raw: Option<String>,
}
impl Parser {
#[allow(clippy::needless_collect)] pub fn new(tokens: Vec<Token>, raw: Option<String>, file_name: String) -> Parser {
let tokens_without_whitespace: Vec<Token> = tokens
.into_iter()
.filter(|token| token.kind != TokenKind::Whitespace && token.kind != TokenKind::Comment)
.collect();
Parser {
path: file_name,
tokens: tokens_without_whitespace.into_iter().peekable(),
peeked: vec![],
current: None,
prev: None,
raw,
}
}
pub fn parse(&mut self) -> Result<Module, String> {
let mut program = self.parse_module()?;
infer(&mut program);
Ok(program)
}
pub(super) fn next(&mut self) -> Result<Token, String> {
self.prev = self.current.to_owned();
let item = if self.peeked.is_empty() {
self.tokens.next()
} else {
self.peeked.pop()
};
self.current = item.to_owned();
item.ok_or_else(|| "Expected token".into())
}
pub(super) fn peek(&mut self) -> Result<Token, String> {
let token = self.next()?;
self.push(token.to_owned());
Ok(token)
}
pub(super) fn push(&mut self, token: Token) {
self.peeked.push(token);
}
pub(super) fn has_more(&mut self) -> bool {
!self.peeked.is_empty() || self.tokens.peek().is_some()
}
pub(super) fn match_token(&mut self, token_kind: TokenKind) -> Result<Token, String> {
match self.next()? {
token if token.kind == token_kind => Ok(token),
other => Err(self.make_error(token_kind, other)),
}
}
pub(super) fn peek_token(&mut self, token_kind: TokenKind) -> Result<Token, String> {
match self.peek()? {
token if token.kind == token_kind => Ok(token),
other => Err(self.make_error(token_kind, other)),
}
}
pub(super) fn match_keyword(&mut self, keyword: Keyword) -> Result<(), String> {
let token = self.next()?;
match &token.kind {
TokenKind::Keyword(ref k) if k == &keyword => Ok(()),
_ => Err(self.make_error(TokenKind::SemiColon, token)),
}
}
pub(super) fn match_operator(&mut self) -> Result<BinOp, String> {
BinOp::try_from(self.next()?.kind)
}
pub(super) fn match_identifier(&mut self) -> Result<String, String> {
let token = self.next()?;
match &token.kind {
TokenKind::Identifier(n) => Ok(n.to_string()),
other => {
Err(self
.make_error_msg(token.pos, format!("Expected Identifier, found {:?}", other)))
}
}
}
pub(super) fn make_error(&mut self, token_kind: TokenKind, other: Token) -> String {
self.make_error_msg(
other.pos,
format!("Token {:?} not found, found {:?}", token_kind, other),
)
}
pub(super) fn make_error_msg(&mut self, pos: Position, msg: String) -> String {
match &self.raw {
Some(raw_file) => format!(
"{}:{}: {}\n{}",
pos.line,
pos.offset,
msg,
highlight_position_in_file(raw_file.to_string(), pos)
),
None => format!("{}:{}: {}", pos.line, pos.offset, msg),
}
}
pub(super) fn prev(&mut self) -> Option<Token> {
self.prev.clone()
}
}