diff --git a/src/ast/mod.rs b/src/ast/mod.rs index fd94bc7..c53e457 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,17 +1,17 @@ use crate::token; -trait NodeTrait { +pub trait NodeTrait { fn token_literal(&self) -> String; } -trait StatementTrait: NodeTrait { +pub trait StatementTrait: NodeTrait { fn statement_node(&self); } trait ExpressionTrait: NodeTrait { fn expression_node(&self); } -struct Expression { +pub struct Expression { // } impl NodeTrait for Expression { @@ -20,7 +20,7 @@ impl NodeTrait for Expression { } } -struct Statement { +pub struct Statement { // } impl NodeTrait for Statement { @@ -34,12 +34,12 @@ impl StatementTrait for Statement { } pub struct Program { - statements: Vec, + pub statements: Vec>, } impl NodeTrait for Program { fn token_literal(&self) -> String { - if self.statements.is_empty() { + if !self.statements.is_empty() { self.statements[0].token_literal() } else { String::new() @@ -47,10 +47,10 @@ impl NodeTrait for Program { } } -struct LetStatement { - token: token::Token, - name: Identifier, - value: Expression, +pub struct LetStatement { + pub token: token::Token, + pub name: Identifier, + pub value: Expression, } impl NodeTrait for LetStatement { @@ -65,9 +65,9 @@ impl StatementTrait for LetStatement { } } -struct Identifier { - token: token::Token, - value: String, +pub struct Identifier { + pub token: token::Token, + pub value: String, } impl NodeTrait for Identifier { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 9e6a00c..92be775 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,21 +1,30 @@ use crate::{ - ast, + ast::{self}, lexer::{self, LexerTraits}, - token, + token::{self, EOF}, }; pub struct Parser { lexer: lexer::Lexer, cur_token: token::Token, peek_token: token::Token, + errors: Vec, } -trait PaserTrait { +pub trait ParserTrait { fn next_token(&mut self); - fn parse_program(&self) -> ast::Program; + fn parse_program(&mut self) -> ast::Program; + fn parse_statement(&mut self) -> Option>; + fn parse_let_statement(&mut self) -> Option>; + + fn cur_token_is(&self, t: String) -> bool; + fn peek_token_is(&self, t: String) -> bool; + fn expect_peek(&mut self, t: String) -> bool; + fn errors(&self) -> &Vec; + fn peek_error(&mut self, t: String); } -pub fn new(l: lexer::Lexer) -> Parser { +pub fn new_parser(l: lexer::Lexer) -> Parser { let mut p: Parser = Parser { lexer: l, cur_token: token::Token { @@ -26,13 +35,14 @@ pub fn new(l: lexer::Lexer) -> Parser { literal: String::new(), type_: String::new(), }, + errors: Vec::new(), }; p.next_token(); p.next_token(); p } -impl PaserTrait for Parser { +impl ParserTrait for Parser { fn next_token(&mut self) { self.cur_token = token::Token { literal: String::from(&self.peek_token.literal), @@ -41,7 +51,91 @@ impl PaserTrait for Parser { self.peek_token = self.lexer.next_token(); } - fn parse_program(&self) -> ast::Program { - todo!() + fn parse_program(&mut self) -> ast::Program { + let mut program = ast::Program { + statements: Vec::new(), + }; + while &self.cur_token.type_ != EOF { + if let Some(stmt) = self.parse_statement() { + program.statements.push(stmt); + } + self.next_token(); + } + program + } + + fn parse_statement(&mut self) -> Option> { + match self.cur_token.type_.as_str() { + token::LET => self.parse_let_statement(), + _ => None, + } + } + + fn cur_token_is(&self, t: String) -> bool { + self.cur_token.type_ == t + } + + fn peek_token_is(&self, t: String) -> bool { + self.peek_token.type_ == t + } + + fn expect_peek(&mut self, t: String) -> bool { + if self.peek_token_is(t) { + self.next_token(); + true + } else { + false + } + } + + fn parse_let_statement(&mut self) -> Option> { + let mut stmt = ast::LetStatement { + token: token::Token { + literal: String::from(&self.cur_token.literal), + type_: String::from(&self.cur_token.type_), + }, + name: ast::Identifier { + token: token::Token { + literal: String::new(), + type_: String::new(), + }, + value: String::new(), + }, + value: ast::Expression {}, + }; + + if !self.expect_peek(token::IDENT.to_string()) { + return None; + } + + stmt.name = ast::Identifier { + token: token::Token { + literal: String::from(&self.cur_token.literal), + type_: String::from(&self.cur_token.type_), + }, + value: String::from(&self.cur_token.literal), + }; + + if !self.expect_peek(token::ASSIGN.to_string()) { + return None; + } + + while !self.cur_token_is(token::SEMICOLON.to_string()) { + self.next_token(); + } + + Some(Box::from(stmt)) + } + + fn errors(&self) -> &Vec { + &self.errors + } + + fn peek_error(&mut self, t: String) { + let msg = format!( + "expected next token to be {}, got {} instead", + t, self.peek_token.type_ + ); + self.errors.push(msg); } } diff --git a/src/repl/mod.rs b/src/repl/mod.rs index 4781a87..72d64dc 100644 --- a/src/repl/mod.rs +++ b/src/repl/mod.rs @@ -1,5 +1,7 @@ -use crate::lexer::LexerTraits; use crate::lexer::new; +use crate::parser::Parser; +use crate::parser::ParserTrait; +use crate::parser::new_parser; const PROMPT: &str = ">> "; @@ -15,13 +17,11 @@ pub fn start_repl() { if input == "exit" { break; } - let mut lexer = new(input.to_string()); - loop { - let token = lexer.next_token(); - if token.type_ == "EOF" { - break; - } - println!("Token: {:?}, Literal: {:?}", token.type_, token.literal); + let lexer = new(input.to_string()); + let mut parser: Parser = new_parser(lexer); + let program = parser.parse_program(); + for stmt in program.statements { + println!("{:?}", stmt.token_literal()); } } }