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