basic/lang/
line.rs

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