basic/mach/
link.rs

1use super::{Address, Opcode, Operation, Stack, Symbol, Val};
2use crate::error;
3use crate::lang::{Column, Error, LineNumber, MaxValue};
4use std::collections::{BTreeMap, HashMap};
5use std::convert::TryFrom;
6use std::rc::Rc;
7
8type Result<T> = std::result::Result<T, Error>;
9
10/// ## Linkable object
11
12#[derive(Debug, Clone)]
13pub struct Link {
14    current_symbol: Symbol,
15    ops: Stack<Opcode>,
16    data: Stack<Val>,
17    data_pos: Address,
18    direct_set: bool,
19    symbols: BTreeMap<Symbol, (Address, Address)>,
20    unlinked: HashMap<Address, (Column, Symbol)>,
21    whiles: Vec<(bool, Column, Address, Symbol)>,
22}
23
24impl Default for Link {
25    fn default() -> Self {
26        Link {
27            current_symbol: 0,
28            ops: Stack::new("PROGRAM SIZE LIMIT EXCEEDED"),
29            data: Stack::new("DATA SIZE LIMIT EXCEEDED"),
30            data_pos: 0,
31            direct_set: false,
32            symbols: BTreeMap::default(),
33            unlinked: HashMap::default(),
34            whiles: Vec::default(),
35        }
36    }
37}
38
39impl Link {
40    pub fn append(&mut self, mut link: Link) -> Result<()> {
41        if self.direct_set && !link.data.is_empty() {
42            return Err(error!(IllegalDirect));
43        }
44        let ops_addr_offset = self.ops.len();
45        let data_addr_offset = self.data.len();
46        let sym_offset = self.current_symbol;
47        for (symbol, (ops_addr, data_addr)) in link.symbols {
48            let mut symbol = symbol;
49            if symbol < 0 {
50                symbol += sym_offset
51            }
52            self.symbols.insert(
53                symbol,
54                (ops_addr + ops_addr_offset, data_addr + data_addr_offset),
55            );
56        }
57        for (address, (col, symbol)) in link.unlinked {
58            let mut symbol = symbol;
59            if symbol < 0 {
60                symbol += sym_offset
61            }
62            self.unlinked
63                .insert(address + ops_addr_offset, (col.clone(), symbol));
64        }
65        for (kind, col, addr, sym) in link.whiles {
66            self.whiles
67                .push((kind, col, addr + ops_addr_offset, sym + sym_offset));
68        }
69        self.current_symbol += link.current_symbol;
70        self.ops.append(&mut link.ops)?;
71        self.data.append(&mut link.data)
72    }
73
74    pub fn push(&mut self, op: Opcode) -> Result<()> {
75        self.ops.push(op)
76    }
77
78    pub fn transform_to_data(&mut self, col: &Column) -> Result<()> {
79        if self.ops.len() == 1 {
80            if let Some(Opcode::Literal(val)) = self.ops.drain(..).next() {
81                self.data.push(val)?;
82                return Ok(());
83            }
84        } else if self.ops.len() == 2 {
85            let mut expr_link = self.ops.drain(..);
86            if let Some(Opcode::Literal(val)) = expr_link.next() {
87                if let Some(Opcode::Neg) = expr_link.next() {
88                    self.data.push(Operation::negate(val)?)?;
89                    return Ok(());
90                }
91            }
92        }
93        Err(error!(SyntaxError, ..col; "EXPECTED LITERAL"))
94    }
95
96    pub fn read_data(&mut self) -> Result<Val> {
97        if let Some(val) = self.data.get(self.data_pos) {
98            self.data_pos += 1;
99            Ok(val.clone())
100        } else {
101            Err(error!(OutOfData))
102        }
103    }
104
105    pub fn restore_data(&mut self, addr: Address) {
106        self.data_pos = addr;
107    }
108
109    pub fn get(&self, addr: Address) -> Option<&Opcode> {
110        self.ops.get(addr)
111    }
112
113    pub fn last(&self) -> Option<&Opcode> {
114        self.ops.last()
115    }
116
117    pub fn drain<R>(&mut self, range: R) -> std::vec::Drain<'_, Opcode>
118    where
119        R: std::ops::RangeBounds<usize>,
120    {
121        self.ops.drain(range)
122    }
123
124    pub fn is_empty(&self) -> bool {
125        self.ops.is_empty()
126    }
127
128    pub fn len(&self) -> usize {
129        self.ops.len()
130    }
131
132    pub fn clear(&mut self) {
133        self.current_symbol = 0;
134        self.direct_set = false;
135        self.ops.clear();
136        self.data.clear();
137        self.symbols.clear();
138        self.unlinked.clear();
139    }
140
141    pub fn next_symbol(&mut self) -> Symbol {
142        self.current_symbol -= 1;
143        self.current_symbol
144    }
145
146    fn symbol_for_line_number(&mut self, line_number: LineNumber) -> Result<Symbol> {
147        match line_number {
148            Some(number) => Ok(number as Symbol),
149            None => Err(error!(InternalError; "NO SYMBOL FOR LINE NUMBER")),
150        }
151    }
152
153    pub fn push_def_fn(
154        &mut self,
155        col: Column,
156        ident: Rc<str>,
157        vars: Vec<Rc<str>>,
158        expr_ops: Link,
159    ) -> Result<()> {
160        let len = Val::try_from(vars.len())?;
161        self.push(Opcode::Literal(len))?;
162        self.push(Opcode::Def(ident))?;
163        let skip = self.next_symbol();
164        self.push_jump(col, skip)?;
165        for var in vars {
166            self.push(Opcode::Pop(var))?;
167        }
168        self.append(expr_ops)?;
169        self.push(Opcode::Return)?;
170        self.push_symbol(skip);
171        Ok(())
172    }
173
174    pub fn push_for(&mut self, col: Column) -> Result<()> {
175        let next = self.next_symbol();
176        self.unlinked.insert(self.ops.len(), (col, next));
177        self.ops.push(Opcode::Literal(Val::Next(0)))?;
178        self.push_symbol(next);
179        Ok(())
180    }
181
182    pub fn push_gosub(&mut self, col: Column, line_number: LineNumber) -> Result<()> {
183        let ret_sym = self.next_symbol();
184        self.push_return_val(col.clone(), ret_sym)?;
185        let line_number_sym = self.symbol_for_line_number(line_number)?;
186        self.unlinked.insert(self.ops.len(), (col, line_number_sym));
187        self.ops.push(Opcode::Jump(0))?;
188        self.push_symbol(ret_sym);
189        Ok(())
190    }
191
192    pub fn push_return_val(&mut self, col: Column, symbol: Symbol) -> Result<()> {
193        self.unlinked.insert(self.ops.len(), (col, symbol));
194        self.ops.push(Opcode::Literal(Val::Return(0)))
195    }
196
197    pub fn push_goto(&mut self, col: Column, line_number: LineNumber) -> Result<()> {
198        let sym = self.symbol_for_line_number(line_number)?;
199        self.unlinked.insert(self.ops.len(), (col, sym));
200        self.ops.push(Opcode::Jump(0))
201    }
202
203    pub fn push_ifnot(&mut self, col: Column, sym: Symbol) -> Result<()> {
204        self.unlinked.insert(self.ops.len(), (col, sym));
205        self.push(Opcode::IfNot(0))
206    }
207
208    pub fn push_jump(&mut self, col: Column, sym: Symbol) -> Result<()> {
209        self.unlinked.insert(self.ops.len(), (col, sym));
210        self.push(Opcode::Jump(0))
211    }
212
213    pub fn push_restore(&mut self, col: Column, line_number: LineNumber) -> Result<()> {
214        if line_number.is_some() {
215            let sym = self.symbol_for_line_number(line_number)?;
216            self.unlinked.insert(self.ops.len(), (col, sym));
217        }
218        self.ops.push(Opcode::Restore(0))
219    }
220
221    pub fn push_run(&mut self, col: Column, line_number: LineNumber) -> Result<()> {
222        self.ops.push(Opcode::Clear)?;
223        if line_number.is_some() {
224            let sym = self.symbol_for_line_number(line_number)?;
225            self.unlinked.insert(self.ops.len(), (col, sym));
226        }
227        self.ops.push(Opcode::Jump(0))
228    }
229
230    pub fn push_symbol(&mut self, sym: Symbol) {
231        if self
232            .symbols
233            .insert(sym, (self.ops.len(), self.data.len()))
234            .is_some()
235        {
236            debug_assert!(false, "Symbol already exists.");
237        }
238    }
239
240    pub fn push_wend(&mut self, col: Column) -> Result<()> {
241        let sym = self.next_symbol();
242        let addr = self.ops.len();
243        self.whiles.push((false, col, addr, sym));
244        self.push(Opcode::Jump(0))?;
245        self.push_symbol(sym);
246        Ok(())
247    }
248
249    pub fn push_while(&mut self, col: Column, expr: Link) -> Result<()> {
250        let sym = self.next_symbol();
251        self.push_symbol(sym);
252        self.append(expr)?;
253        self.whiles.push((true, col, self.ops.len(), sym));
254        self.push(Opcode::IfNot(0))
255    }
256
257    pub fn set_start_of_direct(&mut self, op_addr: Address) {
258        self.direct_set = true;
259        self.symbols.insert(
260            LineNumber::max_value() as isize + 1 as Symbol,
261            (op_addr, self.data.len()),
262        );
263    }
264
265    pub fn line_number_for(&self, op_addr: Address) -> LineNumber {
266        for (line_number, (symbol_addr, _)) in self.symbols.range(0..).rev() {
267            if op_addr >= *symbol_addr {
268                if *line_number <= LineNumber::max_value() as isize {
269                    return Some(*line_number as u16);
270                } else {
271                    return None;
272                }
273            }
274        }
275        None
276    }
277
278    fn link_whiles(&mut self) -> Vec<Error> {
279        let mut errors: Vec<Error> = vec![];
280        let mut whiles: Vec<(Column, Address, Symbol)> = Vec::default();
281        for (kind, col, addr, sym) in std::mem::take(&mut self.whiles).drain(..) {
282            if kind {
283                whiles.push((col, addr, sym));
284                continue;
285            }
286            match whiles.pop() {
287                None => errors.push(error!(WendWithoutWhile, self.line_number_for(addr), ..&col)),
288                Some((wh_col, wh_addr, wh_sym)) => {
289                    self.unlinked.insert(wh_addr, (wh_col.clone(), sym));
290                    self.unlinked.insert(addr, (col, wh_sym));
291                }
292            }
293        }
294        while let Some((col, addr, _)) = whiles.pop() {
295            errors.push(error!(WhileWithoutWend, self.line_number_for(addr), ..&col));
296        }
297        errors
298    }
299
300    pub fn link(&mut self) -> Vec<Error> {
301        let mut errors = self.link_whiles();
302        for (op_addr, (col, symbol)) in std::mem::take(&mut self.unlinked) {
303            match self.symbols.get(&symbol) {
304                None => {
305                    if symbol >= 0 {
306                        let error = error!(UndefinedLine, self.line_number_for(op_addr), ..&col);
307                        errors.push(error);
308                        continue;
309                    }
310                }
311                Some((op_dest, data_dest)) => {
312                    if let Some(op) = self.ops.get_mut(op_addr) {
313                        if let Some(new_op) = match op {
314                            Opcode::IfNot(_) => Some(Opcode::IfNot(*op_dest)),
315                            Opcode::Jump(_) => Some(Opcode::Jump(*op_dest)),
316                            Opcode::Literal(Val::Return(_)) => {
317                                Some(Opcode::Literal(Val::Return(*op_dest)))
318                            }
319                            Opcode::Literal(Val::Next(_)) => {
320                                Some(Opcode::Literal(Val::Next(*op_dest)))
321                            }
322                            Opcode::Restore(_) => Some(Opcode::Restore(*data_dest)),
323                            _ => None,
324                        } {
325                            *op = new_op;
326                            continue;
327                        }
328                    }
329                }
330            }
331            let line_number = self.line_number_for(op_addr);
332            errors.push(error!(InternalError, line_number, ..&col; "LINK FAILURE"));
333        }
334        self.symbols = self.symbols.split_off(&0);
335        self.current_symbol = 0;
336        errors
337    }
338}
339
340impl TryFrom<&Link> for LineNumber {
341    type Error = Error;
342
343    fn try_from(prog: &Link) -> std::result::Result<Self, Self::Error> {
344        if prog.ops.len() == 1 {
345            if let Some(Opcode::Literal(val)) = prog.ops.last() {
346                return Ok(LineNumber::try_from(val.clone())?);
347            }
348        }
349        Err(error!(UndefinedLine; "INVALID LINE NUMBER"))
350    }
351}
352
353impl TryFrom<&Link> for Rc<str> {
354    type Error = Error;
355
356    fn try_from(prog: &Link) -> std::result::Result<Self, Self::Error> {
357        if prog.ops.len() == 1 {
358            if let Some(Opcode::Literal(Val::String(s))) = prog.ops.last() {
359                return Ok(s.clone());
360            }
361        }
362        Err(error!(SyntaxError; "EXPECTED STRING LITERAL"))
363    }
364}