Chapter 10 done

This commit is contained in:
Moritz Gmeiner 2023-01-25 19:01:13 +01:00
commit 46f1030207
16 changed files with 1173 additions and 201 deletions

View file

@ -25,8 +25,8 @@ pub enum LexerError {
pub enum ParserError { pub enum ParserError {
#[error("Token stream ended unexpectedly.")] #[error("Token stream ended unexpectedly.")]
TokenStreamEnded, TokenStreamEnded,
#[error("Unexpected token {token} at {0}.", token.code_pos)] #[error("Expected a primary expression, but found a {token} token instead at {0}.", token.code_pos)]
UnexpectedToken { token: Token }, ExpectedPrimary { token: Token },
#[error("Missing semicolon at {code_pos}")] #[error("Missing semicolon at {code_pos}")]
MissingSemicolon { code_pos: CodePos }, MissingSemicolon { code_pos: CodePos },
#[error("Expected variable name at {0}, got {token} instead", token.code_pos)] #[error("Expected variable name at {0}, got {token} instead", token.code_pos)]
@ -36,7 +36,23 @@ pub enum ParserError {
#[error("Missing closing curly brace at {code_pos}")] #[error("Missing closing curly brace at {code_pos}")]
MissingRightBrace { code_pos: CodePos }, MissingRightBrace { code_pos: CodePos },
#[error("Missing closing parenthesis at {code_pos}")] #[error("Missing closing parenthesis at {code_pos}")]
MissingRightParenthesis { code_pos: CodePos }, MissingRightParen { code_pos: CodePos },
#[error("Missing parenthesis after if at {code_pos}")]
MissingParenAfterIf { code_pos: CodePos },
#[error("Missing parenthesis after while at {code_pos}")]
MissingParenAfterWhile { code_pos: CodePos },
#[error("Missing parenthesis after for at {code_pos}")]
MissingParenAfterFor { code_pos: CodePos },
#[error("Call at {code_pos} has too many arguments")]
TooManyArguments { code_pos: CodePos },
#[error("{msg} at {code_pos}")]
MissingIdentifier { msg: String, code_pos: CodePos },
#[error("Missing arguments to function declaration at {code_pos}")]
MissingFunctionArgs { code_pos: CodePos },
#[error("Missing body to function declaration at {code_pos}")]
MissingFunctionBody { code_pos: CodePos },
#[error("Function declaration at {code_pos} has too many parameters")]
TooManyParams { code_pos: CodePos },
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -49,19 +65,34 @@ pub enum RuntimeError {
DivisionByZero, DivisionByZero,
#[error("Name {name} is not defined")] #[error("Name {name} is not defined")]
NameNotDefined { name: String }, NameNotDefined { name: String },
#[error("{callee} is not callable")]
NotCallable { callee: Value },
#[error("{name}() takes {arity} args, but {given} were given.")]
WrongArity { name: String, arity: usize, given: usize },
#[error("Extern function call to {name} failed: {msg}")]
ExtFunCallFailed { name: String, msg: String },
#[error("Uncaught break statement")]
Break,
#[error("Uncaught return statement")]
Return { value: Value },
#[error("Exit with exit code {exit_code}")]
Exit { exit_code: i32 },
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
#[allow(clippy::enum_variant_names)]
pub enum LoxError { pub enum LoxError {
#[error("{0}", format_errors(inner))] #[error("{0}", format_multiple_errors(inner))]
LexerError { inner: Vec<LexerError> }, LexerError { inner: Vec<LexerError> },
#[error("{0}", format_errors(inner))] #[error("{0}", format_multiple_errors(inner))]
ParserError { inner: Vec<ParserError> }, ParserError { inner: Vec<ParserError> },
#[error("{inner}")] #[error("{inner}")]
EvalError { inner: RuntimeError }, RuntimeError { inner: RuntimeError },
#[error("Called exit() with exit code {exit_code}")]
Exit { exit_code: i32 },
} }
fn format_errors(errs: &Vec<impl std::error::Error>) -> String { fn format_multiple_errors(errs: &Vec<impl std::error::Error>) -> String {
let msg = if errs.len() == 1 { let msg = if errs.len() == 1 {
format!("{}", errs[0]) format!("{}", errs[0])
} else { } else {
@ -85,7 +116,10 @@ impl From<Vec<ParserError>> for LoxError {
} }
impl From<RuntimeError> for LoxError { impl From<RuntimeError> for LoxError {
fn from(eval_err: RuntimeError) -> Self { fn from(runtime_err: RuntimeError) -> Self {
LoxError::EvalError { inner: eval_err } match runtime_err {
RuntimeError::Exit { exit_code } => LoxError::Exit { exit_code },
_ => LoxError::RuntimeError { inner: runtime_err },
}
} }
} }

View file

@ -1,67 +1,146 @@
use std::borrow::Borrow;
use std::collections::HashMap; use std::collections::HashMap;
use crate::error::RuntimeError; use crate::error::RuntimeError;
use super::lox_std::init_std;
use super::value::HeapValue;
use super::Value; use super::Value;
type Scope = HashMap<String, Value>; pub type Scope = HashMap<String, HeapValue>;
pub struct Environment { pub struct Environment {
globals: HashMap<String, Value>, globals: Scope,
scopes: Vec<Scope>, // scopes: Vec<Scope>,
frames: Vec<Frame>,
} }
impl Environment { impl Environment {
pub fn new() -> Self { pub fn new() -> Self {
Environment { let mut env = Environment {
globals: HashMap::new(), globals: HashMap::new(),
scopes: Vec::new(), frames: vec![Frame::new_global()],
} };
init_std(&mut env);
env
} }
pub fn get(&self, name: &str) -> Result<&Value, RuntimeError> { fn current_frame(&self) -> &Frame {
for scope in self.scopes.iter().rev() { self.frames.last().unwrap()
if let Some(value) = scope.get(name) { }
fn current_frame_mut(&mut self) -> &mut Frame {
self.frames.last_mut().unwrap()
}
pub fn globals(&self) -> &Scope {
&self.globals
}
pub fn get(&self, name: &str) -> Result<Value, RuntimeError> {
if let Some(value) = self.current_frame().get(name) {
return Ok(value); return Ok(value);
} }
match self.globals.get(name) {
Some(heap_value) => Ok(heap_value.get_clone()),
None => Err(RuntimeError::NameNotDefined { name: name.to_owned() }),
}
} }
self.globals pub fn define(&mut self, name: impl Into<String> + Borrow<str>, value: Value) {
.get(name) if let Err(value) = self.current_frame_mut().try_define(name.borrow(), value) {
.ok_or(RuntimeError::NameNotDefined { name: name.to_owned() }) self.globals.insert(name.into(), HeapValue::new(value));
}
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> { pub fn assign(&mut self, name: &str, value: Value) -> Result<(), RuntimeError> {
for scope in self.scopes.iter_mut().rev() { let value = match self.current_frame_mut().try_assign(name, value) {
if let Some(var) = scope.get_mut(name) { Ok(()) => return Ok(()),
*var = value; Err(value) => value,
return Ok(()); };
}
}
if let Some(var) = self.globals.get_mut(name) { if let Some(var) = self.globals.get_mut(name) {
*var = value; // *var = value;
var.replace(value);
Ok(()) Ok(())
} else { } else {
let name = name.to_owned(); Err(RuntimeError::NameNotDefined { name: name.to_owned() })
Err(RuntimeError::NameNotDefined { name })
} }
} }
pub fn enter_scope(&mut self) { pub fn enter_scope(&mut self) {
self.scopes.push(Scope::new()); self.current_frame_mut().enter_scope();
} }
pub fn exit_scope(&mut self) { pub fn exit_scope(&mut self) {
self.scopes.pop().expect("Tried to exit scope, but no scope to exit"); self.current_frame_mut().exit_scope();
}
pub fn push_frame(&mut self, base_scope: Scope) {
self.frames.push(Frame::new(base_scope));
}
pub fn pop_frame(&mut self) {
self.frames.pop().expect("Tried to pop global frame");
}
}
/*====================================================================================================================*/
struct Frame {
scopes: Vec<Scope>,
}
impl Frame {
fn new(base_scope: Scope) -> Self {
Frame {
scopes: vec![base_scope],
}
}
fn new_global() -> Self {
Frame { scopes: Vec::new() }
}
fn enter_scope(&mut self) {
self.scopes.push(Scope::new());
}
fn exit_scope(&mut self) {
self.scopes.pop().expect("Tried to exit scope, but no scope to exit");
}
fn get(&self, name: &str) -> Option<Value> {
for scope in self.scopes.iter().rev() {
if let Some(heap_value) = scope.get(name) {
return Some(heap_value.get_clone());
}
}
None
}
fn try_define(&mut self, name: impl Into<String> + Borrow<str>, value: Value) -> Result<(), Value> {
if let Some(scope) = self.scopes.last_mut() {
scope.insert(name.into(), HeapValue::new(value));
Ok(())
} else {
Err(value)
}
}
fn try_assign(&mut self, name: &str, value: Value) -> Result<(), Value> {
for scope in self.scopes.iter_mut().rev() {
if let Some(heap_value) = scope.get_mut(name) {
heap_value.replace(value);
return Ok(());
}
}
Err(value)
} }
} }

104
src/interpreter/function.rs Normal file
View file

@ -0,0 +1,104 @@
use std::fmt::{Debug, Display};
use crate::parser::Stmt;
use super::environment::{Environment, Scope};
use super::interpret::EvalResult;
use super::Value;
#[derive(Debug, Clone)]
pub struct LoxFunction {
name: String,
closure: Scope,
param_names: Vec<String>,
body: Box<Stmt>,
}
impl LoxFunction {
pub fn new(name: impl Into<String>, param_names: Vec<String>, body: Stmt) -> Self {
let name = name.into();
let body = Box::new(body);
LoxFunction {
name,
closure: Scope::new(),
param_names,
body,
}
}
pub fn arity(&self) -> usize {
self.param_names.len()
}
pub fn name(&self) -> &str {
&self.name
}
pub fn closure(&self) -> &Scope {
&self.closure
}
pub fn param_names(&self) -> impl Iterator<Item = &String> {
self.param_names.iter()
}
pub fn body(&self) -> &Stmt {
&self.body
}
}
impl Display for LoxFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<fun {}>", self.name)
}
}
/*====================================================================================================================*/
pub type ExternFunClosure = fn(Vec<Value>, &mut Environment) -> EvalResult<Value>;
#[derive(Clone)]
pub struct LoxExternFunction {
name: String,
closure: ExternFunClosure,
}
impl LoxExternFunction {
pub fn new(name: impl Into<String>, closure: ExternFunClosure) -> Self {
let name = name.into();
LoxExternFunction { name, closure }
}
pub fn register(self, env: &mut Environment) {
let name = self.name.clone();
let fun = Value::extern_function(self);
env.define(name, fun);
}
pub fn call(&self, args: Vec<Value>, env: &mut Environment) -> EvalResult<Value> {
(self.closure)(args, env)
}
}
impl Display for LoxExternFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<extern fun {}>", self.name)
}
}
impl Debug for LoxExternFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LoxExternFunction")
.field("name", &self.name)
.field("closure", &"<closure>")
.finish()
}
}
impl PartialEq for LoxExternFunction {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}

View file

@ -1,46 +1,17 @@
use std::fmt::Display; use std::rc::Rc;
use crate::error::RuntimeError; use crate::error::RuntimeError;
use crate::parser::{BinaryOp, Expr, Literal, Stmt, UnaryOp}; use crate::parser::{BinaryOp, Expr, Literal, LogicalOp, Stmt, UnaryOp};
use super::environment::Environment; use super::environment::Environment;
use super::{LoxFunction, Value};
pub type EvalResult<T> = Result<T, RuntimeError>; pub type EvalResult<T> = Result<T, RuntimeError>;
/*====================================================================================================================*/ /*====================================================================================================================*/
pub fn execute(statement: Stmt, env: &mut Environment) -> Result<(), RuntimeError> { pub fn execute(statement: Stmt, env: &mut Environment) -> Result<(), RuntimeError> {
statement.eval(env) statement.execute(env)
}
/*====================================================================================================================*/
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
String(String),
Number(f64),
Bool(bool),
Nil,
}
impl Value {
fn is_truthy(&self) -> bool {
match self {
Value::Bool(false) | Value::Nil => false,
_ => true,
}
}
}
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::String(s) => write!(f, "\"{s}\""),
Value::Number(num) => write!(f, "{num}"),
Value::Bool(b) => write!(f, "{b}"),
Value::Nil => write!(f, "nil"),
}
}
} }
/*====================================================================================================================*/ /*====================================================================================================================*/
@ -50,24 +21,25 @@ impl Display for Value {
} */ } */
impl Literal { impl Literal {
fn eval(self, _env: &mut Environment) -> EvalResult<Value> { fn eval(&self, env: &mut Environment) -> EvalResult<Value> {
let _ = env;
match self { match self {
Literal::String(s) => Ok(Value::String(s)), Literal::String(s) => Ok(Value::String(Rc::clone(s))),
Literal::Number(num) => Ok(Value::Number(num)), Literal::Number(num) => Ok(Value::Number(*num)),
Literal::Bool(b) => Ok(Value::Bool(b)), Literal::Bool(b) => Ok(Value::Bool(*b)),
Literal::Nil => Ok(Value::Nil), Literal::Nil => Ok(Value::Nil),
} }
} }
} }
impl Expr { impl Expr {
fn eval(self, env: &mut Environment) -> EvalResult<Value> { fn eval(&self, env: &mut Environment) -> EvalResult<Value> {
match self { match self {
Expr::Literal { literal } => literal.eval(env), Expr::Literal { literal } => literal.eval(env),
Expr::Unary { op, expr } => { Expr::Unary { op, expr } => {
let arg = expr.eval(env)?; let arg = expr.eval(env)?;
match (op, arg) { match (*op, arg) {
(UnaryOp::Negate, Value::Number(num)) => Ok(Value::Number(-num)), (UnaryOp::Negate, Value::Number(num)) => Ok(Value::Number(-num)),
(UnaryOp::Not, Value::Bool(b)) => Ok(Value::Bool(!b)), (UnaryOp::Not, Value::Bool(b)) => Ok(Value::Bool(!b)),
(UnaryOp::Not, primitive) => Ok(Value::Bool(!primitive.is_truthy())), (UnaryOp::Not, primitive) => Ok(Value::Bool(!primitive.is_truthy())),
@ -80,7 +52,7 @@ impl Expr {
let left = left.eval(env)?; let left = left.eval(env)?;
let right = right.eval(env)?; let right = right.eval(env)?;
match (left, op, right) { match (left, *op, right) {
(Number(left), BinaryOp::Add, Number(right)) => Ok(Number(left + right)), (Number(left), BinaryOp::Add, Number(right)) => Ok(Number(left + right)),
(Number(left), BinaryOp::Subtract, 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::Multiply, Number(right)) => Ok(Number(left * right)),
@ -91,7 +63,12 @@ impl Expr {
Ok(Number(left / right)) Ok(Number(left / right))
} }
(String(left), BinaryOp::Add, String(right)) => Ok(String(left + &right)), (String(left), BinaryOp::Add, String(right)) => {
let mut s = std::string::String::with_capacity(left.capacity() + right.capacity());
s += &left;
s += &right;
Ok(String(Rc::new(s)))
}
(left, BinaryOp::Equal, right) => Ok(Bool(left == right)), (left, BinaryOp::Equal, right) => Ok(Bool(left == right)),
(left, BinaryOp::NotEqual, right) => Ok(Bool(left != right)), (left, BinaryOp::NotEqual, right) => Ok(Bool(left != right)),
@ -109,26 +86,59 @@ impl Expr {
(left, op, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }), (left, op, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }),
} }
} }
Expr::Logical { left, op, right } => {
let left = left.eval(env)?;
match op {
LogicalOp::Or => {
if left.is_truthy() {
return Ok(left);
}
}
LogicalOp::And => {
if !left.is_truthy() {
return Ok(left);
}
}
}
let right = right.eval(env)?;
Ok(right)
}
Expr::Grouping { expr } => expr.eval(env), Expr::Grouping { expr } => expr.eval(env),
Expr::Variable { name } => env.get(&name).cloned(), Expr::Variable { name } => env.get(name),
Expr::Assignment { name, value } => { Expr::Assignment { name, value } => {
let value = value.eval(env)?; let value = value.eval(env)?;
env.assign(&name, value.clone())?; env.assign(name, value.clone())?;
Ok(value) Ok(value)
} }
Expr::Call { callee, args } => {
let callee = callee.eval(env)?;
let args = args
.iter()
.map(|arg| arg.eval(env))
.collect::<EvalResult<Vec<Value>>>()?;
match callee {
Value::Function(fun) => fun.call(args, env),
Value::ExternFunction(ext_fun) => ext_fun.call(args, env),
_ => Err(RuntimeError::NotCallable { callee }),
}
}
Expr::Function {
name,
param_names,
body,
} => Ok(Value::function(LoxFunction::new(
name,
param_names.clone(),
body.as_ref().clone(),
))),
} }
} }
} }
impl Stmt { impl Stmt {
fn eval(self, env: &mut Environment) -> EvalResult<()> { fn execute(&self, env: &mut Environment) -> EvalResult<()> {
match self { match self {
Stmt::ExprStmt { expr } => {
// expr.eval(env)?;
// Ok(Value::Nil)
expr.eval(env)?;
Ok(())
}
Stmt::Print { expr } => { Stmt::Print { expr } => {
match expr.eval(env)? { match expr.eval(env)? {
// special case: when printing a string, drop the surrounding "" // special case: when printing a string, drop the surrounding ""
@ -138,20 +148,85 @@ impl Stmt {
Ok(()) Ok(())
} }
Stmt::IfStmt {
condition,
then_branch,
else_branch,
} => {
let condition = condition.eval(env)?;
if condition.is_truthy() {
then_branch.execute(env)
} else if let Some(else_branch) = else_branch {
else_branch.execute(env)
} else {
Ok(())
}
}
Stmt::While { condition, body } => {
while condition.eval(env)?.is_truthy() {
match body.execute(env) {
Ok(_) => {}
Err(RuntimeError::Break) => break,
Err(err) => return Err(err),
}
}
Ok(())
}
Stmt::VarDecl { name, initializer } => { Stmt::VarDecl { name, initializer } => {
let initializer = initializer.eval(env)?; let initializer = initializer.eval(env)?;
env.define(name, initializer); env.define(name.as_ref(), initializer);
Ok(()) Ok(())
} }
Stmt::Block { statements } => { Stmt::Block { statements } => {
env.enter_scope(); env.enter_scope();
for statement in statements { for statement in statements {
// on error the current frame gets destroyed anyways, so no need to exit scope // on error the current frame gets destroyed anyways, so no need to exit scope
statement.eval(env)?; statement.execute(env)?;
} }
env.exit_scope(); env.exit_scope();
Ok(()) Ok(())
} }
Stmt::ExprStmt { expr } => {
// expr.eval(env)?;
// Ok(Value::Nil)
expr.eval(env)?;
Ok(())
}
Stmt::Break => Err(RuntimeError::Break),
Stmt::Return { expr } => {
let value = expr.eval(env)?;
Err(RuntimeError::Return { value })
}
} }
} }
} }
/*====================================================================================================================*/
impl LoxFunction {
pub fn call(&self, args: Vec<Value>, env: &mut Environment) -> EvalResult<Value> {
if args.len() != self.arity() {
return Err(RuntimeError::WrongArity {
name: self.name().to_owned(),
arity: self.arity(),
given: args.len(),
});
}
env.push_frame(self.closure().clone());
for (name, value) in std::iter::zip(self.param_names(), args) {
env.define(name.as_ref(), value);
}
let ret_val = match self.body().execute(env) {
Ok(()) => Value::Nil,
Err(RuntimeError::Return { value }) => value,
Err(err) => return Err(err),
};
env.pop_frame();
Ok(ret_val)
}
}

View file

@ -0,0 +1,99 @@
use crate::error::RuntimeError;
use super::environment::Environment;
use super::function::{ExternFunClosure, LoxExternFunction};
use super::value::HeapValue;
use super::Value;
pub fn init_std(env: &mut Environment) {
input().register(env);
clock().register(env);
print_globals().register(env);
exit().register(env);
}
fn input() -> LoxExternFunction {
let closure: ExternFunClosure = |args, _env| match *args {
[] => {
let mut buf = String::new();
std::io::stdin()
.read_line(&mut buf)
.map_err(|err| RuntimeError::ExtFunCallFailed {
name: "input".to_owned(),
msg: format!("input() failed to read from stdin: {err}"),
})?;
assert_eq!(buf.pop(), Some('\n'));
Ok(Value::string(buf))
}
_ => Err(RuntimeError::ExtFunCallFailed {
name: "input".to_owned(),
msg: "input() takes no arguments".to_owned(),
}),
};
LoxExternFunction::new("input", closure)
}
fn clock() -> LoxExternFunction {
let closure: ExternFunClosure = |args, _env| match *args {
[] => {
let time = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs_f64();
Ok(Value::Number(time))
}
_ => Err(RuntimeError::ExtFunCallFailed {
name: "clock".to_owned(),
msg: "clock() takes no arguments".to_owned(),
}),
};
LoxExternFunction::new("clock", closure)
}
fn print_globals() -> LoxExternFunction {
let closure: ExternFunClosure = |args, env| match *args {
[] => {
let mut globals: Vec<(&String, &HeapValue)> = env.globals().iter().collect();
globals.sort_by_key(|&(name, _value)| name);
for (name, value) in globals {
println!("{name}: {value}");
}
Ok(Value::Nil)
}
_ => Err(RuntimeError::ExtFunCallFailed {
name: "print_globals".to_owned(),
msg: "print_globals() takes no arguments".to_owned(),
}),
};
LoxExternFunction::new("print_globals", closure)
}
fn exit() -> LoxExternFunction {
let closure: ExternFunClosure = |args, _env| {
match &*args {
[] => return Err(RuntimeError::Exit { exit_code: 0 }),
[Value::Number(exit_code)] => {
if exit_code.fract() == 0.0 {
let exit_code = *exit_code as i32;
return Err(RuntimeError::Exit { exit_code });
}
}
_ => {}
}
Err(RuntimeError::ExtFunCallFailed {
name: "exit".to_owned(),
msg: "Arguments to exit() must an integer or nothing for exit code 0".to_owned(),
})
};
LoxExternFunction::new("exit", closure)
}

View file

@ -1,6 +1,10 @@
mod environment; mod environment;
mod eval; mod function;
mod interpret;
mod lox_std;
mod run; mod run;
mod value;
pub use eval::Value; pub use function::LoxFunction;
pub use run::interpreter_main; pub use run::interpreter_main;
pub use value::Value;

View file

@ -1,8 +1,7 @@
use std::io::Write; use std::io::Write;
use crate::error::LoxError; use crate::error::LoxError;
use crate::interpreter::eval::execute; use crate::interpreter::interpret::execute;
use crate::interpreter::Value;
use crate::lexer::{scan_tokens, Token}; use crate::lexer::{scan_tokens, Token};
use crate::parser::parse_tokens; use crate::parser::parse_tokens;
@ -34,11 +33,15 @@ fn run_file(script_path: &str) {
let mut env = Environment::new(); let mut env = Environment::new();
if let Err(err) = run(&source_code, &mut env) { match run(&source_code, &mut env) {
Ok(()) => std::process::exit(0),
Err(err) => {
eprintln!("{err}"); eprintln!("{err}");
match err { match err {
LoxError::LexerError { .. } | LoxError::ParserError { .. } => std::process::exit(65), LoxError::LexerError { .. } | LoxError::ParserError { .. } => std::process::exit(65),
LoxError::EvalError { .. } => std::process::exit(70), LoxError::RuntimeError { .. } => std::process::exit(70),
LoxError::Exit { exit_code } => std::process::exit(exit_code),
}
} }
} }
} }
@ -48,7 +51,7 @@ fn run_repl() {
let mut env = Environment::new(); let mut env = Environment::new();
'outer: loop { loop {
let mut input_buf = String::new(); let mut input_buf = String::new();
print!("> "); print!("> ");
@ -60,7 +63,7 @@ fn run_repl() {
std::process::exit(66); 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_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); let num_open_brackets = (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64);
@ -72,22 +75,21 @@ fn run_repl() {
// any braces/parens/brackets more closing than opening => break (will be parse error) // 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 { if num_open_braces < 0 || num_open_parens < 0 || num_open_brackets < 0 {
break 'inner; break 'inner;
} */ }
break 'inner;
print!("< "); print!("< ");
std::io::stdout().flush().unwrap(); std::io::stdout().flush().unwrap();
} }
input_buf = input_buf.trim().to_owned(); let input_buf = input_buf.trim();
if input_buf.is_empty() || input_buf == "exit" || input_buf == "quit" { if input_buf.is_empty() || input_buf == "exit" || input_buf == "quit" {
break 'outer; std::process::exit(0);
} }
match run(&input_buf, &mut env) { match run(input_buf, &mut env) {
Ok(()) => {} Ok(()) => {}
Err(LoxError::Exit { exit_code }) => std::process::exit(exit_code),
Err(err) => eprintln!("{}", err), Err(err) => eprintln!("{}", err),
} }
} }
@ -106,7 +108,9 @@ fn run(code_string: &str, env: &mut Environment) -> Result<(), LoxError> {
let statements = parse_tokens(tokens)?; let statements = parse_tokens(tokens)?;
// println!("{expr}"); /* for statement in statements.iter() {
println!("{statement}");
} */
// let mut result = Value::Nil; // let mut result = Value::Nil;

