V7: Make .try a language feature, this makes try_allow_unused unnecessary. remove try and try_... functions.

This commit is contained in:
Mark
2024-03-22 15:38:09 +01:00
parent 86b6a46d09
commit 8690263b1c
13 changed files with 334 additions and 208 deletions

View File

@@ -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,

View File

@@ -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,