file manipulation basics

This commit is contained in:
Altareos
2022-06-03 11:40:06 +02:00
parent 004788bbfb
commit d8166a9ff6
4 changed files with 115 additions and 16 deletions

30
sample/cp.pl.xml Normal file
View File

@@ -0,0 +1,30 @@
<program name="files">
<main>
<assign variable="args">
<call function="get-args">
<arguments />
</call>
</assign>
<call function="write-file">
<arguments>
<call function="array-get">
<arguments>
<value variable="args" />
<integer value="2" />
</arguments>
</call>
<call function="read-file">
<arguments>
<call function="array-get">
<arguments>
<value variable="args" />
<integer value="1" />
</arguments>
</call>
</arguments>
</call>
<integer value="0" />
</arguments>
</call>
</main>
</program>

View File

@@ -24,11 +24,15 @@ impl fmt::Display for MissingAttribute {
impl Error for MissingAttribute {} impl Error for MissingAttribute {}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BadArgumentCount(pub &'static str, pub usize); pub struct BadArgumentCount(pub &'static str, pub usize, pub usize);
impl fmt::Display for BadArgumentCount { impl fmt::Display for BadArgumentCount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "bad argument count ({}) in call to '{}'", self.1, self.0) write!(
f,
"bad argument count ({}, expected {}) in call to '{}'",
self.1, self.2, self.0
)
} }
} }

View File

