Added Call Expressions
1. Added Call Expressions 2. Refactored Boolean/Prefix/Infix parse functions 3. Added tests to support Call Expressions parser
This commit is contained in:
parent
8536d0defa
commit
8ec7ec1ba1
|
@ -192,6 +192,7 @@ pub enum Expression {
|
|||
BooleanExpression(BooleanExpression),
|
||||
IfExpression(IfExpression),
|
||||
FunctionExpression(FunctionLiteral),
|
||||
CallExpression(CallExpression),
|
||||
// TODO: Temporary placeholder value. Should be removed once this section is done
|
||||
None,
|
||||
}
|
||||
|
@ -225,10 +226,6 @@ impl Expression {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_boolean(_parser: &mut Parser, token: Token) -> Option<Self> {
|
||||
Some(Self::BooleanExpression(BooleanExpression::new(token.name)))
|
||||
}
|
||||
|
||||
pub fn parse_grouped_expression(parser: &mut Parser, _token: Token) -> Option<Self> {
|
||||
let next_token = parser.lexer.next()?;
|
||||
let expr = Expression::parse(parser, next_token, ExpressionPriority::Lowest);
|
||||
|
@ -239,47 +236,6 @@ impl Expression {
|
|||
expr
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_if_expression(parser: &mut Parser, ctoken: Token) -> Option<Self> {
|
||||
if parser.expect_peek(TokenType::LParen).is_none() {
|
||||
return None;
|
||||
}
|
||||
let next_token = parser.lexer.next()?;
|
||||
let condition = Expression::parse(parser, next_token.clone(), ExpressionPriority::Lowest)?;
|
||||
|
||||
if parser.expect_peek(TokenType::RParen).is_none() {
|
||||
return None;
|
||||
}
|
||||
if parser.expect_peek(TokenType::LBrace).is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let consequence = BlockStatement::parse(parser, next_token)?;
|
||||
|
||||
if parser.peek_token_is(TokenType::Else) {
|
||||
let token = parser.lexer.next()?;
|
||||
|
||||
if parser.expect_peek(TokenType::LBrace).is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let alternative = BlockStatement::parse(parser, token);
|
||||
|
||||
Some(Expression::IfExpression(IfExpression::new(
|
||||
ctoken.name,
|
||||
condition,
|
||||
consequence,
|
||||
alternative,
|
||||
)))
|
||||
} else {
|
||||
Some(Expression::IfExpression(IfExpression::new(
|
||||
ctoken.name,
|
||||
condition,
|
||||
consequence,
|
||||
None,
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Expression {
|
||||
|
@ -292,6 +248,7 @@ impl Display for Expression {
|
|||
Expression::BooleanExpression(v) => v.to_string(),
|
||||
Expression::IfExpression(v) => v.to_string(),
|
||||
Expression::FunctionExpression(v) => v.to_string(),
|
||||
Expression::CallExpression(v) => v.to_string(),
|
||||
Expression::None => "None".into(),
|
||||
};
|
||||
|
||||
|
@ -337,16 +294,12 @@ impl Display for Identifier {
|
|||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct IntegerLiteral {
|
||||
token: TokenType,
|
||||
value: i64,
|
||||
}
|
||||
|
||||
impl IntegerLiteral {
|
||||
pub fn new(token: TokenType, v: i64) -> Self {
|
||||
Self {
|
||||
token: token,
|
||||
value: v,
|
||||
}
|
||||
pub fn new(v: i64) -> Self {
|
||||
Self { value: v }
|
||||
}
|
||||
pub fn parse(parser: &mut Parser, token: Token) -> Option<Expression> {
|
||||
let n = match token.literal?.parse::<i64>() {
|
||||
|
@ -358,24 +311,21 @@ impl IntegerLiteral {
|
|||
return None;
|
||||
}
|
||||
};
|
||||
Some(Expression::IntegerLiteral(IntegerLiteral::new(
|
||||
TokenType::Int,
|
||||
n,
|
||||
)))
|
||||
Some(Expression::IntegerLiteral(IntegerLiteral::new(n)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct PrefixExpression {
|
||||
token: Token,
|
||||
token: TokenType,
|
||||
operator: String,
|
||||
right: Box<Expression>,
|
||||
}
|
||||
|
||||
impl PrefixExpression {
|
||||
pub fn new(token: Token, operator: &str, right: Expression) -> Self {
|
||||
pub fn new(token: TokenType, operator: &str, right: Expression) -> Self {
|
||||
Self {
|
||||
token: token,
|
||||
token,
|
||||
operator: operator.to_string(),
|
||||
right: Box::new(right),
|
||||
}
|
||||
|
@ -385,7 +335,7 @@ impl PrefixExpression {
|
|||
let next_token = parser.lexer.next()?;
|
||||
let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?;
|
||||
Some(Expression::PrefixExpression(PrefixExpression {
|
||||
token: ctoken.clone(),
|
||||
token: ctoken.name,
|
||||
operator: ctoken.to_string().into(),
|
||||
right: Box::new(right_expr),
|
||||
}))
|
||||
|
@ -404,16 +354,16 @@ impl Display for PrefixExpression {
|
|||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct InfixExpression {
|
||||
token: Token,
|
||||
token: TokenType,
|
||||
left: Box<Expression>,
|
||||
operator: String,
|
||||
right: Box<Expression>,
|
||||
}
|
||||
|
||||
impl InfixExpression {
|
||||
pub fn new(token: Token, left: Expression, operator: &str, right: Expression) -> Self {
|
||||
pub fn new(token: TokenType, left: Expression, operator: &str, right: Expression) -> Self {
|
||||
Self {
|
||||
token: token,
|
||||
token,
|
||||
left: Box::new(left),
|
||||
operator: operator.to_string(),
|
||||
right: Box::new(right),
|
||||
|
@ -424,7 +374,7 @@ impl InfixExpression {
|
|||
let next_token = parser.lexer.next()?;
|
||||
let right_expr = Expression::parse(parser, next_token, cprecedence)?;
|
||||
Some(Expression::InfixExpression(InfixExpression::new(
|
||||
token.clone(),
|
||||
token.name,
|
||||
left_expr,
|
||||
&token.to_string(),
|
||||
right_expr,
|
||||
|
@ -456,6 +406,11 @@ impl BooleanExpression {
|
|||
value: token == TokenType::True,
|
||||
}
|
||||
}
|
||||
pub fn parse(_parser: &mut Parser, token: Token) -> Option<Expression> {
|
||||
Some(Expression::BooleanExpression(BooleanExpression::new(
|
||||
token.name,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BooleanExpression {
|
||||
|
@ -466,7 +421,6 @@ impl Display for BooleanExpression {
|
|||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct IfExpression {
|
||||
token: TokenType,
|
||||
condition: Box<Expression>,
|
||||
consequence: BlockStatement,
|
||||
alternative: Option<BlockStatement>,
|
||||
|
@ -474,18 +428,54 @@ pub struct IfExpression {
|
|||
|
||||
impl IfExpression {
|
||||
pub fn new(
|
||||
token: TokenType,
|
||||
condition: Expression,
|
||||
consequence: BlockStatement,
|
||||
alternative: Option<BlockStatement>,
|
||||
) -> Self {
|
||||
Self {
|
||||
token,
|
||||
condition: Box::new(condition),
|
||||
consequence,
|
||||
alternative,
|
||||
}
|
||||
}
|
||||
pub fn parse(parser: &mut Parser, _ctoken: Token) -> Option<Expression> {
|
||||
if parser.expect_peek(TokenType::LParen).is_none() {
|
||||
return None;
|
||||
}
|
||||
let next_token = parser.lexer.next()?;
|
||||
let condition = Expression::parse(parser, next_token.clone(), ExpressionPriority::Lowest)?;
|
||||
|
||||
if parser.expect_peek(TokenType::RParen).is_none() {
|
||||
return None;
|
||||
}
|
||||
if parser.expect_peek(TokenType::LBrace).is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let consequence = BlockStatement::parse(parser, next_token)?;
|
||||
|
||||
if parser.peek_token_is(TokenType::Else) {
|
||||
let token = parser.lexer.next()?;
|
||||
|
||||
if parser.expect_peek(TokenType::LBrace).is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let alternative = BlockStatement::parse(parser, token);
|
||||
|
||||
Some(Expression::IfExpression(IfExpression::new(
|
||||
condition,
|
||||
consequence,
|
||||
alternative,
|
||||
)))
|
||||
} else {
|
||||
Some(Expression::IfExpression(IfExpression::new(
|
||||
condition,
|
||||
consequence,
|
||||
None,
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IfExpression {
|
||||
|
@ -504,19 +494,15 @@ impl Display for IfExpression {
|
|||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct BlockStatement {
|
||||
token: Token,
|
||||
statements: Vec<Statement>,
|
||||
}
|
||||
|
||||
impl BlockStatement {
|
||||
pub fn new(token: Token, stmt: Vec<Statement>) -> Self {
|
||||
Self {
|
||||
token,
|
||||
statements: stmt,
|
||||
}
|
||||
pub fn new(stmt: Vec<Statement>) -> Self {
|
||||
Self { statements: stmt }
|
||||
}
|
||||
|
||||
pub fn parse(parser: &mut Parser, ogtoken: Token) -> Option<Self> {
|
||||
pub fn parse(parser: &mut Parser, _ogtoken: Token) -> Option<Self> {
|
||||
let mut stmts = vec![];
|
||||
|
||||
let mut ctoken = parser.lexer.next();
|
||||
|
@ -533,7 +519,7 @@ impl BlockStatement {
|
|||
ctoken = parser.lexer.next();
|
||||
}
|
||||
|
||||
Some(BlockStatement::new(ogtoken, stmts))
|
||||
Some(BlockStatement::new(stmts))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -585,7 +571,7 @@ impl FunctionLiteral {
|
|||
}))
|
||||
}
|
||||
|
||||
fn parse_function_parameters(parser: &mut Parser, ctoken: Token) -> Option<Vec<Identifier>> {
|
||||
fn parse_function_parameters(parser: &mut Parser, _ctoken: Token) -> Option<Vec<Identifier>> {
|
||||
let mut out = vec![];
|
||||
|
||||
if parser.peek_token_is(TokenType::RParen) {
|
||||
|
@ -617,12 +603,77 @@ impl Display for FunctionLiteral {
|
|||
"{} {}({}) {}",
|
||||
self.token.name.to_string(),
|
||||
self.token.literal.as_ref().unwrap(),
|
||||
self.parameters.iter().map(|x| x.to_string()).join(","),
|
||||
self.parameters.iter().join(","),
|
||||
""
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct CallExpression {
|
||||
function: Box<Expression>,
|
||||
arguments: Vec<Expression>,
|
||||
}
|
||||
|
||||
impl CallExpression {
|
||||
pub fn new(f: Expression, arguments: Vec<Expression>) -> Self {
|
||||
Self {
|
||||
function: Box::new(f),
|
||||
arguments,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(parser: &mut Parser, ctoken: Token, expr: Expression) -> Option<Expression> {
|
||||
let args = Self::parse_call_arguments(parser, ctoken);
|
||||
|
||||
Some(Expression::CallExpression(Self {
|
||||
function: Box::new(expr),
|
||||
arguments: args?,
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_call_arguments(parser: &mut Parser, _ctoken: Token) -> Option<Vec<Expression>> {
|
||||
let mut expressions = vec![];
|
||||
if let Some(token) = parser.lexer.peek() {
|
||||
if token.name == TokenType::RParen {
|
||||
parser.lexer.next();
|
||||
return Some(expressions);
|
||||
}
|
||||
}
|
||||
let ntoken = match parser.lexer.next() {
|
||||
Some(token) => token,
|
||||
None => return Some(expressions),
|
||||
};
|
||||
|
||||
Expression::parse(parser, ntoken, ExpressionPriority::Lowest).map(|e| expressions.push(e));
|
||||
|
||||
while parser.peek_token_is(TokenType::Comma) {
|
||||
parser.lexer.next();
|
||||
let token = match parser.lexer.next() {
|
||||
Some(v) => v,
|
||||
None => return Some(expressions),
|
||||
};
|
||||
Expression::parse(parser, token, ExpressionPriority::Lowest)
|
||||
.map(|e| expressions.push(e));
|
||||
}
|
||||
|
||||
if parser.expect_peek(TokenType::RParen).is_none() {
|
||||
return None;
|
||||
}
|
||||
Some(expressions)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for CallExpression {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
f.write_fmt(format_args!(
|
||||
"{}({})",
|
||||
self.function,
|
||||
self.arguments.iter().join(", ")
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
|
|
|
@ -27,6 +27,7 @@ lazy_static! {
|
|||
m.insert(TokenType::Minus, ExpressionPriority::Sum);
|
||||
m.insert(TokenType::Slash, ExpressionPriority::Product);
|
||||
m.insert(TokenType::Asterisk, ExpressionPriority::Product);
|
||||
m.insert(TokenType::LParen, ExpressionPriority::Call);
|
||||
m
|
||||
};
|
||||
}
|
||||
|
@ -51,12 +52,16 @@ impl<'a> Parser<'a> {
|
|||
parser.register_prefix(TokenType::Int, IntegerLiteral::parse);
|
||||
parser.register_prefix(TokenType::Bang, PrefixExpression::parse);
|
||||
parser.register_prefix(TokenType::Minus, PrefixExpression::parse);
|
||||
parser.register_prefix(TokenType::True, Expression::parse_boolean);
|
||||
parser.register_prefix(TokenType::False, Expression::parse_boolean);
|
||||
parser.register_prefix(TokenType::True, BooleanExpression::parse);
|
||||
parser.register_prefix(TokenType::False, BooleanExpression::parse);
|
||||
parser.register_prefix(TokenType::LParen, Expression::parse_grouped_expression);
|
||||
parser.register_prefix(TokenType::If, Expression::parse_if_expression);
|
||||
parser.register_prefix(TokenType::If, IfExpression::parse);
|
||||
parser.register_prefix(TokenType::Function, FunctionLiteral::parse);
|
||||
|
||||
// Neat trick!
|
||||
// Call expressions looks like <ident>(<args>).
|
||||
// We can easily parse those by registering a infix on '('/LParen
|
||||
parser.register_infix(TokenType::LParen, CallExpression::parse);
|
||||
parser.register_infix(TokenType::Plus, InfixExpression::parse);
|
||||
parser.register_infix(TokenType::Minus, InfixExpression::parse);
|
||||
parser.register_infix(TokenType::Slash, InfixExpression::parse);
|
||||
|
@ -254,7 +259,7 @@ mod tests {
|
|||
program.unwrap().statements,
|
||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Int, "5"),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5))
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(5))
|
||||
))]
|
||||
);
|
||||
}
|
||||
|
@ -267,9 +272,9 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::Bang),
|
||||
Expression::PrefixExpression(PrefixExpression::new(
|
||||
Token::new(TokenType::Bang),
|
||||
TokenType::Bang,
|
||||
"!",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(5)),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -278,9 +283,9 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::Minus),
|
||||
Expression::PrefixExpression(PrefixExpression::new(
|
||||
Token::new(TokenType::Minus),
|
||||
TokenType::Minus,
|
||||
"-",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(15)),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -289,7 +294,7 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::Bang),
|
||||
Expression::PrefixExpression(PrefixExpression::new(
|
||||
Token::new(TokenType::Bang),
|
||||
TokenType::Bang,
|
||||
"!",
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
|
||||
)),
|
||||
|
@ -300,7 +305,7 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::Bang),
|
||||
Expression::PrefixExpression(PrefixExpression::new(
|
||||
Token::new(TokenType::Bang),
|
||||
TokenType::Bang,
|
||||
"!",
|
||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||
)),
|
||||
|
@ -311,7 +316,7 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::Bang),
|
||||
Expression::PrefixExpression(PrefixExpression::new(
|
||||
Token::new(TokenType::Bang),
|
||||
TokenType::Bang,
|
||||
"!",
|
||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||
)),
|
||||
|
@ -352,10 +357,10 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Int, "5"),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Plus),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||
TokenType::Plus,
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(5)),
|
||||
"+",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(10)),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -364,10 +369,10 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Int, "5"),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Minus),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||
TokenType::Minus,
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(5)),
|
||||
"-",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(10)),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -376,10 +381,10 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Int, "5"),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Asterisk),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||
TokenType::Asterisk,
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(5)),
|
||||
"*",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(15)),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -388,10 +393,10 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Int, "15"),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Slash),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
||||
TokenType::Slash,
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(15)),
|
||||
"/",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 3)),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(3)),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -400,10 +405,10 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Int, "5"),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::GreaterThan),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||
TokenType::GreaterThan,
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(5)),
|
||||
">",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(15)),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -412,9 +417,9 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Ident, "a"),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Plus),
|
||||
TokenType::Plus,
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Plus),
|
||||
TokenType::Plus,
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "a")),
|
||||
"+",
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "b")),
|
||||
|
@ -429,7 +434,7 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::True),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Equals),
|
||||
TokenType::Equals,
|
||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||
"==",
|
||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||
|
@ -441,7 +446,7 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::True),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::NotEquals),
|
||||
TokenType::NotEquals,
|
||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||
"!=",
|
||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||
|
@ -453,7 +458,7 @@ mod tests {
|
|||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::False),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Equals),
|
||||
TokenType::Equals,
|
||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||
"==",
|
||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||
|
@ -566,20 +571,18 @@ mod tests {
|
|||
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::If),
|
||||
Expression::IfExpression(IfExpression::new(
|
||||
TokenType::If,
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::GreaterThan),
|
||||
TokenType::GreaterThan,
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||
">",
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||
)),
|
||||
BlockStatement::new(
|
||||
Token::with_value(TokenType::Ident, "x"),
|
||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||
ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Ident, "x"),
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||
))],
|
||||
),
|
||||
),
|
||||
)]),
|
||||
None,
|
||||
)),
|
||||
))],
|
||||
|
@ -604,30 +607,24 @@ mod tests {
|
|||
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::new(TokenType::If),
|
||||
Expression::IfExpression(IfExpression::new(
|
||||
TokenType::If,
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::GreaterThan),
|
||||
TokenType::GreaterThan,
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||
">",
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||
)),
|
||||
BlockStatement::new(
|
||||
Token::with_value(TokenType::Ident, "x"),
|
||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||
ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Ident, "x"),
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||
))],
|
||||
),
|
||||
Some(BlockStatement::new(
|
||||
// TODO: Not sure if this is the right token to have here.
|
||||
// Since, It's a block statement parser, I believe it *should* have the first token it encounters in the block
|
||||
// Else is dealt with before the block starts so, maybe this is not the right token to have here. Will revisit later
|
||||
Token::new(TokenType::Else),
|
||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
),
|
||||
)]),
|
||||
Some(BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||
ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Ident, "y"),
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||
))],
|
||||
)),
|
||||
),
|
||||
)])),
|
||||
)),
|
||||
))],
|
||||
},
|
||||
|
@ -645,7 +642,8 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn function_literal_expression() {
|
||||
fn function_literal_parsing() {
|
||||
// TODO: Figure out why are there inconsistencies in BlockStatements Token
|
||||
let test_cases = [
|
||||
(
|
||||
"fn(a,b) {x + y;}",
|
||||
|
@ -657,18 +655,17 @@ mod tests {
|
|||
Identifier::new(TokenType::Ident, "a"),
|
||||
Identifier::new(TokenType::Ident, "b"),
|
||||
],
|
||||
BlockStatement::new(
|
||||
Token::with_value(TokenType::Ident, "x"),
|
||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||
ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Ident, "x"),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Plus),
|
||||
TokenType::Plus,
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||
"+",
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
),
|
||||
)]),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -679,7 +676,7 @@ mod tests {
|
|||
Expression::FunctionExpression(FunctionLiteral::new(
|
||||
Token::new(TokenType::Function),
|
||||
vec![],
|
||||
BlockStatement::new(Token::new(TokenType::RBrace), vec![]),
|
||||
BlockStatement::new(vec![]),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -694,7 +691,7 @@ mod tests {
|
|||
Identifier::new(TokenType::Ident, "ya"),
|
||||
Identifier::new(TokenType::Ident, "z"),
|
||||
],
|
||||
BlockStatement::new(Token::new(TokenType::RBrace), vec![]),
|
||||
BlockStatement::new(vec![]),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -705,7 +702,7 @@ mod tests {
|
|||
Expression::FunctionExpression(FunctionLiteral::new(
|
||||
Token::new(TokenType::Function),
|
||||
vec![Identifier::new(TokenType::Ident, "a")],
|
||||
BlockStatement::new(Token::new(TokenType::RBrace), vec![]),
|
||||
BlockStatement::new(vec![]),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
@ -720,14 +717,13 @@ mod tests {
|
|||
Identifier::new(TokenType::Ident, "b"),
|
||||
Identifier::new(TokenType::Ident, "abc"),
|
||||
],
|
||||
BlockStatement::new(
|
||||
Token::new(TokenType::LParen),
|
||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||
ExpressionStatement::new(
|
||||
Token::new(TokenType::LParen),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Asterisk),
|
||||
TokenType::Asterisk,
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Plus),
|
||||
TokenType::Plus,
|
||||
Expression::Identifier(Identifier::new(
|
||||
TokenType::Ident,
|
||||
"x",
|
||||
|
@ -740,7 +736,7 @@ mod tests {
|
|||
)),
|
||||
"*",
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
Token::new(TokenType::Minus),
|
||||
TokenType::Minus,
|
||||
Expression::Identifier(Identifier::new(
|
||||
TokenType::Ident,
|
||||
"a",
|
||||
|
@ -752,8 +748,58 @@ mod tests {
|
|||
)),
|
||||
)),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
),
|
||||
)]),
|
||||
)),
|
||||
))],
|
||||
),
|
||||
];
|
||||
|
||||
for test in test_cases.iter() {
|
||||
let lexer = Lexer::new(test.0);
|
||||
let mut parser = Parser::new(lexer);
|
||||
let program = parser.parse_program();
|
||||
check_parser_errors(&parser);
|
||||
assert_eq!(parser.errors.len(), 0);
|
||||
assert!(program.is_some());
|
||||
assert_eq!(program.unwrap().statements, test.1);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn call_expression_parsing() {
|
||||
// TODO: Figure out why are there inconsistencies in BlockStatements Token
|
||||
let test_cases = [
|
||||
(
|
||||
"add(1, 2 * 3, 4 + 5);",
|
||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Ident, "add"),
|
||||
Expression::CallExpression(CallExpression::new(
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "add")),
|
||||
vec![
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(1)),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
TokenType::Asterisk,
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(2)),
|
||||
"*",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(3)),
|
||||
)),
|
||||
Expression::InfixExpression(InfixExpression::new(
|
||||
TokenType::Plus,
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(4)),
|
||||
"+",
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(5)),
|
||||
)),
|
||||
],
|
||||
)),
|
||||
))],
|
||||
),
|
||||
(
|
||||
"add();",
|
||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||
Token::with_value(TokenType::Ident, "add"),
|
||||
Expression::CallExpression(CallExpression::new(
|
||||
Expression::Identifier(Identifier::new(TokenType::Ident, "add")),
|
||||
vec![],
|
||||
)),
|
||||
))],
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue
Block a user