mirror of
https://github.com/MorizzG/rlox.git
synced 2025-12-06 04:12:42 +00:00
Chapter 7 done
This commit is contained in:
parent
42dbe531ad
commit
f56fcc4a8b
6 changed files with 186 additions and 19 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1 +1 @@
|
||||||
/target
|
/target/
|
||||||
|
|
|
||||||
58
src/error.rs
58
src/error.rs
|
|
@ -1,7 +1,9 @@
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::interpreter::Primitive;
|
||||||
use crate::lexer::Token;
|
use crate::lexer::Token;
|
||||||
use crate::misc::CodePos;
|
use crate::misc::CodePos;
|
||||||
|
use crate::parser::expr::{BinaryOp, UnaryOp};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum LexerError {
|
pub enum LexerError {
|
||||||
|
|
@ -27,31 +29,55 @@ pub enum ParserError {
|
||||||
UnexpectedToken { token: Token },
|
UnexpectedToken { token: Token },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum EvalError {
|
||||||
|
#[error("Unary operator {op} had invalid argument {arg}")]
|
||||||
|
UnaryOpInvalidArgument { op: UnaryOp, arg: Primitive },
|
||||||
|
#[error("Binary operator {op} had invalid arguments {left} and {right}")]
|
||||||
|
BinaryOpInvalidArguments {
|
||||||
|
left: Primitive,
|
||||||
|
op: BinaryOp,
|
||||||
|
right: Primitive,
|
||||||
|
},
|
||||||
|
#[error("Division by zero")]
|
||||||
|
DivisionByZero,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum LoxError {
|
pub enum LoxError {
|
||||||
#[error("{msg}")]
|
#[error("{0}", format_lexer_errors(inner))]
|
||||||
LexerError { msg: String },
|
LexerError { inner: Vec<LexerError> },
|
||||||
#[error("{msg}")]
|
#[error("{inner}")]
|
||||||
ParserError { msg: String },
|
ParserError { inner: ParserError },
|
||||||
|
#[error("{inner}")]
|
||||||
|
EvalError { inner: EvalError },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_lexer_errors(lexer_errs: &Vec<LexerError>) -> String {
|
||||||
|
let msg = if lexer_errs.len() == 1 {
|
||||||
|
format!("{}", lexer_errs[0])
|
||||||
|
} else {
|
||||||
|
let msgs: Vec<String> = lexer_errs.iter().map(|err| format!("{}", err)).collect();
|
||||||
|
msgs.join("\n")
|
||||||
|
};
|
||||||
|
|
||||||
|
msg
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<LexerError>> for LoxError {
|
impl From<Vec<LexerError>> for LoxError {
|
||||||
fn from(lexer_errs: Vec<LexerError>) -> Self {
|
fn from(lexer_errs: Vec<LexerError>) -> Self {
|
||||||
let msg = if lexer_errs.len() == 1 {
|
LoxError::LexerError { inner: lexer_errs }
|
||||||
format!("{}", lexer_errs[0])
|
|
||||||
} else {
|
|
||||||
let msgs: Vec<String> = lexer_errs.iter().map(|err| format!("{}", err)).collect();
|
|
||||||
msgs.join("\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
LoxError::LexerError { msg }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ParserError> for LoxError {
|
impl From<ParserError> for LoxError {
|
||||||
fn from(parser_error: ParserError) -> Self {
|
fn from(parser_err: ParserError) -> Self {
|
||||||
LoxError::ParserError {
|
LoxError::ParserError { inner: parser_err }
|
||||||
msg: format!("{parser_error}"),
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<EvalError> for LoxError {
|
||||||
|
fn from(eval_err: EvalError) -> Self {
|
||||||
|
LoxError::EvalError { inner: eval_err }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
113
src/interpreter/eval.rs
Normal file
113
src/interpreter/eval.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use crate::error::EvalError;
|
||||||
|
use crate::parser::expr::{BinaryOp, Expr, Literal, UnaryOp};
|
||||||
|
|
||||||
|
pub type EvalResult = Result<Primitive, EvalError>;
|
||||||
|
|
||||||
|
/*====================================================================================================================*/
|
||||||
|
|
||||||
|
pub fn evaluate(expr: Expr) -> EvalResult {
|
||||||
|
expr.eval()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*====================================================================================================================*/
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Primitive {
|
||||||
|
String(String),
|
||||||
|
Number(f64),
|
||||||
|
Bool(bool),
|
||||||
|
Nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Primitive {
|
||||||
|
fn is_truthy(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Primitive::Bool(false) | Primitive::Nil => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Primitive {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Primitive::String(s) => write!(f, "\"{s}\""),
|
||||||
|
Primitive::Number(num) => write!(f, "{num}"),
|
||||||
|
Primitive::Bool(b) => write!(f, "{b}"),
|
||||||
|
Primitive::Nil => write!(f, "nil"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*====================================================================================================================*/
|
||||||
|
|
||||||
|
trait Eval {
|
||||||
|
fn eval(self) -> EvalResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eval for Literal {
|
||||||
|
fn eval(self) -> EvalResult {
|
||||||
|
match self {
|
||||||
|
Literal::String(s) => Ok(Primitive::String(s)),
|
||||||
|
Literal::Number(num) => Ok(Primitive::Number(num)),
|
||||||
|
Literal::Bool(b) => Ok(Primitive::Bool(b)),
|
||||||
|
Literal::Nil => Ok(Primitive::Nil),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eval for Expr {
|
||||||
|
fn eval(self) -> EvalResult {
|
||||||
|
match self {
|
||||||
|
Expr::Literal(literal) => literal.eval(),
|
||||||
|
Expr::Unary(op, expr) => {
|
||||||
|
let arg = expr.eval()?;
|
||||||
|
|
||||||
|
match (op, arg) {
|
||||||
|
(UnaryOp::Negate, Primitive::Number(num)) => Ok(Primitive::Number(-num)),
|
||||||
|
(UnaryOp::Not, Primitive::Bool(b)) => Ok(Primitive::Bool(!b)),
|
||||||
|
(UnaryOp::Not, primitive) => Ok(Primitive::Bool(!primitive.is_truthy())),
|
||||||
|
(op, arg) => Err(EvalError::UnaryOpInvalidArgument { op, arg }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Binary(left_expr, op, right_expr) => {
|
||||||
|
use Primitive::{Bool, Number, String};
|
||||||
|
|
||||||
|
let left = left_expr.eval()?;
|
||||||
|
let right = right_expr.eval()?;
|
||||||
|
|
||||||
|
match (left, op, right) {
|
||||||
|
(Number(left), BinaryOp::Add, Number(right)) => Ok(Number(left + right)),
|
||||||
|
(Number(left), BinaryOp::Subtract, Number(right)) => Ok(Number(left - right)),
|
||||||
|
(Number(left), BinaryOp::Multiply, Number(right)) => Ok(Number(left * right)),
|
||||||
|
(Number(left), BinaryOp::Divide, Number(right)) => {
|
||||||
|
if right == 0.0 {
|
||||||
|
return Err(EvalError::DivisionByZero);
|
||||||
|
}
|
||||||
|
Ok(Number(left / right))
|
||||||
|
}
|
||||||
|
|
||||||
|
(String(left), BinaryOp::Add, String(right)) => Ok(String(left + &right)),
|
||||||
|
|
||||||
|
(left, BinaryOp::Equal, right) => Ok(Bool(left == right)),
|
||||||
|
(left, BinaryOp::NotEqual, right) => Ok(Bool(left != right)),
|
||||||
|
|
||||||
|
(Number(left), BinaryOp::Less, Number(right)) => Ok(Bool(left < right)),
|
||||||
|
(Number(left), BinaryOp::LessEqual, Number(right)) => Ok(Bool(left <= right)),
|
||||||
|
(Number(left), BinaryOp::Greater, Number(right)) => Ok(Bool(left > right)),
|
||||||
|
(Number(left), BinaryOp::GreaterEqual, Number(right)) => Ok(Bool(left >= right)),
|
||||||
|
|
||||||
|
(String(left), BinaryOp::Less, String(right)) => Ok(Bool(left < right)),
|
||||||
|
(String(left), BinaryOp::LessEqual, String(right)) => Ok(Bool(left <= right)),
|
||||||
|
(String(left), BinaryOp::Greater, String(right)) => Ok(Bool(left > right)),
|
||||||
|
(String(left), BinaryOp::GreaterEqual, String(right)) => Ok(Bool(left >= right)),
|
||||||
|
|
||||||
|
(left, op, right) => Err(EvalError::BinaryOpInvalidArguments { left, op, right }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Grouping(expr) => expr.eval(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/interpreter/mod.rs
Normal file
5
src/interpreter/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
mod eval;
|
||||||
|
mod run;
|
||||||
|
|
||||||
|
pub use eval::Primitive;
|
||||||
|
pub use run::interpreter_main;
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use crate::error::LoxError;
|
use crate::error::LoxError;
|
||||||
|
use crate::interpreter::eval::evaluate;
|
||||||
use crate::lexer::{scan_tokens, Token};
|
use crate::lexer::{scan_tokens, Token};
|
||||||
use crate::parser::parser::parse_tokens;
|
use crate::parser::parser::parse_tokens;
|
||||||
|
|
||||||
|
|
@ -23,9 +24,17 @@ fn run_file(script_path: &str) {
|
||||||
std::process::exit(66);
|
std::process::exit(66);
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Err(err) = run(&source_code) {
|
/* if let Err(err) = run(&source_code) {
|
||||||
eprintln!("{}", err);
|
eprintln!("{}", err);
|
||||||
std::process::exit(65);
|
std::process::exit(65);
|
||||||
|
} */
|
||||||
|
|
||||||
|
if let Err(err) = run(&source_code) {
|
||||||
|
eprintln!("{err}");
|
||||||
|
match err {
|
||||||
|
LoxError::LexerError { .. } | LoxError::ParserError { .. } => std::process::exit(65),
|
||||||
|
LoxError::EvalError { .. } => std::process::exit(70),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,5 +99,9 @@ fn run(code_string: &str) -> Result<(), LoxError> {
|
||||||
|
|
||||||
println!("{expr}");
|
println!("{expr}");
|
||||||
|
|
||||||
|
let result = evaluate(expr)?;
|
||||||
|
|
||||||
|
println!("{result}");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,11 @@ impl Parser {
|
||||||
pub fn parse(self) -> ParserResult<Expr> {
|
pub fn parse(self) -> ParserResult<Expr> {
|
||||||
let mut me = self;
|
let mut me = self;
|
||||||
|
|
||||||
me.expression()
|
let expr = me.expression()?;
|
||||||
|
|
||||||
|
me.consume_token(TokenType::EOF)?;
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn synchronise(&mut self) {
|
fn synchronise(&mut self) {
|
||||||
|
|
@ -227,6 +231,12 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_token(&mut self) -> ParserResult<Token> {
|
fn next_token(&mut self) -> ParserResult<Token> {
|
||||||
|
// let next = self.token_iter.next();
|
||||||
|
|
||||||
|
// println!("Next token: {next:?}");
|
||||||
|
|
||||||
|
// next.ok_or(ParserError::TokenStreamEnded)
|
||||||
|
|
||||||
self.token_iter.next().ok_or(ParserError::TokenStreamEnded)
|
self.token_iter.next().ok_or(ParserError::TokenStreamEnded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue