Chapter 2 (finished)
This commit is contained in:
parent
4ad37f9b71
commit
0321e9ba89
4 changed files with 70 additions and 2 deletions
|
@ -132,6 +132,8 @@ pub enum InfixOperator {
|
|||
GreaterThan,
|
||||
LessThanEqual,
|
||||
GreaterThanEqual,
|
||||
|
||||
Call,
|
||||
}
|
||||
|
||||
impl InfixOperator {
|
||||
|
@ -157,6 +159,8 @@ impl TryFrom<&Token> for InfixOperator {
|
|||
Token::GreaterThan => Self::GreaterThan,
|
||||
Token::GreaterThanEqual => Self::GreaterThanEqual,
|
||||
|
||||
Token::LeftParenthesis => Self::Call,
|
||||
|
||||
_ => return Err(LexerError::InvalidToken),
|
||||
};
|
||||
|
||||
|
|
|
@ -85,7 +85,12 @@ pub enum Expression {
|
|||
|
||||
Function {
|
||||
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 } => {
|
||||
write!(f, "fn({}) {}", parameters.join(", "), body)
|
||||
}
|
||||
|
||||
Expression::Call { function, args } => write!(
|
||||
f,
|
||||
"{}({})",
|
||||
function,
|
||||
args.iter()
|
||||
.map(|expr| expr.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,6 +161,7 @@ fn parse_expression(
|
|||
None
|
||||
| Some(Token::RightParenthesis)
|
||||
| Some(Token::Semicolon)
|
||||
| Some(Token::Comma) // Break used when parsing function arguments
|
||||
| Some(Token::LeftBrace) // Break used for if statements
|
||||
| Some(Token::RightBrace) => break,
|
||||
_ => (),
|
||||
|
@ -315,6 +316,39 @@ fn parse_infix_operator(
|
|||
lhs: Expression,
|
||||
) -> Result<Expression, ParserError> {
|
||||
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 expr = match operator {
|
||||
|
@ -331,6 +365,8 @@ fn parse_infix_operator(
|
|||
InfixOperator::LessThan => Expression::LessThan(lhs, rhs),
|
||||
InfixOperator::GreaterThanEqual => Expression::GreaterThanEqual(lhs, rhs),
|
||||
InfixOperator::LessThanEqual => Expression::LessThanEqual(lhs, rhs),
|
||||
|
||||
InfixOperator::Call => panic!("unreachable"),
|
||||
};
|
||||
|
||||
Ok(expr)
|
||||
|
@ -424,4 +460,15 @@ mod tests {
|
|||
let res = parse_expression(&mut tokens, Precedence::Lowest).unwrap();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ pub enum Precedence {
|
|||
Sum,
|
||||
Product,
|
||||
Prefix,
|
||||
// Call,
|
||||
Call,
|
||||
}
|
||||
|
||||
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::ForwardSlash => Precedence::Product,
|
||||
|
||||
InfixOperator::Call => Precedence::Call,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue