mirror of
https://github.com/Dummi26/mers.git
synced 2025-12-15 19:47:50 +01:00
added better error messages inspired by rustc/cargo
but not as good
This commit is contained in:
@@ -24,7 +24,7 @@ impl Config {
|
||||
for t in a.types.iter() {
|
||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||
if t.0.len() != 2 {
|
||||
return Err(CheckError(format!("cannot use try with tuple argument where len != 2 (got len {})", t.0.len())));
|
||||
return Err(format!("cannot use try with tuple argument where len != 2 (got len {})", t.0.len()).into());
|
||||
}
|
||||
let arg_type = &t.0[0];
|
||||
let functions = &t.0[1];
|
||||
@@ -56,7 +56,7 @@ impl Config {
|
||||
},
|
||||
});
|
||||
} else {
|
||||
return Err(CheckError(format!("try: arguments f1-fn must be functions")));
|
||||
return Err(format!("try: arguments f1-fn must be functions").into());
|
||||
}
|
||||
}
|
||||
// found a function that won't fail for this arg_type!
|
||||
@@ -68,18 +68,26 @@ impl Config {
|
||||
}
|
||||
}
|
||||
if tuple_fallible || !tuple_possible {
|
||||
return Err(CheckError(format!("try: if the argument is {arg_type}, there is no infallible function. add a fallback function to handle this case! Errors for all functions: {}", func_errors.iter().enumerate().map(|(i, v)| match v {
|
||||
Some(e) => format!("\n{i}: {}", e.0),
|
||||
None => "\n({i}: no error)".to_owned(),
|
||||
}).collect::<String>())));
|
||||
// if the argument is {arg_type}, there is no infallible function. add a fallback function to handle this case!
|
||||
let mut e = CheckError::new()
|
||||
.msg(format!("if the argument is {arg_type}, there is no infallible function."))
|
||||
.msg(format!("Add a fallback function to handle this case!"));
|
||||
for (i, err) in func_errors.into_iter().enumerate() {
|
||||
if let Some(err) = err {
|
||||
e = e
|
||||
.msg(format!("Error for function #{i}:"))
|
||||
.err(err);
|
||||
}
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!("try: argument must be (arg, (f1, f2, f3, ..., fn))")));
|
||||
return Err(format!("try: argument must be (arg, (f1, f2, f3, ..., fn))").into());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!("cannot use try with non-tuple argument")));
|
||||
return Err(format!("cannot use try with non-tuple argument").into());
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
@@ -106,7 +114,7 @@ impl Config {
|
||||
out: Arc::new(|a, _i| if a.is_included_in(&data::int::IntT) {
|
||||
Ok(Type::empty())
|
||||
} else {
|
||||
Err(CheckError(format!("cannot call exit with non-int argument")))
|
||||
Err(format!("cannot call exit with non-int argument").into())
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
std::process::exit(a.get().as_any().downcast_ref::<data::int::Int>().map(|i| i.0 as _).unwrap_or(1));
|
||||
@@ -120,7 +128,7 @@ impl Config {
|
||||
out: Arc::new(|a, _i| {
|
||||
for t in &a.types {
|
||||
if t.as_any().downcast_ref::<data::string::StringT>().is_none() && t.as_any().downcast_ref::<data::tuple::TupleT>().is_none() {
|
||||
return Err(crate::program::run::CheckError(format!("cannot get length of {t} (must be a tuple or a string)")));
|
||||
return Err(format!("cannot get length of {t} (must be a tuple or a string)").into());
|
||||
}
|
||||
}
|
||||
Ok(Type::new(data::int::IntT))
|
||||
@@ -147,16 +155,16 @@ impl Config {
|
||||
for t in (t.0)(&Type::empty_tuple())?.types {
|
||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||
if t.0.len() > 1 {
|
||||
return Err(crate::program::run::CheckError(format!("called loop with funcion that might return a tuple of length > 1")));
|
||||
return Err(format!("called loop with funcion that might return a tuple of length > 1").into());
|
||||
} else if let Some(v) = t.0.first() {
|
||||
o.add(Arc::new(v.clone()))
|
||||
}
|
||||
} else {
|
||||
return Err(crate::program::run::CheckError(format!("called loop with funcion that might return something other than a tuple")));
|
||||
return Err(format!("called loop with funcion that might return something other than a tuple").into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(crate::program::run::CheckError(format!("called loop on a non-function")));
|
||||
return Err(format!("called loop on a non-function").into());
|
||||
}
|
||||
}
|
||||
Ok(o)
|
||||
@@ -182,7 +190,7 @@ impl Config {
|
||||
out: Arc::new(|a, _i| {
|
||||
for t in &a.types {
|
||||
if t.iterable().is_none() {
|
||||
return Err(crate::program::run::CheckError(format!("called eq on non-iterable")))
|
||||
return Err(format!("called eq on non-iterable").into())
|
||||
}
|
||||
}
|
||||
Ok(Type::new(data::bool::BoolT))
|
||||
@@ -212,7 +220,8 @@ impl Config {
|
||||
Data::new(data::function::Function {
|
||||
info: Arc::new(Info::neverused()),
|
||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||
out: Arc::new(|a, _i| if let Some(v) = a.dereference() { Ok(v) } else { Err(crate::program::run::CheckError(format!("cannot dereference type {a}")))}),
|
||||
out: Arc::new(|a, _i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {a}").into())
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
if let Some(r) = a
|
||||
.get()
|
||||
|
||||
@@ -6,10 +6,7 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
data::{self, Data, MersData, MersType, Type},
|
||||
program::{
|
||||
self,
|
||||
run::{CheckError, CheckInfo},
|
||||
},
|
||||
program::{self, run::CheckInfo},
|
||||
};
|
||||
|
||||
use super::Config;
|
||||
@@ -37,7 +34,7 @@ impl Config {
|
||||
Arc::new(RunCommandErrorT)
|
||||
]))
|
||||
} else {
|
||||
return Err(CheckError(format!("run_command called with invalid arguments (must be (String, Iter<String>))")));
|
||||
return Err(format!("run_command called with invalid arguments (must be (String, Iter<String>))").into());
|
||||
}
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
|
||||
@@ -19,9 +19,7 @@ impl Config {
|
||||
if let Some(v) = a.get() {
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(program::run::CheckError(format!(
|
||||
"called get on non-gettable type {a}"
|
||||
)))
|
||||
Err(format!("called get on non-gettable type {a}").into())
|
||||
}
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
|
||||
@@ -5,10 +5,7 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
data::{self, Data, MersData, MersType, Type},
|
||||
program::{
|
||||
self,
|
||||
run::{CheckError, CheckInfo},
|
||||
},
|
||||
program::{self, run::CheckInfo},
|
||||
};
|
||||
|
||||
use super::Config;
|
||||
@@ -42,24 +39,22 @@ impl Config {
|
||||
for f in f {
|
||||
let ret = f.0(&iter)?;
|
||||
if !ret.is_zero_tuple() {
|
||||
return Err(CheckError(format!(
|
||||
"for_each function must return (), not {ret}"
|
||||
)));
|
||||
return Err(format!("for_each function must return (), not {ret}").into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!(
|
||||
return Err(format!(
|
||||
"for_each called on tuple not containing iterable and function: {v} is {}",
|
||||
if v.iterable().is_some() { "iterable" } else { "not iterable" },
|
||||
)));
|
||||
).into());
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!(
|
||||
return Err(format!(
|
||||
"for_each called on tuple with len < 2"
|
||||
)));
|
||||
).into());
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!("for_each called on non-tuple")));
|
||||
return Err(format!("for_each called on non-tuple").into());
|
||||
}
|
||||
}
|
||||
Ok(Type::empty_tuple())
|
||||
|
||||
@@ -5,10 +5,7 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
data::{self, Data, MersData, MersType, Type},
|
||||
program::{
|
||||
self,
|
||||
run::{CheckError, CheckInfo},
|
||||
},
|
||||
program::{self, run::CheckInfo},
|
||||
};
|
||||
|
||||
use super::Config;
|
||||
@@ -36,14 +33,14 @@ impl Config {
|
||||
if let Some(t) = t.as_any().downcast_ref::<ListT>() {
|
||||
out.add(Arc::new(t.0.clone()));
|
||||
} else {
|
||||
return Err(CheckError(format!(
|
||||
return Err(format!(
|
||||
"pop: found a reference to {t}, which is not a list"
|
||||
)));
|
||||
).into());
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
} else {
|
||||
return Err(CheckError(format!("pop: not a reference: {a}")));
|
||||
return Err(format!("pop: not a reference: {a}").into());
|
||||
}
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
@@ -77,9 +74,9 @@ impl Config {
|
||||
for t in a.types.iter() {
|
||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||
if t.0.len() != 2 {
|
||||
return Err(CheckError(format!(
|
||||
return Err(format!(
|
||||
"push: tuple must have length 2"
|
||||
)));
|
||||
).into());
|
||||
}
|
||||
let a = &t.0[0];
|
||||
let new = &t.0[1];
|
||||
@@ -87,23 +84,24 @@ impl Config {
|
||||
for t in a.types.iter() {
|
||||
if let Some(t) = t.as_any().downcast_ref::<ListT>() {
|
||||
if !new.is_included_in(&t.0) {
|
||||
return Err(CheckError(format!(
|
||||
return Err(format!(
|
||||
"push: found a reference to {t}, which is a list which can't contain elements of type {new}"
|
||||
)));
|
||||
).into());
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!(
|
||||
"push: found a reference to {t}, which is not a list"
|
||||
)));
|
||||
return Err(format!(
|
||||
"push: found a reference to {t}, which is not a list"
|
||||
).into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!(
|
||||
return Err(format!(
|
||||
"push: first element in tuple not a reference: {a}"
|
||||
)));
|
||||
).into());
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!("push: not a tuple: {t}")));
|
||||
return Err(format!("push: not a tuple: {t}")
|
||||
.into());
|
||||
}
|
||||
}
|
||||
Ok(Type::empty_tuple())
|
||||
@@ -138,9 +136,9 @@ impl Config {
|
||||
if let Some(v) = a.iterable() {
|
||||
Ok(Type::new(ListT(v)))
|
||||
} else {
|
||||
Err(program::run::CheckError(format!(
|
||||
Err(format!(
|
||||
"cannot iterate over type {a}"
|
||||
)))
|
||||
).into())
|
||||
}
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
|
||||
@@ -14,6 +14,8 @@ impl Config {
|
||||
/// `sum: fn` returns the sum of all the numbers in the tuple
|
||||
/// `diff: fn` returns b - a
|
||||
/// `product: fn` returns the product of all the numbers in the tuple
|
||||
/// `div: fn` returns a / b. Performs integer division if a and b are both integers.
|
||||
/// `modulo: fn` returns a % b
|
||||
/// `signum: fn` returns 1 for positive numbers, -1 for negative ones and 0 for 0 (always returns an Int, even when input is Float)
|
||||
/// `parse_int: fn` parses a string to an int, returns () on failure
|
||||
/// `parse_float: fn` parses a string to an int, returns () on failure
|
||||
@@ -22,8 +24,6 @@ impl Config {
|
||||
/// `round: fn` rounds the float and returns an int
|
||||
/// `ceil: fn` rounds the float [?] and returns an int
|
||||
/// `floor: fn` rounds the float [?] and returns an int
|
||||
/// `div: fn` returns a / b. Performs integer division if a and b are both integers.
|
||||
/// `modulo: fn` returns a % b
|
||||
pub fn with_math(self) -> Self {
|
||||
self.add_var("parse_float".to_string(), Data::new(data::function::Function {
|
||||
info: Arc::new(program::run::Info::neverused()),
|
||||
@@ -35,7 +35,7 @@ impl Config {
|
||||
Arc::new(data::tuple::TupleT(vec![])),
|
||||
]))
|
||||
} else {
|
||||
Err(CheckError(format!("parse_float called on non-string type")))
|
||||
Err(format!("parse_float called on non-string type").into())
|
||||
}
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
@@ -55,7 +55,7 @@ impl Config {
|
||||
Arc::new(data::tuple::TupleT(vec![])),
|
||||
]))
|
||||
} else {
|
||||
Err(CheckError(format!("parse_float called on non-string type")))
|
||||
Err(format!("parse_float called on non-string type").into())
|
||||
}
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
@@ -72,7 +72,7 @@ impl Config {
|
||||
if a.is_included_in(&Type::newm(vec![Arc::new(data::int::IntT), Arc::new(data::float::FloatT)])) {
|
||||
Ok(Type::new(data::int::IntT))
|
||||
} else {
|
||||
Err(CheckError(format!("signum called on non-number type")))
|
||||
Err(format!("signum called on non-number type").into())
|
||||
}
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
@@ -88,38 +88,47 @@ impl Config {
|
||||
}
|
||||
} else { unreachable!("called signum on non-number type")}))
|
||||
})
|
||||
}))
|
||||
})) .add_var("div".to_string(), Data::new(data::function::Function {
|
||||
info: Arc::new(program::run::Info::neverused()),
|
||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||
out: Arc::new(|a, _i| two_tuple_to_num(a, "div")),
|
||||
run: Arc::new(|a, _i| if let Some(t) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
|
||||
let left = t.0[0].get();
|
||||
let right = t.0[1].get();
|
||||
let (left, right) = (left.as_any(), right.as_any());
|
||||
match (left.downcast_ref::<data::int::Int>(), left.downcast_ref::<data::float::Float>(),
|
||||
right.downcast_ref::<data::int::Int>(), right.downcast_ref::<data::float::Float>()
|
||||
) {
|
||||
(Some(data::int::Int(l)), None, Some(data::int::Int(r)), None) => Data::new(data::int::Int(l / r)),
|
||||
(Some(data::int::Int(l)), None, None, Some(data::float::Float(r))) => Data::new(data::float::Float(*l as f64 / r)),
|
||||
(None, Some(data::float::Float(l)), Some(data::int::Int(r)), None) => Data::new(data::float::Float(l / *r as f64)),
|
||||
(None, Some(data::float::Float(l)), None, Some(data::float::Float(r))) => Data::new(data::float::Float(l / r)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else { unreachable!() }),
|
||||
})).add_var("modulo".to_string(), Data::new(data::function::Function {
|
||||
info: Arc::new(program::run::Info::neverused()),
|
||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||
out: Arc::new(|a, _i| two_tuple_to_num(a, "modulo")),
|
||||
run: Arc::new(|a, _i| if let Some(t) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
|
||||
let left = t.0[0].get();
|
||||
let right = t.0[1].get();
|
||||
let (left, right) = (left.as_any(), right.as_any());
|
||||
match (left.downcast_ref::<data::int::Int>(), left.downcast_ref::<data::float::Float>(),
|
||||
right.downcast_ref::<data::int::Int>(), right.downcast_ref::<data::float::Float>()
|
||||
) {
|
||||
(Some(data::int::Int(l)), None, Some(data::int::Int(r)), None) => Data::new(data::int::Int(l % r)),
|
||||
(Some(data::int::Int(l)), None, None, Some(data::float::Float(r))) => Data::new(data::float::Float(*l as f64 % r)),
|
||||
(None, Some(data::float::Float(l)), Some(data::int::Int(r)), None) => Data::new(data::float::Float(l % *r as f64)),
|
||||
(None, Some(data::float::Float(l)), None, Some(data::float::Float(r))) => Data::new(data::float::Float(l % r)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else { unreachable!() }),
|
||||
}))
|
||||
.add_var("diff".to_string(), Data::new(data::function::Function {
|
||||
info: Arc::new(program::run::Info::neverused()),
|
||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||
out: Arc::new(|a, _i| {
|
||||
let mut float = false;
|
||||
for t in &a.types {
|
||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||
if t.0.len() != 2 {
|
||||
return Err(CheckError(format!("Called diff with a tuple where len != 2")));
|
||||
}
|
||||
for (t, side) in [(&t.0[0], "left"), (&t.0[1], "right")] {
|
||||
for t in t.types.iter() {
|
||||
if t.as_any().is::<data::float::FloatT>() {
|
||||
float = true;
|
||||
} else if !t.as_any().is::<data::int::IntT>() {
|
||||
return Err(CheckError(format!("Called diff, but the {side} side of the tuple had type {t}, which isn't Int/Float.")));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!("Called diff on a non-tuple")));
|
||||
}
|
||||
}
|
||||
Ok(if a.types.is_empty() {
|
||||
Type::empty()
|
||||
} else if float {
|
||||
Type::new(data::float::FloatT)
|
||||
} else {
|
||||
Type::new(data::int::IntT)
|
||||
})
|
||||
}),
|
||||
out: Arc::new(|a, _i| two_tuple_to_num(a, "diff")),
|
||||
run: Arc::new(|a, _i| if let Some(t) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
|
||||
let left = t.0[0].get();
|
||||
let right = t.0[1].get();
|
||||
@@ -156,12 +165,12 @@ impl Config {
|
||||
}) {
|
||||
floats = true;
|
||||
} else {
|
||||
return Err(CheckError(format!("cannot get sum of iterator over type {i} because it contains types that aren't int/float")))
|
||||
return Err(format!("cannot get sum of iterator over type {i} because it contains types that aren't int/float").into())
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!(
|
||||
return Err(format!(
|
||||
"cannot get sum of non-iterable type {a}"
|
||||
)));
|
||||
).into());
|
||||
}
|
||||
}
|
||||
Ok(match (ints, floats) {
|
||||
@@ -217,12 +226,12 @@ impl Config {
|
||||
}) {
|
||||
floats = true;
|
||||
} else {
|
||||
return Err(CheckError(format!("cannot get product of iterator over type {i} because it contains types that aren't int/float")))
|
||||
return Err(format!("cannot get product of iterator over type {i} because it contains types that aren't int/float").into())
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!(
|
||||
return Err(format!(
|
||||
"cannot get product of non-iterable type {a}"
|
||||
)));
|
||||
).into());
|
||||
}
|
||||
}
|
||||
Ok(match (ints, floats) {
|
||||
@@ -259,3 +268,36 @@ impl Config {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// (int, int) -> int
|
||||
/// (int, float) -> float
|
||||
/// (float, int) -> float
|
||||
/// (float, float) -> float
|
||||
fn two_tuple_to_num(a: &Type, func_name: &str) -> Result<Type, CheckError> {
|
||||
let mut float = false;
|
||||
for t in &a.types {
|
||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||
if t.0.len() != 2 {
|
||||
return Err(format!("Called {func_name} with a tuple where len != 2").into());
|
||||
}
|
||||
for (t, side) in [(&t.0[0], "left"), (&t.0[1], "right")] {
|
||||
for t in t.types.iter() {
|
||||
if t.as_any().is::<data::float::FloatT>() {
|
||||
float = true;
|
||||
} else if !t.as_any().is::<data::int::IntT>() {
|
||||
return Err(format!("Called {func_name}, but the {side} side of the tuple had type {t}, which isn't Int/Float.").into());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(format!("Called {func_name} on a non-tuple").into());
|
||||
}
|
||||
}
|
||||
Ok(if a.types.is_empty() {
|
||||
Type::empty()
|
||||
} else if float {
|
||||
Type::new(data::float::FloatT)
|
||||
} else {
|
||||
Type::new(data::int::IntT)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::{
|
||||
data::{self, Data, MersType, Type},
|
||||
program::run::{CheckError, CheckInfo, Info},
|
||||
program::run::{CheckInfo, Info},
|
||||
};
|
||||
|
||||
use super::Config;
|
||||
@@ -21,7 +21,7 @@ impl Config {
|
||||
out: Arc::new(|a, _i| if a.is_included_in(&data::string::StringT) {
|
||||
Ok(Type::new(data::string::StringT))
|
||||
} else {
|
||||
Err(CheckError(format!("cannot call trim on non-strings")))
|
||||
Err(format!("cannot call trim on non-strings").into())
|
||||
}),
|
||||
run: Arc::new(|a, _i| {
|
||||
Data::new(data::string::String(a.get().as_any().downcast_ref::<data::string::String>().unwrap().0.trim().to_owned()))
|
||||
@@ -32,7 +32,7 @@ impl Config {
|
||||
out: Arc::new(|a, _i| if a.iterable().is_some() {
|
||||
Ok(Type::new(data::string::StringT))
|
||||
} else {
|
||||
Err(CheckError(format!("concat called on non-iterable type {a}")))
|
||||
Err(format!("concat called on non-iterable type {a}").into())
|
||||
}),
|
||||
run: Arc::new(|a, _i| Data::new(data::string::String(a.get().iterable().unwrap().map(|v| v.get().to_string()).collect()))),
|
||||
})).add_var("to_string".to_string(), Data::new(data::function::Function {
|
||||
@@ -49,7 +49,7 @@ impl Config {
|
||||
Arc::new(data::int::IntT),
|
||||
]))
|
||||
} else {
|
||||
Err(CheckError(format!("wrong args for index_of: must be (string, string)")))
|
||||
Err(format!("wrong args for index_of: must be (string, string)").into())
|
||||
}),
|
||||
run: Arc::new(|a, _i| index_of(a, false)),
|
||||
})).add_var("index_of_rev".to_string(), Data::new(data::function::Function {
|
||||
@@ -61,7 +61,7 @@ impl Config {
|
||||
Arc::new(data::int::IntT),
|
||||
]))
|
||||
} else {
|
||||
Err(CheckError(format!("wrong args for index_of: must be (string, string)")))
|
||||
Err(format!("wrong args for index_of: must be (string, string)").into())
|
||||
}),
|
||||
run: Arc::new(|a, _i| index_of(a, true)),
|
||||
})).add_var("substring".to_string(), Data::new(data::function::Function {
|
||||
@@ -71,19 +71,19 @@ impl Config {
|
||||
for t in a.types.iter() {
|
||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||
if t.0.len() != 2 && t.0.len() != 3 {
|
||||
return Err(CheckError(format!("cannot call substring with tuple argument of len != 3")));
|
||||
return Err(format!("cannot call substring with tuple argument of len != 3").into());
|
||||
}
|
||||
if !t.0[0].is_included_in(&data::string::StringT) {
|
||||
return Err(CheckError(format!("cannot call substring with tuple argument that isn't (*string*, int, int)")));
|
||||
return Err(format!("cannot call substring with tuple argument that isn't (*string*, int, int)").into());
|
||||
}
|
||||
if !t.0[1].is_included_in(&data::int::IntT) {
|
||||
return Err(CheckError(format!("cannot call substring with tuple argument that isn't (string, *int*, int)")));
|
||||
return Err(format!("cannot call substring with tuple argument that isn't (string, *int*, int)").into());
|
||||
}
|
||||
if t.0.len() > 2 && !t.0[2].is_included_in(&data::int::IntT) {
|
||||
return Err(CheckError(format!("cannot call substring with tuple argument that isn't (string, int, *int*)")));
|
||||
return Err(format!("cannot call substring with tuple argument that isn't (string, int, *int*)").into());
|
||||
}
|
||||
} else {
|
||||
return Err(CheckError(format!("cannot call substring with non-tuple argument.")));
|
||||
return Err(format!("cannot call substring with non-tuple argument.").into());
|
||||
}
|
||||
}
|
||||
Ok(if a.types.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user