improve panic function, add stacktrace

This commit is contained in:
Mark 2024-06-19 12:35:23 +02:00
parent 4770e3f939
commit cd21c2171e
35 changed files with 367 additions and 232 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "mers"
version = "0.8.8"
version = "0.8.9"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "dynamically typed but type-checked programming language"
@ -11,7 +11,7 @@ repository = "https://github.com/Dummi26/mers"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
mers_lib = "0.8.8"
mers_lib = "0.8.9"
# mers_lib = { path = "../mers_lib" }
clap = { version = "4.3.19", features = ["derive"] }
colored = "2.1.0"

View File

@ -122,7 +122,10 @@ fn main() {
exit(255);
}
Ok(_) => {
compiled.run(&mut i2);
if let Err(e) = compiled.run(&mut i2) {
eprintln!("Error while running: {}", e);
std::process::exit(1);
}
}
},
}
@ -145,7 +148,10 @@ fn main() {
exit(255);
}
Ok(compiled) => {
compiled.run(&mut i2);
if let Err(e) = compiled.run(&mut i2) {
eprintln!("Error while running: {}", e);
std::process::exit(1);
}
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "mers_lib"
version = "0.8.8"
version = "0.8.9"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "library to use the mers language in other projects"

View File

@ -43,7 +43,7 @@ fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> {
// check (this step is optional, but if it is skipped when it would have returned an error, `run` will likely panic)
let output_type = compiled.check(&mut i3, None)?;
// run
let output_value = compiled.run(&mut i2);
let output_value = compiled.run(&mut i2)?;
// check that the predicted output type was correct
assert!(output_value.get().as_type().is_included_in(&output_type));
// return the produced value

View File

@ -23,7 +23,7 @@ fn main() -> Result<(), CheckError> {
// use the function to decorate these 3 test strings
for input in ["my test string", "Main Menu", "O.o"] {
let result = func.run(Data::new(data::string::String(input.to_owned())));
let result = func.run(Data::new(data::string::String(input.to_owned())))?;
let result = result.get();
let result = &result
.as_any()
@ -44,6 +44,6 @@ fn parse_compile_check_run(src: String) -> Result<(Type, Data), CheckError> {
let (mut i1, mut i2, mut i3) = Config::new().bundle_std().infos();
let compiled = parsed.compile(&mut i1, CompInfo::default())?;
let output_type = compiled.check(&mut i3, None)?;
let output_value = compiled.run(&mut i2);
let output_value = compiled.run(&mut i2)?;
Ok((output_type, output_value))
}

View File

@ -48,7 +48,7 @@ fn run(src: String) -> Result<(), CheckError> {
.downcast_ref::<data::string::String>()
.unwrap()
.0;
Data::new(data::string::String(arg.chars().rev().collect()))
Ok(Data::new(data::string::String(arg.chars().rev().collect())))
},
)),
)
@ -56,6 +56,6 @@ fn run(src: String) -> Result<(), CheckError> {
let compiled = parsed.compile(&mut i1, CompInfo::default())?;
compiled.check(&mut i3, None)?;
compiled.run(&mut i2);
compiled.run(&mut i2)?;
Ok(())
}

View File

@ -16,7 +16,8 @@ pub struct Function {
pub info: Arc<Info>,
pub info_check: Arc<Mutex<CheckInfo>>,
pub out: Arc<dyn Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
pub run: Arc<dyn Fn(Data, &mut crate::program::run::Info) -> Data + Send + Sync>,
pub run:
Arc<dyn Fn(Data, &mut crate::program::run::Info) -> Result<Data, CheckError> + Send + Sync>,
pub inner_statements: Option<(
Arc<Box<dyn crate::program::run::MersStatement>>,
Arc<Box<dyn crate::program::run::MersStatement>>,
@ -25,7 +26,7 @@ pub struct Function {
impl Function {
pub fn new(
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
run: impl Fn(Data) -> Data + Send + Sync + 'static,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> Self {
Self {
info: Arc::new(crate::info::Info::neverused()),
@ -56,7 +57,7 @@ impl Function {
drop(lock);
(self.out)(arg, &mut info)
}
pub fn run(&self, arg: Data) -> Data {
pub fn run(&self, arg: Data) -> Result<Data, CheckError> {
(self.run)(arg, &mut self.info.as_ref().clone())
}
pub fn get_as_type(&self) -> FunctionT {
@ -72,10 +73,19 @@ impl Function {
}
impl MersData for Function {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
let s = Clone::clone(self);
Some(Box::new(std::iter::from_fn(move || {
s.run(Data::empty_tuple()).one_tuple_content()
match s.run(Data::empty_tuple()) {
Err(e) => Some(Err(e)),
Ok(v) => {
if let Some(v) = v.one_tuple_content() {
Some(Ok(v))
} else {
None
}
}
}
})))
}
fn is_eq(&self, _other: &dyn MersData) -> bool {

View File

@ -4,6 +4,8 @@ use std::{
sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use crate::errors::CheckError;
pub mod bool;
pub mod byte;
pub mod float;
@ -17,12 +19,12 @@ pub mod tuple;
pub mod defs;
pub trait MersData: Any + Debug + Display + Send + Sync {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
None
}
/// By default, uses `iterable` to get an iterator and `nth` to retrieve the nth element.
/// Should have a custom implementation for better performance on most types
fn get(&self, i: usize) -> Option<Data> {
fn get(&self, i: usize) -> Option<Result<Data, CheckError>> {
self.iterable()?.nth(i)
}
/// If self and other are different types (`other.as_any().downcast_ref::<Self>().is_none()`),

View File

@ -1,5 +1,7 @@
use std::{any::Any, fmt::Display, sync::Arc};
use crate::errors::CheckError;
use super::{Data, MersData, MersType, Type};
#[derive(Debug, Clone)]
@ -22,8 +24,8 @@ impl MersData for Tuple {
false
}
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
Some(Box::new(self.0.clone().into_iter()))
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
Some(Box::new(self.0.clone().into_iter().map(Ok)))
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))

View File

@ -395,6 +395,11 @@ impl From<String> for CheckError {
Self::new().msg(value)
}
}
impl From<&str> for CheckError {
fn from(value: &str) -> Self {
Self::new().msg(value.to_owned())
}
}
impl Debug for CheckError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")

View File

@ -8,7 +8,7 @@ use crate::{
pub fn to_mers_func(
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
run: impl Fn(Data) -> Data + Send + Sync + 'static,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> data::function::Function {
data::function::Function {
info: Arc::new(Info::neverused()),
@ -22,7 +22,7 @@ pub fn to_mers_func(
pub fn to_mers_func_with_in_type(
in_type: Type,
out: impl Fn(&Type) -> Result<Type, CheckError> + Send + Sync + 'static,
run: impl Fn(Data) -> Data + Send + Sync + 'static,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> data::function::Function {
to_mers_func(
move |a| {
@ -39,7 +39,7 @@ pub fn to_mers_func_with_in_type(
pub fn to_mers_func_with_in_out_types(
in_type: Type,
out_type: Type,
run: impl Fn(Data) -> Data + Send + Sync + 'static,
run: impl Fn(Data) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> data::function::Function {
to_mers_func(
move |a| {
@ -55,7 +55,7 @@ pub fn to_mers_func_with_in_out_types(
pub fn to_mers_func_concrete_string_to_any(
out_type: Type,
f: impl Fn(&str) -> Data + Send + Sync + 'static,
f: impl Fn(&str) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> data::function::Function {
to_mers_func_with_in_out_types(Type::new(data::string::StringT), out_type, move |a| {
f(a.get()
@ -70,13 +70,13 @@ pub fn to_mers_func_concrete_string_to_string(
f: impl Fn(&str) -> String + Send + Sync + 'static,
) -> data::function::Function {
to_mers_func_concrete_string_to_any(Type::new(data::string::StringT), move |a| {
Data::new(data::string::String(f(a)))
Ok(Data::new(data::string::String(f(a))))
})
}
pub fn to_mers_func_concrete_string_string_to_any(
out_type: Type,
f: impl Fn(&str, &str) -> Data + Send + Sync + 'static,
f: impl Fn(&str, &str) -> Result<Data, CheckError> + Send + Sync + 'static,
) -> data::function::Function {
to_mers_func_with_in_out_types(
Type::new(data::tuple::TupleT(vec![
@ -109,13 +109,13 @@ pub fn to_mers_func_concrete_string_string_to_opt_int(
) -> data::function::Function {
to_mers_func_concrete_string_string_to_any(
Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![Type::new(data::int::IntT)])),
Arc::new(data::tuple::TupleT(vec![])),
Arc::new(data::int::IntT),
]),
move |a, b| {
f(a, b)
.map(|v| Data::new(data::int::Int(v)))
.unwrap_or_else(|| Data::empty_tuple())
Ok(f(a, b)
.map(|v| Data::one_tuple(Data::new(data::int::Int(v))))
.unwrap_or_else(|| Data::empty_tuple()))
},
)
}
@ -123,7 +123,7 @@ pub fn to_mers_func_concrete_string_string_to_bool(
f: impl Fn(&str, &str) -> bool + Send + Sync + 'static,
) -> data::function::Function {
to_mers_func_concrete_string_string_to_any(Type::new(data::bool::BoolT), move |a, b| {
Data::new(data::bool::Bool(f(a, b)))
Ok(Data::new(data::bool::Bool(f(a, b))))
})
}
pub fn to_mers_func_concrete_string_string_to_opt_string_string(
@ -138,14 +138,14 @@ pub fn to_mers_func_concrete_string_string_to_opt_string_string(
])),
]),
move |a, b| {
f(a, b)
Ok(f(a, b)
.map(|(a, b)| {
Data::new(data::tuple::Tuple(vec![
Data::new(data::string::String(a)),
Data::new(data::string::String(b)),
]))
})
.unwrap_or_else(|| Data::empty_tuple())
.unwrap_or_else(|| Data::empty_tuple()))
},
)
}

View File

@ -70,8 +70,8 @@ impl Config {
let mut arg = arg_ref.0.write().unwrap();
let func = a.0[1].get();
let func = func.as_any().downcast_ref::<data::function::Function>().unwrap();
*arg = func.run(arg.clone());
Data::empty_tuple()
*arg = func.run(arg.clone())?;
Ok(Data::empty_tuple())
}),
inner_statements: None,
}))
@ -95,11 +95,11 @@ impl Config {
} else {
unreachable!("sleep called on non-int/non-float")
});
Data::empty_tuple()
Ok(Data::empty_tuple())
}),
inner_statements: None,
}))
.add_var("panic".to_string(), Data::new(data::function::Function {
.add_var("exit".to_string(), Data::new(data::function::Function {
info: Arc::new(Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| if a.is_included_in_single(&data::int::IntT) {
@ -111,6 +111,26 @@ impl Config {
std::process::exit(a.get().as_any().downcast_ref::<data::int::Int>().map(|i| i.0 as _).unwrap_or(1));
}),
inner_statements: None,
}))
.add_var("panic".to_string(), Data::new(data::function::Function {
info: Arc::new(Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| if a.is_included_in_single(&data::string::StringT) {
Ok(Type::empty())
} else {
Err(format!("cannot call panic with non-string argument").into())
}),
run: Arc::new(|a, _i| {
Err(
a
.get()
.as_any()
.downcast_ref::<data::string::String>()
.map(|i| i.0.to_owned())
.unwrap_or_else(String::new).into()
)
}),
inner_statements: None,
}))
.add_var(
"len".to_string(),
@ -126,7 +146,7 @@ impl Config {
Ok(Type::new(data::int::IntT))
}),
run: Arc::new(|a, _i| {
Data::new(data::int::Int(if let Some(t) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
Ok(Data::new(data::int::Int(if let Some(t) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
t.0.len() as _
} else if let Some(s) = a.get().as_any().downcast_ref::<data::string::String>() {
s.0.len() as _
@ -135,7 +155,7 @@ impl Config {
i.take(isize::MAX as usize + 1).count() as isize
} else {
unreachable!("called len on {a:?}, which isn't a tuple or a string")
}))
})))
}),
inner_statements: None,
}),
@ -154,10 +174,12 @@ impl Config {
Ok(Type::new(data::bool::BoolT))
}),
run: Arc::new(|a, _i| {
Data::new(data::bool::Bool(if let Some(mut i) = a.get().iterable() {
Ok(Data::new(data::bool::Bool(if let Some(mut i) = a.get().iterable() {
if let Some(f) = i.next() {
let f = f?;
let mut o = true;
for el in i {
let el = el?;
if el != f {
o = false;
break;
@ -169,7 +191,7 @@ impl Config {
}
} else {
false
}))
})))
}),
inner_statements: None,
}),
@ -181,7 +203,7 @@ impl Config {
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| Ok(Type::new(data::reference::ReferenceT(a.clone())))),
run: Arc::new(|a, _i| {
Data::new(data::reference::Reference(Arc::new(RwLock::new(a.clone()))))
Ok(Data::new(data::reference::Reference(Arc::new(RwLock::new(a.clone())))))
}),
inner_statements: None,
}),
@ -199,9 +221,9 @@ impl Config {
.as_any()
.downcast_ref::<data::reference::Reference>()
{
r.0.write().unwrap().clone()
Ok(r.0.write().unwrap().clone())
} else {
unreachable!("called deref on non-reference")
Err("called deref on non-reference".into())
}
}),
inner_statements: None,

View File

@ -7,6 +7,7 @@ use std::{
use crate::{
data::{self, Data, MersData, MersType, Type},
errors::CheckError,
program::{self, run::CheckInfo},
};
@ -51,8 +52,9 @@ impl Config {
cmd.as_any().downcast_ref::<data::string::String>().unwrap(),
args.get().iterable().unwrap(),
);
let args = args.map(|v| v.map(|v| v.get().to_string())).collect::<Result<Vec<_>, _>>()?;
match Command::new(&cmd.0)
.args(args.map(|v| v.get().to_string()))
.args(args)
.output()
{
Ok(output) => {
@ -65,13 +67,13 @@ impl Config {
String::from_utf8_lossy(&output.stdout).into_owned();
let stderr =
String::from_utf8_lossy(&output.stderr).into_owned();
Data::new(data::tuple::Tuple(vec![
Ok(Data::new(data::tuple::Tuple(vec![
status,
Data::new(data::string::String(stdout)),
Data::new(data::string::String(stderr)),
]))
])))
}
Err(e) => Data::new(data::object::Object(vec![("run_command_error".to_owned(), Data::new(data::string::String(e.to_string())))])),
Err(e) => Ok(Data::new(data::object::Object(vec![("run_command_error".to_owned(), Data::new(data::string::String(e.to_string())))]))),
}
}),
inner_statements: None,
@ -101,8 +103,9 @@ impl Config {
cmd.as_any().downcast_ref::<data::string::String>().unwrap(),
args.get().iterable().unwrap(),
);
let args = args.map(|v| v.map(|v| v.get().to_string())).collect::<Result<Vec<_>, _>>()?;
match Command::new(&cmd.0)
.args(args.map(|v| v.get().to_string()))
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
@ -112,9 +115,9 @@ impl Config {
let a = Some(child.stdin.take().unwrap());
let b = BufReader::new(child.stdout.take().unwrap());
let c = BufReader::new(child.stderr.take().unwrap());
Data::new(ChildProcess(Arc::new(Mutex::new((child, a, b, c)))))
Ok(Data::new(ChildProcess(Arc::new(Mutex::new((child, a, b, c))))))
}
Err(e) => Data::new(data::object::Object(vec![("run_command_error".to_owned(), Data::new(data::string::String(e.to_string())))])),
Err(e) => Ok(Data::new(data::object::Object(vec![("run_command_error".to_owned(), Data::new(data::string::String(e.to_string())))]))),
}
}),
inner_statements: None,
@ -139,11 +142,11 @@ impl Config {
let a = a.get();
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
let mut child = child.0.lock().unwrap();
match child.0.try_wait() {
Ok(match child.0.try_wait() {
Ok(Some(_)) => Data::one_tuple(Data::new(data::bool::Bool(true))),
Ok(None) => Data::one_tuple(Data::new(data::bool::Bool(false))),
Err(_) => Data::empty_tuple(),
}
})
}),
inner_statements: None,
}),
@ -169,14 +172,14 @@ impl Config {
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
let mut child = child.0.lock().unwrap();
drop(child.1.take());
match child.0.wait() {
Ok(match child.0.wait() {
Ok(s) => if let Some(s) = s.code() {
Data::new(data::int::Int(s as _))
} else {
Data::new(data::bool::Bool(s.success()))
}
Err(_) => Data::empty_tuple(),
}
})
}),
inner_statements: None,
}),
@ -200,12 +203,12 @@ impl Config {
let bytes = tuple.0[1].get();
let child = child.as_any().downcast_ref::<ChildProcess>().unwrap();
let mut child = child.0.lock().unwrap();
let buf = bytes.iterable().unwrap().map(|v| v.get().as_any().downcast_ref::<data::byte::Byte>().unwrap().0).collect::<Vec<_>>();
if child.1.as_mut().is_some_and(|v| v.write_all(&buf).is_ok() && v.flush().is_ok()) {
let buf = bytes.iterable().unwrap().map(|v| v.map(|v| v.get().as_any().downcast_ref::<data::byte::Byte>().unwrap().0)).collect::<Result<Vec<_>, _>>()?;
Ok(if child.1.as_mut().is_some_and(|v| v.write_all(&buf).is_ok() && v.flush().is_ok()) {
Data::new(data::bool::Bool(true))
} else {
Data::new(data::bool::Bool(false))
}
})
}),
inner_statements: None,
}),
@ -230,11 +233,11 @@ impl Config {
let child = child.as_any().downcast_ref::<ChildProcess>().unwrap();
let mut child = child.0.lock().unwrap();
let buf = string.as_any().downcast_ref::<data::string::String>().unwrap().0.as_bytes();
if child.1.as_mut().is_some_and(|v| v.write_all(buf).is_ok() && v.flush().is_ok()) {
Ok(if child.1.as_mut().is_some_and(|v| v.write_all(buf).is_ok() && v.flush().is_ok()) {
Data::new(data::bool::Bool(true))
} else {
Data::new(data::bool::Bool(false))
}
})
}),
inner_statements: None,
}),
@ -259,11 +262,11 @@ impl Config {
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
let mut child = child.0.lock().unwrap();
let mut buf = [0];
if child.2.read_exact(&mut buf).is_ok() {
Ok(if child.2.read_exact(&mut buf).is_ok() {
Data::one_tuple(Data::new(data::byte::Byte(buf[0])))
} else {
Data::empty_tuple()
}
})
}),
inner_statements: None,
}),
@ -288,11 +291,11 @@ impl Config {
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
let mut child = child.0.lock().unwrap();
let mut buf = [0];
if child.3.read_exact(&mut buf).is_ok() {
Ok(if child.3.read_exact(&mut buf).is_ok() {
Data::one_tuple(Data::new(data::byte::Byte(buf[0])))
} else {
Data::empty_tuple()
}
})
}),
inner_statements: None,
}),
@ -317,11 +320,11 @@ impl Config {
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
let mut child = child.0.lock().unwrap();
let mut buf = String::new();
if child.2.read_line(&mut buf).is_ok() {
Ok(if child.2.read_line(&mut buf).is_ok() {
Data::one_tuple(Data::new(data::string::String(buf)))
} else {
Data::empty_tuple()
}
})
}),
inner_statements: None,
}),
@ -346,11 +349,11 @@ impl Config {
let child = a.as_any().downcast_ref::<ChildProcess>().unwrap();
let mut child = child.0.lock().unwrap();
let mut buf = String::new();
if child.3.read_line(&mut buf).is_ok() {
Ok(if child.3.read_line(&mut buf).is_ok() {
Data::one_tuple(Data::new(data::string::String(buf)))
} else {
Data::empty_tuple()
}
})
}),
inner_statements: None,
}),
@ -372,10 +375,10 @@ pub struct ChildProcess(
#[derive(Clone, Debug)]
pub struct ChildProcessT;
impl MersData for ChildProcess {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
None
}
fn get(&self, _i: usize) -> Option<Data> {
fn get(&self, _i: usize) -> Option<Result<Data, CheckError>> {
None
}
fn is_eq(&self, other: &dyn MersData) -> bool {

View File

@ -49,21 +49,24 @@ impl Config {
run: Arc::new(|a, _i| {
let a = a.get();
if let (Some(v), Some(i)) = (a.get(0), a.get(1)) {
if let Some(i) = i.get().as_any().downcast_ref::<data::int::Int>() {
if let Ok(i) = i.0.try_into() {
let (v, i2) = (v?, i?);
let o = if let Some(i3) = i2.get().as_any().downcast_ref::<data::int::Int>()
{
if let Ok(i) = i3.0.try_into() {
if let Some(v) = v.get().get(i) {
Data::one_tuple(v)
Ok(Data::one_tuple(v?))
} else {
Data::empty_tuple()
Ok(Data::empty_tuple())
}
} else {
Data::empty_tuple()
Ok(Data::empty_tuple())
}
} else {
unreachable!("get called with non-int index")
}
Err("get called with non-int index".into())
};
o
} else {
unreachable!("get called with less than 2 args")
Err("get called with less than 2 args".into())
}
}),
inner_statements: None,

View File

@ -29,10 +29,20 @@ impl Config {
pub fn with_iters(self) -> Self {
self
.add_var("any".to_string(), Data::new(genfunc_iter_in_val_out("all".to_string(), data::bool::BoolT, Type::new(data::bool::BoolT), |a, _i| {
Data::new(data::bool::Bool(a.get().iterable().unwrap().any(|v| v.get().as_any().downcast_ref::<data::bool::Bool>().is_some_and(|v| v.0))))
for v in a.get().iterable().unwrap().map(|v| v.map(|v| v.get().as_any().downcast_ref::<data::bool::Bool>().is_some_and(|v| v.0))) {
if v? {
return Ok(Data::new(data::bool::Bool(true)));
}
}
Ok(Data::new(data::bool::Bool(false)))
})))
.add_var("all".to_string(), Data::new(genfunc_iter_in_val_out("all".to_string(), data::bool::BoolT, Type::new(data::bool::BoolT), |a, _i| {
Data::new(data::bool::Bool(a.get().iterable().unwrap().all(|v| v.get().as_any().downcast_ref::<data::bool::Bool>().is_some_and(|v| v.0))))
for v in a.get().iterable().unwrap().map(|v| v.map(|v| v.get().as_any().downcast_ref::<data::bool::Bool>().is_some_and(|v| v.0))) {
if !v? {
return Ok(Data::new(data::bool::Bool(false)));
}
}
Ok(Data::new(data::bool::Bool(true)))
})))
.add_var(
"for_each".to_string(),
@ -83,9 +93,9 @@ impl Config {
f.get().as_any().downcast_ref::<data::function::Function>(),
) {
for v in iter {
f.run(v);
f.run(v?)?;
}
Data::empty_tuple()
Ok(Data::empty_tuple())
} else {
unreachable!(
"for_each called on tuple not containing iterable and function"
@ -133,7 +143,7 @@ impl Config {
};
Ok(Type::new(IterT::new(ItersT::Enumerate, data)?))
}),
run: Arc::new(|a, _i| Data::new(Iter(Iters::Enumerate, a.clone()))),
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Enumerate, a.clone())))),
inner_statements: None,
}),
)
@ -150,7 +160,7 @@ impl Config {
};
Ok(Type::new(IterT::new(ItersT::Chained, data)?))
}),
run: Arc::new(|a, _i| Data::new(Iter(Iters::Chained, a.clone()))),
run: Arc::new(|a, _i| Ok(Data::new(Iter(Iters::Chained, a.clone())))),
inner_statements: None,
}),
)
@ -211,7 +221,7 @@ fn genfunc_iter_and_arg<T: MersType, D: MersData>(
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
if let Some(f) = f.get().as_any().downcast_ref::<D>() {
Data::new(Iter(fd(f), v.clone()))
Ok(Data::new(Iter(fd(f), v.clone())))
} else {
unreachable!("{name} called on tuple not containing function")
}
@ -254,55 +264,76 @@ impl MersData for Iter {
fn is_eq(&self, _other: &dyn MersData) -> bool {
false
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
Some(match &self.0 {
Iters::Map(f) => {
let f = Clone::clone(f);
Box::new(self.1.get().iterable()?.map(move |v| f.run(v)))
Box::new(self.1.get().iterable()?.map(move |v| f.run(v?)))
}
Iters::Filter(f) => {
let f = Clone::clone(f);
Box::new(self.1.get().iterable()?.filter(move |v| {
f.run(v.clone())
.get()
Box::new(self.1.get().iterable()?.filter_map(move |v| {
match v {
Ok(v) => match f.run(v.clone()) {
Ok(f) => {
if f.get()
.as_any()
.downcast_ref::<data::bool::Bool>()
.is_some_and(|b| b.0)
{
Some(Ok(v))
} else {
None
}
}
Err(e) => Some(Err(e)),
},
Err(e) => Some(Err(e)),
}
}))
}
Iters::FilterMap(f) => {
let f = Clone::clone(f);
Box::new(
self.1
.get()
.iterable()?
.filter_map(move |v| f.run(v).one_tuple_content()),
)
Box::new(self.1.get().iterable()?.filter_map(move |v| match v {
Ok(v) => match f.run(v) {
Ok(r) => Some(Ok(r.one_tuple_content()?)),
Err(e) => Some(Err(e)),
},
Err(e) => Some(Err(e)),
}))
}
Iters::MapWhile(f) => {
let f = Clone::clone(f);
Box::new(
self.1
.get()
.iterable()?
.map_while(move |v| f.run(v).one_tuple_content()),
)
Box::new(self.1.get().iterable()?.map_while(move |v| match v {
Ok(v) => match f.run(v) {
Ok(r) => Some(Ok(r.one_tuple_content()?)),
Err(e) => Some(Err(e)),
},
Err(e) => Some(Err(e)),
}))
}
Iters::Take(limit) => Box::new(self.1.get().iterable()?.take(*limit)),
Iters::Enumerate => Box::new(self.1.get().iterable()?.enumerate().map(|(i, v)| {
Data::new(data::tuple::Tuple(vec![
Iters::Enumerate => {
Box::new(self.1.get().iterable()?.enumerate().map(|(i, v)| match v {
Ok(v) => Ok(Data::new(data::tuple::Tuple(vec![
Data::new(data::int::Int(i as _)),
v,
]))
})),
]))),
Err(e) => Err(e),
}))
}
Iters::Chained => {
let iters = self
match self
.1
.get()
.iterable()?
.map(|v| v.get().iterable())
.collect::<Option<Vec<_>>>()?;
Box::new(iters.into_iter().flatten())
.map(|v| Ok(v?.get().iterable()))
.collect::<Result<Option<Vec<_>>, CheckError>>()
{
Ok(Some(iters)) => Box::new(iters.into_iter().flatten()),
Ok(None) => return None,
Err(e) => Box::new([Err(e)].into_iter()),
}
}
})
}
@ -433,7 +464,10 @@ fn genfunc_iter_in_val_out(
name: String,
iter_type: impl MersType + 'static,
out_type: Type,
run: impl Fn(Data, &mut crate::info::Info<program::run::Local>) -> Data + Send + Sync + 'static,
run: impl Fn(Data, &mut crate::info::Info<program::run::Local>) -> Result<Data, CheckError>
+ Send
+ Sync
+ 'static,
) -> Function {
Function {
info: Arc::new(crate::info::Info::neverused()),

View File

@ -5,6 +5,7 @@ use std::{
use crate::{
data::{self, Data, MersData, MersType, Type},
errors::CheckError,
parsing::{statements::to_string_literal, Source},
program::{self, run::CheckInfo},
};
@ -93,7 +94,7 @@ impl Config {
}
None => Data::empty_tuple(),
};
o
Ok(o)
}),
inner_statements: None,
}))
@ -123,7 +124,7 @@ impl Config {
}
}),
run: Arc::new(|a, _i| {
match a
Ok(match a
.get()
.as_any()
.downcast_ref::<data::reference::Reference>()
@ -140,7 +141,7 @@ impl Config {
{
Some(data) => Data::one_tuple(data.read().unwrap().clone()),
None => Data::empty_tuple(),
}
})
}),
inner_statements: None,
}),
@ -203,7 +204,7 @@ impl Config {
.unwrap()
.0
.push(Arc::new(RwLock::new(tuple.0[1].clone())));
Data::empty_tuple()
Ok(Data::empty_tuple())
}),
inner_statements: None,
}),
@ -224,9 +225,9 @@ impl Config {
}),
run: Arc::new(|a, _i| {
if let Some(i) = a.get().iterable() {
Data::new(List(i.map(|v| Arc::new(RwLock::new(v))).collect()))
Ok(Data::new(List(i.map(|v| Ok::<_, CheckError>(Arc::new(RwLock::new(v?)))).collect::<Result<_, _>>()?)))
} else {
unreachable!("as_list called on non-iterable")
Err("as_list called on non-iterable".into())
}
}),
inner_statements: None,
@ -262,12 +263,12 @@ impl MersData for List {
false
}
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Result<Data, CheckError>>>> {
Some(Box::new(
self.0
.clone()
.into_iter()
.map(|v| v.read().unwrap().clone()),
.map(|v| Ok(v.read().unwrap().clone())),
))
}
fn clone(&self) -> Box<dyn MersData> {

View File

@ -72,11 +72,11 @@ impl Config {
}
}),
run: Arc::new(|a, _i| {
if let Ok(n) = a.get().as_any().downcast_ref::<data::string::String>().unwrap().0.parse() {
Ok(if let Ok(n) = a.get().as_any().downcast_ref::<data::string::String>().unwrap().0.parse() {
Data::one_tuple(Data::new(data::float::Float(n)))
} else {
Data::empty_tuple()
}
})
}),
inner_statements: None,
})).add_var("parse_int".to_string(), Data::new(data::function::Function {
@ -95,11 +95,11 @@ impl Config {
}
}),
run: Arc::new(|a, _i| {
if let Ok(n) = a.get().as_any().downcast_ref::<data::string::String>().unwrap().0.parse() {
Ok(if let Ok(n) = a.get().as_any().downcast_ref::<data::string::String>().unwrap().0.parse() {
Data::one_tuple(Data::new(data::int::Int(n)))
} else {
Data::empty_tuple()
}
})
}),
inner_statements: None,
})).add_var("signum".to_string(), Data::new(data::function::Function {
@ -113,7 +113,7 @@ impl Config {
}
}),
run: Arc::new(|a, _i| {
Data::new(data::int::Int(if let Some(n) = a.get().as_any().downcast_ref::<data::int::Int>() {
Ok(Data::new(data::int::Int(if let Some(n) = a.get().as_any().downcast_ref::<data::int::Int>() {
n.0.signum()
} else
if let Some(n) = a.get().as_any().downcast_ref::<data::float::Float>() {
@ -123,7 +123,7 @@ impl Config {
-1
} else { 0
}
} else { unreachable!("called signum on non-number type")}))
} else { unreachable!("called signum on non-number type")})))
}),
inner_statements: None,
})) .add_var("div".to_string(), Data::new(data::function::Function {
@ -137,10 +137,10 @@ impl Config {
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)),
(Some(data::int::Int(l)), None, Some(data::int::Int(r)), None) => Ok(Data::new(data::int::Int(l / r))),
(Some(data::int::Int(l)), None, None, Some(data::float::Float(r))) => Ok(Data::new(data::float::Float(*l as f64 / r))),
(None, Some(data::float::Float(l)), Some(data::int::Int(r)), None) => Ok(Data::new(data::float::Float(l / *r as f64))),
(None, Some(data::float::Float(l)), None, Some(data::float::Float(r))) => Ok(Data::new(data::float::Float(l / r))),
_ => unreachable!(),
}
} else { unreachable!() }),
@ -156,10 +156,10 @@ impl Config {
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)),
(Some(data::int::Int(l)), None, Some(data::int::Int(r)), None) => Ok(Data::new(data::int::Int(l % r))),
(Some(data::int::Int(l)), None, None, Some(data::float::Float(r))) => Ok(Data::new(data::float::Float(*l as f64 % r))),
(None, Some(data::float::Float(l)), Some(data::int::Int(r)), None) => Ok(Data::new(data::float::Float(l % *r as f64))),
(None, Some(data::float::Float(l)), None, Some(data::float::Float(r))) => Ok(Data::new(data::float::Float(l % r))),
_ => unreachable!(),
}
} else { unreachable!() }),
@ -206,20 +206,22 @@ impl Config {
let mut sumf = 0.0;
let mut usef = false;
for val in i {
if let Some(i) = val.get().as_any().downcast_ref::<data::int::Int>() {
let val = val?;
let o = if let Some(i) = val.get().as_any().downcast_ref::<data::int::Int>() {
sumi += i.0;
} else if let Some(i) =
val.get().as_any().downcast_ref::<data::float::Float>()
{
sumf += i.0;
usef = true;
};
o
}
}
if usef {
Ok(if usef {
Data::new(data::float::Float(sumi as f64 + sumf))
} else {
Data::new(data::int::Int(sumi))
}
})
} else {
unreachable!("sum called on non-tuple")
}
@ -269,6 +271,7 @@ impl Config {
let mut sumf = 0.0;
let mut usef = false;
for val in i {
let val = val?;
if let Some(i) = val.get().as_any().downcast_ref::<data::int::Int>() {
if first {
sumi = i.0;
@ -289,11 +292,11 @@ impl Config {
first = false;
}
}
if usef {
Ok(if usef {
Data::new(data::float::Float(sumi as f64 + sumf))
} else {
Data::new(data::int::Int(sumi))
}
})
} else {
unreachable!("sum called on non-tuple")
}
@ -342,20 +345,22 @@ impl Config {
let mut prodf = 1.0;
let mut usef = false;
for val in i {
if let Some(i) = val.get().as_any().downcast_ref::<data::int::Int>() {
let val = val?;
let o = if let Some(i) = val.get().as_any().downcast_ref::<data::int::Int>() {
prodi *= i.0;
} else if let Some(i) =
val.get().as_any().downcast_ref::<data::float::Float>()
{
prodf *= i.0;
usef = true;
};
o
}
}
if usef {
Ok(if usef {
Data::new(data::float::Float(prodi as f64 * prodf))
} else {
Data::new(data::int::Int(prodi))
}
})
} else {
unreachable!("product called on non-tuple")
}
@ -424,6 +429,7 @@ fn ltgtoe_function(
run: Arc::new(move |a, _i| {
let mut prev = IntOrFloatOrNothing::Nothing;
for item in a.get().iterable().unwrap() {
let item = item?;
let item = item.get();
let new = if let Some(data::int::Int(v)) = item.as_any().downcast_ref() {
IntOrFloatOrNothing::Int(*v)
@ -435,10 +441,10 @@ fn ltgtoe_function(
if op(prev, new) {
prev = new;
} else {
return Data::new(data::bool::Bool(false));
return Ok(Data::new(data::bool::Bool(false)));
}
}
Data::new(data::bool::Bool(true))
Ok(Data::new(data::bool::Bool(true)))
}),
inner_statements: None,
}

View File

@ -53,9 +53,9 @@ impl Config {
.downcast_ref::<data::function::Function>()
.cloned()
{
Data::new(Thread(Arc::new(Mutex::new(Ok(std::thread::spawn(
Ok(Data::new(Thread(Arc::new(Mutex::new(Ok(std::thread::spawn(
move || f.run(Data::empty_tuple()),
))))))
)))))))
} else {
unreachable!("thread called, but arg wasn't a function");
}
@ -77,10 +77,10 @@ impl Config {
run: Arc::new(|a, _i| {
let a = a.get();
let t = a.as_any().downcast_ref::<Thread>().unwrap().0.lock().unwrap();
Data::new(data::bool::Bool(match &*t {
Ok(Data::new(data::bool::Bool(match &*t {
Ok(t) => t.is_finished(),
Err(_d) => true,
}))
})))
}),
inner_statements: None,
}))
@ -101,7 +101,7 @@ impl Config {
run: Arc::new(|a, _i| {
let a = a.get();
let mut t = a.as_any().downcast_ref::<Thread>().unwrap().0.lock().unwrap();
let d = match std::mem::replace(&mut *t, Err(Data::empty_tuple())) {
let d = match std::mem::replace(&mut *t, Err(Err(CheckError::new()))) {
Ok(t) => t.join().unwrap(),
Err(d) => d,
};
@ -114,7 +114,9 @@ impl Config {
}
#[derive(Clone)]
pub struct Thread(pub Arc<Mutex<Result<JoinHandle<Data>, Data>>>);
pub struct Thread(
pub Arc<Mutex<Result<JoinHandle<Result<Data, CheckError>>, Result<Data, CheckError>>>>,
);
#[derive(Debug, Clone)]
pub struct ThreadT(pub Type);

View File

@ -41,11 +41,11 @@ impl Config {
}
}),
run: Arc::new(|_a, _i| {
if let Some(Ok(line)) = std::io::stdin().lines().next() {
Ok(if let Some(Ok(line)) = std::io::stdin().lines().next() {
Data::one_tuple(Data::new(data::string::String(line)))
} else {
Data::empty_tuple()
}
})
}),
inner_statements: None,
}),
@ -60,7 +60,7 @@ impl Config {
let a2 = a.get();
eprintln!("{} :: {}", a2.as_type(), a2);
drop(a2);
a
Ok(a)
}),
inner_statements: None,
}),
@ -74,7 +74,7 @@ impl Config {
run: Arc::new(|a, _i| {
eprint!("{}", a.get());
_ = std::io::stderr().lock().flush();
Data::empty_tuple()
Ok(Data::empty_tuple())
}),
inner_statements: None,
}),
@ -87,7 +87,7 @@ impl Config {
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
run: Arc::new(|a, _i| {
eprintln!("{}", a.get());
Data::empty_tuple()
Ok(Data::empty_tuple())
}),
inner_statements: None,
}),
@ -101,7 +101,7 @@ impl Config {
run: Arc::new(|a, _i| {
print!("{}", a.get());
_ = std::io::stdout().lock().flush();
Data::empty_tuple()
Ok(Data::empty_tuple())
}),
inner_statements: None,
}),
@ -114,7 +114,7 @@ impl Config {
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
run: Arc::new(|a, _i| {
println!("{}", a.get());
Data::empty_tuple()
Ok(Data::empty_tuple())
}),
inner_statements: None,
}),

