diff options
author | Freya Murphy <freya@freyacat.org> | 2024-02-26 19:00:42 -0500 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2024-02-26 19:00:42 -0500 |
commit | 158bcae00dbe2af50e51468ad003fb594a858e6d (patch) | |
tree | d5639b745b2a24e417e8003694a8994354e2d708 /matrix-stdlib/src/io.rs | |
parent | fn call fix (diff) | |
download | matrix-158bcae00dbe2af50e51468ad003fb594a858e6d.tar.gz matrix-158bcae00dbe2af50e51468ad003fb594a858e6d.tar.bz2 matrix-158bcae00dbe2af50e51468ad003fb594a858e6d.zip |
changes
Diffstat (limited to 'matrix-stdlib/src/io.rs')
-rw-r--r-- | matrix-stdlib/src/io.rs | 181 |
1 files changed, 160 insertions, 21 deletions
diff --git a/matrix-stdlib/src/io.rs b/matrix-stdlib/src/io.rs index 288e99e..d72248c 100644 --- a/matrix-stdlib/src/io.rs +++ b/matrix-stdlib/src/io.rs @@ -1,36 +1,175 @@ -use matrix::{value::Value, self, vm::Vm, Result}; +use std::{io::{self, Read, Write}, cell::RefCell, fs::OpenOptions, rc::Rc}; + +use matrix::{value::Value, self, vm::Vm, Result, unpack_varargs, iter, unpack_args}; use matrix_macros::native_func; +use crate::{error, VmArgs}; -#[native_func(1, true)] -fn print(_vm: &mut Vm, args: Vec<Value>) -> Result<Value> { - let [values] = args.try_into().unwrap(); - if let Value::List(list) = values { - for (i, value) in list.iter().enumerate() { - print!("{}", value.boring_print()); - if i != 0 { - print!(" "); - } +#[native_func(0..)] +fn print(_: VmArgs, args: Vec<Value>) -> Result<Value> { + let ([], varags) = unpack_varargs!(args); + for (i, value) in varags.into_iter().enumerate() { + if i != 0 { + print!(" "); } + print!("{value}"); } Ok(Value::Nil) } -#[native_func(1, true)] -fn println(_vm: &mut Vm, args: Vec<Value>) -> Result<Value> { - let [values] = args.try_into().unwrap(); - if let Value::List(list) = values { - for (i, value) in list.iter().enumerate() { - print!("{}", value.boring_print()); - if i != 0 { - print!(" "); - } +#[native_func(0..)] +fn println(_: VmArgs, args: Vec<Value>) -> Result<Value> { + let ([], varags) = unpack_varargs!(args); + for (i, value) in varags.into_iter().enumerate() { + if i != 0 { + print!(" "); } + print!("{value}"); } print!("\n"); Ok(Value::Nil) } +#[native_func(0)] +fn readln(_: VmArgs, _: Vec<Value>) -> Result<Value> { + let mut input = String::new(); + match io::stdin().read_line(&mut input) { + Ok(_) => { + match input.pop() { + Some(c) if c == '\n' => {}, + Some(c) => input.push(c), + None => {} + }; + Ok(Value::String(input.into())) + }, + Err(err) => error!("cant read from stdin: {err}") + } +} + +#[native_func(1)] +fn input(_: VmArgs, args: Vec<Value>) -> Result<Value> { + let [prompt] = unpack_args!(args); + let mut input = String::new(); + print!("{prompt}"); + let _ = io::stdout().flush(); + match io::stdin().read_line(&mut input) { + Ok(_) => { + match input.pop() { + Some(c) if c == '\n' => {}, + Some(c) => input.push(c), + None => {} + }; + Ok(Value::String(input.into())) + }, + Err(err) => error!("cant read from stdin: {err}") + } +} + +#[native_func(0)] +fn readlines(_: VmArgs, _: Vec<Value>) -> Result<Value> { + let lines = RefCell::new(io::stdin().lines()); + Ok(iter!(move |_,_| { + match lines.borrow_mut().next() { + Some(Ok(line)) => Ok(Value::String(line.into())), + _ => Ok(Value::Nil) + } + })) +} + +#[native_func(2)] +fn file_open(_: VmArgs, args: Vec<Value>) -> Result<Value> { + let [path, mode] = unpack_args!(args); + let Value::String(mode) = mode else { + return error!("open mode must be a string") + }; + let Value::String(path) = path else { + return error!("open path must be a string") + }; + let file = match mode.as_ref() { + "r" => OpenOptions::new().read(true).open(path.as_ref()), + "w" => OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()), + "a" => OpenOptions::new().write(true).create(true).append(true).open(path.as_ref()), + "r+" => OpenOptions::new().read(true).write(true).open(path.as_ref()), + "w+" => OpenOptions::new().read(true).write(true).create(true).truncate(true).open(path.as_ref()), + "a+" => OpenOptions::new().read(true).write(true).create(true).append(true).open(path.as_ref()), + _ => return error!("invalid open mode: {mode}") + }; + + match file { + Ok(file) => Ok(Value::File(Rc::new(RefCell::new(file)))), + Err(err) => return error!("cannot open '{path}': {err}") + } +} + +#[native_func(1)] +fn file_read(_: VmArgs, args: Vec<Value>) -> Result<Value> { + let [file] = unpack_args!(args); + let Value::File(file) = file else { + return error!("file read requires a file") + }; + let mut contents = String::new(); + if let Err(err) = file.try_borrow_mut().unwrap().read_to_string(&mut contents) { + return error!("cannot read file: '{err}'") + }; + Ok(Value::String(contents.into())) +} + +#[native_func(1)] +fn file_lines(_: VmArgs, args: Vec<Value>) -> Result<Value> { + let [file] = unpack_args!(args); + let Value::File(file) = file else { + return error!("file read requires a file") + }; + let mut contents = String::new(); + if let Err(err) = file.try_borrow_mut().unwrap().read_to_string(&mut contents) { + return error!("cannot read file: '{err}'") + }; + let lines: Vec<Rc<str>> = contents.split_inclusive("\n").map(|s| Rc::from(s)).collect(); + let lines = RefCell::new(lines.into_iter()); + Ok(iter!(move |_,_| { + match lines.borrow_mut().next() { + Some(line) => Ok(Value::String(line)), + None => Ok(Value::Nil) + } + })) +} + +#[native_func(2)] +fn file_write(_: VmArgs, args: Vec<Value>) -> Result<Value> { + let [file, content] = unpack_args!(args); + let Value::File(file) = file else { + return error!("file write requires a file") + }; + let content = format!("{content}"); + if let Err(err) = file.try_borrow_mut().unwrap().write_all(content.as_bytes()) { + return error!("cannot write file: '{err}'") + }; + Ok(Value::Nil) +} + +#[native_func(0..)] +fn throw(_: VmArgs, args: Vec<Value>) -> Result<Value> { + let ([], varargs) = unpack_varargs!(args); + + let mut str = String::new(); + for (i, v) in varargs.into_iter().enumerate() { + if i != 0 { + str.push_str(" "); + } + str.push_str(&format!("{v}")); + } + + error!("{str}") +} + pub fn load(vm: &mut Vm) { - vm.load_native_fn(print()); - vm.load_native_fn(println()); + vm.load_global_fn(print(), "print"); + vm.load_global_fn(println(), "println"); + vm.load_global_fn(readln(), "readln"); + vm.load_global_fn(input(), "input"); + vm.load_global_fn(readlines(), "readlines"); + vm.load_global_fn(file_open(), "file_open"); + vm.load_global_fn(file_read(), "file_read"); + vm.load_global_fn(file_lines(), "file_lines"); + vm.load_global_fn(file_write(), "file_write"); + vm.load_global_fn(throw(), "throw"); } |