diff options
author | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-15 17:00:48 +0300 |
---|---|---|
committer | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-15 17:00:48 +0300 |
commit | 95e69fb5d1c3c47650c4df38d3fc62c7f0eed9c1 (patch) | |
tree | 24762fbadaef5eb2eadad293ed9dd12b427b5bf7 | |
parent | 233b91f20e9b7ede3a2aa25ee9f1342b216f30b0 (diff) | |
download | myslip-95e69fb5d1c3c47650c4df38d3fc62c7f0eed9c1.tar.gz myslip-95e69fb5d1c3c47650c4df38d3fc62c7f0eed9c1.zip |
feat: read binds from files, evaluate expression from file
-rw-r--r-- | src/main.rs | 160 |
1 files changed, 127 insertions, 33 deletions
diff --git a/src/main.rs b/src/main.rs index 8a09cfd..639e675 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,13 +2,106 @@ use myslip::parse::parsetree::parse_to_ast; use myslip::sexp::{SExp, SExp::*, SLeaf::Nil, util::scons}; use myslip::r#type::Type::NilType; -use std::{io, io::Write}; +use std::{io, io::Write, io::Read, env}; +use std::fs::File; + + +fn read_bind_files( + file_names: Vec<String> +) -> Result<Vec<SExp>, String> { + let mut res = vec![]; + for name in file_names { + let mut file = File::open(name).map_err(|e| e.to_string())?; + let mut contents = String::new(); + file.read_to_string(&mut contents) + .map_err(|e| e.to_string())?; + res.extend(parse_to_ast(&contents)?.parts()); + } + Ok(res) +} + +fn read_file_to_execute( + file_name: String +) -> Result<SExp, String> { + let mut file = File::open(file_name) + .map_err(|e| e.to_string())?; + let mut contents = String::new(); + file.read_to_string(&mut contents) + .map_err(|e| e.to_string())?; + match parse_to_ast(&contents) { + Ok(SCons(a, b)) if *b == Atom(Nil) => Ok(*a), + t => t + } +} fn main() { - match repl() { - Ok(()) => println!("bye :)"), - Err(e) => println!("Error: {}", e), + + let mut file_to_execute: Option<String> = None; + + let mut bind_files: Vec<String> = vec![]; + + let mut next_is_load = false; + for arg in env::args() { + + if next_is_load { + bind_files.push(arg); + next_is_load = false; + continue; + } + + match arg.as_str() { + s if s.ends_with("myslip") => continue, + "-l" | "--load" => next_is_load = true, + s => match file_to_execute { + Some(n) => { + println!("Error: can't execute both '{}' and '{}', please specify just one file", s, n); + return; + }, + None => file_to_execute = Some(s.to_string()), + } + } + } + if next_is_load { + println!( +"Error: '--load' can't be the last element of the argument list " + ); + return; + } + + let binds = match read_bind_files(bind_files) { + Ok(x) => x, + Err(e) => { + println!( + "Error reading declarations from files: {}", + e.to_string() + ); + return; + } + }; + + match file_to_execute { + Some(name) => { + let mut exp = match read_file_to_execute(name) { + Ok(e) => e, + Err(e) => { + println!("Error reading source file: {e}"); + return; + } + }; + execute_expression(&binds, exp); + }, + None => { + match repl(binds) { + Ok(()) => println!("bye :)"), + Err(e) => println!("Error: {}", e), + } + } + } + + + + } fn prompt_line(stdin: &io::Stdin, stdout: &mut io::Stdout) -> Result<(bool, String), io::Error> { @@ -22,13 +115,39 @@ fn prompt_line(stdin: &io::Stdin, stdout: &mut io::Stdout) -> Result<(bool, Stri Ok((code == 0, line)) } -fn repl() -> Result<(), io::Error> { +fn execute_expression(binds: &Vec<SExp>, mut exp: SExp) { + + for bind in binds.into_iter().rev() { + exp = scons(bind.clone(), exp); + } + + let ty = match exp + .type_check() + .map_err(|e| e.to_string()) { + Ok(t) => t, + Err(e) => { + println!("Type error: {}", e); + return; + }, + }; + + let result = match exp.multistep() { + Ok(t) => t, + Err(e) => { + println!("Runtime error: {}", e); + return; + }, + }; + + println!("{} : {}", result, ty); + +} + +fn repl(mut binds: Vec<SExp>) -> Result<(), io::Error> { let stdin = io::stdin(); let mut stdout = io::stdout(); - let mut binds: Vec<SExp> = vec![]; - loop { let (eof, input) = prompt_line(&stdin, &mut stdout)?; @@ -64,32 +183,7 @@ fn repl() -> Result<(), io::Error> { } } - let mut expression = orig_expression.clone(); - - for i in 1..=binds.len() { - expression = scons(binds[binds.len() - i].clone(), expression); - } - - let ty = match expression - .type_check() - .map_err(|e| e.to_string()) { - Ok(t) => t, - Err(e) => { - println!("Type error: {}", e); - continue; - }, - }; - - let result = match expression.multistep() { - Ok(t) => t, - Err(e) => { - println!("Runtime error: {}", e); - continue; - }, - }; - - println!("{} : {}", result, ty); - + execute_expression(&binds, orig_expression); } Ok(()) |