parsed ast of basic application
This commit is contained in:
		
							
								
								
									
										23
									
								
								src/ast/expression.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/ast/expression.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | use crate::token::{LiteralKind, Number, Token}; | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum Expression { | ||||||
|  |     Literal { | ||||||
|  |         literal: LiteralKind, | ||||||
|  |         token: Token, | ||||||
|  |     }, | ||||||
|  |     Unary, | ||||||
|  |     Binary, | ||||||
|  |     Call { | ||||||
|  |         callee: Box<Expression>, | ||||||
|  |         arguments: Vec<Expression>, | ||||||
|  |     }, | ||||||
|  |     Grouping, | ||||||
|  |     Variable { | ||||||
|  |         name: String, | ||||||
|  |         token: Token, | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub enum BinaryOperator {} | ||||||
|  | pub enum UnaryOperator {} | ||||||
| @@ -1,5 +1,9 @@ | |||||||
|  | mod expression; | ||||||
|  | pub use expression::*; | ||||||
|  | 
 | ||||||
| use crate::token::Token; | use crate::token::Token; | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
| pub struct Module { | pub struct Module { | ||||||
|     pub statements: Vec<Statement>, |     pub statements: Vec<Statement>, | ||||||
| } | } | ||||||
| @@ -19,13 +23,3 @@ pub struct ParameterDeclaration { | |||||||
|     pub name: Token, |     pub name: Token, | ||||||
|     pub typename: Token, |     pub typename: Token, | ||||||
| } | } | ||||||
| 
 |  | ||||||
| #[derive(Debug)] |  | ||||||
| pub enum Expression { |  | ||||||
|     Identifier(Token), |  | ||||||
|     FunctionCall { |  | ||||||
|         function: Box<Expression>, |  | ||||||
|         arguments: Vec<Expression>, |  | ||||||
|         return_type: Option<Token>, |  | ||||||
|     }, |  | ||||||
| } |  | ||||||
| @@ -31,6 +31,7 @@ impl Lexer { | |||||||
|             self.next_token(); |             self.next_token(); | ||||||
|         } |         } | ||||||
|         self.clean_newlines(); |         self.clean_newlines(); | ||||||
|  |         self.push(TokenKind::EndOfFile); | ||||||
|         self.tokens |         self.tokens | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -118,9 +119,6 @@ impl Lexer { | |||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if self.is_eof() { |  | ||||||
|                 todo!("Not sure if handling is necessary") |  | ||||||
|             } |  | ||||||
|             let s = self.current_scan(0, 0); |             let s = self.current_scan(0, 0); | ||||||
|             if let Ok(k) = TryInto::<KeywordKind>::try_into(s.as_str()) { |             if let Ok(k) = TryInto::<KeywordKind>::try_into(s.as_str()) { | ||||||
|                 self.push(TokenKind::Keyword(k)); |                 self.push(TokenKind::Keyword(k)); | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ mod parse; | |||||||
| mod token; | mod token; | ||||||
|  |  | ||||||
| fn main() { | fn main() { | ||||||
|     use format::Formatter; |  | ||||||
|     use lexer::Lexer; |     use lexer::Lexer; | ||||||
|     const BASIC: &str = r#" |     const BASIC: &str = r#" | ||||||
| function hello(name: string){ | function hello(name: string){ | ||||||
| @@ -22,6 +21,6 @@ hello(); | |||||||
|     let lexer = Lexer::new(BASIC, Some("basic.file".to_string())); |     let lexer = Lexer::new(BASIC, Some("basic.file".to_string())); | ||||||
|     let tokens = lexer.lex(); |     let tokens = lexer.lex(); | ||||||
|     let mut parser = Parser::new(tokens); |     let mut parser = Parser::new(tokens); | ||||||
|     let statement = parser.statement(); |     let module = parser.module(); | ||||||
|     println!("{statement:?}"); |     println!("{module:?}"); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										74
									
								
								src/parse/expression.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/parse/expression.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | use crate::{ast, expect_token, get_token, match_token, token::TokenKind}; | ||||||
|  |  | ||||||
|  | use super::Parser; | ||||||
|  |  | ||||||
|  | impl Parser { | ||||||
|  |     pub fn expression(&mut self) -> ast::Expression { | ||||||
|  |         self.call() | ||||||
|  |     } | ||||||
|  |     fn equality(&mut self) -> ast::Expression { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  |     fn comparison(&mut self) -> ast::Expression { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  |     fn term(&mut self) -> ast::Expression { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  |     fn factor(&mut self) -> ast::Expression { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  |     fn unary(&mut self) -> ast::Expression { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  |     fn call(&mut self) -> ast::Expression { | ||||||
|  |         let mut e = self.primary(); | ||||||
|  |  | ||||||
|  |         if match_token!(self, TokenKind::LeftParen) { | ||||||
|  |             let mut arguments = Vec::new(); | ||||||
|  |             while !match_token!(self, TokenKind::RightParen) { | ||||||
|  |                 arguments.push(self.expression()); | ||||||
|  |                 if !match_token!(self, TokenKind::Comma) { | ||||||
|  |                     expect_token!(self, TokenKind::RightParen, "RightParen"); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             e = ast::Expression::Call { | ||||||
|  |                 callee: Box::new(e), | ||||||
|  |                 arguments, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         e | ||||||
|  |     } | ||||||
|  |     fn primary(&mut self) -> ast::Expression { | ||||||
|  |         if let Some((token, TokenKind::Literal(literal))) = get_token!(self, TokenKind::Literal(_)) | ||||||
|  |         { | ||||||
|  |             return ast::Expression::Literal { literal, token }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if let Some((token, TokenKind::Identifier(name))) = | ||||||
|  |             get_token!(self, TokenKind::Identifier(_)) | ||||||
|  |         { | ||||||
|  |             return ast::Expression::Variable { name, token }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         todo!("Unknown expression {:?}", self.peek()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use crate::{ast::Expression, lexer::Lexer, parse::Parser, token::TokenKind}; | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_identifier() { | ||||||
|  |         let tokens = Lexer::new("my_var", None).lex(); | ||||||
|  |         let mut parser = Parser::new(tokens); | ||||||
|  |         let expr = parser.expression(); | ||||||
|  |         let Expression::Variable { name, token } = expr else { | ||||||
|  |             panic!() | ||||||
|  |         }; | ||||||
|  |         assert_eq!("my_var", name) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,9 +1,10 @@ | |||||||
| #[macro_export] | #[macro_export] | ||||||
| macro_rules! expect_token { | macro_rules! expect_token { | ||||||
|     ($self:ident, $expect:pat) => { |     ($self:ident, $expect:pat, $help:literal) => { | ||||||
|         let t = $self.consume(); |         let t = $self.consume(); | ||||||
|         if !matches!(t.kind, $expect) { |         let kind = t.as_ref().map(|t| &t.kind); | ||||||
|             todo!("Expected token, found {:?}", t.kind) |         if !matches!(kind, Some($expect)) { | ||||||
|  |             todo!("Expected token ({}), found {:?}.", $help, t) | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| @@ -12,10 +13,11 @@ macro_rules! expect_token { | |||||||
| macro_rules! expect_identifier { | macro_rules! expect_identifier { | ||||||
|     ($self:ident) => {{ |     ($self:ident) => {{ | ||||||
|         let t = $self.consume(); |         let t = $self.consume(); | ||||||
|         if !matches!(t.kind, TokenKind::Identifier(_)) { |         let kind = t.as_ref().map(|t| &t.kind); | ||||||
|             todo!("Expected token, found {:?}", t.kind) |         if !matches!(kind, Some(TokenKind::Identifier(_))) { | ||||||
|  |             todo!("Expected identifier, found {:?}", t); | ||||||
|         } |         } | ||||||
|         t |         t.unwrap() | ||||||
|     }}; |     }}; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -23,10 +25,11 @@ macro_rules! expect_identifier { | |||||||
| macro_rules! expect_any_keyword { | macro_rules! expect_any_keyword { | ||||||
|     ($self:ident) => {{ |     ($self:ident) => {{ | ||||||
|         let t = $self.consume(); |         let t = $self.consume(); | ||||||
|         if !matches!(t.kind, TokenKind::Keyword(_)) { |         let kind = t.as_ref().map(|t| &t.kind); | ||||||
|             todo!("Expected token, found {:?}", t.kind) |         if !matches!(kind, Some(TokenKind::Keyword(_))) { | ||||||
|  |             todo!("Expected keyword, found {:?}", t) | ||||||
|         } |         } | ||||||
|         t |         t.unwrap() | ||||||
|     }}; |     }}; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -34,8 +37,9 @@ macro_rules! expect_any_keyword { | |||||||
| macro_rules! expect_keyword { | macro_rules! expect_keyword { | ||||||
|     ($self:ident, $keyword:pat) => { |     ($self:ident, $keyword:pat) => { | ||||||
|         let t = $self.consume(); |         let t = $self.consume(); | ||||||
|         if !matches!(t.kind, TokenKind::Keyword($keyword)) { |         let kind = t.as_ref().map(|t| &t.kind); | ||||||
|             todo!("Expected token, found {:?}", t.kind) |         if !matches!(kind, Some(TokenKind::Keyword($keyword))) { | ||||||
|  |             todo!("Expected keyword, found {:?}", t) | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| @@ -43,13 +47,39 @@ macro_rules! expect_keyword { | |||||||
| #[macro_export] | #[macro_export] | ||||||
| macro_rules! peek_keyword { | macro_rules! peek_keyword { | ||||||
|     ($self:ident, $keyword:pat) => { |     ($self:ident, $keyword:pat) => { | ||||||
|         matches!($self.peek().kind, TokenKind::Keyword($keyword)) |         matches!( | ||||||
|  |             $self.peek().map(|t| &t.kind), | ||||||
|  |             Some(TokenKind::Keyword($keyword)) | ||||||
|  |         ) | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| #[macro_export] | #[macro_export] | ||||||
| macro_rules! peek_match { | macro_rules! peek_match { | ||||||
|     ($self:ident, $p:pat) => { |     ($self:ident, $p:pat) => { | ||||||
|         matches!($self.peek().kind, $p) |         matches!($self.peek().map(|t| &t.kind), Some($p)) | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[macro_export] | ||||||
|  | macro_rules! match_token { | ||||||
|  |     ($self:ident, $p:pat) => {{ | ||||||
|  |         let b = matches!($self.peek().map(|t| &t.kind), Some($p)); | ||||||
|  |         if b { | ||||||
|  |             $self.consume(); | ||||||
|  |         } | ||||||
|  |         b | ||||||
|  |     }}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[macro_export] | ||||||
|  | macro_rules! get_token { | ||||||
|  |     ($self:ident, $p:pat) => {{ | ||||||
|  |         let b = matches!($self.peek().map(|t| &t.kind), Some($p)); | ||||||
|  |         if b { | ||||||
|  |             $self.consume().map(|t| (t.clone(), t.kind)) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     }}; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
|  | mod expression; | ||||||
| mod macros; | mod macros; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     ast, expect_any_keyword, expect_identifier, expect_keyword, expect_token, peek_keyword, |     ast, expect_any_keyword, expect_identifier, expect_keyword, expect_token, match_token, | ||||||
|     peek_match, |     peek_keyword, peek_match, | ||||||
|     token::{KeywordKind, Token, TokenKind}, |     token::{KeywordKind, Token, TokenKind}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -13,26 +14,40 @@ pub struct Parser { | |||||||
|  |  | ||||||
| impl Parser { | impl Parser { | ||||||
|     pub fn new(tokens: Vec<Token>) -> Parser { |     pub fn new(tokens: Vec<Token>) -> Parser { | ||||||
|  |         let tokens = tokens | ||||||
|  |             .into_iter() | ||||||
|  |             .filter(|t| !matches!(t.kind, TokenKind::NewLine)) | ||||||
|  |             .collect::<Vec<_>>(); | ||||||
|  |  | ||||||
|         Self { tokens, current: 0 } |         Self { tokens, current: 0 } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn statement(&mut self) -> ast::Statement { |     pub fn module(&mut self) -> ast::Module { | ||||||
|  |         let mut statements = Vec::new(); | ||||||
|  |         while !match_token!(self, TokenKind::EndOfFile) { | ||||||
|  |             let s = self.statement(); | ||||||
|  |             println!("Parsed Statement {s:?}"); | ||||||
|  |             statements.push(s); | ||||||
|  |         } | ||||||
|  |         ast::Module { statements } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn statement(&mut self) -> ast::Statement { | ||||||
|         if peek_keyword!(self, KeywordKind::function) { |         if peek_keyword!(self, KeywordKind::function) { | ||||||
|             return self.function_declaration(); |             return self.function_declaration(); | ||||||
|         } |         } | ||||||
|         return self.expression_statement(); |         self.expression_statement() | ||||||
|         todo!("No statement"); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn function_declaration(&mut self) -> ast::Statement { |     fn function_declaration(&mut self) -> ast::Statement { | ||||||
|         expect_keyword!(self, KeywordKind::function); |         expect_keyword!(self, KeywordKind::function); | ||||||
|         let id = expect_identifier!(self); |         let id = expect_identifier!(self); | ||||||
|         expect_token!(self, TokenKind::LeftParen); |         expect_token!(self, TokenKind::LeftParen, "LeftParen"); | ||||||
|  |  | ||||||
|         let mut parameters = Vec::new(); |         let mut parameters = Vec::new(); | ||||||
|         while peek_match!(self, TokenKind::Identifier(_)) { |         while peek_match!(self, TokenKind::Identifier(_)) { | ||||||
|             let name = expect_identifier!(self); |             let name = expect_identifier!(self); | ||||||
|             expect_token!(self, TokenKind::Colon); |             expect_token!(self, TokenKind::Colon, "Colon"); | ||||||
|             let typename = expect_any_keyword!(self); |             let typename = expect_any_keyword!(self); | ||||||
|             let parameter = ast::ParameterDeclaration { |             let parameter = ast::ParameterDeclaration { | ||||||
|                 name: name.clone(), |                 name: name.clone(), | ||||||
| @@ -41,9 +56,9 @@ impl Parser { | |||||||
|             parameters.push(parameter); |             parameters.push(parameter); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         expect_token!(self, TokenKind::RightParen); |         expect_token!(self, TokenKind::RightParen, "RightParen"); | ||||||
|  |  | ||||||
|         expect_token!(self, TokenKind::LeftCurly); |         expect_token!(self, TokenKind::LeftCurly, "LeftCurly"); | ||||||
|  |  | ||||||
|         let mut statements = Vec::new(); |         let mut statements = Vec::new(); | ||||||
|         while !peek_match!(self, TokenKind::RightCurly) { |         while !peek_match!(self, TokenKind::RightCurly) { | ||||||
| @@ -51,7 +66,7 @@ impl Parser { | |||||||
|             statements.push(statement); |             statements.push(statement); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         expect_token!(self, TokenKind::RightCurly); |         expect_token!(self, TokenKind::RightCurly, "RightCurly"); | ||||||
|  |  | ||||||
|         ast::Statement::FunctionDeclaration { |         ast::Statement::FunctionDeclaration { | ||||||
|             name: id.clone(), |             name: id.clone(), | ||||||
| @@ -61,17 +76,19 @@ impl Parser { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn expression_statement(&mut self) -> ast::Statement { |     fn expression_statement(&mut self) -> ast::Statement { | ||||||
|         todo!() |         let e = self.expression(); | ||||||
|  |         expect_token!(self, TokenKind::Semicolon, "Semicolon"); | ||||||
|  |         ast::Statement::Expression(e) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Parser { | impl Parser { | ||||||
|     fn peek(&self) -> &Token { |     fn peek(&self) -> Option<&Token> { | ||||||
|         &self.tokens[self.current] |         self.tokens.get(self.current) | ||||||
|     } |     } | ||||||
|     fn consume(&mut self) -> Token { |     fn consume(&mut self) -> Option<Token> { | ||||||
|         let token = &self.tokens[self.current]; |         let token = self.peek().cloned(); | ||||||
|         self.current += 1; |         self.current += 1; | ||||||
|         token.clone() |         token | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user