basic/mach/
program.rs

1use super::{compile::compile, Address, Link, Opcode, Symbol, Val};
2use crate::lang::{Error, Line, LineNumber};
3use std::sync::Arc;
4
5type Result<T> = std::result::Result<T, Error>;
6
7/// ## Program memory
8
9#[derive(Debug)]
10pub struct Program {
11    errors: Arc<Vec<Error>>,
12    indirect_errors: Arc<Vec<Error>>,
13    direct_address: Address,
14    line_number: LineNumber,
15    link: Link,
16}
17
18impl Default for Program {
19    fn default() -> Self {
20        Program {
21            errors: Arc::default(),
22            indirect_errors: Arc::default(),
23            direct_address: 0,
24            line_number: None,
25            link: Link::default(),
26        }
27    }
28}
29
30impl Program {
31    pub fn error(&mut self, error: Error) {
32        Arc::make_mut(&mut self.errors).push(error.in_line_number(self.line_number));
33    }
34
35    pub fn append(&mut self, link: Link) -> Result<()> {
36        self.link.append(link)
37    }
38
39    pub fn get(&self, addr: Address) -> Option<Opcode> {
40        match self.link.get(addr) {
41            Some(o) => Some(o.clone()),
42            None => None,
43        }
44    }
45
46    pub fn read_data(&mut self) -> Result<Val> {
47        self.link.read_data()
48    }
49
50    pub fn restore_data(&mut self, addr: Address) {
51        self.link.restore_data(addr)
52    }
53
54    pub fn line_number_for(&self, op_addr: Address) -> LineNumber {
55        self.link.line_number_for(op_addr)
56    }
57
58    pub fn clear(&mut self) {
59        self.errors = Arc::default();
60        self.indirect_errors = Arc::default();
61        self.direct_address = 0;
62        self.line_number = None;
63        self.link.clear();
64    }
65
66    pub fn compile<'b, T: IntoIterator<Item = &'b Line>>(&mut self, lines: T) {
67        let mut direct_seen = false;
68        for line in lines {
69            if let Some(line_number) = line.number() {
70                debug_assert!(
71                    self.direct_address == 0,
72                    "Can't go back to indirect mode without clear()."
73                );
74                if let Some(self_line_number) = self.line_number {
75                    debug_assert!(line_number > self_line_number, "Lines out of order.");
76                }
77            } else {
78                self.link();
79            }
80            self.line_number = line.number();
81            if let Some(line_number) = self.line_number {
82                self.link.push_symbol(line_number as Symbol);
83            } else {
84                debug_assert!(!direct_seen, "Can't handle multiple direct lines.");
85                direct_seen = true;
86                self.link.drain(self.direct_address..);
87                Arc::make_mut(&mut self.errors).clear();
88            }
89            let ast = match line.ast() {
90                Ok(ast) => ast,
91                Err(error) => {
92                    Arc::make_mut(&mut self.errors).push(error);
93                    continue;
94                }
95            };
96            compile(self, &ast);
97            if self.line_number.is_none() {
98                if let Err(e) = self.link.push(Opcode::End) {
99                    Arc::make_mut(&mut self.errors).push(e);
100                }
101            }
102        }
103    }
104
105    pub fn link(&mut self) -> (Address, Arc<Vec<Error>>, Arc<Vec<Error>>) {
106        match self.link.last() {
107            Some(Opcode::End) => {}
108            _ => {
109                if let Err(error) = self.link.push(Opcode::End) {
110                    Arc::make_mut(&mut self.errors).push(error);
111                }
112            }
113        };
114        let mut link_errors = self.link.link();
115        if self.errors.is_empty() {
116            Arc::make_mut(&mut self.errors).append(&mut link_errors);
117        }
118        if self.direct_address == 0 {
119            self.indirect_errors = std::mem::take(&mut self.errors);
120            self.direct_address = self.link.len();
121            self.link.set_start_of_direct(self.link.len());
122        }
123        (
124            self.direct_address,
125            Arc::clone(&self.indirect_errors),
126            Arc::clone(&self.errors),
127        )
128    }
129}