Chapter 2 (finished)

This commit is contained in:
Devon Tingley 2023-03-06 18:05:40 -05:00
parent 4ad37f9b71
commit 0321e9ba89
4 changed files with 70 additions and 2 deletions

View file

@ -132,6 +132,8 @@ pub enum InfixOperator {
GreaterThan, GreaterThan,
LessThanEqual, LessThanEqual,
GreaterThanEqual, GreaterThanEqual,
Call,
} }
impl InfixOperator { impl InfixOperator {
@ -157,6 +159,8 @@ impl TryFrom<&Token> for InfixOperator {
Token::GreaterThan => Self::GreaterThan, Token::GreaterThan => Self::GreaterThan,
Token::GreaterThanEqual => Self::GreaterThanEqual, Token::GreaterThanEqual => Self::GreaterThanEqual,
Token::LeftParenthesis => Self::Call,
_ => return Err(LexerError::InvalidToken), _ => return Err(LexerError::InvalidToken),
}; };

View file

@ -85,7 +85,12 @@ pub enum Expression {
Function { Function {
parameters: Vec<String>, parameters: Vec<String>,
body: Box<Node>, body: Box<Node>, // block statement
},
Call {
function: Box<Expression>, // ident or function
args: Vec<Expression>,
}, },
} }
@ -159,6 +164,16 @@ impl Display for Expression {
Expression::Function { parameters, body } => { Expression::Function { parameters, body } => {
write!(f, "fn({}) {}", parameters.join(", "), body) write!(f, "fn({}) {}", parameters.join(", "), body)
} }
Expression::Call { function, args } => write!(
f,
"{}({})",
function,
args.iter()
.map(|expr| expr.to_string())
.collect::<Vec<String>>()
.join(", ")
),
} }
} }
} }

View file

@ -161,6 +161,7 @@ fn parse_expression(
None None
| Some(Token::RightParenthesis) | Some(Token::RightParenthesis)
| Some(Token::Semicolon) | Some(Token::Semicolon)
| Some(Token::Comma) // Break used when parsing function arguments
| Some(Token::LeftBrace) // Break used for if statements | Some(Token::LeftBrace) // Break used for if statements
| Some(Token::RightBrace) => break, | Some(Token::RightBrace) => break,
_ => (), _ => (),
@ -315,6 +316,39 @@ fn parse_infix_operator(
lhs: Expression, lhs: Expression,
) -> Result<Expression, ParserError> { ) -> Result<Expression, ParserError> {
let lhs = Box::new(lhs); let lhs = Box::new(lhs);
// Call operators are parsed weirdly
if InfixOperator::Call == operator {
let mut args = Vec::new();
loop {
match tokens.peek() {
Some(Token::Comma) => {
tokens.next();
continue;
}
Some(Token::RightParenthesis) => {
tokens.next();
break;
}
// Parse expressions
Some(_) => {
let arg = parse_expression(tokens, Precedence::Lowest)?;
args.push(arg);
continue;
}
// Unexpected EOF
None => return Err(ParserError::EOF),
};
}
return Ok(Expression::Call {
function: lhs,
args,
});
};
let rhs = Box::new(parse_expression(tokens, get_prescedence(&operator))?); let rhs = Box::new(parse_expression(tokens, get_prescedence(&operator))?);
let expr = match operator { let expr = match operator {
@ -331,6 +365,8 @@ fn parse_infix_operator(
InfixOperator::LessThan => Expression::LessThan(lhs, rhs), InfixOperator::LessThan => Expression::LessThan(lhs, rhs),
InfixOperator::GreaterThanEqual => Expression::GreaterThanEqual(lhs, rhs), InfixOperator::GreaterThanEqual => Expression::GreaterThanEqual(lhs, rhs),
InfixOperator::LessThanEqual => Expression::LessThanEqual(lhs, rhs), InfixOperator::LessThanEqual => Expression::LessThanEqual(lhs, rhs),
InfixOperator::Call => panic!("unreachable"),
}; };
Ok(expr) Ok(expr)
@ -424,4 +460,15 @@ mod tests {
let res = parse_expression(&mut tokens, Precedence::Lowest).unwrap(); let res = parse_expression(&mut tokens, Precedence::Lowest).unwrap();
assert_eq!(&res.to_string(), expected); assert_eq!(&res.to_string(), expected);
} }
#[rstest]
#[case("add(2, 3)", "add(2, 3)")]
#[case("add(1 + 2, 3)", "add((1 + 2), 3)")]
#[case("add(x, y)", "add(x, y)")]
#[case("fn(x,y) { x + y }(1,2)", "fn(x, y) { (x + y) }(1, 2)")]
fn test_call_expression(#[case] input: &str, #[case] expected: &str) {
let mut tokens = lexer::tokenize(input).unwrap();
let res = parse_expression(&mut tokens, Precedence::Lowest).unwrap();
assert_eq!(&res.to_string(), expected);
}
} }

View file

@ -8,7 +8,7 @@ pub enum Precedence {
Sum, Sum,
Product, Product,
Prefix, Prefix,
// Call, Call,
} }
pub(super) fn get_prescedence(tok: &InfixOperator) -> Precedence { pub(super) fn get_prescedence(tok: &InfixOperator) -> Precedence {
@ -26,5 +26,7 @@ pub(super) fn get_prescedence(tok: &InfixOperator) -> Precedence {
InfixOperator::Asterisk => Precedence::Product, InfixOperator::Asterisk => Precedence::Product,
InfixOperator::ForwardSlash => Precedence::Product, InfixOperator::ForwardSlash => Precedence::Product,
InfixOperator::Call => Precedence::Call,
} }
} }