aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joel.kronqvist@iki.fi>2025-08-15 17:00:48 +0300
committerJoel Kronqvist <joel.kronqvist@iki.fi>2025-08-15 17:00:48 +0300
commit95e69fb5d1c3c47650c4df38d3fc62c7f0eed9c1 (patch)
tree24762fbadaef5eb2eadad293ed9dd12b427b5bf7
parent233b91f20e9b7ede3a2aa25ee9f1342b216f30b0 (diff)
downloadmyslip-95e69fb5d1c3c47650c4df38d3fc62c7f0eed9c1.tar.gz
myslip-95e69fb5d1c3c47650c4df38d3fc62c7f0eed9c1.zip
feat: read binds from files, evaluate expression from file
-rw-r--r--src/main.rs160
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(())