Working on parser
1. Added Identifier Expression parser 2. Added Prefix IntegerLiteral Parser
This commit is contained in:
parent
2fd6c9ca6d
commit
203ebb169b
|
@ -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::{
|
||||||
|
|
|
@ -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))
|
||||||
|
})]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user