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}