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:
parent
44506cf591
commit
8536d0defa
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -1,16 +1,32 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# 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]]
|
[[package]]
|
||||||
name = "interpreter"
|
name = "interpreter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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)",
|
"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]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[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"
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
name = "interpreter"
|
name = "interpreter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["ishanjain28 <ishanjain28@gmail.com>"]
|
authors = ["ishanjain28 <ishanjain28@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
itertools = "0.8.2"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
fmt::{Display, Formatter, Result as FmtResult},
|
||||||
iter::Peekable,
|
iter::Peekable,
|
||||||
str::{self, Chars},
|
str::{self, Chars},
|
||||||
};
|
};
|
||||||
|
@ -59,9 +60,9 @@ pub enum TokenType {
|
||||||
Return,
|
Return,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenType {
|
impl Display for TokenType {
|
||||||
pub fn to_string(&self) -> &'static str {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
match self {
|
f.write_str(match self {
|
||||||
TokenType::Assign => "=",
|
TokenType::Assign => "=",
|
||||||
TokenType::Plus => "+",
|
TokenType::Plus => "+",
|
||||||
TokenType::Asterisk => "*",
|
TokenType::Asterisk => "*",
|
||||||
|
@ -89,7 +90,7 @@ impl TokenType {
|
||||||
eprintln!("{:?}", self);
|
eprintln!("{:?}", self);
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,9 +118,9 @@ impl Token {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Token {
|
impl Display for Token {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
self.name.to_string().into()
|
f.write_fmt(format_args!("{}", self.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,11 @@ use {
|
||||||
lexer::{Token, TokenType},
|
lexer::{Token, TokenType},
|
||||||
parser::{Error as ParserError, Parser},
|
parser::{Error as ParserError, Parser},
|
||||||
},
|
},
|
||||||
|
itertools::Itertools,
|
||||||
std::{
|
std::{
|
||||||
cmp::PartialOrd,
|
cmp::PartialOrd,
|
||||||
convert::From,
|
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 {
|
impl Display for Program {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
|
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
out.push_str(&statement.to_string());
|
out.push_str(&statement.to_string());
|
||||||
}
|
}
|
||||||
write!(f, "{}", out)
|
f.write_str(&out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,13 +48,13 @@ impl<'a> Statement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Statement {
|
impl Display for Statement {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(v) => v.to_string(),
|
Statement::Let(v) => f.write_str(&v.to_string()),
|
||||||
Statement::Return(v) => v.to_string(),
|
Statement::Return(v) => f.write_str(&v.to_string()),
|
||||||
Statement::ExpressionStatement(v) => v.to_string(),
|
Statement::ExpressionStatement(v) => f.write_str(&v.to_string()),
|
||||||
Statement::BlockStatement(v) => v.to_string(),
|
Statement::BlockStatement(v) => f.write_str(&v.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,13 +62,16 @@ impl ToString for Statement {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct LetStatement {
|
pub struct LetStatement {
|
||||||
// name field is to store the identifier of the binding
|
// 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
|
// value is to store the expression that'll produce value
|
||||||
pub value: Option<Expression>,
|
value: Option<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LetStatement {
|
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 }
|
Self { name, value }
|
||||||
}
|
}
|
||||||
// TODO: Implement code to parse let statement
|
// TODO: Implement code to parse let statement
|
||||||
|
@ -95,7 +99,7 @@ impl LetStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for 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);
|
let mut out = format!("{} {} = ", Self::token_literal(), self.name.value);
|
||||||
|
|
||||||
if let Some(v) = &self.value {
|
if let Some(v) = &self.value {
|
||||||
|
@ -103,7 +107,7 @@ impl Display for LetStatement {
|
||||||
out.push_str(&a);
|
out.push_str(&a);
|
||||||
}
|
}
|
||||||
out.push(';');
|
out.push(';');
|
||||||
write!(f, "{}", out)
|
f.write_str(&out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +131,7 @@ impl ReturnStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for 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());
|
let mut out = String::from(Self::token_literal());
|
||||||
|
|
||||||
if let Some(v) = &self.return_value {
|
if let Some(v) = &self.return_value {
|
||||||
|
@ -136,14 +140,14 @@ impl Display for ReturnStatement {
|
||||||
out.push_str(&a);
|
out.push_str(&a);
|
||||||
}
|
}
|
||||||
out.push(';');
|
out.push(';');
|
||||||
write!(f, "{}", out)
|
f.write_str(&out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct ExpressionStatement {
|
pub struct ExpressionStatement {
|
||||||
pub token: Token,
|
token: Token,
|
||||||
pub expression: Expression,
|
expression: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExpressionStatement {
|
impl ExpressionStatement {
|
||||||
|
@ -162,9 +166,9 @@ impl ExpressionStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for ExpressionStatement {
|
impl Display for ExpressionStatement {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
String::from(self.expression.to_string())
|
f.write_str(&self.expression.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +191,7 @@ pub enum Expression {
|
||||||
InfixExpression(InfixExpression),
|
InfixExpression(InfixExpression),
|
||||||
BooleanExpression(BooleanExpression),
|
BooleanExpression(BooleanExpression),
|
||||||
IfExpression(IfExpression),
|
IfExpression(IfExpression),
|
||||||
|
FunctionExpression(FunctionLiteral),
|
||||||
// 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,
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
pub fn parse_boolean(_parser: &mut Parser, token: Token) -> Option<Self> {
|
||||||
Some(Self::BooleanExpression(BooleanExpression::new(token.name)))
|
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 {
|
impl Display for Expression {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
write!(
|
let value = match self {
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
match self {
|
|
||||||
Expression::Identifier(v) => v.to_string(),
|
Expression::Identifier(v) => v.to_string(),
|
||||||
Expression::IntegerLiteral(v) => v.value.to_string(),
|
Expression::IntegerLiteral(v) => v.value.to_string(),
|
||||||
Expression::PrefixExpression(v) => v.to_string(),
|
Expression::PrefixExpression(v) => v.to_string(),
|
||||||
Expression::InfixExpression(v) => v.to_string(),
|
Expression::InfixExpression(v) => v.to_string(),
|
||||||
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::None => "None".into(),
|
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
|
// but an identifier *can* produce value when used on rhs, e.g. let x = y; Here `y` is producing a value
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Identifier {
|
pub struct Identifier {
|
||||||
pub token: TokenType,
|
token: TokenType,
|
||||||
pub value: String,
|
value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Identifier {
|
impl Identifier {
|
||||||
|
@ -363,11 +321,17 @@ impl Identifier {
|
||||||
value: v.to_string(),
|
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 {
|
impl Display for Identifier {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
write!(f, "{}", self.value.clone())
|
f.write_str(&self.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,6 +348,21 @@ impl IntegerLiteral {
|
||||||
value: v,
|
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)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -401,11 +380,25 @@ impl PrefixExpression {
|
||||||
right: Box::new(right),
|
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 {
|
impl Display for PrefixExpression {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
write!(f, "({}{})", self.operator, self.right.to_string())
|
f.write_fmt(format_args!(
|
||||||
|
"({}{})",
|
||||||
|
self.operator,
|
||||||
|
self.right.to_string()
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,17 +419,27 @@ impl InfixExpression {
|
||||||
right: Box::new(right),
|
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 {
|
impl Display for InfixExpression {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
write!(
|
f.write_fmt(format_args!(
|
||||||
f,
|
|
||||||
"({} {} {})",
|
"({} {} {})",
|
||||||
self.left.to_string(),
|
self.left.to_string(),
|
||||||
self.operator,
|
self.operator,
|
||||||
self.right.to_string()
|
self.right.to_string(),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,8 +459,8 @@ impl BooleanExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for BooleanExpression {
|
impl Display for BooleanExpression {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
write!(f, "{}", self.value)
|
f.write_str(&self.value.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,8 +488,8 @@ impl IfExpression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for IfExpression {
|
impl Display for IfExpression {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
let mut out = format!(
|
let mut out = format!(
|
||||||
"if {} {{ {} }} ",
|
"if {} {{ {} }} ",
|
||||||
self.condition.to_string(),
|
self.condition.to_string(),
|
||||||
|
@ -495,7 +498,7 @@ impl ToString for IfExpression {
|
||||||
if let Some(alternative) = &self.alternative {
|
if let Some(alternative) = &self.alternative {
|
||||||
out += &format!("else {{ {} }}", alternative.to_string());
|
out += &format!("else {{ {} }}", alternative.to_string());
|
||||||
}
|
}
|
||||||
out
|
f.write_str(&out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,14 +537,89 @@ impl BlockStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for BlockStatement {
|
impl Display for BlockStatement {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
|
|
||||||
for stmt in &self.statements {
|
for stmt in &self.statements {
|
||||||
out.push_str(&stmt.to_string());
|
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(","),
|
||||||
|
""
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ pub mod ast;
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
lexer::{Lexer, Token, TokenType},
|
lexer::{Lexer, Token, TokenType},
|
||||||
parser::ast::{Expression, ExpressionPriority, Program, Statement},
|
parser::ast::*,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
@ -47,23 +47,24 @@ impl<'a> Parser<'a> {
|
||||||
infix_parse_fns: HashMap::new(),
|
infix_parse_fns: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
parser.register_prefix(TokenType::Ident, Expression::parse_identifier);
|
parser.register_prefix(TokenType::Ident, Identifier::parse);
|
||||||
parser.register_prefix(TokenType::Int, Expression::parse_integer_literal);
|
parser.register_prefix(TokenType::Int, IntegerLiteral::parse);
|
||||||
parser.register_prefix(TokenType::Bang, Expression::parse_prefix_expression);
|
parser.register_prefix(TokenType::Bang, PrefixExpression::parse);
|
||||||
parser.register_prefix(TokenType::Minus, Expression::parse_prefix_expression);
|
parser.register_prefix(TokenType::Minus, PrefixExpression::parse);
|
||||||
parser.register_prefix(TokenType::True, Expression::parse_boolean);
|
parser.register_prefix(TokenType::True, Expression::parse_boolean);
|
||||||
parser.register_prefix(TokenType::False, Expression::parse_boolean);
|
parser.register_prefix(TokenType::False, Expression::parse_boolean);
|
||||||
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, Expression::parse_if_expression);
|
||||||
|
parser.register_prefix(TokenType::Function, FunctionLiteral::parse);
|
||||||
|
|
||||||
parser.register_infix(TokenType::Plus, Expression::parse_infix_expression);
|
parser.register_infix(TokenType::Plus, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::Minus, Expression::parse_infix_expression);
|
parser.register_infix(TokenType::Minus, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::Slash, Expression::parse_infix_expression);
|
parser.register_infix(TokenType::Slash, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::Asterisk, Expression::parse_infix_expression);
|
parser.register_infix(TokenType::Asterisk, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::Equals, Expression::parse_infix_expression);
|
parser.register_infix(TokenType::Equals, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::NotEquals, Expression::parse_infix_expression);
|
parser.register_infix(TokenType::NotEquals, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::LessThan, Expression::parse_infix_expression);
|
parser.register_infix(TokenType::LessThan, InfixExpression::parse);
|
||||||
parser.register_infix(TokenType::GreaterThan, Expression::parse_infix_expression);
|
parser.register_infix(TokenType::GreaterThan, InfixExpression::parse);
|
||||||
parser
|
parser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,8 +154,8 @@ pub struct Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
||||||
write!(fmt, "{}", self.reason)
|
f.write_str(&self.reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,18 +193,9 @@ mod tests {
|
||||||
program,
|
program,
|
||||||
Program {
|
Program {
|
||||||
statements: vec![
|
statements: vec![
|
||||||
Statement::Let(LetStatement {
|
Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "x"),)),
|
||||||
name: Identifier::new(TokenType::Let, "x"),
|
Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "y"),)),
|
||||||
value: None
|
Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "foobar"),))
|
||||||
}),
|
|
||||||
Statement::Let(LetStatement {
|
|
||||||
name: Identifier::new(TokenType::Let, "y"),
|
|
||||||
value: None
|
|
||||||
}),
|
|
||||||
Statement::Let(LetStatement {
|
|
||||||
name: Identifier::new(TokenType::Let, "foobar"),
|
|
||||||
value: None
|
|
||||||
})
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -242,10 +234,10 @@ mod tests {
|
||||||
assert_eq!(program.statements.len(), 1);
|
assert_eq!(program.statements.len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
program.statements,
|
program.statements,
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Ident, "foobar"),
|
Token::with_value(TokenType::Ident, "foobar"),
|
||||||
expression: Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
|
||||||
})]
|
))]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,10 +252,10 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
program.unwrap().statements,
|
program.unwrap().statements,
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
expression: Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5))
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5))
|
||||||
})]
|
))]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,58 +264,58 @@ mod tests {
|
||||||
let prefix_tests = [
|
let prefix_tests = [
|
||||||
(
|
(
|
||||||
"!5",
|
"!5",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
expression: Expression::PrefixExpression(PrefixExpression::new(
|
Expression::PrefixExpression(PrefixExpression::new(
|
||||||
Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
"!",
|
"!",
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"-15;",
|
"-15;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::new(TokenType::Minus),
|
Token::new(TokenType::Minus),
|
||||||
expression: Expression::PrefixExpression(PrefixExpression::new(
|
Expression::PrefixExpression(PrefixExpression::new(
|
||||||
Token::new(TokenType::Minus),
|
Token::new(TokenType::Minus),
|
||||||
"-",
|
"-",
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"!foobar;",
|
"!foobar;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
expression: Expression::PrefixExpression(PrefixExpression::new(
|
Expression::PrefixExpression(PrefixExpression::new(
|
||||||
Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
"!",
|
"!",
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"!true;",
|
"!true;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
expression: Expression::PrefixExpression(PrefixExpression::new(
|
Expression::PrefixExpression(PrefixExpression::new(
|
||||||
Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
"!",
|
"!",
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"!false;",
|
"!false;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
expression: Expression::PrefixExpression(PrefixExpression::new(
|
Expression::PrefixExpression(PrefixExpression::new(
|
||||||
Token::new(TokenType::Bang),
|
Token::new(TokenType::Bang),
|
||||||
"!",
|
"!",
|
||||||
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
// TODO: Add this test when we add function call parser
|
// TODO: Add this test when we add function call parser
|
||||||
// (
|
// (
|
||||||
|
@ -357,69 +349,69 @@ mod tests {
|
||||||
let infix_tests = [
|
let infix_tests = [
|
||||||
(
|
(
|
||||||
"5 + 10;",
|
"5 + 10;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Plus),
|
Token::new(TokenType::Plus),
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||||
"+",
|
"+",
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"5 - 10;",
|
"5 - 10;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Minus),
|
Token::new(TokenType::Minus),
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||||
"-",
|
"-",
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"5 * 15;",
|
"5 * 15;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Asterisk),
|
Token::new(TokenType::Asterisk),
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||||
"*",
|
"*",
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"15 / 3;",
|
"15 / 3;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Int, "15"),
|
Token::with_value(TokenType::Int, "15"),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Slash),
|
Token::new(TokenType::Slash),
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
||||||
"/",
|
"/",
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 3)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 3)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"5 > 15;",
|
"5 > 15;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Int, "5"),
|
Token::with_value(TokenType::Int, "5"),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::GreaterThan),
|
Token::new(TokenType::GreaterThan),
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
|
||||||
">",
|
">",
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"a + b + c;",
|
"a + b + c;",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Ident, "a"),
|
Token::with_value(TokenType::Ident, "a"),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Plus),
|
Token::new(TokenType::Plus),
|
||||||
Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Plus),
|
Token::new(TokenType::Plus),
|
||||||
|
@ -430,43 +422,43 @@ mod tests {
|
||||||
"+",
|
"+",
|
||||||
Expression::Identifier(Identifier::new(TokenType::Ident, "c")),
|
Expression::Identifier(Identifier::new(TokenType::Ident, "c")),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"true == true",
|
"true == true",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::new(TokenType::True),
|
Token::new(TokenType::True),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Equals),
|
Token::new(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)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"true != false",
|
"true != false",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::new(TokenType::True),
|
Token::new(TokenType::True),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::NotEquals),
|
Token::new(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)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"false == false",
|
"false == false",
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::new(TokenType::False),
|
Token::new(TokenType::False),
|
||||||
expression: Expression::InfixExpression(InfixExpression::new(
|
Expression::InfixExpression(InfixExpression::new(
|
||||||
Token::new(TokenType::Equals),
|
Token::new(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)),
|
||||||
)),
|
)),
|
||||||
})],
|
))],
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
for test in infix_tests.iter() {
|
for test in infix_tests.iter() {
|
||||||
|
@ -548,7 +540,7 @@ mod tests {
|
||||||
(
|
(
|
||||||
"let foobar = true;",
|
"let foobar = true;",
|
||||||
Program {
|
Program {
|
||||||
statements: vec![Statement::Let(LetStatement::new(
|
statements: vec![Statement::Let(LetStatement::with_value(
|
||||||
Identifier::new(TokenType::Let, "foobar"),
|
Identifier::new(TokenType::Let, "foobar"),
|
||||||
None, // TODO: fix this when we complete parsing of let statements
|
None, // TODO: fix this when we complete parsing of let statements
|
||||||
))],
|
))],
|
||||||
|
@ -583,13 +575,10 @@ mod tests {
|
||||||
)),
|
)),
|
||||||
BlockStatement::new(
|
BlockStatement::new(
|
||||||
Token::with_value(TokenType::Ident, "x"),
|
Token::with_value(TokenType::Ident, "x"),
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Ident, "x"),
|
Token::with_value(TokenType::Ident, "x"),
|
||||||
expression: Expression::Identifier(Identifier::new(
|
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||||
TokenType::Ident,
|
))],
|
||||||
"x",
|
|
||||||
)),
|
|
||||||
})],
|
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
)),
|
)),
|
||||||
|
@ -624,23 +613,20 @@ mod tests {
|
||||||
)),
|
)),
|
||||||
BlockStatement::new(
|
BlockStatement::new(
|
||||||
Token::with_value(TokenType::Ident, "x"),
|
Token::with_value(TokenType::Ident, "x"),
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Ident, "x"),
|
Token::with_value(TokenType::Ident, "x"),
|
||||||
expression: Expression::Identifier(Identifier::new(
|
Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
|
||||||
TokenType::Ident,
|
))],
|
||||||
"x",
|
|
||||||
)),
|
|
||||||
})],
|
|
||||||
),
|
),
|
||||||
Some(BlockStatement::new(
|
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),
|
Token::new(TokenType::Else),
|
||||||
vec![Statement::ExpressionStatement(ExpressionStatement {
|
vec![Statement::ExpressionStatement(ExpressionStatement::new(
|
||||||
token: Token::with_value(TokenType::Ident, "y"),
|
Token::with_value(TokenType::Ident, "y"),
|
||||||
expression: Expression::Identifier(Identifier::new(
|
Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
|
||||||
TokenType::Ident,
|
))],
|
||||||
"y",
|
|
||||||
)),
|
|
||||||
})],
|
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
))],
|
))],
|
||||||
|
@ -657,4 +643,130 @@ mod tests {
|
||||||
assert_eq!(program.unwrap(), test.1);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user