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,
|
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),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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(", ")
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue