Add assert and assert_equal tools

This commit is contained in:
Jeff 2023-10-11 12:07:30 -04:00
parent 96c6193799
commit fc92513246
5 changed files with 81 additions and 55 deletions

View File

@ -4,4 +4,4 @@ x = numbers.0
y = numbers.1 y = numbers.1
z = numbers.2 z = numbers.2
assert_equal <x + y, z> (assert_equal x + y, z)

View File

@ -30,6 +30,8 @@ impl AbstractTree for FunctionCall {
"tool" => { "tool" => {
let tool_node = name_node.child(0).unwrap(); let tool_node = name_node.child(0).unwrap();
let tool = match tool_node.kind() { let tool = match tool_node.kind() {
"assert" => Tool::Assert,
"assert_equal" => Tool::AssertEqual,
"output" => Tool::Output, "output" => Tool::Output,
"read" => Tool::Read, "read" => Tool::Read,
_ => panic!(""), _ => panic!(""),
@ -42,14 +44,14 @@ impl AbstractTree for FunctionCall {
let mut arguments = Vec::new(); let mut arguments = Vec::new();
let mut current_index = 2; for index in 2..node.child_count() - 1 {
while current_index < node.child_count() - 1 { let child = node.child(index).unwrap();
let expression_node = node.child(current_index).unwrap();
let expression = Expression::from_syntax_node(source, expression_node)?;
arguments.push(expression); if child.is_named() {
let expression = Expression::from_syntax_node(source, child)?;
current_index += 1; arguments.push(expression);
}
} }
Ok(FunctionCall { name, arguments }) Ok(FunctionCall { name, arguments })
@ -59,13 +61,15 @@ impl AbstractTree for FunctionCall {
let identifier = match &self.name { let identifier = match &self.name {
FunctionName::Identifier(identifier) => identifier, FunctionName::Identifier(identifier) => identifier,
FunctionName::Tool(tool) => { FunctionName::Tool(tool) => {
let value = self let mut values = Vec::with_capacity(self.arguments.len());
.arguments
.first()
.map(|expression| expression.run(source, context))
.unwrap_or(Ok(Value::Empty))?;
return tool.run(&value); for expression in &self.arguments {
let value = expression.run(source, context)?;
values.push(value);
}
return tool.run(&values);
} }
}; };
let key = identifier.inner(); let key = identifier.inner();

View File

@ -2,24 +2,78 @@ use std::fs::read_to_string;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Result, Value}; use crate::{Error, Result, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Tool { pub enum Tool {
Assert,
AssertEqual,
Output, Output,
Read, Read,
} }
impl Tool { impl Tool {
pub fn run(&self, value: &Value) -> Result<Value> { pub fn run(&self, values: &[Value]) -> Result<Value> {
let value = match self { let value = match self {
Tool::Assert => {
if values.len() != 1 {
return Err(Error::ExpectedToolArgumentAmount {
tool_name: "assert",
expected: 1,
actual: values.len(),
});
}
if values[0].as_boolean()? {
Value::Empty
} else {
return Err(Error::AssertEqualFailed {
expected: Value::Boolean(true),
actual: values[0].clone(),
});
}
}
Tool::AssertEqual => {
if values.len() != 2 {
return Err(Error::ExpectedToolArgumentAmount {
tool_name: "assert_equal",
expected: 2,
actual: values.len(),
});
}
if values[0] == values[1] {
Value::Empty
} else {
return Err(Error::AssertEqualFailed {
expected: values[0].clone(),
actual: values[1].clone(),
});
}
}
Tool::Output => { Tool::Output => {
println!("{value}"); if values.len() != 1 {
return Err(Error::ExpectedToolArgumentAmount {
tool_name: "output",
expected: 1,
actual: values.len(),
});
}
println!("{}", values[0]);
Value::Empty Value::Empty
} }
Tool::Read => { Tool::Read => {
let file_contents = read_to_string(value.as_string()?)?; if values.len() != 1 {
return Err(Error::ExpectedToolArgumentAmount {
tool_name: "read",
expected: 1,
actual: values.len(),
});
}
let file_contents = read_to_string(values[0].as_string()?)?;
Value::String(file_contents) Value::String(file_contents)
} }

View File

@ -47,8 +47,8 @@ pub enum Error {
}, },
/// A function was called with the wrong amount of arguments. /// A function was called with the wrong amount of arguments.
ExpectedFunctionArgumentAmount { ExpectedToolArgumentAmount {
identifier: String, tool_name: &'static str,
expected: usize, expected: usize,
actual: usize, actual: usize,
}, },
@ -283,38 +283,6 @@ impl From<toml::de::Error> for Error {
} }
impl Error { impl Error {
pub(crate) fn _expect_function_argument_amount(
identifier: &str,
actual: usize,
expected: usize,
) -> Result<()> {
if actual == expected {
Ok(())
} else {
Err(Error::ExpectedFunctionArgumentAmount {
identifier: identifier.to_string(),
expected,
actual,
})
}
}
pub(crate) fn _expected_minimum_function_argument_amount(
identifier: &str,
actual: usize,
minimum: usize,
) -> Result<()> {
if actual >= minimum {
Ok(())
} else {
Err(Error::ExpectedAtLeastFunctionArgumentAmount {
identifier: identifier.to_string(),
minimum,
actual,
})
}
}
pub fn type_error(actual: Value, expected: &'static [ValueType]) -> Self { pub fn type_error(actual: Value, expected: &'static [ValueType]) -> Self {
Error::TypeError { actual, expected } Error::TypeError { actual, expected }
} }
@ -414,13 +382,13 @@ impl fmt::Display for Error {
"An operator expected {} arguments, but got {}.", "An operator expected {} arguments, but got {}.",
expected, actual expected, actual
), ),
ExpectedFunctionArgumentAmount { ExpectedToolArgumentAmount {
tool_name,
expected, expected,
actual, actual,
identifier,
} => write!( } => write!(
f, f,
"{identifier} expected {expected} arguments, but got {actual}.", "{tool_name} expected {expected} arguments, but got {actual}.",
), ),
ExpectedAtLeastFunctionArgumentAmount { ExpectedAtLeastFunctionArgumentAmount {
minimum, minimum,

@ -1 +1 @@
Subproject commit a207087ccafb71764b007db88580b35d5e37dae3 Subproject commit c6ec1ff6ea51ce28ee465f9c230e2580fab4c437