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#[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}