zaplib_shader_compiler 0.0.3

The shader compiler for Zaplib
Documentation
use crate::detok::*;
use crate::error::ParseError;
use crate::ident::{Ident, IdentPath};
use crate::lit::Lit;
use crate::shaderast::*;
use crate::span::Span;
use crate::token::Token;
use crate::ty::{TyExpr, TyExprKind};
use std::cell::{Cell, RefCell};

impl<'a> DeTokParserImpl<'a> {
    pub(crate) fn parse_shader(&mut self) -> Result<ShaderAst, ParseError> {
        let mut shader_ast = ShaderAst::default();

        while self.peek_token() != Token::Eof {
            match self.peek_token() {
                Token::Ident(ident) if ident == Ident::new("geometry") => {
                    self.skip_token();
                    let decl = self.parse_geometry_decl()?;
                    shader_ast.decls.push(Decl::Geometry(decl));
                }
                Token::Const => {
                    let decl = self.parse_const_decl()?;
                    shader_ast.decls.push(Decl::Const(decl));
                }
                Token::Fn => {
                    let decl = self.parse_fn_decl(None)?;
                    shader_ast.decls.push(Decl::Fn(decl));
                }
                Token::Ident(ident) if ident == Ident::new("impl") => {
                    self.skip_token();
                    let prefix = self.parse_ident()?;
                    self.expect_token(Token::LeftBrace)?;
                    while !self.accept_token(Token::RightBrace) {
                        let decl = self.parse_fn_decl(Some(prefix))?;
                        shader_ast.decls.push(Decl::Fn(decl));
                    }
                }
                Token::Struct => {
                    let decl = self.parse_struct_decl()?;
                    shader_ast.decls.push(Decl::Struct(decl));
                }
                Token::Ident(ident) if ident == Ident::new("instance") => {
                    self.skip_token();
                    let decl = self.parse_instance_decl()?;
                    shader_ast.decls.push(Decl::Instance(decl));
                }
                Token::Ident(ident) if ident == Ident::new("texture") => {
                    self.skip_token();
                    let decl = self.parse_texture_decl()?;
                    shader_ast.decls.push(Decl::Texture(decl));
                }
                Token::Ident(ident) if ident == Ident::new("uniform") => {
                    self.skip_token();
                    let decl = self.parse_uniform_decl()?;
                    shader_ast.decls.push(Decl::Uniform(decl));
                }
                Token::Ident(ident) if ident == Ident::new("varying") => {
                    self.skip_token();
                    let decl = self.parse_varying_decl()?;
                    shader_ast.decls.push(Decl::Varying(decl));
                }
                Token::Ident(ident) if ident == Ident::new("debug") => {
                    self.skip_token();
                    shader_ast.debug = true;
                }
                token => return Err(self.error(format!("unexpected token while parsing shader `{}`", token))),
            }
        }
        Ok(shader_ast)
    }

