added ParseResult
This commit is contained in:
parent
a887bf4b3e
commit
8aeb6e543e
3 changed files with 56 additions and 22 deletions
20
src/error.rs
Normal file
20
src/error.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use std::{error::Error, fmt::Display};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ParseError {
|
||||||
|
message: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParseError {
|
||||||
|
pub fn new(message: impl Into<String>) -> Self {
|
||||||
|
Self { message: message.into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ParseError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "parse error: {}", self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for ParseError {}
|
||||||
|
|
@ -3,6 +3,7 @@ use std::{fs::File, io::Read};
|
||||||
mod token;
|
mod token;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
|
mod error;
|
||||||
use lexer::Lexer;
|
use lexer::Lexer;
|
||||||
mod parser;
|
mod parser;
|
||||||
use parser::Parser;
|
use parser::Parser;
|
||||||
|
|
@ -29,7 +30,7 @@ fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
loop {
|
loop {
|
||||||
let parsed = parser.parse();
|
let parsed = parser.parse().unwrap_or(expr::Expr::EOL);
|
||||||
match parsed {
|
match parsed {
|
||||||
expr::Expr::EOL => break,
|
expr::Expr::EOL => break,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::expr::{Expr, UnaryOp, BinaryOp, infix_bp, prefix_bp};
|
use crate::expr::{Expr, UnaryOp, BinaryOp, infix_bp, prefix_bp};
|
||||||
|
use crate::error::ParseError;
|
||||||
|
|
||||||
|
type ParseResult<T> = Result<T, ParseError>;
|
||||||
|
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
|
|
@ -28,39 +31,49 @@ impl Parser {
|
||||||
tok
|
tok
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_atom(&mut self) -> Expr {
|
fn expect(&mut self, expected: &Token) -> ParseResult<Token> {
|
||||||
match self.next() {
|
match self.next() {
|
||||||
Some(Token::Number(n)) => Expr::Number(n),
|
Some(tok) if &tok == expected => Ok(tok),
|
||||||
Some(Token::Ident(id)) => Expr::Ident(id),
|
other => Err(ParseError::new(format!(
|
||||||
|
"expected {expected:?}, got {other:?}"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_atom(&mut self) -> ParseResult<Expr> {
|
||||||
|
match self.next() {
|
||||||
|
Some(Token::Number(n)) => Ok(Expr::Number(n)),
|
||||||
|
Some(Token::Ident(id)) => Ok(Expr::Ident(id)),
|
||||||
Some(Token::LParen) => {
|
Some(Token::LParen) => {
|
||||||
let expr = self.parse_expr(0);
|
let expr = self.parse_expr(0)?;
|
||||||
|
|
||||||
match self.next() {
|
self.expect(&Token::RParen)?;
|
||||||
Some(Token::RParen) => expr,
|
|
||||||
_ => panic!("expected ')'")
|
Ok(expr)
|
||||||
}
|
|
||||||
},
|
},
|
||||||
tok => panic!("unknown token: {tok:?}")
|
tok => Err(ParseError::new(format!(
|
||||||
|
"unexpected token: {tok:?}"
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_prefix(&mut self) -> Expr {
|
fn parse_prefix(&mut self) -> ParseResult<Expr> {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
Some(Token::Minus) => {
|
Some(Token::Minus) => {
|
||||||
self.advance();
|
self.advance();
|
||||||
let op = UnaryOp::Neg;
|
let op = UnaryOp::Neg;
|
||||||
|
|
||||||
let bp = prefix_bp(&op);
|
let bp = prefix_bp(&op);
|
||||||
let rhs = self.parse_expr(bp);
|
let rhs = self.parse_expr(bp)?;
|
||||||
|
|
||||||
Expr::Unary { op, right: Box::new(rhs) }
|
Ok(Expr::Unary { op, right: Box::new(rhs) })
|
||||||
},
|
},
|
||||||
_ => self.parse_atom()
|
_ => self.parse_atom()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(&mut self, min_bp: u8) -> Expr {
|
fn parse_expr(&mut self, min_bp: u8) -> ParseResult<Expr> {
|
||||||
let mut lhs = self.parse_prefix();
|
let mut lhs = self.parse_prefix()?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let op = match self.peek() {
|
let op = match self.peek() {
|
||||||
|
|
@ -81,16 +94,16 @@ impl Parser {
|
||||||
|
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
||||||
let rhs = self.parse_expr(right_bp);
|
let rhs = self.parse_expr(right_bp)?;
|
||||||
|
|
||||||
lhs = Expr::Binary { left: Box::new(lhs), op, right: Box::new(rhs) }
|
lhs = Expr::Binary { left: Box::new(lhs), op, right: Box::new(rhs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
lhs
|
Ok(lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Expr {
|
pub fn parse(&mut self) -> ParseResult<Expr> {
|
||||||
if self.peek().is_none() {return Expr::EOL}
|
if self.peek().is_none() {return Ok(Expr::EOL)}
|
||||||
self.parse_expr(0)
|
self.parse_expr(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue