From 0122399d625152f9a3dafe9a74bb25cb0d6efbde Mon Sep 17 00:00:00 2001 From: Gaurav Gahlot Date: Thu, 11 Jul 2024 08:02:15 +0530 Subject: [PATCH 1/5] Fix all errors, all errors on the WORLD!!!! Signed-off-by: Gaurav Gahlot --- rustic-chimp/Cargo.toml | 6 ++++++ rustic-chimp/README.md | 3 +++ rustic-chimp/src/main.rs | 3 +++ 3 files changed, 12 insertions(+) create mode 100644 rustic-chimp/Cargo.toml create mode 100644 rustic-chimp/README.md create mode 100644 rustic-chimp/src/main.rs diff --git a/rustic-chimp/Cargo.toml b/rustic-chimp/Cargo.toml new file mode 100644 index 0000000..57a671c --- /dev/null +++ b/rustic-chimp/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rustic-chimp" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/rustic-chimp/README.md b/rustic-chimp/README.md new file mode 100644 index 0000000..870ac13 --- /dev/null +++ b/rustic-chimp/README.md @@ -0,0 +1,3 @@ +# RusticChimp + +An interpreter for the [Monkey programming language](https://monkeylang.org/) in Rust. diff --git a/rustic-chimp/src/main.rs b/rustic-chimp/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/rustic-chimp/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 843e5eed6ce184f8ab8b288da27116ee7087db3a Mon Sep 17 00:00:00 2001 From: Gaurav Gahlot Date: Tue, 16 Jul 2024 08:49:36 +0530 Subject: [PATCH 2/5] Your commit is writing checks your merge can't cash. Signed-off-by: Gaurav Gahlot --- rustic-chimp/src/lexer/mod.rs | 168 ++++++++++++++++++++++++++++++++++ rustic-chimp/src/lib.rs | 2 + rustic-chimp/src/token/mod.rs | 33 +++++++ 3 files changed, 203 insertions(+) create mode 100644 rustic-chimp/src/lexer/mod.rs create mode 100644 rustic-chimp/src/lib.rs create mode 100644 rustic-chimp/src/token/mod.rs diff --git a/rustic-chimp/src/lexer/mod.rs b/rustic-chimp/src/lexer/mod.rs new file mode 100644 index 0000000..f2ada31 --- /dev/null +++ b/rustic-chimp/src/lexer/mod.rs @@ -0,0 +1,168 @@ +use crate::token::{lookup_ident, Token}; + +struct Lexer<'a> { + /// input source + input: &'a str, + + /// current position in input (points to current char) + position: usize, + + /// current reading position in input (after current char) + read_position: usize, + + /// current char under examination + ch: char, +} + +impl<'a> Lexer<'a> { + pub fn new(input: &'a str) -> Self { + let mut lex = Lexer { + input, + position: 0, + read_position: 0, + ch: '\0', + }; + + lex.read_char(); + lex + } + + pub fn read_char(&mut self) { + self.ch = self.peek_char(); + self.position = self.read_position; + self.read_position += 1; + } + + fn peek_char(&self) -> char { + if self.read_position >= self.input.len() { + return '\0'; + } + + self.input.chars().nth(self.read_position).unwrap() + } + + fn next_token(&mut self) -> Token { + self.skip_whitespace(); + + let tok = match self.ch { + // operators + '=' => Token::Assign, + '+' => Token::Plus, + + // delimeters + ',' => Token::Comma, + ';' => Token::Semicolon, + '(' => Token::Lparen, + ')' => Token::Rparen, + '{' => Token::Lcurly, + '}' => Token::Rcurly, + + '\0' => Token::Eof, + _ => { + if is_letter(self.ch) { + return self.read_identifier(); + } + if is_digit(self.ch) { + return self.read_number(); + } + Token::Illegal + } + }; + + self.read_char(); + tok + } + + fn read_identifier(&mut self) -> Token { + let pos = self.position; + while is_letter(self.ch) { + self.read_char(); + } + + lookup_ident(&self.input[pos..self.position]) + } + + fn read_number(&mut self) -> Token { + let pos = self.position; + while is_digit(self.ch) { + self.read_char(); + } + + Token::Int(self.input[pos..self.position].parse().unwrap()) + } + + fn skip_whitespace(&mut self) { + while self.ch == ' ' || self.ch == '\t' || self.ch == '\n' || self.ch == '\r' { + self.read_char() + } + } +} + +fn is_digit(ch: char) -> bool { + ch.is_ascii_digit() +} + +fn is_letter(ch: char) -> bool { + ch.is_ascii_alphabetic() || ch == '_' +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_next_token() { + let input = "let five = 5; +let ten = 10; +let add = fn(x, y) { + x + y; +}; +let result = add(five, ten);"; + + let tests = vec![ + Token::Let, + Token::Ident("five".to_string()), + Token::Assign, + Token::Int(5), + Token::Semicolon, + Token::Let, + Token::Ident("ten".to_string()), + Token::Assign, + Token::Int(10), + Token::Semicolon, + Token::Let, + Token::Ident("add".to_string()), + Token::Assign, + Token::Function, + Token::Lparen, + Token::Ident("x".to_string()), + Token::Comma, + Token::Ident("y".to_string()), + Token::Rparen, + Token::Lcurly, + Token::Ident("x".to_string()), + Token::Plus, + Token::Ident("y".to_string()), + Token::Semicolon, + Token::Rcurly, + Token::Semicolon, + Token::Let, + Token::Ident("result".to_string()), + Token::Assign, + Token::Ident("add".to_string()), + Token::Lparen, + Token::Ident("five".to_string()), + Token::Comma, + Token::Ident("ten".to_string()), + Token::Rparen, + Token::Semicolon, + Token::Eof, + ]; + + let mut lex = Lexer::new(input); + for expected_token in tests { + let tok = lex.next_token(); + assert_eq!(expected_token, tok); + } + } +} diff --git a/rustic-chimp/src/lib.rs b/rustic-chimp/src/lib.rs new file mode 100644 index 0000000..e12719b --- /dev/null +++ b/rustic-chimp/src/lib.rs @@ -0,0 +1,2 @@ +pub mod lexer; +pub mod token; diff --git a/rustic-chimp/src/token/mod.rs b/rustic-chimp/src/token/mod.rs new file mode 100644 index 0000000..adaabe9 --- /dev/null +++ b/rustic-chimp/src/token/mod.rs @@ -0,0 +1,33 @@ +#[derive(Debug, Eq, PartialEq)] +pub enum Token { + Illegal, + Eof, + + // Identifiers + literals + Ident(String), + Int(i64), + + // Operators + Assign, // = + Plus, // + + + // Delimeters + Comma, // , + Semicolon, // ; + Lparen, // ( + Rparen, // ) + Lcurly, // { + Rcurly, // } + + // Keywords + Function, // fn + Let, // let +} + +pub fn lookup_ident(ident: &str) -> Token { + match ident { + "fn" => Token::Function, + "let" => Token::Let, + _ => Token::Ident(ident.to_string()), + } +} From ced4b652d140d26f7a9985b3b78849536afcbd85 Mon Sep 17 00:00:00 2001 From: Gaurav Gahlot Date: Tue, 16 Jul 2024 12:50:40 +0530 Subject: [PATCH 3/5] Don't push this commit Signed-off-by: Gaurav Gahlot --- rustic-chimp/src/lexer/mod.rs | 48 ++++++++++++++++++++++++++++++++++- rustic-chimp/src/token/mod.rs | 25 ++++++++++++++++-- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/rustic-chimp/src/lexer/mod.rs b/rustic-chimp/src/lexer/mod.rs index f2ada31..a70604b 100644 --- a/rustic-chimp/src/lexer/mod.rs +++ b/rustic-chimp/src/lexer/mod.rs @@ -48,6 +48,14 @@ impl<'a> Lexer<'a> { // operators '=' => Token::Assign, '+' => Token::Plus, + '-' => Token::Minus, + '!' => Token::Bang, + '*' => Token::Asterisk, + '/' => Token::Slash, + + // comparisons + '<' => Token::Lt, + '>' => Token::Gt, // delimeters ',' => Token::Comma, @@ -117,7 +125,16 @@ let ten = 10; let add = fn(x, y) { x + y; }; -let result = add(five, ten);"; + +let result = add(five, ten); +!-/*5; +5 < 10 > 5; + +if (5 < 10) { + return true; +} else { + return false; +}"; let tests = vec![ Token::Let, @@ -156,6 +173,35 @@ let result = add(five, ten);"; Token::Ident("ten".to_string()), Token::Rparen, Token::Semicolon, + Token::Bang, + Token::Minus, + Token::Slash, + Token::Asterisk, + Token::Int(5), + Token::Semicolon, + Token::Int(5), + Token::Lt, + Token::Int(10), + Token::Gt, + Token::Int(5), + Token::Semicolon, + Token::If, + Token::Lparen, + Token::Int(5), + Token::Lt, + Token::Int(10), + Token::Rparen, + Token::Lcurly, + Token::Return, + Token::True, + Token::Semicolon, + Token::Rcurly, + Token::Else, + Token::Lcurly, + Token::Return, + Token::False, + Token::Semicolon, + Token::Rcurly, Token::Eof, ]; diff --git a/rustic-chimp/src/token/mod.rs b/rustic-chimp/src/token/mod.rs index adaabe9..29d2c4d 100644 --- a/rustic-chimp/src/token/mod.rs +++ b/rustic-chimp/src/token/mod.rs @@ -8,8 +8,16 @@ pub enum Token { Int(i64), // Operators - Assign, // = - Plus, // + + Assign, // = + Plus, // + + Minus, // - + Bang, // ! + Asterisk, // * + Slash, // / + + // Comparisions + Lt, // < + Gt, // > // Delimeters Comma, // , @@ -22,12 +30,25 @@ pub enum Token { // Keywords Function, // fn Let, // let + True, // true + False, // false + If, // if + Else, // else + Return, // return } pub fn lookup_ident(ident: &str) -> Token { match ident { + // keywords "fn" => Token::Function, "let" => Token::Let, + "true" => Token::True, + "false" => Token::False, + "if" => Token::If, + "else" => Token::Else, + "return" => Token::Return, + + // identifier _ => Token::Ident(ident.to_string()), } } From ea8c5682d1e6de64c5e40b689cc97333bf164fb3 Mon Sep 17 00:00:00 2001 From: Gaurav Gahlot Date: Tue, 16 Jul 2024 13:25:49 +0530 Subject: [PATCH 4/5] if you're not using et, fuck off Signed-off-by: Gaurav Gahlot --- rustic-chimp/src/lexer/mod.rs | 39 +++++++++++++++++++++++++++-------- rustic-chimp/src/token/mod.rs | 6 ++++-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/rustic-chimp/src/lexer/mod.rs b/rustic-chimp/src/lexer/mod.rs index a70604b..5f1a929 100644 --- a/rustic-chimp/src/lexer/mod.rs +++ b/rustic-chimp/src/lexer/mod.rs @@ -45,26 +45,35 @@ impl<'a> Lexer<'a> { self.skip_whitespace(); let tok = match self.ch { - // operators - '=' => Token::Assign, + '=' => { + if self.peek_char() == '=' { + self.read_char(); + Token::Eq + } else { + Token::Assign + } + } + '!' => { + if self.peek_char() == '=' { + self.read_char(); + Token::NotEq + } else { + Token::Bang + } + } + '+' => Token::Plus, '-' => Token::Minus, - '!' => Token::Bang, '*' => Token::Asterisk, '/' => Token::Slash, - - // comparisons '<' => Token::Lt, '>' => Token::Gt, - - // delimeters ',' => Token::Comma, ';' => Token::Semicolon, '(' => Token::Lparen, ')' => Token::Rparen, '{' => Token::Lcurly, '}' => Token::Rcurly, - '\0' => Token::Eof, _ => { if is_letter(self.ch) { @@ -134,7 +143,11 @@ if (5 < 10) { return true; } else { return false; -}"; +} + +10 == 10; +10 != 9; +"; let tests = vec![ Token::Let, @@ -202,6 +215,14 @@ if (5 < 10) { Token::False, Token::Semicolon, Token::Rcurly, + Token::Int(10), + Token::Eq, + Token::Int(10), + Token::Semicolon, + Token::Int(10), + Token::NotEq, + Token::Int(9), + Token::Semicolon, Token::Eof, ]; diff --git a/rustic-chimp/src/token/mod.rs b/rustic-chimp/src/token/mod.rs index 29d2c4d..f6e982d 100644 --- a/rustic-chimp/src/token/mod.rs +++ b/rustic-chimp/src/token/mod.rs @@ -16,8 +16,10 @@ pub enum Token { Slash, // / // Comparisions - Lt, // < - Gt, // > + Lt, // < + Gt, // > + Eq, // == + NotEq, // != // Delimeters Comma, // , From b187743d12b7962f1ef41068e784b650d490883a Mon Sep 17 00:00:00 2001 From: Gaurav Gahlot Date: Tue, 16 Jul 2024 18:13:45 +0530 Subject: [PATCH 5/5] whooooooooooooooooooooooooooo Signed-off-by: Gaurav Gahlot --- rustic-chimp/src/lexer/mod.rs | 4 ++-- rustic-chimp/src/lib.rs | 1 + rustic-chimp/src/main.rs | 9 ++++++++- rustic-chimp/src/repl/mod.rs | 31 +++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 rustic-chimp/src/repl/mod.rs diff --git a/rustic-chimp/src/lexer/mod.rs b/rustic-chimp/src/lexer/mod.rs index 5f1a929..2f0a8d2 100644 --- a/rustic-chimp/src/lexer/mod.rs +++ b/rustic-chimp/src/lexer/mod.rs @@ -1,6 +1,6 @@ use crate::token::{lookup_ident, Token}; -struct Lexer<'a> { +pub struct Lexer<'a> { /// input source input: &'a str, @@ -41,7 +41,7 @@ impl<'a> Lexer<'a> { self.input.chars().nth(self.read_position).unwrap() } - fn next_token(&mut self) -> Token { + pub fn next_token(&mut self) -> Token { self.skip_whitespace(); let tok = match self.ch { diff --git a/rustic-chimp/src/lib.rs b/rustic-chimp/src/lib.rs index e12719b..808f21d 100644 --- a/rustic-chimp/src/lib.rs +++ b/rustic-chimp/src/lib.rs @@ -1,2 +1,3 @@ pub mod lexer; +pub mod repl; pub mod token; diff --git a/rustic-chimp/src/main.rs b/rustic-chimp/src/main.rs index e7a11a9..c77f3a6 100644 --- a/rustic-chimp/src/main.rs +++ b/rustic-chimp/src/main.rs @@ -1,3 +1,10 @@ +use std::io; + +use rustic_chimp::repl; + fn main() { - println!("Hello, world!"); + println!("Hello! This is the Monkey programming language!"); + println!("Feel free to type in commands"); + + repl::start(io::stdin(), io::stdout()); } diff --git a/rustic-chimp/src/repl/mod.rs b/rustic-chimp/src/repl/mod.rs new file mode 100644 index 0000000..0400c11 --- /dev/null +++ b/rustic-chimp/src/repl/mod.rs @@ -0,0 +1,31 @@ +use std::io::{self, BufRead, Read, Write}; + +use crate::{lexer::Lexer, token::Token}; + +const PROMPT: &str = ">> "; + +pub fn start(input: R, output: W) +where + R: Read, + W: Write, +{ + let mut reader = io::BufReader::new(input); + let mut writer = output; + + loop { + write!(writer, "{}", PROMPT).unwrap(); + writer.flush().unwrap(); + + let mut line = String::new(); + if reader.read_line(&mut line).is_err() { + return; + } + + let mut lex = Lexer::new(&line); + let mut tok = lex.next_token(); + while tok != Token::Eof { + println!("{:?}", tok); + tok = lex.next_token(); + } + } +}