1pub mod binary_parser;
2pub mod string_parser;
4pub mod tokens;
6
7use std::fmt::{self};
8
9use cpclib_common::winnow::Parser;
10use cpclib_common::winnow::ascii::space0;
11use cpclib_sna::Snapshot;
12use string_parser::parse_basic_program;
13use thiserror::Error;
14use tokens::BasicToken;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum BasicProgramLineIdx {
19 Index(usize),
21 Number(u16)
23}
24
25#[derive(Debug, Error, PartialEq, Eq, Clone)]
26#[allow(missing_docs)]
27pub enum BasicError {
28 #[error("Line does not exist: {:?}", idx)]
29 UnknownLine { idx: BasicProgramLineIdx },
30 #[error("{}", msg)]
31 ParseError { msg: String },
32 #[error("Exponent Overflow")]
33 ExponentOverflow
34}
35
36#[derive(Debug, Clone)]
38pub struct BasicLine {
39 line_number: u16,
41 tokens: Vec<BasicToken>,
43 forced_length: Option<u16>
45}
46
47impl fmt::Display for BasicLine {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 write!(f, "{} ", self.line_number)?;
50 for token in self.tokens().iter() {
51 write!(f, "{token}")?;
52 }
53 Ok(())
54 }
55}
56
57#[allow(missing_docs)]
58impl BasicLine {
59 pub fn line_number(&self) -> u16 {
60 self.line_number
61 }
62
63 pub fn new(line_number: u16, tokens: &[BasicToken]) -> Self {
65 Self {
66 line_number,
67 tokens: tokens.to_vec(),
68 forced_length: None
69 }
70 }
71
72 pub fn add_length(&mut self, length: u16) {
73 let current = self.expected_length();
74 self.force_length(current + length);
75 }
76
77 pub fn force_length(&mut self, length: u16) {
78 self.forced_length = Some(length);
79 }
80
81 pub fn expected_length(&self) -> u16 {
83 match self.forced_length {
84 Some(val) => val,
85 None => self.real_complete_length()
86 }
87 }
88
89 pub fn real_length(&self) -> u16 {
91 self.tokens_as_bytes().len() as _
92 }
93
94 pub fn real_complete_length(&self) -> u16 {
95 self.real_length() + 2 + 2 + 1
96 }
97
98 pub fn len(&self) -> usize {
100 self.tokens().len()
101 }
102
103 pub fn is_empty(&self) -> bool {
105 self.tokens().is_empty()
106 }
107
108 pub fn tokens_as_bytes(&self) -> Vec<u8> {
109 self.tokens
110 .iter()
111 .flat_map(BasicToken::as_bytes)
112 .collect::<Vec<u8>>()
113 }
114
115 pub fn as_bytes(&self) -> Vec<u8> {
121 let size = self.expected_length();
122
123 let mut content = vec![
124 (size % 256) as u8,
125 (size / 256) as u8,
126 (self.line_number % 256) as u8,
127 (self.line_number / 256) as u8,
128 ];
129 content.extend_from_slice(&self.tokens_as_bytes());
130 content.push(0);
131
132 content
133 }
134
135 pub fn tokens(&self) -> &[BasicToken] {
136 &self.tokens
137 }
138}
139
140#[derive(Debug, Clone)]
142pub struct BasicProgram {
143 lines: Vec<BasicLine>
145}
146
147impl fmt::Display for BasicProgram {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 for line in &self.lines {
150 writeln!(f, "{line}")?;
151 }
152 Ok(())
153 }
154}
155
156#[allow(missing_docs)]
157impl BasicProgram {
158 pub fn new(lines: Vec<BasicLine>) -> Self {
160 Self { lines }
161 }
162
163 pub fn parse<S: AsRef<str>>(code: S) -> Result<Self, BasicError> {
165 let input = code.as_ref();
166 match (parse_basic_program, space0).parse(input) {
167 Ok((prog, _)) => Ok(prog),
168 Err(e) => {
169 Err(BasicError::ParseError {
170 msg: format!("Error while parsing the Basic content: {e}")
171 })
172 },
173
174 _ => unreachable!()
175 }
176 }
177
178 pub fn add_line(&mut self, line: BasicLine) {
180 self.lines.push(line);
181 }
182
183 pub fn get_line_mut(&mut self, idx: BasicProgramLineIdx) -> Option<&mut BasicLine> {
185 match self.line_idx_as_valid_index(idx) {
186 Ok(BasicProgramLineIdx::Index(index)) => self.lines.get_mut(index),
187 _ => None
188 }
189 }
190
191 pub fn get_line(&mut self, idx: BasicProgramLineIdx) -> Option<&BasicLine> {
193 match self.line_idx_as_valid_index(idx) {
194 Ok(BasicProgramLineIdx::Index(index)) => self.lines.get(index),
195 _ => None
196 }
197 }
198
199 pub fn is_first_line(&self, idx: BasicProgramLineIdx) -> bool {
201 match self.line_idx_as_valid_index(idx) {
202 Ok(BasicProgramLineIdx::Index(0)) => true,
203 _ => false
204 }
205 }
206
207 pub fn previous_idx(&self, idx: BasicProgramLineIdx) -> Option<BasicProgramLineIdx> {
209 match self.line_idx_as_valid_index(idx) {
210 Ok(BasicProgramLineIdx::Index(index)) => {
211 if index == 0 {
212 None
213 }
214 else {
215 Some(BasicProgramLineIdx::Index(index - 1))
216 }
217 },
218 Err(_e) => None,
219 _ => unreachable!()
220 }
221 }
222
223 pub fn has_line(&self, idx: BasicProgramLineIdx) -> bool {
225 self.line_idx_as_valid_index(idx).is_ok()
226 }
227
228 fn line_idx_as_valid_index(
230 &self,
231 idx: BasicProgramLineIdx
232 ) -> Result<BasicProgramLineIdx, BasicError> {
233 match &idx {
234 BasicProgramLineIdx::Index(index) => {
235 if self.lines.len() <= *index {
236 Err(BasicError::UnknownLine { idx })
237 }
238 else {
239 Ok(idx)
240 }
241 },
242
243 BasicProgramLineIdx::Number(number) => {
244 match self.get_index_of_line_number(*number) {
245 Some(index) => Ok(BasicProgramLineIdx::Index(index)),
246 None => Err(BasicError::UnknownLine { idx })
247 }
248 },
249 }
250 }
251
252 fn get_index_of_line_number(&self, number: u16) -> Option<usize> {
254 self.lines
255 .iter()
256 .enumerate()
257 .filter_map(move |(index, line)| {
258 if line.line_number == number {
259 Some(index)
260 }
261 else {
262 None
263 }
264 })
265 .collect::<Vec<_>>()
266 .first()
267 .cloned()
268 }
269
270 pub fn hide_line(&mut self, current_idx: BasicProgramLineIdx) -> Result<(), BasicError> {
273 if !self.has_line(current_idx) {
274 Err(BasicError::UnknownLine { idx: current_idx })
275 }
276 else if self.is_first_line(current_idx) {
277 self.lines[0].line_number = 0;
279 Ok(())
280 }
281 else {
282 match self.previous_idx(current_idx) {
283 Some(previous_idx) => {
284 let current_length = self.get_line(current_idx).unwrap().real_complete_length(); self.get_line_mut(previous_idx)
286 .unwrap()
287 .add_length(current_length);
288 self.get_line_mut(current_idx).unwrap().force_length(0);
289 Ok(())
290 },
291 None => Err(BasicError::UnknownLine { idx: current_idx })
292 }
293 }
294 }
295
296 pub fn hide_lines(&mut self, lines: &[u16]) -> Result<(), BasicError> {
297 match lines.len() {
298 0 => Ok(()),
299 1 => self.hide_line(BasicProgramLineIdx::Number(lines[0])),
300 _ => {
301 unimplemented!(
302 "The current version is only able to hide one line. I can still implement multiline version if needed"
303 )
304 }
305 }
306 }
307
308 pub fn as_bytes(&self) -> Vec<u8> {
310 let mut bytes = self
311 .lines
312 .iter()
313 .flat_map(BasicLine::as_bytes)
314 .collect::<Vec<u8>>();
315 bytes.resize(bytes.len() + 3, 0);
316 bytes
317 }
318
319 pub fn as_sna(&self) -> Result<Snapshot, String> {
320 let bytes = self.as_bytes();
321 let mut sna = Snapshot::new_6128()?;
322 sna.unwrap_memory_chunks();
323 sna.add_data(&bytes, 0x170).map_err(|e| format!("{e:?}"))?;
324 Ok(sna)
325 }
326}
327
328#[allow(clippy::let_unit_value)]
329#[allow(clippy::shadow_unrelated)]
330#[cfg(test)]
331pub mod test {
332
333 use super::*;
334
335 #[test]
336 fn parse_complete() {
337 let code = "10 call &0: call &0\n";
338 BasicProgram::parse(code).expect("Unable to produce basic tokens");
339
340 let code1 = "10 call &0: call &0";
341 BasicProgram::parse(code1).expect("Unable to produce basic tokens");
342
343 let code2 = "10 ' blabla bla\n20 ' blab bla bal\n30 call &180";
344 BasicProgram::parse(code2).expect("Unable to produce basic tokens");
345 }
346
347 #[test]
348 fn parse_correct() {
349 let code = "10 CALL &1234";
350 let prog = BasicProgram::parse(code).unwrap();
351 let bytes = prog.as_bytes();
352 let expected = [10, 0, 10, 0, 131, 32, 28, 0x34, 0x12, 0, 0, 0, 0];
353
354 assert_eq!(&bytes, &expected);
355
356 let code = "10 CALL &1234\n20 CALL &1234";
357 let prog = BasicProgram::parse(code).unwrap();
358 let bytes = prog.as_bytes();
359 let expected = [
360 10, 0, 10, 0, 131, 32, 28, 0x34, 0x12, 0, 10, 0, 20, 0, 131, 32, 28, 0x34, 0x12, 0, 0,
361 0, 0
362 ];
363
364 assert_eq!(&bytes, &expected);
365 }
366
367 #[test]
368 fn hide1() {
369 let code = "10 CALL &1234";
370 let mut prog = BasicProgram::parse(code).unwrap();
371 prog.hide_line(BasicProgramLineIdx::Number(10)).unwrap();
372 let bytes = prog.as_bytes();
373 let expected = vec![10, 0, 0, 0, 131, 32, 28, 0x34, 0x12, 0, 0, 0, 0];
374
375 assert_eq!(bytes, expected);
376 }
377
378 #[test]
379 fn indices() {
380 let code = "10 CALL &1234\n20 CALL &1234";
381 let prog = BasicProgram::parse(code).unwrap();
382
383 assert_eq!(
384 Ok(BasicProgramLineIdx::Index(0)),
385 prog.line_idx_as_valid_index(BasicProgramLineIdx::Index(0))
386 );
387 assert_eq!(
388 Ok(BasicProgramLineIdx::Index(1)),
389 prog.line_idx_as_valid_index(BasicProgramLineIdx::Index(1))
390 );
391 assert_eq!(
392 Err(BasicError::UnknownLine {
393 idx: BasicProgramLineIdx::Index(2)
394 }),
395 prog.line_idx_as_valid_index(BasicProgramLineIdx::Index(2))
396 );
397
398 assert_eq!(
399 Some(BasicProgramLineIdx::Index(0)),
400 prog.previous_idx(BasicProgramLineIdx::Index(1))
401 );
402 assert_eq!(None, prog.previous_idx(BasicProgramLineIdx::Index(0)));
403
404 assert!(prog.has_line(BasicProgramLineIdx::Number(10)));
405 assert!(prog.has_line(BasicProgramLineIdx::Number(20)));
406 assert!(!prog.has_line(BasicProgramLineIdx::Number(30)));
407 assert!(prog.has_line(BasicProgramLineIdx::Index(0)));
408 assert!(prog.has_line(BasicProgramLineIdx::Index(1)));
409 assert!(!prog.has_line(BasicProgramLineIdx::Index(2)));
410 }
411
412 #[test]
413 fn hide2() {
414 let code = "10 CALL &1234\n20 CALL &1234";
415 let mut prog = BasicProgram::parse(code).unwrap();
416 assert!(prog.has_line(BasicProgramLineIdx::Number(20)));
417 prog.hide_line(BasicProgramLineIdx::Number(20)).unwrap();
418 let bytes = prog.as_bytes();
419 let expected = vec![
420 20, 0, 10, 0, 131, 32, 28, 0x34, 0x12, 0, 00, 0, 20, 0, 131, 32, 28, 0x34, 0x12, 0, 0,
421 0, 0,
422 ];
423
424 assert_eq!(bytes, expected);
425 }
426}