View File

@ -25,17 +25,17 @@ impl Config {
.add_var("ends_with".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_bool(|v, p| v.ends_with(p))))
.add_var("str_split_once".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_opt_string_string(|v, p| v.split_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())))))
.add_var("str_split_once_rev".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_opt_string_string(|v, p| v.rsplit_once(p).map(|(a, b)| (a.to_owned(), b.to_owned())))))
.add_var("str_split".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_any(Type::new(super::with_list::ListT(Type::new(data::string::StringT))), |v, p| Data::new(super::with_list::List(v.split(p).map(|v| Arc::new(RwLock::new(Data::new(data::string::String(v.to_owned()))))).collect())))))
.add_var("str_split".to_string(), Data::new(util::to_mers_func_concrete_string_string_to_any(Type::new(super::with_list::ListT(Type::new(data::string::StringT))), |v, p| Ok(Data::new(super::with_list::List(v.split(p).map(|v| Arc::new(RwLock::new(Data::new(data::string::String(v.to_owned()))))).collect()))))))
.add_var("concat".to_string(), Data::new(util::to_mers_func(
|a| if a.iterable().is_some() {
Ok(Type::new(data::string::StringT))
} else {
Err(format!("concat called on non-iterable type {a}").into())
},
|a| Data::new(data::string::String(a.get().iterable().unwrap().map(|v| v.get().to_string()).collect()))),
|a| Ok(Data::new(data::string::String(a.get().iterable().unwrap().map(|v| v.map(|v| v.get().to_string())).collect::<Result<_, _>>()?)))),
))
.add_var("to_string".to_string(), Data::new(util::to_mers_func(|_a| Ok(Type::new(data::string::StringT)),
|a| Data::new(data::string::String(a.get().to_string()))
|a| Ok(Data::new(data::string::String(a.get().to_string())))
)))
.add_var("substring".to_string(), Data::new(util::to_mers_func(
|a| {
@ -79,9 +79,9 @@ impl Config {
.unwrap_or(usize::MAX);
let end = end.min(s.len());
if end < start {
return Data::new(data::string::String(String::new()));
return Ok(Data::new(data::string::String(String::new())));
}
Data::new(data::string::String(s[start..end].to_owned()))
Ok(Data::new(data::string::String(s[start..end].to_owned())))
})
))
}

