use nxc_frontend::{analyze, emit_c, lower_to_hir, HirExprKind, HirStmtKind, Lexer, Parser}; fn lower(source: &str) -> nxc_frontend::LoweringResult { let lexed = Lexer::new(source).lex(); assert!(lexed.diagnostics.is_empty(), "{:?}", lexed.diagnostics); let parsed = Parser::new(lexed.tokens).parse_module(); assert!(parsed.diagnostics.is_empty(), "{:?}", parsed.diagnostics); let semantic = analyze(&parsed.module); assert!(semantic.diagnostics.is_empty(), "{:?}", semantic.diagnostics); lower_to_hir(&semantic.module) } #[test] fn lowers_simple_program_to_hir() { let lowered = lower( "\ fn add(a: Int, b: Int) -> Int: let sum = a + b return sum ", ); assert!(lowered.diagnostics.is_empty(), "{:?}", lowered.diagnostics); assert_eq!(lowered.module.functions.len(), 1); let function = &lowered.module.functions[0]; assert_eq!(function.params.len(), 2); assert_eq!(function.body.statements.len(), 2); let HirStmtKind::Let { value, .. } = &function.body.statements[0].kind else { panic!("expected let statement"); }; match &value.kind { HirExprKind::Binary { .. } => {} other => panic!("expected lowered binary expression, got {other:?}"), } } #[test] fn emits_c_for_precedence_and_return() { let lowered = lower( "\ fn predicate() -> Bool: return 1 + 2 * 3 == 7 || false ", ); let emitted = emit_c(&lowered.module); assert!(emitted.diagnostics.is_empty(), "{:?}", emitted.diagnostics); let code = emitted.code.expect("expected generated C"); assert!(code.contains("return (((1LL + (2LL * 3LL)) == 7LL) || false);")); assert!(code.contains("bool nxc_fn_0_predicate(void)")); } #[test] fn emits_if_else_and_function_calls() { let lowered = lower( "\ fn choose(flag: Bool) -> Int: if flag: return answer() else: return 0 fn answer() -> Int: return 42 ", ); let emitted = emit_c(&lowered.module); assert!(emitted.diagnostics.is_empty(), "{:?}", emitted.diagnostics); let code = emitted.code.expect("expected generated C"); assert!(code.contains("if (nxc_local_0_flag) {")); assert!(code.contains("return nxc_fn_1_answer();")); assert!(code.contains("else {")); } #[test] fn rejects_unsupported_string_binary_ops_in_backend() { let lowered = lower( "\ fn main() -> Bool: return \"a\" == \"b\" ", ); let emitted = emit_c(&lowered.module); assert!(emitted.code.is_none()); assert!(emitted .diagnostics .iter() .any(|diag| diag.message.contains("string binary operations are not supported"))); }