Skip to content

Commit e1e0cd1

Browse files
committed
[assembler] Allow # in more symbolic contexts.
Section 6-2.8 explicitly describes '#' as a "special symex", so we now allow this in more contexts where a symex is expected. However, we still do not allow it in some other contexts, such as origin and tag definitions.
1 parent 242e383 commit e1e0cd1

File tree

6 files changed

+259
-129
lines changed

6 files changed

+259
-129
lines changed

assembler/src/asmlib/ast.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::symtab::{LookupOperation, RcAllocator, RcBlock};
1717
use super::eval::{Evaluate, SymbolContext, SymbolDefinition, SymbolLookup, SymbolUse};
1818
use super::glyph;
1919
use super::state::NumeralMode;
20-
use super::symbol::SymbolName;
20+
use super::symbol::{SymbolName, SymbolOrHere};
2121
use super::symtab::SymbolTable;
2222
use super::types::{
2323
offset_from_origin, AssemblerFailure, BlockIdentifier, MachineLimitExceededFailure, Span,
@@ -36,6 +36,10 @@ impl LiteralValue {
3636
self.value << self.elevation.shift()
3737
}
3838

39+
pub(crate) fn unshifted_value(&self) -> Unsigned36Bit {
40+
self.value
41+
}
42+
3943
#[cfg(test)]
4044
pub(crate) fn span(&self) -> &Span {
4145
&self.span
@@ -272,14 +276,15 @@ impl Evaluate for ArithmeticExpression {
272276
#[derive(Debug, Clone, PartialEq, Eq)]
273277
pub(crate) enum ConfigValue {
274278
Literal(Span, Unsigned36Bit),
275-
Symbol(Span, SymbolName),
279+
Symbol(Span, SymbolOrHere),
276280
}
277281

278282
impl ConfigValue {
279283
pub(crate) fn symbol_uses(&self) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> {
280284
match self {
281285
ConfigValue::Literal(_span, _value) => None,
282-
ConfigValue::Symbol(span, name) => Some((
286+
ConfigValue::Symbol(_span, SymbolOrHere::Here) => None,
287+
ConfigValue::Symbol(span, SymbolOrHere::Named(name)) => Some((
283288
name.to_owned(),
284289
*span,
285290
SymbolUse::Reference(SymbolContext::configuration()),
@@ -299,7 +304,10 @@ impl Evaluate for ConfigValue {
299304
) -> Result<Unsigned36Bit, SymbolLookupFailure> {
300305
match self {
301306
ConfigValue::Literal(_span, value) => Ok(*value),
302-
ConfigValue::Symbol(span, name) => {
307+
ConfigValue::Symbol(span, SymbolOrHere::Here) => {
308+
Ok(Unsigned36Bit::from(target_address.get_address(span)?))
309+
}
310+
ConfigValue::Symbol(span, SymbolOrHere::Named(name)) => {
303311
let context = SymbolContext::configuration();
304312
match symtab.lookup_with_op(name, *span, target_address, rc_allocator, &context, op)
305313
{
@@ -318,8 +326,7 @@ impl Evaluate for ConfigValue {
318326
#[derive(Debug, Clone, PartialEq, Eq)]
319327
pub(crate) enum Atom {
320328
Literal(LiteralValue),
321-
Symbol(Span, Script, SymbolName),
322-
Here(Script), // the special symbol '#'.
329+
Symbol(Span, Script, SymbolOrHere),
323330
Parens(Script, Box<ArithmeticExpression>),
324331
RcRef(Span, Vec<InstructionFragment>),
325332
}
@@ -328,10 +335,10 @@ impl Atom {
328335
pub(crate) fn symbol_uses(&self) -> impl Iterator<Item = (SymbolName, Span, SymbolUse)> {
329336
let mut result = Vec::with_capacity(1);
330337
match self {
331-
Atom::Literal(_) | Atom::Here(_) | Atom::RcRef(_, _) => (),
332-
Atom::Symbol(span, script, symbol_name) => {
338+
Atom::Literal(_) | Atom::RcRef(_, _) | Atom::Symbol(_, _, SymbolOrHere::Here) => (),
339+
Atom::Symbol(span, script, SymbolOrHere::Named(name)) => {
333340
result.push((
334-
symbol_name.clone(),
341+
name.clone(),
335342
*span,
336343
SymbolUse::Reference(SymbolContext::from((script, *span))),
337344
));
@@ -353,17 +360,12 @@ impl Evaluate for Atom {
353360
op: &mut LookupOperation,
354361
) -> Result<Unsigned36Bit, SymbolLookupFailure> {
355362
match self {
356-
Atom::Here(elevation) => match target_address {
357-
HereValue::Address(addr) => {
358-
let value: Unsigned36Bit = (*addr).into();
359-
Ok(value.shl(elevation.shift()))
360-
}
361-
HereValue::NotAllowed => {
362-
todo!("# is not allowed in origins")
363-
}
364-
},
363+
Atom::Symbol(span, elevation, SymbolOrHere::Here) => {
364+
let value: Unsigned36Bit = target_address.get_address(span)?.into();
365+
Ok(value.shl(elevation.shift()))
366+
}
365367
Atom::Literal(literal) => Ok(literal.value()),
366-
Atom::Symbol(span, elevation, name) => {
368+
Atom::Symbol(span, elevation, SymbolOrHere::Named(name)) => {
367369
let context = SymbolContext::from((elevation, *span));
368370
match symtab.lookup_with_op(name, *span, target_address, rc_allocator, &context, op)
369371
{
@@ -419,11 +421,13 @@ fn elevated_string<'a>(s: &'a str, elevation: &Script) -> Cow<'a, str> {
419421
impl std::fmt::Display for Atom {
420422
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
421423
match self {
422-
Atom::Here(Script::Super) => f.write_str("@super_hash@"),
423-
Atom::Here(Script::Normal) => f.write_char('#'),
424-
Atom::Here(Script::Sub) => f.write_str("@sub_hash@"),
424+
Atom::Symbol(_span, elevation, SymbolOrHere::Here) => match elevation {
425+
Script::Super => f.write_str("@super_hash@"),
426+
Script::Normal => f.write_char('#'),
427+
Script::Sub => f.write_str("@sub_hash@"),
428+
},
425429
Atom::Literal(value) => value.fmt(f),
426-
Atom::Symbol(_span, elevation, name) => {
430+
Atom::Symbol(_span, elevation, SymbolOrHere::Named(name)) => {
427431
elevated_string(&name.to_string(), elevation).fmt(f)
428432
}
429433
Atom::Parens(script, expr) => elevated_string(&expr.to_string(), script).fmt(f),

assembler/src/asmlib/driver/tests.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use std::{
44
};
55

66
use super::super::ast::{
7-
ArithmeticExpression, Atom, HoldBit, InstructionFragment, LiteralValue, LocatedBlock,
8-
ManuscriptBlock, PunchCommand, SourceFile, Statement, TaggedProgramInstruction,
7+
ArithmeticExpression, Atom, ConfigValue, HoldBit, InstructionFragment, LiteralValue,
8+
LocatedBlock, ManuscriptBlock, PunchCommand, SourceFile, Statement, TaggedProgramInstruction,
99
UntaggedProgramInstruction,
1010
};
1111
use super::super::eval::{SymbolContext, SymbolLookup, SymbolValue};
@@ -209,7 +209,7 @@ fn test_metacommand_dec_changes_default_base() {
209209
fn test_assemble_octal_superscript_literal() {
210210
assemble_literal(
211211
"⁺³⁶\n", // 36, superscript
212-
&InstructionFragment::from((span(0..8), Script::Super, Unsigned36Bit::from(0o36_u32))),
212+
&InstructionFragment::Config(ConfigValue::Literal(span(0..8), u36!(0o36))),
213213
);
214214
}
215215

@@ -257,10 +257,15 @@ fn test_normal_hash_value() {
257257

258258
#[test]
259259
fn test_super_hash_value() {
260-
let program =
261-
assemble_source(concat!("1| @sup_hash@\n",), Default::default()).expect("program is valid");
260+
let input = "1| @sup_hash@\n";
261+
let program = assemble_source(input, Default::default()).expect("program is valid");
262262
assert_eq!(program.chunks[0].address, Address::from(u18!(0o1)));
263-
assert_eq!(program.chunks[0].words[0], u36!(1).shl(30));
263+
let got = program.chunks[0].words[0];
264+
let expected = u36!(1).shl(30);
265+
assert_eq!(
266+
got, expected,
267+
"input '{input}' assembled to {got} but we expected {expected}"
268+
);
264269
}
265270

266271
#[test]

assembler/src/asmlib/eval.rs

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::collections::BTreeSet;
2-
use std::fmt::{self, Debug, Display, Formatter};
2+
use std::fmt::{self, Debug, Display, Formatter, Write};
33

44
use base::{
55
charset::Script,
@@ -12,13 +12,16 @@ use super::ast::UntaggedProgramInstruction;
1212
use super::symbol::SymbolName;
1313
use super::symtab::RcAllocator;
1414
use super::types::{
15-
AssemblerFailure, BlockIdentifier, MachineLimitExceededFailure, OrderableSpan, Span,
15+
AssemblerFailure, BlockIdentifier, LineAndColumn, MachineLimitExceededFailure, OrderableSpan,
16+
Span,
1617
};
1718

1819
#[derive(Debug, PartialEq, Eq)]
1920
pub(crate) enum LookupTarget {
2021
Symbol(SymbolName, Span),
2122
MemRef(MemoryReference, Span),
23+
/// Attempt to look up "here", that is, '#'.
24+
Hash(Span),
2225
}
2326

2427
impl From<(SymbolName, Span)> for LookupTarget {
@@ -36,14 +39,17 @@ impl From<(MemoryReference, Span)> for LookupTarget {
3639
impl LookupTarget {
3740
fn span(&self) -> &Span {
3841
match self {
39-
LookupTarget::Symbol(_, span) | LookupTarget::MemRef(_, span) => span,
42+
LookupTarget::Hash(span)
43+
| LookupTarget::Symbol(_, span)
44+
| LookupTarget::MemRef(_, span) => span,
4045
}
4146
}
4247
}
4348

4449
impl Display for LookupTarget {
4550
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
4651
match self {
52+
LookupTarget::Hash(_) => f.write_char('#'),
4753
LookupTarget::Symbol(name, _) => {
4854
write!(f, "symbol {name}")
4955
}
@@ -82,6 +88,7 @@ pub(crate) enum SymbolLookupFailureKind {
8288
Inconsistent(String),
8389
Loop { deps_in_order: Vec<SymbolName> },
8490
MachineLimitExceeded(MachineLimitExceededFailure),
91+
HereIsNotAllowedHere,
8592
}
8693

8794
#[derive(Debug, PartialEq, Eq)]
@@ -106,34 +113,42 @@ impl Display for SymbolLookupFailure {
106113
SymbolLookupFailureKind::MachineLimitExceeded(fail) => {
107114
write!(f, "machine limit exceeded: {fail}")
108115
}
116+
SymbolLookupFailureKind::HereIsNotAllowedHere => {
117+
f.write_str("'#' (representing the current address) is not allowed here")
118+
}
109119
}
110120
}
111121
}
112122

113-
impl From<SymbolLookupFailure> for AssemblerFailure {
114-
fn from(f: SymbolLookupFailure) -> AssemblerFailure {
115-
let symbol_desc: String = f.target.to_string();
116-
let span: Span = *f.target.span();
117-
match f.kind {
118-
SymbolLookupFailureKind::MachineLimitExceeded(limit_exceeded) => {
119-
AssemblerFailure::MachineLimitExceeded(limit_exceeded)
120-
}
121-
SymbolLookupFailureKind::Loop { deps_in_order } => {
122-
let chain: String = deps_in_order
123-
.iter()
124-
.map(|dep| dep.to_string())
125-
.collect::<Vec<_>>()
126-
.join("->");
127-
AssemblerFailure::InvalidProgram {
128-
span,
129-
msg: format!("definition of {symbol_desc} has a dependency loop ({chain})",),
130-
}
131-
}
132-
SymbolLookupFailureKind::Inconsistent(msg) => AssemblerFailure::InvalidProgram {
123+
fn convert_symbol_lookup_failure_to_assembler_failure(
124+
f: SymbolLookupFailure,
125+
source_file_body: &str,
126+
) -> AssemblerFailure {
127+
let symbol_desc: String = f.target.to_string();
128+
let span: Span = *f.target.span();
129+
match f.kind {
130+
SymbolLookupFailureKind::HereIsNotAllowedHere => AssemblerFailure::SyntaxError {
131+
location: LineAndColumn::from((source_file_body, &span)),
132+
msg: f.to_string(),
133+
},
134+
SymbolLookupFailureKind::MachineLimitExceeded(limit_exceeded) => {
135+
AssemblerFailure::MachineLimitExceeded(limit_exceeded)
136+
}
137+
SymbolLookupFailureKind::Loop { deps_in_order } => {
138+
let chain: String = deps_in_order
139+
.iter()
140+
.map(|dep| dep.to_string())
141+
.collect::<Vec<_>>()
142+
.join("->");
143+
AssemblerFailure::InvalidProgram {
133144
span,
134-
msg: format!("program is inconsistent: {msg}",),
135-
},
145+
msg: format!("definition of {symbol_desc} has a dependency loop ({chain})",),
146+
}
136147
}
148+
SymbolLookupFailureKind::Inconsistent(msg) => AssemblerFailure::InvalidProgram {
149+
span,
150+
msg: format!("program is inconsistent: {msg}",),
151+
},
137152
}
138153
}
139154

@@ -180,6 +195,18 @@ pub(crate) enum HereValue {
180195
NotAllowed,
181196
}
182197

198+
impl HereValue {
199+
pub(crate) fn get_address(&self, span: &Span) -> Result<Address, SymbolLookupFailure> {
200+
match self {
201+
HereValue::Address(addr) => Ok(*addr),
202+
HereValue::NotAllowed => Err(SymbolLookupFailure {
203+
target: LookupTarget::Hash(*span),
204+
kind: SymbolLookupFailureKind::HereIsNotAllowedHere,
205+
}),
206+
}
207+
}
208+
}
209+
183210
pub(crate) trait Evaluate {
184211
fn evaluate<R: RcAllocator>(
185212
&self,

0 commit comments

Comments
 (0)