1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
use super::{ast::*, lex, parse, token, Column, Error, LineNumber, MaxValue}; use std::collections::HashMap; #[derive(Debug)] pub struct Line { number: LineNumber, tokens: Vec<token::Token>, } impl Line { pub fn new(source_line: &str) -> Line { let (number, tokens) = lex(&source_line); Line { number, tokens } } pub fn number(&self) -> LineNumber { self.number } pub fn is_direct(&self) -> bool { self.number.is_none() } pub fn is_empty(&self) -> bool { self.tokens.is_empty() } pub fn ast(&self) -> Result<Vec<Statement>, Error> { parse(self.number, &self.tokens) } pub fn renum(&self, changes: &HashMap<u16, u16>) -> Self { let number = if let Some(line_number) = self.number { changes.get(&line_number).cloned().or(self.number) } else { None }; let ast = match parse(self.number, &self.tokens) { Ok(ast) => ast, Err(_) => { return Line { number: self.number, tokens: self.tokens.clone(), } } }; let mut visitor = RenumVisitor::new(changes); for statement in ast { statement.accept(&mut visitor); } if visitor.replace.is_empty() { return Line { number, tokens: self.tokens.clone(), }; } let mut s: String = self.tokens.iter().map(|s| s.to_string()).collect(); while let Some((col, num)) = visitor.replace.pop() { s.replace_range(col, &format!("{}", num)); } let (_, tokens) = lex(&s); Line { number, tokens } } } #[derive(Debug)] struct RenumVisitor<'a> { changes: &'a HashMap<u16, u16>, replace: Vec<(Column, u16)>, } impl<'a> RenumVisitor<'a> { fn new(changes: &HashMap<u16, u16>) -> RenumVisitor { RenumVisitor { changes, replace: vec![], } } fn line(&mut self, expr: &Expression) { use Expression::*; let (col, n) = match expr { Single(col, n) => (col, *n as f64), Double(col, n) => (col, *n), Integer(col, n) => (col, *n as f64), _ => return, }; if n > LineNumber::max_value() as f64 { return; } let n = n as u16; if let Some(new_num) = self.changes.get(&n) { self.replace.push((col.clone(), *new_num)); } } } impl<'a> Visitor for RenumVisitor<'a> { fn visit_statement(&mut self, stmt: &Statement) { use Statement::*; match stmt { Goto(_, ln) | Gosub(_, ln) | Restore(_, ln) | Run(_, ln) => self.line(ln), Delete(_, ln1, ln2) | List(_, ln1, ln2) => { self.line(ln1); self.line(ln2); } OnGoto(_, _, ve) => { for ln in ve { self.line(ln); } } _ => {} } } } impl std::fmt::Display for Line { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let s: String = self.tokens.iter().map(|s| s.to_string()).collect(); if let Some(number) = self.number { write!(f, "{} {}", number, s) } else { write!(f, "{}", s) } } } impl<'a> IntoIterator for &'a Line { type Item = &'a Line; type IntoIter = std::option::IntoIter<Self::Item>; fn into_iter(self) -> Self::IntoIter { Some(self).into_iter() } }