Working on parser

1. Added Identifier Expression parser
2. Added Prefix IntegerLiteral Parser
This commit is contained in:
Ishan Jain 2020-01-12 00:03:18 +05:30
parent 2fd6c9ca6d
commit 203ebb169b
2 changed files with 97 additions and 16 deletions

View File

@ -2,7 +2,7 @@
use { use {
crate::{ crate::{
lexer::{Token, TokenType}, lexer::{Token, TokenType},
parser::Parser, parser::{Parser, ParserError},
}, },
std::convert::From, std::convert::From,
}; };
@ -181,28 +181,43 @@ enum ExpressionPriority {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Expression { pub enum Expression {
Identifier(Identifier), Identifier(Identifier),
IntegerLiteral(IntegerLiteral),
// 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,
} }
impl Expression { impl Expression {
fn parse(parser: &mut Parser, token: Token, precedence: ExpressionPriority) -> Option<Self> { fn parse(parser: &mut Parser, token: Token, precedence: ExpressionPriority) -> Option<Self> {
match token.name { let prefix = parser.prefix_parse_fns.get(&token.name)?;
TokenType::Ident => Self::parse_identifier(parser, token),
_ => None, prefix(parser, token)
}
} }
fn parse_identifier(parser: &mut Parser, token: Token) -> Option<Self> { pub fn parse_identifier(parser: &mut Parser, token: Token) -> Option<Self> {
Some(Self::Identifier(Identifier::new( Some(Self::Identifier(Identifier::new(
token.name, token.name,
&token.literal?, &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)))
}
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self { match self {
Expression::Identifier(v) => v.to_string(), Expression::Identifier(v) => v.to_string(),
Expression::IntegerLiteral(v) => v.value.to_string(),
Expression::None => "None".into(), 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)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{

View File

@ -2,25 +2,37 @@ pub mod ast;
use { use {
crate::{ crate::{
lexer::{Lexer, Token, TokenType}, lexer::{Lexer, Token, TokenType},
parser::ast::{Program, Statement}, parser::ast::{Expression, Program, Statement},
}, },
std::{ std::{
collections::HashMap,
fmt::{Display, Error as FmtError, Formatter}, fmt::{Display, Error as FmtError, Formatter},
iter::Peekable, iter::Peekable,
}, },
}; };
type PrefixParseFn = fn(&mut Parser, token: Token) -> Option<Expression>;
type InfixParseFn = fn(Expression) -> Option<Expression>;
pub struct Parser<'a> { pub struct Parser<'a> {
lexer: Peekable<Lexer<'a>>, lexer: Peekable<Lexer<'a>>,
errors: Vec<ParserError>, errors: Vec<ParserError>,
prefix_parse_fns: HashMap<TokenType, PrefixParseFn>,
infix_parse_fns: HashMap<TokenType, InfixParseFn>,
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
pub fn new(lexer: Lexer<'a>) -> Self { pub fn new(lexer: Lexer<'a>) -> Self {
Self { let mut parser = Parser {
lexer: lexer.peekable(), lexer: lexer.peekable(),
errors: vec![], 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 { pub fn parse_program(&mut self) -> Program {
@ -71,6 +83,14 @@ impl<'a> Parser<'a> {
}; };
self.errors.push(ParserError { reason: msg }); 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 { pub struct ParserError {
@ -88,7 +108,10 @@ mod tests {
use crate::{ use crate::{
lexer::{Lexer, Token, TokenType}, lexer::{Lexer, Token, TokenType},
parser::{ parser::{
ast::{Expression, ExpressionStatement, Identifier, LetStatement, Program, Statement}, ast::{
Expression, ExpressionStatement, Identifier, IntegerLiteral, LetStatement, Program,
Statement,
},
Parser, Parser,
}, },
}; };
@ -98,9 +121,7 @@ mod tests {
return; return;
} else { } else {
let mut out = String::new(); let mut out = String::new();
out.push_str(&format!("parser has {} errors\n", p.errors.len())); out.push_str(&format!("parser has {} errors\n", p.errors.len()));
for error in &p.errors { for error in &p.errors {
out.push_str(&format!("parser error: {}\n", error)); 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); parser = Parser::new(lexer);
let program = parser.parse_program(); let _program = parser.parse_program();
check_parser_errors(&parser); check_parser_errors(&parser);
// println!("{:?}", program);
assert_eq!(parser.errors.len(), 3); assert_eq!(parser.errors.len(), 3);
assert_eq!(program.statements.len(), 1);
} }
#[test] #[test]
@ -154,4 +173,36 @@ mod tests {
assert_eq!(program.statements.len(), 3); assert_eq!(program.statements.len(), 3);
assert_eq!(parser.errors.len(), 0); 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))
})]
);
}
} }