use crate::{
compilation::{
Lexer, Parser,
error::CompilationError,
precedence::Precedence,
token::{Token, TokenKind},
},
execution::{Chunk, op_code::OpCode},
};
use super::InfixParselet;
#[derive(Clone, Copy, Debug)]
pub enum LogicKind {
BitAnd,
And,
BitXor,
Or,
BitOr,
Ternary,
}
impl LogicKind {
const fn precedence(self) -> Precedence {
match self {
Self::BitAnd => Precedence::BitAnd,
Self::And => Precedence::And,
Self::BitXor => Precedence::BitXor,
Self::Or => Precedence::Or,
Self::BitOr => Precedence::BitOr,
Self::Ternary => Precedence::Ternary,
}
}
const fn higher(self) -> Precedence {
match self {
Self::BitAnd => Precedence::Equality,
Self::And => Precedence::BitOr,
Self::BitXor => Precedence::BitAnd,
Self::Or => Precedence::And,
Self::BitOr => Precedence::BitXor,
Self::Ternary => Precedence::Or,
}
}
}
#[derive(Clone)]
pub struct LogicParselet {
kind: LogicKind,
}
impl LogicParselet {
pub const fn new(kind: LogicKind) -> Self {
Self { kind }
}
}
impl InfixParselet for LogicParselet {
fn parse(
&self,
lexer: &mut Lexer,
parser: &mut Parser,
chunk: &mut Chunk,
_token: Token,
) -> Result<(), CompilationError> {
let higher = self.kind.higher();
match self.kind {
LogicKind::BitAnd => {
parser.with_precedence(lexer, higher, chunk)?;
parser.emit_byte(OpCode::BitwiseAnd as u8, chunk);
Ok(())
}
LogicKind::And => {
let target_pos = parser.emit_jump(OpCode::JmpIfFalse as u8, chunk);
parser.emit_byte(OpCode::Pop as u8, chunk);
parser.with_precedence(lexer, higher, chunk)?;
Parser::patch_jump(target_pos, chunk);
Ok(())
}
LogicKind::BitXor => {
parser.with_precedence(lexer, higher, chunk)?;
parser.emit_byte(OpCode::BitwiseXor as u8, chunk);
Ok(())
}
LogicKind::Or => {
let target_pos = parser.emit_jump(OpCode::JmpIfTrue as u8, chunk);
parser.emit_byte(OpCode::Pop as u8, chunk);
parser.with_precedence(lexer, higher, chunk)?;
Parser::patch_jump(target_pos, chunk);
Ok(())
}
LogicKind::BitOr => {
parser.with_precedence(lexer, higher, chunk)?;
parser.emit_byte(OpCode::BitwiseOr as u8, chunk);
Ok(())
}
LogicKind::Ternary => {
let else_pos = parser.emit_jump(OpCode::JmpIfFalse as u8, chunk);
parser.emit_byte(OpCode::Pop as u8, chunk);
parser.with_precedence(lexer, higher, chunk)?;
let end_pos = parser.emit_jump(OpCode::Jmp as u8, chunk);
Parser::patch_jump(else_pos, chunk);
parser.consume(lexer, TokenKind::Colon)?;
parser.emit_byte(OpCode::Pop as u8, chunk);
parser.with_precedence(lexer, higher, chunk)?;
Parser::patch_jump(end_pos, chunk);
Ok(())
}
}
}
fn get_precedence(&self) -> Precedence {
self.kind.precedence()
}
}