summaryrefslogtreecommitdiff
path: root/src/stages/bytecode_tokens.rs
blob: b54cb0e4330d14907f512d31dcd96e734edc378e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use crate::*;


pub struct Segment {
    pub address: usize,
    /// Source of the address value.
    pub source: Option<SourceSpan>,
    pub words: Vec<Tracked<Word>>,
}

pub struct Word {
    pub value: usize,
    pub width: u32,
}

impl std::fmt::Display for Word {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        if self.width == 0 {
            write!(f, "0")
        } else {
            for i in (0..self.width).rev() {
                let is_first_bit = i+1 == self.width;
                if !is_first_bit && (i+1) % 4 == 0 {
                    write!(f, "_")?;
                }
                match (self.value >> i) & 1 {
                    0 => write!(f, "0")?,
                    _ => write!(f, "1")?,
                }
            }
            Ok(())
        }
    }
}

pub enum BytecodeError {
    /// expected, received
    IncorrectWidth(u32, u32),
    /// pinned, real
    PinnedAddressBacktrack(usize, usize),
    /// expected, received
    ValueTooWide(u32, u32),
    StackError(Tracked<StackError>),
}


pub fn report_bytecode_errors(errors: &[Tracked<BytecodeError>], source_code: &str) {
    for error in errors {
        report_bytecode_error(error, source_code);
    }
}

fn report_bytecode_error(error: &Tracked<BytecodeError>, source_code: &str) {
    let context = Context { source_code: &source_code, source: &error.source };
    let message = match &error.value {
        BytecodeError::IncorrectWidth(expected, received) =>
            &format!("Word is {received} bits wide, but was expected to have a fixed width of {expected} bits"),
        BytecodeError::PinnedAddressBacktrack(pinned, real) =>
            &format!("Cannot pin to address {pinned} when address is already {real}"),
        BytecodeError::StackError(stack_error) => {
            report_stack_error(stack_error, source_code); return; },
        BytecodeError::ValueTooWide(expected, received) =>
            &format!("Field is {expected} bits wide, but received a value that is {received} bits wide"),
    };

    report_source_issue(LogLevel::Error, &context, message);
}


pub fn print_segment(segment: &Segment) {
    println!("SEGMENT: 0x{:>04x}", segment.address);
    // Find maximum width of all words in the segment.
    let width = segment.words.iter().map(|w| w.to_string().chars().count()).max().unwrap_or(0);
    for word in &segment.words {
        let string = word.to_string();
        println!("  {string:>w$}", w=width as usize);
    }
}