assembler/parser/
helpers.rs1use std::fmt::{Display, Write};
3use std::num::IntErrorKind;
4
5use base::prelude::*;
6
7use super::super::{ast::LiteralValue, manuscript::PunchCommand, state::NumeralMode};
8
9#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
11pub(crate) enum Sign {
12 Plus,
13 Minus,
14}
15
16impl Display for Sign {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 f.write_char(match self {
19 Sign::Plus => '+',
20 Sign::Minus => '-',
21 })
22 }
23}
24
25pub(super) fn make_u36(s: &str, radix: u32) -> Result<Unsigned36Bit, StringConversionFailed> {
27 match u64::from_str_radix(s, radix) {
28 Ok(n) => n.try_into().map_err(StringConversionFailed::Range),
29 Err(e) => match e.kind() {
30 IntErrorKind::Empty => Err(StringConversionFailed::EmptyInput),
31 IntErrorKind::InvalidDigit => match s.chars().find(|ch| ch.to_digit(radix).is_none()) {
32 Some(ch) => Err(StringConversionFailed::NotOctal(ch)),
33 None => {
34 panic!(
35 "at least one character of '{s}' is known to be invalid in base {radix}"
36 );
37 }
38 },
39 IntErrorKind::PosOverflow => {
40 Err(StringConversionFailed::Range(ConversionFailed::TooLarge))
41 }
42 _ => unreachable!(),
43 },
44 }
45}
46
47#[test]
48fn test_make_u36() {
49 assert_eq!(Ok(u36!(0)), make_u36("0", 8));
50 assert_eq!(Ok(u36!(0)), make_u36("+0", 8));
51 assert_eq!(Ok(u36!(1)), make_u36("1", 8));
52 assert_eq!(Ok(u36!(1)), make_u36("1", 10));
53 assert_eq!(Ok(u36!(1)), make_u36("+1", 8));
54 assert_eq!(Ok(u36!(1)), make_u36("+1", 8));
55 assert!(make_u36("+1+1", 8).is_err());
56 assert!(make_u36("+-1", 8).is_err());
57 assert!(make_u36("-+1", 8).is_err());
58 assert!(make_u36("--1", 8).is_err());
59 assert!(make_u36("++1", 8).is_err());
60 assert!(make_u36("+ 1", 8).is_err());
61 assert!(make_u36("- 1", 8).is_err());
62 assert!(make_u36("18", 8).is_err());
63 assert!(make_u36("19", 8).is_err());
64 assert_eq!(Ok(u36!(19)), make_u36("19", 10));
65}
66
67pub(crate) fn make_num(
86 digits: &str,
87 hasdot: bool,
88 state: NumeralMode,
89) -> Result<Unsigned36Bit, StringConversionFailed> {
90 make_u36(digits, state.radix(hasdot))
91}
92
93pub(super) fn punch_address(a: Option<LiteralValue>) -> Result<PunchCommand, String> {
94 match a {
95 None => Ok(PunchCommand(None)),
96 Some(literal) => {
97 let value = literal.value();
98 match Unsigned18Bit::try_from(value) {
99 Err(e) => Err(format!(
100 "PUNCH address value {value:o} is not a valid address: {e}",
101 )),
102 Ok(halfword) => {
103 let addr: Address = Address::from(halfword);
104 if addr.mark_bit() == Unsigned18Bit::ZERO {
105 Ok(PunchCommand(Some(addr)))
106 } else {
107 Err(format!(
108 "PUNCH address value {addr:o} must not be a deferred address",
109 ))
110 }
111 }
112 }
113 }
114 }
115}
116
117pub(super) fn opcode_auto_hold_bit(opcode: Unsigned6Bit) -> u64 {
123 if matches!(u8::from(opcode), 0o06 | 0o07 | 0o20 | 0o40) {
124 1 << 35
125 } else {
126 0
127 }
128}
129
130pub(super) fn is_arithmetic_element_register_name(name: &str) -> bool {
132 matches!(name, "A" | "B" | "C" | "D" | "E")
133}