basic/mach/
compile.rs

1use super::{Function, Link, Opcode, Program, Stack, Val};
2use crate::error;
3use crate::lang::ast::{self, AcceptVisitor};
4use crate::lang::{Column, Error, LineNumber};
5use std::convert::TryFrom;
6use std::rc::Rc;
7
8type Result<T> = std::result::Result<T, Error>;
9
10pub fn compile(program: &mut Program, ast: &[ast::Statement]) {
11    Visitor::compile(program, ast)
12}
13
14struct Visitor<'a> {
15    link: &'a mut Program,
16    comp: Compiler,
17}
18
19impl<'a> Visitor<'a> {
20    fn compile(program: &mut Program, ast: &[ast::Statement]) {
21        let mut this = Visitor {
22            link: program,
23            comp: Compiler::new(),
24        };
25        for statement in ast {
26            statement.accept(&mut this);
27        }
28        for (_col, frag) in this.comp.stmt.drain(..) {
29            if let Some(error) = this.link.append(frag).err() {
30                this.link.error(error);
31                break;
32            }
33        }
34        debug_assert_eq!(0, this.comp.var.len());
35        debug_assert_eq!(0, this.comp.expr.len());
36        debug_assert_eq!(0, this.comp.stmt.len());
37    }
38}
39
40impl<'a> ast::Visitor for Visitor<'a> {
41    fn visit_statement(&mut self, statement: &ast::Statement) {
42        let mut link = Link::default();
43        let col = match self.comp.statement(&mut link, statement) {
44            Ok(col) => col,
45            Err(e) => {
46                self.link.error(e);
47                0..0
48            }
49        };
50        if let Some(error) = self.comp.stmt.push((col.clone(), link)).err() {
51            self.link.error(error.in_column(&col))
52        }
53    }
54    fn visit_variable(&mut self, var: &ast::Variable) {
55        let mut link = Link::default();
56        let (col, name, len) = match self.comp.variable(&mut link, var) {
57            Ok((col, name, len)) => (col, name, len),
58            Err(e) => {
59                self.link.error(e);
60                (0..0, "".into(), None)
61            }
62        };
63        let var_item = VarItem::new(col.clone(), name, link, len);
64        if let Some(error) = self.comp.var.push(var_item).err() {
65            self.link.error(error.in_column(&col))
66        }
67    }
68    fn visit_expression(&mut self, expression: &ast::Expression) {
69        let mut link = Link::default();
70        let col = match self.comp.expression(&mut link, expression) {
71            Ok(col) => col,
72            Err(e) => {
73                self.link.error(e);
74                0..0
75            }
76        };
77        if let Some(error) = self.comp.expr.push((col.clone(), link)).err() {
78            self.link.error(error.in_column(&col))
79        }
80    }
81}
82
83#[derive(Clone, Debug)]
84struct VarItem {
85    col: Column,
86    name: Rc<str>,
87    link: Link,
88    arg_len: Option<usize>,
89}
90
91impl VarItem {
92    fn new(col: Column, name: Rc<str>, link: Link, arg_len: Option<usize>) -> VarItem {
93        VarItem {
94            col,
95            name,
96            link,
97            arg_len,
98        }
99    }
100
101    fn test_for_built_in(&self, strict: bool) -> Result<()> {
102        match Function::opcode_and_arity(&self.name) {
103            Some((_, range)) if range == (0..=0) && self.arg_len.is_some() && !strict => Ok(()),
104            Some((_, range)) if range != (0..=0) && self.arg_len.is_none() && !strict => Ok(()),
105            Some(_) => Err(error!(SyntaxError, ..&self.col; "RESERVED FOR BUILT-IN")),
106            None => Ok(()),
107        }
108    }
109
110    fn push_as_dim(self, link: &mut Link) -> Result<Column> {
111        self.test_for_built_in(true)?;
112        if let Some(len) = self.arg_len {
113            if len > 0 {
114                link.append(self.link)?;
115                link.push(Opcode::Literal(Val::try_from(len)?))?;
116                link.push(Opcode::DimArr(self.name))?;
117                return Ok(self.col.clone());
118            }
119        }
120        Err(error!(SyntaxError, ..&self.col; "NOT AN ARRAY"))
121    }
122
123    fn push_as_pop_unary(self, link: &mut Link) -> Result<Column> {
124        self.test_for_built_in(false)?;
125        debug_assert!(self.arg_len.is_none());
126        debug_assert!(self.link.is_empty());
127        link.push(Opcode::Pop(self.name))?;
128        Ok(self.col.clone())
129    }
130
131    fn push_as_pop(self, link: &mut Link) -> Result<Column> {
132        self.test_for_built_in(false)?;
133        if let Some(len) = self.arg_len {
134            if len > 0 {
135                link.append(self.link)?;
136                link.push(Opcode::Literal(Val::try_from(len)?))?;
137                link.push(Opcode::PopArr(self.name))?;
138            } else {
139                return Err(error!(SyntaxError, ..&self.col; "MISSING INDEX EXPRESSION"));
140            }
141        } else {
142            debug_assert!(self.link.is_empty());
143            link.push(Opcode::Pop(self.name))?;
144        }
145        Ok(self.col.clone())
146    }
147
148    fn push_as_expression(self, link: &mut Link) -> Result<Column> {
149        link.append(self.link)?;
150        if let Some((opcode, arity)) = Function::opcode_and_arity(&self.name) {
151            if arity == (0..=0) && self.arg_len.is_none() {
152                link.push(opcode)?;
153                return Ok(self.col.clone());
154            } else if let Some(len) = self.arg_len {
155                if arity.contains(&len) {
156                    if arity.start() != arity.end() {
157                        link.push(Opcode::Literal(Val::try_from(len)?))?;
158                    }
159                    link.push(opcode)?;
160                    return Ok(self.col.clone());
161                }
162                return Err(error!(IllegalFunctionCall, ..&self.col; "WRONG NUMBER OF ARGUMENTS"));
163            }
164        }
165        match self.arg_len {
166            None => link.push(Opcode::Push(self.name))?,
167            Some(len) => {
168                if self.name.starts_with("FN") {
169                    link.push(Opcode::Literal(Val::try_from(len)?))?;
170                    link.push(Opcode::Fn(self.name))?;
171                } else {
172                    link.push(Opcode::Literal(Val::try_from(len)?))?;
173                    link.push(Opcode::PushArr(self.name))?;
174                }
175            }
176        }
177        Ok(self.col.clone())
178    }
179}
180
181struct Compiler {
182    var: Stack<VarItem>,
183    expr: Stack<(Column, Link)>,
184    stmt: Stack<(Column, Link)>,
185}
186
187impl Compiler {
188    fn new() -> Compiler {
189        Compiler {
190            var: Stack::new("COMPILER VARIABLE OVERFLOW"),
191            expr: Stack::new("COMPILER EXPRESSION OVERFLOW"),
192            stmt: Stack::new("COMPILER STATEMENT OVERFLOW"),
193        }
194    }
195
196    fn variable(
197        &mut self,
198        link: &mut Link,
199        var: &ast::Variable,
200    ) -> Result<(Column, Rc<str>, Option<usize>)> {
201        use ast::Variable;
202        let (col, ident, len) = match var {
203            Variable::Unary(col, ident) => (col, ident, None),
204            Variable::Array(col, ident, vec_expr) => {
205                let len = vec_expr.len();
206                let vec_expr = self.expr.pop_n(len)?;
207                for (_col, ops) in vec_expr {
208                    link.append(ops)?
209                }
210                (col, ident, Some(len))
211            }
212        };
213        let s = match ident {
214            ast::Ident::Plain(s) => s,
215            ast::Ident::String(s) => s,
216            ast::Ident::Single(s) => s,
217            ast::Ident::Double(s) => s,
218            ast::Ident::Integer(s) => s,
219        };
220        Ok((col.clone(), s.clone(), len))
221    }
222
223    fn expression(&mut self, link: &mut Link, expr: &ast::Expression) -> Result<Column> {
224        fn unary_expression(
225            this: &mut Compiler,
226            link: &mut Link,
227            op: Opcode,
228            col: &Column,
229        ) -> Result<Column> {
230            let (expr_col, ops) = this.expr.pop()?;
231            link.append(ops)?;
232            link.push(op)?;
233            Ok(col.start..expr_col.end)
234        }
235        fn binary_expression(this: &mut Compiler, link: &mut Link, op: Opcode) -> Result<Column> {
236            let (col_rhs, rhs) = this.expr.pop()?;
237            let (col_lhs, lhs) = this.expr.pop()?;
238            link.append(lhs)?;
239            link.append(rhs)?;
240            link.push(op)?;
241            Ok(col_lhs.start..col_rhs.end)
242        }
243        fn literal(link: &mut Link, col: &Column, val: Val) -> Result<Column> {
244            link.push(Opcode::Literal(val))?;
245            Ok(col.clone())
246        }
247        use ast::Expression;
248        match expr {
249            Expression::Single(col, val) => literal(link, col, Val::Single(*val)),
250            Expression::Double(col, val) => literal(link, col, Val::Double(*val)),
251            Expression::Integer(col, val) => literal(link, col, Val::Integer(*val)),
252            Expression::String(col, val) => literal(link, col, Val::String(val.clone())),
253            Expression::Variable(_) => self.var.pop()?.push_as_expression(link),
254            Expression::Negation(col, ..) => unary_expression(self, link, Opcode::Neg, col),
255            Expression::Power(..) => binary_expression(self, link, Opcode::Pow),
256            Expression::Multiply(..) => binary_expression(self, link, Opcode::Mul),
257            Expression::Divide(..) => binary_expression(self, link, Opcode::Div),
258            Expression::DivideInt(..) => binary_expression(self, link, Opcode::DivInt),
259            Expression::Modulo(..) => binary_expression(self, link, Opcode::Mod),
260            Expression::Add(..) => binary_expression(self, link, Opcode::Add),
261            Expression::Subtract(..) => binary_expression(self, link, Opcode::Sub),
262            Expression::Equal(..) => binary_expression(self, link, Opcode::Eq),
263            Expression::NotEqual(..) => binary_expression(self, link, Opcode::NotEq),
264            Expression::Less(..) => binary_expression(self, link, Opcode::Lt),
265            Expression::LessEqual(..) => binary_expression(self, link, Opcode::LtEq),
266            Expression::Greater(..) => binary_expression(self, link, Opcode::Gt),
267            Expression::GreaterEqual(..) => binary_expression(self, link, Opcode::GtEq),
268            Expression::Not(col, ..) => unary_expression(self, link, Opcode::Not, col),
269            Expression::And(..) => binary_expression(self, link, Opcode::And),
270            Expression::Or(..) => binary_expression(self, link, Opcode::Or),
271            Expression::Xor(..) => binary_expression(self, link, Opcode::Xor),
272            Expression::Imp(..) => binary_expression(self, link, Opcode::Imp),
273            Expression::Eqv(..) => binary_expression(self, link, Opcode::Eqv),
274        }
275    }
276
277    fn statement(&mut self, link: &mut Link, statement: &ast::Statement) -> Result<Column> {
278        use ast::Statement;
279        match statement {
280            Statement::Clear(col, ..) => self.r#clear(link, col),
281            Statement::Cls(col, ..) => self.r#cls(link, col),
282            Statement::Cont(col, ..) => self.r#cont(link, col),
283            Statement::Data(col, v) => self.r#data(link, col, v.len()),
284            Statement::Def(col, _, v, _) => self.r#def(link, col, v.len()),
285            Statement::Defdbl(col, ..) => self.r#defdbl(link, col),
286            Statement::Defint(col, ..) => self.r#defint(link, col),
287            Statement::Defsng(col, ..) => self.r#defsng(link, col),
288            Statement::Defstr(col, ..) => self.r#defstr(link, col),
289            Statement::Delete(col, ..) => self.r#delete(link, col),
290            Statement::Dim(col, v) => self.r#dim(link, col, v.len()),
291            Statement::End(col, ..) => self.r#end(link, col),
292            Statement::Erase(col, v) => self.r#erase(link, col, v.len()),
293            Statement::For(col, ..) => self.r#for(link, col),
294            Statement::Gosub(col, ..) => self.r#gosub(link, col),
295            Statement::Goto(col, ..) => self.r#goto(link, col),
296            Statement::If(col, _, th, el) => self.r#if(link, col, th.len(), el.len()),
297            Statement::Input(col, _, _, v) => self.r#input(link, col, v.len()),
298            Statement::Let(col, ..) => self.r#let(link, col),
299            Statement::List(col, ..) => self.r#list(link, col),
300            Statement::Load(col, ..) => self.r#load(link, col),
301            Statement::Mid(col, ..) => self.r#mid(link, col),
302            Statement::New(col, ..) => self.r#new_(link, col),
303            Statement::Next(col, v) => self.r#next(link, col, v.len()),
304            Statement::OnGoto(col, _, v) => self.r#on(link, col, v.len(), false),
305            Statement::OnGosub(col, _, v) => self.r#on(link, col, v.len(), true),
306            Statement::Print(col, v) => self.r#print(link, col, v.len()),
307            Statement::Read(col, v) => self.r#read(link, col, v.len()),
308            Statement::Renum(col, ..) => self.r#renum(link, col),
309            Statement::Restore(col, ..) => self.r#restore(link, col),
310            Statement::Return(col, ..) => self.r#return(link, col),
311            Statement::Run(col, ..) => self.r#run(link, col),
312            Statement::Save(col, ..) => self.r#save(link, col),
313            Statement::Stop(col, ..) => self.r#stop(link, col),
314            Statement::Swap(col, ..) => self.r#swap(link, col),
315            Statement::Troff(col, ..) => self.r#troff(link, col),
316            Statement::Tron(col, ..) => self.r#tron(link, col),
317            Statement::Wend(col, ..) => self.r#wend(link, col),
318            Statement::While(col, ..) => self.r#while(link, col),
319        }
320    }
321
322    fn expr_pop_line_number(&mut self) -> Result<(Column, LineNumber)> {
323        let (sub_col, ops) = self.expr.pop()?;
324        match LineNumber::try_from(&ops) {
325            Ok(ln) => Ok((sub_col, ln)),
326            Err(e) => Err(e.in_column(&sub_col)),
327        }
328    }
329
330    fn r#clear(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
331        link.push(Opcode::Clear)?;
332        Ok(col.clone())
333    }
334
335    fn r#cls(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
336        link.push(Opcode::Cls)?;
337        Ok(col.clone())
338    }
339
340    fn r#cont(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
341        link.push(Opcode::Cont)?;
342        Ok(col.clone())
343    }
344
345    fn r#data(&mut self, link: &mut Link, col: &Column, len: usize) -> Result<Column> {
346        let exprs = self.expr.pop_n(len)?;
347        for (expr_col, mut expr_link) in exprs {
348            expr_link.transform_to_data(&expr_col)?;
349            link.append(expr_link)?;
350        }
351        Ok(col.clone())
352    }
353
354    fn r#def(&mut self, link: &mut Link, col: &Column, len: usize) -> Result<Column> {
355        let mut vars = self.var.pop_n(len)?;
356        let fn_name = self.var.pop()?;
357        debug_assert!(fn_name.arg_len.is_none());
358        let (_expr_col, expr_ops) = self.expr.pop()?;
359        let fn_vars: Vec<Rc<str>> = vars
360            .drain(..)
361            .map(|var_item| {
362                debug_assert!(var_item.arg_len.is_none());
363                var_item.name
364            })
365            .collect();
366        link.push_def_fn(col.clone(), fn_name.name, fn_vars, expr_ops)?;
367        Ok(col.clone())
368    }
369
370    fn r#defdbl(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
371        let to = self.var.pop()?;
372        let from = self.var.pop()?;
373        link.push(Opcode::Literal(Val::String(from.name)))?;
374        link.push(Opcode::Literal(Val::String(to.name)))?;
375        link.push(Opcode::Defdbl)?;
376        Ok(col.clone())
377    }
378
379    fn r#defint(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
380        let to = self.var.pop()?;
381        let from = self.var.pop()?;
382        link.push(Opcode::Literal(Val::String(from.name)))?;
383        link.push(Opcode::Literal(Val::String(to.name)))?;
384        link.push(Opcode::Defint)?;
385        Ok(col.clone())
386    }
387
388    fn r#defsng(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
389        let to = self.var.pop()?;
390        let from = self.var.pop()?;
391        link.push(Opcode::Literal(Val::String(from.name)))?;
392        link.push(Opcode::Literal(Val::String(to.name)))?;
393        link.push(Opcode::Defsng)?;
394        Ok(col.clone())
395    }
396
397    fn r#defstr(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
398        let to = self.var.pop()?;
399        let from = self.var.pop()?;
400        link.push(Opcode::Literal(Val::String(from.name)))?;
401        link.push(Opcode::Literal(Val::String(to.name)))?;
402        link.push(Opcode::Defstr)?;
403        Ok(col.clone())
404    }
405
406    fn r#delete(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
407        let (col_to, ln_to) = self.expr_pop_line_number()?;
408        let (_col_from, ln_from) = self.expr_pop_line_number()?;
409        link.push(Opcode::Literal(Val::try_from(ln_from)?))?;
410        link.push(Opcode::Literal(Val::try_from(ln_to)?))?;
411        link.push(Opcode::Delete)?;
412        Ok(col.start..col_to.end)
413    }
414
415    fn r#dim(&mut self, link: &mut Link, col: &Column, len: usize) -> Result<Column> {
416        let mut col = col.clone();
417        for var in self.var.pop_n(len)? {
418            let sub_col = var.push_as_dim(link)?;
419            col.end = sub_col.end;
420        }
421        Ok(col)
422    }
423
424    fn r#end(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
425        link.push(Opcode::End)?;
426        Ok(col.clone())
427    }
428
429    fn r#erase(&mut self, link: &mut Link, col: &Column, len: usize) -> Result<Column> {
430        for var in self.var.pop_n(len)? {
431            link.push(Opcode::EraseArr(var.name))?;
432        }
433        Ok(col.clone())
434    }
435
436    fn r#for(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
437        let (step_col, step_ops) = self.expr.pop()?;
438        let (_to_col, to_ops) = self.expr.pop()?;
439        let (_from_col, from_ops) = self.expr.pop()?;
440        let var = self.var.pop()?;
441        let var_name = var.name.clone();
442        link.append(from_ops)?;
443        var.push_as_pop_unary(link)?;
444        link.append(to_ops)?;
445        link.append(step_ops)?;
446        link.push(Opcode::Literal(Val::String(var_name)))?;
447        link.push_for(col.start..step_col.end)?;
448        Ok(col.start..step_col.end)
449    }
450
451    fn r#gosub(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
452        let (sub_col, line_number) = self.expr_pop_line_number()?;
453        let full_col = col.start..sub_col.end;
454        link.push_gosub(sub_col, line_number)?;
455        Ok(full_col)
456    }
457
458    fn r#goto(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
459        let (sub_col, line_number) = self.expr_pop_line_number()?;
460        let full_col = col.start..sub_col.end;
461        link.push_goto(sub_col, line_number)?;
462        Ok(full_col)
463    }
464
465    fn r#if(
466        &mut self,
467        link: &mut Link,
468        col: &Column,
469        then_len: usize,
470        else_len: usize,
471    ) -> Result<Column> {
472        let (_predicate_col, predicate) = self.expr.pop()?;
473        link.append(predicate)?;
474        let else_sym = link.next_symbol();
475        link.push_ifnot(col.clone(), else_sym)?;
476        let elses = self.stmt.pop_n(else_len)?;
477        for (_col, stmt_ops) in self.stmt.pop_n(then_len)? {
478            link.append(stmt_ops)?;
479        }
480        if else_len == 0 {
481            link.push_symbol(else_sym);
482        } else {
483            let finished_sym = link.next_symbol();
484            link.push_jump(col.clone(), finished_sym)?;
485            link.push_symbol(else_sym);
486            for (_col, stmt_ops) in elses {
487                link.append(stmt_ops)?;
488            }
489            link.push_symbol(finished_sym);
490        }
491        Ok(col.clone())
492    }
493
494    fn r#input(&mut self, link: &mut Link, col: &Column, len: usize) -> Result<Column> {
495        let (_prompt_col, prompt) = self.expr.pop()?;
496        let (_caps_col, caps) = self.expr.pop()?;
497        link.append(prompt)?;
498        link.append(caps)?;
499        link.push(Opcode::Literal(Val::try_from(len)?))?;
500        for var in self.var.pop_n(len)? {
501            link.push(Opcode::Input(var.name.clone()))?;
502            var.push_as_pop(link)?;
503        }
504        link.push(Opcode::Input("".into()))?;
505        Ok(col.clone())
506    }
507
508    fn r#let(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
509        let (expr_col, expr_ops) = self.expr.pop()?;
510        link.append(expr_ops)?;
511        self.var.pop()?.push_as_pop(link)?;
512        Ok(col.start..expr_col.end)
513    }
514
515    fn r#list(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
516        let (col_to, ln_to) = self.expr_pop_line_number()?;
517        let (_col_from, ln_from) = self.expr_pop_line_number()?;
518        link.push(Opcode::Literal(Val::try_from(ln_from)?))?;
519        link.push(Opcode::Literal(Val::try_from(ln_to)?))?;
520        link.push(Opcode::List)?;
521        Ok(col.start..col_to.end)
522    }
523
524    fn r#load(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
525        let (sub_col, expr) = self.expr.pop()?;
526        link.append(expr)?;
527        link.push(Opcode::Load)?;
528        Ok(col.start..sub_col.end)
529    }
530
531    fn r#mid(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
532        let var = self.var.pop()?;
533        let (expr_col, expr_link) = self.expr.pop()?;
534        let (_len_col, len_link) = self.expr.pop()?;
535        let (_pos_col, pos_link) = self.expr.pop()?;
536        var.clone().push_as_expression(link)?;
537        link.append(expr_link)?;
538        link.append(len_link)?;
539        link.append(pos_link)?;
540        link.push(Opcode::LetMid)?;
541        var.push_as_pop(link)?;
542        Ok(col.start..expr_col.end)
543    }
544
545    fn r#new_(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
546        link.push(Opcode::New)?;
547        Ok(col.clone())
548    }
549
550    fn r#next(&mut self, link: &mut Link, col: &Column, len: usize) -> Result<Column> {
551        for var in self.var.pop_n(len)? {
552            var.test_for_built_in(false)?;
553            link.push(Opcode::Next(var.name))?;
554        }
555        Ok(col.clone())
556    }
557
558    fn r#on(
559        &mut self,
560        link: &mut Link,
561        col: &Column,
562        len: usize,
563        is_gosub: bool,
564    ) -> Result<Column> {
565        let line_numbers = self.expr.pop_n(len)?;
566        let len = Val::try_from(len)?;
567        let (mut sub_col, var_ops) = self.expr.pop()?;
568        let ret_symbol = link.next_symbol();
569        if is_gosub {
570            link.push_return_val(col.clone(), ret_symbol)?;
571        }
572        link.push(Opcode::Literal(len))?;
573        link.append(var_ops)?;
574        link.push(Opcode::On)?;
575        for (column, ops) in line_numbers {
576            sub_col.end = column.end;
577            let ln = match LineNumber::try_from(&ops) {
578                Ok(ln) => ln,
579                Err(e) => return Err(e.in_column(&column)),
580            };
581            link.push_goto(column, ln)?;
582        }
583        if is_gosub {
584            link.push_symbol(ret_symbol);
585        }
586        Ok(col.start..sub_col.end)
587    }
588
589    fn r#print(&mut self, link: &mut Link, col: &Column, len: usize) -> Result<Column> {
590        for (_col, expr_ops) in self.expr.pop_n(len)? {
591            link.append(expr_ops)?;
592            link.push(Opcode::Print)?;
593        }
594        Ok(col.clone())
595    }
596
597    fn r#read(&mut self, link: &mut Link, col: &Column, len: usize) -> Result<Column> {
598        for var in self.var.pop_n(len)? {
599            link.push(Opcode::Read)?;
600            var.push_as_pop(link)?;
601        }
602        Ok(col.clone())
603    }
604
605    fn r#renum(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
606        let (_col_step, step) = self.expr_pop_line_number()?;
607        let (_col_old_start, old_start) = self.expr_pop_line_number()?;
608        let (_col_new_start, new_start) = self.expr_pop_line_number()?;
609        if let Some(new_start) = new_start {
610            if let Some(old_start) = old_start {
611                if let Some(step) = step {
612                    link.push(Opcode::Literal(Val::Single(new_start as f32)))?;
613                    link.push(Opcode::Literal(Val::Single(old_start as f32)))?;
614                    link.push(Opcode::Literal(Val::Single(step as f32)))?;
615                    link.push(Opcode::Renum)?;
616                }
617            }
618        }
619        Ok(col.clone())
620    }
621
622    fn r#restore(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
623        let mut line_number: LineNumber = None;
624        let (sub_col, ops) = self.expr.pop()?;
625        if let Ok(ln) = LineNumber::try_from(&ops) {
626            line_number = ln;
627        }
628        link.push_restore(sub_col, line_number)?;
629        Ok(col.clone())
630    }
631
632    fn r#return(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
633        link.push(Opcode::Return)?;
634        Ok(col.clone())
635    }
636
637    fn r#run(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
638        let (sub_col, ops) = self.expr.pop()?;
639        let full_col = col.start..sub_col.end;
640        if let Ok(filename) = Rc::<str>::try_from(&ops) {
641            link.push(Opcode::Literal(Val::String(filename)))?;
642            link.push(Opcode::LoadRun)?;
643        } else if let Ok(ln) = LineNumber::try_from(&ops) {
644            link.push_run(sub_col, ln)?;
645        } else {
646            link.push_run(sub_col, None)?;
647        }
648        Ok(full_col)
649    }
650
651    fn r#save(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
652        let (sub_col, expr) = self.expr.pop()?;
653        link.append(expr)?;
654        link.push(Opcode::Save)?;
655        Ok(col.start..sub_col.end)
656    }
657
658    fn r#stop(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
659        link.push(Opcode::Stop)?;
660        Ok(col.clone())
661    }
662
663    fn r#swap(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
664        let var1 = self.var.pop()?;
665        let var2 = self.var.pop()?;
666        var1.test_for_built_in(false)?;
667        var2.test_for_built_in(false)?;
668        var1.clone().push_as_expression(link)?;
669        var2.clone().push_as_expression(link)?;
670        link.push(Opcode::Swap)?;
671        var1.push_as_pop(link)?;
672        var2.push_as_pop(link)?;
673        Ok(col.clone())
674    }
675
676    fn r#troff(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
677        link.push(Opcode::Troff)?;
678        Ok(col.clone())
679    }
680
681    fn r#tron(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
682        link.push(Opcode::Tron)?;
683        Ok(col.clone())
684    }
685
686    fn r#wend(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
687        link.push_wend(col.clone())?;
688        Ok(col.clone())
689    }
690
691    fn r#while(&mut self, link: &mut Link, col: &Column) -> Result<Column> {
692        let (sub_col, expr) = self.expr.pop()?;
693        link.push_while(col.clone(), expr)?;
694        Ok(col.start..sub_col.end)
695    }
696}