use dever::{ compiler::{check, model::Program}, syntax::{diagnostic::Diagnostic, source::Source}, }; fn linked(text: &str) -> Result { let inputs = [ ("main", text), ("text", include_str!("../../../lib/text.dever")), ("int", include_str!("../../../lib/int.dever")), ("decimal", include_str!("../../../lib/decimal.dever")), ("float", include_str!("../../../lib/float.dever")), ("math", include_str!("../../../lib/math.dever")), ]; let modules = inputs .iter() .enumerate() .map(|(index, (_, text))| { dever::syntax::parse(&Source::new( index, if index == 0 { "main.dever".into() } else { format!("library{index}.dever") }, (*text).into(), )) }) .collect::, _>>()?; check::check( modules, &inputs .iter() .map(|(package, _)| (*package).into()) .collect::>(), ) } #[test] fn text_and_numeric_standard_calls_remain_typed_and_effect_free() { let program = linked("main() (answer: Bool) pure { text = text.join([int.toText(42), decimal.toText(decimal.round(1.25, 1))], \"/\")\n answer = text.contains(text, \"42\") and math.isNan(math.sqrt(-1e0)) }").unwrap(); let main = program .functions .iter() .find(|function| function.signature.name == "main") .unwrap(); assert_eq!(main.signature.effects, Default::default()); for source in [ "main() () { value = int.parse(1) }", "main() () { value = text.slice(\"x\", 1.0, 2) }", "main() () { value = math.sqrt(\"9\") }", "main() (answer: Int) { answer = int.parse(\"1\") }", ] { assert_eq!(linked(source).unwrap_err().code, "C005", "{source}"); } } #[test] fn user_sources_cannot_call_standard_primitive_boundaries() { for name in [ "textTrim", "textJoin", "intParse", "decimalRound", "floatFromInt", "floatSqrt", ] { assert_eq!( linked(&format!("main() () {{ value = dever.system.{name}(1) }}")) .unwrap_err() .code, "C006", "{name}" ); } }