106
src/interpreter/value.rs Normal file
View file

@ -0,0 +1,106 @@
use std::cell::UnsafeCell;
use std::fmt::{Debug, Display};
use std::rc::Rc;
use super::function::LoxExternFunction;
use super::LoxFunction;
#[derive(Debug, Clone)]
pub enum Value {
Function(Rc<LoxFunction>),
ExternFunction(Rc<LoxExternFunction>),
String(Rc<String>),
Number(f64),
Bool(bool),
Nil,
}
impl Value {
pub fn function(fun: LoxFunction) -> Self {
let fun = Rc::new(fun);
Value::Function(fun)
}
pub fn extern_function(fun: LoxExternFunction) -> Self {
let fun = Rc::new(fun);
Value::ExternFunction(fun)
}
pub fn string(s: impl Into<String>) -> Self {
let s = Rc::new(s.into());
Value::String(s)
}
pub fn is_truthy(&self) -> bool {
!matches!(self, Value::Bool(false) | Value::Nil)
}
}
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Function(fun) => write!(f, "{fun}"),
Value::ExternFunction(ext_fun) => write!(f, "{ext_fun}"),
Value::String(s) => write!(f, "\"{s}\""),
Value::Number(num) => write!(f, "{num}"),
Value::Bool(b) => write!(f, "{b}"),
Value::Nil => write!(f, "nil"),
}
}
}
impl PartialEq for Value {
fn eq(&self, other: &Value) -> bool {
match (self, other) {
(Value::Function(l0), Value::Function(r0)) => Rc::ptr_eq(l0, r0),
(Value::ExternFunction(l0), Value::ExternFunction(r0)) => Rc::ptr_eq(l0, r0),
(Value::String(l0), Value::String(r0)) => l0 == r0,
(Value::Number(l0), Value::Number(r0)) => l0 == r0,
(Value::Bool(l0), Value::Bool(r0)) => l0 == r0,
(Value::Nil, Value::Nil) => true,
_ => false,
}
}
}
/*====================================================================================================================*/
#[derive(Clone)]
pub struct HeapValue {
inner: Rc<UnsafeCell<Value>>,
}
impl HeapValue {
pub fn new(value: Value) -> Self {
let inner = Rc::new(UnsafeCell::new(value));
HeapValue { inner }
}
pub fn get_clone(&self) -> Value {
unsafe {
let ptr = self.inner.get();
let value = &*ptr;
value.clone()
}
}
pub fn replace(&mut self, value: Value) {
let mut value = value;
unsafe {
let ptr_mut = self.inner.get();
std::ptr::swap(&mut value, ptr_mut);
}
}
}
impl Debug for HeapValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HeapValue").field("inner", &self.get_clone()).finish()
}
}
impl Display for HeapValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.get_clone())
}
}

