use crate::{
compilation::{Lexer, Parser, error::CompilationError, precedence::Precedence, token::Token},
execution::{Chunk, op_code::OpCode},
};
use super::InfixParselet;
#[derive(Clone, Copy, Debug)]
pub enum BinaryKind {
BangEqual,
EqualEqual,
Greater,
GreaterEqual,
Less,
LessEqual,
Plus,
Minus,
Star,
Slash,
}
impl BinaryKind {
const fn precedence(self) -> Precedence {
match self {
Self::BangEqual
| Self::EqualEqual
| Self::GreaterEqual
| Self::LessEqual => Precedence::Equality,
Self::Greater | Self::Less => Precedence::Comparison,
Self::Plus | Self::Minus => Precedence::Term,
Self::Star | Self::Slash => Precedence::Factor,
}
}
const fn higher(self) -> Precedence {
match self {
Self::BangEqual
| Self::EqualEqual
| Self::GreaterEqual
| Self::LessEqual => Precedence::Comparison,
Self::Greater | Self::Less => Precedence::Term,
Self::Plus | Self::Minus => Precedence::Factor,
Self::Star | Self::Slash => Precedence::Unary,
}
}
}
#[derive(Clone)]
pub struct BinaryParselet {
kind: BinaryKind,
}
impl BinaryParselet {
pub const fn new(kind: BinaryKind) -> Self {
Self { kind }
}
}
impl InfixParselet for BinaryParselet {
fn parse(
&self,
lexer: &mut Lexer,
parser: &mut Parser,
chunk: &mut Chunk,
_token: Token,
) -> Result<(), CompilationError> {
parser.with_precedence(lexer, self.kind.higher(), chunk)?;
match self.kind {
BinaryKind::BangEqual => {
parser.emit_bytes(OpCode::Equal as u8, OpCode::Not as u8, chunk);
}
BinaryKind::EqualEqual => {
parser.emit_byte(OpCode::Equal as u8, chunk);
}
BinaryKind::Greater => {
parser.emit_byte(OpCode::Greater as u8, chunk);
}
BinaryKind::GreaterEqual => {
parser.emit_bytes(OpCode::Less as u8, OpCode::Not as u8, chunk);
}
BinaryKind::Less => {
parser.emit_byte(OpCode::Less as u8, chunk);
}
BinaryKind::LessEqual => {
parser.emit_bytes(OpCode::Greater as u8, OpCode::Not as u8, chunk);
}
BinaryKind::Plus => {
parser.emit_byte(OpCode::Add as u8, chunk);
}
BinaryKind::Minus => {
parser.emit_byte(OpCode::Subtract as u8, chunk);
}
BinaryKind::Star => {
parser.emit_byte(OpCode::Multiply as u8, chunk);
}
BinaryKind::Slash => {
parser.emit_byte(OpCode::Divide as u8, chunk);
}
}
Ok(())
}
fn get_precedence(&self) -> Precedence {
self.kind.precedence()
}
}
#[cfg(test)]
mod tests {
use super::*;
const fn is_normal<T: Sized + Send + Sync>() {}
#[test]
const fn normal_types() {
is_normal::<&BinaryParselet>();
is_normal::<BinaryParselet>();
}
}