@@ -2,11 +2,13 @@ use super::error::{BadArgumentCount, InvalidArgument};
use super::{Context, Value}; use super::{Context, Value};
use std::cell::RefCell; use std::cell::RefCell;
use std::error::Error; use std::error::Error;
use std::io; use std::fs::{self, OpenOptions};
use std::io::{stdin, stdout, Write};
use std::rc::Rc; use std::rc::Rc;
pub fn inject_all(ctx: &mut Context) { pub fn inject_all(ctx: &mut Context) {
ctx.assign(String::from("print"), Value::StdFunction(print)); ctx.assign(String::from("print"), Value::StdFunction(print));
ctx.assign(String::from("print-line"), Value::StdFunction(print_line));
ctx.assign(String::from("input"), Value::StdFunction(input)); ctx.assign(String::from("input"), Value::StdFunction(input));
ctx.assign( ctx.assign(
String::from("string-split"), String::from("string-split"),
@@ -23,9 +25,26 @@ pub fn inject_all(ctx: &mut Context) {
ctx.assign(String::from("to-ascii"), Value::StdFunction(to_ascii)); ctx.assign(String::from("to-ascii"), Value::StdFunction(to_ascii));
ctx.assign(String::from("from-ascii"), Value::StdFunction(from_ascii)); ctx.assign(String::from("from-ascii"), Value::StdFunction(from_ascii));
ctx.assign(String::from("get-args"), Value::StdFunction(get_args)); ctx.assign(String::from("get-args"), Value::StdFunction(get_args));
ctx.assign(String::from("write-file"), Value::StdFunction(write_file));
ctx.assign(String::from("read-file"), Value::StdFunction(read_file));
} }
fn print(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> { fn print(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
if vals.len() == 1 {
match &vals[0] {
Value::Integer(i) => print!("{}", i),
Value::Float(f) => print!("{}", f),
Value::String(s) => print!("{}", s),
v => print!("{:?}", v), // _ => Err("unprintable value")?,
};
let _ = stdout().flush();
Ok(Some(vals[0].clone()))
} else {
Err(BadArgumentCount("print", vals.len(), 1).into())
}
}
fn print_line(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
if vals.len() == 1 { if vals.len() == 1 {
match &vals[0] { match &vals[0] {
Value::Integer(i) => println!("{}", i), Value::Integer(i) => println!("{}", i),
@@ -33,20 +52,21 @@ fn print(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Value::String(s) => println!("{}", s), Value::String(s) => println!("{}", s),
v => println!("{:?}", v), // _ => Err("unprintable value")?, v => println!("{:?}", v), // _ => Err("unprintable value")?,
}; };
let _ = stdout().flush();
Ok(Some(vals[0].clone())) Ok(Some(vals[0].clone()))
} else { } else {
Err(BadArgumentCount("print", vals.len()).into()) Err(BadArgumentCount("print-line", vals.len(), 1).into())
} }
} }
fn input(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> { fn input(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
if vals.len() == 0 { if vals.len() == 0 {
let mut line = String::new(); let mut line = String::new();
io::stdin().read_line(&mut line)?; stdin().read_line(&mut line)?;
line.pop(); line.pop();
Ok(Some(Value::String(line))) Ok(Some(Value::String(line)))
} else { } else {
Err(BadArgumentCount("input", vals.len()).into()) Err(BadArgumentCount("input", vals.len(), 0).into())
} }
} }
@@ -68,7 +88,7 @@ fn string_split(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Err(InvalidArgument("string-split", "target").into()) Err(InvalidArgument("string-split", "target").into())
} }
} else { } else {
Err(BadArgumentCount("string-split", vals.len()).into()) Err(BadArgumentCount("string-split", vals.len(), 2).into())
} }
} }
@@ -90,7 +110,7 @@ fn array_set(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Err(InvalidArgument("array-set", "array").into()) Err(InvalidArgument("array-set", "array").into())
} }
} else { } else {
Err(BadArgumentCount("array-set", vals.len()).into()) Err(BadArgumentCount("array-set", vals.len(), 3).into())
} }
} }
@@ -103,7 +123,7 @@ fn array_push(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Err(InvalidArgument("array-push", "array").into()) Err(InvalidArgument("array-push", "array").into())
} }
} else { } else {
Err(BadArgumentCount("array-push", vals.len()).into()) Err(BadArgumentCount("array-push", vals.len(), 2).into())
} }
} }
@@ -119,7 +139,7 @@ fn array_pop(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Err(InvalidArgument("array-pop", "array").into()) Err(InvalidArgument("array-pop", "array").into())
} }
} else { } else {
Err(BadArgumentCount("array-pop", vals.len()).into()) Err(BadArgumentCount("array-pop", vals.len(), 1).into())
} }
} }
@@ -140,7 +160,7 @@ fn array_get(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Err(InvalidArgument("array-set", "array").into()) Err(InvalidArgument("array-set", "array").into())
} }
} else { } else {
Err(BadArgumentCount("array-get", vals.len()).into()) Err(BadArgumentCount("array-get", vals.len(), 2).into())
} }
} }
@@ -152,7 +172,7 @@ fn array_length(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Err(InvalidArgument("array-length", "array").into()) Err(InvalidArgument("array-length", "array").into())
} }
} else { } else {
Err(BadArgumentCount("array-length", vals.len()).into()) Err(BadArgumentCount("array-length", vals.len(), 1).into())
} }
} }
@@ -168,7 +188,7 @@ fn to_ascii(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Err(InvalidArgument("to-ascii", "integer").into()) Err(InvalidArgument("to-ascii", "integer").into())
} }
} else { } else {
Err(BadArgumentCount("to-ascii", vals.len()).into()) Err(BadArgumentCount("to-ascii", vals.len(), 1).into())
} }
} }
@@ -184,7 +204,7 @@ fn from_ascii(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
Err(InvalidArgument("from-ascii", "string").into()) Err(InvalidArgument("from-ascii", "string").into())
} }
} else { } else {
Err(BadArgumentCount("from-ascii", vals.len()).into()) Err(BadArgumentCount("from-ascii", vals.len(), 1).into())
} }
} }
@@ -197,6 +217,51 @@ fn get_args(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
.collect(), .collect(),
))))) )))))
} else { } else {
Err(BadArgumentCount("get-args", vals.len()).into()) Err(BadArgumentCount("get-args", vals.len(), 0).into())
}
}
fn write_file(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
if vals.len() == 3 {
if let Value::String(path) = &vals[0] {
if let Value::String(contents) = &vals[1] {
if let Ok(mut file) = OpenOptions::new()
.write(true)
.create(true)
.append(Value::to_bool(&vals[2]))
.open(path)
{
if let Ok(_) = write!(file, "{}", contents) {
Ok(Some(Value::Integer(1)))
} else {
Ok(Some(Value::Integer(0)))
}
} else {
Ok(Some(Value::Integer(0)))
}
} else {
Err(InvalidArgument("write-file", "string").into())
}
} else {
Err(InvalidArgument("write-file", "string").into())
}
} else {
Err(BadArgumentCount("write-file", vals.len(), 3).into())
}
}
fn read_file(vals: Vec<Value>) -> Result<Option<Value>, Box<dyn Error>> {
if vals.len() == 1 {
if let Value::String(path) = &vals[0] {
if let Ok(contents) = fs::read_to_string(path) {
Ok(Some(Value::String(contents)))
} else {
Ok(None)
}
} else {
Err(InvalidArgument("read-file", "string").into())
}
} else {
Err(BadArgumentCount("read-file", vals.len(), 1).into())
} }
} }

View File

@@ -19,7 +19,7 @@ impl Function {
globals: &Context, globals: &Context,
) -> Result<Option<Value>, Box<dyn Error>> { ) -> Result<Option<Value>, Box<dyn Error>> {
if args.len() != self.args.len() { if args.len() != self.args.len() {
Err(BadArgumentCount("function", args.len()))? Err(BadArgumentCount("function", args.len(), self.args.len()))?
} }
self.args self.args
.iter() .iter()