View File

@ -43,7 +43,7 @@ impl MersStatement for Function {
Ok(run2.check(i, None)?)
}),
run: Arc::new(move |arg, info| {
data::defs::assign(&arg, &arg_target.run(info));
data::defs::assign(&arg, &arg_target.run(info)?);
run.run(info)
}),
inner_statements: Some((arg3, run3)),

View File

@ -66,7 +66,7 @@ impl MersStatement for AsType {
return_type
})
}
fn run_custom(&self, info: &mut super::Info) -> Data {
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
self.statement.run(info)
}
fn has_scope(&self) -> bool {

View File

@ -77,11 +77,11 @@ impl MersStatement for AssignTo {
}
Ok(Type::empty_tuple())
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
let source = self.source.run(info);
let target = self.target.run(info);
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
let source = self.source.run(info)?;
let target = self.target.run(info)?;
data::defs::assign(&source, &target);
Data::empty_tuple()
Ok(Data::empty_tuple())
}
fn has_scope(&self) -> bool {
false

View File

@ -1,5 +1,5 @@
use crate::{
data::Type,
data::{self, Data, Type},
errors::{CheckError, SourceRange},
};
@ -25,12 +25,12 @@ impl MersStatement for Block {
}
Ok(o)
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
self.statements
.iter()
.map(|s| s.run(info))
.last()
.unwrap_or_else(|| crate::data::Data::new(crate::data::tuple::Tuple(vec![])))
.unwrap_or_else(|| Ok(Data::new(data::tuple::Tuple(vec![]))))
}
fn has_scope(&self) -> bool {
true

View File

@ -88,12 +88,42 @@ impl MersStatement for Chain {
}
Ok(o)
}
fn run_custom(&self, info: &mut super::Info) -> Data {
let f = self.first.run(info);
let c = self.chained.run(info);
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
let f = self.first.run(info)?;
let c = self.chained.run(info)?;
let c = c.get();
if let Some(func) = c.as_any().downcast_ref::<crate::data::function::Function>() {
func.run(f)
match func.run(f) {
Ok(v) => Ok(v),
Err(e) => Err(if let Some(_) = &self.as_part_of_include {
CheckError::new()
.src(vec![(
self.pos_in_src.clone(),
Some(error_colors::HashIncludeErrorInIncludedFile),
)])
.msg(
"Error in #include:"
.color(error_colors::HashIncludeErrorInIncludedFile)
.to_string(),
)
.err_with_diff_src(e)
} else {
CheckError::new()
.src(vec![
(self.pos_in_src.clone(), None),
(
self.first.source_range(),
Some(error_colors::FunctionArgument),
),
(self.chained.source_range(), Some(error_colors::Function)),
])
.msg(format!(
"Error in {}:",
"this function".color(error_colors::Function)
))
.err(e)
}),
}
} else {
todo!("err: not a function");
}

View File

@ -56,8 +56,8 @@ impl MersStatement for CustomType {
}
Ok(Type::empty_tuple())
}
fn run_custom(&self, _info: &mut Info) -> Data {
Data::empty_tuple()
fn run_custom(&self, _info: &mut Info) -> Result<Data, CheckError> {
Ok(Data::empty_tuple())
}
fn has_scope(&self) -> bool {
false

View File

@ -25,8 +25,10 @@ impl MersStatement for Function {
self.func_no_info.with_info_check(info.clone());
Ok(self.func_no_info.as_type())
}
fn run_custom(&self, info: &mut super::Info) -> Data {
Data::new(self.func_no_info.with_info_run(Arc::new(info.clone())))
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
Ok(Data::new(
self.func_no_info.with_info_run(Arc::new(info.clone())),
))
}
fn has_scope(&self) -> bool {
true

View File

@ -52,20 +52,22 @@ impl MersStatement for If {
}
Ok(t)
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
Ok(
if let Some(data::bool::Bool(true)) = self
.condition
.run(info)
.run(info)?
.get()
.as_any()
.downcast_ref::<data::bool::Bool>()
{
self.on_true.run(info)
self.on_true.run(info)?
} else if let Some(on_false) = &self.on_false {
on_false.run(info)
on_false.run(info)?
} else {
Data::empty_tuple()
}
},
)
}
fn has_scope(&self) -> bool {
true

View File

@ -47,10 +47,10 @@ impl MersStatement for Loop {
}
Ok(t)
}
fn run_custom(&self, info: &mut Info) -> Data {
fn run_custom(&self, info: &mut Info) -> Result<Data, CheckError> {
loop {
if let Some(v) = self.inner.run(info).one_tuple_content() {
return v;
if let Some(v) = self.inner.run(info)?.one_tuple_content() {
return Ok(v);
}
}
}

View File

@ -43,7 +43,7 @@ pub trait MersStatement: Debug + Send + Sync {
info: &mut CheckInfo,
init_to: Option<&Type>,
) -> Result<Type, CheckError>;
fn run_custom(&self, info: &mut Info) -> Data;
fn run_custom(&self, info: &mut Info) -> Result<Data, CheckError>;
/// if true, local variables etc. will be contained inside their own scope.
fn has_scope(&self) -> bool;
fn check(&self, info: &mut CheckInfo, init_to: Option<&Type>) -> Result<Type, CheckError> {
@ -93,7 +93,7 @@ pub trait MersStatement: Debug + Send + Sync {
info.global.depth -= 1;
o
}
fn run(&self, info: &mut Info) -> Data {
fn run(&self, info: &mut Info) -> Result<Data, CheckError> {
if self.has_scope() {
info.create_scope();
}

View File

@ -119,13 +119,13 @@ impl MersStatement for Object {
.collect::<Result<_, _>>()?,
)))
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
Data::new(data::object::Object(
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
Ok(Data::new(data::object::Object(
self.elems
.iter()
.map(|(n, s)| (n.clone(), s.run(info)))
.collect(),
))
.map(|(n, s)| Ok::<_, CheckError>((n.clone(), s.run(info)?)))
.collect::<Result<_, _>>()?,
)))
}
fn has_scope(&self) -> bool {
false

View File

@ -103,8 +103,8 @@ impl MersStatement for Try {
}
Ok(t)
}
fn run_custom(&self, info: &mut Info) -> Data {
let arg = self.arg.run(info);
fn run_custom(&self, info: &mut Info) -> Result<Data, CheckError> {
let arg = self.arg.run(info)?;
let ar = arg.get();
let a = ar.as_ref();
let arg_type = a.as_type();
@ -112,14 +112,16 @@ impl MersStatement for Try {
.funcs
.iter()
.map(|v| {
v.run(info)
Ok::<_, CheckError>(
v.run(info)?
.get()
.as_any()
.downcast_ref::<data::function::Function>()
.unwrap()
.clone()
.clone(),
)
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>, _>>()?;
let mut found = None;
for (i, func) in functions.iter().enumerate() {
match func.get_as_type().o(&arg_type) {

View File

@ -4,7 +4,7 @@ use colored::Colorize;
use crate::{
data::{self, tuple::TupleT, Data, Type},
errors::{error_colors, SourceRange},
errors::{error_colors, CheckError, SourceRange},
};
use super::MersStatement;
@ -82,10 +82,13 @@ impl MersStatement for Tuple {
.collect::<Result<_, _>>()?,
)))
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
Data::new(data::tuple::Tuple(
self.elems.iter().map(|s| s.run(info)).collect(),
))
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
Ok(Data::new(data::tuple::Tuple(
self.elems
.iter()
.map(|s| Ok(s.run(info)?))
.collect::<Result<_, CheckError>>()?,
)))
}
fn has_scope(&self) -> bool {
false

View File

@ -1,6 +1,6 @@
use crate::{
data::{Data, Type},
errors::SourceRange,
errors::{CheckError, SourceRange},
};
use super::{CheckInfo, MersStatement};
@ -25,8 +25,8 @@ impl MersStatement for Value {
}
Ok(self.val.get().as_type())
}
fn run_custom(&self, _info: &mut super::Info) -> Data {
self.val.clone()
fn run_custom(&self, _info: &mut super::Info) -> Result<Data, CheckError> {
Ok(self.val.clone())
}
fn source_range(&self) -> SourceRange {
self.pos_in_src.clone()

View File

@ -2,7 +2,7 @@ use std::sync::{Arc, RwLock};
use crate::{
data::{self, Data, Type},
errors::SourceRange,
errors::{CheckError, SourceRange},
};
use super::MersStatement;
@ -50,7 +50,7 @@ impl MersStatement for Variable {
};
Ok(val)
}
fn run_custom(&self, info: &mut super::Info) -> Data {
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {
if self.is_init {
if self.is_ref_not_ignore {
let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
@ -60,12 +60,12 @@ impl MersStatement for Variable {
info.scopes[self.var.0].vars[self.var.1] = nothing;
} else {
// (reference to) data which will never be referenced again
return Data::new(data::reference::Reference(Arc::new(RwLock::new(
Data::empty_tuple(),
return Ok(Data::new(data::reference::Reference(Arc::new(
RwLock::new(Data::empty_tuple()),
))));
}
}
if self.is_ref_not_ignore {
Ok(if self.is_ref_not_ignore {
let v = &info.scopes[self.var.0].vars[self.var.1];
Data::new(data::reference::Reference(Arc::clone(v)))
} else {
@ -73,7 +73,7 @@ impl MersStatement for Variable {
.write()
.unwrap()
.clone()
}
})
}
fn source_range(&self) -> SourceRange {
self.pos_in_src.clone()