Removed foreign macros

Converted the function integration to use template
metaprogramming instead of macros.
This commit is contained in:
2023-09-22 23:17:54 +01:00
parent 7396078304
commit ba0b155ebd
45 changed files with 854 additions and 1126 deletions

View File

@@ -1,39 +1,63 @@
use std::ffi::OsString;
use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;
use std::path::{Path, PathBuf};
use hashbrown::HashMap;
use itertools::Itertools;
use super::osstring::os_string_lib;
use crate::ddispatch::Responder;
use crate::facade::{IntoSystem, System};
use crate::foreign::cps_box::{init_cps, CPSBox};
use crate::foreign::{Atomic, InertAtomic};
use crate::foreign::{
xfn_1ary, xfn_2ary, Atomic, AtomicReturn, InertAtomic, XfnResult,
};
use crate::interpreted::{Clause, ExprInst};
use crate::interpreter::HandlerTable;
use crate::systems::codegen::{call, list, orchid_opt, tuple};
use crate::systems::io::wrap_io_error;
use crate::systems::codegen::{call, list, opt, tuple};
use crate::systems::io::{wrap_io_error, Source};
use crate::systems::scheduler::{SeqScheduler, SharedHandle};
use crate::systems::stl::Boolean;
use crate::systems::RuntimeError;
use crate::utils::unwrap_or;
use crate::{define_fn, ConstTree, OrcString};
use crate::ConstTree;
#[derive(Debug, Clone)]
pub struct ReadFileCmd(OrcString);
pub struct CurrentDir;
impl Responder for CurrentDir {}
impl Atomic for CurrentDir {
fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> { self }
fn as_any_ref(&self) -> &dyn std::any::Any { self }
fn run(
self: Box<Self>,
ctx: crate::interpreter::Context,
) -> crate::foreign::AtomicResult {
let cwd = std::env::current_dir()
.map_err(|e| RuntimeError::ext(e.to_string(), "reading CWD"))?;
Ok(AtomicReturn {
clause: cwd.into_os_string().atom_cls(),
gas: ctx.gas.map(|g| g - 1),
inert: false,
})
}
}
#[derive(Debug, Clone)]
pub struct ReadFileCmd(OsString);
impl InertAtomic for ReadFileCmd {
fn type_str() -> &'static str { "readfile command" }
}
#[derive(Debug, Clone)]
pub struct ReadDirCmd(OrcString);
pub struct ReadDirCmd(OsString);
impl InertAtomic for ReadDirCmd {
fn type_str() -> &'static str { "readdir command" }
}
#[derive(Debug, Clone)]
pub struct WriteFile {
name: OrcString,
name: OsString,
append: bool,
}
impl InertAtomic for WriteFile {
@@ -43,15 +67,14 @@ impl InertAtomic for WriteFile {
#[must_use]
fn read_file(sched: &SeqScheduler, cmd: CPSBox<ReadFileCmd>) -> ExprInst {
let (ReadFileCmd(name), succ, fail, cont) = cmd.unpack3();
let name = name.get_string();
let cancel = sched.run_orphan(
move |_| File::open(name),
|file, _| match file {
Err(e) => vec![call(fail, [wrap_io_error(e)]).wrap()],
Ok(f) => {
let source =
SharedHandle::wrap(BufReader::new(Box::new(f) as Box<dyn Read>));
vec![call(succ, [source.atom_exi()]).wrap()]
let source: Source =
BufReader::new(Box::new(f) as Box<dyn Read + Send>);
vec![call(succ, [SharedHandle::wrap(source).atom_exi()]).wrap()]
},
},
);
@@ -61,7 +84,6 @@ fn read_file(sched: &SeqScheduler, cmd: CPSBox<ReadFileCmd>) -> ExprInst {
#[must_use]
fn read_dir(sched: &SeqScheduler, cmd: CPSBox<ReadDirCmd>) -> ExprInst {
let (ReadDirCmd(name), succ, fail, cont) = cmd.unpack3();
let name = name.get_string();
let cancel = sched.run_orphan(
move |_| {
Path::new(&name)
@@ -73,9 +95,7 @@ fn read_dir(sched: &SeqScheduler, cmd: CPSBox<ReadDirCmd>) -> ExprInst {
Err(e) => vec![call(fail, [wrap_io_error(e)]).wrap()],
Ok(os_namev) => {
let converted = (os_namev.into_iter())
.map(|(n, d)| {
Ok(tuple([os_str_cls(n)?.wrap(), Boolean(d).atom_exi()]).wrap())
})
.map(|(n, d)| Ok(tuple([n.atom_exi(), Boolean(d).atom_exi()]).wrap()))
.collect::<Result<Vec<_>, Clause>>();
match converted {
Err(e) => vec![call(fail, [e.wrap()]).wrap()],
@@ -90,7 +110,6 @@ fn read_dir(sched: &SeqScheduler, cmd: CPSBox<ReadDirCmd>) -> ExprInst {
#[must_use]
pub fn write_file(sched: &SeqScheduler, cmd: CPSBox<WriteFile>) -> ExprInst {
let (WriteFile { name, append }, succ, fail, cont) = cmd.unpack3();
let name = name.get_string();
let cancel = sched.run_orphan(
move |_| File::options().write(true).append(append).open(name),
|file, _| match file {
@@ -104,61 +123,38 @@ pub fn write_file(sched: &SeqScheduler, cmd: CPSBox<WriteFile>) -> ExprInst {
call(cont, [init_cps(1, cancel).wrap()]).wrap()
}
#[derive(Debug, Clone)]
pub struct InvalidString(OsString);
impl InertAtomic for InvalidString {
fn type_str() -> &'static str { "invalidstring error" }
pub fn open_file_read_cmd(name: OsString) -> XfnResult<Clause> {
Ok(init_cps(3, ReadFileCmd(name)))
}
fn os_str_cls(str: OsString) -> Result<Clause, Clause> {
(str.into_string())
.map_err(|e| InvalidString(e).atom_cls())
.map(|s| OrcString::from(s).cls())
pub fn read_dir_cmd(name: OsString) -> XfnResult<Clause> {
Ok(init_cps(3, ReadDirCmd(name)))
}
define_fn! {
pub IsInvalidString = |x| {
Ok(Boolean(x.downcast::<InvalidString>().is_ok()).atom_cls())
};
pub OpenFileRead = |x| Ok(init_cps(3, ReadFileCmd(x.downcast()?)));
pub ReadDir = |x| Ok(init_cps(3, ReadDirCmd(x.downcast()?)));
pub OpenFileWrite = |x| {
Ok(init_cps(3, WriteFile{ name: x.downcast()?, append: false }))
};
pub OpenFileAppend = |x| {
Ok(init_cps(3, WriteFile{ name: x.downcast()?, append: true }))
};
pub fn open_file_write_cmd(name: OsString) -> XfnResult<Clause> {
Ok(init_cps(3, WriteFile { name, append: false }))
}
pub JoinPaths { root: OrcString, sub: OrcString } => {
let res = Path::new(root.as_str())
.join(sub.as_str())
.into_os_string();
os_str_cls(res.clone()).map_err(|_| RuntimeError::ext(
format!("result {res:?} contains illegal characters"),
"joining paths"
))
};
pub PopPath = |x| {
eprintln!("argument is {x}");
let arg = x.downcast::<OrcString>()?;
let full_path = Path::new(arg.as_str());
let parent = unwrap_or! {full_path.parent(); {
return Ok(orchid_opt(None))
}};
let sub = unwrap_or! {full_path.file_name(); {
return Ok(orchid_opt(None))
}};
Ok(orchid_opt(Some(tuple(
[parent.as_os_str(), sub]
.into_iter()
.map(|s| os_str_cls(s.to_owned()).map_err(|_| RuntimeError::ext(
format!("Result {s:?} contains illegal characters"),
"splitting a path"
)))
.map_ok(Clause::wrap)
.collect::<Result<Vec<_>, _>>()?
).wrap())))
}
pub fn open_file_append_cmd(name: OsString) -> XfnResult<Clause> {
Ok(init_cps(3, WriteFile { name, append: true }))
}
pub fn join_paths(root: OsString, sub: OsString) -> XfnResult<OsString> {
let mut path = PathBuf::from(root);
path.push(sub);
Ok(path.into_os_string())
}
pub fn pop_path(path: OsString) -> XfnResult<Clause> {
let mut path = PathBuf::from(path);
let sub = unwrap_or! {path.file_name(); {
return Ok(opt(None))
}}
.to_owned();
debug_assert!(path.pop(), "file_name above returned Some");
Ok(opt(Some(
tuple([path.into_os_string().atom_exi(), sub.atom_exi()]).wrap(),
)))
}
/// A rudimentary system to read and write files.
@@ -187,14 +183,14 @@ impl IntoSystem<'static> for DirectFS {
constants: ConstTree::namespace(
[i.i("system"), i.i("directfs")],
ConstTree::tree([
(i.i("is_invalid_string"), ConstTree::xfn(IsInvalidString)),
(i.i("readfile"), ConstTree::xfn(OpenFileRead)),
(i.i("readdir"), ConstTree::xfn(ReadDir)),
(i.i("writefile"), ConstTree::xfn(OpenFileWrite)),
(i.i("appendfile"), ConstTree::xfn(OpenFileAppend)),
(i.i("join_paths"), ConstTree::xfn(JoinPaths)),
(i.i("pop_path"), ConstTree::xfn(PopPath)),
]),
(i.i("read_file"), ConstTree::xfn(xfn_1ary(open_file_read_cmd))),
(i.i("read_dir"), ConstTree::xfn(xfn_1ary(read_dir_cmd))),
(i.i("write_file"), ConstTree::xfn(xfn_1ary(open_file_write_cmd))),
(i.i("append_file"), ConstTree::xfn(xfn_1ary(open_file_append_cmd))),
(i.i("join_paths"), ConstTree::xfn(xfn_2ary(join_paths))),
(i.i("pop_path"), ConstTree::xfn(xfn_1ary(pop_path))),
(i.i("cwd"), ConstTree::atom(CurrentDir)),
]) + os_string_lib(i),
)
.unwrap_tree(),
handlers,