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()
    }
}