mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
V7: Make .try
a language feature, this makes try_allow_unused unnecessary. remove try and try_... functions.
This commit is contained in:
parent
86b6a46d09
commit
8690263b1c
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mers"
|
name = "mers"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "dynamically typed but type-checked programming language"
|
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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mers_lib = "0.6.0"
|
mers_lib = "0.7.0"
|
||||||
# mers_lib = { path = "../mers_lib" }
|
# mers_lib = { path = "../mers_lib" }
|
||||||
clap = { version = "4.3.19", features = ["derive"] }
|
clap = { version = "4.3.19", features = ["derive"] }
|
||||||
colored = "2.1.0"
|
colored = "2.1.0"
|
||||||
|
@ -84,13 +84,13 @@ fn main() {
|
|||||||
exit(20);
|
exit(20);
|
||||||
}
|
}
|
||||||
Ok(parsed) => {
|
Ok(parsed) => {
|
||||||
let (mut i1, _, mut i3) = config.infos();
|
let (i1, _, i3) = config.infos();
|
||||||
match parsed.compile(&mut i1, CompInfo::default()) {
|
match compile(&*parsed, i1) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
exit(24);
|
exit(24);
|
||||||
}
|
}
|
||||||
Ok(compiled) => match compiled.check(&mut i3, None) {
|
Ok(compiled) => match check(&*compiled, i3) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
exit(28);
|
exit(28);
|
||||||
@ -110,13 +110,13 @@ fn main() {
|
|||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
Ok(parsed) => {
|
Ok(parsed) => {
|
||||||
let (mut i1, mut i2, mut i3) = config.infos();
|
let (i1, mut i2, i3) = config.infos();
|
||||||
match parsed.compile(&mut i1, CompInfo::default()) {
|
match compile(&*parsed, i1) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
Ok(compiled) => match compiled.check(&mut i3, None) {
|
Ok(compiled) => match check(&*compiled, i3) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
exit(255);
|
exit(255);
|
||||||
@ -138,8 +138,8 @@ fn main() {
|
|||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
Ok(parsed) => {
|
Ok(parsed) => {
|
||||||
let (mut i1, mut i2, _) = config.infos();
|
let (i1, mut i2, _) = config.infos();
|
||||||
match parsed.compile(&mut i1, CompInfo::default()) {
|
match compile(&*parsed, i1) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
exit(255);
|
exit(255);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mers_lib"
|
name = "mers_lib"
|
||||||
version = "0.6.1"
|
version = "0.7.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "library to use the mers language in other projects"
|
description = "library to use the mers language in other projects"
|
||||||
|
@ -18,8 +18,8 @@ pub struct Function {
|
|||||||
pub out: Arc<dyn Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
|
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) -> Data + Send + Sync>,
|
||||||
pub inner_statements: Option<(
|
pub inner_statements: Option<(
|
||||||
Arc<Box<dyn crate::prelude_compile::RunMersStatement>>,
|
Arc<Box<dyn crate::program::run::MersStatement>>,
|
||||||
Arc<Box<dyn crate::prelude_compile::RunMersStatement>>,
|
Arc<Box<dyn crate::program::run::MersStatement>>,
|
||||||
)>,
|
)>,
|
||||||
}
|
}
|
||||||
impl Function {
|
impl Function {
|
||||||
|
@ -81,6 +81,12 @@ pub mod error_colors {
|
|||||||
pub const BadCharInFunctionType: Color = Color::Red;
|
pub const BadCharInFunctionType: Color = Color::Red;
|
||||||
pub const BadTypeFromParsed: Color = Color::Blue;
|
pub const BadTypeFromParsed: Color = Color::Blue;
|
||||||
pub const TypeAnnotationNoClosingBracket: Color = Color::Blue;
|
pub const TypeAnnotationNoClosingBracket: Color = Color::Blue;
|
||||||
|
|
||||||
|
pub const TryBadSyntax: Color = Color::Red;
|
||||||
|
pub const TryNoFunctionFound: Color = Color::Red;
|
||||||
|
pub const TryNotAFunction: Color = Color::Red;
|
||||||
|
pub const TryUnusedFunction1: Color = Color::Red;
|
||||||
|
pub const TryUnusedFunction2: Color = Color::BrightRed;
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum CheckErrorComponent {
|
pub enum CheckErrorComponent {
|
||||||
@ -125,6 +131,7 @@ impl Display for CheckErrorDisplay<'_> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
impl CheckError {
|
impl CheckError {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
CheckError(vec![])
|
CheckError(vec![])
|
||||||
@ -133,18 +140,34 @@ impl CheckError {
|
|||||||
self.0.push(v);
|
self.0.push(v);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
fn add_mut(&mut self, v: CheckErrorComponent) -> &mut Self {
|
||||||
|
self.0.push(v);
|
||||||
|
self
|
||||||
|
}
|
||||||
pub(crate) fn msg(self, s: String) -> Self {
|
pub(crate) fn msg(self, s: String) -> Self {
|
||||||
self.add(CheckErrorComponent::Message(s))
|
self.add(CheckErrorComponent::Message(s))
|
||||||
}
|
}
|
||||||
|
pub(crate) fn msg_mut(&mut self, s: String) -> &mut Self {
|
||||||
|
self.add_mut(CheckErrorComponent::Message(s))
|
||||||
|
}
|
||||||
pub(crate) fn err(self, e: Self) -> Self {
|
pub(crate) fn err(self, e: Self) -> Self {
|
||||||
self.add(CheckErrorComponent::Error(e))
|
self.add(CheckErrorComponent::Error(e))
|
||||||
}
|
}
|
||||||
|
pub(crate) fn err_mut(&mut self, e: Self) -> &mut Self {
|
||||||
|
self.add_mut(CheckErrorComponent::Error(e))
|
||||||
|
}
|
||||||
pub(crate) fn err_with_diff_src(self, e: CheckError) -> Self {
|
pub(crate) fn err_with_diff_src(self, e: CheckError) -> Self {
|
||||||
self.add(CheckErrorComponent::ErrorWithDifferentSource(e))
|
self.add(CheckErrorComponent::ErrorWithDifferentSource(e))
|
||||||
}
|
}
|
||||||
|
pub(crate) fn err_with_diff_src_mut(&mut self, e: CheckError) -> &mut Self {
|
||||||
|
self.add_mut(CheckErrorComponent::ErrorWithDifferentSource(e))
|
||||||
|
}
|
||||||
pub(crate) fn src(self, s: Vec<(SourceRange, Option<colored::Color>)>) -> Self {
|
pub(crate) fn src(self, s: Vec<(SourceRange, Option<colored::Color>)>) -> Self {
|
||||||
self.add(CheckErrorComponent::Source(s))
|
self.add(CheckErrorComponent::Source(s))
|
||||||
}
|
}
|
||||||
|
pub(crate) fn src_mut(&mut self, s: Vec<(SourceRange, Option<colored::Color>)>) -> &mut Self {
|
||||||
|
self.add_mut(CheckErrorComponent::Source(s))
|
||||||
|
}
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub fn display<'a>(&'a self) -> CheckErrorDisplay<'a> {
|
pub fn display<'a>(&'a self) -> CheckErrorDisplay<'a> {
|
||||||
CheckErrorDisplay {
|
CheckErrorDisplay {
|
||||||
|
@ -3,7 +3,7 @@ use std::fmt::Debug;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Info<L: Local> {
|
pub struct Info<L: Local> {
|
||||||
pub scopes: Vec<L>,
|
pub scopes: Vec<L>,
|
||||||
pub global: L::Global,
|
pub(crate) global: L::Global,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Local> Info<L> {
|
impl<L: Local> Info<L> {
|
||||||
|
@ -11,11 +11,12 @@ pub mod program;
|
|||||||
|
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub mod prelude_compile {
|
pub mod prelude_compile {
|
||||||
|
pub use crate::parsing::check;
|
||||||
|
pub use crate::parsing::compile;
|
||||||
pub use crate::parsing::parse;
|
pub use crate::parsing::parse;
|
||||||
pub use crate::parsing::Source;
|
pub use crate::parsing::Source;
|
||||||
pub use crate::program::configs::Config;
|
pub use crate::program::configs::Config;
|
||||||
pub use crate::program::parsed::{CompInfo, MersStatement as ParsedMersStatement};
|
pub use crate::program::parsed::CompInfo;
|
||||||
pub use crate::program::run::MersStatement as RunMersStatement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// can be used to extend the mers config.
|
/// can be used to extend the mers config.
|
||||||
|
@ -3,8 +3,12 @@ use std::{fmt::Debug, path::PathBuf, sync::Arc};
|
|||||||
use line_span::{LineSpan, LineSpanExt};
|
use line_span::{LineSpan, LineSpanExt};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{CheckError, SourcePos},
|
data::Type,
|
||||||
program::{self, parsed::block::Block},
|
errors::{error_colors, CheckError, SourcePos},
|
||||||
|
program::{
|
||||||
|
self,
|
||||||
|
parsed::{block::Block, CompInfo},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod statements;
|
pub mod statements;
|
||||||
@ -22,6 +26,70 @@ pub fn parse(
|
|||||||
};
|
};
|
||||||
Ok(Box::new(block))
|
Ok(Box::new(block))
|
||||||
}
|
}
|
||||||
|
pub fn compile(
|
||||||
|
statement: &(impl program::parsed::MersStatement + ?Sized),
|
||||||
|
mut info: crate::program::parsed::Info,
|
||||||
|
) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
|
||||||
|
statement.compile(&mut info, CompInfo::default())
|
||||||
|
}
|
||||||
|
pub fn check(
|
||||||
|
statement: &(impl program::run::MersStatement + ?Sized),
|
||||||
|
mut info: crate::program::run::CheckInfo,
|
||||||
|
) -> Result<Type, CheckError> {
|
||||||
|
let o = statement.check(&mut info, None)?;
|
||||||
|
let mut err = None;
|
||||||
|
for (try_stmt, used) in info.global.unused_try_statements.lock().unwrap().iter() {
|
||||||
|
if used.iter().any(|v| v.is_some()) {
|
||||||
|
let err = err.get_or_insert_with(|| {
|
||||||
|
CheckError::new().msg(format!(
|
||||||
|
"There are `.try` statements with unused functions!"
|
||||||
|
))
|
||||||
|
});
|
||||||
|
let unused = used
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|v| Some((v.0, v.1.clone()?)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
err.msg_mut(format!(
|
||||||
|
"Here, {}function{} {} {} unused:",
|
||||||
|
if unused.len() == 1 { "the " } else { "" },
|
||||||
|
if unused.len() == 1 { "" } else { "s" },
|
||||||
|
unused
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.fold(String::new(), |mut a, (i, (v, _))| {
|
||||||
|
if i > 0 {
|
||||||
|
a.push_str(", ");
|
||||||
|
if i == unused.len() - 1 {
|
||||||
|
a.push_str("and ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.push_str(&format!("#{}", v + 1));
|
||||||
|
a
|
||||||
|
}),
|
||||||
|
if unused.len() == 1 { "is" } else { "are" },
|
||||||
|
))
|
||||||
|
.src_mut({
|
||||||
|
let mut src = vec![(try_stmt.clone(), None)];
|
||||||
|
for (i, (_, src_range)) in unused.into_iter().enumerate() {
|
||||||
|
src.push((
|
||||||
|
src_range,
|
||||||
|
Some(if i % 2 == 0 {
|
||||||
|
error_colors::TryUnusedFunction1
|
||||||
|
} else {
|
||||||
|
error_colors::TryUnusedFunction2
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
src
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(err) = err {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
Ok(o)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Source {
|
pub struct Source {
|
||||||
src_from: SourceFrom,
|
src_from: SourceFrom,
|
||||||
|
@ -168,30 +168,52 @@ pub fn parse(
|
|||||||
let dot_in_src = src.get_pos();
|
let dot_in_src = src.get_pos();
|
||||||
if let Some('.') = src.peek_char() {
|
if let Some('.') = src.peek_char() {
|
||||||
src.next_char();
|
src.next_char();
|
||||||
let chained = match parse_no_chain(src, srca) {
|
src.skip_whitespace();
|
||||||
Ok(Some(v)) => v,
|
if src.peek_word() == "try" {
|
||||||
Ok(None) => {
|
src.next_word();
|
||||||
|
src.skip_whitespace();
|
||||||
|
if let Some('(') = src.next_char() {
|
||||||
|
let funcs = parse_tuple_without_open(src, srca)?;
|
||||||
|
first = Box::new(program::parsed::r#try::Try {
|
||||||
|
pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(),
|
||||||
|
arg: first,
|
||||||
|
funcs,
|
||||||
|
});
|
||||||
|
pos_after_first = src.get_pos();
|
||||||
|
} else {
|
||||||
return Err(CheckError::new()
|
return Err(CheckError::new()
|
||||||
.src(vec![((dot_in_src, src.get_pos(), srca).into(), None)])
|
.msg(format!("Expected `(` after `.try`"))
|
||||||
.msg(format!("EOF after `.`")))
|
.src(vec![(
|
||||||
|
(dot_in_src, src.get_pos(), srca).into(),
|
||||||
|
Some(error_colors::TryBadSyntax),
|
||||||
|
)]));
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
} else {
|
||||||
};
|
let chained = match parse_no_chain(src, srca) {
|
||||||
// allow a.f(b, c) syntax (but not f(a, b, c))
|
Ok(Some(v)) => v,
|
||||||
if let Some('(') = src.peek_char() {
|
Ok(None) => {
|
||||||
src.next_char();
|
return Err(CheckError::new()
|
||||||
let elems = parse_multiple(src, srca, ")")?;
|
.src(vec![((dot_in_src, src.get_pos(), srca).into(), None)])
|
||||||
first = Box::new(program::parsed::tuple::Tuple {
|
.msg(format!("EOF after `.`")))
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
|
// allow a.f(b, c) syntax (but not f(a, b, c))
|
||||||
|
if let Some('(') = src.peek_char() {
|
||||||
|
src.next_char();
|
||||||
|
let elems = parse_multiple(src, srca, ")")?;
|
||||||
|
first = Box::new(program::parsed::tuple::Tuple {
|
||||||
|
pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(),
|
||||||
|
elems: [first].into_iter().chain(elems).collect(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
first = Box::new(program::parsed::chain::Chain {
|
||||||
pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(),
|
pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(),
|
||||||
elems: [first].into_iter().chain(elems).collect(),
|
first,
|
||||||
|
chained,
|
||||||
});
|
});
|
||||||
|
pos_after_first = src.get_pos();
|
||||||
}
|
}
|
||||||
first = Box::new(program::parsed::chain::Chain {
|
|
||||||
pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(),
|
|
||||||
first,
|
|
||||||
chained,
|
|
||||||
});
|
|
||||||
pos_after_first = src.get_pos();
|
|
||||||
} else {
|
} else {
|
||||||
src.set_pos(pos_after_first);
|
src.set_pos(pos_after_first);
|
||||||
break;
|
break;
|
||||||
@ -203,6 +225,12 @@ pub fn parse(
|
|||||||
}
|
}
|
||||||
Ok(Some(first))
|
Ok(Some(first))
|
||||||
}
|
}
|
||||||
|
pub fn parse_tuple_without_open(
|
||||||
|
src: &mut Source,
|
||||||
|
srca: &Arc<Source>,
|
||||||
|
) -> Result<Vec<Box<dyn MersStatement>>, CheckError> {
|
||||||
|
parse_multiple(src, srca, ")")
|
||||||
|
}
|
||||||
pub fn parse_multiple(
|
pub fn parse_multiple(
|
||||||
src: &mut Source,
|
src: &mut Source,
|
||||||
srca: &Arc<Source>,
|
srca: &Arc<Source>,
|
||||||
@ -374,7 +402,7 @@ pub fn parse_no_chain(
|
|||||||
Some('(') => {
|
Some('(') => {
|
||||||
let pos_in_src = src.get_pos();
|
let pos_in_src = src.get_pos();
|
||||||
src.next_char();
|
src.next_char();
|
||||||
let elems = parse_multiple(src, srca, ")")?;
|
let elems = parse_tuple_without_open(src, srca)?;
|
||||||
return Ok(Some(Box::new(program::parsed::tuple::Tuple {
|
return Ok(Some(Box::new(program::parsed::tuple::Tuple {
|
||||||
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
||||||
elems,
|
elems,
|
||||||
|
@ -22,8 +22,9 @@ impl Config {
|
|||||||
/// `panic: fn` exits the program with the given exit code
|
/// `panic: fn` exits the program with the given exit code
|
||||||
/// `lock_update: fn` locks the value of a reference so you can exclusively modify it: &var.lock_update(v -> (v, 1).sum)
|
/// `lock_update: fn` locks the value of a reference so you can exclusively modify it: &var.lock_update(v -> (v, 1).sum)
|
||||||
pub fn with_base(self) -> Self {
|
pub fn with_base(self) -> Self {
|
||||||
self.add_var("try".to_string(), get_try(false))
|
self
|
||||||
.add_var("try_allow_unused".to_string(), get_try(true))
|
// .add_var("try".to_string(), get_try(false))
|
||||||
|
// .add_var("try_allow_unused".to_string(), get_try(true))
|
||||||
.add_var("lock_update".to_string(), Data::new(data::function::Function {
|
.add_var("lock_update".to_string(), Data::new(data::function::Function {
|
||||||
info: Arc::new(Info::neverused()),
|
info: Arc::new(Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
@ -196,170 +197,170 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_try(allow_unused_functions: bool) -> Data {
|
// fn get_try(allow_unused_functions: bool) -> Data {
|
||||||
Data::new(data::function::Function {
|
// Data::new(data::function::Function {
|
||||||
info: Arc::new(Info::neverused()),
|
// info: Arc::new(Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
// info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Arc::new(move |a, _i| {
|
// out: Arc::new(move |a, _i| {
|
||||||
let mut out = Type::empty();
|
// let mut out = Type::empty();
|
||||||
for t in a.types.iter() {
|
// for t in a.types.iter() {
|
||||||
if let Some(outer_tuple) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
// if let Some(outer_tuple) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
if outer_tuple.0.len() != 2 {
|
// if outer_tuple.0.len() != 2 {
|
||||||
return Err(format!(
|
// return Err(format!(
|
||||||
"cannot use try with tuple argument where len != 2 (got len {})",
|
// "cannot use try with tuple argument where len != 2 (got len {})",
|
||||||
outer_tuple.0.len()
|
// outer_tuple.0.len()
|
||||||
)
|
// )
|
||||||
.into());
|
// .into());
|
||||||
}
|
// }
|
||||||
let arg_type = &outer_tuple.0[0];
|
// let arg_type = &outer_tuple.0[0];
|
||||||
let functions = &outer_tuple.0[1];
|
// let functions = &outer_tuple.0[1];
|
||||||
let mut used_functions_and_errors = vec![];
|
// let mut used_functions_and_errors = vec![];
|
||||||
for arg_type in arg_type.subtypes_type().types.iter() {
|
// for arg_type in arg_type.subtypes_type().types.iter() {
|
||||||
let arg_type = Type::newm(vec![arg_type.clone()]);
|
// let arg_type = Type::newm(vec![arg_type.clone()]);
|
||||||
// possibilities for the tuple (f1, f2, f3, ..., fn)
|
// // possibilities for the tuple (f1, f2, f3, ..., fn)
|
||||||
for (fti, ft) in functions.types.iter().enumerate() {
|
// for (fti, ft) in functions.types.iter().enumerate() {
|
||||||
if used_functions_and_errors.len() <= fti {
|
// if used_functions_and_errors.len() <= fti {
|
||||||
used_functions_and_errors.push(vec![]);
|
// used_functions_and_errors.push(vec![]);
|
||||||
}
|
// }
|
||||||
let mut tuple_fallible = true;
|
// let mut tuple_fallible = true;
|
||||||
let mut tuple_possible = false;
|
// let mut tuple_possible = false;
|
||||||
if let Some(ft) = ft.as_any().downcast_ref::<data::tuple::TupleT>() {
|
// if let Some(ft) = ft.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||||
// f1, f2, f3, ..., fn
|
// // f1, f2, f3, ..., fn
|
||||||
let mut func_errors = vec![];
|
// let mut func_errors = vec![];
|
||||||
let mut skip_checks = false;
|
// let mut skip_checks = false;
|
||||||
for (fi, ft) in ft.0.iter().enumerate() {
|
// for (fi, ft) in ft.0.iter().enumerate() {
|
||||||
if used_functions_and_errors[fti].len() <= fi {
|
// if used_functions_and_errors[fti].len() <= fi {
|
||||||
used_functions_and_errors[fti].push(vec![]);
|
// used_functions_and_errors[fti].push(vec![]);
|
||||||
}
|
// }
|
||||||
let mut func_fallible = false;
|
// let mut func_fallible = false;
|
||||||
// possibilities for f_
|
// // possibilities for f_
|
||||||
for (fvi, ft) in ft.types.iter().enumerate() {
|
// for (fvi, ft) in ft.types.iter().enumerate() {
|
||||||
if let Some(ft) =
|
// if let Some(ft) =
|
||||||
ft.as_any().downcast_ref::<data::function::FunctionT>()
|
// ft.as_any().downcast_ref::<data::function::FunctionT>()
|
||||||
{
|
// {
|
||||||
if used_functions_and_errors[fti][fi].len() <= fvi {
|
// if used_functions_and_errors[fti][fi].len() <= fvi {
|
||||||
used_functions_and_errors[fti][fi]
|
// used_functions_and_errors[fti][fi]
|
||||||
.push(Some(vec![]));
|
// .push(Some(vec![]));
|
||||||
}
|
// }
|
||||||
if !skip_checks {
|
// if !skip_checks {
|
||||||
func_errors.push((
|
// func_errors.push((
|
||||||
fvi,
|
// fvi,
|
||||||
match ft.o(&arg_type) {
|
// match ft.o(&arg_type) {
|
||||||
Err(e) => {
|
// Err(e) => {
|
||||||
func_fallible = true;
|
// func_fallible = true;
|
||||||
if let Some(errs) =
|
// if let Some(errs) =
|
||||||
&mut used_functions_and_errors[fti]
|
// &mut used_functions_and_errors[fti]
|
||||||
[fi][fvi]
|
// [fi][fvi]
|
||||||
{
|
// {
|
||||||
errs.push(e.clone());
|
// errs.push(e.clone());
|
||||||
}
|
// }
|
||||||
Some(e)
|
// Some(e)
|
||||||
}
|
// }
|
||||||
Ok(o) => {
|
// Ok(o) => {
|
||||||
used_functions_and_errors[fti][fi]
|
// used_functions_and_errors[fti][fi]
|
||||||
[fvi] = None;
|
// [fvi] = None;
|
||||||
tuple_possible = true;
|
// tuple_possible = true;
|
||||||
for t in o.types {
|
// for t in o.types {
|
||||||
out.add(t);
|
// out.add(t);
|
||||||
}
|
// }
|
||||||
None
|
// None
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
return Err(format!(
|
// return Err(format!(
|
||||||
"try: arguments f1-fn must be functions"
|
// "try: arguments f1-fn must be functions"
|
||||||
)
|
// )
|
||||||
.into());
|
// .into());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// found a function that won't fail for this arg_type!
|
// // found a function that won't fail for this arg_type!
|
||||||
if !func_fallible {
|
// if !func_fallible {
|
||||||
tuple_fallible = false;
|
// tuple_fallible = false;
|
||||||
if tuple_possible {
|
// if tuple_possible {
|
||||||
skip_checks = true;
|
// skip_checks = true;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if tuple_fallible || !tuple_possible {
|
// if tuple_fallible || !tuple_possible {
|
||||||
// if the argument is {arg_type}, there is no infallible function. add a fallback function to handle this case!
|
// // if the argument is {arg_type}, there is no infallible function. add a fallback function to handle this case!
|
||||||
let mut e = CheckError::new()
|
// let mut e = CheckError::new()
|
||||||
.msg(format!("if the argument is {arg_type}, there is no infallible function."))
|
// .msg(format!("if the argument is {arg_type}, there is no infallible function."))
|
||||||
.msg(format!("Add a function to handle this case!"));
|
// .msg(format!("Add a function to handle this case!"));
|
||||||
for (i, err) in func_errors.into_iter() {
|
// for (i, err) in func_errors.into_iter() {
|
||||||
if let Some(err) = err {
|
// if let Some(err) = err {
|
||||||
e = e
|
// e = e
|
||||||
.msg(format!("Error for function #{}:", i + 1))
|
// .msg(format!("Error for function #{}:", i + 1))
|
||||||
.err(err);
|
// .err(err);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return Err(e);
|
// return Err(e);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
return Err(format!(
|
// return Err(format!(
|
||||||
"try: argument must be (arg, (f1, f2, f3, ..., fn))"
|
// "try: argument must be (arg, (f1, f2, f3, ..., fn))"
|
||||||
)
|
// )
|
||||||
.into());
|
// .into());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// check for unused functions
|
// // check for unused functions
|
||||||
if !allow_unused_functions {
|
// if !allow_unused_functions {
|
||||||
for (functions_posibility_index, functions_possibility) in
|
// for (functions_posibility_index, functions_possibility) in
|
||||||
used_functions_and_errors.into_iter().enumerate()
|
// used_functions_and_errors.into_iter().enumerate()
|
||||||
{
|
// {
|
||||||
for (func_index, func_possibilities) in
|
// for (func_index, func_possibilities) in
|
||||||
functions_possibility.into_iter().enumerate()
|
// functions_possibility.into_iter().enumerate()
|
||||||
{
|
// {
|
||||||
for (func_possibility_index, errors_if_unused) in
|
// for (func_possibility_index, errors_if_unused) in
|
||||||
func_possibilities.into_iter().enumerate()
|
// func_possibilities.into_iter().enumerate()
|
||||||
{
|
// {
|
||||||
if let Some(errs) = errors_if_unused {
|
// if let Some(errs) = errors_if_unused {
|
||||||
let mut e = CheckError::new().msg(format!("try: For the argument {t}:\nFunction #{}{} is never used. (use `try_allow_unused` to avoid this error){}",
|
// let mut e = CheckError::new().msg(format!("try: For the argument {t}:\nFunction #{}{} is never used. (use `try_allow_unused` to avoid this error){}",
|
||||||
func_index + 1,
|
// func_index + 1,
|
||||||
if functions_posibility_index != 0 || func_possibility_index != 0 {
|
// if functions_posibility_index != 0 || func_possibility_index != 0 {
|
||||||
format!(" (func-tuple possibility {}, function possibility {})", functions_posibility_index + 1, func_possibility_index + 1)
|
// format!(" (func-tuple possibility {}, function possibility {})", functions_posibility_index + 1, func_possibility_index + 1)
|
||||||
} else {
|
// } else {
|
||||||
format!("")
|
// format!("")
|
||||||
},
|
// },
|
||||||
if errs.is_empty() { "" } else { " Errors:" }));
|
// if errs.is_empty() { "" } else { " Errors:" }));
|
||||||
for err in errs {
|
// for err in errs {
|
||||||
e = e.err(err);
|
// e = e.err(err);
|
||||||
}
|
// }
|
||||||
return Err(e);
|
// return Err(e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
return Err(format!("cannot use try with non-tuple argument").into());
|
// return Err(format!("cannot use try with non-tuple argument").into());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
Ok(out)
|
// Ok(out)
|
||||||
}),
|
// }),
|
||||||
run: Arc::new(|a, _i| {
|
// run: Arc::new(|a, _i| {
|
||||||
let tuple = a.get();
|
// let tuple = a.get();
|
||||||
let tuple = tuple
|
// let tuple = tuple
|
||||||
.as_any()
|
// .as_any()
|
||||||
.downcast_ref::<data::tuple::Tuple>()
|
// .downcast_ref::<data::tuple::Tuple>()
|
||||||
.expect("try: not a tuple");
|
// .expect("try: not a tuple");
|
||||||
let arg = &tuple.0[0];
|
// let arg = &tuple.0[0];
|
||||||
let funcs = tuple.0[1].get();
|
// let funcs = tuple.0[1].get();
|
||||||
let funcs = funcs.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
|
// let funcs = funcs.as_any().downcast_ref::<data::tuple::Tuple>().unwrap();
|
||||||
for func in funcs.0.iter() {
|
// for func in funcs.0.iter() {
|
||||||
let func = func.get();
|
// let func = func.get();
|
||||||
let func = func
|
// let func = func
|
||||||
.as_any()
|
// .as_any()
|
||||||
.downcast_ref::<data::function::Function>()
|
// .downcast_ref::<data::function::Function>()
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
if func.check(&arg.get().as_type()).is_ok() {
|
// if func.check(&arg.get().as_type()).is_ok() {
|
||||||
return func.run(arg.clone());
|
// return func.run(arg.clone());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
unreachable!("try: no function found")
|
// unreachable!("try: no function found")
|
||||||
}),
|
// }),
|
||||||
inner_statements: None,
|
// inner_statements: None,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
@ -32,6 +32,8 @@ pub mod r#loop;
|
|||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub mod object;
|
pub mod object;
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
|
pub mod r#try;
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
pub mod tuple;
|
pub mod tuple;
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
@ -20,7 +20,7 @@ impl MersStatement for Loop {
|
|||||||
init_to: Option<&Type>,
|
init_to: Option<&Type>,
|
||||||
) -> Result<data::Type, CheckError> {
|
) -> Result<data::Type, CheckError> {
|
||||||
if init_to.is_some() {
|
if init_to.is_some() {
|
||||||
return Err("can't init to statement type If".to_string().into());
|
return Err("can't init to statement type Loop".to_string().into());
|
||||||
}
|
}
|
||||||
let mut t = Type::empty();
|
let mut t = Type::empty();
|
||||||
let inner_return_type = self.inner.check(info, None)?;
|
let inner_return_type = self.inner.check(info, None)?;
|
||||||
|
@ -29,6 +29,8 @@ pub mod r#loop;
|
|||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
pub mod object;
|
pub mod object;
|
||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
|
pub mod r#try;
|
||||||
|
#[cfg(feature = "run")]
|
||||||
pub mod tuple;
|
pub mod tuple;
|
||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
pub mod value;
|
pub mod value;
|
||||||
@ -140,6 +142,7 @@ pub struct CheckLocalGlobalInfo {
|
|||||||
)>,
|
)>,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
|
pub unused_try_statements: Arc<Mutex<Vec<(SourceRange, Vec<Option<SourceRange>>)>>>,
|
||||||
}
|
}
|
||||||
impl Debug for CheckLocal {
|
impl Debug for CheckLocal {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Loading…
Reference in New Issue
Block a user