use crate::{
compilation::{
Lexer, Parser,
error::CompilationError,
precedence::Precedence,
token::{Token, TokenKind},
},
execution::{Chunk, op_code::OpCode},
};
use super::PrefixParselet;
#[derive(Clone)]
pub struct UnaryParselet;
impl PrefixParselet for UnaryParselet {
fn parse(
&self,
lexer: &mut Lexer,
parser: &mut Parser,
chunk: &mut Chunk,
_token: Token,
) -> Result<(), CompilationError> {
let token = parser.current();
if parser.next().kind == TokenKind::None {
return Err(CompilationError::ExpressionExpected {
token: "None".into(),
pos: parser.next().line,
});
}
parser.with_precedence(lexer, Precedence::Unary, chunk)?;
match token.kind {
TokenKind::Bang => {
parser.emit_byte(OpCode::Not as u8, chunk);
Ok(())
}
TokenKind::Minus => {
parser.emit_byte(OpCode::Negate as u8, chunk);
Ok(())
}
TokenKind::Plus => {
Ok(())
}
TokenKind::Tilde => {
parser.emit_byte(OpCode::BitwiseNot as u8, chunk);
Ok(())
}
_ => Err(CompilationError::Unreachable {
file: file!().into(),
line: line!(),
}),
}
}
}
#[cfg(test)]
mod tests {
use alloc::{collections::btree_map::BTreeMap, string::String};
use super::*;
const fn is_normal<T: Sized + Send + Sync>() {}
#[test]
const fn normal_types() {
is_normal::<&UnaryParselet>();
is_normal::<UnaryParselet>();
}
#[test]
fn parse_rejects_non_unary_current_token() {
let enums = BTreeMap::<String, i8>::new();
let mut lexer = Lexer::new(&enums, "1 2");
let mut parser = Parser::new();
let mut chunk = Chunk::default();
assert!(parser.advance(&mut lexer).is_ok());
assert!(parser.advance(&mut lexer).is_ok());
let token = parser.current();
let result = UnaryParselet.parse(&mut lexer, &mut parser, &mut chunk, token);
assert!(matches!(result, Err(CompilationError::Unreachable { .. })));
}
}