View file

@ -9,9 +9,10 @@ use super::{Token, TokenType};
static KEYWORDS: phf::Map<&'static str, TokenType> = phf_map! { static KEYWORDS: phf::Map<&'static str, TokenType> = phf_map! {
"and" => TokenType::And, "and" => TokenType::And,
"break" => TokenType::Break,
"class" => TokenType::Class, "class" => TokenType::Class,
"else" => TokenType::Else, "else" => TokenType::Else,
"false" => TokenType::Else, "false" => TokenType::False,
"for" => TokenType::For, "for" => TokenType::For,
"fun" => TokenType::Fun, "fun" => TokenType::Fun,
"if" => TokenType::If, "if" => TokenType::If,
@ -232,7 +233,7 @@ impl Lexer {
} }
fn push_token(&mut self, token_type: TokenType) { fn push_token(&mut self, token_type: TokenType) {
let lexeme: String = self.source[self.start..self.current].iter().collect(); // let lexeme: String = self.source[self.start..self.current].iter().collect();
self.tokens.push(Token::new(token_type, self.code_pos)); self.tokens.push(Token::new(token_type, self.code_pos));
} }

View file

@ -1,6 +1,6 @@
use crate::misc::CodePos; use crate::misc::CodePos;
#[allow(dead_code)] #[allow(dead_code, clippy::upper_case_acronyms)]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[rustfmt::skip] #[rustfmt::skip]
pub enum TokenType { pub enum TokenType {
@ -20,12 +20,13 @@ pub enum TokenType {
Number(f64), Number(f64),
// Keywords // Keywords
And, Class, Else, False, Fun, For, If, Nil, Or, And, Break, Class, Else, False, Fun, For, If, Nil, Or,
Print, Return, Super, This, True, Var, While, Print, Return, Super, This, True, Var, While,
EOF EOF
} }
#[derive(Clone)]
pub struct Token { pub struct Token {
pub token_type: TokenType, pub token_type: TokenType,
// pub lexeme: String, // pub lexeme: String,

View file

@ -23,3 +23,12 @@ impl Debug for CodePos {
write!(f, "{}:{}", self.line, self.col) write!(f, "{}:{}", self.line, self.col)
} }
} }
/*====================================================================================================================*/
pub fn indent(s: String) -> String {
s.split('\n')
.map(|line| format!("\t{line}"))
.collect::<Vec<String>>()
.join("\n")
}