    fn parse_const_decl(&mut self) -> Result<ConstDecl, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::Const)?;
        let ident = self.parse_ident()?;
        self.expect_token(Token::Colon)?;
        let ty_expr = self.parse_ty_expr()?;
        self.expect_token(Token::Eq)?;
        let expr = self.parse_expr()?;
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| ConstDecl { span, ident, ty_expr, expr }))
    }

    fn parse_fn_decl(&mut self, prefix: Option<Ident>) -> Result<FnDecl, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::Fn)?;
        let ident_path = if let Some(prefix) = prefix {
            IdentPath::from_two_idents(prefix, self.parse_ident()?)
        } else {
            IdentPath::from_ident(self.parse_ident()?)
        };

        self.expect_token(Token::LeftParen)?;
        let mut params = Vec::new();
        if !self.accept_token(Token::RightParen) {
            if let Some(prefix) = prefix {
                let span = self.begin_span();
                let is_inout = self.accept_token(Token::Inout);
                if self.accept_ident("self") {
                    params.push(span.end(self, |span| Param {
                        span,
                        is_inout,
                        ident: Ident::new("self"),
                        ty_expr: TyExpr {
                            ty: RefCell::new(None),
                            kind: TyExprKind::Var { span: Span::default(), ident: prefix },
                        },
                    }))
                } else {
                    let ident = self.parse_ident()?;
                    self.expect_token(Token::Colon)?;
                    let ty_expr = self.parse_ty_expr()?;
                    params.push(span.end(self, |span| Param { span, is_inout, ident, ty_expr }));
                }
            } else {
                params.push(self.parse_param()?);
            }
            while self.accept_token(Token::Comma) {
                params.push(self.parse_param()?);
            }
            self.expect_token(Token::RightParen)?;
        }
        let return_ty_expr = if self.accept_token(Token::Arrow) { Some(self.parse_ty_expr()?) } else { None };
        let block = self.parse_block()?;

        Ok(span.end(self, |span| FnDecl {
            span,
            return_ty: RefCell::new(None),
            is_used_in_vertex_shader: Cell::new(None),
            is_used_in_fragment_shader: Cell::new(None),
            callees: RefCell::new(None),
            uniform_block_deps: RefCell::new(None),
            has_texture_deps: Cell::new(None),
            geometry_deps: RefCell::new(None),
            instance_deps: RefCell::new(None),
            has_varying_deps: Cell::new(None),
            cons_fn_deps: RefCell::new(None),
            ident_path,
            params,
            return_ty_expr,
            block,
        }))
    }

    fn parse_geometry_decl(&mut self) -> Result<GeometryDecl, ParseError> {
        let span = self.begin_span();
        let ident = self.parse_ident()?;
        self.expect_token(Token::Colon)?;
        let ty_expr = self.parse_prim_ty_expr()?;
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| GeometryDecl { is_used_in_fragment_shader: Cell::new(None), span, ident, ty_expr }))
    }

    fn parse_instance_decl(&mut self) -> Result<InstanceDecl, ParseError> {
        let span = self.begin_span();
        let ident = self.parse_ident()?;
        self.expect_token(Token::Colon)?;
        let ty_expr = self.parse_prim_ty_expr()?;
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| InstanceDecl { is_used_in_fragment_shader: Cell::new(None), span, ident, ty_expr }))
    }

    fn parse_texture_decl(&mut self) -> Result<TextureDecl, ParseError> {
        let span = self.begin_span();
        let ident = self.parse_ident()?;
        self.expect_token(Token::Colon)?;
        let ty_expr = self.parse_prim_ty_expr()?;
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| TextureDecl { span, ident, ty_expr }))
    }

    fn parse_uniform_decl(&mut self) -> Result<UniformDecl, ParseError> {
        let span = self.begin_span();
        let ident = self.parse_ident()?;
        self.expect_token(Token::Colon)?;
        let ty_expr = self.parse_prim_ty_expr()?;
        let block_ident = if self.accept_ident("in") { Some(self.parse_ident()?) } else { None };
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| UniformDecl { span, ident, ty_expr, block_ident }))
    }

    fn parse_struct_decl(&mut self) -> Result<StructDecl, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::Struct)?;
        let ident = self.parse_ident()?;
        self.expect_token(Token::LeftBrace)?;
        let mut fields = Vec::new();
        loop {
            fields.push(self.parse_field()?);
            if !self.accept_token(Token::Comma) {
                break;
            }
        }
        self.expect_token(Token::RightBrace)?;
        Ok(span.end(self, |span| StructDecl { span, ident, fields }))
    }

    fn parse_varying_decl(&mut self) -> Result<VaryingDecl, ParseError> {
        let span = self.begin_span();
        let ident = self.parse_ident()?;
        self.expect_token(Token::Colon)?;
        let ty_expr = self.parse_ty_expr()?;
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| VaryingDecl { span, ident, ty_expr }))
    }

    fn parse_param(&mut self) -> Result<Param, ParseError> {
        let span = self.begin_span();
        let is_inout = self.accept_token(Token::Inout);
        let ident = self.parse_ident()?;
        self.expect_token(Token::Colon)?;
        let ty_expr = self.parse_ty_expr()?;
        Ok(span.end(self, |span| Param { span, is_inout, ident, ty_expr }))
    }

    fn parse_field(&mut self) -> Result<Field, ParseError> {
        let ident = self.parse_ident()?;
        self.expect_token(Token::Colon)?;
        let ty_expr = self.parse_ty_expr()?;
        Ok(Field { ident, ty_expr })
    }

    fn parse_block(&mut self) -> Result<Block, ParseError> {
        self.expect_token(Token::LeftBrace)?;
        let mut stmts = Vec::new();
        while !self.accept_token(Token::RightBrace) {
            stmts.push(self.parse_stmt()?);
        }
        Ok(Block { stmts })
    }

    fn parse_stmt(&mut self) -> Result<Stmt, ParseError> {
        match self.peek_token() {
            Token::Break => self.parse_break_stmt(),
            Token::Continue => self.parse_continue_stmt(),
            Token::For => self.parse_for_stmt(),
            Token::If => self.parse_if_stmt(),
            Token::Let => self.parse_let_stmt(),
            Token::Return => self.parse_return_stmt(),
            _ => self.parse_expr_stmt(),
        }
    }

    fn parse_break_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::Break)?;
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| Stmt::Break { span }))
    }

    fn parse_continue_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::Continue)?;
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| Stmt::Continue { span }))
    }

    fn parse_for_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::For)?;
        let ident = self.parse_ident()?;
        self.expect_ident("from")?;
        let from_expr = self.parse_expr()?;
        self.expect_ident("to")?;
        let to_expr = self.parse_expr()?;
        let step_expr = if self.accept_ident("step") { Some(self.parse_expr()?) } else { None };
        let block = Box::new(self.parse_block()?);
        Ok(span.end(self, |span| Stmt::For { span, ident, from_expr, to_expr, step_expr, block }))
    }

    fn parse_if_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::If)?;
        let expr = self.parse_expr()?;
        let block_if_true = Box::new(self.parse_block()?);
        let block_if_false = if self.accept_token(Token::Else) {
            if self.peek_token() == Token::If {
                Some(Box::new(Block { stmts: vec![self.parse_if_stmt()?] }))
            } else {
                Some(Box::new(self.parse_block()?))
            }
        } else {
            None
        };
        Ok(span.end(self, |span| Stmt::If { span, expr, block_if_true, block_if_false }))
    }

    fn parse_let_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::Let)?;
        let ident = self.parse_ident()?;
        let ty_expr = if self.accept_token(Token::Colon) { Some(self.parse_ty_expr()?) } else { None };
        let expr = if self.accept_token(Token::Eq) { Some(self.parse_expr()?) } else { None };
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| Stmt::Let { span, ty: RefCell::new(None), ident, ty_expr, expr }))
    }

    fn parse_return_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.begin_span();
        self.expect_token(Token::Return)?;
        let expr = if !self.accept_token(Token::Semi) {
            let expr = self.parse_expr()?;
            self.expect_token(Token::Semi)?;
            Some(expr)
        } else {
            None
        };
        Ok(span.end(self, |span| Stmt::Return { span, expr }))
    }

    fn parse_expr_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.begin_span();
        let expr = self.parse_expr()?;
        self.expect_token(Token::Semi)?;
        Ok(span.end(self, |span| Stmt::Expr { span, expr }))
    }

    fn parse_ty_expr(&mut self) -> Result<TyExpr, ParseError> {
        let span = self.begin_span();
        let mut acc = self.parse_prim_ty_expr()?;
        if self.accept_token(Token::LeftBracket) {
            let elem_ty_expr = Box::new(acc);
            match self.peek_token() {
                Token::Lit(Lit::Int(len)) => {
                    self.skip_token();
                    self.expect_token(Token::RightBracket)?;
                    acc = span.end(self, |span| TyExpr {
                        ty: RefCell::new(None),
                        kind: TyExprKind::Array { span, elem_ty_expr, len: len as u32 },
                    });
                }
                token => return Err(span.error(self, format!("unexpected token `{}`", token))),
            }
        }
        Ok(acc)
    }

    fn parse_prim_ty_expr(&mut self) -> Result<TyExpr, ParseError> {
        let span = self.begin_span();
        match self.peek_token() {
            Token::TyLit(ty_lit) => {
                self.skip_token();
                Ok(span.end(self, |span| TyExpr { ty: RefCell::new(None), kind: TyExprKind::Lit { span, ty_lit } }))
            }
            Token::Ident(ident) => {
                self.skip_token();
                Ok(span.end(self, |span| TyExpr { ty: RefCell::new(None), kind: TyExprKind::Var { span, ident } }))
            }
            token => Err(span.error(self, format!("unexpected token `{}`", token))),
        }
    }

    fn parse_expr(&mut self) -> Result<Expr, ParseError> {
        self.parse_assign_expr()
    }

    fn parse_assign_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let expr = self.parse_cond_expr()?;
        Ok(if let Some(op) = self.peek_token().to_assign_op() {
            self.skip_token();
            let left_expr = Box::new(expr);
            let right_expr = Box::new(self.parse_assign_expr()?);
            span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Bin { span, op, left_expr, right_expr },
            })
        } else {
            expr
        })
    }

    fn parse_cond_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let expr = self.parse_or_expr()?;
        Ok(if self.accept_token(Token::Question) {
            let expr = Box::new(expr);
            let expr_if_true = Box::new(self.parse_expr()?);
            self.expect_token(Token::Colon)?;
            let expr_if_false = Box::new(self.parse_cond_expr()?);
            span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Cond { span, expr, expr_if_true, expr_if_false },
            })
        } else {
            expr
        })
    }

    fn parse_or_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let mut acc = self.parse_and_expr()?;
        while let Some(op) = self.peek_token().to_or_op() {
            self.skip_token();
            let left_expr = Box::new(acc);
            let right_expr = Box::new(self.parse_and_expr()?);
            acc = span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Bin { span, op, left_expr, right_expr },
            });
        }
        Ok(acc)
    }

    fn parse_and_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let mut acc = self.parse_eq_expr()?;
        while let Some(op) = self.peek_token().to_and_op() {
            self.skip_token();
            let left_expr = Box::new(acc);
            let right_expr = Box::new(self.parse_eq_expr()?);
            acc = span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Bin { span, op, left_expr, right_expr },
            });
        }
        Ok(acc)
    }

    fn parse_eq_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let mut acc = self.parse_rel_expr()?;
        while let Some(op) = self.peek_token().to_eq_op() {
            self.skip_token();
            let left_expr = Box::new(acc);
            let right_expr = Box::new(self.parse_rel_expr()?);
            acc = span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Bin { span, op, left_expr, right_expr },
            });
        }
        Ok(acc)
    }

    fn parse_rel_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let mut acc = self.parse_add_expr()?;
        while let Some(op) = self.peek_token().to_rel_op() {
            self.skip_token();
            let left_expr = Box::new(acc);
            let right_expr = Box::new(self.parse_add_expr()?);
            acc = span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Bin { span, op, left_expr, right_expr },
            });
        }
        Ok(acc)
    }

    fn parse_add_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let mut acc = self.parse_mul_expr()?;
        while let Some(op) = self.peek_token().to_add_op() {
            self.skip_token();
            let left_expr = Box::new(acc);
            let right_expr = Box::new(self.parse_mul_expr()?);
            acc = span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Bin { span, op, left_expr, right_expr },
            });
        }
        Ok(acc)
    }

    fn parse_mul_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let mut acc = self.parse_un_expr()?;
        while let Some(op) = self.peek_token().to_mul_op() {
            self.skip_token();
            let left_expr = Box::new(acc);
            let right_expr = Box::new(self.parse_un_expr()?);
            acc = span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Bin { span, op, left_expr, right_expr },
            });
        }
        Ok(acc)
    }

    fn parse_un_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        Ok(if let Some(op) = self.peek_token().to_un_op() {
            self.skip_token();
            let expr = Box::new(self.parse_un_expr()?);
            span.end(self, |span| Expr {
                span,
                ty: RefCell::new(None),
                const_val: RefCell::new(None),
                const_index: Cell::new(None),
                kind: ExprKind::Un { span, op, expr },
            })
        } else {
            self.parse_postfix_expr()?
        })
    }

    fn parse_postfix_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        let mut acc = self.parse_prim_expr()?;
        loop {
            match self.peek_token() {
                Token::Dot => {
                    self.skip_token();
                    let ident = self.parse_ident()?;
                    acc = if self.accept_token(Token::LeftParen) {
                        let mut arg_exprs = vec![acc];
                        if !self.accept_token(Token::RightParen) {
                            loop {
                                arg_exprs.push(self.parse_expr()?);
                                if !self.accept_token(Token::Comma) {
                                    break;
                                }
                            }
                            self.expect_token(Token::RightParen)?;
                        }
                        span.end(self, |span| Expr {
                            span,
                            ty: RefCell::new(None),
                            const_val: RefCell::new(None),
                            const_index: Cell::new(None),
                            kind: ExprKind::MethodCall { span, ident, arg_exprs },
                        })
                    } else {
                        let expr = Box::new(acc);
                        span.end(self, |span| Expr {
                            span,
                            ty: RefCell::new(None),
                            const_val: RefCell::new(None),
                            const_index: Cell::new(None),
                            kind: ExprKind::Field { span, expr, field_ident: ident },
                        })
                    }
                }
                Token::LeftBracket => {
                    self.skip_token();
                    let expr = Box::new(acc);
                    let index_expr = Box::new(self.parse_expr()?);
                    self.expect_token(Token::RightBracket)?;
                    acc = span.end(self, |span| Expr {
                        span,
                        ty: RefCell::new(None),
                        const_val: RefCell::new(None),
                        const_index: Cell::new(None),
                        kind: ExprKind::Index { span, expr, index_expr },
                    });
                }
                _ => break,
            }
        }
        Ok(acc)
    }

    fn parse_prim_expr(&mut self) -> Result<Expr, ParseError> {
        let span = self.begin_span();
        match self.peek_token() {
            Token::TyLit(ty_lit) => {
                self.skip_token();
                self.expect_token(Token::LeftParen)?;
                let mut arg_exprs = Vec::new();
                if !self.accept_token(Token::RightParen) {
                    loop {
                        arg_exprs.push(self.parse_expr()?);
                        if !self.accept_token(Token::Comma) {
                            break;
                        }
                    }
                    self.expect_token(Token::RightParen)?;
                }
                Ok(span.end(self, |span| Expr {
                    span,
                    ty: RefCell::new(None),
                    const_val: RefCell::new(None),
                    const_index: Cell::new(None),
                    kind: ExprKind::ConsCall { span, ty_lit, arg_exprs },
                }))
            }
            Token::Ident(_) => {
                let ident_path = self.parse_ident_path()?;
                match self.peek_token() {
                    Token::LeftParen => {
                        let arg_exprs = self.parse_arg_exprs()?;
                        Ok(span.end(self, |span| Expr {
                            span,
                            ty: RefCell::new(None),
                            const_val: RefCell::new(None),
                            const_index: Cell::new(None),
                            kind: ExprKind::Call { span, ident_path, arg_exprs },
                        }))
                    }
                    _ => Ok(span.end(self, |span| Expr {
                        span,
                        ty: RefCell::new(None),
                        const_val: RefCell::new(None),
                        const_index: Cell::new(None),
                        kind: ExprKind::Var { span, kind: Cell::new(None), ident_path },
                    })),
                }
            }
            Token::Lit(lit) => {
                self.skip_token();
                Ok(span.end(self, |span| Expr {
                    span,
                    ty: RefCell::new(None),
                    const_val: RefCell::new(None),
                    const_index: Cell::new(None),
                    kind: ExprKind::Lit { span, lit },
                }))
            }
            Token::LeftParen => {
                self.skip_token();
                let expr = self.parse_expr()?;
                self.expect_token(Token::RightParen)?;
                Ok(expr)
            }
            token => Err(span.error(self, format!("unexpected token `{}`", token))),
        }
    }

    fn parse_arg_exprs(&mut self) -> Result<Vec<Expr>, ParseError> {
        self.expect_token(Token::LeftParen)?;
        let mut arg_exprs = Vec::new();
        if !self.accept_token(Token::RightParen) {
            loop {
                arg_exprs.push(self.parse_expr()?);
                if !self.accept_token(Token::Comma) {
                    break;
                }
            }
            self.expect_token(Token::RightParen)?;
        }
        Ok(arg_exprs)
    }
}

