Add simple tokenizer for easiest.reid
This commit is contained in:
		
						commit
						cca69976dd
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | /target | ||||||
							
								
								
									
										7
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | # This file is automatically @generated by Cargo. | ||||||
|  | # It is not intended for manual editing. | ||||||
|  | version = 3 | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "reid" | ||||||
|  | version = "0.1.0" | ||||||
							
								
								
									
										8
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | [package] | ||||||
|  | name = "reid" | ||||||
|  | version = "0.1.0" | ||||||
|  | edition = "2021" | ||||||
|  | 
 | ||||||
|  | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||||
|  | 
 | ||||||
|  | [dependencies] | ||||||
							
								
								
									
										4
									
								
								easiest.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								easiest.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | // Hello, comment here! | ||||||
|  | let hello = 32; | ||||||
|  | let beep =  | ||||||
|  |     hello ; | ||||||
							
								
								
									
										9
									
								
								easy.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								easy.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | // Arithmetic, function calls and imports! | ||||||
|  | 
 | ||||||
|  | import std::print; | ||||||
|  | 
 | ||||||
|  | let arithmetic = 3 + 2 * 5 + 1 * 2; | ||||||
|  | let multiplier = 5 * 2; | ||||||
|  | 
 | ||||||
|  | let result = arithmetic * multiplier + arithmetic; | ||||||
|  | print(result); | ||||||
							
								
								
									
										8
									
								
								hard.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								hard.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | // New types, type-casting | ||||||
|  | 
 | ||||||
|  | import std::print; | ||||||
|  | 
 | ||||||
|  | let text: string = "hello there!"; | ||||||
|  | let value: i16 = 123; | ||||||
|  | 
 | ||||||
|  | print(text + (value as string)); | ||||||
							
								
								
									
										12
									
								
								medium.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								medium.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | // if-statements, functions | ||||||
|  | 
 | ||||||
|  | import std::print; | ||||||
|  | 
 | ||||||
|  | fn fibonacci(value: i32) -> i32 { | ||||||
|  |     if value < 3 { | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |     return fibonacci(value - 1) + fibonacci(value - 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | print(fibonacci(15)); | ||||||
							
								
								
									
										138
									
								
								src/lexer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/lexer.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,138 @@ | |||||||
|  | use std::{fmt::Debug, iter::Peekable, str::Chars}; | ||||||
|  | 
 | ||||||
|  | pub static EASIEST: &str = include_str!("../easiest.reid"); | ||||||
|  | // pub static EASY: &str = include_str!("../easy.reid");
 | ||||||
|  | // pub static MEDIUM: &str = include_str!("../medium.reid");
 | ||||||
|  | // pub static HARD: &str = include_str!("../hard.reid");
 | ||||||
|  | 
 | ||||||
|  | static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; | ||||||
|  | 
 | ||||||
|  | pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<Token>, String> { | ||||||
|  |     let to_tokenize = to_tokenize.into(); | ||||||
|  |     let mut position = (0, 1); | ||||||
|  |     let mut cursor = Cursor { | ||||||
|  |         char_stream: to_tokenize.chars().peekable(), | ||||||
|  |         position, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let mut tokens = Vec::new(); | ||||||
|  | 
 | ||||||
|  |     while let Some(character) = &cursor.consume() { | ||||||
|  |         position.0 += 1; | ||||||
|  |         if *character == '\n' { | ||||||
|  |             position.1 += 1; | ||||||
|  |             position.0 = 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let peek = cursor.peek(); | ||||||
|  | 
 | ||||||
|  |         let variant = match character { | ||||||
|  |             // Whitespace
 | ||||||
|  |             w if w.is_whitespace() => continue, | ||||||
|  |             // Comments
 | ||||||
|  |             '/' if peek == Some(&'/') => { | ||||||
|  |                 while !matches!(&cursor.peek(), Some('\n')) { | ||||||
|  |                     cursor.consume(); | ||||||
|  |                 } | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             // "words"
 | ||||||
|  |             c if c.is_alphabetic() => { | ||||||
|  |                 let mut value = character.to_string(); | ||||||
|  |                 while let Some(c) = &cursor.peek() { | ||||||
|  |                     if !c.is_ascii_alphanumeric() { | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                     value += &c.to_string(); | ||||||
|  |                     cursor.consume(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Check for keywords
 | ||||||
|  |                 let variant = match value.as_str() { | ||||||
|  |                     "let" => TokenVariant::LetKeyword, | ||||||
|  |                     _ => TokenVariant::Identifier(value), | ||||||
|  |                 }; | ||||||
|  |                 variant | ||||||
|  |             } | ||||||
|  |             // Decimals
 | ||||||
|  |             c if DECIMAL_NUMERICS.contains(c) => { | ||||||
|  |                 let mut value = character.to_string(); | ||||||
|  |                 while let Some(c) = &cursor.peek() { | ||||||
|  |                     if !DECIMAL_NUMERICS.contains(c) { | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                     value += &c.to_string(); | ||||||
|  |                     cursor.consume(); | ||||||
|  |                 } | ||||||
|  |                 TokenVariant::DecimalValue(value) | ||||||
|  |             } | ||||||
|  |             // Single character tokens
 | ||||||
|  |             '=' => TokenVariant::Equals, | ||||||
|  |             ';' => TokenVariant::Semicolon, | ||||||
|  |             // Invalid token
 | ||||||
|  |             _ => Err(format!( | ||||||
|  |                 "Unknown token '{}' at {}, {}", | ||||||
|  |                 character, position.0, position.1 | ||||||
|  |             ))?, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         tokens.push(Token { variant, position }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     position.0 += 1; | ||||||
|  | 
 | ||||||
|  |     tokens.push(Token { | ||||||
|  |         variant: TokenVariant::Eof, | ||||||
|  |         position, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     Ok(tokens) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Token { | ||||||
|  |     variant: TokenVariant, | ||||||
|  |     position: Position, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Debug for Token { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|  |         f.write_fmt(format_args!( | ||||||
|  |             "{:?} (Ln {}, Col {})", | ||||||
|  |             self.variant, self.position.1, self.position.0 | ||||||
|  |         )) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub type Position = (u32, u32); | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum TokenVariant { | ||||||
|  |     LetKeyword, | ||||||
|  |     Semicolon, | ||||||
|  |     Equals, | ||||||
|  |     Identifier(String), | ||||||
|  |     /// Number with at most one decimal point
 | ||||||
|  |     DecimalValue(String), | ||||||
|  |     Eof, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Cursor<'a> { | ||||||
|  |     pub position: Position, | ||||||
|  |     char_stream: Peekable<Chars<'a>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> Cursor<'a> { | ||||||
|  |     fn consume(&mut self) -> Option<char> { | ||||||
|  |         let next = self.char_stream.next(); | ||||||
|  |         self.position.0 += 1; | ||||||
|  |         if let Some('\n') = next { | ||||||
|  |             self.position.1 += 1; | ||||||
|  |             self.position.0 = 0; | ||||||
|  |         } | ||||||
|  |         next | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn peek(&mut self) -> Option<&char> { | ||||||
|  |         self.char_stream.peek() | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | use crate::lexer::EASIEST; | ||||||
|  | 
 | ||||||
|  | mod lexer; | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     let token_stream = lexer::tokenize(EASIEST).unwrap(); | ||||||
|  | 
 | ||||||
|  |     dbg!(&token_stream); | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user