View file

@ -1,18 +1,44 @@
program -> statement* EOF ; program -> statement* EOF ;
statement -> exprStmt | printStmt | declaration | block ; statement -> if_stmt
| print_stmt
| while_stmt
| for_stmt
| declaration
| block
| expr_stmt
| break
| return_stmt ;
exprStmt -> expression ";" ; if_stmt -> "if" "(" expression ")" statement ( "else" statement )? ;
printStmt -> "print" expression ";" ; print_stmt -> "print" expression ";" ;
declaration -> "var" IDENTIFIER ( "=" expression )? ";" ; while_stmt -> "while" "(" expression ")" statement ;
for_stmt -> "for" "(" (declaration | expr_stmt | ";") ";" expression? ";" expression ";" ")" statement ;
declaration -> var_decl | fun_decl ;
block -> "{" statement* "}" ; block -> "{" statement* "}" ;
expr_Stmt -> expression ";" ;
break -> "break" ";" ;
return -> "return" expression? ";" ;
var_decl -> "var" IDENTIFIER ( "=" expression )? ";"
fun_decl -> "fun" IDENTIFIER "(" parameters ")" block ;
expression -> assignment expression -> assignment
assignment -> IDENTIFIER "=" assignment | equality ; assignment -> IDENTIFIER "=" assignment | logic_or ;
logic_or -> logic_and ( "or" logic_and )* ;
logic_and -> equality ( "and" equality )* ;
equality -> comparison ( ( "==" | "!=" ) comparison )* ; equality -> comparison ( ( "==" | "!=" ) comparison )* ;
comparison -> term ( ">" | ">=" | "<" | "<=" term )* ; comparison -> term ( ">" | ">=" | "<" | "<=" term )* ;
term -> factor ( ( "+" | "-" ) factor )* term -> factor ( ( "+" | "-" ) factor )*
factor -> unary ( ( "*" | "/" ) unary )* ; factor -> unary ( ( "*" | "/" ) unary )* ;
unary -> ( "!" | "-" ) unary | primary ; unary -> ( "!" | "-" ) unary | call ;
primary -> "(" expression ")" | IDENTIFIER | NUMBER | STRING | "true" | "false" | "nil" ;
call -> primary ( "(" arguments? ")" )* ;
arguments -> expression ( "," expression )* ;
primary -> "(" expression ")" | IDENTIFIER | fun_expr | NUMBER | STRING | "true" | "false" | "nil" ;
fun_expr -> "fun" "(" parameters ")" block ;
parameters -> ( IDENTIFIER ( "," IDENTIFIER )* )? ;

