Skip to content

Commit 6d68400

Browse files
committed
[assemblers] Support commas in RC-words.
1 parent 6ba066a commit 6d68400

File tree

4 files changed

+263
-210
lines changed

4 files changed

+263
-210
lines changed

assembler/src/asmlib/ast.rs

Lines changed: 96 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use base::prelude::*;
1212
use crate::eval::{combine_fragment_values, HereValue, SymbolLookupFailure, SymbolValue};
1313
use crate::symtab::LookupOperation;
1414

15-
use super::eval::{Evaluate, RcBlock, SymbolContext, SymbolDefinition, SymbolLookup, SymbolUse};
15+
use super::eval::{
16+
evaluate_tagged_program_instructions, Evaluate, RcBlock, SymbolContext, SymbolDefinition,
17+
SymbolLookup, SymbolUse,
18+
};
1619
use super::glyph;
1720
use super::span::*;
1821
use super::state::NumeralMode;
@@ -187,10 +190,18 @@ impl ArithmeticExpression {
187190
ArithmeticExpression { first, tail }
188191
}
189192

190-
pub(crate) fn symbol_uses(&self) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> {
193+
pub(crate) fn symbol_uses(
194+
&self,
195+
block_id: BlockIdentifier,
196+
block_offset: Unsigned18Bit,
197+
) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> {
191198
let mut result = Vec::with_capacity(1 + self.tail.len());
192-
result.extend(self.first.symbol_uses());
193-
result.extend(self.tail.iter().flat_map(|(_op, x)| x.symbol_uses()));
199+
result.extend(self.first.symbol_uses(block_id, block_offset));
200+
result.extend(
201+
self.tail
202+
.iter()
203+
.flat_map(|(_op, x)| x.symbol_uses(block_id, block_offset)),
204+
);
194205
result.into_iter()
195206
}
196207

@@ -335,7 +346,7 @@ pub(crate) enum Atom {
335346
Literal(LiteralValue),
336347
Symbol(Span, Script, SymbolOrHere),
337348
Parens(Script, Box<ArithmeticExpression>),
338-
RcRef(Span, Vec<InstructionFragment>),
349+
RcRef(Span, Vec<TaggedProgramInstruction>),
339350
}
340351

341352
impl From<SymbolOrLiteral> for Atom {
@@ -350,10 +361,14 @@ impl From<SymbolOrLiteral> for Atom {
350361
}
351362

352363
impl Atom {
353-
pub(crate) fn symbol_uses(&self) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> {
364+
pub(crate) fn symbol_uses(
365+
&self,
366+
block_id: BlockIdentifier,
367+
block_offset: Unsigned18Bit,
368+
) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> {
354369
let mut result = Vec::with_capacity(1);
355370
match self {
356-
Atom::Literal(_) | Atom::RcRef(_, _) | Atom::Symbol(_, _, SymbolOrHere::Here) => (),
371+
Atom::Literal(_) | Atom::Symbol(_, _, SymbolOrHere::Here) => (),
357372
Atom::Symbol(span, script, SymbolOrHere::Named(name)) => {
358373
result.push((
359374
name.clone(),
@@ -362,7 +377,47 @@ impl Atom {
362377
));
363378
}
364379
Atom::Parens(_script, expr) => {
365-
result.extend(expr.symbol_uses());
380+
result.extend(expr.symbol_uses(block_id, block_offset));
381+
}
382+
Atom::RcRef(_span, tagged_instructions) => {
383+
// Tags defined inside the RC-word are not counted as
384+
// defined outside it. But if we refer to a symbol
385+
// inside the RC-word it counts as a reference for the
386+
// purpose of determining which contexts it has been
387+
// used in.
388+
for symbol_use in tagged_instructions
389+
.iter()
390+
.flat_map(|instr| instr.symbol_uses(block_id, block_offset))
391+
{
392+
match &symbol_use {
393+
(_, _, SymbolUse::Reference(_)) => {
394+
result.push(symbol_use);
395+
}
396+
(name, _span, SymbolUse::Definition(SymbolDefinition::Tag { .. })) => {
397+
panic!("Found definition of tag {name} inside an RC-word; this is allowed but is not yet supported.");
398+
}
399+
(name, _span, SymbolUse::Origin(_name, _block)) => {
400+
unreachable!("Found origin {name} inside an RC-word; the parser should have rejected this.");
401+
}
402+
(name, span, SymbolUse::Definition(_)) => {
403+
// e.g. we have an input like
404+
//
405+
// { X = 2 }
406+
//
407+
//
408+
// Ideally we would issue an error for
409+
// this, but since this function cannot
410+
// fail, it's better to do that at the
411+
// time we parse the RC-word reference
412+
// (thus eliminating this case).
413+
//
414+
// When working on this case we should
415+
// figure out if an equality is allowed
416+
// inside a macro expansion.
417+
panic!("Found unexpected definition of {name} inside RC-word reference at {span:?}");
418+
}
419+
}
420+
}
366421
}
367422
}
368423
result.into_iter()
@@ -410,9 +465,9 @@ impl Evaluate for Atom {
410465
op,
411466
),
412467
Atom::Parens(_script, expr) => expr.evaluate(target_address, symtab, rc_allocator, op),
413-
Atom::RcRef(span, fragments) => {
414-
let value: Unsigned36Bit = evaluate_instruction_fragments(
415-
fragments,
468+
Atom::RcRef(span, tagged_program_instructions) => {
469+
let value: Unsigned36Bit = evaluate_tagged_program_instructions(
470+
tagged_program_instructions,
416471
target_address,
417472
symtab,
418473
rc_allocator,
@@ -544,11 +599,15 @@ pub(crate) enum InstructionFragment {
544599
}
545600

546601
impl InstructionFragment {
547-
pub(crate) fn symbol_uses(&self) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> {
602+
pub(crate) fn symbol_uses(
603+
&self,
604+
block_id: BlockIdentifier,
605+
block_offset: Unsigned18Bit,
606+
) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> {
548607
let mut result: Vec<_> = Vec::new();
549608
match self {
550609
InstructionFragment::Arithmetic(expr) => {
551-
result.extend(expr.symbol_uses());
610+
result.extend(expr.symbol_uses(block_id, block_offset));
552611
}
553612
InstructionFragment::DeferredAddressing => (),
554613
InstructionFragment::Config(value) => {
@@ -567,8 +626,8 @@ impl InstructionFragment {
567626
(name, span, symbol_use)
568627
}));
569628
let (base, index) = rc_word_value.as_ref();
570-
result.extend(base.symbol_uses());
571-
result.extend(index.symbol_uses());
629+
result.extend(base.symbol_uses(block_id, block_offset));
630+
result.extend(index.symbol_uses(block_id, block_offset));
572631
}
573632
}
574633
result.into_iter()
@@ -783,8 +842,12 @@ impl CommaDelimitedInstruction {
783842
}
784843
}
785844

786-
pub(crate) fn symbol_uses(&self) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> + '_ {
787-
self.instruction.symbol_uses()
845+
pub(crate) fn symbol_uses(
846+
&self,
847+
block_id: BlockIdentifier,
848+
block_offset: Unsigned18Bit,
849+
) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> + '_ {
850+
self.instruction.symbol_uses(block_id, block_offset)
788851
}
789852

790853
pub(crate) fn span(&self) -> Span {
@@ -1762,46 +1825,13 @@ pub(crate) struct UntaggedProgramInstruction {
17621825
}
17631826

17641827
impl UntaggedProgramInstruction {
1765-
pub(crate) fn symbol_uses(&self) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> + '_ {
1766-
self.inst.symbol_uses()
1767-
}
1768-
}
1769-
1770-
fn evaluate_instruction_fragments<R: RcAllocator>(
1771-
parts: &[InstructionFragment],
1772-
target_address: &HereValue,
1773-
symtab: &mut SymbolTable,
1774-
rc_allocator: &mut R,
1775-
op: &mut LookupOperation,
1776-
) -> Result<Unsigned36Bit, SymbolLookupFailure> {
1777-
fn or_looked_up_value<R: RcAllocator>(
1778-
accumulator: Unsigned36Bit,
1779-
frag: &InstructionFragment,
1780-
target_address: &HereValue,
1781-
symtab: &mut SymbolTable,
1782-
rc_allocator: &mut R,
1783-
op: &mut LookupOperation,
1784-
) -> Result<Unsigned36Bit, SymbolLookupFailure> {
1785-
Ok(combine_fragment_values(
1786-
accumulator,
1787-
frag.evaluate(target_address, symtab, rc_allocator, op)?,
1788-
))
1828+
pub(crate) fn symbol_uses(
1829+
&self,
1830+
block_id: BlockIdentifier,
1831+
block_offset: Unsigned18Bit,
1832+
) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> + '_ {
1833+
self.inst.symbol_uses(block_id, block_offset)
17891834
}
1790-
1791-
parts.iter().try_fold(Unsigned36Bit::ZERO, |acc, curr| {
1792-
or_looked_up_value(acc, curr, target_address, symtab, rc_allocator, op)
1793-
})
1794-
}
1795-
1796-
fn evaluate_instruction_fragment<R: RcAllocator>(
1797-
// TODO: fold into caller
1798-
inst: &InstructionFragment,
1799-
target_address: &HereValue,
1800-
symtab: &mut SymbolTable,
1801-
rc_allocator: &mut R,
1802-
op: &mut LookupOperation,
1803-
) -> Result<Unsigned36Bit, SymbolLookupFailure> {
1804-
inst.evaluate(target_address, symtab, rc_allocator, op)
18051835
}
18061836

18071837
impl Evaluate for UntaggedProgramInstruction {
@@ -1812,13 +1842,18 @@ impl Evaluate for UntaggedProgramInstruction {
18121842
rc_allocator: &mut R,
18131843
op: &mut LookupOperation,
18141844
) -> Result<Unsigned36Bit, SymbolLookupFailure> {
1815-
evaluate_instruction_fragment(&self.inst, target_address, symtab, rc_allocator, op).map(
1816-
|word| match self.holdbit {
1845+
// TODO: issue a diagnostic if a TaggedProgramInstruction
1846+
// contains inconsistent values for the hold bit. We will need to decide
1847+
// whether something like ",h" sets the hold bit (i.e. whether
1848+
// the hold bit is supposed to be subject to the same
1849+
// comma rules that other values are).
1850+
self.inst
1851+
.evaluate(target_address, symtab, rc_allocator, op)
1852+
.map(|word| match self.holdbit {
18171853
HoldBit::Hold => word | HELD_MASK,
18181854
HoldBit::NotHold => word & !HELD_MASK,
18191855
HoldBit::Unspecified => word,
1820-
},
1821-
)
1856+
})
18221857
}
18231858
}
18241859

@@ -1868,7 +1903,7 @@ impl TaggedProgramInstruction {
18681903
result.extend(tag.symbol_uses(block_id, offset));
18691904
}
18701905
for inst in self.instructions.iter() {
1871-
result.extend(inst.symbol_uses());
1906+
result.extend(inst.symbol_uses(block_id, offset));
18721907
}
18731908
result.into_iter()
18741909
}

assembler/src/asmlib/eval.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,3 +489,13 @@ impl Evaluate for TaggedProgramInstruction {
489489
evaluate_and_combine_values(&self.instructions, target_address, symtab, rc_allocator, op)
490490
}
491491
}
492+
493+
pub(crate) fn evaluate_tagged_program_instructions<R: RcAllocator>(
494+
instructions: &[TaggedProgramInstruction],
495+
target_address: &HereValue,
496+
symtab: &mut SymbolTable,
497+
rc_allocator: &mut R,
498+
op: &mut LookupOperation,
499+
) -> Result<Unsigned36Bit, SymbolLookupFailure> {
500+
evaluate_and_combine_values(instructions, target_address, symtab, rc_allocator, op)
501+
}

0 commit comments

Comments
 (0)