From 013221143844275d20024f935db6f01902a5a054 Mon Sep 17 00:00:00 2001 From: Slendi Date: Sun, 16 Jul 2023 22:22:28 +0300 Subject: [PATCH] =?UTF-8?q?=C3=8Embun=C4=83t=C4=83=C8=9Bire=20CLI,=20organ?= =?UTF-8?q?izare=20cod,=20primul=20release!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Slendi --- Cargo.lock | 2 +- Cargo.toml | 4 +- src/main.rs | 134 +++++----------------------------------------------- src/repl.rs | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 126 deletions(-) create mode 100644 src/repl.rs diff --git a/Cargo.lock b/Cargo.lock index d52f8e0..b18c6db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,7 +242,7 @@ dependencies = [ [[package]] name = "rolang" -version = "0.1.0" +version = "1.0.0" dependencies = [ "anyhow", "crossterm", diff --git a/Cargo.toml b/Cargo.toml index 85250ec..c388eb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,8 @@ [package] name = "rolang" -version = "0.1.0" +version = "1.0.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] anyhow = "1.0.71" crossterm = "0.26.1" diff --git a/src/main.rs b/src/main.rs index 61ff7eb..696e544 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,68 +3,26 @@ use std::fs::read_to_string; use std::io::Write; use std::process::exit; -use std::{path::Path, rc::Rc, cell::RefCell}; +use std::path::Path; use std::env; -use crossterm::cursor; -use home::home_dir; -use interpreter::{Environment, eval}; -use rustyline::{Editor, history::DefaultHistory, validate::Validator, hint::{Hinter, HistoryHinter}, Context, highlight::Highlighter, Helper, completion::{Completer, Pair}, error::ReadlineError, config::Configurer}; -use lexer::Lexer; -use parser::Parser; - -use crate::interpreter::Object; +use repl::{repl, exec}; mod lexer; mod parser; mod interpreter; +mod repl; -struct CustomHelper { - hinter: HistoryHinter, -} - -impl Validator for CustomHelper {} -impl Highlighter for CustomHelper {} -impl Helper for CustomHelper {} -impl Completer for CustomHelper { - type Candidate = Pair; - - fn complete(&self, line: &str, pos: usize, _: &Context<'_>) -> Result<(usize, Vec), ReadlineError> { - let mut completions = Vec::new(); - let word_start = match line[..pos].rfind(|c: char| c.is_whitespace() || c == '(' || c == ')') { - Some(index) => index + 1, - None => 0, - }; - let word = &line[word_start..pos]; - - if !word.is_empty() { - for i in vec!["dacă", "până când", "pânăcând", "cât timp", "câttimp", "atunci", "altfel", "pentru", "execută", "scrie", "citește"] { - if i.starts_with(word) { - completions.push(Pair { - display: i.to_string(), - replacement: i.to_string(), - }); - } - } - } - - Ok((word_start, completions)) - } -} - -impl Hinter for CustomHelper { - type Hint = String; - fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option { - self.hinter.hint(line, pos, ctx) - } -} - -type CustomEditor = Editor; +const VERSION: &str = env!("CARGO_PKG_VERSION"); fn main() { - let envb = Rc::new(RefCell::new(Environment::new())); - let args: Vec<_> = env::args().collect(); + for i in &args { + if matches!(i.as_str(), "--version" | "-v" | "--versiune") { + println!("{} v{}", args[0], VERSION); + exit(0); + } + } if args.len() > 1 { let mut filep = args[1].clone(); let mut file = Path::new(&filep); @@ -78,77 +36,9 @@ fn main() { } let input = read_to_string(file).unwrap(); - let lex = Lexer::new(input); - let mut parser = Parser::new(lex); - let root = parser.parse(); - //root.print(String::new(), true); - - if parser.errors.len() > 0 { - println!("Erori găsite:"); - for (pos, msg) in parser.errors.iter().enumerate() { - println!(" {}: {}", pos+1, msg); - } - return; - } - - eval(root, Some(Rc::clone(&envb))).unwrap(); + exec(&input).unwrap(); return; } - let mut rl_hist = home_dir().unwrap(); - rl_hist.push(Path::new(".rolang_history")); - let rl_hist = rl_hist.to_str().unwrap(); - - let mut rl = CustomEditor::new().unwrap(); - if rl.load_history(rl_hist).is_err() { - println!("Istoric nou creat."); - } - - rl.set_helper(Some(CustomHelper { hinter: HistoryHinter { }})); - rl.set_completion_type(rustyline::CompletionType::Circular); - - loop { - let readline = rl.readline("> "); - if readline.is_err() { - break; - } - let mut input = readline.unwrap(); - - if input.trim().is_empty() { - continue; - } - - rl.add_history_entry(input.clone()).unwrap(); - - input.push('\n'); - - let lex = Lexer::new(input); - let mut parser = Parser::new(lex); - let root = parser.parse(); - //root.print(String::new(), true); - - if parser.errors.len() > 0 { - println!("Erori găsite:"); - for (pos, msg) in parser.errors.iter().enumerate() { - println!(" {}: {}", pos+1, msg); - } - continue; - } - - let res = eval(root, Some(Rc::clone(&envb))); - match cursor::position() { - Ok((x, _)) => if x != 0 { - println!("\x1b[7m%\x1b[0m"); - }, - Err(_) => () - }; - match res { - Err(e) => println!("Eroare ROLang: {}", e), - Ok(res) => if res != Object::Null { - println!("Rezultat: {}", res); - } - } - } - - rl.save_history(rl_hist).unwrap(); + repl(); } diff --git a/src/repl.rs b/src/repl.rs new file mode 100644 index 0000000..ffdef5c --- /dev/null +++ b/src/repl.rs @@ -0,0 +1,119 @@ +use rustyline::{Editor, history::DefaultHistory, validate::Validator, hint::{Hinter, HistoryHinter}, Context, highlight::Highlighter, Helper, completion::{Completer, Pair}, error::ReadlineError, config::Configurer}; +use crossterm::cursor; +use home::home_dir; +use std::{rc::Rc, cell::RefCell}; +use std::path::Path; +use anyhow::{anyhow, Result}; + +use crate::interpreter::{Environment, eval}; +use crate::lexer::Lexer; +use crate::parser::Parser; +use crate::interpreter::Object; + +pub struct CustomHelper { + pub hinter: HistoryHinter, +} + +impl Validator for CustomHelper {} +impl Highlighter for CustomHelper {} +impl Helper for CustomHelper {} +impl Completer for CustomHelper { + type Candidate = Pair; + + fn complete(&self, line: &str, pos: usize, _: &Context<'_>) -> Result<(usize, Vec), ReadlineError> { + let mut completions = Vec::new(); + let word_start = match line[..pos].rfind(|c: char| c.is_whitespace() || c == '(' || c == ')') { + Some(index) => index + 1, + None => 0, + }; + let word = &line[word_start..pos]; + + if !word.is_empty() { + for i in vec!["dacă", "până când", "pânăcând", "cât timp", "câttimp", "atunci", "altfel", "pentru", "execută", "scrie", "citește"] { + if i.starts_with(word) { + completions.push(Pair { + display: i.to_string(), + replacement: i.to_string(), + }); + } + } + } + + Ok((word_start, completions)) + } +} + +impl Hinter for CustomHelper { + type Hint = String; + fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option { + self.hinter.hint(line, pos, ctx) + } +} + +pub type RoLangReadlineEditor = Editor; + +pub fn exec(input: &str) -> Result { + let envb = Rc::new(RefCell::new(Environment::new())); + + let lex = Lexer::new(input.to_string()); + let mut parser = Parser::new(lex); + let root = parser.parse(); + //root.print(String::new(), true); + + if parser.errors.len() > 0 { + println!("Erori găsite:"); + for (pos, msg) in parser.errors.iter().enumerate() { + println!(" {}: {}", pos+1, msg); + } + return Err(anyhow!("Există erori.")); + } + + eval(root, Some(Rc::clone(&envb))) +} + +pub fn repl() { + let mut rl_hist = home_dir().unwrap(); + rl_hist.push(Path::new(".rolang_history")); + let rl_hist = rl_hist.to_str().unwrap(); + + let mut rl = RoLangReadlineEditor::new().unwrap(); + if rl.load_history(rl_hist).is_err() { + println!("Istoric nou creat."); + } + + rl.set_helper(Some(CustomHelper { hinter: HistoryHinter { }})); + rl.set_completion_type(rustyline::CompletionType::Circular); + + loop { + let readline = rl.readline("> "); + if readline.is_err() { + break; + } + let mut input = readline.unwrap(); + + if input.trim().is_empty() { + continue; + } + + rl.add_history_entry(input.clone()).unwrap(); + + input.push('\n'); + + let res = exec(&input); + match cursor::position() { + Ok((x, _)) => if x != 0 { + println!("\x1b[7m%\x1b[0m"); + }, + Err(_) => () + }; + match res { + Err(e) => println!("Eroare ROLang: {}", e), + Ok(res) => if res != Object::Null { + println!("Rezultat: {}", res); + } + } + } + + rl.save_history(rl_hist).unwrap(); + +}