View file

@ -1,6 +1,9 @@
use std::fmt::Display; use std::fmt::Display;
use std::rc::Rc;
#[derive(Debug)] use super::Stmt;
#[derive(Debug, Clone)]
pub enum Expr { pub enum Expr {
Literal { Literal {
literal: Literal, literal: Literal,
@ -14,6 +17,11 @@ pub enum Expr {
op: BinaryOp, op: BinaryOp,
right: Box<Expr>, right: Box<Expr>,
}, },
Logical {
left: Box<Expr>,
op: LogicalOp,
right: Box<Expr>,
},
Grouping { Grouping {
expr: Box<Expr>, expr: Box<Expr>,
}, },
@ -24,12 +32,22 @@ pub enum Expr {
name: String, name: String,
value: Box<Expr>, value: Box<Expr>,
}, },
Call {
callee: Box<Expr>,
args: Vec<Expr>,
},
Function {
name: String,
param_names: Vec<String>,
body: Box<Stmt>,
},
} }
impl Expr { impl Expr {
pub fn string(s: String) -> Self { pub fn string(s: impl Into<String>) -> Self {
let s = s.into();
Expr::Literal { Expr::Literal {
literal: Literal::String(s), literal: Literal::String(Rc::new(s)),
} }
} }
@ -60,15 +78,36 @@ impl Expr {
Expr::Binary { left, op, right } Expr::Binary { left, op, right }
} }
pub fn logical(left: Expr, op: LogicalOp, right: Expr) -> Self {
let left = Box::new(left);
let right = Box::new(right);
Expr::Logical { left, op, right }
}
pub fn grouping(expr: Expr) -> Self { pub fn grouping(expr: Expr) -> Self {
let expr = Box::new(expr); let expr = Box::new(expr);
Expr::Grouping { expr } Expr::Grouping { expr }
} }
pub fn assignment(name: String, value: Expr) -> Self { pub fn assignment(name: impl Into<String>, value: Expr) -> Self {
let name = name.into();
let value = Box::new(value); let value = Box::new(value);
Expr::Assignment { name, value } Expr::Assignment { name, value }
} }
pub fn call(callee: Expr, args: Vec<Expr>) -> Self {
let callee = Box::new(callee);
Expr::Call { callee, args }
}
pub fn function(name: String, param_names: Vec<String>, body: Stmt) -> Self {
let body = Box::new(body);
Self::Function {
name,
param_names,
body,
}
}
} }
impl Display for Expr { impl Display for Expr {
@ -77,18 +116,36 @@ impl Display for Expr {
Expr::Literal { literal } => write!(f, "{literal}"), Expr::Literal { literal } => write!(f, "{literal}"),
Expr::Unary { op, expr } => write!(f, "({op} {expr})"), Expr::Unary { op, expr } => write!(f, "({op} {expr})"),
Expr::Binary { left, op, right } => write!(f, "({op} {left} {right})"), Expr::Binary { left, op, right } => write!(f, "({op} {left} {right})"),
Expr::Logical { left, op, right } => {
write!(f, "({op} {left} {right})")
}
Expr::Grouping { expr } => write!(f, "(group {expr})"), Expr::Grouping { expr } => write!(f, "(group {expr})"),
Expr::Variable { name } => write!(f, "{name}"), Expr::Variable { name } => write!(f, "{name}"),
Expr::Assignment { name, value } => write!(f, "{name} = {value}"), Expr::Assignment { name, value } => write!(f, "{name} = {value}"),
Expr::Call { callee, args } => write!(
f,
"({callee} {})",
args.iter()
.map(|arg| format!("{arg}"))
.collect::<Vec<String>>()
.join(" ")
),
Expr::Function {
name,
param_names,
body,
} => {
write!(f, "fun {name}({}) {body}", param_names.join(", "))
}
} }
} }
} }
/*====================================================================================================================*/ /*====================================================================================================================*/
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Literal { pub enum Literal {
String(String), String(Rc<String>),
Number(f64), Number(f64),
Bool(bool), Bool(bool),
Nil, Nil,
@ -107,7 +164,7 @@ impl Display for Literal {
/*====================================================================================================================*/ /*====================================================================================================================*/
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
pub enum UnaryOp { pub enum UnaryOp {
Negate, Negate,
Not, Not,
@ -124,7 +181,7 @@ impl Display for UnaryOp {
/*====================================================================================================================*/ /*====================================================================================================================*/
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
#[rustfmt::skip] #[rustfmt::skip]
pub enum BinaryOp { pub enum BinaryOp {
// arithmetic // arithmetic
@ -154,3 +211,18 @@ impl Display for BinaryOp {
} }
} }
} }
#[derive(Debug, Clone, Copy)]
pub enum LogicalOp {
Or,
And,
}
impl Display for LogicalOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LogicalOp::Or => write!(f, "or"),
LogicalOp::And => write!(f, "and"),
}
}
}

