added array literals, refactored CallExpression::parse

This commit is contained in:
Ishan Jain 2024-05-26 17:41:59 +05:30
parent ad2d88e511
commit 3eeec60d3b
Signed by: ishan
GPG Key ID: 0506DB2A1CC75C27
4 changed files with 109 additions and 40 deletions

View File

@ -47,6 +47,7 @@ impl Evaluator for TreeWalker {
Expression::Identifier(v) => self.eval_identifier(v, env), Expression::Identifier(v) => self.eval_identifier(v, env),
Expression::IntegerLiteral(il) => Some(Object::Integer(il.value)), Expression::IntegerLiteral(il) => Some(Object::Integer(il.value)),
Expression::StringLiteral(s) => Some(Object::String(s.value)), Expression::StringLiteral(s) => Some(Object::String(s.value)),
Expression::ArrayLiteral(v) => unimplemented!(),
Expression::BooleanExpression(b) => Some(Object::Boolean(b.value)), Expression::BooleanExpression(b) => Some(Object::Boolean(b.value)),
Expression::PrefixExpression(p) => { Expression::PrefixExpression(p) => {
let expr = self.eval(Node::Expression(*p.right), env)?; let expr = self.eval(Node::Expression(*p.right), env)?;

View File

@ -51,6 +51,8 @@ pub enum TokenType {
RParen, RParen,
LBrace, LBrace,
RBrace, RBrace,
LBracket,
RBracket,
// Keywords // Keywords
Function, Function,
@ -81,6 +83,8 @@ impl Display for TokenType {
TokenType::RParen => ")", TokenType::RParen => ")",
TokenType::LBrace => "{", TokenType::LBrace => "{",
TokenType::RBrace => "}", TokenType::RBrace => "}",
TokenType::LBracket => "[",
TokenType::RBracket => "]",
TokenType::Function => "fn", TokenType::Function => "fn",
TokenType::If => "if", TokenType::If => "if",
TokenType::Else => "else", TokenType::Else => "else",
@ -241,6 +245,8 @@ impl<'a> Iterator for Lexer<'a> {
Some(';') => Some(token!(TokenType::Semicolon)), Some(';') => Some(token!(TokenType::Semicolon)),
Some('(') => Some(token!(TokenType::LParen)), Some('(') => Some(token!(TokenType::LParen)),
Some(')') => Some(token!(TokenType::RParen)), Some(')') => Some(token!(TokenType::RParen)),
Some('[') => Some(token!(TokenType::LBracket)),
Some(']') => Some(token!(TokenType::RBracket)),
Some('{') => Some(token!(TokenType::LBrace)), Some('{') => Some(token!(TokenType::LBrace)),
Some('}') => Some(token!(TokenType::RBrace)), Some('}') => Some(token!(TokenType::RBrace)),
Some('!') => { Some('!') => {
@ -379,6 +385,7 @@ mod tests {
\"foobar\" \"foobar\"
\"foo bar\" \"foo bar\"
[1,2];
" "
) )
@ -433,6 +440,12 @@ mod tests {
token!(TokenType::Semicolon), token!(TokenType::Semicolon),
token!(TokenType::String, "foobar"), token!(TokenType::String, "foobar"),
token!(TokenType::String, "foo bar"), token!(TokenType::String, "foo bar"),
token!(TokenType::LBracket),
token!(TokenType::Int, "1"),
token!(TokenType::Comma),
token!(TokenType::Int, "2"),
token!(TokenType::RBracket),
token!(TokenType::Semicolon),
token!(TokenType::EOF), token!(TokenType::EOF),
], ],
); );

View File

@ -7,7 +7,7 @@ use {
std::{ std::{
cmp::PartialOrd, cmp::PartialOrd,
convert::From, convert::From,
fmt::{Display, Formatter, Result as FmtResult}, fmt::{Display, Formatter, Result as FmtResult, Write},
}, },
}; };
@ -189,6 +189,7 @@ pub enum Expression {
Identifier(Identifier), Identifier(Identifier),
IntegerLiteral(IntegerLiteral), IntegerLiteral(IntegerLiteral),
StringLiteral(StringLiteral), StringLiteral(StringLiteral),
ArrayLiteral(ArrayLiteral),
PrefixExpression(PrefixExpression), PrefixExpression(PrefixExpression),
InfixExpression(InfixExpression), InfixExpression(InfixExpression),
BooleanExpression(BooleanExpression), BooleanExpression(BooleanExpression),
@ -198,7 +199,11 @@ pub enum Expression {
} }
impl Expression { impl Expression {
fn parse(parser: &mut Parser, ctoken: Token, precedence: ExpressionPriority) -> Option<Self> { pub fn parse(
parser: &mut Parser,
ctoken: Token,
precedence: ExpressionPriority,
) -> Option<Self> {
match parser.prefix_parse_fns.get(&ctoken.name) { match parser.prefix_parse_fns.get(&ctoken.name) {
Some(prefix) => { Some(prefix) => {
let mut left_expr = prefix(parser, ctoken); let mut left_expr = prefix(parser, ctoken);
@ -244,6 +249,7 @@ impl Display for Expression {
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::StringLiteral(v) => v.value.to_string(), Expression::StringLiteral(v) => v.value.to_string(),
Expression::ArrayLiteral(v) => v.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(),
@ -333,6 +339,33 @@ impl StringLiteral {
} }
} }
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ArrayLiteral {
elements: Vec<Expression>,
}
impl ArrayLiteral {
pub fn new(expr: Vec<Expression>) -> Self {
Self { elements: expr }
}
pub fn parse(parser: &mut Parser, _token: Token) -> Option<Expression> {
let mut out = ArrayLiteral { elements: vec![] };
out.elements = parser.parse_expression_list(TokenType::RBracket)?;
Some(Expression::ArrayLiteral(out))
}
}
impl Display for ArrayLiteral {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_char('[').unwrap();
f.write_str(&self.elements.iter().map(|x| x.to_string()).join(", "))
.unwrap();
f.write_char(']')
}
}
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct PrefixExpression { pub struct PrefixExpression {
pub operator: TokenType, pub operator: TokenType,
@ -591,49 +624,14 @@ impl CallExpression {
} }
} }
pub fn parse(parser: &mut Parser, ctoken: Token, expr: Expression) -> Option<Expression> { pub fn parse(parser: &mut Parser, _ctoken: Token, expr: Expression) -> Option<Expression> {
let args = Self::parse_call_arguments(parser, ctoken); let args = parser.parse_expression_list(TokenType::RParen)?;
Some(Expression::CallExpression(Self { Some(Expression::CallExpression(Self {
function: Box::new(expr), function: Box::new(expr),
arguments: args?, 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),
};
if let Some(expr) = Expression::parse(parser, ntoken, ExpressionPriority::Lowest) {
expressions.push(expr);
} else {
return Some(expressions);
}
while parser.peek_token_is(TokenType::Comma) {
parser.lexer.next();
let token = match parser.lexer.next() {
Some(v) => v,
None => return Some(expressions),
};
if let Some(expr) = Expression::parse(parser, token, ExpressionPriority::Lowest) {
expressions.push(expr);
} else {
return Some(expressions);
}
}
parser.expect_peek(TokenType::RParen)?;
Some(expressions)
}
} }
impl Display for CallExpression { impl Display for CallExpression {

View File

@ -58,6 +58,7 @@ impl<'a> Parser<'a> {
parser.register_prefix(TokenType::LParen, Expression::parse_grouped_expression); parser.register_prefix(TokenType::LParen, Expression::parse_grouped_expression);
parser.register_prefix(TokenType::If, IfExpression::parse); parser.register_prefix(TokenType::If, IfExpression::parse);
parser.register_prefix(TokenType::Function, FunctionLiteral::parse); parser.register_prefix(TokenType::Function, FunctionLiteral::parse);
parser.register_prefix(TokenType::LBracket, ArrayLiteral::parse);
// Neat trick! // Neat trick!
// Call expressions looks like <ident>(<args>). // Call expressions looks like <ident>(<args>).
@ -146,6 +147,37 @@ impl<'a> Parser<'a> {
None => ExpressionPriority::Lowest, None => ExpressionPriority::Lowest,
} }
} }
fn parse_expression_list(&mut self, end_token: TokenType) -> Option<Vec<Expression>> {
let mut out = vec![];
if self.peek_token_is(end_token) {
self.lexer.next();
return Some(out);
}
let next_token = self.lexer.next()?;
out.push(Expression::parse(
self,
next_token,
ExpressionPriority::Lowest,
)?);
while self.peek_token_is(TokenType::Comma) {
self.lexer.next();
let next_token = self.lexer.next()?;
out.push(Expression::parse(
self,
next_token,
ExpressionPriority::Lowest,
)?);
}
self.expect_peek(end_token)?;
Some(out)
}
} }
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
@ -892,4 +924,29 @@ mod tests {
assert_eq!(program.unwrap().to_string(), test.1); assert_eq!(program.unwrap().to_string(), test.1);
} }
} }
#[test]
fn array_literals() {
let test_cases = [(
"[1, 2 * 2, 3 + 3]",
vec![Statement::ExpressionStatement(ExpressionStatement::new(
token!(TokenType::LBracket),
Expression::ArrayLiteral(ArrayLiteral::new(vec![
Expression::IntegerLiteral(IntegerLiteral::new(1)),
Expression::InfixExpression(InfixExpression::new(
Expression::IntegerLiteral(IntegerLiteral::new(2)),
TokenType::Asterisk,
Expression::IntegerLiteral(IntegerLiteral::new(2)),
)),
Expression::InfixExpression(InfixExpression::new(
Expression::IntegerLiteral(IntegerLiteral::new(3)),
TokenType::Plus,
Expression::IntegerLiteral(IntegerLiteral::new(3)),
)),
])),
))],
)];
check_test_cases(&test_cases);
}
} }