1use std::collections::BTreeMap;
8use std::fmt::{self, Debug, Display, Formatter};
9use std::ops::Shl;
10
11use tracing::{Level, event};
12
13use base::{
14 charset::Script,
15 prelude::{Address, IndexBy, Unsigned18Bit, Unsigned36Bit},
16 subword,
17};
18#[cfg(test)]
19use base::{u18, u36};
20
21use super::ast::{Equality, Origin, RcUpdater};
22use super::collections::OneOrMore;
23use super::memorymap::{
24 BlockPosition, MemoryMap, RcAllocator, RcWordAllocationFailure, RcWordSource,
25};
26use super::source::Source;
27#[cfg(test)]
28use super::span::{OrderableSpan, span};
29use super::span::{Span, Spanned};
30#[cfg(test)]
31use super::symbol::AddressUse;
32use super::symbol::{ConfigUse, IndexUse, OriginUse, SymbolName};
33
34use super::types::{AssemblerFailure, BlockIdentifier, MachineLimitExceededFailure, ProgramError};
35use crate::symbol::SymbolContext;
36use crate::symtab::{
37 ExplicitDefinition, ExplicitSymbolTable, FinalSymbolDefinition, FinalSymbolTable,
38 FinalSymbolType, ImplicitDefinition, ImplicitSymbolTable, IndexRegisterAssigner,
39 LookupOperation, TagDefinition, record_undefined_symbol_or_return_failure,
40};
41
42#[derive(Debug, PartialEq, Eq, Clone, Hash)]
48pub(crate) struct ExhaustedIndexRegisters {
49 span: Span,
51 name: SymbolName,
53}
54
55#[derive(Debug, PartialEq, Eq)]
58pub(crate) enum EvaluationFailure {
59 SymbolDefinitionLoop {
63 span: Span,
64 deps_in_order: OneOrMore<SymbolName>,
65 },
66 BlockTooLarge(Span, MachineLimitExceededFailure),
68 FailedToAssignIndexRegister(ExhaustedIndexRegisters),
71
72 HereIsNotAllowedHere(Span),
75}
76
77impl Spanned for EvaluationFailure {
78 fn span(&self) -> Span {
79 match self {
80 EvaluationFailure::HereIsNotAllowedHere(span)
81 | EvaluationFailure::FailedToAssignIndexRegister(ExhaustedIndexRegisters {
82 span,
83 ..
84 })
85 | EvaluationFailure::SymbolDefinitionLoop { span, .. }
86 | EvaluationFailure::BlockTooLarge(span, _) => *span,
87 }
88 }
89}
90
91impl Display for EvaluationFailure {
92 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
93 match self {
94 EvaluationFailure::SymbolDefinitionLoop {
95 deps_in_order,
96 span: _,
97 } => {
98 let names: Vec<String> = deps_in_order.iter().map(ToString::to_string).collect();
99 write!(
100 f,
101 "definition of {} has a dependency loop ({})",
102 deps_in_order.first(),
103 names.join("->")
104 )
105 }
106 EvaluationFailure::FailedToAssignIndexRegister(ExhaustedIndexRegisters {
107 name,
108 ..
109 }) => {
110 write!(
111 f,
112 "unable to assign index register as the default value for symbol {name} because there are not enough index registers"
113 )
114 }
115 EvaluationFailure::BlockTooLarge(_span, mle) => {
116 write!(f, "program block too large: {mle}")
117 }
118 EvaluationFailure::HereIsNotAllowedHere(_) => {
119 f.write_str("'#' (representing the current address) is not allowed here")
120 }
121 }
122 }
123}
124
125impl EvaluationFailure {
126 pub(crate) fn into_program_error(self) -> ProgramError {
130 match self {
131 EvaluationFailure::FailedToAssignIndexRegister(ExhaustedIndexRegisters {
132 span,
133 name,
134 }) => ProgramError::FailedToAssignIndexRegister(span, name),
135 EvaluationFailure::BlockTooLarge(span, mle) => ProgramError::BlockTooLong(span, mle),
136 EvaluationFailure::SymbolDefinitionLoop {
137 deps_in_order,
138 span,
139 } => ProgramError::SymbolDefinitionLoop {
140 symbol_names: deps_in_order,
141 span,
142 },
143 EvaluationFailure::HereIsNotAllowedHere(span) => ProgramError::SyntaxError {
144 span,
145 msg: "# is not allowed in this context".to_string(),
146 },
147 }
148 }
149}
150
151impl std::error::Error for EvaluationFailure {}
152
153#[derive(Debug, PartialEq, Eq, Clone, Copy)]
156pub(crate) enum HereValue {
157 Address(Address),
159 NotAllowed,
162}
163
164impl HereValue {
165 pub(crate) fn get_address(self, span: &Span) -> Result<Address, EvaluationFailure> {
166 match self {
167 HereValue::Address(addr) => Ok(addr),
168 HereValue::NotAllowed => Err(EvaluationFailure::HereIsNotAllowedHere(*span)),
169 }
170 }
171}
172
173fn assign_default_value(
176 index_register_assigner: &mut IndexRegisterAssigner,
177 name: &SymbolName,
178 contexts_used: &SymbolContext,
179) -> Result<Unsigned36Bit, ExhaustedIndexRegisters> {
180 event!(
181 Level::DEBUG,
182 "assigning default value for {name} used in contexts {contexts_used:?}"
183 );
184 let span: Span = *contexts_used.any_span();
185 match &contexts_used.origin {
186 OriginUse::IncludesOrigin(_block, _origin) => {
187 unreachable!(
188 "assign_default_value should not be called for origin specifications; attempted to assign default value for {name} (used in contexts: {contexts_used:?}"
189 )
190 }
191 OriginUse::NotOrigin { config, index } => match (config, index) {
192 (ConfigUse::NotConfig, IndexUse::NotIndex) => {
193 if contexts_used.is_address() {
194 unreachable!(
199 "default assignments for address-context symexes should be assigned before evaluation starts"
200 )
201 }
202 unreachable!(
203 "attempted to assign a default value for a symbol {name} which appears not to be used in any context at all"
204 )
205 }
206 (ConfigUse::IncludesConfig, _) => Ok(Unsigned36Bit::ZERO),
207 (ConfigUse::NotConfig, IndexUse::IncludesIndex) => {
208 match index_register_assigner.assign_index_register() {
211 Some(n) => Ok(n.into()),
212 None => Err(ExhaustedIndexRegisters {
213 span,
214 name: name.clone(),
215 }),
216 }
217 }
218 },
219 }
220}
221
222#[derive(Debug)]
230pub(crate) struct EvaluationContext<'s, R: RcUpdater> {
231 pub(crate) here: HereValue,
233 pub(crate) explicit_symtab: &'s ExplicitSymbolTable,
235 pub(crate) implicit_symtab: &'s mut ImplicitSymbolTable,
238 pub(crate) index_register_assigner: &'s mut IndexRegisterAssigner,
240 pub(crate) memory_map: &'s MemoryMap,
242 pub(crate) rc_updater: &'s mut R,
244 pub(crate) lookup_operation: LookupOperation,
246}
247
248impl<R: RcUpdater> EvaluationContext<'_, R> {
249 pub(super) fn fetch_or_assign_default(
253 &mut self,
254 name: &SymbolName,
255 ) -> Result<Unsigned36Bit, EvaluationFailure> {
256 let existing_def: &mut ImplicitDefinition = match self.implicit_symtab.get_mut(name) {
257 Some(def) => def,
258 None => {
259 panic!("attempted to assign a default value for an entirely unknown symbol {name}");
264 }
265 };
266
267 match existing_def {
268 ImplicitDefinition::DefaultAssigned(value, _) => Ok(*value),
269 ImplicitDefinition::Undefined(_) => {
270 let saved_def = existing_def.clone();
271 let context: SymbolContext = existing_def.context().clone();
272 let span: Span = *context.any_span();
273
274 if let Some((block_identifier, _origin)) = context.get_origin() {
278 if let Some(block_position) = self.memory_map.get(&block_identifier).cloned() {
279 let position_without_origin = BlockPosition {
288 origin: None,
289 ..block_position
290 };
291 match position_without_origin.evaluate(self, ScopeIdentifier::global()) {
292 Ok(value) => {
293 let address: Address = subword::right_half(value).into();
294 match self.implicit_symtab.record_deduced_origin_value(
295 name,
296 address,
297 block_identifier,
298 span,
299 ) {
300 Ok(()) => Ok(value),
301 Err(e) => {
302 dbg!(saved_def);
303 panic!(
304 "got a bad symbol definition error ({e:?}) on a previously undefined origin symbol {name}"
305 );
306 }
307 }
308 }
309 Err(e) => Err(e),
310 }
311 } else {
312 unreachable!(
313 "symbol {name} was used as an origin for block {block_identifier} but this is not a known block"
314 );
315 }
316 } else {
317 match assign_default_value(self.index_register_assigner, name, &context) {
318 Ok(value) => {
319 *existing_def = ImplicitDefinition::DefaultAssigned(value, context);
320 Ok(value)
321 }
322 Err(e) => Err(EvaluationFailure::FailedToAssignIndexRegister(e)),
323 }
324 }
325 }
326 }
327 }
328}
329
330#[test]
331fn can_deduce_address_of_origin_with_previous_forward_reference() {
332 const BLOCK0_SIZE: Unsigned18Bit = u18!(4);
336 const BLOCK1_SIZE: Unsigned18Bit = u18!(3);
337 let origin_name = SymbolName::from("INPUT");
338 let origin_def = Origin::Symbolic(span(2455..2461), origin_name.clone());
339 let block0_pos = BlockPosition {
340 block_identifier: BlockIdentifier::from(0),
341 span: span(0..2400),
346 origin: None,
347 block_address: None,
348 block_size: BLOCK0_SIZE,
349 };
350 let block1_pos = BlockPosition {
351 block_identifier: BlockIdentifier::from(1),
352 span: span(2455..2800),
353 origin: None,
354 block_address: None,
355 block_size: BLOCK1_SIZE,
356 };
357
358 let mut implicit_symtab = ImplicitSymbolTable::default();
359 implicit_symtab.load_test_definitions([(
360 origin_name.clone(),
361 ImplicitDefinition::Undefined(SymbolContext {
362 address: AddressUse::IncludesAddress,
363 origin: OriginUse::IncludesOrigin(block1_pos.block_identifier, origin_def.clone()),
364 uses: [
365 OrderableSpan(span(1188..1193)),
367 OrderableSpan(span(block1_pos.span.start..(block1_pos.span.start + 6))),
371 OrderableSpan(span(3059..3064)),
375 ]
376 .into_iter()
377 .collect(),
378 }),
379 )]);
380
381 let explicit_symtab = ExplicitSymbolTable::default();
382 let mut register_assigner = IndexRegisterAssigner::default();
383 let mut memory_map = MemoryMap::new([
384 (span(0..10), None, BLOCK0_SIZE),
385 (
386 span(2455..2461),
387 Some(Origin::Symbolic(span(2455..2461), origin_name.clone())),
388 BLOCK1_SIZE,
389 ),
390 ]);
391 let mut rc_block = RcBlock::default();
392 let mut context = EvaluationContext {
393 here: HereValue::Address(Address::from(u18!(0o100))),
394 explicit_symtab: &explicit_symtab,
395 implicit_symtab: &mut implicit_symtab,
396 index_register_assigner: &mut register_assigner,
397 memory_map: &memory_map,
398 rc_updater: &mut rc_block,
399 lookup_operation: LookupOperation::default(),
400 };
401 let scope = ScopeIdentifier::global();
402
403 let block0_addr = block0_pos
405 .evaluate(&mut context, scope)
406 .expect("should be able to assign an address to the first block");
407 drop(context); memory_map.set_block_position(
409 block0_pos.block_identifier,
410 subword::right_half(block0_addr).into(),
411 );
412
413 let mut context = EvaluationContext {
415 here: HereValue::Address(Address::from(u18!(0o100))),
416 explicit_symtab: &explicit_symtab,
417 implicit_symtab: &mut implicit_symtab,
418 index_register_assigner: &mut register_assigner,
419 memory_map: &memory_map,
420 rc_updater: &mut rc_block,
421 lookup_operation: LookupOperation::default(),
422 };
423 let eval_result = context.fetch_or_assign_default(&origin_name);
424
425 match eval_result {
427 Err(e) => {
428 panic!("should not fail to assign a start address to a block: {e}");
429 }
430 Ok(default_value) => {
431 let expected: Unsigned36Bit =
432 u36!(0o200_000).wrapping_add(Unsigned36Bit::from(BLOCK0_SIZE));
433 assert_eq!(default_value, expected);
434 }
435 }
436}
437
438impl<R: RcUpdater> EvaluationContext<'_, R> {
439 pub(super) fn for_target_address<F, T>(&mut self, new_here: HereValue, mut closure: F) -> T
440 where
441 F: FnMut(&mut EvaluationContext<'_, R>) -> T,
442 {
443 let old_here = self.here;
444 self.here = new_here;
445 let output = closure(self);
446 self.here = old_here;
447 output
448 }
449}
450
451#[derive(Debug, PartialEq, Eq, Clone, Hash, Ord, PartialOrd, Copy)]
458pub(super) struct ScopeIdentifier(());
459
460impl ScopeIdentifier {
461 pub(super) fn global() -> ScopeIdentifier {
462 ScopeIdentifier(())
463 }
464}
465
466pub(super) trait Evaluate: Spanned {
473 fn evaluate<R: RcUpdater>(
476 &self,
477 ctx: &mut EvaluationContext<R>,
478 scope: ScopeIdentifier,
479 ) -> Result<Unsigned36Bit, EvaluationFailure>;
480}
481
482#[derive(Debug, Default, Clone)]
486pub(crate) struct RcBlock {
487 pub(crate) address: Address,
489 pub(crate) words: Vec<(RcWordSource, Unsigned36Bit)>,
492}
493
494impl RcBlock {
495 fn end(&self) -> Option<Address> {
496 match Unsigned18Bit::try_from(self.words.len()) {
497 Ok(offset) => Some(self.address.index_by(offset)),
498 Err(_) => None,
499 }
500 }
501}
502
503impl RcAllocator for RcBlock {
504 fn allocate(
505 &mut self,
506 source: RcWordSource,
507 value: Unsigned36Bit,
508 ) -> Result<Address, RcWordAllocationFailure> {
509 if let Some(addr) = self.end() {
510 self.words.push((source, value));
511 Ok(addr)
512 } else {
513 Err(RcWordAllocationFailure::RcBlockTooBig {
514 source,
515 rc_block_len: self.words.len(),
516 })
517 }
518 }
519}
520
521impl RcUpdater for RcBlock {
522 fn update(&mut self, address: Address, value: Unsigned36Bit) {
523 assert!(
524 address >= self.address,
525 "out of range access to address {address} of RC-block starting at {}",
526 self.address
527 );
528 match Unsigned18Bit::from(address).checked_sub(Unsigned18Bit::from(self.address)) {
529 Some(offset) => match self.words.get_mut(usize::from(offset)) {
530 Some((_source, spot)) => {
531 *spot = value;
532 }
533 None => {
534 panic!(
535 "out of range access to offset {offset} of RC-block having length {}",
536 self.words.len()
537 );
538 }
539 },
540 None => {
541 panic!(
543 "inconsistent checks; {address:o} should be greater than {:o}",
544 self.address
545 );
546 }
547 }
548 }
549}
550
551#[cfg(test)]
552pub(crate) fn make_empty_rc_block_for_test(location: Address) -> RcBlock {
553 RcBlock {
554 address: location,
555 words: Vec::new(),
556 }
557}
558
559fn evaluate_normal_symbol<R: RcUpdater>(
561 name: &SymbolName,
562 span: Span,
563 ctx: &mut EvaluationContext<R>,
564 scope: ScopeIdentifier,
565) -> Result<Unsigned36Bit, EvaluationFailure> {
566 ctx.lookup_operation.deps_in_order.push(name.clone());
567 if !ctx.lookup_operation.depends_on.insert(name.clone()) {
568 if let Ok(deps_in_order) =
571 OneOrMore::try_from_vec(ctx.lookup_operation.deps_in_order.clone())
572 {
573 return Err(EvaluationFailure::SymbolDefinitionLoop {
574 span,
575 deps_in_order,
576 });
577 }
578 panic!("we know deps_in_order is non-empty because we just appended an item to it");
579 }
580
581 let result = if let Some(def) = ctx.explicit_symtab.get(name) {
582 let what: (&Span, &SymbolName, &ExplicitDefinition) = (&span, name, def);
583 what.evaluate(ctx, scope)
584 } else {
585 ctx.fetch_or_assign_default(name)
586 };
587
588 ctx.lookup_operation.deps_in_order.pop();
589 ctx.lookup_operation.depends_on.remove(name);
590 result
591}
592
593pub(crate) fn evaluate_elevated_symbol<R: RcUpdater>(
598 name: &SymbolName,
599 elevation: Script,
600 span: Span,
601 ctx: &mut EvaluationContext<R>,
602 scope: ScopeIdentifier,
603) -> Result<Unsigned36Bit, EvaluationFailure> {
604 evaluate_normal_symbol(name, span, ctx, scope).map(|value| value.shl(elevation.shift()))
605}
606
607#[allow(clippy::too_many_arguments)]
616pub(super) fn extract_final_equalities<R: RcUpdater>(
617 equalities: &[Equality],
618 body: &Source,
619 explicit_symbols: &ExplicitSymbolTable,
620 implicit_symbols: &mut ImplicitSymbolTable,
621 memory_map: &MemoryMap,
622 index_register_assigner: &mut IndexRegisterAssigner,
623 rc_allocator: &mut R,
624 final_symbols: &mut FinalSymbolTable,
625 bad_symbol_definitions: &mut BTreeMap<SymbolName, ProgramError>,
626) -> Result<(), AssemblerFailure> {
627 for eq in equalities {
628 let mut ctx = EvaluationContext {
629 explicit_symtab: explicit_symbols,
630 implicit_symtab: implicit_symbols,
631 memory_map,
632 here: HereValue::NotAllowed,
633 index_register_assigner,
634 rc_updater: rc_allocator,
635 lookup_operation: Default::default(),
636 };
637 let scope = ScopeIdentifier::global();
638
639 match eq.value.evaluate(&mut ctx, scope) {
640 Ok(value) => {
641 final_symbols.define(
642 eq.name.clone(),
643 FinalSymbolType::Equality,
644 body.extract(eq.span.start..eq.span.end).to_string(),
645 FinalSymbolDefinition::PositionIndependent(value),
646 );
647 }
648 Err(EvaluationFailure::HereIsNotAllowedHere(_)) => {
649 final_symbols.define(
653 eq.name.clone(),
654 FinalSymbolType::Equality,
655 body.extract(eq.span.start..eq.span.end).to_string(),
656 FinalSymbolDefinition::PositionDependent,
657 );
658 }
659 Err(e) => {
660 record_undefined_symbol_or_return_failure(body, e, bad_symbol_definitions)?;
661 }
662 }
663 }
664 Ok(())
665}
666
667impl Spanned for (&BlockIdentifier, &Option<Origin>, &Span) {
668 fn span(&self) -> Span {
669 *self.2
670 }
671}
672
673#[derive(Debug)]
675struct AddressOverflow(pub(crate) Address, pub(crate) Unsigned18Bit);
676
677impl std::error::Error for AddressOverflow {}
678
679impl Display for AddressOverflow {
680 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
681 write!(
682 f,
683 "Adding {:o} to {:o} would generate a result which doesn't fit into an 18-bit address",
684 self.0, self.1
685 )
686 }
687}
688
689fn offset_from_origin(origin: Address, offset: Unsigned18Bit) -> Result<Address, AddressOverflow> {
691 let (physical, _mark) = origin.split();
692 match physical.checked_add(offset) {
693 Some(total) => Ok(Address::from(total)),
694 None => Err(AddressOverflow(origin, offset)),
695 }
696}
697
698impl Evaluate for BlockPosition {
699 fn evaluate<R: RcUpdater>(
700 &self,
701 ctx: &mut EvaluationContext<R>,
702 scope: ScopeIdentifier,
703 ) -> Result<Unsigned36Bit, EvaluationFailure> {
704 if let Some(origin) = self.origin.as_ref() {
707 return origin.evaluate(ctx, scope);
708 }
709
710 let previous_block_id: BlockIdentifier = match self.block_identifier.previous_block() {
715 None => {
716 return Ok(Origin::default_address().into());
718 }
719 Some(id) => id,
720 };
721
722 let (prev_addr, prev_size, prev_span): (Address, Unsigned18Bit, Span) =
724 if let Some(previous_block) = ctx.memory_map.get(&previous_block_id).cloned() {
725 let address_of_previous_block: Address = previous_block
729 .block_address
730 .expect("blocks should be assigned addresses in ascending block order");
731 (
732 address_of_previous_block,
733 previous_block.block_size,
734 previous_block.span,
735 )
736 } else {
737 unreachable!("unknown block {previous_block_id}")
738 };
739
740 match offset_from_origin(prev_addr, prev_size) {
744 Ok(addr) => Ok(addr.into()),
745 Err(_) => {
746 Err(EvaluationFailure::BlockTooLarge(
752 prev_span,
753 MachineLimitExceededFailure::BlockTooLarge {
754 span: prev_span,
755 block_id: previous_block_id,
756 offset: prev_size.into(),
757 },
758 ))
759 }
760 }
761 }
762}
763
764impl Evaluate for (&Span, &SymbolName, &ExplicitDefinition) {
765 fn evaluate<R: RcUpdater>(
766 &self,
767 ctx: &mut EvaluationContext<R>,
768 scope: ScopeIdentifier,
769 ) -> Result<Unsigned36Bit, EvaluationFailure> {
770 let (_span, name, def): (&Span, &SymbolName, &ExplicitDefinition) = *self;
771 match def {
772 ExplicitDefinition::Origin(Origin::Symbolic(_span, name), _block_id) => {
773 unreachable!("symbolic origin {name} should already have been deduced")
774 }
775 ExplicitDefinition::Origin(Origin::Deduced(_span, _name, address), _block_id) => {
776 Ok((*address).into())
777 }
778 ExplicitDefinition::Origin(Origin::Literal(_span, address), _block_id) => {
779 Ok((*address).into())
780 }
781 ExplicitDefinition::Tag(TagDefinition::Resolved { span: _, address }) => {
782 Ok(address.into())
783 }
784 ExplicitDefinition::Tag(TagDefinition::Unresolved {
785 block_id,
786 block_offset,
787 span,
788 }) => {
789 if let Some(block_position) = ctx.memory_map.get(block_id).cloned() {
790 let block_origin: Address =
791 subword::right_half(block_position.evaluate(ctx, scope)?).into();
792 match offset_from_origin(block_origin, *block_offset) {
793 Ok(computed_address) => Ok(computed_address.into()),
794 Err(_overflow_error) => Err(EvaluationFailure::BlockTooLarge(
795 *span,
796 MachineLimitExceededFailure::BlockTooLarge {
797 span: *span,
798 block_id: *block_id,
799 offset: (*block_offset).into(),
800 },
801 )),
802 }
803 } else {
804 panic!(
805 "Tag named {name} at {span:?} refers to unknown block {block_id}: {def:?}"
806 );
807 }
808 }
809 ExplicitDefinition::Equality(expression) => expression.evaluate(ctx, scope),
810 }
811 }
812}