View file

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

View file

@ -5,7 +5,7 @@ use crate::lexer::{Token, TokenType};
use crate::parser::expr::BinaryOp; use crate::parser::expr::BinaryOp;
use super::expr::{Expr, UnaryOp}; use super::expr::{Expr, UnaryOp};
use super::Stmt; use super::{LogicalOp, Stmt};
/*====================================================================================================================*/ /*====================================================================================================================*/
@ -60,12 +60,15 @@ impl Iterator for TokenIter {
struct Parser { struct Parser {
token_iter: TokenIter, token_iter: TokenIter,
parse_errors: Vec<ParserError>,
} }
impl Parser { impl Parser {
pub fn new(tokens: Vec<Token>) -> Self { pub fn new(tokens: Vec<Token>) -> Self {
Parser { Parser {
token_iter: TokenIter::new(tokens), token_iter: TokenIter::new(tokens),
parse_errors: Vec::new(),
} }
} }
@ -73,7 +76,7 @@ impl Parser {
let mut me = self; let mut me = self;
let mut statements = Vec::new(); let mut statements = Vec::new();
let mut parse_errors = Vec::new(); // let mut parse_errors = Vec::new();
while !me.token_iter.is_empty() && me.peek_token().token_type != TokenType::EOF { while !me.token_iter.is_empty() && me.peek_token().token_type != TokenType::EOF {
// statements.push(me.statement()?); // statements.push(me.statement()?);
@ -82,16 +85,18 @@ impl Parser {
statements.push(stmt); statements.push(stmt);
} }
Err(err) => { Err(err) => {
parse_errors.push(err); me.parse_errors.push(err);
// println!("Synchronising...");
me.synchronise(); me.synchronise();
// println!("Synchronised")
} }
} }
} }
// me.consume_token(TokenType::EOF).unwrap(); // me.consume_token(TokenType::EOF).unwrap();
if !parse_errors.is_empty() { if !me.parse_errors.is_empty() {
Err(parse_errors) Err(me.parse_errors)
} else { } else {
Ok(statements) Ok(statements)
} }
@ -126,18 +131,133 @@ impl Parser {
// no sync point: discard token // no sync point: discard token
let _ = self.next_token(); let _ = self.next_token();
// println!("Discarding {} token", self.next_token());
} }
} }
fn statement(&mut self) -> ParserResult<Stmt> { fn statement(&mut self) -> ParserResult<Stmt> {
match self.peek_token().token_type { match self.peek_token().token_type {
TokenType::Print => self.print_statement(), TokenType::Print => self.print_statement(),
TokenType::If => self.if_statement(),
TokenType::While => self.while_statement(),
TokenType::For => self.for_statement(),
TokenType::Var => self.var_declaration(), TokenType::Var => self.var_declaration(),
TokenType::Fun => self.fun_declaration(),
TokenType::LeftBrace => self.block(), TokenType::LeftBrace => self.block(),
TokenType::Break => {
assert_eq!(self.next_token().token_type, TokenType::Break);
self.semicolon()?;
Ok(Stmt::Break)
}
TokenType::Return => {
assert_eq!(self.next_token().token_type, TokenType::Return);
let expr = match self.peek_token().token_type {
TokenType::Semicolon => Expr::nil(),
_ => self.expression()?,
};
self.semicolon()?;
Ok(Stmt::return_stmt(expr))
}
_ => self.expression_statement(), _ => self.expression_statement(),
} }
} }
fn if_statement(&mut self) -> ParserResult<Stmt> {
assert_eq!(self.next_token().token_type, TokenType::If);
self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterIf {
code_pos: token.code_pos,
})?;
let condition = self.expression()?;
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen {
code_pos: token.code_pos,
})?;
let then_branch = self.statement()?;
let else_branch = if self.peek_token().token_type == TokenType::Else {
// consume else token
let _ = self.next_token();
Some(self.statement()?)
} else {
None
};
Ok(Stmt::if_stmt(condition, then_branch, else_branch))
}
fn while_statement(&mut self) -> ParserResult<Stmt> {
assert_eq!(self.next_token().token_type, TokenType::While);
self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterWhile {
code_pos: token.code_pos,
})?;
let condition = self.expression()?;
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen {
code_pos: token.code_pos,
})?;
let body = self.statement()?;
Ok(Stmt::while_stmt(condition, body))
}
fn for_statement(&mut self) -> ParserResult<Stmt> {
assert_eq!(self.next_token().token_type, TokenType::For);
self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterFor {
code_pos: token.code_pos,
})?;
let initializer = match self.peek_token().token_type {
TokenType::Semicolon => {
assert_eq!(self.next_token().token_type, TokenType::Semicolon);
None
}
TokenType::Var => Some(self.var_declaration()?),
_ => Some(self.expression_statement()?),
};
let condition = match self.peek_token().token_type {
TokenType::Semicolon => Expr::bool(true),
_ => self.expression()?,
};
self.semicolon()?;
let increment = match self.peek_token().token_type {
TokenType::RightParen => None,
_ => Some(self.expression()?),
};
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen {
code_pos: token.code_pos,
})?;
let mut body = self.statement()?;
if let Some(increment) = increment {
body = Stmt::Block {
statements: vec![body, Stmt::expr_stmt(increment)],
}
}
let mut for_stmt = Stmt::while_stmt(condition, body);
if let Some(initializer) = initializer {
for_stmt = Stmt::Block {
statements: vec![initializer, for_stmt],
};
}
Ok(for_stmt)
}
fn print_statement(&mut self) -> ParserResult<Stmt> { fn print_statement(&mut self) -> ParserResult<Stmt> {
// self.consume_token(TokenType::Print)?; // self.consume_token(TokenType::Print)?;
assert_eq!(self.next_token().token_type, TokenType::Print); assert_eq!(self.next_token().token_type, TokenType::Print);
@ -175,6 +295,74 @@ impl Parser {
Ok(Stmt::var_decl(name, initializer)) Ok(Stmt::var_decl(name, initializer))
} }
fn fun_declaration(&mut self) -> ParserResult<Stmt> {
assert_eq!(self.next_token().token_type, TokenType::Fun);
let name = self.identifier("Missing function name")?;
let fun = self.fun_params_and_body(name.clone())?;
Ok(Stmt::var_decl(name, fun))
}
fn fun_params_and_body(&mut self, name: impl Into<String>) -> ParserResult<Expr> {
// <Fun> token has already been eaten by primary or fun_declaration
// assert_eq!(self.next_token().token_type, TokenType::Fun);
if self.peek_token().token_type != TokenType::LeftParen {
return Err(ParserError::MissingFunctionArgs {
code_pos: self.peek_token().code_pos,
});
}
let params_code_pos = self.peek_token().code_pos;
let param_names = self.collect_params()?;
if param_names.len() > 255 {
self.parse_errors.push(ParserError::TooManyParams {
code_pos: params_code_pos,
});
}
if self.peek_token().token_type != TokenType::LeftBrace {
return Err(ParserError::MissingFunctionBody {
code_pos: self.peek_token().code_pos,
});
}
let body = self.block()?;
let name = name.into();
Ok(Expr::function(name, param_names, body))
}
fn collect_params(&mut self) -> ParserResult<Vec<String>> {
assert_eq!(self.next_token().token_type, TokenType::LeftParen);
if self.peek_token().token_type == TokenType::RightParen {
assert_eq!(self.next_token().token_type, TokenType::RightParen);
return Ok(Vec::new());
}
let mut param_names = Vec::new();
param_names.push(self.identifier("Expected parameter name")?);
while self.peek_token().token_type == TokenType::Comma {
assert_eq!(self.next_token().token_type, TokenType::Comma);
param_names.push(self.identifier("Expected parameter name")?);
}
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen {
code_pos: token.code_pos,
})?;
Ok(param_names)
}
fn block(&mut self) -> ParserResult<Stmt> { fn block(&mut self) -> ParserResult<Stmt> {
// self.consume_token(TokenType::LeftBrace)?; // self.consume_token(TokenType::LeftBrace)?;
assert_eq!(self.next_token().token_type, TokenType::LeftBrace); assert_eq!(self.next_token().token_type, TokenType::LeftBrace);
@ -215,7 +403,7 @@ impl Parser {
fn assignment(&mut self) -> ParserResult<Expr> { fn assignment(&mut self) -> ParserResult<Expr> {
let code_pos = self.peek_token().code_pos; let code_pos = self.peek_token().code_pos;
let expr = self.equality()?; let expr = self.logical_or()?;
if self.peek_token().token_type != TokenType::Equal { if self.peek_token().token_type != TokenType::Equal {
return Ok(expr); return Ok(expr);
@ -232,6 +420,36 @@ impl Parser {
} }
} }
fn logical_or(&mut self) -> ParserResult<Expr> {
let mut expr = self.logical_and()?;
if self.peek_token().token_type == TokenType::Or {
// consume or
let _ = self.next_token();
let right = self.logical_or()?;
expr = Expr::logical(expr, LogicalOp::Or, right);
}
Ok(expr)
}
fn logical_and(&mut self) -> ParserResult<Expr> {
let mut expr = self.equality()?;
if self.peek_token().token_type == TokenType::And {
// consume and
let _ = self.next_token();
let right = self.logical_and()?;
expr = Expr::logical(expr, LogicalOp::And, right);
}
Ok(expr)
}
fn equality(&mut self) -> ParserResult<Expr> { fn equality(&mut self) -> ParserResult<Expr> {
let mut expr = self.comparison()?; let mut expr = self.comparison()?;
@ -329,10 +547,62 @@ impl Parser {
let _ = self.next_token(); let _ = self.next_token();
Ok(Expr::unary(UnaryOp::Negate, self.unary()?)) Ok(Expr::unary(UnaryOp::Negate, self.unary()?))
} }
_ => self.primary(), _ => self.call(),
} }
} }
fn call(&mut self) -> ParserResult<Expr> {
let mut expr = self.primary()?;
loop {
match self.peek_token().token_type {
TokenType::LeftParen => {
let args_code_pos = self.peek_token().code_pos;
let args = self.collect_args()?;
if args.len() > 255 {
self.parse_errors.push(ParserError::TooManyArguments {
code_pos: args_code_pos,
});
}
expr = Expr::call(expr, args);
}
TokenType::Dot => todo!(),
_ => break,
}
}
Ok(expr)
}
fn collect_args(&mut self) -> ParserResult<Vec<Expr>> {
assert_eq!(self.next_token().token_type, TokenType::LeftParen);
if self.peek_token().token_type == TokenType::RightParen {
assert_eq!(self.next_token().token_type, TokenType::RightParen);
return Ok(Vec::new());
}
let mut args = Vec::new();
args.push(self.expression()?);
while self.peek_token().token_type == TokenType::Comma {
assert_eq!(self.next_token().token_type, TokenType::Comma);
args.push(self.expression()?);
}
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen {
code_pos: token.code_pos,
})?;
Ok(args)
}
fn primary(&mut self) -> ParserResult<Expr> { fn primary(&mut self) -> ParserResult<Expr> {
if self.peek_token().token_type == TokenType::EOF { if self.peek_token().token_type == TokenType::EOF {
return Err(ParserError::TokenStreamEnded); return Err(ParserError::TokenStreamEnded);
@ -341,6 +611,7 @@ impl Parser {
let token = self.next_token(); let token = self.next_token();
match token.token_type { match token.token_type {
TokenType::Fun => Ok(self.fun_params_and_body("<lambda>")?),
TokenType::Number(num) => Ok(Expr::number(num)), TokenType::Number(num) => Ok(Expr::number(num)),
TokenType::String(s) => Ok(Expr::string(s)), TokenType::String(s) => Ok(Expr::string(s)),
TokenType::False => Ok(Expr::bool(false)), TokenType::False => Ok(Expr::bool(false)),
@ -348,56 +619,54 @@ impl Parser {
TokenType::Nil => Ok(Expr::nil()), TokenType::Nil => Ok(Expr::nil()),
TokenType::LeftParen => { TokenType::LeftParen => {
let expr = self.expression()?; let expr = self.expression()?;
// 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(); self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen {
code_pos: token.code_pos,
})?;
Ok(Expr::grouping(expr)) Ok(Expr::grouping(expr))
} }
TokenType::Identifier(name) => Ok(Expr::Variable { name }), TokenType::Identifier(name) => Ok(Expr::Variable { name }),
_ => Err(ParserError::UnexpectedToken { token }), _ => Err(ParserError::ExpectedPrimary { token }),
} }
} }
fn semicolon(&mut self) -> ParserResult<()> { fn semicolon(&mut self) -> ParserResult<()> {
/* match self.next_token() { self.consume_token(TokenType::Semicolon, |token| ParserError::MissingSemicolon {
token if token.token_type == TokenType::Semicolon => Ok(()),
token => Err(ParserError::MissingSemicolon {
code_pos: token.code_pos, 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 identifier(&mut self, msg: &str) -> ParserResult<String> {
match self.peek_token().token_type {
TokenType::Identifier(_) => {
if let TokenType::Identifier(name) = self.next_token().token_type {
Ok(name)
} else {
unreachable!()
}
}
_ => Err(ParserError::MissingIdentifier {
msg: msg.to_owned(),
code_pos: self.peek_token().code_pos,
}),
}
} }
fn next_token(&mut self) -> Token { fn next_token(&mut self) -> Token {
/* let next = self.token_iter.next(); /* let token = self.token_iter.next().unwrap();
// println!("Next token: {next:?}"); // println!("Next token: {next:?}");
if let Some(ref token) = next {
if token.token_type == TokenType::EOF { if token.token_type == TokenType::EOF {
panic!("Someone ate a EOF token"); panic!("Someone ate a EOF token");
} }
}
next.ok_or(ParserError::TokenStreamEnded) */ // if token.token_type == TokenType::Print {
// panic!("Found the print");
// }
token */
self.token_iter.next().unwrap() // .ok_or(ParserError::TokenStreamEnded) self.token_iter.next().unwrap() // .ok_or(ParserError::TokenStreamEnded)
} }
@ -406,16 +675,25 @@ impl Parser {
self.token_iter.peek().unwrap() // .ok_or(ParserError::TokenStreamEnded) self.token_iter.peek().unwrap() // .ok_or(ParserError::TokenStreamEnded)
} }
/* fn consume_token(&mut self, token_type: TokenType) -> ParserResult<bool> { fn consume_token<F>(&mut self, token_type: TokenType, err_fn: F) -> ParserResult<()>
/* self.next_token().and_then(|token| { where
if token.token_type == token_type { F: Fn(Token) -> ParserError,
Some(token) {
} else { /* let token = self.next_token();
// Err(ParserError::UnexpectedToken { token })
None
}
}) */
Ok(self.next_token().token_type == token_type) if token.token_type == token_type {
Ok(())
} else {
Err(err_fn(token))
} */ } */
match &self.peek_token().token_type {
tt if tt == &token_type => {
let _ = self.next_token();
Ok(())
}
TokenType::EOF => Err(err_fn(self.peek_token().clone())),
_ => Err(err_fn(self.next_token())),
}
}
} }

