use std::collections::{HashMap, HashSet};

use crate::{
    diag::Diagnostic,
    reserved::{
        is_unsupported_generic_standard_library_call, unsupported_generic_function,
        unsupported_generic_standard_library_call, unsupported_generic_type_alias,
        unsupported_reserved_type_diagnostic,
    },
    sexpr::{Atom, SExpr, SExprKind},
    std_runtime,
    token::Span,
};

pub fn format(file: &str, source: &str, forms: &[SExpr]) -> Result<String, Vec<Diagnostic>> {
    let (comments, comment_errors) = collect_comments(source)
        .into_iter()
        .partition::<Vec<_>, _>(|comment| comment.full_line);
    let mut formatter = Formatter {
        file,
        comments,
        next_comment: 0,
        output: String::new(),
        function_names: collect_function_names(forms),
        struct_names: collect_struct_names(forms),
        enum_names: collect_enum_names(forms),
        type_alias_names: collect_type_alias_names(forms),
        errors: comment_errors
            .into_iter()
            .map(|comment| unsupported_non_full_line_comment(file, comment.span))
            .collect(),
    };

    formatter.write_forms(forms);

    if formatter.errors.is_empty() {
        Ok(formatter.output)
    } else {
        Err(formatter.errors)
    }
}

struct Formatter<'a> {
    file: &'a str,
    comments: Vec<LineComment>,
    next_comment: usize,
    output: String,
    function_names: HashSet<String>,
    struct_names: HashSet<String>,
    enum_names: HashSet<String>,
    type_alias_names: HashSet<String>,
    errors: Vec<Diagnostic>,
}

