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 } else {
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 }
207 (ConfigUse::IncludesConfig, _) => Ok(Unsigned36Bit::ZERO),
208 (ConfigUse::NotConfig, IndexUse::IncludesIndex) => {
209 match index_register_assigner.assign_index_register() {
212 Some(n) => Ok(n.into()),
213 None => Err(ExhaustedIndexRegisters {
214 span,
215 name: name.clone(),
216 }),
217 }
218 }
219 },
220 }
221}
222
223#[derive(Debug)]
231pub(crate) struct EvaluationContext<'s, R: RcUpdater> {
232 pub(crate) here: HereValue,
234 pub(crate) explicit_symtab: &'s ExplicitSymbolTable,
236 pub(crate) implicit_symtab: &'s mut ImplicitSymbolTable,
239 pub(crate) index_register_assigner: &'s mut IndexRegisterAssigner,
241 pub(crate) memory_map: &'s MemoryMap,
243 pub(crate) rc_updater: &'s mut R,
245 pub(crate) lookup_operation: LookupOperation,
247}
248
249impl<R: RcUpdater> EvaluationContext<'_, R> {
250 pub(super) fn fetch_or_assign_default(
254 &mut self,
255 name: &SymbolName,
256 ) -> Result<Unsigned36Bit, EvaluationFailure> {
257 let existing_def: &mut ImplicitDefinition = match self.implicit_symtab.get_mut(name) {
258 Some(def) => def,
259 None => {
260 panic!("attempted to assign a default value for an entirely unknown symbol {name}");
265 }
266 };
267
268 match existing_def {
269 ImplicitDefinition::DefaultAssigned(value, _) => Ok(*value),
270 ImplicitDefinition::Undefined(_) => {
271 let saved_def = existing_def.clone();
272 let context: SymbolContext = existing_def.context().clone();
273 let span: Span = *context.any_span();
274
275 if let Some((block_identifier, _origin)) = context.get_origin() {
279 if let Some(block_position) = self.memory_map.get(&block_identifier).cloned() {
280 let position_without_origin = BlockPosition {
289 origin: None,
290 ..block_position
291 };
292 match position_without_origin.evaluate(self, ScopeIdentifier::global()) {
293 Ok(value) => {
294 let address: Address = subword::right_half(value).into();
295 match self.implicit_symtab.record_deduced_origin_value(
296 name,
297 address,
298 block_identifier,
299 span,
300 ) {
301 Ok(()) => Ok(value),
302 Err(e) => {
303 dbg!(saved_def);
304 panic!(
305 "got a bad symbol definition error ({e:?}) on a previously undefined origin symbol {name}"
306 );
307 }
308 }
309 }
310 Err(e) => Err(e),
311 }
312 } else {
313 unreachable!(
314 "symbol {name} was used as an origin for block {block_identifier} but this is not a known block"
315 );
316 }
317 } else {
318 match assign_default_value(self.index_register_assigner, name, &context) {
319 Ok(value) => {
320 *existing_def = ImplicitDefinition::DefaultAssigned(value, context);
321 Ok(value)
322 }
323 Err(e) => Err(EvaluationFailure::FailedToAssignIndexRegister(e)),
324 }
325 }
326 }
327 }
328 }
329}
330
331#[test]
332fn can_deduce_address_of_origin_with_previous_forward_reference() {
333 const BLOCK0_SIZE: Unsigned18Bit = u18!(4);
337 const BLOCK1_SIZE: Unsigned18Bit = u18!(3);
338 let origin_name = SymbolName::from("INPUT");
339 let origin_def = Origin::Symbolic(span(2455..2461), origin_name.clone());
340 let block0_pos = BlockPosition {
341 block_identifier: BlockIdentifier::from(0),
342 span: span(0..2400),
347 origin: None,
348 block_address: None,
349 block_size: BLOCK0_SIZE,
350 };
351 let block1_pos = BlockPosition {
352 block_identifier: BlockIdentifier::from(1),
353 span: span(2455..2800),
354 origin: None,
355 block_address: None,
356 block_size: BLOCK1_SIZE,
357 };
358
359 let mut implicit_symtab = ImplicitSymbolTable::default();
360 implicit_symtab.load_test_definitions([(
361 origin_name.clone(),
362 ImplicitDefinition::Undefined(SymbolContext {
363 address: AddressUse::IncludesAddress,
364 origin: OriginUse::IncludesOrigin(block1_pos.block_identifier, origin_def.clone()),
365 uses: [
366 OrderableSpan(span(1188..1193)),
368 OrderableSpan(span(block1_pos.span.start..(block1_pos.span.start + 6))),
372 OrderableSpan(span(3059..3064)),
376 ]
377 .into_iter()
378 .collect(),
379 }),
380 )]);
381
382 let explicit_symtab = ExplicitSymbolTable::default();
383 let mut register_assigner = IndexRegisterAssigner::default();
384 let mut memory_map = MemoryMap::new([
385 (span(0..10), None, BLOCK0_SIZE),
386 (
387 span(2455..2461),
388 Some(Origin::Symbolic(span(2455..2461), origin_name.clone())),
389 BLOCK1_SIZE,
390 ),
391 ]);
392 let mut rc_block = RcBlock::default();
393 let mut context = EvaluationContext {
394 here: HereValue::Address(Address::from(u18!(0o100))),
395 explicit_symtab: &explicit_symtab,
396 implicit_symtab: &mut implicit_symtab,
397 index_register_assigner: &mut register_assigner,
398 memory_map: &memory_map,
399 rc_updater: &mut rc_block,
400 lookup_operation: LookupOperation::default(),
401 };
402 let scope = ScopeIdentifier::global();
403
404 let block0_addr = block0_pos
406 .evaluate(&mut context, scope)
407 .expect("should be able to assign an address to the first block");
408 drop(context); memory_map.set_block_position(
410 block0_pos.block_identifier,
411 subword::right_half(block0_addr).into(),
412 );
413
414 let mut context = EvaluationContext {
416 here: HereValue::Address(Address::from(u18!(0o100))),
417 explicit_symtab: &explicit_symtab,
418 implicit_symtab: &mut implicit_symtab,
419 index_register_assigner: &mut register_assigner,
420 memory_map: &memory_map,
421 rc_updater: &mut rc_block,
422 lookup_operation: LookupOperation::default(),
423 };
424 let eval_result = context.fetch_or_assign_default(&origin_name);
425
426 match eval_result {
428 Err(e) => {
429 panic!("should not fail to assign a start address to a block: {e}");
430 }
431 Ok(default_value) => {
432 let expected: Unsigned36Bit =
433 u36!(0o200_000).wrapping_add(Unsigned36Bit::from(BLOCK0_SIZE));
434 assert_eq!(default_value, expected);
435 }
436 }
437}
438
439impl<R: RcUpdater> EvaluationContext<'_, R> {
440 pub(super) fn for_target_address<F, T>(&mut self, new_here: HereValue, mut closure: F) -> T
441 where
442 F: FnMut(&mut EvaluationContext<'_, R>) -> T,
443 {
444 let old_here = self.here;
445 self.here = new_here;
446 let output = closure(self);
447 self.here = old_here;
448 output
449 }
450}
451
452#[derive(Debug, PartialEq, Eq, Clone, Hash, Ord, PartialOrd, Copy)]
459pub(super) struct ScopeIdentifier(());
460
461impl ScopeIdentifier {
462 pub(super) fn global() -> ScopeIdentifier {
463 ScopeIdentifier(())
464 }
465}
466
467pub(super) trait Evaluate: Spanned {
474 fn evaluate<R: RcUpdater>(
477 &self,
478 ctx: &mut EvaluationContext<R>,
479 scope: ScopeIdentifier,
480 ) -> Result<Unsigned36Bit, EvaluationFailure>;
481}
482
483#[derive(Debug, Default, Clone)]
487pub(crate) struct RcBlock {
488 pub(crate) address: Address,
490 pub(crate) words: Vec<(RcWordSource, Unsigned36Bit)>,
493}
494
495impl RcBlock {
496 fn end(&self) -> Option<Address> {
497 match Unsigned18Bit::try_from(self.words.len()) {
498 Ok(offset) => Some(self.address.index_by(offset)),
499 Err(_) => None,
500 }
501 }
502}
503
504impl RcAllocator for RcBlock {
505 fn allocate(
506 &mut self,
507 source: RcWordSource,
508 value: Unsigned36Bit,
509 ) -> Result<Address, RcWordAllocationFailure> {
510 if let Some(addr) = self.end() {
511 self.words.push((source, value));
512 Ok(addr)
513 } else {
514 Err(RcWordAllocationFailure::RcBlockTooBig {
515 source,
516 rc_block_len: self.words.len(),
517 })
518 }
519 }
520}
521
522impl RcUpdater for RcBlock {
523 fn update(&mut self, address: Address, value: Unsigned36Bit) {
524 assert!(
525 address >= self.address,
526 "out of range access to address {address} of RC-block starting at {}",
527 self.address
528 );
529 match Unsigned18Bit::from(address).checked_sub(Unsigned18Bit::from(self.address)) {
530 Some(offset) => match self.words.get_mut(usize::from(offset)) {
531 Some((_source, spot)) => {
532 *spot = value;
533 }
534 None => {
535 panic!(
536 "out of range access to offset {offset} of RC-block having length {}",
537 self.words.len()
538 );
539 }
540 },
541 None => {
542 panic!(
544 "inconsistent checks; {address:o} should be greater than {:o}",
545 self.address
546 );
547 }
548 }
549 }
550}
551
552#[cfg(test)]
553pub(crate) fn make_empty_rc_block_for_test(location: Address) -> RcBlock {
554 RcBlock {
555 address: location,
556 words: Vec::new(),
557 }
558}
559
560fn evaluate_normal_symbol<R: RcUpdater>(
562 name: &SymbolName,
563 span: Span,
564 ctx: &mut EvaluationContext<R>,
565 scope: ScopeIdentifier,
566) -> Result<Unsigned36Bit, EvaluationFailure> {
567 ctx.lookup_operation.deps_in_order.push(name.clone());
568 if !ctx.lookup_operation.depends_on.insert(name.clone()) {
569 if let Ok(deps_in_order) =
572 OneOrMore::try_from_vec(ctx.lookup_operation.deps_in_order.clone())
573 {
574 return Err(EvaluationFailure::SymbolDefinitionLoop {
575 span,
576 deps_in_order,
577 });
578 }
579 panic!("we know deps_in_order is non-empty because we just appended an item to it");
580 }
581
582 let result = if let Some(def) = ctx.explicit_symtab.get(name) {
583 let what: (&Span, &SymbolName, &ExplicitDefinition) = (&span, name, def);
584 what.evaluate(ctx, scope)
585 } else {
586 ctx.fetch_or_assign_default(name)
587 };
588
589 ctx.lookup_operation.deps_in_order.pop();
590 ctx.lookup_operation.depends_on.remove(name);
591 result
592}
593
594pub(crate) fn evaluate_elevated_symbol<R: RcUpdater>(
599 name: &SymbolName,
600 elevation: Script,
601 span: Span,
602 ctx: &mut EvaluationContext<R>,
603 scope: ScopeIdentifier,
604) -> Result<Unsigned36Bit, EvaluationFailure> {
605 evaluate_normal_symbol(name, span, ctx, scope).map(|value| value.shl(elevation.shift()))
606}
607
608#[allow(clippy::too_many_arguments)]
617pub(super) fn extract_final_equalities<R: RcUpdater>(
618 equalities: &[Equality],
619 body: &Source,
620 explicit_symbols: &ExplicitSymbolTable,
621 implicit_symbols: &mut ImplicitSymbolTable,
622 memory_map: &MemoryMap,
623 index_register_assigner: &mut IndexRegisterAssigner,
624 rc_allocator: &mut R,
625 final_symbols: &mut FinalSymbolTable,
626 bad_symbol_definitions: &mut BTreeMap<SymbolName, ProgramError>,
627) -> Result<(), AssemblerFailure> {
628 for eq in equalities {
629 let mut ctx = EvaluationContext {
630 explicit_symtab: explicit_symbols,
631 implicit_symtab: implicit_symbols,
632 memory_map,
633 here: HereValue::NotAllowed,
634 index_register_assigner,
635 rc_updater: rc_allocator,
636 lookup_operation: Default::default(),
637 };
638 let scope = ScopeIdentifier::global();
639
640 match eq.value.evaluate(&mut ctx, scope) {
641 Ok(value) => {
642 final_symbols.define(
643 eq.name.clone(),
644 FinalSymbolType::Equality,
645 body.extract(eq.span.start..eq.span.end).to_string(),
646 FinalSymbolDefinition::PositionIndependent(value),
647 );
648 }
649 Err(EvaluationFailure::HereIsNotAllowedHere(_)) => {
650 final_symbols.define(
654 eq.name.clone(),
655 FinalSymbolType::Equality,
656 body.extract(eq.span.start..eq.span.end).to_string(),
657 FinalSymbolDefinition::PositionDependent,
658 );
659 }
660 Err(e) => {
661 record_undefined_symbol_or_return_failure(body, e, bad_symbol_definitions)?;
662 }
663 }
664 }
665 Ok(())
666}
667
668impl Spanned for (&BlockIdentifier, &Option<Origin>, &Span) {
669 fn span(&self) -> Span {
670 *self.2
671 }
672}
673
674#[derive(Debug)]
676struct AddressOverflow(pub(crate) Address, pub(crate) Unsigned18Bit);
677
678impl std::error::Error for AddressOverflow {}
679
680impl Display for AddressOverflow {
681 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
682 write!(
683 f,
684 "Adding {:o} to {:o} would generate a result which doesn't fit into an 18-bit address",
685 self.0, self.1
686 )
687 }
688}
689
690fn offset_from_origin(origin: Address, offset: Unsigned18Bit) -> Result<Address, AddressOverflow> {
692 let (physical, _mark) = origin.split();
693 match physical.checked_add(offset) {
694 Some(total) => Ok(Address::from(total)),
695 None => Err(AddressOverflow(origin, offset)),
696 }
697}
698
699impl Evaluate for BlockPosition {
700 fn evaluate<R: RcUpdater>(
701 &self,
702 ctx: &mut EvaluationContext<R>,
703 scope: ScopeIdentifier,
704 ) -> Result<Unsigned36Bit, EvaluationFailure> {
705 if let Some(origin) = self.origin.as_ref() {
708 return origin.evaluate(ctx, scope);
709 }
710
711 let previous_block_id: BlockIdentifier = match self.block_identifier.previous_block() {
716 None => {
717 return Ok(Origin::default_address().into());
719 }
720 Some(id) => id,
721 };
722
723 let (prev_addr, prev_size, prev_span): (Address, Unsigned18Bit, Span) =
725 if let Some(previous_block) = ctx.memory_map.get(&previous_block_id).cloned() {
726 let address_of_previous_block: Address = previous_block
730 .block_address
731 .expect("blocks should be assigned addresses in ascending block order");
732 (
733 address_of_previous_block,
734 previous_block.block_size,
735 previous_block.span,
736 )
737 } else {
738 unreachable!("unknown block {previous_block_id}")
739 };
740
741 match offset_from_origin(prev_addr, prev_size) {
745 Ok(addr) => Ok(addr.into()),
746 Err(_) => {
747 Err(EvaluationFailure::BlockTooLarge(
753 prev_span,
754 MachineLimitExceededFailure::BlockTooLarge {
755 span: prev_span,
756 block_id: previous_block_id,
757 offset: prev_size.into(),
758 },
759 ))
760 }
761 }
762 }
763}
764
765impl Evaluate for (&Span, &SymbolName, &ExplicitDefinition) {
766 fn evaluate<R: RcUpdater>(
767 &self,
768 ctx: &mut EvaluationContext<R>,
769 scope: ScopeIdentifier,
770 ) -> Result<Unsigned36Bit, EvaluationFailure> {
771 let (_span, name, def): (&Span, &SymbolName, &ExplicitDefinition) = *self;
772 match def {
773 ExplicitDefinition::Origin(Origin::Symbolic(_span, name), _block_id) => {
774 unreachable!("symbolic origin {name} should already have been deduced")
775 }
776 ExplicitDefinition::Origin(Origin::Deduced(_span, _name, address), _block_id) => {
777 Ok((*address).into())
778 }
779 ExplicitDefinition::Origin(Origin::Literal(_span, address), _block_id) => {
780 Ok((*address).into())
781 }
782 ExplicitDefinition::Tag(TagDefinition::Resolved { span: _, address }) => {
783 Ok(address.into())
784 }
785 ExplicitDefinition::Tag(TagDefinition::Unresolved {
786 block_id,
787 block_offset,
788 span,
789 }) => {
790 if let Some(block_position) = ctx.memory_map.get(block_id).cloned() {
791 let block_origin: Address =
792 subword::right_half(block_position.evaluate(ctx, scope)?).into();
793 match offset_from_origin(block_origin, *block_offset) {
794 Ok(computed_address) => Ok(computed_address.into()),
795 Err(_overflow_error) => Err(EvaluationFailure::BlockTooLarge(
796 *span,
797 MachineLimitExceededFailure::BlockTooLarge {
798 span: *span,
799 block_id: *block_id,
800 offset: (*block_offset).into(),
801 },
802 )),
803 }
804 } else {
805 panic!(
806 "Tag named {name} at {span:?} refers to unknown block {block_id}: {def:?}"
807 );
808 }
809 }
810 ExplicitDefinition::Equality(expression) => expression.evaluate(ctx, scope),
811 }
812 }
813}