diff --git a/src/parser/ast/mod.rs b/src/parser/ast/mod.rs index 4997bf9..ba69042 100644 --- a/src/parser/ast/mod.rs +++ b/src/parser/ast/mod.rs @@ -2,7 +2,7 @@ use { crate::{ lexer::{Token, TokenType}, - parser::Parser, + parser::{Parser, ParserError}, }, std::convert::From, }; @@ -181,28 +181,43 @@ enum ExpressionPriority { #[derive(Debug, PartialEq)] pub enum Expression { Identifier(Identifier), + IntegerLiteral(IntegerLiteral), // TODO: Temporary placeholder value. Should be removed once this section is done None, } impl Expression { fn parse(parser: &mut Parser, token: Token, precedence: ExpressionPriority) -> Option { - match token.name { - TokenType::Ident => Self::parse_identifier(parser, token), - _ => None, - } + let prefix = parser.prefix_parse_fns.get(&token.name)?; + + prefix(parser, token) } - fn parse_identifier(parser: &mut Parser, token: Token) -> Option { + pub fn parse_identifier(parser: &mut Parser, token: Token) -> Option { Some(Self::Identifier(Identifier::new( token.name, &token.literal?, ))) } + pub fn parse_integer_literal(parser: &mut Parser, token: Token) -> Option { + let n = match token.literal?.parse::() { + Ok(v) => v, + Err(e) => { + parser.errors.push(ParserError { + reason: e.to_string(), + }); + return None; + } + }; + + Some(Self::IntegerLiteral(IntegerLiteral::new(TokenType::Int, n))) + } + fn to_string(&self) -> String { match self { Expression::Identifier(v) => v.to_string(), + Expression::IntegerLiteral(v) => v.value.to_string(), Expression::None => "None".into(), } } @@ -236,6 +251,21 @@ impl Identifier { } } +#[derive(Debug, PartialEq)] +pub struct IntegerLiteral { + token: TokenType, + value: i64, +} + +impl IntegerLiteral { + pub fn new(token: TokenType, v: i64) -> Self { + Self { + token: token, + value: v, + } + } +} + #[cfg(test)] mod tests { use crate::{ diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 102eade..7f9efab 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -2,25 +2,37 @@ pub mod ast; use { crate::{ lexer::{Lexer, Token, TokenType}, - parser::ast::{Program, Statement}, + parser::ast::{Expression, Program, Statement}, }, std::{ + collections::HashMap, fmt::{Display, Error as FmtError, Formatter}, iter::Peekable, }, }; +type PrefixParseFn = fn(&mut Parser, token: Token) -> Option; +type InfixParseFn = fn(Expression) -> Option; + pub struct Parser<'a> { lexer: Peekable>, errors: Vec, + prefix_parse_fns: HashMap, + infix_parse_fns: HashMap, } impl<'a> Parser<'a> { pub fn new(lexer: Lexer<'a>) -> Self { - Self { + let mut parser = Parser { lexer: lexer.peekable(), errors: vec![], - } + prefix_parse_fns: HashMap::new(), + infix_parse_fns: HashMap::new(), + }; + + parser.register_prefix(TokenType::Ident, Expression::parse_identifier); + parser.register_prefix(TokenType::Int, Expression::parse_integer_literal); + parser } pub fn parse_program(&mut self) -> Program { @@ -71,6 +83,14 @@ impl<'a> Parser<'a> { }; self.errors.push(ParserError { reason: msg }); } + + fn register_prefix(&mut self, token: TokenType, f: PrefixParseFn) { + self.prefix_parse_fns.insert(token, f); + } + + fn register_infix(&mut self, token: TokenType, f: InfixParseFn) { + self.infix_parse_fns.insert(token, f); + } } pub struct ParserError { @@ -88,7 +108,10 @@ mod tests { use crate::{ lexer::{Lexer, Token, TokenType}, parser::{ - ast::{Expression, ExpressionStatement, Identifier, LetStatement, Program, Statement}, + ast::{ + Expression, ExpressionStatement, Identifier, IntegerLiteral, LetStatement, Program, + Statement, + }, Parser, }, }; @@ -98,9 +121,7 @@ mod tests { return; } else { let mut out = String::new(); - out.push_str(&format!("parser has {} errors\n", p.errors.len())); - for error in &p.errors { out.push_str(&format!("parser error: {}\n", error)); } @@ -135,13 +156,11 @@ mod tests { } ); - lexer = Lexer::new("let x = 5;let x 5; let 83838383; let = 10;"); + lexer = Lexer::new("let x 5; let 10; let 83838383;"); parser = Parser::new(lexer); - let program = parser.parse_program(); + let _program = parser.parse_program(); check_parser_errors(&parser); - // println!("{:?}", program); assert_eq!(parser.errors.len(), 3); - assert_eq!(program.statements.len(), 1); } #[test] @@ -154,4 +173,36 @@ mod tests { assert_eq!(program.statements.len(), 3); assert_eq!(parser.errors.len(), 0); } + #[test] + fn identifier_expression() { + let lexer = Lexer::new("foobar;"); + let mut parser = Parser::new(lexer); + let program = parser.parse_program(); + + check_parser_errors(&parser); + 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")), + })] + ); + } + + #[test] + fn integer_literal_expression() { + let lexer = Lexer::new("5;"); + let mut parser = Parser::new(lexer); + let program = parser.parse_program(); + check_parser_errors(&parser); + + assert_eq!( + program.statements, + vec![Statement::ExpressionStatement(ExpressionStatement { + token: Token::with_value(TokenType::Int, "5"), + expression: Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)) + })] + ); + } }