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),
|
BooleanExpression(BooleanExpression),
|
||||||
IfExpression(IfExpression),
|
IfExpression(IfExpression),
|
||||||
FunctionExpression(FunctionLiteral),
|
FunctionExpression(FunctionLiteral),
|
||||||
|
CallExpression(CallExpression),
|
||||||
// TODO: Temporary placeholder value. Should be removed once this section is done
|
// TODO: Temporary placeholder value. Should be removed once this section is done
|
||||||
None,
|
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> {
|
pub fn parse_grouped_expression(parser: &mut Parser, _token: Token) -> Option<Self> {
|
||||||
let next_token = parser.lexer.next()?;
|
let next_token = parser.lexer.next()?;
|
||||||
let expr = Expression::parse(parser, next_token, ExpressionPriority::Lowest);
|
let expr = Expression::parse(parser, next_token, ExpressionPriority::Lowest);
|
||||||
|
@ -239,47 +236,6 @@ impl Expression {
|
||||||
expr
|
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 {
|
impl Display for Expression {
|
||||||
|
@ -292,6 +248,7 @@ impl Display for Expression {
|
||||||
Expression::BooleanExpression(v) => v.to_string(),
|
Expression::BooleanExpression(v) => v.to_string(),
|
||||||
Expression::IfExpression(v) => v.to_string(),
|
Expression::IfExpression(v) => v.to_string(),
|
||||||
Expression::FunctionExpression(v) => v.to_string(),
|
Expression::FunctionExpression(v) => v.to_string(),
|
||||||
|
Expression::CallExpression(v) => v.to_string(),
|
||||||
Expression::None => "None".into(),
|
Expression::None => "None".into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -337,16 +294,12 @@ impl Display for Identifier {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct IntegerLiteral {
|
pub struct IntegerLiteral {
|
||||||
token: TokenType,
|
|
||||||
value: i64,
|
value: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntegerLiteral {
|
impl IntegerLiteral {
|
||||||
pub fn new(token: TokenType, v: i64) -> Self {
|
pub fn new(v: i64) -> Self {
|
||||||
Self {
|
Self { value: v }
|
||||||
token: token,
|
|
||||||
value: v,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn parse(parser: &mut Parser, token: Token) -> Option<Expression> {
|
pub fn parse(parser: &mut Parser, token: Token) -> Option<Expression> {
|
||||||
let n = match token.literal?.parse::<i64>() {
|
let n = match token.literal?.parse::<i64>() {
|
||||||
|
@ -358,24 +311,21 @@ impl IntegerLiteral {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some(Expression::IntegerLiteral(IntegerLiteral::new(
|
Some(Expression::IntegerLiteral(IntegerLiteral::new(n)))
|
||||||
TokenType::Int,
|
|
||||||
n,
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct PrefixExpression {
|
pub struct PrefixExpression {
|
||||||
token: Token,
|
token: TokenType,
|
||||||
operator: String,
|
operator: String,
|
||||||
right: Box<Expression>,
|
right: Box<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrefixExpression {
|
impl PrefixExpression {
|
||||||
pub fn new(token: Token, operator: &str, right: Expression) -> Self {
|
pub fn new(token: TokenType, operator: &str, right: Expression) -> Self {
|
||||||
Self {
|
Self {
|
||||||
token: token,
|
token,
|
||||||
operator: operator.to_string(),
|
operator: operator.to_string(),
|
||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
}
|
}
|
||||||
|
@ -385,7 +335,7 @@ impl PrefixExpression {
|
||||||
let next_token = parser.lexer.next()?;
|
let next_token = parser.lexer.next()?;
|
||||||
let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?;
|
let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?;
|
||||||
Some(Expression::PrefixExpression(PrefixExpression {
|
Some(Expression::PrefixExpression(PrefixExpression {
|
||||||
token: ctoken.clone(),
|
token: ctoken.name,
|
||||||
operator: ctoken.to_string().into(),
|
operator: ctoken.to_string().into(),
|
||||||
right: Box::new(right_expr),
|
right: Box::new(right_expr),
|
||||||
}))
|
}))
|
||||||
|
@ -404,16 +354,16 @@ impl Display for PrefixExpression {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct InfixExpression {
|
pub struct InfixExpression {
|
||||||
token: Token,
|
token: TokenType,
|
||||||
left: Box<Expression>,
|
left: Box<Expression>,
|
||||||
operator: String,
|
operator: String,
|
||||||
right: Box<Expression>,
|
right: Box<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InfixExpression {
|
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 {
|
Self {
|
||||||
token: token,
|
token,
|
||||||
left: Box::new(left),
|
left: Box::new(left),
|
||||||
operator: operator.to_string(),
|
operator: operator.to_string(),
|
||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
|
@ -424,7 +374,7 @@ impl InfixExpression {
|
||||||
let next_token = parser.lexer.next()?;
|
let next_token = parser.lexer.next()?;
|
||||||
let right_expr = Expression::parse(parser, next_token, cprecedence)?;
|
let right_expr = Expression::parse(parser, next_token, cprecedence)?;
|
||||||
Some(Expression::InfixExpression(InfixExpression::new(
|
Some(Expression::InfixExpression(InfixExpression::new(
|
||||||
token.clone(),
|
token.name,
|
||||||
left_expr,
|
left_expr,
|
||||||
&token.to_string(),
|
&token.to_string(),
|
||||||
right_expr,
|
right_expr,
|
||||||
|
@ -456,6 +406,11 @@ impl BooleanExpression {
|
||||||
value: token == TokenType::True,
|
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 {
|
impl Display for BooleanExpression {
|
||||||
|
@ -466,7 +421,6 @@ impl Display for BooleanExpression {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct IfExpression {
|
pub struct IfExpression {
|
||||||
token: TokenType,
|
|
||||||
condition: Box<Expression>,
|
condition: Box<Expression>,
|
||||||
consequence: BlockStatement,
|
consequence: BlockStatement,
|
||||||
alternative: Option<BlockStatement>,
|
alternative: Option<BlockStatement>,
|
||||||
|
@ -474,18 +428,54 @@ pub struct IfExpression {
|
||||||
|
|
||||||
impl IfExpression {
|
impl IfExpression {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
token: TokenType,
|
|
||||||
condition: Expression,
|
condition: Expression,
|
||||||
consequence: BlockStatement,
|
consequence: BlockStatement,
|
||||||
alternative: Option<BlockStatement>,
|
alternative: Option<BlockStatement>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
token,
|
|
||||||
condition: Box::new(condition),
|
condition: Box::new(condition),
|
||||||
consequence,
|
consequence,
|
||||||
alternative,
|
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 {
|
impl Display for IfExpression {
|
||||||
|
@ -504,19 +494,15 @@ impl Display for IfExpression {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct BlockStatement {
|
pub struct BlockStatement {
|
||||||
token: Token,
|
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockStatement {
|
impl BlockStatement {
|
||||||
pub fn new(token: Token, stmt: Vec<Statement>) -> Self {
|
pub fn new(stmt: Vec<Statement>) -> Self {
|
||||||
Self {
|
Self { statements: stmt }
|
||||||
token,
|
|
||||||
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 stmts = vec![];
|
||||||
|
|
||||||
let mut ctoken = parser.lexer.next();
|
let mut ctoken = parser.lexer.next();
|
||||||
|
@ -533,7 +519,7 @@ impl BlockStatement {
|
||||||
ctoken = parser.lexer.next();
|
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![];
|
let mut out = vec![];
|
||||||
|
|
||||||
if parser.peek_token_is(TokenType::RParen) {
|
if parser.peek_token_is(TokenType::RParen) {
|
||||||
|
@ -617,12 +603,77 @@ impl Display for FunctionLiteral {
|
||||||
"{} {}({}) {}",
|
"{} {}({}) {}",
|
||||||
self.token.name.to_string(),
|
self.token.name.to_string(),
|
||||||
self.token.literal.as_ref().unwrap(),
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
@ -27,6 +27,7 @@ lazy_static! {
|
||||||
m.insert(TokenType::Minus, ExpressionPriority::Sum);
|
m.insert(TokenType::Minus, ExpressionPriority::Sum);
|
||||||
m.insert(TokenType::Slash, ExpressionPriority::Product);
|
m.insert(TokenType::Slash, ExpressionPriority::Product);
|
||||||
m.insert(TokenType::Asterisk, ExpressionPriority::Product);
|
m.insert(TokenType::Asterisk, ExpressionPriority::Product);
|
||||||
|
m.insert(TokenType::LParen, ExpressionPriority::Call);
|
||||||
m
|
m
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -51,12 +52,16 @@ impl<'a> Parser<'a> {
|
||||||
parser.register_prefix(TokenType::Int, IntegerLiteral::parse);
|
parser.register_prefix(TokenType::Int, IntegerLiteral::parse);
|
||||||
parser.register_prefix(TokenType::Bang, PrefixExpression::parse);
|
parser.register_prefix(TokenType::Bang, PrefixExpression::parse);
|
||||||
parser.register_prefix(TokenType::Minus, PrefixExpression::parse);
|
parser.register_prefix(TokenType::Minus, PrefixExpression::parse);
|
||||||
parser.register_prefix(TokenType::True, Expression::parse_boolean);
|
parser.register_prefix(TokenType::True, BooleanExpression::parse);
|
||||||
parser.register_prefix(TokenType::False, Expression::parse_boolean);
|
parser.register_prefix(TokenType::False, BooleanExpression::parse);
|
||||||
parser.register_prefix(TokenType::LParen, Expression::parse_grouped_expression);
|
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);
|
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::Plus, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::Minus, InfixExpression::parse);
|
parser.register_infix(TokenType::Minus, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::Slash, InfixExpression::parse);
|
parser.register_infix(TokenType::Slash, InfixExpression::parse);
|
||||||
|
@ -254,7 +259,7 @@ mod tests {
|
||||||
program.unwrap().statements,
|
program.unwrap().statements,
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::with_value(TokenType::Int, "5"),
|
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(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
Expression::PrefixExpression(PrefixExpression::new(
|
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(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::Minus),
|
Token::new(TokenType::Minus),
|
||||||
Expression::PrefixExpression(PrefixExpression::new(
|
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(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
Expression::PrefixExpression(PrefixExpression::new(
|
Expression::PrefixExpression(PrefixExpression::new(
|
||||||
Token::new(TokenType::Bang),
|
TokenType::Bang,
|
||||||
"!",
|
"!",
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
|
||||||
)),
|
)),
|
||||||
|
@ -300,7 +305,7 @@ mod tests {
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
Expression::PrefixExpression(PrefixExpression::new(
|
Expression::PrefixExpression(PrefixExpression::new(
|
||||||
Token::new(TokenType::Bang),
|
TokenType::Bang,
|
||||||
"!",
|
"!",
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||||
)),
|
)),
|
||||||
|
@ -311,7 +316,7 @@ mod tests {
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
Expression::PrefixExpression(PrefixExpression::new(
|
Expression::PrefixExpression(PrefixExpression::new(
|
||||||
Token::new(TokenType::Bang),
|
TokenType::Bang,
|
||||||
"!",
|
"!",
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||||
)),
|
)),
|
||||||
|
@ -352,10 +357,10 @@ mod tests {
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Plus),
|
TokenType::Plus,
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
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(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Minus),
|
TokenType::Minus,
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
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(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Asterisk),
|
TokenType::Asterisk,
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
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(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::with_value(TokenType::Int, "15"),
|
Token::with_value(TokenType::Int, "15"),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Slash),
|
TokenType::Slash,
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
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(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::GreaterThan),
|
TokenType::GreaterThan,
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
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(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::with_value(TokenType::Ident, "a"),
|
Token::with_value(TokenType::Ident, "a"),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Plus),
|
TokenType::Plus,
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Plus),
|
TokenType::Plus,
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "a")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "a")),
|
||||||
"+",
|
"+",
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "b")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "b")),
|
||||||
|
@ -429,7 +434,7 @@ mod tests {
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::True),
|
Token::new(TokenType::True),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Equals),
|
TokenType::Equals,
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||||
"==",
|
"==",
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||||
|
@ -441,7 +446,7 @@ mod tests {
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::True),
|
Token::new(TokenType::True),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::NotEquals),
|
TokenType::NotEquals,
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||||
"!=",
|
"!=",
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||||
|
@ -453,7 +458,7 @@ mod tests {
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::False),
|
Token::new(TokenType::False),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Equals),
|
TokenType::Equals,
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||||
"==",
|
"==",
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||||
|
@ -566,20 +571,18 @@ mod tests {
|
||||||
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::If),
|
Token::new(TokenType::If),
|
||||||
Expression::IfExpression(IfExpression::new(
|
Expression::IfExpression(IfExpression::new(
|
||||||
TokenType::If,
|
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::GreaterThan),
|
TokenType::GreaterThan,
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||||
">",
|
">",
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||||
)),
|
)),
|
||||||
BlockStatement::new(
|
BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||||
Token::with_value(TokenType::Ident, "x"),
|
ExpressionStatement::new(
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
|
||||||
Token::with_value(TokenType::Ident, "x"),
|
Token::with_value(TokenType::Ident, "x"),
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||||
))],
|
),
|
||||||
),
|
)]),
|
||||||
None,
|
None,
|
||||||
)),
|
)),
|
||||||
))],
|
))],
|
||||||
|
@ -604,30 +607,24 @@ mod tests {
|
||||||
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
Token::new(TokenType::If),
|
Token::new(TokenType::If),
|
||||||
Expression::IfExpression(IfExpression::new(
|
Expression::IfExpression(IfExpression::new(
|
||||||
TokenType::If,
|
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::GreaterThan),
|
TokenType::GreaterThan,
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||||
">",
|
">",
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||||
)),
|
)),
|
||||||
BlockStatement::new(
|
BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||||
Token::with_value(TokenType::Ident, "x"),
|
ExpressionStatement::new(
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
|
||||||
Token::with_value(TokenType::Ident, "x"),
|
Token::with_value(TokenType::Ident, "x"),
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||||
))],
|
),
|
||||||
),
|
)]),
|
||||||
Some(BlockStatement::new(
|
Some(BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||||
// TODO: Not sure if this is the right token to have here.
|
ExpressionStatement::new(
|
||||||
// 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(
|
|
||||||
Token::with_value(TokenType::Ident, "y"),
|
Token::with_value(TokenType::Ident, "y"),
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||||
))],
|
),
|
||||||
)),
|
)])),
|
||||||
)),
|
)),
|
||||||
))],
|
))],
|
||||||
},
|
},
|
||||||
|
@ -645,7 +642,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function_literal_expression() {
|
fn function_literal_parsing() {
|
||||||
|
// TODO: Figure out why are there inconsistencies in BlockStatements Token
|
||||||
let test_cases = [
|
let test_cases = [
|
||||||
(
|
(
|
||||||
"fn(a,b) {x + y;}",
|
"fn(a,b) {x + y;}",
|
||||||
|
@ -657,18 +655,17 @@ mod tests {
|
||||||
Identifier::new(TokenType::Ident, "a"),
|
Identifier::new(TokenType::Ident, "a"),
|
||||||
Identifier::new(TokenType::Ident, "b"),
|
Identifier::new(TokenType::Ident, "b"),
|
||||||
],
|
],
|
||||||
BlockStatement::new(
|
BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||||
Token::with_value(TokenType::Ident, "x"),
|
ExpressionStatement::new(
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
|
||||||
Token::with_value(TokenType::Ident, "x"),
|
Token::with_value(TokenType::Ident, "x"),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Plus),
|
TokenType::Plus,
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||||
"+",
|
"+",
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||||
)),
|
)),
|
||||||
))],
|
),
|
||||||
),
|
)]),
|
||||||
)),
|
)),
|
||||||
))],
|
))],
|
||||||
),
|
),
|
||||||
|
@ -679,7 +676,7 @@ mod tests {
|
||||||
Expression::FunctionExpression(FunctionLiteral::new(
|
Expression::FunctionExpression(FunctionLiteral::new(
|
||||||
Token::new(TokenType::Function),
|
Token::new(TokenType::Function),
|
||||||
vec![],
|
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, "ya"),
|
||||||
Identifier::new(TokenType::Ident, "z"),
|
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(
|
Expression::FunctionExpression(FunctionLiteral::new(
|
||||||
Token::new(TokenType::Function),
|
Token::new(TokenType::Function),
|
||||||
vec![Identifier::new(TokenType::Ident, "a")],
|
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, "b"),
|
||||||
Identifier::new(TokenType::Ident, "abc"),
|
Identifier::new(TokenType::Ident, "abc"),
|
||||||
],
|
],
|
||||||
BlockStatement::new(
|
BlockStatement::new(vec![Statement::ExpressionStatement(
|
||||||
Token::new(TokenType::LParen),
|
ExpressionStatement::new(
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
|
||||||
Token::new(TokenType::LParen),
|
Token::new(TokenType::LParen),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Asterisk),
|
TokenType::Asterisk,
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Plus),
|
TokenType::Plus,
|
||||||
Expression::Identifier(Identifier::new(
|
Expression::Identifier(Identifier::new(
|
||||||
TokenType::Ident,
|
TokenType::Ident,
|
||||||
"x",
|
"x",
|
||||||
|
@ -740,7 +736,7 @@ mod tests {
|
||||||
)),
|
)),
|
||||||
"*",
|
"*",
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Minus),
|
TokenType::Minus,
|
||||||
Expression::Identifier(Identifier::new(
|
Expression::Identifier(Identifier::new(
|
||||||
TokenType::Ident,
|
TokenType::Ident,
|
||||||
"a",
|
"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