Add type checks

This commit is contained in:
Jeff 2023-08-24 06:16:28 -04:00
parent 7c6a4e5ece
commit fabcbdd216
2 changed files with 70 additions and 139 deletions

View File

@ -8,7 +8,7 @@ impl Tool for Transform {
fn info(&self) -> ToolInfo<'static> { fn info(&self) -> ToolInfo<'static> {
ToolInfo { ToolInfo {
identifier: "transform", identifier: "transform",
description: "Alter a collection by calling a function on each value.", description: "Alter a list by calling a function on each value.",
group: "collections", group: "collections",
inputs: vec![ValueType::ListExact(vec![ inputs: vec![ValueType::ListExact(vec![
ValueType::List, ValueType::List,
@ -18,36 +18,27 @@ impl Tool for Transform {
} }
fn run(&self, argument: &Value) -> Result<Value> { fn run(&self, argument: &Value) -> Result<Value> {
let argument = argument.as_list()?; let argument = self.check_type(argument)?;
let value = &argument[0];
let function = argument[1].as_function()?;
match value { if let Value::List(list) = argument {
Value::String(_string) => todo!(), let list = list[0].as_list()?;
Value::Float(_) => todo!(), let function = list[1].as_function()?;
Value::Integer(_) => todo!(), let mut mapped_list = Vec::with_capacity(list.len());
Value::Boolean(_) => todo!(),
Value::List(list) => {
let mut mapped_list = Vec::with_capacity(list.len());
for value in list { for value in list {
let mut context = VariableMap::new(); let mut context = VariableMap::new();
context.set_value("input", value.clone())?; context.set_value("input", value.clone())?;
let mapped_value = function.run_with_context(&mut context)?; let mapped_value = function.run_with_context(&mut context)?;
mapped_list.push(mapped_value); mapped_list.push(mapped_value);
}
Ok(Value::List(mapped_list))
} }
Value::Empty => todo!(),
Value::Map(_map) => todo!(), return Ok(Value::List(mapped_list));
Value::Table(_) => todo!(),
Value::Function(_) => todo!(),
Value::Time(_) => todo!(),
} }
self.fail(argument)
} }
} }
@ -59,22 +50,26 @@ impl Tool for String {
identifier: "string", identifier: "string",
description: "Stringify a value.", description: "Stringify a value.",
group: "collections", group: "collections",
inputs: vec![ValueType::Any], inputs: vec![
ValueType::String,
ValueType::Function,
ValueType::Float,
ValueType::Integer,
ValueType::Boolean,
],
} }
} }
fn run(&self, argument: &Value) -> Result<Value> { fn run(&self, argument: &Value) -> Result<Value> {
let string = match argument.clone() { let argument = self.check_type(argument)?;
Value::String(string) => string,
Value::List(_list) => todo!(), let string = match argument {
Value::Map(_map) => todo!(), Value::String(string) => string.clone(),
Value::Table(_table) => todo!(),
Value::Function(function) => function.to_string(), Value::Function(function) => function.to_string(),
Value::Float(float) => float.to_string(), Value::Float(float) => float.to_string(),
Value::Integer(integer) => integer.to_string(), Value::Integer(integer) => integer.to_string(),
Value::Boolean(boolean) => boolean.to_string(), Value::Boolean(boolean) => boolean.to_string(),
Value::Time(_) => todo!(), _ => return self.fail(argument),
Value::Empty => todo!(),
}; };
Ok(Value::String(string)) Ok(Value::String(string))
@ -87,13 +82,15 @@ impl Tool for Count {
fn info(&self) -> ToolInfo<'static> { fn info(&self) -> ToolInfo<'static> {
ToolInfo { ToolInfo {
identifier: "count", identifier: "count",
description: "Return the number of items in a value.", description: "Return the number of items in a collection.",
group: "collections", group: "collections",
inputs: vec![ValueType::Any], inputs: vec![ValueType::Any],
} }
} }
fn run(&self, argument: &Value) -> Result<Value> { fn run(&self, argument: &Value) -> Result<Value> {
let argument = self.check_type(argument)?;
let len = match argument { let len = match argument {
Value::String(string) => string.chars().count(), Value::String(string) => string.chars().count(),
Value::List(list) => list.len(), Value::List(list) => list.len(),
@ -103,8 +100,8 @@ impl Tool for Count {
| Value::Float(_) | Value::Float(_)
| Value::Integer(_) | Value::Integer(_)
| Value::Boolean(_) | Value::Boolean(_)
| Value::Time(_) => 1, | Value::Time(_)
Value::Empty => 0, | Value::Empty => return self.fail(argument),
}; };
Ok(Value::Integer(len as i64)) Ok(Value::Integer(len as i64))
@ -119,12 +116,15 @@ impl Tool for CreateTable {
identifier: "create_table", identifier: "create_table",
description: "Define a new table with a list of column names and list of rows.", description: "Define a new table with a list of column names and list of rows.",
group: "collections", group: "collections",
inputs: vec![ValueType::ListExact(vec![ValueType::List, ValueType::List])], inputs: vec![ValueType::ListExact(vec![
ValueType::ListOf(Box::new(ValueType::String)),
ValueType::ListOf(Box::new(ValueType::List)),
])],
} }
} }
fn run(&self, argument: &Value) -> Result<Value> { fn run(&self, argument: &Value) -> Result<Value> {
let argument = argument.as_list()?; let argument = self.check_type(argument)?.as_list()?;
let column_name_inputs = argument[0].as_list()?; let column_name_inputs = argument[0].as_list()?;
let mut column_names = Vec::with_capacity(column_name_inputs.len()); let mut column_names = Vec::with_capacity(column_name_inputs.len());
@ -160,49 +160,20 @@ impl Tool for Rows {
} }
fn run(&self, argument: &Value) -> Result<Value> { fn run(&self, argument: &Value) -> Result<Value> {
let table = argument.as_table()?; let argument = self.check_type(argument)?;
let rows = table if let Value::Table(table) = argument {
.rows() let rows = table
.iter() .rows()
.map(|row| Value::List(row.clone())) .iter()
.collect(); .map(|row| Value::List(row.clone()))
.collect();
Ok(Value::List(rows)) Ok(Value::List(rows))
} } else {
} self.fail(argument)
pub struct Get;
impl Tool for Get {
fn info(&self) -> ToolInfo<'static> {
ToolInfo {
identifier: "get",
description: "Retrieve a value from a collection.",
group: "collections",
inputs: vec![
ValueType::ListExact(vec![ValueType::List, ValueType::Integer]),
ValueType::ListExact(vec![ValueType::Map, ValueType::String]),
],
} }
} }
fn run(&self, argument: &Value) -> Result<Value> {
let argument = argument.as_list()?;
let collection = &argument[0];
let index = argument[1].as_int()?;
if let Ok(list) = collection.as_list() {
if let Some(value) = list.get(index as usize) {
return Ok(value.clone());
} else {
return Ok(Value::Empty);
}
}
todo!()
}
} }
pub struct Insert; pub struct Insert;
@ -213,7 +184,10 @@ impl Tool for Insert {
identifier: "insert", identifier: "insert",
description: "Add new rows to a table.", description: "Add new rows to a table.",
group: "collections", group: "collections",
inputs: vec![ValueType::Table, ValueType::List], inputs: vec![ValueType::ListExact(vec![
ValueType::Table,
ValueType::ListOf(Box::new(ValueType::List)),
])],
} }
} }
@ -351,76 +325,34 @@ impl Tool for Where {
identifier: "where", identifier: "where",
description: "Keep rows matching a predicate.", description: "Keep rows matching a predicate.",
group: "collections", group: "collections",
inputs: vec![], inputs: vec![ValueType::ListExact(vec![
ValueType::Table,
ValueType::Function,
])],
} }
} }
fn run(&self, argument: &Value) -> Result<Value> { fn run(&self, argument: &Value) -> Result<Value> {
let argument_list = argument.as_list()?; let argument = self.check_type(argument)?.as_list()?;
Error::expect_function_argument_amount(self.info().identifier, argument_list.len(), 2)?; let table = &argument[0].as_table()?;
let function = argument[1].as_function()?;
let collection = &argument_list[0]; let mut context = VariableMap::new();
let function = argument_list[1].as_function()?; let mut new_table = Table::new(table.column_names().clone());
if let Ok(list) = collection.as_list() { for row in table.rows() {
let mut context = VariableMap::new(); for (column_index, cell) in row.iter().enumerate() {
let mut new_list = Vec::new(); let column_name = table.column_names().get(column_index).unwrap();
for value in list { context.set_value(column_name, cell.clone())?;
context.set_value("input", value.clone())?;
let keep_row = function.run_with_context(&mut context)?.as_boolean()?;
if keep_row {
new_list.push(value.clone());
}
} }
let keep_row = function.run_with_context(&mut context)?.as_boolean()?;
return Ok(Value::List(new_list)); if keep_row {
new_table.insert(row.clone())?;
}
} }
if let Ok(map) = collection.as_map() { Ok(Value::Table(new_table))
let mut context = VariableMap::new();
let mut new_map = VariableMap::new();
for (key, value) in map.inner() {
if let Ok(map) = value.as_map() {
for (key, value) in map.inner() {
context.set_value(key, value.clone())?;
}
} else {
context.set_value("input", value.clone())?;
}
let keep_row = function.run_with_context(&mut context)?.as_boolean()?;
if keep_row {
new_map.set_value(key, value.clone())?;
}
}
return Ok(Value::Map(new_map));
}
if let Ok(table) = collection.as_table() {
let mut context = VariableMap::new();
let mut new_table = Table::new(table.column_names().clone());
for row in table.rows() {
for (column_index, cell) in row.iter().enumerate() {
let column_name = table.column_names().get(column_index).unwrap();
context.set_value(column_name, cell.clone())?;
}
let keep_row = function.run_with_context(&mut context)?.as_boolean()?;
if keep_row {
new_table.insert(row.clone())?;
}
}
return Ok(Value::Table(new_table));
}
todo!()
} }
} }

View File

@ -51,10 +51,9 @@ pub mod time;
/// Master list of all tools. /// Master list of all tools.
/// ///
/// This list is used to match identifiers with tools and to provide info to the shell. /// This list is used to match identifiers with tools and to provide info to the shell.
pub const TOOL_LIST: [&'static dyn Tool; 57] = [ pub const TOOL_LIST: [&'static dyn Tool; 56] = [
&collections::Count, &collections::Count,
&collections::CreateTable, &collections::CreateTable,
&collections::Get,
&collections::Insert, &collections::Insert,
&collections::Rows, &collections::Rows,
&collections::Select, &collections::Select,