Working on parser. It can parse return statements and log errors now

This commit is contained in:
Ishan Jain 2019-12-25 23:07:39 +05:30
parent 5ac3b5e29a
commit e6e1be2e00
4 changed files with 109 additions and 31 deletions

View File

@ -18,7 +18,7 @@ lazy_static! {
}; };
} }
#[derive(Debug, PartialEq, Eq, Clone, Hash)] #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum TokenType { pub enum TokenType {
Illegal, Illegal,
EOF, EOF,

View File

@ -3,7 +3,7 @@ use crate::{
parser::Parser, parser::Parser,
}; };
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub struct Program { pub struct Program {
pub statements: Vec<Statement>, pub statements: Vec<Statement>,
} }
@ -16,13 +16,15 @@ pub enum Node {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Statement { pub enum Statement {
Let(LetStatement), Let(LetStatement),
Return(ReturnStatement),
} }
impl<'a> Statement { impl<'a> Statement {
pub fn parse(parser: &'a mut Parser, token: Token) -> Option<Self> { pub fn parse(parser: &'a mut Parser, token: Token) -> Option<Self> {
match token.name { match token.name {
TokenType::Let => Some(Statement::Let(LetStatement::parse(parser)?)), TokenType::Let => Some(Statement::Let(LetStatement::parse(parser)?)),
_ => todo!(), TokenType::Return => Some(Statement::Return(ReturnStatement::parse(parser)?)),
_ => None,
} }
} }
} }
@ -57,12 +59,28 @@ impl LetStatement {
// TODO: Right now, We are just skipping over all the expressions // TODO: Right now, We are just skipping over all the expressions
// That'll come later // That'll come later
// Also, Right now, It hangs forever in case there is no semicolon at the end
while parser.lexer.next() != Some(Token::new(TokenType::Semicolon)) {} while parser.lexer.next() != Some(Token::new(TokenType::Semicolon)) {}
Some(stmt) Some(stmt)
} }
} }
#[derive(Debug, PartialEq)]
pub struct ReturnStatement {
return_value: Option<Expression>,
}
impl ReturnStatement {
fn parse(parser: &mut Parser) -> Option<Self> {
let stmt = ReturnStatement {
return_value: Some(Expression),
};
while parser.lexer.next() != Some(Token::new(TokenType::Semicolon)) {}
return Some(stmt);
}
}
// Identifier will be an expression // Identifier will be an expression
// Identifier in a let statement like, let x = 5; where `x` is an identifier doesn't produce a value // Identifier in a let statement like, let x = 5; where `x` is an identifier doesn't produce a value
// 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

View File

@ -4,32 +4,35 @@ use {
lexer::{Lexer, Token, TokenType}, lexer::{Lexer, Token, TokenType},
parser::ast::{Program, Statement}, parser::ast::{Program, Statement},
}, },
std::iter::Peekable, std::{
fmt::{Display, Error as FmtError, Formatter},
iter::Peekable,
},
}; };
pub struct Parser<'a> { pub struct Parser<'a> {
lexer: Peekable<Lexer<'a>>, lexer: Peekable<Lexer<'a>>,
pub errors: Vec<ParserError>,
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
pub fn new(lexer: Lexer<'a>) -> Self { pub fn new(lexer: Lexer<'a>) -> Self {
Self { Self {
lexer: lexer.peekable(), lexer: lexer.peekable(),
errors: vec![],
} }
} }
pub fn parse_program(mut self) -> Program { pub fn parse_program(&mut self) -> Program {
let mut program = Program { statements: vec![] }; let mut program = Program { statements: vec![] };
loop { while let Some(token) = self.lexer.next() {
let token = self.lexer.next().unwrap();
if token.name == TokenType::EOF { if token.name == TokenType::EOF {
break; break;
} }
match Statement::parse(self, token.clone()) {
match Statement::parse(&mut self, token) {
Some(v) => program.statements.push(v), Some(v) => program.statements.push(v),
None => todo!(), // This will happen in case of a parsing error or something None => {} // This will happen in case of a parsing error or something
} }
} }
@ -52,9 +55,32 @@ impl<'a> Parser<'a> {
if self.peek_token_is(token) { if self.peek_token_is(token) {
self.lexer.next() self.lexer.next()
} else { } else {
let got_token = match self.lexer.peek() {
Some(v) => Some(v.name),
None => None,
};
self.peek_error(token, got_token);
None None
} }
} }
fn peek_error(&mut self, et: TokenType, gt: Option<TokenType>) {
let msg = match gt {
Some(v) => format!("expected next token to be {:?}, Got {:?} instead", et, v),
None => format!("expected next token to be {:?}, Got None instead", et),
};
self.errors.push(ParserError { reason: msg });
}
}
pub struct ParserError {
reason: String,
}
impl Display for ParserError {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
write!(fmt, "{}", self.reason)
}
} }
#[cfg(test)] #[cfg(test)]
@ -62,34 +88,68 @@ mod tests {
use crate::{ use crate::{
lexer::{Lexer, TokenType}, lexer::{Lexer, TokenType},
parser::{ parser::{
ast::{Identifier, LetStatement, Statement}, ast::{Identifier, LetStatement, Program, Statement},
Parser, Parser,
}, },
}; };
#[test] #[test]
fn let_statements() { fn let_statements() {
let lexer = Lexer::new("let x =5;let y=10; let foobar=538383;"); let mut lexer = Lexer::new("let x =5;let y=10; let foobar=538383;");
let parser = Parser::new(lexer); let mut parser = Parser::new(lexer);
let program = parser.parse_program();
check_parser_errors(&parser);
assert_eq!(program.statements.len(), 3);
assert_eq!(
program,
Program {
statements: vec![
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "x"),
value: None
}),
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "y"),
value: None
}),
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "foobar"),
value: None
})
],
}
);
lexer = Lexer::new("let x = 5;let x 5;let = 10; let 83838383;");
parser = Parser::new(lexer);
let program = parser.parse_program();
check_parser_errors(&parser);
assert_eq!(parser.errors.len(), 3);
assert_eq!(program.statements.len(), 1);
}
#[test]
fn return_statements() {
let lexer = Lexer::new("return 5; return 10; return add(10);");
let mut parser = Parser::new(lexer);
let program = parser.parse_program(); let program = parser.parse_program();
check_parser_errors(&parser);
assert_eq!(program.statements.len(), 3); assert_eq!(program.statements.len(), 3);
assert_eq!(parser.errors.len(), 0);
}
assert_eq!( fn check_parser_errors(p: &Parser) {
program.statements, if p.errors.is_empty() {
vec![ return;
Statement::Let(LetStatement { } else {
name: Identifier::new(TokenType::Let, "x"), let mut out = String::new();
value: None
}), out.push_str(&format!("parser has {} errors\n", p.errors.len()));
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "y"), for error in &p.errors {
value: None out.push_str(&format!("parser error: {}\n", error));
}), }
Statement::Let(LetStatement { eprintln!("{}", out);
name: Identifier::new(TokenType::Let, "foobar"), }
value: None
})
]
);
} }
} }

View File

@ -24,7 +24,7 @@ fn start<R: BufRead, W: Write>(mut ip: R, mut out: W) {
println!("{:?}", token); println!("{:?}", token);
} }
let parser = Parser::new(tokens); let mut parser = Parser::new(tokens);
let stmts = parser.parse_program(); let stmts = parser.parse_program();
println!("parser={:?}", stmts); println!("parser={:?}", stmts);