use dever::compiler::check; use dever::syntax::source::Source; #[path = "compiler/application/mod.rs"] mod application; #[path = "compiler/auth/mod.rs"] mod auth; #[path = "compiler/database/mod.rs"] mod database; #[path = "compiler/job/mod.rs"] mod job; #[path = "compiler/api.rs"] mod api; #[path = "compiler/bytes.rs"] mod bytes; #[path = "compiler/calendar.rs"] mod calendar; #[path = "compiler/choice.rs"] mod choice; #[path = "compiler/collection.rs"] mod collection; #[path = "compiler/crypto.rs"] mod crypto; #[path = "compiler/failure.rs"] mod failure; #[path = "compiler/format.rs"] mod format; #[path = "compiler/handler.rs"] mod handler; #[path = "compiler/http.rs"] mod http; #[path = "compiler/id.rs"] mod id; #[path = "compiler/io/mod.rs"] mod io; #[path = "compiler/json.rs"] mod json; #[path = "compiler/net.rs"] mod net; #[path = "compiler/numeric/mod.rs"] mod numeric; #[path = "compiler/package.rs"] mod package; #[path = "compiler/port/mod.rs"] mod port; #[path = "compiler/standard.rs"] mod standard; #[path = "compiler/storage.rs"] mod storage; #[path = "compiler/task/mod.rs"] mod task; #[path = "compiler/tenant.rs"] mod tenant; #[path = "compiler/upload.rs"] mod upload; #[path = "compiler/usage.rs"] mod usage; #[path = "compiler/uuid.rs"] mod uuid; fn checked( text: &str, ) -> Result { let source = Source::new(0, "case.dever", text.into()); check::check(vec![dever::syntax::parse(&source)?], &["main".into()]) } #[test] fn rejects_overlap_gaps_and_recursion() { assert_eq!( checked("pick(value: Int < 0) (answer: Int) { answer = 1 }") .unwrap_err() .code, "C009" ); assert_eq!(checked("pick(value: Int <= 0) (answer: Int) { answer = 1 }\npick(value: Int >= 0) (answer: Int) { answer = 2 }").unwrap_err().code, "C009"); assert_eq!( checked("cycle() (answer: Int) { answer = cycle() }") .unwrap_err() .code, "C007" ); assert!(checked("pick(value: Int < 0) (answer: Int) { answer = 1 }\npick(value: other) (answer: Int) { answer = 2 }").is_ok()); } #[test] fn rejects_uninitialized_outputs_and_overflow() { assert!(checked("main() (answer: Int) { value = answer }").is_err()); assert!(checked("main() (answer: Int) {}").is_err()); assert!(checked("main() (answer: Int) { answer = 9223372036854775807 + 1 }").is_err()); assert!(checked("main() (answer: Int) { answer = -9223372036854775808 }").is_ok()); assert!(checked("main() (answer: Int) { answer = 9223372036854775806 + (1 + 1) }").is_err()); assert!(checked("main() (answer: Decimal) { answer = 1.0 / (2.0 - 2.0) }").is_err()); } #[test] fn preserves_record_and_list_types() { assert!(checked("type Row { name: Text\n count: Int }\nmain() (answer: Row) { answer = Row { name = \"雪\"\n count = sum([1, 2, 3]) } }").is_ok()); assert!( checked("type Row { count: Int }\nmain() (answer: Row) { answer = Row { wrong = 1 } }") .is_err() ); assert!(checked("main() (answer: List) { answer = [1, true] }").is_err()); } #[test] fn retains_original_naming_constraints() { assert_eq!(checked("read_value() () {}").unwrap_err().code, "C010"); assert_eq!(checked("Wrong() () {}").unwrap_err().code, "C010"); assert_eq!(checked("type bad { count: Int }").unwrap_err().code, "C010"); assert_eq!(checked("main() () { Bad = 1 }").unwrap_err().code, "C010"); assert!(checked("type HttpClient { user_id: Int }\nreadValue(input_value: Int) (output_value: Int) { output_value = input_value }").is_ok()); } #[test] #[ignore = "explicit compiler cost probe: fixed 15 rounds, run without concurrent CPU work"] fn compiler_reduction_costs() { use dever::compiler::project::Project; use std::{hint::black_box, path::Path, time::Instant}; let fixtures = Path::new(env!("CARGO_MANIFEST_DIR")).join("../test/rust/fixtures"); for (label, count) in [("medium", 32), ("large", 512)] { let mut text = "copyText(value: Text) (answer: Text) { answer = value }\n".to_owned(); for index in 0..count { let mut body = format!("case{index}(value: Text) (answer: Text) {{\nanswer = copyText(value)\n"); for _ in 0..15 { body.push_str("answer = copyText(answer)\n"); } body.push_str("}\n"); text.push_str(&body); } let source = Source::new(0, "cost.dever", text); let mut project = Project::load(&fixtures.join("core.dever")).unwrap(); project.sources[0] = Source::new(0, project.sources[0].path.clone(), source.text.clone()); let packages = vec!["main".to_owned()]; let expected_project_functions = project.check().unwrap().functions.len(); assert!(expected_project_functions > count); println!( "audit_compiler input={label} functions={} calls={} bytes={} project_bytes={} rounds=15 profile=test", count + 1, count * 16, source.text.len(), project.sources[0].text.len() ); for round in 1..=15 { let started = Instant::now(); let module = dever::syntax::parse(black_box(&source)).unwrap(); let elapsed = started.elapsed().as_nanos(); assert_eq!(module.declarations.len(), count + 1); println!("audit_compiler case={label} phase=parse round={round} ns={elapsed}"); let started = Instant::now(); let program = check::check(vec![module], black_box(&packages)).unwrap(); let elapsed = started.elapsed().as_nanos(); assert_eq!(program.functions.len(), count + 1); black_box(&program); println!("audit_compiler case={label} phase=check round={round} ns={elapsed}"); drop(program); let started = Instant::now(); let program = black_box(&project).check().unwrap(); let elapsed = started.elapsed().as_nanos(); assert_eq!(program.functions.len(), expected_project_functions); black_box(&program); println!("audit_compiler case={label} phase=project round={round} ns={elapsed}"); } } let project = Project::load(&fixtures.join("tenant")).unwrap(); let program = project.check().unwrap(); let roots = program.entries().collect::>(); assert!(!roots.is_empty()); println!( "audit_compiler input=tenant roots={} repeats=64 rounds=15", roots.len() ); for round in 1..=15 { let started = Instant::now(); let mut required = 0usize; for _ in 0..64 { for root in &roots { let access = black_box(&program).tenant_access(black_box(*root)); required += usize::from(access.required); black_box(access); } } let elapsed = started.elapsed().as_nanos(); println!( "audit_compiler case=tenant phase=access round={round} ns={elapsed} required={required}" ); } }