Move File module and tests to the shell project
Signed-off-by: Ava Affine <ava@sunnypup.io>
This commit is contained in:
parent
6d2925984f
commit
74f73fb493
4 changed files with 87 additions and 82 deletions
252
shell/src/file.rs
Normal file
252
shell/src/file.rs
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/* Flesh: Flexible Shell
|
||||
* Copyright (C) 2021 Ava Hahn
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use flesh::ast::{
|
||||
start_trace, Ctr, Seg, Type, SymTable,
|
||||
Symbol, ValueType, Args, Traceback,
|
||||
};
|
||||
|
||||
use std::io::Write;
|
||||
use std::fs::{File, read_to_string, OpenOptions};
|
||||
use std::rc::Rc;
|
||||
use std::path::Path;
|
||||
|
||||
|
||||
const READ_TO_STRING_DOCSTRING: &str = "Takes one input (filename).
|
||||
If file exists, returns a string containing file contents.
|
||||
If the file does not exist returns error.";
|
||||
fn read_to_string_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::String(ref filename) = *ast.car {
|
||||
let res = read_to_string(filename);
|
||||
if let Ok(s) = res {
|
||||
Ok(Ctr::String(s))
|
||||
} else {
|
||||
Err(start_trace(
|
||||
("read-file", res.err().unwrap().to_string())
|
||||
.into()))
|
||||
}
|
||||
} else {
|
||||
Err(start_trace(("read-file", "impossible arg").into()))
|
||||
}
|
||||
}
|
||||
|
||||
const WRITE_TO_FILE_DOCSTRING: &str = "Takes two inputs: a filename and a string of content.
|
||||
Writes contents to the file and returns None.";
|
||||
fn write_to_file_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::String(ref filename) = *ast.car {
|
||||
if let Ctr::Seg(ref next) = *ast.cdr {
|
||||
if let Ctr::String(ref body) = *next.car {
|
||||
let fres = OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.write(true)
|
||||
.open(filename);
|
||||
if fres.is_err() {
|
||||
Err(start_trace(
|
||||
("write-file",
|
||||
format!("couldn't open file: {}", fres.err().unwrap().to_string()))
|
||||
.into()))
|
||||
} else {
|
||||
if let Err(e) = write!(&mut fres.unwrap(), "{}", body) {
|
||||
Err(start_trace(
|
||||
("write-file", format!("failed to write to file: {}", e))
|
||||
.into()))
|
||||
} else {
|
||||
Ok(Ctr::None)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(start_trace(("write-file", "impossible arg").into()))
|
||||
}
|
||||
} else {
|
||||
Err(start_trace(("write-file", "not enough args").into()))
|
||||
}
|
||||
} else {
|
||||
Err(start_trace(("write-file", "impossible arg").into()))
|
||||
}
|
||||
}
|
||||
|
||||
const APPEND_TO_FILE_DOCSTRING: &str = "Takes two inputs: a filename and a string of content.
|
||||
Appends content to the end of the file and returns None";
|
||||
fn append_to_file_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::String(ref filename) = *ast.car {
|
||||
if let Ctr::Seg(ref next) = *ast.cdr {
|
||||
if let Ctr::String(ref body) = *next.car {
|
||||
let fres = File::options().append(true).open(filename);
|
||||
if fres.is_err() {
|
||||
Err(start_trace(
|
||||
("append-file",
|
||||
format!("couldn't open file: {}", fres.err().unwrap().to_string()))
|
||||
.into()))
|
||||
} else {
|
||||
if let Err(e) = write!(&mut fres.unwrap(), "{}", body) {
|
||||
Err(start_trace(
|
||||
("append-file", format!("failed to write to file: {}", e))
|
||||
.into()))
|
||||
} else {
|
||||
Ok(Ctr::None)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(start_trace(("append-file", "impossible arg").into()))
|
||||
}
|
||||
} else {
|
||||
Err(start_trace(("append-file", "not enough args").into()))
|
||||
}
|
||||
} else {
|
||||
Err(start_trace(("append-file", "impossible arg").into()))
|
||||
}
|
||||
}
|
||||
|
||||
const IS_FILE_EXISTS_DOCSTRING: &str = "Takes one input: a filename.
|
||||
Returns true or false depending on if the file exists.";
|
||||
fn is_file_exists_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||
if let Ctr::String(ref filename) = *ast.car {
|
||||
Ok(Ctr::Bool(Path::new(&filename).exists()))
|
||||
} else {
|
||||
Err(Traceback::new().with_trace(("exists?", "impossible arg").into()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_file_lib(syms: &mut SymTable) {
|
||||
syms.insert(
|
||||
"read-file".to_string(),
|
||||
Symbol {
|
||||
name: String::from("read-file"),
|
||||
args: Args::Strict(vec![Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: READ_TO_STRING_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(read_to_string_callback)),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"write-file".to_string(),
|
||||
Symbol {
|
||||
name: String::from("write-file"),
|
||||
args: Args::Strict(vec![Type::String, Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: WRITE_TO_FILE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(write_to_file_callback)),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"append-file".to_string(),
|
||||
Symbol {
|
||||
name: String::from("append-file"),
|
||||
args: Args::Strict(vec![Type::String, Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: APPEND_TO_FILE_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(append_to_file_callback)),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"exists?".to_string(),
|
||||
Symbol {
|
||||
name: String::from("exists?"),
|
||||
args: Args::Strict(vec![Type::String]),
|
||||
conditional_branches: false,
|
||||
docs: IS_FILE_EXISTS_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(is_file_exists_callback)),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use flesh::ast::{eval, lex, SymTable};
|
||||
use flesh::stdlib::static_stdlib;
|
||||
use crate::stl::static_stdlib_overwrites;
|
||||
|
||||
#[test]
|
||||
fn test_fexists() {
|
||||
let document = "(exists? \"/tmp\")";
|
||||
let result = "true";
|
||||
let mut syms = SymTable::new();
|
||||
static_stdlib(&mut syms);
|
||||
static_stdlib_overwrites(&mut syms);
|
||||
assert_eq!(
|
||||
*eval(&lex(&document.to_string()).unwrap(), &mut syms)
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
result.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fexists_doesnt() {
|
||||
let document = "(exists? \"cargo.timtam\")";
|
||||
let result = "false";
|
||||
let mut syms = SymTable::new();
|
||||
static_stdlib(&mut syms);
|
||||
static_stdlib_overwrites(&mut syms);
|
||||
assert_eq!(
|
||||
*eval(&lex(&document.to_string()).unwrap(), &mut syms)
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
result.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_file() {
|
||||
let document = "
|
||||
(let ((s \"test\")
|
||||
(t \"/tmp/flesh-lib-test-file-1\"))
|
||||
(write-file t s)
|
||||
(echo (read-file t))
|
||||
(eq? (read-file t) s))";
|
||||
let result = "true";
|
||||
let mut syms = SymTable::new();
|
||||
static_stdlib(&mut syms);
|
||||
static_stdlib_overwrites(&mut syms);
|
||||
assert_eq!(
|
||||
*eval(&lex(&document.to_string()).unwrap(), &mut syms)
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
result.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_append_file() {
|
||||
let document = "
|
||||
(let ((s \"test\")
|
||||
(t \"/tmp/flesh-lib-test-file-2\"))
|
||||
(write-file t s)
|
||||
(append-file t s)
|
||||
(eq? (read-file t)
|
||||
(concat s s)))";
|
||||
let result = "true";
|
||||
let mut syms = SymTable::new();
|
||||
static_stdlib(&mut syms);
|
||||
static_stdlib_overwrites(&mut syms);
|
||||
assert_eq!(
|
||||
*eval(&lex(&document.to_string()).unwrap(), &mut syms)
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
result.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -31,8 +31,10 @@ use crate::posix;
|
|||
|
||||
#[path = "window.rs"]
|
||||
mod window;
|
||||
#[path = "store.rs"]
|
||||
#[path = "store.rs"]
|
||||
mod store;
|
||||
#[path = "file.rs"]
|
||||
mod file;
|
||||
|
||||
pub const CONSOLE_XDIM_VNAME: &str = "_FLESH_WIDTH";
|
||||
pub const CONSOLE_YDIM_VNAME: &str = "_FLESH_HEIGHT";
|
||||
|
|
@ -63,6 +65,7 @@ fn prompt_delimiter_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, T
|
|||
pub fn static_stdlib_overwrites(syms: &mut SymTable) {
|
||||
static_stdlib(syms);
|
||||
window::add_window_lib_funcs(syms);
|
||||
file::add_file_lib(syms);
|
||||
|
||||
syms.insert(
|
||||
"call".to_string(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue