vhdl_lang 0.86.0

VHDL Language Frontend
Documentation
// This Source Code Form is subject to the terms of the Mozilla Public
// Lic// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// This Source Code Form is subject to the terms of the Mozilla Public
// You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2024, Olof Kraigher olof.kraigher@gmail.com

use crate::ast::ArchitectureBody;
use crate::formatting::buffer::Buffer;
use crate::formatting::VHDLFormatter;
use crate::{indented, HasTokenSpan, TokenSpan};

impl VHDLFormatter<'_> {
    pub fn format_architecture(&self, arch: &ArchitectureBody, buffer: &mut Buffer) {
        self.format_context_clause(&arch.context_clause, buffer);
        if let Some(item) = arch.context_clause.last() {
            self.line_break_preserve_whitespace(item.span().end_token, buffer);
        }
        let span = arch.span();
        // architecture <ident> of <ident> is
        self.format_token_span(TokenSpan::new(span.start_token, arch.is_token()), buffer);
        indented!(buffer, { self.format_declarations(&arch.decl, buffer) });
        buffer.line_break();
        self.format_token_id(arch.begin_token, buffer);
        indented!(buffer, {
            self.format_concurrent_statements(&arch.statements, buffer);
        });
        buffer.line_break();
        // end [architecture] [name];
        self.format_token_span(TokenSpan::new(arch.end_token, span.end_token - 1), buffer);
        self.format_token_id(span.end_token, buffer);
    }
}

#[cfg(test)]
mod test {
    use crate::syntax::test::Code;
    use vhdl_lang::formatting::test_utils::check_formatted;

    fn check_architecture_formatted(input: &str) {
        check_formatted(
            input,
            input,
            Code::architecture_body,
            |formatter, arch, buffer| formatter.format_architecture(arch, buffer),
        )
    }

    #[test]
    fn format_empty_architecture() {
        check_architecture_formatted(
            "\
architecture foo of bar is
begin
end foo;",
        );

        check_architecture_formatted(
            "\
architecture foo of bar is
begin
end architecture foo;",
        );

        check_architecture_formatted(
            "\
architecture foo of bar is
begin
end;",
        );
    }

    #[test]
    fn format_architecture_with_declarations() {
        check_architecture_formatted(
            "\
architecture foo of bar is
    constant x: foo := bar;
begin
end foo;",
        );

        check_architecture_formatted(
            "\
architecture foo of bar is
    constant x: foo := bar;
    signal y: bar := foobar;
begin
end foo;",
        );
    }

    #[test]
    fn format_full_architecture() {
        check_architecture_formatted(
            "\
architecture foo of bar is
    constant x: foo := bar;
    signal y: bar := foobar;
begin
    bar: process(clk) is
        variable z: baz;
    begin
        if rising_edge(clk) then
            if rst = '1' then
                foo <= '0';
            else
                foo <= bar and baz;
            end if;
        end if;
    end process bar;
    y <= x; -- An assignment
end foo;",
        );
    }

    #[test]
    fn format_architecture_preserve_whitespace() {
        check_architecture_formatted(
            "\
architecture foo of bar is
    constant x: foo := bar;
    constant baz: char := '1';

    signal y: bar := foobar;
    signal foobar: std_logic := 'Z';

    shared variable sv: natural;
begin
end foo;",
        );
    }
}