impl Token {
    fn to_assign_op(self) -> Option<BinOp> {
        match self {
            Token::Eq => Some(BinOp::Assign),
            Token::PlusEq => Some(BinOp::AddAssign),
            Token::MinusEq => Some(BinOp::SubAssign),
            Token::StarEq => Some(BinOp::MulAssign),
            Token::SlashEq => Some(BinOp::DivAssign),
            _ => None,
        }
    }

    fn to_or_op(self) -> Option<BinOp> {
        match self {
            Token::OrOr => Some(BinOp::Or),
            _ => None,
        }
    }

    fn to_and_op(self) -> Option<BinOp> {
        match self {
            Token::AndAnd => Some(BinOp::And),
            _ => None,
        }
    }

    fn to_eq_op(self) -> Option<BinOp> {
        match self {
            Token::EqEq => Some(BinOp::Eq),
            Token::NotEq => Some(BinOp::Ne),
            _ => None,
        }
    }

    fn to_rel_op(self) -> Option<BinOp> {
        match self {
            Token::Lt => Some(BinOp::Lt),
            Token::LtEq => Some(BinOp::Le),
            Token::Gt => Some(BinOp::Gt),
            Token::GtEq => Some(BinOp::Ge),
            _ => None,
        }
    }

    fn to_add_op(self) -> Option<BinOp> {
        match self {
            Token::Plus => Some(BinOp::Add),
            Token::Minus => Some(BinOp::Sub),
            _ => None,
        }
    }

    fn to_mul_op(self) -> Option<BinOp> {
        match self {
            Token::Star => Some(BinOp::Mul),
            Token::Slash => Some(BinOp::Div),
            _ => None,
        }
    }

    fn to_un_op(self) -> Option<UnOp> {
        match self {
            Token::Not => Some(UnOp::Not),
            Token::Minus => Some(UnOp::Neg),
            _ => None,
        }
    }
}