View file

@ -1,49 +1,129 @@
use std::fmt::Display; use std::fmt::Display;
use crate::misc::indent;
use super::Expr; use super::Expr;
#[derive(Debug, Clone)]
pub enum Stmt { pub enum Stmt {
ExprStmt { expr: Box<Expr> }, Print {
Print { expr: Box<Expr> }, expr: Box<Expr>,
VarDecl { name: String, initializer: Box<Expr> }, },
Block { statements: Vec<Stmt> }, IfStmt {
condition: Box<Expr>,
then_branch: Box<Stmt>,
else_branch: Option<Box<Stmt>>,
},
While {
condition: Box<Expr>,
body: Box<Stmt>,
},
VarDecl {
name: String,
initializer: Box<Expr>,
},
Block {
statements: Vec<Stmt>,
},
ExprStmt {
expr: Box<Expr>,
},
Break,
Return {
expr: Box<Expr>,
},
} }
impl 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 { pub fn print_stmt(expr: Expr) -> Self {
let expr = Box::new(expr); let expr = Box::new(expr);
Stmt::Print { expr } Stmt::Print { expr }
} }
pub fn var_decl(name: String, initializer: Expr) -> Self { pub fn if_stmt(
let initializer = Box::new(initializer); condition: impl Into<Box<Expr>>,
then_branch: impl Into<Box<Stmt>>,
else_branch: Option<impl Into<Box<Stmt>>>,
) -> Self {
let condition = condition.into();
let then_branch = then_branch.into();
let else_branch = else_branch.map(|stmt| stmt.into());
Stmt::IfStmt {
condition,
then_branch,
else_branch,
}
}
pub fn while_stmt(condition: impl Into<Box<Expr>>, body: impl Into<Box<Stmt>>) -> Self {
let condition = condition.into();
let body = body.into();
Stmt::While { condition, body }
}
pub fn var_decl(name: impl Into<String>, initializer: impl Into<Box<Expr>>) -> Self {
let name = name.into();
let initializer = initializer.into();
Stmt::VarDecl { name, initializer } Stmt::VarDecl { name, initializer }
} }
pub fn expr_stmt(expr: impl Into<Box<Expr>>) -> Self {
let expr = expr.into();
Stmt::ExprStmt { expr }
}
pub fn return_stmt(expr: impl Into<Box<Expr>>) -> Self {
let expr = expr.into();
Stmt::Return { expr }
}
} }
impl Display for Stmt { impl Display for Stmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Stmt::ExprStmt { expr } => write!(f, "{expr}"), Stmt::Print { expr } => write!(f, "print {expr};"),
Stmt::Print { expr } => write!(f, "print {expr}"), Stmt::IfStmt {
Stmt::VarDecl { name, initializer } => write!(f, "var {name} = {initializer}"), condition,
then_branch,
else_branch,
} => {
writeln!(f, "if {condition}")?;
match then_branch.as_ref() {
Stmt::Block { .. } => write!(f, "{then_branch}")?,
_ => write!(f, "{}", indent(format!("{then_branch}")))?,
}
if let Some(else_branch) = else_branch {
writeln!(f, "\nelse")?;
match else_branch.as_ref() {
Stmt::Block { .. } => write!(f, "{else_branch}")?,
_ => write!(f, "{}", indent(format!("{else_branch}")))?,
}
}
Ok(())
}
Stmt::While { condition, body } => {
writeln!(f, "{condition}")?;
match body.as_ref() {
Stmt::Block { .. } => write!(f, "{body}")?,
_ => write!(f, "{}", indent(format!("{body}")))?,
}
Ok(())
}
Stmt::VarDecl { name, initializer } => write!(f, "var {name} = {initializer};"),
Stmt::Block { statements } => { Stmt::Block { statements } => {
writeln!(f, "{{")?; writeln!(f, "{{")?;
for statement in statements { for statement in statements {
// for each statement: statement to string, split by lines, preprend each line with tab, print write!(f, "{}", indent(format!("{statement}")))?;
// 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, "}}") write!(f, "}}")
} }
Stmt::ExprStmt { expr } => write!(f, "{expr};"),
Stmt::Break => write!(f, "break;"),
Stmt::Return { expr } => {
write!(f, "return {expr};")
}
} }
} }
} }