impl Formatter<'_> {
    fn write_forms(&mut self, forms: &[SExpr]) {
        for (index, form) in forms.iter().enumerate() {
            let before = self.take_comments_before(form.span.start);

            if index > 0 {
                self.output.push('\n');
            }

            self.write_comments(&before, "");

            if !before.is_empty() {
                self.output.push('\n');
            }

            match list_head(form) {
                Some("module") => self.write_module(form),
                Some("import") => self.write_import(form),
                Some("import_c") => self.write_c_import(form),
                Some("type") => self.write_type_alias(form),
                Some("enum") => self.write_enum(form),
                Some("struct") => self.write_struct(form),
                Some("fn") => self.write_function(form),
                Some("test") => self.write_test(form),
                Some(other) => self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        format!("formatter does not support top-level form `{}`", other),
                    )
                    .with_span(form.span)
                    .hint("current formatter syntax is limited to module/import declarations, C imports, strict `struct` forms, strict `fn` forms, and strict top-level `test` forms"),
                ),
                None => self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "formatter expected a top-level form",
                    )
                    .with_span(form.span),
                ),
            }

            self.output.push('\n');
        }

        let trailing = self.take_remaining_comments();
        if !trailing.is_empty() {
            if !self.output.is_empty() {
                self.output.push('\n');
            }
            self.write_comments(&trailing, "");
        }
    }

    fn write_module(&mut self, form: &SExpr) {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(self.file, "InvalidModule", "module form must be a list")
                    .with_span(form.span),
            );
            return;
        };

        if items.len() != 2 && items.len() != 3 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidModule",
                    "module form must be `(module name)` or `(module name (export ...))`",
                )
                .with_span(form.span),
            );
            return;
        }

        let Some(name) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidModuleName",
                    "module name must be an identifier",
                )
                .with_span(items[1].span),
            );
            return;
        };

        self.output.push_str("(module ");
        self.output.push_str(name);
        if let Some(export_form) = items.get(2) {
            let Some(exports) = expect_list(export_form) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidExport",
                        "export list must be `(export name...)`",
                    )
                    .with_span(export_form.span),
                );
                return;
            };
            if !matches!(exports.first().and_then(expect_ident), Some("export")) {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidExport",
                        "module option must be an export list",
                    )
                    .with_span(export_form.span),
                );
                return;
            }
            self.output.push_str(" (export");
            for export in &exports[1..] {
                let Some(name) = expect_ident(export) else {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "InvalidExport",
                            "exported name must be an identifier",
                        )
                        .with_span(export.span),
                    );
                    continue;
                };
                self.output.push(' ');
                self.output.push_str(name);
            }
            self.output.push(')');
        }
        self.reject_comments_before(
            form.span.end,
            "formatter does not support comments inside module forms",
        );
        self.output.push(')');
    }

    fn write_import(&mut self, form: &SExpr) {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(self.file, "InvalidImport", "import form must be a list")
                    .with_span(form.span),
            );
            return;
        };
        if items.len() != 3 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidImport",
                    "import form must be `(import module (name...))`",
                )
                .with_span(form.span),
            );
            return;
        }
        let Some(module) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidImport",
                    "import module must be an identifier",
                )
                .with_span(items[1].span),
            );
            return;
        };
        let Some(names) = expect_list(&items[2]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidImport",
                    "import list must contain imported names",
                )
                .with_span(items[2].span),
            );
            return;
        };

        self.output.push_str("(import ");
        self.output.push_str(module);
        self.output.push_str(" (");
        for (index, name) in names.iter().enumerate() {
            let Some(name) = expect_ident(name) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidImport",
                        "imported name must be an identifier",
                    )
                    .with_span(name.span),
                );
                continue;
            };
            if index > 0 {
                self.output.push(' ');
            }
            self.output.push_str(name);
        }
        self.output.push_str("))");
        self.reject_comments_before(
            form.span.end,
            "formatter does not support comments inside import forms",
        );
    }

    fn write_type_alias(&mut self, form: &SExpr) {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedTypeAlias",
                    "type alias form must be a list",
                )
                .with_span(form.span),
            );
            return;
        };

        if matches!(items.get(2).and_then(list_head), Some("type_params")) {
            self.errors.push(unsupported_generic_type_alias(
                self.file,
                items.get(2).map_or(form.span, |item| item.span),
            ));
            return;
        }

        if items.len() != 3 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedTypeAlias",
                    "type alias form must be `(type Alias TargetType)`",
                )
                .with_span(form.span),
            );
            return;
        }

        let Some(name) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidTypeAliasName",
                    "type alias name must be an identifier",
                )
                .with_span(items[1].span),
            );
            return;
        };

        let Some(target) = self.render_alias_target_type(&items[2]) else {
            return;
        };

        self.reject_comments_before(
            form.span.end,
            "formatter does not support comments inside type alias forms",
        );

        self.output.push_str("(type ");
        self.output.push_str(name);
        self.output.push(' ');
        self.output.push_str(&target);
        self.output.push(')');
    }

    fn write_struct(&mut self, form: &SExpr) {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedStructForm",
                    "struct form must be a list",
                )
                .with_span(form.span),
            );
            return;
        };

        if items.len() < 2 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedStructForm",
                    "struct form must be `(struct Name (field type)...)`",
                )
                .with_span(form.span),
            );
            return;
        }

        let Some(name) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidStructName",
                    "struct name must be an identifier",
                )
                .with_span(items[1].span),
            );
            return;
        };

        let mut fields = Vec::new();
        for item in &items[2..] {
            let Some(pair) = expect_list(item) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidStructField",
                        "struct field must be `(name type)`",
                    )
                    .with_span(item.span),
                );
                continue;
            };

            if pair.len() != 2 {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidStructField",
                        "struct field must be `(name type)`",
                    )
                    .with_span(item.span),
                );
                continue;
            }

            let Some(field_name) = expect_ident(&pair[0]) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidStructFieldName",
                        "struct field name must be an identifier",
                    )
                    .with_span(pair[0].span),
                );
                continue;
            };

            let Some(field_ty) = self.render_struct_field_type(&pair[1]) else {
                continue;
            };

            fields.push((field_name, field_ty));
        }

        self.reject_comments_before(
            form.span.end,
            "formatter does not support comments inside struct forms",
        );

        self.output.push_str("(struct ");
        self.output.push_str(name);
        for (field, field_ty) in fields {
            self.output.push('\n');
            self.output.push_str("  (");
            self.output.push_str(field);
            self.output.push(' ');
            self.output.push_str(&field_ty);
            self.output.push(')');
        }
        self.output.push(')');
    }

    fn write_c_import(&mut self, form: &SExpr) {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedCImport",
                    "`import_c` form must be a list",
                )
                .with_span(form.span),
            );
            return;
        };
        if items.len() != 5 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedCImport",
                    "`import_c` form must be `(import_c name ((arg i32)...) -> ReturnType)`",
                )
                .with_span(form.span),
            );
            return;
        }
        let Some(name) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedCImport",
                    "C import name must be an identifier",
                )
                .with_span(items[1].span),
            );
            return;
        };
        if !is_c_symbol_name(name) {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedCImport",
                    "C import name must be a C symbol identifier",
                )
                .with_span(items[1].span)
                .expected("ASCII letter or `_`, followed by ASCII letters, digits, or `_`")
                .found(name.to_string()),
            );
            return;
        }
        if !matches!(items[3].kind, SExprKind::Atom(Atom::Arrow)) {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedCImport",
                    "expected `->` in C import signature",
                )
                .with_span(items[3].span),
            );
            return;
        }
        let Some(params) = self.params(&items[2]) else {
            return;
        };
        let Some(return_type) = self.render_c_import_return_type(&items[4]) else {
            return;
        };

        self.output.push_str("(import_c ");
        self.output.push_str(name);
        self.output.push(' ');
        self.write_params(&params);
        self.output.push_str(" -> ");
        self.output.push_str(&return_type);
        self.output.push(')');
    }

    fn write_enum(&mut self, form: &SExpr) {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(self.file, "MalformedEnumForm", "enum form must be a list")
                    .with_span(form.span),
            );
            return;
        };

        if items.len() < 2 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedEnumForm",
                    "enum form must be `(enum Name Variant...)`",
                )
                .with_span(form.span),
            );
            return;
        }

        let Some(name) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidEnumName",
                    "enum name must be an identifier",
                )
                .with_span(items[1].span),
            );
            return;
        };

        let mut variants = Vec::new();
        let mut has_payload_variant = false;
        let mut enum_payload_ty: Option<(String, Span)> = None;
        for item in &items[2..] {
            if let Some(variant) = expect_ident(item) {
                variants.push(variant.to_string());
                continue;
            }

            let Some(variant_items) = expect_list(item) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidEnumVariant",
                        "enum variants must be identifiers or unary payload forms",
                    )
                    .with_span(item.span),
                );
                continue;
            };
            if variant_items.len() != 2 {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidEnumVariant",
                        "enum payload variants must be unary forms",
                    )
                    .with_span(item.span)
                    .expected("(Variant i32), (Variant i64), (Variant f64), (Variant bool), (Variant string), or (Variant KnownStruct)"),
                );
                continue;
            }
            let Some(variant) = expect_ident(&variant_items[0]) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidEnumVariant",
                        "enum variant name must be an identifier",
                    )
                    .with_span(variant_items[0].span),
                );
                continue;
            };
            let payload_ty = if is_ident(&variant_items[1], "i32") {
                "i32".to_string()
            } else if is_ident(&variant_items[1], "i64") {
                "i64".to_string()
            } else if is_ident(&variant_items[1], "f64") {
                "f64".to_string()
            } else if is_ident(&variant_items[1], "bool") {
                "bool".to_string()
            } else if is_ident(&variant_items[1], "string") {
                "string".to_string()
            } else if let Some(name) = expect_ident(&variant_items[1]) {
                if self.struct_names.contains(name) || self.type_alias_names.contains(name) {
                    name.to_string()
                } else {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "UnsupportedFormatterForm",
                            "formatter supports only unary direct i32, i64, f64, bool, string, known type aliases, and known non-recursive struct enum payload variants",
                        )
                        .with_span(variant_items[1].span)
                        .expected("i32, i64, f64, bool, string, known type alias, or known non-recursive struct type"),
                    );
                    continue;
                }
            } else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "formatter supports only unary direct i32, i64, f64, bool, string, known type aliases, and known non-recursive struct enum payload variants",
                    )
                    .with_span(variant_items[1].span)
                    .expected("i32, i64, f64, bool, string, known type alias, or known non-recursive struct type"),
                );
                continue;
            };
            if let Some((expected_ty, expected_span)) = &enum_payload_ty {
                if payload_ty != *expected_ty {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "UnsupportedFormatterForm",
                            "formatter requires all payload variants in one enum to share the same payload type",
                        )
                        .with_span(variant_items[1].span)
                        .related("first payload type in this enum", *expected_span)
                        .expected(expected_ty)
                        .found(&payload_ty)
                        .hint("split mixed payload kinds into separate enums"),
                    );
                    continue;
                }
            } else {
                enum_payload_ty = Some((payload_ty.clone(), variant_items[1].span));
            }
            has_payload_variant = true;
            variants.push(format!("({} {})", variant, payload_ty));
        }

        self.reject_comments_before(
            form.span.end,
            "formatter does not support comments inside enum forms",
        );

        self.output.push_str("(enum ");
        self.output.push_str(name);
        if has_payload_variant {
            for variant in variants {
                self.output.push('\n');
                self.output.push_str("  ");
                self.output.push_str(&variant);
            }
        } else {
            for variant in variants {
                self.output.push(' ');
                self.output.push_str(&variant);
            }
        }
        self.output.push(')');
    }

    fn write_function(&mut self, form: &SExpr) {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(self.file, "InvalidFunction", "function form must be a list")
                    .with_span(form.span),
            );
            return;
        };

        if items.len() < 6 {
            self.errors.push(
                Diagnostic::new(self.file, "InvalidFunction", "function form is incomplete")
                    .with_span(form.span)
                    .hint("expected `(fn name ((arg i32) ...) -> i32 body...)`"),
            );
            return;
        }

        if matches!(items.get(2).and_then(list_head), Some("type_params")) {
            self.errors
                .push(unsupported_generic_function(self.file, items[2].span));
            return;
        }

        let Some(name) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidFunctionName",
                    "function name must be an identifier",
                )
                .with_span(items[1].span),
            );
            return;
        };

        if !matches!(items[3].kind, SExprKind::Atom(Atom::Arrow)) {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "ExpectedArrow",
                    "expected `->` in function signature",
                )
                .with_span(items[3].span),
            );
            return;
        }

        let Some(return_type) = self.render_return_type(&items[4]) else {
            return;
        };

        let Some(params) = self.params(&items[2]) else {
            return;
        };

        self.reject_comments_before(
            items[4].span.end,
            "formatter does not support comments inside function signatures",
        );

        let mut env = HashSet::new();
        for (param, _) in &params {
            env.insert((*param).to_string());
        }

        self.output.push_str("(fn ");
        self.output.push_str(name);
        self.output.push(' ');
        self.write_params(&params);
        self.output.push_str(" -> ");
        self.output.push_str(&return_type);

        for expr in &items[5..] {
            let before = self.take_comments_before(expr.span.start);
            for comment in &before {
                self.output.push('\n');
                self.output.push_str("  ");
                self.output.push_str(&comment.text);
            }

            let rendered = self.render_body_expr(expr, &mut env);
            self.reject_comments_before(
                expr.span.end,
                "formatter does not support comments inside expression forms",
            );

            let Some(rendered) = rendered else {
                continue;
            };
            self.output.push('\n');
            self.write_indented_rendered("  ", &rendered);
        }

        let trailing = self.take_comments_before(form.span.end);
        if trailing.is_empty() {
            self.output.push(')');
        } else {
            for comment in &trailing {
                self.output.push('\n');
                self.output.push_str("  ");
                self.output.push_str(&comment.text);
            }
            self.output.push('\n');
            self.output.push(')');
        }
    }

    fn write_test(&mut self, form: &SExpr) {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(self.file, "MalformedTestForm", "test form must be a list")
                    .with_span(form.span)
                    .expected(r#"(test "name" body... final-expression)"#),
            );
            return;
        };

        if items.len() < 3 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedTestForm",
                    r#"test form must be `(test "name" body...)`"#,
                )
                .with_span(form.span)
                .expected(r#"(test "name" body... final-expression)"#),
            );
            return;
        }

        let Some(name) = expect_string(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedTestForm",
                    "test name must be a string literal",
                )
                .with_span(items[1].span)
                .expected("string literal"),
            );
            return;
        };

        if !is_valid_test_name(name) {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidTestName",
                    "test name must be non-empty printable ASCII without quotes, backslashes, or newlines",
                )
                .with_span(items[1].span),
            );
            return;
        }

        self.reject_comments_before(
            items[1].span.end,
            "formatter does not support comments inside test headers",
        );

        self.output.push_str("(test ");
        self.output.push_str(&render_string_literal(name));

        let mut env = HashSet::new();
        for (index, expr) in items[2..].iter().enumerate() {
            let before = self.take_comments_before(expr.span.start);
            for comment in &before {
                self.output.push('\n');
                self.output.push_str("  ");
                self.output.push_str(&comment.text);
            }

            if index + 1 < items[2..].len() && !is_sequential_test_body_form(expr) {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "MalformedTestForm",
                        "test body forms before the final expression must be local declarations, assignments, or while loops",
                    )
                    .with_span(expr.span)
                    .hint("use `(let name i32 expr)`, `(var name i32 expr)`, `(set name expr)`, or `(while condition body...)` before the final bool expression"),
                );
                continue;
            }

            let rendered = self.render_body_expr(expr, &mut env);
            self.reject_comments_before(
                expr.span.end,
                "formatter does not support comments inside expression forms",
            );

            let Some(rendered) = rendered else {
                continue;
            };
            self.output.push('\n');
            self.write_indented_rendered("  ", &rendered);
        }

        let trailing = self.take_comments_before(form.span.end);
        if trailing.is_empty() {
            self.output.push(')');
        } else {
            for comment in &trailing {
                self.output.push('\n');
                self.output.push_str("  ");
                self.output.push_str(&comment.text);
            }
            self.output.push('\n');
            self.output.push(')');
        }
    }

    fn params<'a>(&mut self, form: &'a SExpr) -> Option<Vec<(&'a str, String)>> {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(self.file, "InvalidParams", "parameters must be a list")
                    .with_span(form.span),
            );
            return None;
        };

        let mut params = Vec::new();

        let starting_error_count = self.errors.len();

        for item in items {
            let Some(pair) = expect_list(item) else {
                self.errors.push(
                    Diagnostic::new(self.file, "InvalidParam", "parameter must be `(name i32)`")
                        .with_span(item.span),
                );
                continue;
            };

            if pair.len() != 2 {
                self.errors.push(
                    Diagnostic::new(self.file, "InvalidParam", "parameter must be `(name i32)`")
                        .with_span(item.span),
                );
                continue;
            }

            let Some(name) = expect_ident(&pair[0]) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidParamName",
                        "parameter name must be an identifier",
                    )
                    .with_span(pair[0].span),
                );
                continue;
            };

            let ty = if is_ident(&pair[1], "i32") {
                "i32".to_string()
            } else if is_ident(&pair[1], "i64") {
                "i64".to_string()
            } else if is_ident(&pair[1], "u32") {
                "u32".to_string()
            } else if is_ident(&pair[1], "u64") {
                "u64".to_string()
            } else if is_ident(&pair[1], "f64") {
                "f64".to_string()
            } else if is_ident(&pair[1], "bool") {
                "bool".to_string()
            } else if is_ident(&pair[1], "string") {
                "string".to_string()
            } else if let Some(name) = expect_ident(&pair[1]) {
                if self.struct_names.contains(name)
                    || self.enum_names.contains(name)
                    || self.type_alias_names.contains(name)
                {
                    name.to_string()
                } else if self.push_reserved_type_error(&pair[1]) {
                    continue;
                } else {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "UnsupportedFormatterForm",
                            "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, `string`, known struct types, `(option i32)`, `(option i64)`, `(option u32)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)`, `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)`, `(array i32 N)`, `(array i64 N)`, `(array u32 N)`, `(array u64 N)`, `(array f64 N)`, `(array bool N)`, `(array string N)`, `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, and `(vec string)` parameters",
                        )
                        .with_span(pair[1].span),
                    );
                    continue;
                }
            } else if let Some(items) = expect_list(&pair[1]) {
                if let Some(text) = render_option_result_type(items, &self.type_alias_names) {
                    text
                } else if let Some(text) = render_supported_array_type(
                    items,
                    &self.struct_names,
                    &self.enum_names,
                    &self.type_alias_names,
                ) {
                    text
                } else if let Some(text) = render_supported_vec_type(items, &self.type_alias_names)
                {
                    text
                } else if self.push_reserved_type_error(&pair[1]) {
                    continue;
                } else {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "UnsupportedFormatterForm",
                            "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, `string`, known struct types, `(option i32)`, `(option i64)`, `(option u32)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)`, `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)`, `(array i32 N)`, `(array i64 N)`, `(array u32 N)`, `(array u64 N)`, `(array f64 N)`, `(array bool N)`, `(array string N)`, `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, and `(vec string)` parameters",
                        )
                        .with_span(pair[1].span),
                    );
                    continue;
                }
            } else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, `string`, known struct types, `(option i32)`, `(option i64)`, `(option u32)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)`, `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)`, `(array i32 N)`, `(array i64 N)`, `(array u32 N)`, `(array u64 N)`, `(array f64 N)`, `(array bool N)`, `(array string N)`, `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, and `(vec string)` parameters",
                    )
                    .with_span(pair[1].span),
                );
                continue;
            };

            params.push((name, ty));
        }

        if self.errors.len() == starting_error_count {
            Some(params)
        } else {
            None
        }
    }

    fn write_params(&mut self, params: &[(&str, String)]) {
        if params.is_empty() {
            self.output.push_str("()");
            return;
        }

        self.output.push('(');
        for (index, (name, ty)) in params.iter().enumerate() {
            if index > 0 {
                self.output.push(' ');
            }
            self.output.push('(');
            self.output.push_str(name);
            self.output.push(' ');
            self.output.push_str(ty);
            self.output.push(')');
        }
        self.output.push(')');
    }

    fn render_return_type(&mut self, form: &SExpr) -> Option<String> {
        if is_ident(form, "i32") {
            return Some("i32".to_string());
        }
        if is_ident(form, "i64") {
            return Some("i64".to_string());
        }
        if is_ident(form, "u32") {
            return Some("u32".to_string());
        }
        if is_ident(form, "u64") {
            return Some("u64".to_string());
        }
        if is_ident(form, "f64") {
            return Some("f64".to_string());
        }
        if is_ident(form, "bool") {
            return Some("bool".to_string());
        }
        if is_ident(form, "string") {
            return Some("string".to_string());
        }

        if let Some(name) = expect_ident(form) {
            if self.struct_names.contains(name)
                || self.enum_names.contains(name)
                || self.type_alias_names.contains(name)
            {
                return Some(name.to_string());
            }
        }

        if self.push_reserved_type_error(form) {
            return None;
        }

        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, `string`, known struct types, `(option i32)`, `(option i64)`, `(option u32)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)`, `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)`, `(array i32 N)`, `(array i64 N)`, `(array u32 N)`, `(array u64 N)`, `(array f64 N)`, `(array bool N)`, `(array string N)`, `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, and `(vec string)` function returns",
                )
                .with_span(form.span),
            );
            return None;
        };

        if let Some(text) = render_option_result_type(items, &self.type_alias_names) {
            return Some(text);
        }

        if let Some(text) = render_supported_array_type(
            items,
            &self.struct_names,
            &self.enum_names,
            &self.type_alias_names,
        ) {
            return Some(text);
        }

        if let Some(text) = render_supported_vec_type(items, &self.type_alias_names) {
            return Some(text);
        }

        if self.push_reserved_type_error(form) {
            return None;
        }

        self.errors.push(
            Diagnostic::new(
                self.file,
                "UnsupportedFormatterForm",
                    "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, `string`, known struct types, `(option i32)`, `(option i64)`, `(option u32)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)`, `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)`, `(array i32 N)`, `(array i64 N)`, `(array u32 N)`, `(array u64 N)`, `(array f64 N)`, `(array bool N)`, `(array string N)`, `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, and `(vec string)` function returns",
            )
            .with_span(form.span),
        );
        None
    }

    fn render_alias_target_type(&mut self, form: &SExpr) -> Option<String> {
        if let Some(text) = render_direct_type_atom(
            form,
            &self.struct_names,
            &self.enum_names,
            &self.type_alias_names,
        ) {
            return Some(text);
        }

        if self.push_reserved_type_error(form) {
            return None;
        }

        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidTypeAliasTarget",
                    "type alias target type is invalid",
                )
                .with_span(form.span)
                .expected("concrete type"),
            );
            return None;
        };

        if let Some(text) = render_option_result_type(items, &self.type_alias_names) {
            return Some(text);
        }

        if let Some(text) = render_supported_array_type(
            items,
            &self.struct_names,
            &self.enum_names,
            &self.type_alias_names,
        ) {
            return Some(text);
        }

        if let Some(text) = render_supported_vec_type(items, &self.type_alias_names) {
            return Some(text);
        }

        if self.push_reserved_type_error(form) {
            return None;
        }

        self.errors.push(
            Diagnostic::new(
                self.file,
                "InvalidTypeAliasTarget",
                "type alias target type is invalid",
            )
            .with_span(form.span)
            .expected("concrete type"),
        );
        None
    }

    fn render_c_import_return_type(&mut self, form: &SExpr) -> Option<String> {
        if is_ident(form, "i32") {
            return Some("i32".to_string());
        }
        if is_ident(form, "unit") {
            return Some("unit".to_string());
        }
        self.errors.push(
            Diagnostic::new(
                self.file,
                "UnsupportedCImportType",
                "C import return type must be `i32` or `unit` in exp-6",
            )
            .with_span(form.span)
            .expected("i32 or unit"),
        );
        None
    }

    fn render_body_expr(&mut self, expr: &SExpr, env: &mut HashSet<String>) -> Option<String> {
        if let SExprKind::List(items) = &expr.kind {
            if let Some(head) = items.first().and_then(expect_ident) {
                match head {
                    "let" | "var" => return self.render_local(expr.span, head, items, env),
                    "set" => return self.render_set(expr.span, items, env),
                    "while" => return self.render_while(expr.span, items, env),
                    _ => {}
                }
            }
        }

        self.render_expr(expr, env)
    }

    fn render_expr(&mut self, expr: &SExpr, env: &mut HashSet<String>) -> Option<String> {
        match &expr.kind {
            SExprKind::Atom(Atom::Int(value)) => {
                if i32::try_from(*value).is_err() {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "IntegerOutOfRange",
                            "integer literal is outside the supported i32 range",
                        )
                        .with_span(expr.span)
                        .expected("i32")
                        .found(value.to_string()),
                    );
                    None
                } else {
                    Some(value.to_string())
                }
            }
            SExprKind::Atom(Atom::I64(value)) => Some(format!("{}i64", value)),
            SExprKind::Atom(Atom::U32(value)) => Some(format!("{}u32", value)),
            SExprKind::Atom(Atom::U64(value)) => Some(format!("{}u64", value)),
            SExprKind::Atom(Atom::Float(value)) => {
                if !value.is_finite() {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "UnsupportedFloatLiteral",
                            "f64 literals must be finite in exp-20",
                        )
                        .with_span(expr.span)
                        .expected("finite f64 literal")
                        .found(value.to_string())
                        .hint("NaN and infinity semantics remain deferred"),
                    );
                    None
                } else {
                    Some(render_float_literal(*value))
                }
            }
            SExprKind::Atom(Atom::Ident(name)) if name == "true" || name == "false" => {
                Some(name.to_string())
            }
            SExprKind::Atom(Atom::String(value)) => Some(render_string_literal(value)),
            SExprKind::Atom(Atom::Ident(name)) if env.contains(name.as_str()) => {
                Some(name.to_string())
            }
            SExprKind::Atom(Atom::Ident(name)) => {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        format!(
                            "formatter does not support expression identifier `{}`",
                            name
                        ),
                    )
                    .with_span(expr.span)
                    .hint("current formatter identifiers must be function parameters or locals"),
                );
                None
            }
            SExprKind::List(items) if items.is_empty() => {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "empty forms are unsupported",
                    )
                    .with_span(expr.span),
                );
                None
            }
            SExprKind::List(items) => {
                let Some(head) = expect_ident(&items[0]) else {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "UnsupportedFormatterForm",
                            "expression form head must be an identifier",
                        )
                        .with_span(items[0].span),
                    );
                    return None;
                };

                match head {
                    "+" | "-" | "*" | "/" | "%" | "bit_and" | "bit_or" | "bit_xor" | "=" | "<"
                    | ">" | "<=" | ">=" => self.render_call(expr.span, head, &items[1..], env, 2),
                    "and" | "or" => self.render_call(expr.span, head, &items[1..], env, 2),
                    "not" => self.render_call(expr.span, head, &items[1..], env, 1),
                    "." => self.render_field_access(expr.span, items, env),
                    "array" => self.render_array_constructor(expr.span, items, env),
                    "some" | "none" => self.render_option_constructor(expr.span, head, items, env),
                    "ok" | "err" => self.render_result_constructor(expr.span, head, items, env),
                    "is_some" | "is_none" | "is_ok" | "is_err" | "std.result.is_ok"
                    | "std.result.is_err" => self.render_call(expr.span, head, &items[1..], env, 1),
                    "unwrap_some"
                    | "unwrap_ok"
                    | "unwrap_err"
                    | "std.result.unwrap_ok"
                    | "std.result.unwrap_err" => {
                        self.render_call(expr.span, head, &items[1..], env, 1)
                    }
                    "index" => self.render_call(expr.span, head, &items[1..], env, 2),
                    "if" => self.render_if(expr.span, items, env),
                    "match" => self.render_match(expr.span, items, env),
                    "unsafe" => self.render_unsafe(expr.span, items, env),
                    name if std_runtime::function(name).is_some() => {
                        let function = std_runtime::function(name).expect("runtime function");
                        self.render_call(expr.span, head, &items[1..], env, function.params.len())
                    }
                    name if self.struct_names.contains(name) => {
                        self.render_struct_constructor(expr.span, name, &items[1..], env)
                    }
                    name if qualified_enum_name(name)
                        .map(|(enum_name, _)| self.enum_names.contains(enum_name))
                        .unwrap_or(false) =>
                    {
                        if items.len() > 2 {
                            self.errors.push(
                                Diagnostic::new(
                                    self.file,
                                    "VariantConstructorArity",
                                    "enum constructors support zero or one argument",
                                )
                                .with_span(expr.span)
                                .expected("0 or 1")
                                .found((items.len() - 1).to_string()),
                            );
                            None
                        } else if items.len() == 2 {
                            let rendered = self.render_expr(&items[1], env)?;
                            Some(format!("({} {})", name, rendered))
                        } else {
                            Some(format!("({})", name))
                        }
                    }
                    other if is_unsupported_generic_standard_library_call(other) => {
                        self.errors.push(unsupported_generic_standard_library_call(
                            self.file,
                            items[0].span,
                            other,
                        ));
                        None
                    }
                    other if std_runtime::is_standard_path(other) => {
                        self.errors
                            .push(std_runtime::unsupported_standard_library_call(
                                self.file, expr.span, other,
                            ));
                        None
                    }
                    name if self.function_names.contains(name) => {
                        self.render_call(expr.span, name, &items[1..], env, usize::MAX)
                    }
                    other => {
                        self.errors.push(
                            Diagnostic::new(
                                self.file,
                                "UnsupportedFormatterForm",
                                format!("formatter does not support expression form `{}`", other),
                            )
                            .with_span(expr.span)
                            .hint("current formatter syntax supports integer, bool, and string literals, numeric and bitwise binary heads, boolean logic heads, comparisons, `if`, `match`, `while`, `unsafe`, arrays, structs, option/result observers and unwraps, standard-runtime calls, legacy runtime aliases, and user-defined calls"),
                        );
                        None
                    }
                }
            }
            _ => {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "formatter does not support this expression",
                    )
                    .with_span(expr.span),
                );
                None
            }
        }
    }

    fn render_local(
        &mut self,
        span: Span,
        keyword: &str,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() != 4 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    format!(
                        "formatter expected `{}` to have name, type, and initializer",
                        keyword
                    ),
                )
                .with_span(span),
            );
            return None;
        }

        let Some(name) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidLocalName",
                    "local name must be an identifier",
                )
                .with_span(items[1].span),
            );
            return None;
        };

        let Some(ty) = self.render_local_type(&items[2]) else {
            return None;
        };

        if keyword == "var" && ty.is_array {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter does not support mutable array locals",
                )
                .with_span(items[2].span),
            );
            return None;
        }

        let initializer = self.render_expr(&items[3], env)?;
        env.insert(name.to_string());
        Some(format!(
            "({} {} {} {})",
            keyword, name, ty.text, initializer
        ))
    }

    fn render_local_type(&mut self, form: &SExpr) -> Option<RenderedType> {
        if is_ident(form, "i32") {
            return Some(RenderedType {
                text: "i32".to_string(),
                is_array: false,
            });
        }

        if is_ident(form, "i64") {
            return Some(RenderedType {
                text: "i64".to_string(),
                is_array: false,
            });
        }

        if is_ident(form, "u32") {
            return Some(RenderedType {
                text: "u32".to_string(),
                is_array: false,
            });
        }

        if is_ident(form, "u64") {
            return Some(RenderedType {
                text: "u64".to_string(),
                is_array: false,
            });
        }

        if is_ident(form, "f64") {
            return Some(RenderedType {
                text: "f64".to_string(),
                is_array: false,
            });
        }

        if is_ident(form, "bool") {
            return Some(RenderedType {
                text: "bool".to_string(),
                is_array: false,
            });
        }

        if is_ident(form, "string") {
            return Some(RenderedType {
                text: "string".to_string(),
                is_array: false,
            });
        }

        if let Some(name) = expect_ident(form) {
            if self.struct_names.contains(name) {
                return Some(RenderedType {
                    text: name.to_string(),
                    is_array: false,
                });
            }
            if self.enum_names.contains(name) {
                return Some(RenderedType {
                    text: name.to_string(),
                    is_array: false,
                });
            }
            if self.type_alias_names.contains(name) {
                return Some(RenderedType {
                    text: name.to_string(),
                    is_array: false,
                });
            }
        }

        if self.push_reserved_type_error(form) {
            return None;
        }

        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, `string`, known struct and enum types, `(option i32)`, `(option i64)`, `(option u32)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)`, `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)`, `(array i32 N)`, `(array i64 N)`, `(array u32 N)`, `(array u64 N)`, `(array f64 N)`, `(array bool N)`, `(array string N)`, `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, and `(vec string)` locals",
                )
                .with_span(form.span),
            );
            return None;
        };

        if let Some(text) = render_option_result_type(items, &self.type_alias_names) {
            return Some(RenderedType {
                text,
                is_array: false,
            });
        }

        if let Some(text) = render_supported_vec_type(items, &self.type_alias_names) {
            return Some(RenderedType {
                text,
                is_array: false,
            });
        }

        if self.push_reserved_type_error(form) {
            return None;
        }

        if items.len() != 3 || !is_ident(&items[0], "array") {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, `string`, known struct and enum types, `(option i32)`, `(option i64)`, `(option u32)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)`, `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)`, `(array i32 N)`, `(array i64 N)`, `(array u32 N)`, `(array u64 N)`, `(array f64 N)`, `(array bool N)`, `(array string N)`, `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, and `(vec string)` locals",
                )
                .with_span(form.span),
            );
            return None;
        }

        let Some(elem_ty) = render_supported_array_constructor_type(
            &items[1],
            &self.struct_names,
            &self.enum_names,
            &self.type_alias_names,
        ) else {
            if self.push_reserved_type_error(&items[1]) {
                return None;
            }
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, `string`, known struct and enum types, `(option i32)`, `(option i64)`, `(option u32)`, `(option u64)`, `(option f64)`, `(option bool)`, `(option string)`, `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, `(result string i32)`, `(array i32 N)`, `(array i64 N)`, `(array u32 N)`, `(array u64 N)`, `(array f64 N)`, `(array bool N)`, `(array string N)`, `(vec i32)`, `(vec i64)`, `(vec f64)`, `(vec bool)`, and `(vec string)` locals",
                )
                .with_span(form.span),
            );
            return None;
        };

        let Some(len) = expect_int(&items[2]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter expected array local length to be an integer literal",
                )
                .with_span(items[2].span),
            );
            return None;
        };

        if len <= 0 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only positive-length array locals",
                )
                .with_span(items[2].span),
            );
            return None;
        }

        Some(RenderedType {
            text: format!("(array {} {})", elem_ty, len),
            is_array: true,
        })
    }

    fn render_struct_field_type(&mut self, form: &SExpr) -> Option<String> {
        if is_ident(form, "i32") {
            return Some("i32".to_string());
        }
        if is_ident(form, "i64") {
            return Some("i64".to_string());
        }
        if is_ident(form, "f64") {
            return Some("f64".to_string());
        }
        if is_ident(form, "bool") {
            return Some("bool".to_string());
        }
        if is_ident(form, "string") {
            return Some("string".to_string());
        }

        if let Some(name) = expect_ident(form) {
            if self.struct_names.contains(name)
                || self.enum_names.contains(name)
                || self.type_alias_names.contains(name)
            {
                return Some(name.to_string());
            }
        }

        if self.push_reserved_type_error(form) {
            return None;
        }

        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports direct scalar/string/enum fields, direct fixed-array fields over current released element families, current concrete vec/option/result fields, and current non-recursive struct fields",
                )
                .with_span(form.span),
            );
            return None;
        };

        if let Some(text) = render_option_result_type(items, &self.type_alias_names) {
            return Some(text);
        }

        if let Some(text) = render_supported_array_type(
            items,
            &self.struct_names,
            &self.enum_names,
            &self.type_alias_names,
        ) {
            return Some(text);
        }

        if let Some(text) = render_supported_vec_type(items, &self.type_alias_names) {
            return Some(text);
        }

        if self.push_reserved_type_error(form) {
            return None;
        }

        self.errors.push(
            Diagnostic::new(
                self.file,
                "UnsupportedFormatterForm",
                "formatter supports direct scalar/string/enum fields, direct fixed-array fields over current released element families, current concrete vec/option/result fields, and current non-recursive struct fields",
            )
            .with_span(form.span),
        );
        None
    }

    fn render_set(
        &mut self,
        span: Span,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() != 3 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter expected `set` to have a name and value",
                )
                .with_span(span),
            );
            return None;
        }

        let Some(name) = expect_ident(&items[1]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidSetTarget",
                    "`set` target must be an identifier",
                )
                .with_span(items[1].span),
            );
            return None;
        };

        if !env.contains(name) {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    format!("formatter does not know local `{}`", name),
                )
                .with_span(items[1].span),
            );
            return None;
        }

        let value = self.render_expr(&items[2], env)?;
        Some(format!("(set {} {})", name, value))
    }

    fn render_while(
        &mut self,
        span: Span,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() < 3 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter expected `while` to have a condition and body",
                )
                .with_span(span),
            );
            return None;
        }

        let condition = self.render_expr(&items[1], env)?;
        let mut output = format!("(while {}", condition);

        for item in &items[2..] {
            if is_local_body_form(item) {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "formatter does not support local declarations inside `while` bodies",
                    )
                    .with_span(item.span)
                    .hint("declare loop locals before the `while` form"),
                );
                return None;
            }

            if matches!(list_head(item), Some("while")) {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "formatter does not support nested `while` loops",
                    )
                    .with_span(item.span)
                    .hint("keep first-pass loop bodies flat"),
                );
                return None;
            }

            let rendered = self.render_body_expr(item, env)?;
            output.push('\n');
            push_indented(&mut output, "  ", &rendered);
        }

        output.push(')');
        Some(output)
    }

    fn render_if(
        &mut self,
        span: Span,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() != 4 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter expected `if` to have condition, then expression, and else expression",
                )
                .with_span(span),
            );
            return None;
        }

        let condition = self.render_expr(&items[1], env)?;
        let then_expr = self.render_expr(&items[2], env)?;
        let else_expr = self.render_expr(&items[3], env)?;
        let mut output = format!("(if {}", condition);
        output.push('\n');
        push_indented(&mut output, "  ", &then_expr);
        output.push('\n');
        push_indented(&mut output, "  ", &else_expr);
        output.push(')');
        Some(output)
    }

    fn render_match(
        &mut self,
        span: Span,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() < 2 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedMatchPattern",
                    "`match` expects a subject",
                )
                .with_span(span)
                .expected("(match subject (pattern body...) (pattern body...))"),
            );
            return None;
        }

        let subject = self.render_expr(&items[1], env)?;
        let mut output = format!("(match {}", subject);
        let mut seen = HashMap::new();

        for arm in &items[2..] {
            let Some(arm_items) = expect_list(arm) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "MalformedMatchPattern",
                        "match arm must be a list containing a pattern and body",
                    )
                    .with_span(arm.span),
                );
                return None;
            };

            if arm_items.len() < 2 {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "MalformedMatchPattern",
                        "match arm must contain a pattern and at least one body expression",
                    )
                    .with_span(arm.span),
                );
                return None;
            }

            let pattern = self.render_match_pattern(&arm_items[0])?;
            if let Some(original) = seen.insert(pattern.kind, arm_items[0].span) {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "DuplicateMatchArm",
                        format!("duplicate `{}` match arm", pattern.kind),
                    )
                    .with_span(arm_items[0].span)
                    .related("original match arm", original),
                );
                return None;
            }

            let mut arm_env = env.clone();
            if let Some(binding) = pattern.binding {
                arm_env.insert(binding.to_string());
            }

            let before_arm = self.take_comments_before(arm.span.start);
            for comment in &before_arm {
                output.push('\n');
                output.push_str("  ");
                output.push_str(&comment.text);
            }

            output.push('\n');
            output.push_str("  (");
            output.push_str(&pattern.text);

            for body_expr in &arm_items[1..] {
                let before_expr = self.take_comments_before(body_expr.span.start);
                for comment in &before_expr {
                    output.push('\n');
                    output.push_str("    ");
                    output.push_str(&comment.text);
                }

                let rendered = self.render_body_expr(body_expr, &mut arm_env)?;
                self.reject_comments_before(
                    body_expr.span.end,
                    "formatter does not support comments inside expression forms",
                );

                output.push('\n');
                push_indented(&mut output, "    ", &rendered);
            }

            let trailing = self.take_comments_before(arm.span.end);
            for comment in &trailing {
                output.push('\n');
                output.push_str("    ");
                output.push_str(&comment.text);
            }

            output.push(')');
        }

        let has_some = seen.contains_key("some");
        let has_none = seen.contains_key("none");
        let has_ok = seen.contains_key("ok");
        let has_err = seen.contains_key("err");
        let option_family = has_some || has_none;
        let result_family = has_ok || has_err;

        if option_family && result_family {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedMatchPattern",
                    "match arms must belong to one pattern family",
                )
                .with_span(span),
            );
            return None;
        }

        if option_family && (!has_some || !has_none) {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "NonExhaustiveMatch",
                    "option match must contain `some` and `none` arms",
                )
                .with_span(span)
                .expected("some and none"),
            );
            return None;
        }

        if result_family && (!has_ok || !has_err) {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "NonExhaustiveMatch",
                    "result match must contain `ok` and `err` arms",
                )
                .with_span(span)
                .expected("ok and err"),
            );
            return None;
        }

        let trailing = self.take_comments_before(span.end);
        for comment in &trailing {
            output.push('\n');
            output.push_str("  ");
            output.push_str(&comment.text);
        }

        output.push(')');
        Some(output)
    }

    fn render_match_pattern<'a>(&mut self, form: &'a SExpr) -> Option<RenderedMatchPattern<'a>> {
        let Some(items) = expect_list(form) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedMatchPattern",
                    "match arm pattern must be a list",
                )
                .with_span(form.span)
                .expected("(some binding), (none), (ok binding), or (err binding)"),
            );
            return None;
        };

        let Some(kind) = items.first().and_then(expect_ident) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedMatchPattern",
                    "match arm pattern head must be an identifier",
                )
                .with_span(form.span),
            );
            return None;
        };

        match kind {
            "some" | "ok" | "err" => {
                if items.len() != 2 {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "MalformedMatchPattern",
                            format!("`{}` match pattern requires one payload binding", kind),
                        )
                        .with_span(form.span),
                    );
                    return None;
                }

                let Some(binding) = expect_ident(&items[1]) else {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "MalformedMatchPattern",
                            "match payload binding must be an identifier",
                        )
                        .with_span(items[1].span),
                    );
                    return None;
                };

                Some(RenderedMatchPattern {
                    kind,
                    binding: Some(binding),
                    text: format!("({} {})", kind, binding),
                })
            }
            "none" => {
                if items.len() != 1 {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "MalformedMatchPattern",
                            "`none` match pattern does not take a payload binding",
                        )
                        .with_span(form.span),
                    );
                    return None;
                }

                Some(RenderedMatchPattern {
                    kind,
                    binding: None,
                    text: "(none)".to_string(),
                })
            }
            name if qualified_enum_name(name)
                .map(|(enum_name, _)| self.enum_names.contains(enum_name))
                .unwrap_or(false) =>
            {
                if items.len() > 2 {
                    self.errors.push(
                        Diagnostic::new(
                            self.file,
                            "InvalidEnumMatchArm",
                            "enum match patterns support at most one payload binding",
                        )
                        .with_span(form.span)
                        .expected("(Name.Variant) or (Name.Variant binding)"),
                    );
                    return None;
                }

                let binding = if items.len() == 2 {
                    let Some(binding) = expect_ident(&items[1]) else {
                        self.errors.push(
                            Diagnostic::new(
                                self.file,
                                "MalformedMatchPattern",
                                "match payload binding must be an identifier",
                            )
                            .with_span(items[1].span),
                        );
                        return None;
                    };
                    Some(binding)
                } else {
                    None
                };

                Some(RenderedMatchPattern {
                    kind: name,
                    binding,
                    text: binding
                        .map(|binding| format!("({} {})", name, binding))
                        .unwrap_or_else(|| format!("({})", name)),
                })
            }
            _ => {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "MalformedMatchPattern",
                        format!("unsupported match pattern `{}`", kind),
                    )
                    .with_span(form.span),
                );
                None
            }
        }
    }

    fn render_unsafe(
        &mut self,
        span: Span,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() < 2 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "MalformedUnsafeForm",
                    "`unsafe` block must contain a final expression",
                )
                .with_span(span)
                .expected("(unsafe body-form... final-expression)"),
            );
            return None;
        }

        let mut scoped_env = env.clone();
        let mut output = "(unsafe".to_string();

        for item in &items[1..] {
            let rendered = self.render_body_expr(item, &mut scoped_env)?;
            output.push('\n');
            push_indented(&mut output, "  ", &rendered);
        }

        output.push(')');
        Some(output)
    }

    fn render_field_access(
        &mut self,
        span: Span,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() != 3 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter expected field access to be `(. value field)`",
                )
                .with_span(span),
            );
            return None;
        }

        let value = self.render_expr(&items[1], env)?;
        let Some(field) = expect_ident(&items[2]) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "InvalidFieldName",
                    "field name must be an identifier",
                )
                .with_span(items[2].span),
            );
            return None;
        };

        Some(format!("(. {} {})", value, field))
    }

    fn render_struct_constructor(
        &mut self,
        span: Span,
        name: &str,
        fields: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        let mut output = String::new();
        output.push('(');
        output.push_str(name);

        for field in fields {
            let Some(pair) = expect_list(field) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "formatter expected struct constructor fields to be `(field value)`",
                    )
                    .with_span(field.span),
                );
                return None;
            };

            if pair.len() != 2 {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "UnsupportedFormatterForm",
                        "formatter expected struct constructor fields to be `(field value)`",
                    )
                    .with_span(field.span),
                );
                return None;
            }

            let Some(field_name) = expect_ident(&pair[0]) else {
                self.errors.push(
                    Diagnostic::new(
                        self.file,
                        "InvalidStructConstructorField",
                        "struct constructor field name must be an identifier",
                    )
                    .with_span(pair[0].span),
                );
                return None;
            };

            let value = self.render_expr(&pair[1], env)?;
            output.push_str(" (");
            output.push_str(field_name);
            output.push(' ');
            output.push_str(&value);
            output.push(')');
        }

        if fields.is_empty() {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter expected at least one struct constructor field",
                )
                .with_span(span),
            );
            return None;
        }

        output.push(')');
        Some(output)
    }

    fn render_array_constructor(
        &mut self,
        span: Span,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() < 2 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter expected array constructor to be `(array TYPE value...)`",
                )
                .with_span(span),
            );
            return None;
        }

        let Some(elem_ty) = render_supported_array_constructor_type(
            &items[1],
            &self.struct_names,
            &self.enum_names,
            &self.type_alias_names,
        ) else {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only direct scalar `i32`, `i64`, `f64`, `bool`, or `string` array constructors",
                )
                .with_span(items[1].span),
            );
            return None;
        };

        if items.len() == 2 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter expected at least one array element",
                )
                .with_span(span),
            );
            return None;
        }

        let mut output = format!("(array {}", elem_ty);
        for item in &items[2..] {
            let rendered = self.render_expr(item, env)?;
            output.push(' ');
            output.push_str(&rendered);
        }
        output.push(')');
        Some(output)
    }

    fn render_option_constructor(
        &mut self,
        span: Span,
        name: &str,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        let expected_len = if name == "some" { 3 } else { 2 };
        if items.len() != expected_len {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    format!(
                        "formatter expected `{}` to be `{}`",
                        name,
                        if name == "some" {
                            "(some i32 value), (some i64 value), (some u32 value), (some u64 value), (some f64 value), (some bool value), or (some string value)"
                        } else {
                            "(none i32), (none i64), (none u32), (none u64), (none f64), (none bool), or (none string)"
                        }
                    ),
                )
                .with_span(span),
            );
            return None;
        }

        let Some(payload_type) = render_payload_type_atom(&items[1], &self.type_alias_names) else {
            if self.push_reserved_type_error(&items[1]) {
                return None;
            }
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only `i32`, `i64`, `u32`, `u64`, `f64`, `bool`, and `string` option payloads",
                )
                .with_span(items[1].span),
            );
            return None;
        };

        if name == "none" {
            return Some(format!("(none {})", payload_type));
        }

        let value = self.render_expr(&items[2], env)?;
        Some(format!("(some {} {})", payload_type, value))
    }

    fn render_result_constructor(
        &mut self,
        span: Span,
        name: &str,
        items: &[SExpr],
        env: &mut HashSet<String>,
    ) -> Option<String> {
        if items.len() != 4 {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    format!(
                        "formatter expected `{}` to be `({} i32 i32 value)`, `({} i64 i32 value)`, `({} u32 i32 value)`, `({} u64 i32 value)`, `({} f64 i32 value)`, `({} bool i32 value)`, or `({} string i32 value)`",
                        name, name, name, name, name, name, name, name
                    ),
                )
                .with_span(span),
            );
            return None;
        }

        let Some(ok_ty) = render_payload_type_atom(&items[1], &self.type_alias_names) else {
            if self.push_reserved_type_error(&items[1]) {
                return None;
            }
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, and `(result string i32)` constructors",
                )
                .with_span(span),
            );
            return None;
        };
        let Some(err_ty) = render_result_err_type_atom(&items[2], &self.type_alias_names) else {
            if self.push_reserved_type_error(&items[2]) {
                return None;
            }
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    "formatter supports only `(result i32 i32)`, `(result i64 i32)`, `(result u32 i32)`, `(result u64 i32)`, `(result f64 i32)`, `(result bool i32)`, and `(result string i32)` constructors",
                )
                .with_span(span),
            );
            return None;
        };

        let value = self.render_expr(&items[3], env)?;
        Some(format!("({} {} {} {})", name, ok_ty, err_ty, value))
    }

    fn render_call(
        &mut self,
        span: Span,
        name: &str,
        args: &[SExpr],
        env: &mut HashSet<String>,
        exact_arity: usize,
    ) -> Option<String> {
        if exact_arity != usize::MAX && args.len() != exact_arity {
            self.errors.push(
                Diagnostic::new(
                    self.file,
                    "UnsupportedFormatterForm",
                    format!(
                        "formatter expected `{}` to have {} argument(s)",
                        name, exact_arity
                    ),
                )
                .with_span(span),
            );
            return None;
        }

        let mut output = String::new();
        output.push('(');
        output.push_str(name);
        for arg in args {
            let rendered = self.render_expr(arg, env)?;
            output.push(' ');
            output.push_str(&rendered);
        }
        output.push(')');
        Some(output)
    }

    fn push_reserved_type_error(&mut self, form: &SExpr) -> bool {
        if let Some(diagnostic) = unsupported_reserved_type_diagnostic(self.file, form) {
            self.errors.push(diagnostic);
            true
        } else {
            false
        }
    }

    fn write_indented_rendered(&mut self, indent: &str, rendered: &str) {
        push_indented(&mut self.output, indent, rendered);
    }

    fn take_comments_before(&mut self, offset: usize) -> Vec<LineComment> {
        let start = self.next_comment;
        while self
            .comments
            .get(self.next_comment)
            .is_some_and(|comment| comment.start < offset)
        {
            self.next_comment += 1;
        }
        self.comments[start..self.next_comment].to_vec()
    }

    fn take_remaining_comments(&mut self) -> Vec<LineComment> {
        let comments = self.comments[self.next_comment..].to_vec();
        self.next_comment = self.comments.len();
        comments
    }

    fn write_comments(&mut self, comments: &[LineComment], indent: &str) {
        for comment in comments {
            self.output.push_str(indent);
            self.output.push_str(&comment.text);
            self.output.push('\n');
        }
    }

    fn reject_comments_before(&mut self, offset: usize, message: &'static str) {
        let comments = self.take_comments_before(offset);
        for comment in comments {
            self.errors.push(
                Diagnostic::new(self.file, "UnsupportedFormatterComment", message)
                    .with_span(comment.span)
                    .hint(
                        "move the full-line comment between body expressions or outside the form",
                    ),
            );
        }
    }
}

#[derive(Clone, Debug)]
struct LineComment {
    start: usize,
    span: Span,
    text: String,
    full_line: bool,
}

struct RenderedType {
    text: String,
    is_array: bool,
}

struct RenderedMatchPattern<'a> {
    kind: &'a str,
    binding: Option<&'a str>,
    text: String,
}

fn collect_function_names(forms: &[SExpr]) -> HashSet<String> {
    let mut names = HashSet::new();
    for form in forms {
        let Some(items) = expect_list(form) else {
            continue;
        };
        match items.first() {
            Some(head) if is_ident(head, "fn") => {
                if let Some(name) = items.get(1).and_then(expect_ident) {
                    names.insert(name.to_string());
                }
            }
            Some(head) if is_ident(head, "import_c") => {
                if let Some(name) = items.get(1).and_then(expect_ident) {
                    names.insert(name.to_string());
                }
            }
            Some(head) if is_ident(head, "import") => {
                if let Some(imports) = items.get(2).and_then(expect_list) {
                    for import in imports {
                        if let Some(name) = expect_ident(import) {
                            names.insert(name.to_string());
                        }
                    }
                }
            }
            _ => {}
        }
    }
    names
}

fn collect_struct_names(forms: &[SExpr]) -> HashSet<String> {
    forms
        .iter()
        .filter_map(|form| {
            let items = expect_list(form)?;
            if !is_ident(items.first()?, "struct") {
                return None;
            }
            expect_ident(items.get(1)?).map(str::to_string)
        })
        .collect()
}

fn collect_enum_names(forms: &[SExpr]) -> HashSet<String> {
    forms
        .iter()
        .filter_map(|form| {
            let items = expect_list(form)?;
            if !is_ident(items.first()?, "enum") {
                return None;
            }
            expect_ident(items.get(1)?).map(str::to_string)
        })
        .collect()
}

fn collect_type_alias_names(forms: &[SExpr]) -> HashSet<String> {
    forms
        .iter()
        .filter_map(|form| {
            let items = expect_list(form)?;
            if !is_ident(items.first()?, "type") {
                return None;
            }
            expect_ident(items.get(1)?).map(str::to_string)
        })
        .collect()
}

fn qualified_enum_name(name: &str) -> Option<(&str, &str)> {
    let (enum_name, variant) = name.split_once('.')?;
    if enum_name.is_empty() || variant.is_empty() || variant.contains('.') {
        return None;
    }
    Some((enum_name, variant))
}

fn collect_comments(source: &str) -> Vec<LineComment> {
    let mut comments = Vec::new();
    let bytes = source.as_bytes();
    let mut line_start = 0;
    let mut i = 0;
    let mut in_string = false;
    let mut escaped = false;

    while i < bytes.len() {
        let byte = bytes[i];

        if in_string {
            if escaped {
                escaped = false;
                i += 1;
                continue;
            }

            match byte {
                b'\\' => {
                    escaped = true;
                    i += 1;
                }
                b'"' => {
                    in_string = false;
                    i += 1;
                }
                b'\n' => {
                    line_start = i + 1;
                    i += 1;
                }
                _ => i += 1,
            }
            continue;
        }

        match byte {
            b'"' => {
                in_string = true;
                i += 1;
            }
            b'\n' => {
                line_start = i + 1;
                i += 1;
            }
            b';' => {
                let comment_start = i;
                let mut comment_end = i;
                while comment_end < bytes.len() && bytes[comment_end] != b'\n' {
                    comment_end += 1;
                }

                let trimmed_end = trim_ascii_horizontal_end(source, comment_start, comment_end);
                let full_line = source[line_start..comment_start]
                    .bytes()
                    .all(|prefix| matches!(prefix, b' ' | b'\t'));
                let text = if full_line {
                    source[comment_start..trimmed_end].to_string()
                } else {
                    String::new()
                };

                comments.push(LineComment {
                    start: comment_start,
                    span: Span::new(comment_start, trimmed_end),
                    text,
                    full_line,
                });

                i = comment_end;
            }
            _ => i += 1,
        }
    }

    comments
}

fn trim_ascii_horizontal_end(source: &str, start: usize, mut end: usize) -> usize {
    let bytes = source.as_bytes();
    while end > start && matches!(bytes[end - 1], b' ' | b'\t') {
        end -= 1;
    }
    end
}

fn unsupported_non_full_line_comment(file: &str, span: Span) -> Diagnostic {
    Diagnostic::new(
        file,
        "UnsupportedFormatterComment",
        "formatter supports comments only as full-line comments in stable positions",
    )
    .with_span(span)
    .hint(
        "move the comment to its own line before a top-level form, between body expressions, or after the final top-level form",
    )
}

fn list_head(form: &SExpr) -> Option<&str> {
    let items = expect_list(form)?;
    let first = items.first()?;
    expect_ident(first)
}

fn render_option_result_type(
    items: &[SExpr],
    type_alias_names: &HashSet<String>,
) -> Option<String> {
    if items.len() == 2 && is_ident(&items[0], "option") {
        let payload = render_payload_type_atom(&items[1], type_alias_names)?;
        return Some(format!("(option {})", payload));
    }

    if items.len() == 3 && is_ident(&items[0], "result") {
        let ok = render_payload_type_atom(&items[1], type_alias_names)?;
        let err = render_result_err_type_atom(&items[2], type_alias_names)?;
        return Some(format!("(result {} {})", ok, err));
    }

    None
}

fn render_supported_array_constructor_type(
    form: &SExpr,
    struct_names: &HashSet<String>,
    enum_names: &HashSet<String>,
    type_alias_names: &HashSet<String>,
) -> Option<String> {
    render_direct_type_atom(form, struct_names, enum_names, type_alias_names)
}

fn render_supported_array_type(
    items: &[SExpr],
    struct_names: &HashSet<String>,
    enum_names: &HashSet<String>,
    type_alias_names: &HashSet<String>,
) -> Option<String> {
    if items.len() != 3 || !is_ident(&items[0], "array") {
        return None;
    }

    let elem_ty = render_supported_array_constructor_type(
        &items[1],
        struct_names,
        enum_names,
        type_alias_names,
    )?;
    let len = expect_int(&items[2])?;
    if len <= 0 {
        return None;
    }

    Some(format!("(array {} {})", elem_ty, len))
}

fn render_supported_vec_type(
    items: &[SExpr],
    type_alias_names: &HashSet<String>,
) -> Option<String> {
    if items.len() == 2 && is_ident(&items[0], "vec") {
        if is_ident(&items[1], "i32") {
            return Some("(vec i32)".to_string());
        }
        if is_ident(&items[1], "i64") {
            return Some("(vec i64)".to_string());
        }
        if is_ident(&items[1], "f64") {
            return Some("(vec f64)".to_string());
        }
        if is_ident(&items[1], "bool") {
            return Some("(vec bool)".to_string());
        }
        if is_ident(&items[1], "string") {
            return Some("(vec string)".to_string());
        }
        if let Some(name) = expect_ident(&items[1]) {
            if type_alias_names.contains(name) {
                return Some(format!("(vec {})", name));
            }
        }
    }

    None
}

fn render_payload_type_atom(form: &SExpr, type_alias_names: &HashSet<String>) -> Option<String> {
    if is_ident(form, "i32") {
        Some("i32".to_string())
    } else if is_ident(form, "i64") {
        Some("i64".to_string())
    } else if is_ident(form, "u32") {
        Some("u32".to_string())
    } else if is_ident(form, "u64") {
        Some("u64".to_string())
    } else if is_ident(form, "f64") {
        Some("f64".to_string())
    } else if is_ident(form, "bool") {
        Some("bool".to_string())
    } else if is_ident(form, "string") {
        Some("string".to_string())
    } else if let Some(name) = expect_ident(form) {
        type_alias_names.contains(name).then(|| name.to_string())
    } else {
        None
    }
}

fn render_result_err_type_atom(form: &SExpr, type_alias_names: &HashSet<String>) -> Option<String> {
    if is_ident(form, "i32") {
        Some("i32".to_string())
    } else if let Some(name) = expect_ident(form) {
        type_alias_names.contains(name).then(|| name.to_string())
    } else {
        None
    }
}

fn render_direct_type_atom(
    form: &SExpr,
    struct_names: &HashSet<String>,
    enum_names: &HashSet<String>,
    type_alias_names: &HashSet<String>,
) -> Option<String> {
    if let Some(text) = render_payload_type_atom(form, type_alias_names) {
        return Some(text);
    }

    let name = expect_ident(form)?;
    if struct_names.contains(name) || enum_names.contains(name) {
        Some(name.to_string())
    } else {
        None
    }
}

fn expect_list(form: &SExpr) -> Option<&[SExpr]> {
    match &form.kind {
        SExprKind::List(items) => Some(items),
        _ => None,
    }
}

fn expect_ident(form: &SExpr) -> Option<&str> {
    match &form.kind {
        SExprKind::Atom(Atom::Ident(name)) => Some(name.as_str()),
        _ => None,
    }
}

fn expect_int(form: &SExpr) -> Option<i64> {
    match &form.kind {
        SExprKind::Atom(Atom::Int(value)) => Some(*value),
        _ => None,
    }
}

fn expect_string(form: &SExpr) -> Option<&str> {
    match &form.kind {
        SExprKind::Atom(Atom::String(value)) => Some(value.as_str()),
        _ => None,
    }
}

fn is_ident(form: &SExpr, expected: &str) -> bool {
    expect_ident(form).is_some_and(|actual| actual == expected)
}

fn is_c_symbol_name(value: &str) -> bool {
    let mut chars = value.chars();
    let Some(first) = chars.next() else {
        return false;
    };
    (first == '_' || first.is_ascii_alphabetic())
        && chars.all(|ch| ch == '_' || ch.is_ascii_alphanumeric())
}

fn is_local_body_form(form: &SExpr) -> bool {
    matches!(list_head(form), Some("let" | "var"))
}

fn is_sequential_test_body_form(form: &SExpr) -> bool {
    matches!(list_head(form), Some("let" | "var" | "set" | "while"))
}

fn push_indented(output: &mut String, indent: &str, rendered: &str) {
    for (index, line) in rendered.split('\n').enumerate() {
        if index > 0 {
            output.push('\n');
        }
        output.push_str(indent);
        output.push_str(line);
    }
}

fn is_valid_test_name(name: &str) -> bool {
    !name.is_empty()
        && name
            .bytes()
            .all(|byte| matches!(byte, 0x20..=0x7e) && byte != b'"' && byte != b'\\')
}

fn render_string_literal(value: &str) -> String {
    let mut output = String::from("\"");
    for ch in value.chars() {
        match ch {
            '"' => output.push_str("\\\""),
            '\\' => output.push_str("\\\\"),
            '\n' => output.push_str("\\n"),
            '\t' => output.push_str("\\t"),
            ch if ch.is_control() => output.extend(ch.escape_default()),
            ch => output.push(ch),
        }
    }
    output.push('"');
    output
}

fn render_float_literal(value: f64) -> String {
    let rendered = value.to_string();
    if rendered.contains('.') || rendered.contains('e') || rendered.contains('E') {
        rendered
    } else {
        format!("{}.0", rendered)
    }
}
