Added let statement parser
This commit is contained in:
parent
142b34edc4
commit
20a4907153
|
@ -1,5 +1,6 @@
|
||||||
use super::ParserError;
|
use super::ParseError;
|
||||||
use crate::lexer::Lexer;
|
use crate::lexer::Token;
|
||||||
|
use crate::parser::Parser;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
pub trait Node {
|
pub trait Node {
|
||||||
|
@ -7,8 +8,8 @@ pub trait Node {
|
||||||
fn validate(&self) -> Result<(), Box<dyn Error>>;
|
fn validate(&self) -> Result<(), Box<dyn Error>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Statement: Node {
|
pub(crate) trait Statement: Node {
|
||||||
fn parse(&mut Lexer) -> Self
|
fn parse(&mut Parser) -> Result<Self, Box<dyn Error>>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
@ -21,11 +22,16 @@ pub struct LetStatement {
|
||||||
// value: dyn Expression,
|
// value: dyn Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LetStatement {
|
||||||
|
pub fn new(identifier: Identifier) -> LetStatement {
|
||||||
|
LetStatement { name: identifier }
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Node for LetStatement {
|
impl Node for LetStatement {
|
||||||
fn validate(&self) -> Result<(), Box<dyn Error>> {
|
fn validate(&self) -> Result<(), Box<dyn Error>> {
|
||||||
if self.token_literal() != "let" {
|
if self.token_literal() != "let" {
|
||||||
return Err(Box::new(ParserError::new(
|
return Err(Box::new(ParseError::new(
|
||||||
"self.token_literal is not set, got=".to_owned() + self.token_literal(),
|
&("self.token_literal is not set, got=".to_owned() + self.token_literal()),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -37,19 +43,52 @@ impl Node for LetStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Statement for LetStatement {
|
impl Statement for LetStatement {
|
||||||
fn parse(lexer: &mut Lexer) -> LetStatement {
|
fn parse(parser: &mut Parser) -> Result<LetStatement, Box<dyn Error>> {
|
||||||
LetStatement {
|
let name;
|
||||||
name: Identifier { name: "potato" },
|
//TODO: Add expression parser
|
||||||
// value: "",
|
match parser.lexer.next() {
|
||||||
|
Some(v) => match v {
|
||||||
|
Token::Ident(q) => name = Identifier { name: q },
|
||||||
|
n @ _ => {
|
||||||
|
return Err(Box::new(ParseError::new(&format!(
|
||||||
|
"expected IDENT, Found {:?}",
|
||||||
|
n
|
||||||
|
))))
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
return Err(Box::new(ParseError::new(
|
||||||
|
"expected IDENT after let, Could not find it",
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !parser.expect_peek(Token::Assign) {
|
||||||
|
return Err(Box::new(ParseError::new("expected =, Could not find it")));
|
||||||
|
}
|
||||||
|
|
||||||
|
while !parser.current_token_is(Token::Semicolon) {
|
||||||
|
println!("prev_token={:?}", parser.current_token);
|
||||||
|
parser.current_token = parser.lexer.next();
|
||||||
|
println!("current_token={:?}", parser.current_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(LetStatement { name })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Identifier {
|
pub struct Identifier {
|
||||||
name: &'static str,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Identifier {
|
||||||
|
pub fn new(name: &str) -> Identifier {
|
||||||
|
Identifier {
|
||||||
|
name: name.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Node for Identifier {
|
impl Node for Identifier {
|
||||||
fn validate(&self) -> Result<(), Box<dyn Error>> {
|
fn validate(&self) -> Result<(), Box<dyn Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -5,37 +5,76 @@ pub use self::program::Program;
|
||||||
|
|
||||||
use self::ast::{LetStatement, Statement};
|
use self::ast::{LetStatement, Statement};
|
||||||
use crate::lexer::{Lexer, Token};
|
use crate::lexer::{Lexer, Token};
|
||||||
|
use std::iter::Peekable;
|
||||||
|
|
||||||
struct Parser {}
|
pub(crate) struct Parser<'a> {
|
||||||
|
lexer: Peekable<Lexer<'a>>,
|
||||||
impl Parser {
|
current_token: Option<Token>,
|
||||||
fn parse_statement(token: Token, lexer: &mut Lexer) -> Option<Box<dyn ast::Statement>> {
|
|
||||||
match token {
|
|
||||||
Token::Let => Some(Box::new(LetStatement::parse(lexer))),
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Parser<'a> {
|
||||||
|
fn new(lexer: Lexer<'a>) -> Parser {
|
||||||
|
Parser {
|
||||||
|
lexer: lexer.peekable(),
|
||||||
|
current_token: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_statement(&mut self, token: Token) -> Option<Box<dyn ast::Statement>> {
|
||||||
|
match token {
|
||||||
|
Token::Let => {
|
||||||
|
let stmt = match LetStatement::parse(self) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => return None, //TODO: Return appropriate error
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Box::new(stmt))
|
||||||
|
}
|
||||||
|
n @ _ => {
|
||||||
|
println!("{:?}", n);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_peek(&mut self, token: Token) -> bool {
|
||||||
|
if let Some(v) = self.lexer.peek() {
|
||||||
|
if v == &token {
|
||||||
|
self.lexer.next();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_token_is(&self, token: Token) -> bool {
|
||||||
|
self.current_token == Some(token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ParserError {
|
struct ParseError {
|
||||||
desc: String,
|
desc: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for ParserError {
|
impl std::fmt::Display for ParseError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(f, "ParserError: ")
|
write!(f, "ParseError: {}", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for ParserError {
|
impl std::error::Error for ParseError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
&self.desc
|
&self.desc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserError {
|
impl ParseError {
|
||||||
fn new(desc: String) -> ParserError {
|
fn new(desc: &str) -> ParseError {
|
||||||
ParserError { desc }
|
ParseError {
|
||||||
|
desc: desc.to_owned(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::lexer::{Lexer, Token};
|
use crate::lexer::{Lexer, Token};
|
||||||
use crate::parser::ast::{LetStatement, Statement};
|
use crate::parser::ast::Statement;
|
||||||
use crate::parser::Parser;
|
use crate::parser::Parser;
|
||||||
|
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
|
@ -7,24 +7,16 @@ pub struct Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
pub fn token_literal(&self) -> &'static str {
|
pub fn parse(lexer: Lexer) -> Program {
|
||||||
if self.statements.len() > 0 {
|
|
||||||
self.statements[0].token_literal()
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(mut lexer: Lexer) -> Program {
|
|
||||||
let mut statements = vec![];
|
let mut statements = vec![];
|
||||||
|
let mut parser = Parser::new(lexer);
|
||||||
loop {
|
loop {
|
||||||
if let Some(token) = lexer.next() {
|
if let Some(token) = parser.lexer.next() {
|
||||||
if token == Token::EOF {
|
if token == Token::EOF {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(stmt) = Parser::parse_statement(token, &mut lexer) {
|
if let Some(stmt) = parser.parse_statement(token) {
|
||||||
statements.push(stmt);
|
statements.push(stmt);
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -41,8 +33,8 @@ impl Program {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::lexer::Lexer;
|
use crate::lexer::Lexer;
|
||||||
|
use crate::parser::ast::{Identifier, LetStatement};
|
||||||
use crate::parser::Program;
|
use crate::parser::Program;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn let_statements() {
|
fn let_statements() {
|
||||||
let ip = "
|
let ip = "
|
||||||
|
@ -50,12 +42,21 @@ mod tests {
|
||||||
let qq = 10;
|
let qq = 10;
|
||||||
let foobar = 8388383;
|
let foobar = 8388383;
|
||||||
";
|
";
|
||||||
|
let out = Program {
|
||||||
|
statements: vec![
|
||||||
|
Box::new(LetStatement::new(Identifier::new("yr"))),
|
||||||
|
Box::new(LetStatement::new(Identifier::new("qq"))),
|
||||||
|
Box::new(LetStatement::new(Identifier::new("foobar"))),
|
||||||
|
],
|
||||||
|
};
|
||||||
let lexer = Lexer::new(ip);
|
let lexer = Lexer::new(ip);
|
||||||
let ast_tree = Program::parse(lexer);
|
let ast_tree = Program::parse(lexer);
|
||||||
|
|
||||||
if ast_tree.statements.len() != 3 {
|
if ast_tree.statements.len() != 3 {
|
||||||
assert_eq!(ast_tree.statements.len(), 3);
|
assert_eq!(ast_tree.statements.len(), 3);
|
||||||
}
|
}
|
||||||
|
for (out, expected_out) in ast_tree.statements.iter().zip(out.statements.iter()) {
|
||||||
|
// assert!(out, expected_out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user