lox_one 0.1.0

A tree-walking interpreter for the Lox programming language.
Documentation
use crate::function::FunDecl;
use crate::lox_value::LoxValue;

use crate::token::{Position, Token};

use std::fmt::{self, Debug};

#[derive(Debug, Clone)]
pub enum Expr {
    Identifier(String, Position),
    Value {
        value: LoxValue,
        position: Position,
    },
    Grouping(Box<Expr>, Position),
    Unary {
        op: Token,
        rhs: Box<Expr>,
        position: Position,
    },
    Binary {
        lhs: Box<Expr>,
        op: Token,
        rhs: Box<Expr>,
        position: Position,
    },
    Ternary {
        condition: Box<Expr>,
        result_1: Box<Expr>,
        result_2: Box<Expr>,
        position: Position,
    },
    Assignment {
        name: String,
        value: Box<Expr>,
        position: Position,
    },
    Call {
        callee: Box<Expr>,
        arguments: Vec<Expr>,
        position: Position,
    },
}

impl Expr {
    pub fn get_position(&self) -> Position {
        use Expr::*;
        match self {
            Identifier(_, p) => p.to_owned(),
            Value { position, .. } => position.clone(),
            Grouping(_, position) => position.clone(),
            Unary { position, .. } => position.clone(),
            Binary { position, .. } => position.clone(),
            Ternary { position, .. } => position.clone(),
            Assignment { position, .. } => position.clone(),
            Call { position, .. } => position.clone(),
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use Expr::*;

        match self {
            Value { value, position: _ } => write!(f, "{}", value),
            Grouping(expr, _position) => write!(f, "({})", expr),
            Unary {
                op,
                rhs,
                position: _,
            } => write!(f, "{} {}", op.token_type, rhs),
            Binary {
                lhs,
                op,
                rhs,
                position: _,
            } => write!(f, "{} {} {}", lhs, op.token_type, rhs),
            Ternary {
                condition,
                result_1,
                result_2,
                position: _,
            } => write!(f, "{} ? {} : {}", condition, result_1, result_2),
            Identifier(name, _position) => write!(f, "{}", name),
            Assignment {
                name,
                value,
                position: _,
            } => write!(f, "{} = {}", name, value),
            Call {
                callee,
                arguments,
                position: _,
            } => {
                let args = if arguments.len() == 0 {
                    String::new()
                } else {
                    arguments
                        .iter()
                        .fold(format!("{}", arguments[0]), |acc, arg| {
                            format!("{}, {}", acc, arg)
                        })
                };

                write!(f, "{}({})", callee, args)
            }
        }
    }
}

#[derive(Debug, Clone)]
pub enum Stmt {
    PrintStmt(Expr),
    ExprStmt(Expr),
    Var {
        name: String,
        initializer: Expr,
        postion: Position,
    },
    Block(Vec<Stmt>),
    IfStmt {
        condition: Expr,
        then_branch: Box<Stmt>,
        else_branch: Option<Box<Stmt>>,
        position: Position,
    },
    WhileStmt {
        condition: Expr,
        body: Box<Stmt>,
        position: Position,
    },
    BreakStmt(Position),
    ContinueStmt(Position),
    FunStmt {
        fun_declaration: FunDecl,
        position: Position,
    },
    ReturnStmt {
        expr: Option<Expr>,
        position: Position,
    },
}

impl fmt::Display for Stmt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use Stmt::*;

        match self {
            PrintStmt(expr) => write!(f, "print {};", expr),
            ExprStmt(expr) => write!(f, "{};", expr),
            Var {
                name,
                initializer,
                postion: _,
            } => write!(f, "var {} = {}", name, initializer),
            Block(declarations) => {
                let repr = declarations.iter().fold(String::from("{\n"), |acc, stmt| {
                    format!("{}    {}\n", acc, stmt)
                });

                write!(f, "{}}}", repr)
            }
            IfStmt {
                condition,
                then_branch,
                else_branch,
                position: _,
            } => match else_branch {
                None => write!(f, "if ({}) {}", condition, then_branch,),
                Some(stmt) => write!(f, "if ({}) {} else {}", condition, then_branch, stmt),
            },
            WhileStmt {
                condition,
                body,
                position: _,
            } => write!(f, "while ({}) {}", condition, body),
            BreakStmt(_position) => write!(f, "break ;"),
            ContinueStmt(_position) => write!(f, "continue ;"),
            FunStmt {
                fun_declaration: FunDecl { name, params, body },
                position: _,
            } => {
                let params_repr = if params.len() == 0 {
                    String::new()
                } else {
                    params.iter().fold(format!("{}", params[0]), |acc, arg| {
                        format!("{}, {}", acc, arg)
                    })
                };

                write!(f, "fun {}({}) {:?}", name, params_repr, body)
            }
            ReturnStmt { expr, position: _ } => {
                if let Some(expr) = expr {
                    write!(f, "return {};", expr)
                } else {
                    write!(f, "return ;")
                }
            }
        }
    }
}