2024-08-09 01:59:09 +00:00
|
|
|
//! Integrated functions that can be called from Dust code.
|
2024-08-08 17:49:40 +00:00
|
|
|
use std::{
|
2024-08-09 00:58:56 +00:00
|
|
|
error::Error,
|
2024-08-08 17:49:40 +00:00
|
|
|
fmt::{self, Display, Formatter},
|
|
|
|
io::{self, stdin},
|
|
|
|
};
|
2024-08-07 23:44:01 +00:00
|
|
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
use crate::{Type, Value};
|
|
|
|
|
2024-08-09 01:59:09 +00:00
|
|
|
/// Integrated function that can be called from Dust code.
|
2024-08-07 23:44:01 +00:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
|
|
|
pub enum BuiltInFunction {
|
2024-08-08 17:49:40 +00:00
|
|
|
// Integer and float tools
|
2024-08-07 23:44:01 +00:00
|
|
|
IsEven,
|
|
|
|
IsOdd,
|
2024-08-08 17:49:40 +00:00
|
|
|
|
|
|
|
// List tools
|
2024-08-07 23:44:01 +00:00
|
|
|
Length,
|
2024-08-08 17:49:40 +00:00
|
|
|
|
|
|
|
// I/O
|
|
|
|
ReadLine,
|
|
|
|
WriteLine,
|
2024-08-07 23:44:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BuiltInFunction {
|
|
|
|
pub fn name(&self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
BuiltInFunction::IsEven => "is_even",
|
|
|
|
BuiltInFunction::IsOdd => "is_odd",
|
|
|
|
BuiltInFunction::Length => "length",
|
2024-08-08 17:49:40 +00:00
|
|
|
BuiltInFunction::ReadLine => "read_line",
|
|
|
|
BuiltInFunction::WriteLine => "write_line",
|
2024-08-07 23:44:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn call(
|
|
|
|
&self,
|
|
|
|
_type_arguments: Option<Vec<Type>>,
|
|
|
|
value_arguments: Option<Vec<Value>>,
|
2024-08-08 17:49:40 +00:00
|
|
|
) -> Result<Option<Value>, BuiltInFunctionError> {
|
2024-08-07 23:44:01 +00:00
|
|
|
match self {
|
|
|
|
BuiltInFunction::IsEven => {
|
|
|
|
if let Some(value_arguments) = value_arguments {
|
|
|
|
if value_arguments.len() == 1 {
|
|
|
|
if let Some(integer) = value_arguments[0].as_integer() {
|
2024-08-08 17:49:40 +00:00
|
|
|
Ok(Some(Value::boolean(integer % 2 == 0)))
|
2024-08-07 23:44:01 +00:00
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::ExpectedInteger)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BuiltInFunction::IsOdd => {
|
|
|
|
if let Some(value_arguments) = value_arguments {
|
|
|
|
if value_arguments.len() == 1 {
|
|
|
|
if let Some(integer) = value_arguments[0].as_integer() {
|
2024-08-08 17:49:40 +00:00
|
|
|
Ok(Some(Value::boolean(integer % 2 != 0)))
|
2024-08-07 23:44:01 +00:00
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::ExpectedInteger)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BuiltInFunction::Length => {
|
|
|
|
if let Some(value_arguments) = value_arguments {
|
|
|
|
if value_arguments.len() == 1 {
|
|
|
|
if let Some(list) = value_arguments[0].as_list() {
|
2024-08-08 17:49:40 +00:00
|
|
|
Ok(Some(Value::integer(list.len() as i64)))
|
2024-08-07 23:44:01 +00:00
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::ExpectedInteger)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
}
|
2024-08-08 17:49:40 +00:00
|
|
|
BuiltInFunction::ReadLine => {
|
|
|
|
if value_arguments.is_none() {
|
|
|
|
let mut input = String::new();
|
|
|
|
|
|
|
|
stdin().read_line(&mut input)?;
|
|
|
|
|
|
|
|
Ok(Some(Value::string(input)))
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BuiltInFunction::WriteLine => {
|
|
|
|
if let Some(value_arguments) = value_arguments {
|
|
|
|
if value_arguments.len() == 1 {
|
|
|
|
println!("{}", value_arguments[0]);
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
|
|
|
}
|
|
|
|
}
|
2024-08-07 23:44:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expected_type(&self) -> Option<Type> {
|
|
|
|
match self {
|
|
|
|
BuiltInFunction::IsEven => Some(Type::Boolean),
|
|
|
|
BuiltInFunction::IsOdd => Some(Type::Boolean),
|
|
|
|
BuiltInFunction::Length => Some(Type::Integer),
|
2024-08-08 17:49:40 +00:00
|
|
|
BuiltInFunction::ReadLine => Some(Type::String),
|
|
|
|
BuiltInFunction::WriteLine => None,
|
2024-08-07 23:44:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for BuiltInFunction {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub enum BuiltInFunctionError {
|
|
|
|
ExpectedInteger,
|
2024-08-08 17:49:40 +00:00
|
|
|
Io(io::ErrorKind),
|
2024-08-07 23:44:01 +00:00
|
|
|
WrongNumberOfValueArguments,
|
|
|
|
}
|
2024-08-08 17:49:40 +00:00
|
|
|
|
|
|
|
impl From<io::Error> for BuiltInFunctionError {
|
|
|
|
fn from(error: io::Error) -> Self {
|
|
|
|
Self::Io(error.kind())
|
|
|
|
}
|
|
|
|
}
|
2024-08-09 00:58:56 +00:00
|
|
|
|
|
|
|
impl Error for BuiltInFunctionError {}
|
|
|
|
|
|
|
|
impl Display for BuiltInFunctionError {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
BuiltInFunctionError::ExpectedInteger => write!(f, "Expected an integer"),
|
|
|
|
BuiltInFunctionError::Io(error_kind) => write!(f, "I/O error: {}", error_kind),
|
|
|
|
BuiltInFunctionError::WrongNumberOfValueArguments => {
|
|
|
|
write!(f, "Wrong number of value arguments")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|