From 817ed25f96e78869bceafb5af40463a2c9fdc5dd Mon Sep 17 00:00:00 2001 From: Mark <> Date: Thu, 29 Aug 2024 15:48:01 +0200 Subject: [PATCH] add warning to if-statement in check mode warning is shown if the condition of an if statement can never be true or false, and the user used the check command. warnings are not shown when you use `mers run`. --- mers/src/main.rs | 3 ++- mers_lib/src/errors/mod.rs | 2 ++ mers_lib/src/errors/themes.rs | 6 +++++- mers_lib/src/program/run/if.rs | 32 +++++++++++++++++++++++++++++--- mers_lib/src/program/run/mod.rs | 19 ++++++++++++++++++- 5 files changed, 56 insertions(+), 6 deletions(-) diff --git a/mers/src/main.rs b/mers/src/main.rs index ede4906..69853b8 100755 --- a/mers/src/main.rs +++ b/mers/src/main.rs @@ -125,7 +125,8 @@ fn main() { exit(20); } Ok(parsed) => { - let (i1, _, i3) = config.infos(); + let (i1, _, mut i3) = config.infos(); + i3.global.show_warnings_to_stderr(); match compile(&*parsed, i1) { Err(e) => { eprintln!("{e:?}"); diff --git a/mers_lib/src/errors/mod.rs b/mers_lib/src/errors/mod.rs index 61eb64c..0ff07e0 100644 --- a/mers_lib/src/errors/mod.rs +++ b/mers_lib/src/errors/mod.rs @@ -97,6 +97,8 @@ pub enum EColor { MaximumRuntimeExceeded, InCodePositionLine, + + Warning, } pub trait ETheme: ThemeGen {} diff --git a/mers_lib/src/errors/themes.rs b/mers_lib/src/errors/themes.rs index 3b4f20d..8e7ded5 100644 --- a/mers_lib/src/errors/themes.rs +++ b/mers_lib/src/errors/themes.rs @@ -42,6 +42,10 @@ pub fn default_theme( _ => return None, }); } + if let Warning = color { + // same color as runtime errors, because warnings are only displayed in `check` mode, where the program won't run. + return Some(yellow); + } let hard_err = red; let type_right = blue; let type_wrong = magenta; @@ -56,7 +60,7 @@ pub fn default_theme( drop(cyan_bright); use EColor::*; Some(match color { - Indent(_) => unreachable!(), + Indent(_) | Warning => unreachable!(), // macros (#...) WhitespaceAfterHashtag diff --git a/mers_lib/src/program/run/if.rs b/mers_lib/src/program/run/if.rs index 33ebf67..d2ead0a 100755 --- a/mers_lib/src/program/run/if.rs +++ b/mers_lib/src/program/run/if.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use crate::{ - data::{self, tuple::TupleT, Data, MersType, Type}, + data::{self, tuple::TupleT, Data, Type}, errors::{CheckError, EColor, SourceRange}, }; @@ -47,18 +47,44 @@ impl MersStatement for If { ), ])); } - let mut t = if Type::new(data::bool::TrueT).is_included_in(&cond_return_type) { + let may_be_true = Type::new(data::bool::TrueT).is_included_in(&cond_return_type); + let may_be_false = Type::new(data::bool::FalseT).is_included_in(&cond_return_type); + let mut t = if may_be_true { self.on_true.check(info, None)? } else { Type::empty() }; - if Type::new(data::bool::FalseT).is_included_in(&cond_return_type) { + if may_be_false { if let Some(f) = &self.on_false { t.add_all(&f.check(info, None)?); } else { t.add(Arc::new(TupleT(vec![]))); } } + if let Some(show_warning) = &info.global.show_warnings { + if !may_be_false || !may_be_true { + let mut e = CheckError::new().src(vec![ + (self.pos_in_src.clone(), None), + ( + self.condition.source_range(), + Some(EColor::IfConditionNotBool), + ), + ]); + if !may_be_true { + e.msg_mut(vec![( + "Condition in this if-statement is never true".to_owned(), + Some(EColor::Warning), + )]); + } + if !may_be_false { + e.msg_mut(vec![( + "Condition in this if-statement is never false".to_owned(), + Some(EColor::Warning), + )]); + } + show_warning(e); + } + } Ok(t) } fn run_custom(&self, info: &mut super::Info) -> Result { diff --git a/mers_lib/src/program/run/mod.rs b/mers_lib/src/program/run/mod.rs index 3718091..91e6ceb 100755 --- a/mers_lib/src/program/run/mod.rs +++ b/mers_lib/src/program/run/mod.rs @@ -142,10 +142,11 @@ pub struct CheckLocal { >, >, } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Default)] pub struct CheckLocalGlobalInfo { pub depth: usize, pub enable_hooks: bool, + pub show_warnings: Option>, /// ((results, byte_pos_in_src, deepest_statement)) /// you only have to set `byte_pos_in_src`. `deepest` is used internally. /// These values should be initialized to `(vec![], _, 0)`, but `0` can be replaced by a minimum statement depth, i.e. `2` to exclude the outer scope (which has depth `1`). @@ -160,6 +161,22 @@ pub struct CheckLocalGlobalInfo { >, pub unused_try_statements: Arc>)>>>, } +impl CheckLocalGlobalInfo { + pub fn show_warnings_to_stderr(&mut self) { + self.show_warnings = Some(Arc::new(|e| { + #[cfg(feature = "ecolor-term")] + let theme = crate::errors::themes::TermDefaultTheme; + #[cfg(not(feature = "ecolor-term"))] + let theme = crate::errors::themes::NoTheme; + eprintln!("{}", e.display(theme)); + })); + } +} +impl Debug for CheckLocalGlobalInfo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "CheckLocalGlobalInfo {{ depth: {}, enable_hooks: {}, show_warnings: {}, unused_try_statements: {} }}", self.depth, self.enable_hooks, self.show_warnings.is_some(), self.unused_try_statements.lock().unwrap().len()) + } +} impl Debug for CheckLocal { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "CheckLocal {:?}, {:?}", self.vars, self.types.keys())