Skip to content

Commit

Permalink
Chapter 6 up to 'Syntax Errors'
Browse files Browse the repository at this point in the history
  • Loading branch information
Vegard committed May 9, 2023
1 parent a21d836 commit 443f6a6
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 34 deletions.
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub enum Error {
Repl(String),
#[error("[line {0}] Error {1}: {2}")]
SyntaxError(String, String, String),
#[error("Parsing error: {0}")]
ParsingError(String),
#[error("Anyhow: {0}")]
Anyhow(String),
}
Expand Down
12 changes: 8 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use clap::Parser;
use std::{fmt, path::PathBuf};
mod error;
pub use error::Error;
pub mod parser;
pub mod scanner;
use rustyline::error::ReadlineError;
use rustyline::Editor;
Expand Down Expand Up @@ -92,17 +93,20 @@ impl Seid {
fn handle_error(&mut self, e: Error) {
match e {
Error::InputError(_) => {
eprintln!("{:?}", e)
eprintln!("{e:?}")
}
Error::Repl(_) => {
eprintln!("{:?}", e)
eprintln!("{e:?}")
}
Error::SyntaxError(_, _, _) => {
eprintln!("{:?}", e);
eprintln!("{e:?}");
self.had_error = true;
}
Error::Anyhow(_) => {
eprintln!("{:?}", e)
eprintln!("{e:?}")
}
Error::ParsingError(_) => {
eprintln!("{e:?}")
}
}
}
Expand Down
38 changes: 15 additions & 23 deletions src/parser/expr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::fmt;
use crate::Token;
use std::fmt;
/*
Expression grammar:
Expand All @@ -12,24 +12,23 @@ unary → ( "-" | "!" ) unary | primary ;
primary → NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" ;
*/

pub enum Expr {
pub enum Expr<'a> {
Literal(LiteralOp),
Unary(Token, Box<Expr>),
Binary(Box<Expr>, Token, Box<Expr>),
Grouping(Box<Expr>),
Unary(&'a Token, Box<Expr<'a>>),
Binary(Box<Expr<'a>>, &'a Token, Box<Expr<'a>>),
Grouping(Box<Expr<'a>>),
}

impl fmt::Display for Expr {
impl fmt::Display for Expr<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expr::Literal(op) => write!(f, "{}", &op.op_type),
Expr::Unary(t, exp) => {
Expr::Literal(op) => write!(f, "{}", &op),
Expr::Unary(t, exp) => {
if let Ok(s) = std::str::from_utf8(&t.lexeme) {
return write!(f, "( {} {})", s, &*exp);
} else {
return Err(fmt::Error);
}

}
Expr::Binary(exp_lhs, t, exp_rhs) => {
if let Ok(s) = std::str::from_utf8(&t.lexeme) {
Expand All @@ -43,29 +42,22 @@ impl fmt::Display for Expr {
}
}


pub enum LiteralOpType {
pub enum LiteralOp {
Number(f64),
Str(String),
True,
False,
Nil,
}


impl fmt::Display for LiteralOpType {
impl fmt::Display for LiteralOp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LiteralOpType::Number(n) => write!(f, "{}", n),
LiteralOpType::Str(s) => write!(f, "{}", s),
LiteralOpType::True => write!(f, "True"),
LiteralOpType::False => write!(f, "False"),
LiteralOpType::Nil => write!(f, "Nil"),
LiteralOp::Number(n) => write!(f, "{}", n),
LiteralOp::Str(s) => write!(f, "{}", s),
LiteralOp::True => write!(f, "True"),
LiteralOp::False => write!(f, "False"),
LiteralOp::Nil => write!(f, "Nil"),
}
}
}

pub struct LiteralOp {
pub op_type: LiteralOpType,
}

2 changes: 0 additions & 2 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
mod expr;
mod parser;

use expr::*;
168 changes: 164 additions & 4 deletions src/parser/parser.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,175 @@
use crate::{Expr, Token};
use crate::Error;
use crate::{
parser::expr::{Expr, LiteralOp},
Literal, Token, TokenType,
};
use std::sync::atomic::{AtomicUsize, Ordering};

struct Parser {
tokens: Vec<Token>,
current: usize,
current: AtomicUsize,
}

impl Parser {
pub fn new(tokens: Vec<Token>) -> Self {
Parser {
tokens,
current: 0,
current: AtomicUsize::new(0),
}
}
}

fn expression(&self) -> Result<Box<Expr>, Error> {
self.equality()
}

fn equality(&self) -> Result<Box<Expr>, Error> {
let mut expr = self.comparison()?;

while self.find(&[&TokenType::BangEqual, &TokenType::EqualEqual]) {
let operator = self.previous()?;
let right = self.comparison()?;
expr = Box::new(Expr::Binary(expr, operator, right))
}

Ok(expr)
}

fn find(&self, tokens: &[&TokenType]) -> bool {
for ttype in tokens {
if self.check(**ttype) {
self.advance();
return true;
}
}
false
}

fn check(&self, token: TokenType) -> bool {
if self.is_at_end() {
return false;
}
if let Ok(t) = self.peek() {
return t.token_type == token;
}
false
}

fn advance(&self) -> Result<&Token, Error> {
if !self.is_at_end() {
self.current.fetch_add(1, Ordering::AcqRel);
}
self.previous()
}

fn is_at_end(&self) -> bool {
if let Ok(t) = self.peek() {
return t.token_type == TokenType::Eof;
}
false
}

fn peek(&self) -> Result<&Token, Error> {
let current = self.current.load(Ordering::Relaxed);
self.tokens
.get(current)
.ok_or_else(|| Error::ParsingError(format!("Could not get token at idx {}", current)))
}

fn previous(&self) -> Result<&Token, Error> {
let current = self.current.load(Ordering::Relaxed);
self.tokens.get(current - 1).ok_or_else(|| {
Error::ParsingError(format!("Could not get token at idx {}", current - 1))
})
}

fn comparison(&self) -> Result<Box<Expr>, Error> {
let mut expr = self.term()?;

while self.find(&[
&TokenType::Greater,
&TokenType::GreaterEqual,
&TokenType::Less,
&TokenType::LessEqual,
]) {
let operator = self.previous()?;
let right = self.term()?;
expr = Box::new(Expr::Binary(expr, operator, right));
}

Ok(expr)
}

fn term(&self) -> Result<Box<Expr>, Error> {
let mut expr = self.factor()?;

while self.find(&[&TokenType::Minus, &TokenType::Plus]) {
let operator = self.previous()?;
let right = self.factor()?;
expr = Box::new(Expr::Binary(expr, operator, right));
}

Ok(expr)
}

fn factor(&self) -> Result<Box<Expr>, Error> {
let mut expr = self.unary()?;

while self.find(&[&TokenType::Slash, &TokenType::Star]) {
let operator = self.previous().unwrap();
let right = self.unary()?;
expr = Box::new(Expr::Binary(expr, operator, right));
}

Ok(expr)
}

fn unary(&self) -> Result<Box<Expr>, Error> {
while self.find(&[&TokenType::Bang, &TokenType::Minus]) {
let operator = self.previous().unwrap();
let right = self.unary()?;
return Ok(Box::new(Expr::Unary(operator, right)));
}

self.primary()
}

fn primary(&self) -> Result<Box<Expr>, Error> {
if self.find(&[&TokenType::False]) {
return Ok(Box::new(Expr::Literal(LiteralOp::False)));
}
if self.find(&[&TokenType::True]) {
return Ok(Box::new(Expr::Literal(LiteralOp::True)));
}
if self.find(&[&TokenType::Nil]) {
return Ok(Box::new(Expr::Literal(LiteralOp::Nil)));
}

if self.find(&[&TokenType::Number, &TokenType::String]) {
let exp = match &self.previous()?.literal {
Some(Literal::Str(s)) => Ok(Box::new(Expr::Literal(LiteralOp::Str(s.to_string())))),
Some(Literal::Number(f)) => Ok(Box::new(Expr::Literal(LiteralOp::Number(*f)))),
_ => Err(Error::ParsingError(format!(
"Invalid literal at token {}",
self.current.load(Ordering::Relaxed)
))),
};
return exp;
}

if self.find(&[&TokenType::LeftParen]) {
let expr = self.expression()?;
self.consume(TokenType::RightParen)?;
return Ok(Box::new(Expr::Grouping(expr)));
}

Err(Error::SyntaxError(
String::from("TODO"),
String::from("TODO"),
String::from("TODO"),
))
}

fn consume(&self, ttype: TokenType) -> Result<(), Error> {
Ok(())
}
}
2 changes: 1 addition & 1 deletion src/scanner/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Token {
}
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TokenType {
//Single-character tokens.
LeftParen,
Expand Down

0 comments on commit 443f6a6

Please sign in to comment.