mirror of
https://github.com/Dummi26/mers.git
synced 2025-12-16 03:57:50 +01:00
V7: Make .try a language feature, this makes try_allow_unused unnecessary. remove try and try_... functions.
This commit is contained in:
@@ -3,8 +3,12 @@ use std::{fmt::Debug, path::PathBuf, sync::Arc};
|
||||
use line_span::{LineSpan, LineSpanExt};
|
||||
|
||||
use crate::{
|
||||
errors::{CheckError, SourcePos},
|
||||
program::{self, parsed::block::Block},
|
||||
data::Type,
|
||||
errors::{error_colors, CheckError, SourcePos},
|
||||
program::{
|
||||
self,
|
||||
parsed::{block::Block, CompInfo},
|
||||
},
|
||||
};
|
||||
|
||||
pub mod statements;
|
||||
@@ -22,6 +26,70 @@ pub fn parse(
|
||||
};
|
||||
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 {
|
||||
src_from: SourceFrom,
|
||||
|
||||
@@ -168,30 +168,52 @@ pub fn parse(
|
||||
let dot_in_src = src.get_pos();
|
||||
if let Some('.') = src.peek_char() {
|
||||
src.next_char();
|
||||
let chained = match parse_no_chain(src, srca) {
|
||||
Ok(Some(v)) => v,
|
||||
Ok(None) => {
|
||||
src.skip_whitespace();
|
||||
if src.peek_word() == "try" {
|
||||
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()
|
||||
.src(vec![((dot_in_src, src.get_pos(), srca).into(), None)])
|
||||
.msg(format!("EOF after `.`")))
|
||||
.msg(format!("Expected `(` after `.try`"))
|
||||
.src(vec![(
|
||||
(dot_in_src, src.get_pos(), srca).into(),
|
||||
Some(error_colors::TryBadSyntax),
|
||||
)]));
|
||||
}
|
||||
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 {
|
||||
} else {
|
||||
let chained = match parse_no_chain(src, srca) {
|
||||
Ok(Some(v)) => v,
|
||||
Ok(None) => {
|
||||
return Err(CheckError::new()
|
||||
.src(vec![((dot_in_src, src.get_pos(), srca).into(), None)])
|
||||
.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(),
|
||||
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 {
|
||||
src.set_pos(pos_after_first);
|
||||
break;
|
||||
@@ -203,6 +225,12 @@ pub fn parse(
|
||||
}
|
||||
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(
|
||||
src: &mut Source,
|
||||
srca: &Arc<Source>,
|
||||
@@ -374,7 +402,7 @@ pub fn parse_no_chain(
|
||||
Some('(') => {
|
||||
let pos_in_src = src.get_pos();
|
||||
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 {
|
||||
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
||||
elems,
|
||||
|
||||
Reference in New Issue
Block a user