diff --git a/src/eval.rs b/src/eval.rs index 52b85ec..02661a7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -73,6 +73,7 @@ pub fn eval(node: &ASTNode) -> Type { ASTNode::Tuple(_) => todo!(), ASTNode::Signature(_, _) => todo!(), ASTNode::Infix(op, lhs, rhs) => infix(*op, eval(lhs), eval(rhs)), + ASTNode::Prefix(_, _) => todo!(), } } diff --git a/src/lexer.rs b/src/lexer.rs index e86efdd..2e556c1 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -4,6 +4,7 @@ use std::{iter::Peekable, str::Chars, vec}; pub enum Token { Arrow, Assign, + Bang, BitwiseAnd, BitwiseOr, BitwiseXor, @@ -32,6 +33,7 @@ pub enum Token { RightShift, Rparen, Over, + Tilde, Times, ToThe, True, @@ -53,6 +55,7 @@ impl Iterator for Lexer<'_> { self.next() } Some(chr) => Some(match chr { + '!' => Token::Bang, '^' => Token::BitwiseXor, ',' => Token::Comma, '.' => Token::Dot, @@ -77,6 +80,7 @@ impl Iterator for Lexer<'_> { '*' => self.stars(), '}' => Token::Rbrace, ')' => Token::Rparen, + '~' => Token::Tilde, '0'..='9' => self.integer(chr), chr if chr.is_alphabetic() => self.identifier_or_keyword(chr), _ => Token::Unknown, diff --git a/src/parser.rs b/src/parser.rs index f101a12..ed020ce 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -16,6 +16,7 @@ enum Precedence { Multiplication, Exponentiation, Correspondence, + Highest, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -95,6 +96,24 @@ impl InfixOperator { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum PrefixOperator { + BitwiseNot, + LogicNot, + Minus, +} + +impl PrefixOperator { + fn from(tok: Token) -> Option { + match tok { + Token::Bang => Some(Self::LogicNot), + Token::Minus => Some(Self::Minus), + Token::Tilde => Some(Self::BitwiseNot), + _ => None, + } + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum ASTNode { Boolean(bool), @@ -103,6 +122,7 @@ pub enum ASTNode { Infix(InfixOperator, Box, Box), Integer(String), Let(Box, Vec, Box), + Prefix(PrefixOperator, Box), Signature(Box, Option>), Symbol(String), Tuple(Vec), @@ -238,6 +258,9 @@ impl> Parser { Token::Lbrace => self.set(), Token::Integer(int) => Ok(ASTNode::Integer(int)), Token::Ident(literal) => Ok(ASTNode::Symbol(literal)), + tok if PrefixOperator::from(tok.clone()).is_some() => { + self.prefix(PrefixOperator::from(tok).unwrap()) + } tok => Err(ParserError::UnexpectedTokenError( vec![ Token::Lparen, @@ -268,6 +291,11 @@ impl> Parser { .and_then(|tok| InfixOperator::from(tok.clone())) } + fn prefix(&mut self, op: PrefixOperator) -> NodeResult { + self.expression(Precedence::Highest) + .map(|expr| ASTNode::Prefix(op, Box::new(expr))) + } + fn parenthesis(&mut self) -> NodeResult { if matches!(self.tokens.peek(), Some(&Token::Rparen)) { self.tokens.next(); @@ -814,4 +842,27 @@ mod tests { ]))) ); } + + #[test] + fn prefixes() { + let lexer = build_lexer("!(~1 - -1)"); + + assert_eq!( + parser_from(lexer).next(), + Some(Ok(ASTNode::Prefix( + PrefixOperator::LogicNot, + Box::new(ASTNode::Infix( + InfixOperator::Substraction, + Box::new(ASTNode::Prefix( + PrefixOperator::BitwiseNot, + Box::new(ASTNode::Integer(String::from("1"))), + )), + Box::new(ASTNode::Prefix( + PrefixOperator::Minus, + Box::new(ASTNode::Integer(String::from("1"))), + )), + )) + ))) + ); + } }