Skip to content

Commit

Permalink
#9 - add prefix ops to parser
Browse files Browse the repository at this point in the history
  • Loading branch information
danilopedraza committed Feb 7, 2024
1 parent 5233947 commit 87ca23e
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(),
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{iter::Peekable, str::Chars, vec};
pub enum Token {
Arrow,
Assign,
Bang,
BitwiseAnd,
BitwiseOr,
BitwiseXor,
Expand Down Expand Up @@ -32,6 +33,7 @@ pub enum Token {
RightShift,
Rparen,
Over,
Tilde,
Times,
ToThe,
True,
Expand All @@ -53,6 +55,7 @@ impl Iterator for Lexer<'_> {
self.next()
}
Some(chr) => Some(match chr {
'!' => Token::Bang,
'^' => Token::BitwiseXor,
',' => Token::Comma,
'.' => Token::Dot,
Expand All @@ -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,
Expand Down
51 changes: 51 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum Precedence {
Multiplication,
Exponentiation,
Correspondence,
Highest,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -95,6 +96,24 @@ impl InfixOperator {
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PrefixOperator {
BitwiseNot,
LogicNot,
Minus,
}

impl PrefixOperator {
fn from(tok: Token) -> Option<Self> {
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),
Expand All @@ -103,6 +122,7 @@ pub enum ASTNode {
Infix(InfixOperator, Box<ASTNode>, Box<ASTNode>),
Integer(String),
Let(Box<ASTNode>, Vec<ASTNode>, Box<ASTNode>),
Prefix(PrefixOperator, Box<ASTNode>),
Signature(Box<ASTNode>, Option<Box<ASTNode>>),
Symbol(String),
Tuple(Vec<ASTNode>),
Expand Down Expand Up @@ -238,6 +258,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
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,
Expand Down Expand Up @@ -268,6 +291,11 @@ impl<T: Iterator<Item = Token>> Parser<T> {
.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();
Expand Down Expand Up @@ -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"))),
)),
))
)))
);
}
}

0 comments on commit 87ca23e

Please sign in to comment.