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}