assembler/
listing.rs

1//! Emit assembly language listing, with a symbol table.
2use std::fmt::Display;
3
4use super::memorymap::{RcWordKind, RcWordSource};
5use super::source::Source;
6use super::span::Span;
7use super::symtab::FinalSymbolTable;
8use base::prelude::*;
9
10#[derive(Debug, Default)]
11pub(crate) struct Listing {
12    final_symbols: FinalSymbolTable,
13    output: Vec<ListingLine>,
14    rc_block: Vec<ListingLine>,
15}
16
17impl Listing {
18    pub(super) fn set_final_symbols(&mut self, final_symbols: FinalSymbolTable) {
19        self.final_symbols = final_symbols;
20    }
21
22    pub(super) fn push_line(&mut self, line: ListingLine) {
23        self.output.push(line);
24    }
25
26    pub(super) fn push_rc_line(&mut self, line: ListingLine) {
27        self.rc_block.push(line);
28    }
29
30    fn format_symbol_table(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        write!(f, "{}", self.final_symbols)
32    }
33}
34
35#[derive(Debug)]
36pub(super) struct ListingLine {
37    pub(super) span: Option<Span>,
38    pub(super) rc_source: Option<RcWordSource>,
39    pub(super) content: Option<(Address, Unsigned36Bit)>,
40}
41
42struct ListingLineWithBody<'a, 'b> {
43    line: &'a ListingLine,
44    body: &'b Source<'a>,
45}
46
47fn write_address(f: &mut std::fmt::Formatter<'_>, addr: Address) -> std::fmt::Result {
48    let addr_value: Unsigned18Bit = addr.into();
49    if addr_value & 0o7 == 0 {
50        write!(f, "{addr_value:>06o}")
51    } else {
52        write!(f, "   {:>03o}", addr_value & 0o777)
53    }
54}
55
56impl Display for ListingLineWithBody<'_, '_> {
57    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58        let source_span_to_print: Option<Span> = match self.line.span.as_ref() {
59            Some(span) => Some(*span),
60            None => self.line.rc_source.as_ref().map(|source| source.span),
61        };
62
63        if let Some(span) = source_span_to_print {
64            let s = self.body.extract(span.start..span.end).trim();
65            let prefix = self.body.extract_prefix(span.start);
66            write!(f, "{prefix}{s:54}")?;
67        } else if matches!(
68            &self.line.rc_source,
69            Some(RcWordSource {
70                kind: RcWordKind::DefaultAssignment,
71                ..
72            })
73        ) {
74            write!(f, "{:<54}", 0)?;
75        }
76
77        if let Some((address, word)) = self.line.content.as_ref() {
78            let (left, right) = split_halves(*word);
79            write!(f, " |{left:06} {right:06}| ")?;
80            write_address(f, *address)?;
81        }
82        Ok(())
83    }
84}
85
86pub(super) struct ListingWithBody<'a, 'b> {
87    pub(super) listing: &'a Listing,
88    pub(super) body: &'b Source<'a>,
89}
90
91impl Display for ListingWithBody<'_, '_> {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        fn write_listing_line(
94            f: &mut std::fmt::Formatter<'_>,
95            body: &Source,
96            line: &ListingLine,
97        ) -> std::fmt::Result {
98            writeln!(f, "{}", &ListingLineWithBody { line, body })
99        }
100
101        writeln!(f, "Symbol Table:")?;
102        self.listing.format_symbol_table(f)?;
103        writeln!(f)?;
104
105        writeln!(f, "Directive:")?;
106        for line in &self.listing.output {
107            write_listing_line(f, self.body, line)?;
108        }
109
110        if !self.listing.rc_block.is_empty() {
111            writeln!(f, "☛☛RC")?;
112            for line in &self.listing.rc_block {
113                write_listing_line(f, self.body, line)?;
114            }
115        }
116        Ok(())
117    }
118}