Added Function Literal parser

1. Added function literal parser.
2. Replaced all ToString impls with fmt::Display Impls.
3. Fixed few issues in existing fmt::Display impls.
4. Refactored Expression parsers
5. Added more tests to support new changes
This commit is contained in:
Ishan Jain 2020-01-20 14:45:21 +05:30
parent 44506cf591
commit 8536d0defa
5 changed files with 429 additions and 220 deletions

16
Cargo.lock generated
View File

@ -1,16 +1,32 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "either"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "interpreter"
version = "0.1.0"
dependencies = [
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

View File

@ -2,7 +2,9 @@
name = "interpreter"
version = "0.1.0"
authors = ["ishanjain28 <ishanjain28@gmail.com>"]
edition = "2018"
[dependencies]
lazy_static = "1.4.0"
itertools = "0.8.2"

View File

@ -1,5 +1,6 @@
use std::{
collections::HashMap,
fmt::{Display, Formatter, Result as FmtResult},
iter::Peekable,
str::{self, Chars},
};
@ -59,9 +60,9 @@ pub enum TokenType {
Return,
}
impl TokenType {
pub fn to_string(&self) -> &'static str {
match self {
impl Display for TokenType {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.write_str(match self {
TokenType::Assign => "=",
TokenType::Plus => "+",
TokenType::Asterisk => "*",
@ -89,7 +90,7 @@ impl TokenType {
eprintln!("{:?}", self);
unreachable!()
}
}
})
}
}
@ -117,9 +118,9 @@ impl Token {
}
}
impl ToString for Token {
fn to_string(&self) -> String {
self.name.to_string().into()
impl Display for Token {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.write_fmt(format_args!("{}", self.name))
}
}

View File

@ -4,10 +4,11 @@ use {
lexer::{Token, TokenType},
parser::{Error as ParserError, Parser},
},
itertools::Itertools,
std::{
cmp::PartialOrd,
convert::From,
fmt::{Display, Error as FmtError, Formatter},
fmt::{Display, Formatter, Result as FmtResult},
},
};
@ -17,13 +18,13 @@ pub struct Program {
}
impl Display for Program {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
let mut out = String::new();
for statement in &self.statements {
out.push_str(&statement.to_string());
}
write!(f, "{}", out)
f.write_str(&out)
}
}
@ -47,13 +48,13 @@ impl<'a> Statement {
}
}
impl ToString for Statement {
fn to_string(&self) -> String {
impl Display for Statement {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match self {
Statement::Let(v) => v.to_string(),
Statement::Return(v) => v.to_string(),
Statement::ExpressionStatement(v) => v.to_string(),
Statement::BlockStatement(v) => v.to_string(),
Statement::Let(v) => f.write_str(&v.to_string()),
Statement::Return(v) => f.write_str(&v.to_string()),
Statement::ExpressionStatement(v) => f.write_str(&v.to_string()),
Statement::BlockStatement(v) => f.write_str(&v.to_string()),
}
}
}
@ -61,13 +62,16 @@ impl ToString for Statement {
#[derive(Debug, PartialEq)]
pub struct LetStatement {
// name field is to store the identifier of the binding
pub name: Identifier,
name: Identifier,
// value is to store the expression that'll produce value
pub value: Option<Expression>,
value: Option<Expression>,
}
impl LetStatement {
pub fn new(name: Identifier, value: Option<Expression>) -> Self {
pub fn new(name: Identifier) -> Self {
Self { name, value: None }
}
pub fn with_value(name: Identifier, value: Option<Expression>) -> Self {
Self { name, value }
}
// TODO: Implement code to parse let statement
@ -95,7 +99,7 @@ impl LetStatement {
}
impl Display for LetStatement {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
let mut out = format!("{} {} = ", Self::token_literal(), self.name.value);
if let Some(v) = &self.value {
@ -103,7 +107,7 @@ impl Display for LetStatement {
out.push_str(&a);
}
out.push(';');
write!(f, "{}", out)
f.write_str(&out)
}
}
@ -127,7 +131,7 @@ impl ReturnStatement {
}
impl Display for ReturnStatement {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
let mut out = String::from(Self::token_literal());
if let Some(v) = &self.return_value {
@ -136,14 +140,14 @@ impl Display for ReturnStatement {
out.push_str(&a);
}
out.push(';');
write!(f, "{}", out)
f.write_str(&out)
}
}
#[derive(Debug, PartialEq)]
pub struct ExpressionStatement {
pub token: Token,
pub expression: Expression,
token: Token,
expression: Expression,
}
impl ExpressionStatement {
@ -162,9 +166,9 @@ impl ExpressionStatement {
}
}
impl ToString for ExpressionStatement {
fn to_string(&self) -> String {
String::from(self.expression.to_string())
impl Display for ExpressionStatement {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.write_str(&self.expression.to_string())
}
}
@ -187,6 +191,7 @@ pub enum Expression {
InfixExpression(InfixExpression),
BooleanExpression(BooleanExpression),
IfExpression(IfExpression),
FunctionExpression(FunctionLiteral),
// TODO: Temporary placeholder value. Should be removed once this section is done
None,
}
@ -220,26 +225,6 @@ impl Expression {
}
}
pub fn parse_identifier(_parser: &mut Parser, token: Token) -> Option<Self> {
Some(Self::Identifier(Identifier::new(
token.name,
&token.literal?,
)))
}
pub fn parse_integer_literal(parser: &mut Parser, token: Token) -> Option<Self> {
let n = match token.literal?.parse::<i64>() {
Ok(v) => v,
Err(e) => {
parser.errors.push(ParserError {
reason: e.to_string(),
});
return None;
}
};
Some(Self::IntegerLiteral(IntegerLiteral::new(TokenType::Int, n)))
}
pub fn parse_boolean(_parser: &mut Parser, token: Token) -> Option<Self> {
Some(Self::BooleanExpression(BooleanExpression::new(token.name)))
}
@ -295,49 +280,22 @@ impl Expression {
)))
}
}
pub fn parse_prefix_expression(parser: &mut Parser, ctoken: Token) -> Option<Self> {
let next_token = parser.lexer.next()?;
let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?;
Some(Expression::PrefixExpression(PrefixExpression {
token: ctoken.clone(),
operator: ctoken.to_string().into(),
right: Box::new(right_expr),
}))
}
pub fn parse_infix_expression(
parser: &mut Parser,
token: Token,
left_expr: Self,
) -> Option<Self> {
let cprecedence = parser.current_precedence(&token.name);
let next_token = parser.lexer.next()?;
let right_expr = Expression::parse(parser, next_token, cprecedence)?;
Some(Expression::InfixExpression(InfixExpression::new(
token.clone(),
left_expr,
&token.to_string(),
right_expr,
)))
}
}
impl Display for Expression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
f,
"{}",
match self {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
let value = match self {
Expression::Identifier(v) => v.to_string(),
Expression::IntegerLiteral(v) => v.value.to_string(),
Expression::PrefixExpression(v) => v.to_string(),
Expression::InfixExpression(v) => v.to_string(),
Expression::BooleanExpression(v) => v.to_string(),
Expression::IfExpression(v) => v.to_string(),
Expression::FunctionExpression(v) => v.to_string(),
Expression::None => "None".into(),
}
)
};
f.write_str(&value)
}
}
@ -352,8 +310,8 @@ impl From<&Expression> for String {
// but an identifier *can* produce value when used on rhs, e.g. let x = y; Here `y` is producing a value
#[derive(Debug, PartialEq)]
pub struct Identifier {
pub token: TokenType,
pub value: String,
token: TokenType,
value: String,
}
impl Identifier {
@ -363,11 +321,17 @@ impl Identifier {
value: v.to_string(),
}
}
pub fn parse(_parser: &mut Parser, token: Token) -> Option<Expression> {
Some(Expression::Identifier(Identifier::new(
token.name,
&token.literal?,
)))
}
}
impl Display for Identifier {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "{}", self.value.clone())
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.write_str(&self.value)
}
}
@ -384,6 +348,21 @@ impl IntegerLiteral {
value: v,
}
}
pub fn parse(parser: &mut Parser, token: Token) -> Option<Expression> {
let n = match token.literal?.parse::<i64>() {
Ok(v) => v,
Err(e) => {
parser.errors.push(ParserError {
reason: e.to_string(),
});
return None;
}
};
Some(Expression::IntegerLiteral(IntegerLiteral::new(
TokenType::Int,
n,
)))
}
}
#[derive(Debug, PartialEq)]
@ -401,11 +380,25 @@ impl PrefixExpression {
right: Box::new(right),
}
}
pub fn parse(parser: &mut Parser, ctoken: Token) -> Option<Expression> {
let next_token = parser.lexer.next()?;
let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?;
Some(Expression::PrefixExpression(PrefixExpression {
token: ctoken.clone(),
operator: ctoken.to_string().into(),
right: Box::new(right_expr),
}))
}
}
impl Display for PrefixExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "({}{})", self.operator, self.right.to_string())
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.write_fmt(format_args!(
"({}{})",
self.operator,
self.right.to_string()
))
}
}
@ -426,17 +419,27 @@ impl InfixExpression {
right: Box::new(right),
}
}
pub fn parse(parser: &mut Parser, token: Token, left_expr: Expression) -> Option<Expression> {
let cprecedence = parser.current_precedence(&token.name);
let next_token = parser.lexer.next()?;
let right_expr = Expression::parse(parser, next_token, cprecedence)?;
Some(Expression::InfixExpression(InfixExpression::new(
token.clone(),
left_expr,
&token.to_string(),
right_expr,
)))
}
}
impl Display for InfixExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
f,
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.write_fmt(format_args!(
"({} {} {})",
self.left.to_string(),
self.operator,
self.right.to_string()
)
self.right.to_string(),
))
}
}
@ -456,8 +459,8 @@ impl BooleanExpression {
}
impl Display for BooleanExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "{}", self.value)
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.write_str(&self.value.to_string())
}
}
@ -485,8 +488,8 @@ impl IfExpression {
}
}
impl ToString for IfExpression {
fn to_string(&self) -> String {
impl Display for IfExpression {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
let mut out = format!(
"if {} {{ {} }} ",
self.condition.to_string(),
@ -495,7 +498,7 @@ impl ToString for IfExpression {
if let Some(alternative) = &self.alternative {
out += &format!("else {{ {} }}", alternative.to_string());
}
out
f.write_str(&out)
}
}
@ -534,14 +537,89 @@ impl BlockStatement {
}
}
impl ToString for BlockStatement {
fn to_string(&self) -> String {
impl Display for BlockStatement {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
let mut out = String::new();
for stmt in &self.statements {
out.push_str(&stmt.to_string());
}
out
f.write_str(&out)
}
}
#[derive(Debug, PartialEq)]
pub struct FunctionLiteral {
token: Token,
parameters: Vec<Identifier>,
body: BlockStatement,
}
impl FunctionLiteral {
pub fn new(token: Token, parameters: Vec<Identifier>, body: BlockStatement) -> Self {
Self {
token,
parameters,
body,
}
}
pub fn parse(parser: &mut Parser, ctoken: Token) -> Option<Expression> {
if parser.expect_peek(TokenType::LParen).is_none() {
return None;
}
let ntoken = parser.lexer.peek()?.clone();
let parameters = FunctionLiteral::parse_function_parameters(parser, ntoken)?;
if parser.expect_peek(TokenType::LBrace).is_none() {
return None;
}
let ntoken = parser.lexer.peek()?.clone();
let body = BlockStatement::parse(parser, ntoken)?;
Some(Expression::FunctionExpression(Self {
token: ctoken,
parameters,
body,
}))
}
fn parse_function_parameters(parser: &mut Parser, ctoken: Token) -> Option<Vec<Identifier>> {
let mut out = vec![];
if parser.peek_token_is(TokenType::RParen) {
parser.lexer.next();
Some(out)
} else {
let ntoken = parser.lexer.next()?;
let ident = Identifier::new(ntoken.name, &ntoken.literal?);
out.push(ident);
while parser.peek_token_is(TokenType::Comma) {
parser.lexer.next();
let token = parser.lexer.next()?;
let ident = Identifier::new(token.name, &token.literal?);
out.push(ident);
}
if parser.expect_peek(TokenType::RParen).is_none() {
return None;
}
Some(out)
}
}
}
impl Display for FunctionLiteral {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.write_fmt(format_args!(
"{} {}({}) {}",
self.token.name.to_string(),
self.token.literal.as_ref().unwrap(),
self.parameters.iter().map(|x| x.to_string()).join(","),
""
))
}
}

View File

@ -2,7 +2,7 @@ pub mod ast;
use {
crate::{
lexer::{Lexer, Token, TokenType},
parser::ast::{Expression, ExpressionPriority, Program, Statement},
parser::ast::*,
},
std::{
collections::HashMap,
@ -47,23 +47,24 @@ impl<'a> Parser<'a> {
infix_parse_fns: HashMap::new(),
};
parser.register_prefix(TokenType::Ident, Expression::parse_identifier);
parser.register_prefix(TokenType::Int, Expression::parse_integer_literal);
parser.register_prefix(TokenType::Bang, Expression::parse_prefix_expression);
parser.register_prefix(TokenType::Minus, Expression::parse_prefix_expression);
parser.register_prefix(TokenType::Ident, Identifier::parse);
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::LParen, Expression::parse_grouped_expression);
parser.register_prefix(TokenType::If, Expression::parse_if_expression);
parser.register_prefix(TokenType::Function, FunctionLiteral::parse);
parser.register_infix(TokenType::Plus, Expression::parse_infix_expression);
parser.register_infix(TokenType::Minus, Expression::parse_infix_expression);
parser.register_infix(TokenType::Slash, Expression::parse_infix_expression);
parser.register_infix(TokenType::Asterisk, Expression::parse_infix_expression);
parser.register_infix(TokenType::Equals, Expression::parse_infix_expression);
parser.register_infix(TokenType::NotEquals, Expression::parse_infix_expression);
parser.register_infix(TokenType::LessThan, Expression::parse_infix_expression);
parser.register_infix(TokenType::GreaterThan, Expression::parse_infix_expression);
parser.register_infix(TokenType::Plus, InfixExpression::parse);
parser.register_infix(TokenType::Minus, InfixExpression::parse);
parser.register_infix(TokenType::Slash, InfixExpression::parse);
parser.register_infix(TokenType::Asterisk, InfixExpression::parse);
parser.register_infix(TokenType::Equals, InfixExpression::parse);
parser.register_infix(TokenType::NotEquals, InfixExpression::parse);
parser.register_infix(TokenType::LessThan, InfixExpression::parse);
parser.register_infix(TokenType::GreaterThan, InfixExpression::parse);
parser
}
@ -153,8 +154,8 @@ pub struct Error {
}
impl Display for Error {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
write!(fmt, "{}", self.reason)
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
f.write_str(&self.reason)
}
}
@ -192,18 +193,9 @@ mod tests {
program,
Program {
statements: vec![
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "x"),
value: None
}),
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "y"),
value: None
}),
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "foobar"),
value: None
})
Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "x"),)),
Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "y"),)),
Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "foobar"),))
],
}
);
@ -242,10 +234,10 @@ mod tests {
assert_eq!(program.statements.len(), 1);
assert_eq!(
program.statements,
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Ident, "foobar"),
expression: Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
})]
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::with_value(TokenType::Ident, "foobar"),
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
))]
);
}
@ -260,10 +252,10 @@ mod tests {
assert_eq!(
program.unwrap().statements,
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Int, "5"),
expression: Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5))
})]
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::with_value(TokenType::Int, "5"),
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5))
))]
);
}
@ -272,58 +264,58 @@ mod tests {
let prefix_tests = [
(
"!5",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::Bang),
expression: Expression::PrefixExpression(PrefixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Bang),
Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Bang),
"!",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
)),
})],
))],
),
(
"-15;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::Minus),
expression: Expression::PrefixExpression(PrefixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Minus),
Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Minus),
"-",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
)),
})],
))],
),
(
"!foobar;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::Bang),
expression: Expression::PrefixExpression(PrefixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Bang),
Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Bang),
"!",
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
)),
})],
))],
),
(
"!true;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::Bang),
expression: Expression::PrefixExpression(PrefixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Bang),
Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Bang),
"!",
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
)),
})],
))],
),
(
"!false;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::Bang),
expression: Expression::PrefixExpression(PrefixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Bang),
Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Bang),
"!",
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
)),
})],
))],
),
// TODO: Add this test when we add function call parser
// (
@ -357,69 +349,69 @@ mod tests {
let infix_tests = [
(
"5 + 10;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Int, "5"),
expression: Expression::InfixExpression(InfixExpression::new(
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)),
"+",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
)),
})],
))],
),
(
"5 - 10;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Int, "5"),
expression: Expression::InfixExpression(InfixExpression::new(
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)),
"-",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
)),
})],
))],
),
(
"5 * 15;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Int, "5"),
expression: Expression::InfixExpression(InfixExpression::new(
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)),
"*",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
)),
})],
))],
),
(
"15 / 3;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Int, "15"),
expression: Expression::InfixExpression(InfixExpression::new(
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)),
"/",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 3)),
)),
})],
))],
),
(
"5 > 15;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Int, "5"),
expression: Expression::InfixExpression(InfixExpression::new(
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)),
">",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
)),
})],
))],
),
(
"a + b + c;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Ident, "a"),
expression: Expression::InfixExpression(InfixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::with_value(TokenType::Ident, "a"),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Plus),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Plus),
@ -430,43 +422,43 @@ mod tests {
"+",
Expression::Identifier(Identifier::new(TokenType::Ident, "c")),
)),
})],
))],
),
(
"true == true",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::True),
expression: Expression::InfixExpression(InfixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::True),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Equals),
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
"==",
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
)),
})],
))],
),
(
"true != false",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::True),
expression: Expression::InfixExpression(InfixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::True),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::NotEquals),
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
"!=",
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
)),
})],
))],
),
(
"false == false",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::False),
expression: Expression::InfixExpression(InfixExpression::new(
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::False),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Equals),
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
"==",
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
)),
})],
))],
),
];
for test in infix_tests.iter() {
@ -548,7 +540,7 @@ mod tests {
(
"let foobar = true;",
Program {
statements: vec![Statement::Let(LetStatement::new(
statements: vec![Statement::Let(LetStatement::with_value(
Identifier::new(TokenType::Let, "foobar"),
None, // TODO: fix this when we complete parsing of let statements
))],
@ -583,13 +575,10 @@ mod tests {
)),
BlockStatement::new(
Token::with_value(TokenType::Ident, "x"),
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Ident, "x"),
expression: Expression::Identifier(Identifier::new(
TokenType::Ident,
"x",
)),
})],
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::with_value(TokenType::Ident, "x"),
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
))],
),
None,
)),
@ -624,23 +613,20 @@ mod tests {
)),
BlockStatement::new(
Token::with_value(TokenType::Ident, "x"),
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Ident, "x"),
expression: Expression::Identifier(Identifier::new(
TokenType::Ident,
"x",
)),
})],
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 {
token: Token::with_value(TokenType::Ident, "y"),
expression: Expression::Identifier(Identifier::new(
TokenType::Ident,
"y",
)),
})],
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::with_value(TokenType::Ident, "y"),
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
))],
)),
)),
))],
@ -657,4 +643,130 @@ mod tests {
assert_eq!(program.unwrap(), test.1);
}
}
#[test]
fn function_literal_expression() {
let test_cases = [
(
"fn(a,b) {x + y;}",
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Function),
Expression::FunctionExpression(FunctionLiteral::new(
Token::new(TokenType::Function),
vec![
Identifier::new(TokenType::Ident, "a"),
Identifier::new(TokenType::Ident, "b"),
],
BlockStatement::new(
Token::with_value(TokenType::Ident, "x"),
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::with_value(TokenType::Ident, "x"),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Plus),
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
"+",
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
)),
))],
),
)),
))],
),
(
"fn() {}",
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Function),
Expression::FunctionExpression(FunctionLiteral::new(
Token::new(TokenType::Function),
vec![],
BlockStatement::new(Token::new(TokenType::RBrace), vec![]),
)),
))],
),
(
"fn(x,ya,z) {}",
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Function),
Expression::FunctionExpression(FunctionLiteral::new(
Token::new(TokenType::Function),
vec![
Identifier::new(TokenType::Ident, "x"),
Identifier::new(TokenType::Ident, "ya"),
Identifier::new(TokenType::Ident, "z"),
],
BlockStatement::new(Token::new(TokenType::RBrace), vec![]),
)),
))],
),
(
"fn(a) {}",
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Function),
Expression::FunctionExpression(FunctionLiteral::new(
Token::new(TokenType::Function),
vec![Identifier::new(TokenType::Ident, "a")],
BlockStatement::new(Token::new(TokenType::RBrace), vec![]),
)),
))],
),
(
"fn(a,b,abc) {(x + y) * (a -b);}",
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::Function),
Expression::FunctionExpression(FunctionLiteral::new(
Token::new(TokenType::Function),
vec![
Identifier::new(TokenType::Ident, "a"),
Identifier::new(TokenType::Ident, "b"),
Identifier::new(TokenType::Ident, "abc"),
],
BlockStatement::new(
Token::new(TokenType::LParen),
vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::LParen),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Asterisk),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Plus),
Expression::Identifier(Identifier::new(
TokenType::Ident,
"x",
)),
"+",
Expression::Identifier(Identifier::new(
TokenType::Ident,
"y",
)),
)),
"*",
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Minus),
Expression::Identifier(Identifier::new(
TokenType::Ident,
"a",
)),
"-",
Expression::Identifier(Identifier::new(
TokenType::Ident,
"b",
)),
)),
)),
))],
),
)),
))],
),
];
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);
}
}
}