1use 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}