/* relish: versatile lisp shell * Copyright (C) 2021 Ava Affine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ use dirs::home_dir; use relish::ast::{ast_to_string, eval, func_call, lex, new_ast, Ctr, FTable, VTable}; use relish::aux::configure; use rustyline::error::ReadlineError; use rustyline::Editor; use std::cell::RefCell; use std::env; use std::rc::Rc; fn main() { let mut rl = Editor::<()>::new(); const HIST_FILE: &str = "/.relish_hist"; const CONFIG_FILE_DEFAULT: &str = "/.relishrc"; let mut hist: String = "".to_owned(); let mut cfg: String = "".to_owned(); if let Some(home) = home_dir() { if let Some(h) = home.to_str() { hist = h.to_owned() + HIST_FILE; cfg = h.to_owned() + CONFIG_FILE_DEFAULT; } } if hist != "" { // ignore result. it loads or it doesnt. let _ = rl.load_history(&hist); } let vt = Rc::new(RefCell::new(VTable::new())); let conf_file; let ft; match env::var("RELISH_CFG_FILE") { Ok(s) => { conf_file = s }, Err(e) => { eprintln!("{}", e); conf_file = cfg; }, } match configure(conf_file, vt.clone()) { Ok(f) => ft = f, Err(e) => { ft = Rc::new(RefCell::new(FTable::new())); eprintln!("{}", e); }, } loop { let readline: Result; // Rust is pain let tmp_ft_clone = ft.clone(); // this is not okay let t_ft_c_b = tmp_ft_clone.borrow(); let pfunc = t_ft_c_b.get("CFG_RELISH_PROMPT"); if let Some(fnc) = pfunc { match func_call( fnc.clone(), new_ast(Ctr::None, Ctr::None), vt.clone(), ft.clone(), ) { Err(s) => { eprintln!("Couldnt generate prompt: {}", s); readline = rl.readline(""); } Ok(c) => match c { Ctr::Symbol(s) => readline = rl.readline(&s.to_owned()), Ctr::String(s) => readline = rl.readline(&s), Ctr::Integer(i) => readline = rl.readline(&format!("{}", i)), Ctr::Float(f) => readline = rl.readline(&format!("{}", f)), Ctr::Bool(b) => readline = rl.readline(&format!("{}", b)), Ctr::Seg(c) => readline = rl.readline(&ast_to_string(c.clone())), Ctr::None => readline = rl.readline(""), }, } } else { readline = rl.readline(""); } match readline { Ok(line) => { rl.add_history_entry(line.as_str()); let mut l = line.as_str().to_owned(); if !l.starts_with("(") { l = "(".to_owned() + &l; } if !l.ends_with(")") { l = l + ")"; } match lex(l) { Ok(a) => match eval(a.clone(), vt.clone(), ft.clone(), false) { Ok(a) => match a { Ctr::Symbol(s) => println!("{}", s), Ctr::String(s) => println!("{}", s), Ctr::Integer(i) => println!("{}", i), Ctr::Float(f) => println!("{}", f), Ctr::Bool(b) => println!("{}", b), Ctr::Seg(c) => println!("{}", ast_to_string(c.clone())), Ctr::None => (), }, Err(s) => { println!("{}", s); } }, Err(s) => { println!("{}", s); } } } Err(ReadlineError::Interrupted) => break, Err(ReadlineError::Eof) => return, Err(err) => { eprintln!("Prompt error: {:?}", err); break; } } } if hist != "" { rl.save_history(&hist).unwrap(); } }