1use std::fmt::Debug;
2use std::sync::Arc;
3
4use cpclib_common::itertools::Itertools;
5use cpclib_common::smallvec::SmallVec;
6use cpclib_tokens::symbols::*;
7use cpclib_tokens::tokens::*;
8
9use crate::assembler::{Env, Visited, assemble_defs_item};
10use crate::error::*;
11use crate::implementation::expression::ExprEvaluationExt;
12use crate::implementation::listing::ListingExt;
13use crate::{AssemblingOptions, EnvOptions};
14
15pub trait TokenExt: ListingElement + Debug + Visited {
17 fn estimated_duration(&self) -> Result<usize, AssemblerError>;
18 fn unroll(&self, env: &mut crate::Env) -> Option<Result<Vec<&Self>, AssemblerError>>;
20
21 fn disassemble_data(&self) -> Result<Listing, String>;
23
24 fn to_bytes_with_options(&self, option: EnvOptions) -> Result<Vec<u8>, AssemblerError> {
25 let mut env = Env::new(option);
26 loop {
28 env.start_new_pass();
29 if env.pass().is_finished() {
32 break;
33 }
34
35 self.visited(&mut env)?;
36 }
37
38 Ok(env.produced_bytes())
39 }
40
41 fn number_of_bytes(&self) -> Result<usize, String> {
43 let bytes = self.to_bytes();
44 if bytes.is_ok() {
45 Ok(bytes.ok().unwrap().len())
46 }
47 else {
48 Err(format!("Unable to get the bytes of this token: {:?}", self))
49 }
50 }
51
52 fn fallback_number_of_bytes(&self) -> Result<usize, String>;
54
55 fn number_of_bytes_with_context(
57 &self,
58 table: &mut SymbolsTableCaseDependent
59 ) -> Result<usize, String> {
60 let bytes = self.to_bytes_with_context(table);
61 if bytes.is_ok() {
62 Ok(bytes.ok().unwrap().len())
63 }
64 else {
65 eprintln!("{:?}", bytes);
66 Err(format!("Unable to get the bytes of this token: {:?}", self))
67 }
68 }
69
70 fn to_bytes(&self) -> Result<Vec<u8>, AssemblerError> {
73 let mut table = SymbolsTableCaseDependent::laxist();
74 let table = &mut table;
75 self.to_bytes_with_context(table)
76 }
77
78 #[allow(clippy::match_same_arms)]
80 fn to_bytes_with_context(
81 &self,
82 table: &mut SymbolsTableCaseDependent
83 ) -> Result<Vec<u8>, AssemblerError> {
84 let mut options = if table.is_case_sensitive() {
85 AssemblingOptions::new_case_sensitive()
86 }
87 else {
88 AssemblingOptions::new_case_insensitive()
89 };
90 options.set_symbols(table.table());
91
92 let options = EnvOptions::new(Default::default(), options, Arc::new(()));
93 self.to_bytes_with_options(options)
94 }
95
96 fn is_valid(&self) -> bool {
98 self.to_bytes().is_ok()
99 }
100}
101
102impl TokenExt for Token {
121 fn unroll(&self, env: &mut crate::Env) -> Option<Result<Vec<&Self>, AssemblerError>> {
124 if let Token::Repeat(expr, tokens, _counter_label, _counter_start) = self {
125 let count: Result<ExprResult, AssemblerError> = expr.resolve(env);
126 if count.is_err() {
127 Some(Err(count.err().unwrap()))
128 }
129 else {
130 let count = count.unwrap().int().unwrap();
131 let mut res = Vec::with_capacity(count as usize * tokens.len());
132 for _i in 0..count {
133 for t in tokens.iter() {
135 res.push(t);
136 }
137 }
138 Some(Ok(res))
139 }
140 }
141 else {
142 None
143 }
144 }
145
146 fn disassemble_data(&self) -> Result<Listing, String> {
149 let wrap = |bytes: &[u8]| {
151 use crate::disass::disassemble;
152
153 let lst = disassemble(bytes);
154 for token in lst.listing() {
155 match token {
156 Token::Defb(_) | Token::Defw(_) | Token::Defs(_) => {
157 return Err(format!("{} as not been disassembled", token));
158 },
159 _ => {}
160 }
161 }
162
163 Ok(lst)
164 };
165
166 match self {
167 Token::Defs(l) => {
168 l.iter()
169 .map(|(e, f)| {
170 assemble_defs_item(e, f.as_ref(), &mut Env::default())
171 .map_err(|err| format!("Unable to assemble {}: {:?}", self, err))
172 })
173 .fold_ok(SmallVec::<[u8; 4]>::new(), |mut acc, v| {
174 acc.extend_from_slice(v.as_slice());
175 acc
176 })
177 .and_then(|b| wrap(&b))
178 },
179
180 Token::Defb(e) | Token::Defw(e) | Token::Str(e) => {
181 let mut env = Env::default();
182 env.visit_db_or_dw_or_str(self.into(), e, 0.into())
183 .map_err(|err| format!("Unable to assemble {}: {:?}", self, err))?;
184 wrap(&env.produced_bytes())
185 },
186
187 _ => {
188 let mut lst = Listing::new();
189 lst.push(self.clone());
190 Ok(lst)
191 }
192 }
193 }
194
195 #[allow(clippy::match_same_arms)]
198 fn estimated_duration(&self) -> Result<usize, AssemblerError> {
199 let duration = match self {
200 Token::Assert(..)
201 | Token::Breakpoint { .. }
202 | Token::Comment(_)
203 | Token::Label(_)
204 | Token::Equ { .. }
205 | Token::Protect(..) => 0,
206
207 Token::Repeat(Expr::Value(count), lst, ..) if *count >= 0 => {
208 let lst_count = lst.estimated_duration()?;
209 lst_count * (*count as usize)
210 },
211
212 Token::Defw(_) | Token::Defb(_) | Token::Defs(_) => {
214 self.disassemble_data()
215 .map_err(|e| AssemblerError::DisassemblerError { msg: e })
216 .and_then(|lst| lst.estimated_duration())?
217 },
218
219 Token::OpCode(mnemonic, arg1, arg2, _arg3) => {
220 match mnemonic {
221 &Mnemonic::Add => {
222 match arg1 {
223 Some(DataAccess::Register8(_)) => {
224 match arg2 {
225 Some(DataAccess::Register8(_)) => 1,
226 Some(DataAccess::IndexRegister16WithIndex(..)) => 5,
227 _ => 2
228 }
229 },
230 Some(DataAccess::Register16(_)) => 4,
231 Some(DataAccess::IndexRegister16(_)) => 5,
232 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
233 }
234 },
235
236 &Mnemonic::And | &Mnemonic::Or | &Mnemonic::Xor => {
237 match arg1 {
238 Some(DataAccess::Register8(_)) => 1,
239 Some(DataAccess::IndexRegister8(_)) => 2,
240 Some(DataAccess::Expression(_)) => 2,
241 Some(DataAccess::MemoryRegister16(_)) => 2,
242 Some(DataAccess::IndexRegister16WithIndex(..)) => 5,
243 _ => unreachable!()
244 }
245 },
246
247 Mnemonic::Call => {
248 match arg1 {
249 Some(_) => 3, None => 5
251 }
252 },
253
254 &Mnemonic::Djnz => 3, &Mnemonic::ExAf => 1,
258
259 &Mnemonic::Inc | &Mnemonic::Dec => {
260 match arg1 {
261 Some(DataAccess::Register8(_)) => 1,
262 Some(DataAccess::Register16(_)) => 2,
263 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
264 }
265 },
266
267 &Mnemonic::Jp => {
268 match arg1 {
269 &None => {
270 match arg2 {
271 Some(DataAccess::Expression(_)) => 3,
272 Some(DataAccess::MemoryRegister16(Register16::Hl)) => 1,
273 Some(DataAccess::IndexRegister16(_)) => 2,
274 _ => {
275 panic!(
276 "Impossible case {:?}, {:?}, {:?}",
277 mnemonic, arg1, arg2
278 )
279 }
280 }
281 },
282
283 Some(DataAccess::FlagTest(_)) => {
284 match arg2 {
285 Some(DataAccess::Expression(_)) => 3,
286 _ => {
287 panic!(
288 "Impossible case {:?}, {:?}, {:?}",
289 mnemonic, arg1, arg2
290 )
291 }
292 }
293 },
294
295 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
296 }
297 },
298
299 &Mnemonic::Jr => {
301 match arg1 {
302 &None => {
303 match arg2 {
304 Some(DataAccess::Expression(_)) => 3,
305 _ => {
306 panic!(
307 "Impossible case {:?}, {:?}, {:?}",
308 mnemonic, arg1, arg2
309 )
310 }
311 }
312 },
313
314 Some(DataAccess::FlagTest(_)) => {
315 match arg2 {
316 Some(DataAccess::Expression(_)) => 2, _ => {
318 panic!(
319 "Impossible case {:?}, {:?}, {:?}",
320 mnemonic, arg1, arg2
321 )
322 }
323 }
324 },
325
326 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
327 }
328 },
329
330 &Mnemonic::Ld => {
331 match arg1 {
332 Some(DataAccess::MemoryRegister16(_)) => {
334 match arg2 {
335 Some(DataAccess::Register8(_)) => 2,
336 Some(DataAccess::Expression(_)) => 3, _ => {
338 panic!(
339 "Impossible case {:?}, {:?}, {:?}",
340 mnemonic, arg1, arg2
341 )
342 }
343 }
344 },
345
346 Some(DataAccess::Register8(_dst)) => {
348 match arg2 {
349 Some(DataAccess::Register8(_)) => 1,
350 Some(DataAccess::MemoryRegister16(Register16::Hl)) => 2,
351 Some(DataAccess::Expression(_)) => 2,
352 Some(DataAccess::Memory(_)) => 4,
353 Some(DataAccess::IndexRegister16WithIndex(..)) => 5,
354 _ => {
355 panic!(
356 "Impossible case {:?}, {:?}, {:?}",
357 mnemonic, arg1, arg2
358 )
359 }
360 }
361 },
362
363 Some(DataAccess::Register16(dst)) => {
365 match arg2 {
366 Some(DataAccess::Expression(_)) => 3,
367 Some(DataAccess::Memory(_)) if dst == &Register16::Hl => 5,
368 Some(DataAccess::Memory(_)) => 6,
369 _ => {
370 panic!(
371 "Impossible case {:?}, {:?}, {:?}",
372 mnemonic, arg1, arg2
373 )
374 }
375 }
376 },
377
378 Some(DataAccess::IndexRegister16(_)) => {
379 match arg2 {
380 Some(DataAccess::Expression(_)) => 4,
381 _ => {
382 panic!(
383 "Impossible case {:?}, {:?}, {:?}",
384 mnemonic, arg1, arg2
385 )
386 }
387 }
388 },
389
390 Some(DataAccess::Memory(_)) => {
391 match arg2 {
392 Some(DataAccess::Register8(Register8::A)) => 4,
393 Some(DataAccess::Register16(Register16::Hl)) => 5,
394 Some(DataAccess::Register16(_)) => 6,
395 Some(DataAccess::IndexRegister16(_)) => 6,
396 _ => {
397 panic!(
398 "Impossible case {:?}, {:?}, {:?}",
399 mnemonic, arg1, arg2
400 )
401 }
402 }
403 },
404
405 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
406 }
407 },
408
409 &Mnemonic::Ldi | &Mnemonic::Ldd => 5,
410
411 &Mnemonic::Nop | &Mnemonic::Exx | &Mnemonic::Di | &Mnemonic::ExHlDe => 1,
412 &Mnemonic::Nop2 => 2,
413
414 &Mnemonic::Out => {
415 match arg1 {
416 Some(DataAccess::PortC) => 4, Some(DataAccess::Expression(_)) => 3,
418 Some(DataAccess::PortN(_)) => 3,
419 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
420 }
421 },
422
423 Mnemonic::Outi | Mnemonic::Outd => 5,
424
425 &Mnemonic::Pop => {
426 match arg1 {
427 Some(DataAccess::Register16(_)) => 3,
428 Some(DataAccess::IndexRegister16(_)) => 4,
429 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
430 }
431 },
432
433 &Mnemonic::Push => {
434 match arg1 {
435 Some(DataAccess::Register16(_)) => 4,
436 Some(DataAccess::IndexRegister16(_)) => 5,
437 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
438 }
439 },
440
441 &Mnemonic::Res | &Mnemonic::Set => {
442 match arg2 {
443 Some(DataAccess::Register8(_)) => 2,
444 Some(DataAccess::MemoryRegister16(_)) => 3, Some(DataAccess::IndexRegister16WithIndex(..)) => 7,
446 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
447 }
448 },
449
450 &Mnemonic::Ret => {
451 match arg1 {
452 None => 3,
453 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
454 }
455 },
456
457 &Mnemonic::Sub => {
458 match arg1 {
459 Some(DataAccess::Register8(_)) => 1,
460 Some(DataAccess::IndexRegister8(_)) => 2,
461 Some(DataAccess::Expression(_)) => 2,
462 Some(DataAccess::MemoryRegister16(Register16::Hl)) => 2,
463 Some(DataAccess::IndexRegister16WithIndex(..)) => 5,
464 _ => panic!("Impossible case {:?}, {:?}, {:?}", mnemonic, arg1, arg2)
465 }
466 },
467
468 _ => {
469 panic!(
470 "Duration not set for {:?}, {:?}, {:?}",
471 mnemonic, arg1, arg2
472 )
473 }
474 }
475 },
476 _ => {
477 return Err(AssemblerError::BugInAssembler {
478 file: file!(),
479 line: line!(),
480 msg: format!("Duration computation for {:?} not yet coded", self)
481 });
482 }
483 };
484 Ok(duration)
485 }
486
487 fn fallback_number_of_bytes(&self) -> Result<usize, String> {
488 match self {
489 Self::OpCode(mne, arg1, arg2, arg3) => {
490 let arg1 = arg1.as_ref().map(|arg| arg.replace_expressions_by_0());
491 let arg2 = arg2.as_ref().map(|arg| arg.replace_expressions_by_0());
492
493 Self::OpCode(*mne, arg1, arg2, *arg3).number_of_bytes()
494 },
495 Self::Comment(..) | Self::Label(..) | Self::Assert(..) => Ok(0),
496 _ => {
497 Result::Err(format!(
498 "fallback_number_of_bytes not implemented for {self}"
499 ))
500 },
501 }
502 }
503}
504
505#[cfg(test)]
506#[allow(clippy::pedantic)]
507#[allow(warnings)]
508mod tests {
509 use crate::preamble::*;
510
511 #[test]
512 fn test_timing2() {
513 assert_eq!(defs_expr_expr(10, 0).estimated_duration().unwrap(), 10);
515 assert_eq!(defw(0).estimated_duration().unwrap(), 2);
516 assert_eq!(defb(0).estimated_duration().unwrap(), 1);
517
518 assert_eq!(exx().estimated_duration().unwrap(), 1);
519
520 assert_eq!(pop_de().estimated_duration().unwrap(), 3);
521
522 assert_eq!(inc_l().estimated_duration().unwrap(), 1);
523
524 assert_eq!(jp_label("XX").estimated_duration().unwrap(), 3);
525
526 assert_eq!(ld_l_mem_ix(14.into()).estimated_duration().unwrap(), 5);
527
528 assert_eq!(ld_mem_hl_e().estimated_duration().unwrap(), 2);
529
530 assert_eq!(ld_e_mem_hl().estimated_duration().unwrap(), 2);
531
532 assert_eq!(ld_d_mem_hl().estimated_duration().unwrap(), 2);
533
534 assert_eq!(out_c_d().estimated_duration().unwrap(), 4);
535 }
536
537 #[test]
538 fn is_valid_ok() {
539 assert!(out_c_d().is_valid());
540 }
541
542 #[test]
543 fn is_valid_nok() {
544 assert!(
545 !Token::OpCode(
546 Mnemonic::Out,
547 Some(DataAccess::Register8(Register8::C)),
548 Some(DataAccess::Register8(Register8::A)),
549 None
550 )
551 .is_valid()
552 );
553 }
554
555 #[cfg(test)]
556 mod test {
557
558 use ParseToken;
559
560 use super::*;
561 #[test]
562 fn fixup_duration() {
563 assert_eq!(
564 Token::parse_token(" di")
565 .unwrap()
566 .estimated_duration()
567 .unwrap(),
568 1
569 );
570 assert_eq!(
571 Token::parse_token(" add a,c ")
572 .unwrap()
573 .estimated_duration()
574 .unwrap(),
575 1
576 );
577 assert_eq!(
578 Token::parse_token(" ld l, a")
579 .unwrap()
580 .estimated_duration()
581 .unwrap(),
582 1
583 );
584 assert_eq!(
585 Token::parse_token(" ld b, e")
586 .unwrap()
587 .estimated_duration()
588 .unwrap(),
589 1
590 );
591 assert_eq!(
592 Token::parse_token(" ld e, b")
593 .unwrap()
594 .estimated_duration()
595 .unwrap(),
596 1
597 );
598 assert_eq!(
599 Token::parse_token(" exx")
600 .unwrap()
601 .estimated_duration()
602 .unwrap(),
603 1
604 );
605 assert_eq!(
606 Token::parse_token(" push bc")
607 .unwrap()
608 .estimated_duration()
609 .unwrap(),
610 4
611 );
612 assert_eq!(
613 Token::parse_token(" pop bc")
614 .unwrap()
615 .estimated_duration()
616 .unwrap(),
617 3
618 );
619 assert_eq!(
620 Token::parse_token(" push ix")
621 .unwrap()
622 .estimated_duration()
623 .unwrap(),
624 5
625 );
626 assert_eq!(
627 Token::parse_token(" pop ix")
628 .unwrap()
629 .estimated_duration()
630 .unwrap(),
631 4
632 );
633 assert_eq!(
634 Token::parse_token(" ld b, nnn")
635 .unwrap()
636 .estimated_duration()
637 .unwrap(),
638 2
639 );
640 assert_eq!(
641 Token::parse_token(" ld e, (hl)")
642 .unwrap()
643 .estimated_duration()
644 .unwrap(),
645 2
646 );
647 assert_eq!(
648 Token::parse_token(" ld d, (hl)")
649 .unwrap()
650 .estimated_duration()
651 .unwrap(),
652 2
653 );
654 assert_eq!(
655 Token::parse_token(" ld a, (hl)")
656 .unwrap()
657 .estimated_duration()
658 .unwrap(),
659 2
660 );
661 assert_eq!(
662 dbg!(Token::parse_token(" ld a, (dd)").unwrap())
663 .estimated_duration()
664 .unwrap(),
665 4
666 );
667 assert_eq!(
668 Token::parse_token(" ld hl, (dd)")
669 .unwrap()
670 .estimated_duration()
671 .unwrap(),
672 5
673 );
674 println!("{:?}", Token::parse_token(" ld de, (dd)").unwrap());
675 assert_eq!(
676 Token::parse_token(" ld de, (dd)")
677 .unwrap()
678 .estimated_duration()
679 .unwrap(),
680 6
681 );
682 assert_eq!(
683 Token::parse_token(" ld a, (ix+0)")
684 .unwrap()
685 .estimated_duration()
686 .unwrap(),
687 5
688 );
689 assert_eq!(
690 Token::parse_token(" ld l, (ix+0)")
691 .unwrap()
692 .estimated_duration()
693 .unwrap(),
694 5
695 );
696 assert_eq!(
697 Token::parse_token(" ldi")
698 .unwrap()
699 .estimated_duration()
700 .unwrap(),
701 5
702 );
703 assert_eq!(
704 Token::parse_token(" inc c")
705 .unwrap()
706 .estimated_duration()
707 .unwrap(),
708 1
709 );
710 assert_eq!(
711 Token::parse_token(" inc l")
712 .unwrap()
713 .estimated_duration()
714 .unwrap(),
715 1
716 );
717 assert_eq!(
718 Token::parse_token(" dec c")
719 .unwrap()
720 .estimated_duration()
721 .unwrap(),
722 1
723 );
724 assert_eq!(
725 Token::parse_token(" out (c), d")
726 .unwrap()
727 .estimated_duration()
728 .unwrap(),
729 4
730 );
731 assert_eq!(
732 Token::parse_token(" out (c), c")
733 .unwrap()
734 .estimated_duration()
735 .unwrap(),
736 4
737 );
738 assert_eq!(
739 Token::parse_token(" out (c), e")
740 .unwrap()
741 .estimated_duration()
742 .unwrap(),
743 4
744 );
745 assert_eq!(
746 Token::parse_token(" ld b, 0x7f")
747 .unwrap()
748 .estimated_duration()
749 .unwrap(),
750 2
751 );
752
753 assert!(
754 Token::Basic(None, None, "".to_owned())
755 .estimated_duration()
756 .is_err()
757 );
758 }
759 }
760}