assembler/
symtab.rs

1//! Explicit and implicit symbol definitions.
2use std::collections::BTreeMap;
3use std::collections::HashSet;
4use std::fmt::{self, Debug, Display, Formatter};
5
6use base::prelude::*;
7
8use super::ast::{EqualityValue, Origin};
9use super::collections::OneOrMore;
10use super::eval::EvaluationFailure;
11use super::memorymap::{RcAllocator, RcWordAllocationFailure, RcWordKind, RcWordSource};
12use super::source::Source;
13use super::span::{Span, Spanned};
14use super::symbol::{InconsistentSymbolUse, SymbolContext, SymbolName};
15use super::types::{AssemblerFailure, BlockIdentifier, ProgramError};
16
17#[derive(Debug, Default, PartialEq, Eq)]
18pub(crate) struct IndexRegisterAssigner {
19    index_registers_used: Unsigned6Bit,
20}
21
22impl IndexRegisterAssigner {
23    pub(crate) fn assign_index_register(&mut self) -> Option<Unsigned6Bit> {
24        // These start at 0, but we can't assign X0 (since it is
25        // always zero), and this is why we increment
26        // `index_registers_used` first.
27        if let Some(n) = self.index_registers_used.checked_add(u6!(1)) {
28            self.index_registers_used = n;
29            Some(n)
30        } else {
31            None
32        }
33    }
34
35    pub(crate) fn is_empty(&self) -> bool {
36        self.index_registers_used == 0
37    }
38}
39
40/// Implicit definitions (e.g. index, configuration and address
41/// values), including information about the usage of symbols for
42/// which we have not yet assigned a default value.
43///
44/// The rules for how symbols which have references but no explicit
45/// definition are assigned values are indicated in "Unassigned
46/// Symexes" in section 6-2.2 of the User Handbook.
47#[derive(Debug, Default, Clone, PartialEq, Eq)]
48pub(crate) struct ImplicitSymbolTable {
49    definitions: BTreeMap<SymbolName, ImplicitDefinition>,
50}
51
52impl ImplicitSymbolTable {
53    pub(super) fn symbols(&self) -> impl Iterator<Item = &SymbolName> {
54        self.definitions.keys()
55    }
56
57    pub(crate) fn get(&self, name: &SymbolName) -> Option<&ImplicitDefinition> {
58        self.definitions.get(name)
59    }
60
61    pub(super) fn get_mut(&mut self, name: &SymbolName) -> Option<&mut ImplicitDefinition> {
62        self.definitions.get_mut(name)
63    }
64
65    pub(crate) fn remove(&mut self, name: &SymbolName) -> Option<ImplicitDefinition> {
66        self.definitions.remove(name)
67    }
68
69    pub(crate) fn record_usage_context(
70        &mut self,
71        name: &SymbolName,
72        context: &SymbolContext,
73    ) -> Result<(), InconsistentSymbolUse> {
74        self.definitions
75            .entry(name.clone())
76            .or_insert_with(|| ImplicitDefinition::Undefined(context.clone()))
77            .merge_context(name, context.clone())
78    }
79
80    pub(super) fn record_deduced_origin_value(
81        &mut self,
82        name: &SymbolName,
83        value: Address,
84        block_id: BlockIdentifier,
85        span: Span,
86    ) -> Result<(), InconsistentSymbolUse> {
87        let context = SymbolContext::origin(block_id, Origin::Deduced(span, name.clone(), value));
88        self.definitions
89            .entry(name.clone())
90            .or_insert_with(|| ImplicitDefinition::DefaultAssigned(value.into(), context.clone()))
91            .merge_context(name, context)
92    }
93
94    #[cfg(test)]
95    pub(super) fn load_test_definitions<
96        I: IntoIterator<Item = (SymbolName, ImplicitDefinition)>,
97    >(
98        &mut self,
99        defs: I,
100    ) {
101        for (name, definition) in defs {
102            self.definitions.insert(name, definition);
103        }
104    }
105}
106
107#[derive(Debug, Default, Clone, PartialEq, Eq)]
108pub(crate) struct ExplicitSymbolTable {
109    definitions: BTreeMap<SymbolName, ExplicitDefinition>,
110}
111
112#[derive(Debug, Default)]
113pub(crate) struct LookupOperation {
114    pub(super) depends_on: HashSet<SymbolName>,
115    pub(super) deps_in_order: Vec<SymbolName>,
116}
117
118// TODO: check whether we still need this at all.
119impl Spanned for (&Span, &SymbolName, &ExplicitDefinition) {
120    fn span(&self) -> Span {
121        let r1: &Span = self.0;
122        let r2: Span = self.2.span();
123        assert_eq!(r1, &r2);
124        r2
125    }
126}
127
128impl ExplicitSymbolTable {
129    pub(crate) fn new() -> ExplicitSymbolTable {
130        ExplicitSymbolTable {
131            definitions: Default::default(),
132        }
133    }
134
135    pub(crate) fn get(&self, name: &SymbolName) -> Option<&ExplicitDefinition> {
136        self.definitions.get(name)
137    }
138
139    pub(crate) fn is_defined(&self, name: &SymbolName) -> bool {
140        self.definitions.contains_key(name)
141    }
142
143    pub(crate) fn define(
144        &mut self,
145        name: SymbolName,
146        new_definition: ExplicitDefinition,
147    ) -> Result<(), BadSymbolDefinition> {
148        if let Some(existing) = self.definitions.get_mut(&name) {
149            existing.override_with(name, new_definition)
150        } else {
151            self.definitions.insert(name, new_definition);
152            Ok(())
153        }
154    }
155    pub(crate) fn merge(
156        &mut self,
157        other: ExplicitSymbolTable,
158    ) -> Result<(), OneOrMore<BadSymbolDefinition>> {
159        let mut errors: Vec<BadSymbolDefinition> = Vec::new();
160        for (name, def) in other.definitions {
161            if let Err(e) = self.define(name, def) {
162                errors.push(e);
163            }
164        }
165        match OneOrMore::try_from_vec(errors) {
166            Ok(errors) => Err(errors),
167            Err(_) => Ok(()), // errors was empty
168        }
169    }
170}
171
172#[derive(Debug, PartialEq, Eq)]
173pub(crate) enum FinalSymbolType {
174    Tag,
175    Equality,
176    Default,
177}
178
179#[derive(Debug)]
180pub(crate) enum FinalSymbolDefinition {
181    PositionIndependent(Unsigned36Bit),
182    PositionDependent,
183}
184
185#[derive(Debug, Default)]
186pub(crate) struct FinalSymbolTable {
187    definitions: BTreeMap<SymbolName, (FinalSymbolType, String, FinalSymbolDefinition)>,
188}
189
190impl FinalSymbolTable {
191    pub(crate) fn define(
192        &mut self,
193        name: SymbolName,
194        sym_type: FinalSymbolType,
195        rep: String,
196        def: FinalSymbolDefinition,
197    ) {
198        self.definitions.insert(name, (sym_type, rep, def));
199    }
200
201    pub(crate) fn define_if_undefined(
202        &mut self,
203        name: SymbolName,
204        sym_type: FinalSymbolType,
205        rep: String,
206        def: FinalSymbolDefinition,
207    ) {
208        self.definitions.entry(name).or_insert((sym_type, rep, def));
209    }
210}
211
212impl Display for FinalSymbolTable {
213    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214        let show = |f: &mut std::fmt::Formatter<'_>,
215                    sym_type_wanted: FinalSymbolType,
216                    title: &str|
217         -> std::fmt::Result {
218            writeln!(f)?;
219            writeln!(f, "** {title}")?;
220            for (name, (_final_symbol_type, representation, definition)) in self
221                .definitions
222                .iter()
223                .filter(|(_, (symtype, _, _))| symtype == &sym_type_wanted)
224            {
225                match definition {
226                    FinalSymbolDefinition::PositionIndependent(word) => {
227                        writeln!(f, "{name:20} = {word:012} ** {representation:>20}")?;
228                    }
229                    FinalSymbolDefinition::PositionDependent => {
230                        writeln!(f, "{name:20} = {representation}")?;
231                    }
232                }
233            }
234            Ok(())
235        };
236
237        show(f, FinalSymbolType::Tag, "Tags")?;
238        show(f, FinalSymbolType::Equality, "Equalities")?;
239        show(f, FinalSymbolType::Default, "Default-assigned values")?;
240        Ok(())
241    }
242}
243
244#[derive(Debug, PartialEq, Eq, Clone)]
245pub(crate) enum TagDefinition {
246    Unresolved {
247        block_id: BlockIdentifier,
248        block_offset: Unsigned18Bit,
249        span: Span,
250    },
251    Resolved {
252        address: Address,
253        span: Span,
254    },
255}
256
257impl Spanned for TagDefinition {
258    fn span(&self) -> Span {
259        match self {
260            TagDefinition::Unresolved { span, .. } | TagDefinition::Resolved { span, .. } => *span,
261        }
262    }
263}
264
265impl Display for TagDefinition {
266    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
267        match self {
268            TagDefinition::Unresolved {
269                block_id,
270                block_offset,
271                span: _,
272            } => {
273                write!(
274                    f,
275                    "tag at offset {block_offset} in {block_id} with unspecified address"
276                )
277            }
278            TagDefinition::Resolved { address, span: _ } => {
279                write!(f, "tag with address {address:06o}")
280            }
281        }
282    }
283}
284
285#[derive(Debug, PartialEq, Eq, Clone)]
286pub(crate) enum ExplicitDefinition {
287    Tag(TagDefinition),
288    Equality(EqualityValue),
289    Origin(Origin, BlockIdentifier),
290}
291
292impl Spanned for ExplicitDefinition {
293    fn span(&self) -> Span {
294        match self {
295            ExplicitDefinition::Tag(tag_definition) => tag_definition.span(),
296            ExplicitDefinition::Equality(equality_value) => equality_value.span(),
297            ExplicitDefinition::Origin(origin, _block_identifier) => origin.span(),
298        }
299    }
300}
301
302impl Display for ExplicitDefinition {
303    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
304        match self {
305            ExplicitDefinition::Origin(origin, _block_identifier) => {
306                write!(f, "{origin}")
307            }
308            ExplicitDefinition::Tag(tagdef) => {
309                write!(f, "{tagdef}")
310            }
311            ExplicitDefinition::Equality(inst) => {
312                // TODO: print the assigned value, too?
313                write!(f, "assignment with value {inst:#?}")
314            }
315        }
316    }
317}
318
319impl ExplicitDefinition {
320    pub(crate) fn override_with(
321        &mut self,
322        name: SymbolName,
323        update: ExplicitDefinition,
324    ) -> Result<(), BadSymbolDefinition> {
325        match (self, update) {
326            (current @ ExplicitDefinition::Equality(_), new @ ExplicitDefinition::Equality(_)) => {
327                // This is always OK.
328                *current = new;
329                Ok(())
330            }
331            (current, new) => {
332                if current == &new {
333                    Ok(()) // nothing to do.
334                } else {
335                    Err(BadSymbolDefinition {
336                        symbol_name: name,
337                        span: new.span(),
338                        existing: Box::new(current.clone()),
339                        proposed: Box::new(new),
340                    })
341                }
342            }
343        }
344    }
345}
346
347#[derive(Debug, PartialEq, Eq, Clone)]
348pub(crate) enum ImplicitDefinition {
349    Undefined(SymbolContext),
350    DefaultAssigned(Unsigned36Bit, SymbolContext),
351}
352
353impl ImplicitDefinition {
354    pub(crate) fn context(&self) -> &SymbolContext {
355        match self {
356            ImplicitDefinition::Undefined(context)
357            | ImplicitDefinition::DefaultAssigned(_, context) => context,
358        }
359    }
360}
361
362impl Display for ImplicitDefinition {
363    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
364        match self {
365            ImplicitDefinition::Undefined(_context) => f.write_str("undefined"),
366            ImplicitDefinition::DefaultAssigned(value, _) => {
367                write!(f, "default-assigned as {value}")
368            }
369        }
370    }
371}
372
373#[derive(Debug, PartialEq, Eq, Clone)]
374pub(crate) struct BadSymbolDefinition {
375    /// Signals that an origin has been inconsistently defined, or a
376    /// tag has been defined in more than once place.
377    pub(crate) symbol_name: SymbolName,
378    pub(crate) span: Span,
379    // We box the two definitions here to reduce the (direct) size
380    // of the BadSymbolDefinition object itself.  Otherwise, this
381    // will give rise to large disparities between the Ok() and
382    // Err() variants of results that directly or indirectly
383    // include BadSymbolDefinition instances.
384    pub(crate) existing: Box<ExplicitDefinition>,
385    pub(crate) proposed: Box<ExplicitDefinition>,
386}
387
388impl Spanned for BadSymbolDefinition {
389    fn span(&self) -> Span {
390        self.span
391    }
392}
393
394impl Display for BadSymbolDefinition {
395    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
396        match (&*self.existing, &*self.proposed) {
397            (ExplicitDefinition::Tag(td1), ExplicitDefinition::Tag(td2)) => {
398                write!(
399                    f,
400                    "{0} is defined more than once, but this is not allowed for tags (tag defitions are {1} and {2})",
401                    &self.symbol_name, td1, td2
402                )
403            }
404            _ => {
405                write!(
406                    f,
407                    "it is not allowed to override the symbol definition of {0} as {1} with a new definition {2}",
408                    &self.symbol_name, &self.existing, &self.proposed
409                )
410            }
411        }
412    }
413}
414
415impl std::error::Error for BadSymbolDefinition {}
416
417impl ImplicitDefinition {
418    pub(crate) fn merge_context(
419        &mut self,
420        name: &SymbolName,
421        context: SymbolContext,
422    ) -> Result<(), InconsistentSymbolUse> {
423        match self {
424            ImplicitDefinition::Undefined(current) => current.merge(name, context),
425            ImplicitDefinition::DefaultAssigned(value, existing_context) => {
426                if &context == existing_context {
427                    Ok(())
428                } else {
429                    panic!(
430                        "attempting to change the recorded usage context for {name} after a default value {value:?} has been assigned; previous context was {existing_context:?}, new context is {context:?}"
431                    );
432                }
433            }
434        }
435    }
436}
437
438pub(super) fn assign_default_rc_word_tags<R: RcAllocator>(
439    implicit_symtab: &mut ImplicitSymbolTable,
440    rcblock: &mut R,
441    final_symbols: &mut FinalSymbolTable,
442) -> Result<(), RcWordAllocationFailure> {
443    for (name, def) in &mut implicit_symtab.definitions {
444        if let ImplicitDefinition::Undefined(context) = def
445            && context.requires_rc_word_allocation()
446        {
447            let span: Span = *context.any_span();
448            let value = Unsigned36Bit::ZERO;
449            let addr = rcblock.allocate(
450                RcWordSource {
451                    span,
452                    kind: RcWordKind::DefaultAssignment,
453                },
454                value,
455            )?;
456            final_symbols.define(
457                name.clone(),
458                FinalSymbolType::Equality,
459                value.to_string(),
460                FinalSymbolDefinition::PositionIndependent(value),
461            );
462            *def = ImplicitDefinition::DefaultAssigned(addr.into(), context.clone());
463        }
464    }
465    Ok(())
466}
467
468pub(super) fn record_undefined_symbol_or_return_failure(
469    source_file_body: &Source<'_>,
470    e: EvaluationFailure,
471    undefined_symbols: &mut BTreeMap<SymbolName, ProgramError>,
472) -> Result<(), AssemblerFailure> {
473    match e {
474        EvaluationFailure::SymbolDefinitionLoop {
475            span,
476            deps_in_order,
477            ..
478        } => {
479            undefined_symbols
480                .entry(deps_in_order.first().clone())
481                .or_insert_with(|| ProgramError::SymbolDefinitionLoop {
482                    symbol_names: deps_in_order,
483                    span,
484                });
485            Ok(())
486        }
487        other => Err(other
488            .into_program_error()
489            .into_assembler_failure(source_file_body)),
490    }
491}