chapter 8 done

This commit is contained in:
Moritz Gmeiner 2023-01-22 23:33:57 +01:00
commit 956c4d0f28
13 changed files with 570 additions and 177 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target/
test.lox

View file

@ -1,9 +1,9 @@
use thiserror::Error;
use crate::interpreter::Primitive;
use crate::interpreter::Value;
use crate::lexer::Token;
use crate::misc::CodePos;
use crate::parser::expr::{BinaryOp, UnaryOp};
use crate::parser::{BinaryOp, Expr, UnaryOp};
#[derive(Error, Debug)]
pub enum LexerError {
@ -25,39 +25,47 @@ pub enum LexerError {
pub enum ParserError {
#[error("Token stream ended unexpectedly.")]
TokenStreamEnded,
#[error("Unexpected token {token} at {0}.", token.code_pos())]
#[error("Unexpected token {token} at {0}.", token.code_pos)]
UnexpectedToken { token: Token },
#[error("Missing semicolon at {code_pos}")]
MissingSemicolon { code_pos: CodePos },
#[error("Expected variable name at {0}, got {token} instead", token.code_pos)]
ExpectedVarName { token: Token },
#[error("Can't assign to {expr} at {code_pos}")]
InvalidAssignment { expr: Expr, code_pos: CodePos },
#[error("Missing closing curly brace at {code_pos}")]
MissingRightBrace { code_pos: CodePos },
#[error("Missing closing parenthesis at {code_pos}")]
MissingRightParenthesis { code_pos: CodePos },
}
#[derive(Error, Debug)]
pub enum EvalError {
pub enum RuntimeError {
#[error("Unary operator {op} had invalid argument {arg}")]
UnaryOpInvalidArgument { op: UnaryOp, arg: Primitive },
UnaryOpInvalidArgument { op: UnaryOp, arg: Value },
#[error("Binary operator {op} had invalid arguments {left} and {right}")]
BinaryOpInvalidArguments {
left: Primitive,
op: BinaryOp,
right: Primitive,
},
BinaryOpInvalidArguments { left: Value, op: BinaryOp, right: Value },
#[error("Division by zero")]
DivisionByZero,
#[error("Name {name} is not defined")]
NameNotDefined { name: String },
}
#[derive(Error, Debug)]
pub enum LoxError {
#[error("{0}", format_lexer_errors(inner))]
#[error("{0}", format_errors(inner))]
LexerError { inner: Vec<LexerError> },
#[error("{0}", format_errors(inner))]
ParserError { inner: Vec<ParserError> },
#[error("{inner}")]
ParserError { inner: ParserError },
#[error("{inner}")]
EvalError { inner: EvalError },
EvalError { inner: RuntimeError },
}
fn format_lexer_errors(lexer_errs: &Vec<LexerError>) -> String {
let msg = if lexer_errs.len() == 1 {
format!("{}", lexer_errs[0])
fn format_errors(errs: &Vec<impl std::error::Error>) -> String {
let msg = if errs.len() == 1 {
format!("{}", errs[0])
} else {
let msgs: Vec<String> = lexer_errs.iter().map(|err| format!("{}", err)).collect();
let msgs: Vec<String> = errs.iter().map(|err| format!("{}", err)).collect();
msgs.join("\n")
};
@ -70,14 +78,14 @@ impl From<Vec<LexerError>> for LoxError {
}
}
impl From<ParserError> for LoxError {
fn from(parser_err: ParserError) -> Self {
LoxError::ParserError { inner: parser_err }
impl From<Vec<ParserError>> for LoxError {
fn from(parser_errs: Vec<ParserError>) -> Self {
LoxError::ParserError { inner: parser_errs }
}
}
impl From<EvalError> for LoxError {
fn from(eval_err: EvalError) -> Self {
impl From<RuntimeError> for LoxError {
fn from(eval_err: RuntimeError) -> Self {
LoxError::EvalError { inner: eval_err }
}
}

View file

@ -0,0 +1,67 @@
use std::collections::HashMap;
use crate::error::RuntimeError;
use super::Value;
type Scope = HashMap<String, Value>;
pub struct Environment {
globals: HashMap<String, Value>,
scopes: Vec<Scope>,
}
impl Environment {
pub fn new() -> Self {
Environment {
globals: HashMap::new(),
scopes: Vec::new(),
}
}
pub fn get(&self, name: &str) -> Result<&Value, RuntimeError> {
for scope in self.scopes.iter().rev() {
if let Some(value) = scope.get(name) {
return Ok(value);
}
}
self.globals
.get(name)
.ok_or(RuntimeError::NameNotDefined { name: name.to_owned() })
}
pub fn define(&mut self, name: String, value: Value) {
if let Some(scope) = self.scopes.last_mut() {
scope.insert(name, value);
} else {
self.globals.insert(name, value);
}
}
pub fn assign(&mut self, name: &str, value: Value) -> Result<(), RuntimeError> {
for scope in self.scopes.iter_mut().rev() {
if let Some(var) = scope.get_mut(name) {
*var = value;
return Ok(());
}
}
if let Some(var) = self.globals.get_mut(name) {
*var = value;
Ok(())
} else {
let name = name.to_owned();
Err(RuntimeError::NameNotDefined { name })
}
}
pub fn enter_scope(&mut self) {
self.scopes.push(Scope::new());
}
pub fn exit_scope(&mut self) {
self.scopes.pop().expect("Tried to exit scope, but no scope to exit");
}
}

View file

@ -1,82 +1,84 @@
use std::fmt::Display;
use crate::error::EvalError;
use crate::parser::expr::{BinaryOp, Expr, Literal, UnaryOp};
use crate::error::RuntimeError;
use crate::parser::{BinaryOp, Expr, Literal, Stmt, UnaryOp};
pub type EvalResult = Result<Primitive, EvalError>;
use super::environment::Environment;
pub type EvalResult<T> = Result<T, RuntimeError>;
/*====================================================================================================================*/
pub fn evaluate(expr: Expr) -> EvalResult {
expr.eval()
pub fn execute(statement: Stmt, env: &mut Environment) -> Result<(), RuntimeError> {
statement.eval(env)
}
/*====================================================================================================================*/
#[derive(Debug, PartialEq)]
pub enum Primitive {
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
String(String),
Number(f64),
Bool(bool),
Nil,
}
impl Primitive {
impl Value {
fn is_truthy(&self) -> bool {
match self {
Primitive::Bool(false) | Primitive::Nil => false,
Value::Bool(false) | Value::Nil => false,
_ => true,
}
}
}
impl Display for Primitive {
impl Display for Value {
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"),
Value::String(s) => write!(f, "\"{s}\""),
Value::Number(num) => write!(f, "{num}"),
Value::Bool(b) => write!(f, "{b}"),
Value::Nil => write!(f, "nil"),
}
}
}
/*====================================================================================================================*/
trait Eval {
fn eval(self) -> EvalResult;
}
/* trait Eval {
fn eval(self, env: &mut Environment) -> EvalResult;
} */
impl Eval for Literal {
fn eval(self) -> EvalResult {
impl Literal {
fn eval(self, _env: &mut Environment) -> EvalResult<Value> {
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),
Literal::String(s) => Ok(Value::String(s)),
Literal::Number(num) => Ok(Value::Number(num)),
Literal::Bool(b) => Ok(Value::Bool(b)),
Literal::Nil => Ok(Value::Nil),
}
}
}
impl Eval for Expr {
fn eval(self) -> EvalResult {
impl Expr {
fn eval(self, env: &mut Environment) -> EvalResult<Value> {
match self {
Expr::Literal(literal) => literal.eval(),
Expr::Unary(op, expr) => {
let arg = expr.eval()?;
Expr::Literal { literal } => literal.eval(env),
Expr::Unary { op, expr } => {
let arg = expr.eval(env)?;
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 }),
(UnaryOp::Negate, Value::Number(num)) => Ok(Value::Number(-num)),
(UnaryOp::Not, Value::Bool(b)) => Ok(Value::Bool(!b)),
(UnaryOp::Not, primitive) => Ok(Value::Bool(!primitive.is_truthy())),
(op, arg) => Err(RuntimeError::UnaryOpInvalidArgument { op, arg }),
}
}
Expr::Binary(left_expr, op, right_expr) => {
use Primitive::{Bool, Number, String};
Expr::Binary { left, op, right } => {
use Value::{Bool, Number, String};
let left = left_expr.eval()?;
let right = right_expr.eval()?;
let left = left.eval(env)?;
let right = right.eval(env)?;
match (left, op, right) {
(Number(left), BinaryOp::Add, Number(right)) => Ok(Number(left + right)),
@ -84,7 +86,7 @@ impl Eval for Expr {
(Number(left), BinaryOp::Multiply, Number(right)) => Ok(Number(left * right)),
(Number(left), BinaryOp::Divide, Number(right)) => {
if right == 0.0 {
return Err(EvalError::DivisionByZero);
return Err(RuntimeError::DivisionByZero);
}
Ok(Number(left / right))
}
@ -104,10 +106,52 @@ impl Eval for Expr {
(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 }),
(left, op, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }),
}
}
Expr::Grouping(expr) => expr.eval(),
Expr::Grouping { expr } => expr.eval(env),
Expr::Variable { name } => env.get(&name).cloned(),
Expr::Assignment { name, value } => {
let value = value.eval(env)?;
env.assign(&name, value.clone())?;
Ok(value)
}
}
}
}
impl Stmt {
fn eval(self, env: &mut Environment) -> EvalResult<()> {
match self {
Stmt::ExprStmt { expr } => {
// expr.eval(env)?;
// Ok(Value::Nil)
expr.eval(env)?;
Ok(())
}
Stmt::Print { expr } => {
match expr.eval(env)? {
// special case: when printing a string, drop the surrounding ""
Value::String(s) => println!("{s}"),
val => println!("{val}"),
}
Ok(())
}
Stmt::VarDecl { name, initializer } => {
let initializer = initializer.eval(env)?;
env.define(name, initializer);
Ok(())
}
Stmt::Block { statements } => {
env.enter_scope();
for statement in statements {
// on error the current frame gets destroyed anyways, so no need to exit scope
statement.eval(env)?;
}
env.exit_scope();
Ok(())
}
}
}
}

View file

@ -1,5 +1,6 @@
mod environment;
mod eval;
mod run;
pub use eval::Primitive;
pub use eval::Value;
pub use run::interpreter_main;

View file

@ -1,9 +1,12 @@
use std::io::Write;
use crate::error::LoxError;
use crate::interpreter::eval::evaluate;
use crate::interpreter::eval::execute;
use crate::interpreter::Value;
use crate::lexer::{scan_tokens, Token};
use crate::parser::parser::parse_tokens;
use crate::parser::parse_tokens;
use super::environment::Environment;
pub fn interpreter_main() {
let args: Vec<String> = std::env::args().collect();
@ -29,7 +32,9 @@ fn run_file(script_path: &str) {
std::process::exit(65);
} */
if let Err(err) = run(&source_code) {
let mut env = Environment::new();
if let Err(err) = run(&source_code, &mut env) {
eprintln!("{err}");
match err {
LoxError::LexerError { .. } | LoxError::ParserError { .. } => std::process::exit(65),
@ -41,6 +46,8 @@ fn run_file(script_path: &str) {
fn run_repl() {
let stdin = std::io::stdin();
let mut env = Environment::new();
'outer: loop {
let mut input_buf = String::new();
@ -53,7 +60,7 @@ fn run_repl() {
std::process::exit(66);
});
let num_open_braces = (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64);
/* let num_open_braces = (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64);
let num_open_parens = (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64);
let num_open_brackets = (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64);
@ -65,7 +72,9 @@ fn run_repl() {
// any braces/parens/brackets more closing than opening => break (will be parse error)
if num_open_braces < 0 || num_open_parens < 0 || num_open_brackets < 0 {
break 'inner;
}
} */
break 'inner;
print!("< ");
std::io::stdout().flush().unwrap();
@ -77,14 +86,14 @@ fn run_repl() {
break 'outer;
}
match run(&input_buf) {
match run(&input_buf, &mut env) {
Ok(()) => {}
Err(err) => eprintln!("{}", err),
}
}
}
fn run(code_string: &str) -> Result<(), LoxError> {
fn run(code_string: &str, env: &mut Environment) -> Result<(), LoxError> {
let tokens: Vec<Token> = scan_tokens(code_string)?;
/* let token_str = tokens
@ -95,13 +104,20 @@ fn run(code_string: &str) -> Result<(), LoxError> {
println!("{token_str}"); */
let expr = parse_tokens(tokens)?;
let statements = parse_tokens(tokens)?;
println!("{expr}");
// println!("{expr}");
let result = evaluate(expr)?;
// let mut result = Value::Nil;
println!("{result}");
for statement in statements {
execute(statement, env)?;
}
/* match result {
Value::Nil => {}
result => println!("{result}"),
} */
Ok(())
}

View file

@ -71,7 +71,7 @@ impl Lexer {
me.scan_token();
}
me.tokens.push(Token::new(TokenType::EOF, "".to_owned(), me.code_pos));
me.tokens.push(Token::new(TokenType::EOF, me.code_pos));
if me.errors.is_empty() {
Ok(me.tokens)
@ -234,7 +234,7 @@ impl Lexer {
fn push_token(&mut self, token_type: TokenType) {
let lexeme: String = self.source[self.start..self.current].iter().collect();
self.tokens.push(Token::new(token_type, lexeme, self.code_pos));
self.tokens.push(Token::new(token_type, self.code_pos));
}
fn try_parse_string(&mut self) -> Option<TokenType> {

View file

@ -27,33 +27,25 @@ pub enum TokenType {
}
pub struct Token {
token_type: TokenType,
lexeme: String,
code_pos: CodePos,
pub token_type: TokenType,
// pub lexeme: String,
pub code_pos: CodePos,
}
impl Token {
pub fn new(token_type: TokenType, lexeme: String, pos: CodePos) -> Self {
pub fn new(token_type: TokenType, pos: CodePos) -> Self {
Token {
token_type,
lexeme: lexeme,
// lexeme,
code_pos: pos,
}
}
pub fn token_type(&self) -> &TokenType {
&self.token_type
}
pub fn code_pos(&self) -> CodePos {
self.code_pos
}
}
impl std::fmt::Debug for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<{:?}> (\"{}\")", self.token_type, self.lexeme)
write!(f, "<{:?}>", self.token_type)
// write!(f, "<{:?}> (\"{}\")", self.token_type, self.lexeme)
}
}

View file

@ -1,8 +1,18 @@
expression -> equality
program -> statement* EOF ;
statement -> exprStmt | printStmt | declaration | block ;
exprStmt -> expression ";" ;
printStmt -> "print" expression ";" ;
declaration -> "var" IDENTIFIER ( "=" expression )? ";" ;
block -> "{" statement* "}" ;
expression -> assignment
assignment -> IDENTIFIER "=" assignment | equality ;
equality -> comparison ( ( "==" | "!=" ) comparison )* ;
comparison -> term ( ">" | ">=" | "<" | "<=" term )* ;
term -> factor ( ( "+" | "-" ) factor )*
factor -> unary ( ( "*" | "/" ) unary )* ;
unary -> ( "!" | "-" ) unary | primary ;
primary -> "(" expression ")" | NUMBER | STRING | "true" | "false" | "nil" ;
primary -> "(" expression ")" | IDENTIFIER | NUMBER | STRING | "true" | "false" | "nil" ;

View file

@ -2,49 +2,84 @@ use std::fmt::Display;
#[derive(Debug)]
pub enum Expr {
Literal(Literal),
Unary(UnaryOp, Box<Expr>),
Binary(Box<Expr>, BinaryOp, Box<Expr>),
Grouping(Box<Expr>),
Literal {
literal: Literal,
},
Unary {
op: UnaryOp,
expr: Box<Expr>,
},
Binary {
left: Box<Expr>,
op: BinaryOp,
right: Box<Expr>,
},
Grouping {
expr: Box<Expr>,
},
Variable {
name: String,
},
Assignment {
name: String,
value: Box<Expr>,
},
}
impl Expr {
pub fn new_string(s: String) -> Self {
Expr::Literal(Literal::String(s))
pub fn string(s: String) -> Self {
Expr::Literal {
literal: Literal::String(s),
}
}
pub fn new_number(num: f64) -> Self {
Expr::Literal(Literal::Number(num))
pub fn number(num: f64) -> Self {
Expr::Literal {
literal: Literal::Number(num),
}
}
pub fn new_bool(b: bool) -> Self {
Expr::Literal(Literal::Bool(b))
pub fn bool(b: bool) -> Self {
Expr::Literal {
literal: Literal::Bool(b),
}
}
pub fn new_nil() -> Self {
Expr::Literal(Literal::Nil)
pub fn nil() -> Self {
Expr::Literal { literal: Literal::Nil }
}
pub fn new_unary(operator: UnaryOp, expr: Expr) -> Self {
Expr::Unary(operator, Box::new(expr))
pub fn unary(op: UnaryOp, expr: Expr) -> Self {
let expr = Box::new(expr);
Expr::Unary { op, expr }
}
pub fn new_binary(left: Expr, operator: BinaryOp, right: Expr) -> Self {
Expr::Binary(Box::new(left), operator, Box::new(right))
pub fn binary(left: Expr, op: BinaryOp, right: Expr) -> Self {
let left = Box::new(left);
let right = Box::new(right);
Expr::Binary { left, op, right }
}
pub fn new_grouping(expr: Expr) -> Self {
Expr::Grouping(Box::new(expr))
pub fn grouping(expr: Expr) -> Self {
let expr = Box::new(expr);
Expr::Grouping { expr }
}
pub fn assignment(name: String, value: Expr) -> Self {
let value = Box::new(value);
Expr::Assignment { name, value }
}
}
impl Display for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Literal(literal) => write!(f, "{literal}"),
Expr::Unary(op, expr) => write!(f, "({op} {expr})"),
Expr::Binary(left, op, right) => write!(f, "({op} {left} {right})"),
Expr::Grouping(expr) => write!(f, "(group {expr})"),
Expr::Literal { literal } => write!(f, "{literal}"),
Expr::Unary { op, expr } => write!(f, "({op} {expr})"),
Expr::Binary { left, op, right } => write!(f, "({op} {left} {right})"),
Expr::Grouping { expr } => write!(f, "(group {expr})"),
Expr::Variable { name } => write!(f, "{name}"),
Expr::Assignment { name, value } => write!(f, "{name} = {value}"),
}
}
}

View file

@ -1,2 +1,7 @@
pub mod expr;
pub mod parser;
mod expr;
mod parser;
mod stmt;
pub use expr::{BinaryOp, Expr, Literal, UnaryOp};
pub use parser::parse_tokens;
pub use stmt::Stmt;

View file

@ -5,12 +5,13 @@ use crate::lexer::{Token, TokenType};
use crate::parser::expr::BinaryOp;
use super::expr::{Expr, UnaryOp};
use super::Stmt;
/*====================================================================================================================*/
type ParserResult<T> = Result<T, ParserError>;
pub fn parse_tokens(tokens: Vec<Token>) -> ParserResult<Expr> {
pub fn parse_tokens(tokens: Vec<Token>) -> Result<Vec<Stmt>, Vec<ParserError>> {
Parser::new(tokens).parse()
}
@ -39,6 +40,11 @@ impl TokenIter {
self.peek_token.as_ref()
}
fn is_empty(&self) -> bool {
// peek_token is None and there are no more tokens to take from token_iter
self.peek_token.is_none() && self.token_iter.len() == 0
}
}
impl Iterator for TokenIter {
@ -63,24 +69,44 @@ impl Parser {
}
}
pub fn parse(self) -> ParserResult<Expr> {
pub fn parse(self) -> Result<Vec<Stmt>, Vec<ParserError>> {
let mut me = self;
let expr = me.expression()?;
let mut statements = Vec::new();
let mut parse_errors = Vec::new();
me.consume_token(TokenType::EOF)?;
while !me.token_iter.is_empty() && me.peek_token().token_type != TokenType::EOF {
// statements.push(me.statement()?);
match me.statement() {
Ok(stmt) => {
statements.push(stmt);
}
Err(err) => {
parse_errors.push(err);
me.synchronise();
}
}
}
Ok(expr)
// me.consume_token(TokenType::EOF).unwrap();
if !parse_errors.is_empty() {
Err(parse_errors)
} else {
Ok(statements)
}
}
fn synchronise(&mut self) {
loop {
let peek_token = self
.peek_token()
.unwrap_or_else(|err| panic!("peek_token returned error in synchronise: {err}"));
if self.token_iter.is_empty() {
return;
}
let peek_token = self.peek_token();
// if we match a synchronisation point: return
match peek_token.token_type() {
match peek_token.token_type {
TokenType::Class
| TokenType::Fun
| TokenType::Var
@ -92,23 +118,118 @@ impl Parser {
| TokenType::EOF => return,
TokenType::Semicolon => {
// discard semicolon first, then return
let _ = self
.next_token()
.unwrap_or_else(|err| panic!("next_token returned error in synchronise: {err}"));
let _ = self.next_token();
return;
}
_ => {}
}
// no sync point: discard token
let _ = self
.next_token()
.unwrap_or_else(|err| panic!("next_token returned error in synchronise: {err}"));
let _ = self.next_token();
}
}
fn statement(&mut self) -> ParserResult<Stmt> {
match self.peek_token().token_type {
TokenType::Print => self.print_statement(),
TokenType::Var => self.var_declaration(),
TokenType::LeftBrace => self.block(),
_ => self.expression_statement(),
}
}
fn print_statement(&mut self) -> ParserResult<Stmt> {
// self.consume_token(TokenType::Print)?;
assert_eq!(self.next_token().token_type, TokenType::Print);
let expr = self.expression()?;
self.semicolon()?;
Ok(Stmt::print_stmt(expr))
}
fn var_declaration(&mut self) -> ParserResult<Stmt> {
// self.consume_token(TokenType::Var)?;
assert_eq!(self.next_token().token_type, TokenType::Var);
let name = match self.next_token() {
Token {
token_type: TokenType::Identifier(name),
..
} => name,
token => return Err(ParserError::ExpectedVarName { token }),
};
let initializer = if self.peek_token().token_type == TokenType::Equal {
// self.consume_token(TokenType::Equal).unwrap();
assert_eq!(self.next_token().token_type, TokenType::Equal);
self.expression()?
} else {
Expr::nil()
};
self.semicolon()?;
Ok(Stmt::var_decl(name, initializer))
}
fn block(&mut self) -> ParserResult<Stmt> {
// self.consume_token(TokenType::LeftBrace)?;
assert_eq!(self.next_token().token_type, TokenType::LeftBrace);
let mut statements = Vec::new();
while self.peek_token().token_type != TokenType::RightBrace {
let statement = self.statement().map_err(|err| {
if self.peek_token().token_type == TokenType::EOF {
ParserError::MissingRightBrace {
code_pos: self.peek_token().code_pos,
}
} else {
err
}
})?;
statements.push(statement);
}
// self.consume_token(TokenType::RightBrace)?;
assert_eq!(self.next_token().token_type, TokenType::RightBrace);
Ok(Stmt::Block { statements })
}
fn expression_statement(&mut self) -> ParserResult<Stmt> {
let expr = self.expression()?;
self.semicolon()?;
Ok(Stmt::expr_stmt(expr))
}
fn expression(&mut self) -> ParserResult<Expr> {
self.equality()
self.assignment()
}
fn assignment(&mut self) -> ParserResult<Expr> {
let code_pos = self.peek_token().code_pos;
let expr = self.equality()?;
if self.peek_token().token_type != TokenType::Equal {
return Ok(expr);
}
// self.consume_token(TokenType::Equal).unwrap();
assert_eq!(self.next_token().token_type, TokenType::Equal);
let value = self.assignment()?;
match expr {
Expr::Variable { name } => Ok(Expr::assignment(name, value)),
_ => Err(ParserError::InvalidAssignment { expr, code_pos }),
}
}
fn equality(&mut self) -> ParserResult<Expr> {
@ -116,18 +237,18 @@ impl Parser {
loop {
// get comparison operator as BinaryOp; otherwise break out of loop
let operator = match self.peek_token()?.token_type() {
let operator = match self.peek_token().token_type {
TokenType::EqualEqual => BinaryOp::Equal,
TokenType::BangEqual => BinaryOp::NotEqual,
_ => break,
};
// consume operator token
let _ = self.next_token().unwrap();
let _ = self.next_token();
let right = self.comparison()?;
expr = Expr::new_binary(expr, operator, right);
expr = Expr::binary(expr, operator, right);
}
Ok(expr)
@ -137,7 +258,7 @@ impl Parser {
let mut expr = self.term()?;
loop {
let operator = match self.peek_token()?.token_type() {
let operator = match self.peek_token().token_type {
TokenType::Less => BinaryOp::Less,
TokenType::LessEqual => BinaryOp::LessEqual,
TokenType::Greater => BinaryOp::Greater,
@ -146,11 +267,11 @@ impl Parser {
};
// consume operator token
let _ = self.next_token().unwrap();
let _ = self.next_token();
let right = self.term()?;
expr = Expr::new_binary(expr, operator, right);
expr = Expr::binary(expr, operator, right);
}
Ok(expr)
@ -160,18 +281,18 @@ impl Parser {
let mut expr = self.factor()?;
loop {
let operator = match self.peek_token()?.token_type() {
let operator = match self.peek_token().token_type {
TokenType::Plus => BinaryOp::Add,
TokenType::Minus => BinaryOp::Subtract,
_ => break,
};
// consume operator token
let _ = self.next_token().unwrap();
let _ = self.next_token();
let right = self.factor()?;
expr = Expr::new_binary(expr, operator, right);
expr = Expr::binary(expr, operator, right);
}
Ok(expr)
@ -181,76 +302,120 @@ impl Parser {
let mut expr = self.unary()?;
loop {
let operator = match self.peek_token()?.token_type() {
let operator = match self.peek_token().token_type {
TokenType::Star => BinaryOp::Multiply,
TokenType::Slash => BinaryOp::Divide,
_ => break,
};
// consume operator token
let _ = self.next_token().unwrap();
let _ = self.next_token();
let right = self.unary()?;
expr = Expr::new_binary(expr, operator, right);
expr = Expr::binary(expr, operator, right);
}
Ok(expr)
}
fn unary(&mut self) -> ParserResult<Expr> {
match self.peek_token()?.token_type() {
match self.peek_token().token_type {
TokenType::Bang => {
let _ = self.next_token().unwrap();
Ok(Expr::new_unary(UnaryOp::Not, self.unary()?))
self.next_token();
Ok(Expr::unary(UnaryOp::Not, self.unary()?))
}
TokenType::Minus => {
let _ = self.next_token().unwrap();
Ok(Expr::new_unary(UnaryOp::Negate, self.unary()?))
let _ = self.next_token();
Ok(Expr::unary(UnaryOp::Negate, self.unary()?))
}
_ => self.primary(),
}
}
fn primary(&mut self) -> ParserResult<Expr> {
let token = self.next_token()?;
if self.peek_token().token_type == TokenType::EOF {
return Err(ParserError::TokenStreamEnded);
}
match token.token_type() {
TokenType::Number(num) => Ok(Expr::new_number(*num)),
TokenType::String(s) => Ok(Expr::new_string(s.clone())),
TokenType::False => Ok(Expr::new_bool(false)),
TokenType::True => Ok(Expr::new_bool(true)),
TokenType::Nil => Ok(Expr::new_nil()),
let token = self.next_token();
match token.token_type {
TokenType::Number(num) => Ok(Expr::number(num)),
TokenType::String(s) => Ok(Expr::string(s)),
TokenType::False => Ok(Expr::bool(false)),
TokenType::True => Ok(Expr::bool(true)),
TokenType::Nil => Ok(Expr::nil()),
TokenType::LeftParen => {
let expr = self.expression()?;
self.consume_token(TokenType::RightParen)?;
Ok(Expr::new_grouping(expr))
// self.consume_token(TokenType::RightParen)?;
let peek_token = self.peek_token();
if peek_token.token_type != TokenType::RightParen {
return Err(ParserError::MissingRightParenthesis {
code_pos: token.code_pos,
});
}
let _ = self.next_token();
Ok(Expr::grouping(expr))
}
TokenType::Identifier(name) => Ok(Expr::Variable { name }),
_ => Err(ParserError::UnexpectedToken { token }),
}
}
fn next_token(&mut self) -> ParserResult<Token> {
// let next = self.token_iter.next();
fn semicolon(&mut self) -> ParserResult<()> {
/* match self.next_token() {
token if token.token_type == TokenType::Semicolon => Ok(()),
token => Err(ParserError::MissingSemicolon {
code_pos: token.code_pos,
}),
// None => Err(ParserError::TokenStreamEnded),
} */
let peek_token = self.peek_token();
if peek_token.token_type == TokenType::Semicolon {
self.next_token();
Ok(())
} else {
Err(ParserError::MissingSemicolon {
code_pos: peek_token.code_pos,
})
}
}
fn next_token(&mut self) -> Token {
/* let next = self.token_iter.next();
// println!("Next token: {next:?}");
// next.ok_or(ParserError::TokenStreamEnded)
self.token_iter.next().ok_or(ParserError::TokenStreamEnded)
}
fn peek_token(&mut self) -> ParserResult<&Token> {
self.token_iter.peek().ok_or(ParserError::TokenStreamEnded)
}
fn consume_token(&mut self, token_type: TokenType) -> ParserResult<Token> {
self.next_token().and_then(|token| {
if token.token_type() == &token_type {
Ok(token)
} else {
Err(ParserError::UnexpectedToken { token })
if let Some(ref token) = next {
if token.token_type == TokenType::EOF {
panic!("Someone ate a EOF token");
}
})
}
next.ok_or(ParserError::TokenStreamEnded) */
self.token_iter.next().unwrap() // .ok_or(ParserError::TokenStreamEnded)
}
fn peek_token(&mut self) -> &Token {
self.token_iter.peek().unwrap() // .ok_or(ParserError::TokenStreamEnded)
}
/* fn consume_token(&mut self, token_type: TokenType) -> ParserResult<bool> {
/* self.next_token().and_then(|token| {
if token.token_type == token_type {
Some(token)
} else {
// Err(ParserError::UnexpectedToken { token })
None
}
}) */
Ok(self.next_token().token_type == token_type)
} */
}

49
src/parser/stmt.rs Normal file
View file

@ -0,0 +1,49 @@
use std::fmt::Display;
use super::Expr;
pub enum Stmt {
ExprStmt { expr: Box<Expr> },
Print { expr: Box<Expr> },
VarDecl { name: String, initializer: Box<Expr> },
Block { statements: Vec<Stmt> },
}
impl Stmt {
pub fn expr_stmt(expr: Expr) -> Self {
let expr = Box::new(expr);
Stmt::ExprStmt { expr }
}
pub fn print_stmt(expr: Expr) -> Self {
let expr = Box::new(expr);
Stmt::Print { expr }
}
pub fn var_decl(name: String, initializer: Expr) -> Self {
let initializer = Box::new(initializer);
Stmt::VarDecl { name, initializer }
}
}
impl Display for Stmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Stmt::ExprStmt { expr } => write!(f, "{expr}"),
Stmt::Print { expr } => write!(f, "print {expr}"),
Stmt::VarDecl { name, initializer } => write!(f, "var {name} = {initializer}"),
Stmt::Block { statements } => {
writeln!(f, "{{")?;
for statement in statements {
// for each statement: statement to string, split by lines, preprend each line with tab, print
// return first error or, on success, "collect" the resulting () into a Vec (ZST, so no allocation)
format!("{statement}")
.split("\n")
.map(|line| writeln!(f, "\t{line}"))
.collect::<Result<Vec<()>, std::fmt::Error>>()?;
}
write!(f, "}}")
}
}
}
}