1use std::fmt;
2use std::fmt::Debug;
3
4use cpclib_common::itertools::Itertools;
5use cpclib_common::smol_str::SmolStr;
6use cpclib_sna::{
7 RemuBreakPointAccessMode, RemuBreakPointRunMode, RemuBreakPointType, SnapshotVersion
8};
9
10use crate::tokens::data_access::*;
11use crate::tokens::expression::*;
12use crate::tokens::listing::ListingElement;
13use crate::{Listing, Register8};
14
15#[derive(Debug, PartialEq, Eq, Clone, Hash)]
16pub enum MacroParam {
20 RawArgument(String),
22 EvaluatedArgument(String),
23 List(Vec<Box<MacroParam>>)
25}
26
27impl ToString for MacroParam {
28 fn to_string(&self) -> String {
29 match self {
30 Self::RawArgument(s) | Self::EvaluatedArgument(s) => s.clone(),
31 Self::List(l) => {
32 format!("[{}]", l.iter().map(|p| p.to_string()).join(","))
33 }
34 }
35 }
36}
37
38pub trait MacroParamElement: Clone + core::fmt::Debug {
39 fn empty() -> Self;
40
41 fn is_single(&self) -> bool;
42 fn is_list(&self) -> bool;
43 fn is_empty(&self) -> bool {
44 self.is_single() && self.single_argument().is_empty()
45 }
46
47 fn single_argument(&self) -> beef::lean::Cow<str>;
48 fn list_argument(&self) -> &[Box<Self>];
49
50 fn must_be_evaluated(&self) -> bool;
51}
52
53impl MacroParamElement for MacroParam {
54 fn must_be_evaluated(&self) -> bool {
55 matches!(self, MacroParam::EvaluatedArgument(..))
56 }
57
58 fn empty() -> Self {
59 Self::RawArgument("".to_owned())
60 }
61
62 fn is_single(&self) -> bool {
63 matches!(
64 self,
65 MacroParam::RawArgument(_) | MacroParam::EvaluatedArgument(_)
66 )
67 }
68
69 fn is_list(&self) -> bool {
70 matches!(self, MacroParam::List(_))
71 }
72
73 fn single_argument(&self) -> beef::lean::Cow<str> {
74 match self {
75 MacroParam::RawArgument(s) | MacroParam::EvaluatedArgument(s) => {
76 beef::lean::Cow::borrowed(s)
77 },
78 MacroParam::List(_) => unreachable!()
79 }
80 }
81
82 fn list_argument(&self) -> &[Box<Self>] {
83 match self {
84 MacroParam::List(l) => l,
85 _ => unreachable!()
86 }
87 }
88}
89
90impl MacroParam {
91 pub fn do_apply_macro_labels_modification(&mut self, seed: usize) {
94 match self {
95 Self::RawArgument(s) | Self::EvaluatedArgument(s) => {
96 Expr::do_apply_macro_labels_modification(s, seed);
97 },
98 Self::List(l) => {
99 l.iter_mut().for_each(|m| {
100 m.do_apply_macro_labels_modification(seed);
101 })
102 },
103 }
104 }
105}
106
107#[remain::sorted]
108#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
109#[allow(missing_docs)]
110pub enum Mnemonic {
111 Adc,
112 Add,
113 And,
114 Bit,
115 Call,
116 Ccf,
117 Cp,
118 Cpd,
119 Cpdr,
120 Cpi,
121 Cpir,
122 Cpl,
123 Daa,
124 Dec,
125 Di,
126 Djnz,
127 Ei,
128 ExAf,
129 ExHlDe,
130 ExMemSp,
131 Exx,
132 Halt,
133 Im,
134 In,
135 Inc,
136 Ind,
137 Indr,
138 Ini,
139 Inir,
140 Jp,
141 Jr,
142 Ld,
143 Ldd,
144 Lddr,
145 Ldi,
146 Ldir,
147 Neg,
148 Nop,
149 Nop2, Or,
151 Otdr,
152 Otir,
153 Out,
154 Outd,
155 Outi,
156 Pop,
157 Push,
158 Res,
159 Ret,
160 Reti,
161 Retn,
162 Rl,
163 Rla,
164 Rlc,
165 Rlca,
166 Rld,
167 Rr,
168 Rra,
169 Rrc,
170 Rrca,
171 Rrd,
172 Rst,
173 Sbc,
174 Scf,
175 Set,
176 Sl1,
177 Sla,
178 Sra,
179 Srl,
180 Sub,
181 Xor
182}
183
184impl fmt::Display for Mnemonic {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 #[remain::sorted]
187 match self {
188 Mnemonic::Adc => write!(f, "ADC"),
189 Mnemonic::Add => write!(f, "ADD"),
190 Mnemonic::And => write!(f, "AND"),
191 Mnemonic::Bit => write!(f, "BIT"),
192 Mnemonic::Call => write!(f, "CALL"),
193 Mnemonic::Ccf => write!(f, "CCF"),
194 Mnemonic::Cp => write!(f, "CP"),
195 Mnemonic::Cpd => write!(f, "CPD"),
196 Mnemonic::Cpdr => write!(f, "CPDR"),
197 Mnemonic::Cpi => write!(f, "CPI"),
198 Mnemonic::Cpir => write!(f, "CPIR"),
199 Mnemonic::Cpl => write!(f, "CPL"),
200 Mnemonic::Daa => write!(f, "DAA"),
201 Mnemonic::Dec => write!(f, "DEC"),
202 Mnemonic::Di => write!(f, "DI"),
203 Mnemonic::Djnz => write!(f, "DJNZ"),
204 Mnemonic::Ei => write!(f, "EI"),
205 Mnemonic::ExAf => write!(f, "EX AF, AF'"),
206 Mnemonic::ExHlDe => write!(f, "EX DE, HL"),
207 Mnemonic::ExMemSp => write!(f, "EX (SP), "),
208 Mnemonic::Exx => write!(f, "EXX"),
209 Mnemonic::Halt => write!(f, "HALT"),
210 Mnemonic::Im => write!(f, "IM"),
211 Mnemonic::In => write!(f, "IN"),
212 Mnemonic::Inc => write!(f, "INC"),
213 Mnemonic::Ind => write!(f, "IND"),
214 Mnemonic::Indr => write!(f, "INDR"),
215 Mnemonic::Ini => write!(f, "INI"),
216 Mnemonic::Inir => write!(f, "INIR"),
217 Mnemonic::Jp => write!(f, "JP"),
218 Mnemonic::Jr => write!(f, "JR"),
219 Mnemonic::Ld => write!(f, "LD"),
220 Mnemonic::Ldd => write!(f, "LDD"),
221 Mnemonic::Lddr => write!(f, "LDDR"),
222 Mnemonic::Ldi => write!(f, "LDI"),
223 Mnemonic::Ldir => write!(f, "LDIR"),
224 Mnemonic::Neg => write!(f, "NEG"),
225 Mnemonic::Nop => write!(f, "NOP"),
226 Mnemonic::Nop2 => write!(f, "DB 0xed, 0xff ; Winape Breakpoint"),
227 Mnemonic::Or => write!(f, "OR"),
228 Mnemonic::Otdr => write!(f, "OTDR"),
229 Mnemonic::Otir => write!(f, "OTIR"),
230 Mnemonic::Out => write!(f, "OUT"),
231 Mnemonic::Outd => write!(f, "OUTD"),
232 Mnemonic::Outi => write!(f, "OUTI"),
233 Mnemonic::Pop => write!(f, "POP"),
234 Mnemonic::Push => write!(f, "PUSH"),
235 Mnemonic::Res => write!(f, "RES"),
236 Mnemonic::Ret => write!(f, "RET"),
237 Mnemonic::Reti => write!(f, "RETI"),
238 Mnemonic::Retn => write!(f, "RETN"),
239 Mnemonic::Rl => write!(f, "RL"),
240 Mnemonic::Rla => write!(f, "RLA"),
241 Mnemonic::Rlc => write!(f, "RLC"),
242 Mnemonic::Rlca => write!(f, "RLCA"),
243 Mnemonic::Rld => write!(f, "RLD"),
244 Mnemonic::Rr => write!(f, "RR"),
245 Mnemonic::Rra => write!(f, "RRA"),
246 Mnemonic::Rrc => write!(f, "RRC"),
247 Mnemonic::Rrca => write!(f, "RRCA"),
248 Mnemonic::Rrd => write!(f, "RRD"),
249 Mnemonic::Rst => write!(f, "RST"),
250 Mnemonic::Sbc => write!(f, "SBC"),
251 Mnemonic::Scf => write!(f, "SCF"),
252 Mnemonic::Set => write!(f, "SET"),
253 Mnemonic::Sl1 => write!(f, "SL1"),
254 Mnemonic::Sla => write!(f, "SLA"),
255 Mnemonic::Sra => write!(f, "SRA"),
256 Mnemonic::Srl => write!(f, "SRL"),
257 Mnemonic::Sub => write!(f, "SUB"),
258 Mnemonic::Xor => write!(f, "XOR")
259 }
260 }
261}
262
263macro_rules! is_mnemonic {
264 ($($mnemonic:ident)*) => {$(
265 paste::paste! {
266 impl Mnemonic {
267 pub fn [<is_ $mnemonic:lower>] (&self) -> bool {
269 match self {
270 Mnemonic::$mnemonic => true,
271 _ => false,
272 }
273 }
274 }
275 }
276 )*}
277}
278is_mnemonic!(
279 Adc
280 Add
281 And
282 Bit
283 Call
284 Ccf
285 Cp
286 Cpd
287 Cpdr
288 Cpi
289 Cpir
290 Cpl
291 Daa
292 Dec
293 Di
294 Djnz
295 Ei
296 ExAf
297 ExHlDe
298 ExMemSp
299 Exx
300 Halt
301 Im
302 In
303 Inc
304 Ind
305 Indr
306 Ini
307 Inir
308 Jp
309 Jr
310 Ld
311 Ldd
312 Lddr
313 Ldi
314 Ldir
315 Neg
316 Nop
317 Nop2
318 Or
319 Otdr
320 Otir
321 Out
322 Outd
323 Outi
324 Pop
325 Push
326 Res
327 Ret
328 Reti
329 Retn
330 Rl
331 Rla
332 Rlc
333 Rlca
334 Rld
335 Rr
336 Rra
337 Rrc
338 Rrca
339 Rrd
340 Rst
341 Sbc
342 Scf
343 Set
344 Sla
345 Sl1
346 Sra
347 Srl
348 Sub
349 Xor
350);
351
352#[derive(Debug, Clone, PartialEq, Eq, Hash)]
354#[allow(missing_docs)]
355pub enum StableTickerAction<S: AsRef<str>> {
356 Start(S),
358 Stop(Option<S>)
359}
360
361#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
362#[allow(missing_docs)]
363pub enum CrunchType {
364 LZ48,
365 LZ49,
366 #[cfg(not(target_arch = "wasm32"))]
367 LZ4,
368 LZX7,
369 #[cfg(not(target_arch = "wasm32"))]
370 LZX0,
371 #[cfg(not(target_arch = "wasm32"))]
372 LZEXO,
373 #[cfg(not(target_arch = "wasm32"))]
374 LZAPU,
375 LZSA1,
376 LZSA2,
377 #[cfg(not(target_arch = "wasm32"))]
378 Shrinkler,
379 #[cfg(not(target_arch = "wasm32"))]
380 Upkr
381}
382
383#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
384#[allow(missing_docs)]
385pub enum DiscType {
386 Dsk,
387 Hfe,
388 Auto
389}
390
391#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
392#[allow(missing_docs)]
393pub enum SaveType {
394 AmsdosBas,
395 AmsdosBin,
396 Ascii,
397 Disc(DiscType),
398 Tape
399}
400
401#[derive(Debug, Clone, PartialEq, Eq, Hash)]
403#[allow(missing_docs)]
404pub enum TestKind {
405 True(Expr),
407 False(Expr),
409 LabelExists(SmolStr),
411 LabelDoesNotExist(SmolStr),
413 LabelUsed(SmolStr),
414 LabelNused(SmolStr)
415}
416
417impl TestKind {
418 pub fn iftrue<E: Into<Expr>>(e: E) -> Self {
419 Self::True(e.into())
420 }
421
422 pub fn iffalse<E: Into<Expr>>(e: E) -> Self {
423 Self::False(e.into())
424 }
425
426 pub fn ifndef<S: Into<SmolStr>>(l: S) -> Self {
427 TestKind::LabelDoesNotExist(l.into())
428 }
429
430 pub fn ifdef<S: Into<SmolStr>>(l: S) -> Self {
431 TestKind::LabelExists(l.into())
432 }
433
434 pub fn ifnused<S: Into<SmolStr>>(l: S) -> Self {
435 TestKind::LabelNused(l.into())
436 }
437
438 pub fn ifused<S: Into<SmolStr>>(l: S) -> Self {
439 TestKind::LabelUsed(l.into())
440 }
441}
442
443pub trait TestKindElement {
444 type Expr: ExprElement;
445
446 fn is_true_test(&self) -> bool;
447 fn is_false_test(&self) -> bool;
448
449 fn is_label_used_test(&self) -> bool;
450 fn is_label_nused_test(&self) -> bool;
451
452 fn is_label_exists_test(&self) -> bool;
453 fn is_label_nexists_test(&self) -> bool;
454
455 fn expr_unchecked(&self) -> &Self::Expr;
456 fn label_unchecked(&self) -> &str;
457}
458
459impl TestKindElement for TestKind {
460 type Expr = Expr;
461
462 fn is_true_test(&self) -> bool {
463 todo!()
464 }
465
466 fn is_false_test(&self) -> bool {
467 todo!()
468 }
469
470 fn is_label_used_test(&self) -> bool {
471 todo!()
472 }
473
474 fn is_label_nused_test(&self) -> bool {
475 todo!()
476 }
477
478 fn is_label_exists_test(&self) -> bool {
479 todo!()
480 }
481
482 fn is_label_nexists_test(&self) -> bool {
483 todo!()
484 }
485
486 fn expr_unchecked(&self) -> &Self::Expr {
487 todo!()
488 }
489
490 fn label_unchecked(&self) -> &str {
491 todo!()
492 }
493}
494
495#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
497#[allow(missing_docs)]
498pub enum BinaryTransformation {
499 None,
501 Crunch(CrunchType)
502}
503
504impl BinaryTransformation {
505 pub fn crunch_type(&self) -> Option<CrunchType> {
506 match self {
507 BinaryTransformation::None => None,
508 BinaryTransformation::Crunch(crunch) => Some(*crunch)
509 }
510 }
511}
512
513#[derive(Debug, Clone, PartialEq, Eq, Hash)]
515pub enum CharsetFormat {
516 Reset,
518 CharsList(Vec<char>, Expr),
520 Char(Expr, Expr),
522 Interval(Expr, Expr, Expr)
524}
525
526pub trait ToSimpleToken {
527 fn as_simple_token(&self) -> std::borrow::Cow<Token>;
529}
530
531impl ToSimpleToken for Token {
532 fn as_simple_token(&self) -> std::borrow::Cow<Token> {
533 std::borrow::Cow::Borrowed(self)
534 }
535}
536
537#[derive(Debug, Clone, Hash, PartialEq)]
538pub enum StandardAssemblerControlCommand {
539 RestrictedAssemblingEnvironment { passes: Option<Expr>, lst: Listing },
540 PrintAtParsingState(Vec<FormattedExpr>), PrintAtAssemblingState(Vec<FormattedExpr>)
542}
543
544pub trait AssemblerControlCommand {
545 type Expr;
546 type T: ListingElement + Debug + Sync;
547
548 fn is_restricted_assembling_environment(&self) -> bool;
549 fn is_print_at_parse_state(&self) -> bool;
550 fn is_print_at_assembling_state(&self) -> bool;
551
552 fn get_max_nb_passes(&self) -> Option<&Self::Expr>;
553 fn get_listing(&self) -> &[Self::T];
554 fn get_formatted_expr(&self) -> &[FormattedExpr];
555}
556
557impl AssemblerControlCommand for StandardAssemblerControlCommand {
558 type Expr = Expr;
559 type T = Token;
560
561 fn is_restricted_assembling_environment(&self) -> bool {
562 todo!()
563 }
564
565 fn is_print_at_parse_state(&self) -> bool {
566 todo!()
567 }
568
569 fn is_print_at_assembling_state(&self) -> bool {
570 todo!()
571 }
572
573 fn get_max_nb_passes(&self) -> Option<&Self::Expr> {
574 todo!()
575 }
576
577 fn get_listing(&self) -> &[Self::T] {
578 todo!()
579 }
580
581 fn get_formatted_expr(&self) -> &[FormattedExpr] {
582 todo!()
583 }
584}
585
586#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
587pub enum AssemblerFlavor {
588 Basm,
589 Orgams
591}
592
593#[remain::sorted]
595#[derive(Debug, Clone, Hash, PartialEq)]
596#[allow(missing_docs)]
597pub enum Token {
598 Abyte(Expr, Vec<Expr>),
599
600 Align(Expr, Option<Expr>),
601 AssemblerControl(StandardAssemblerControlCommand),
602 Assert(Expr, Option<Vec<FormattedExpr>>),
603 Assign {
604 label: SmolStr,
605 expr: Expr,
606 op: Option<BinaryOperation>
607 },
608
609 Bank(Option<Expr>),
612 Bankset(Expr),
613 Basic(Option<Vec<SmolStr>>, Option<Vec<Expr>>, String),
615 Break,
616 Breakpoint {
617 address: Option<Expr>,
618 r#type: Option<RemuBreakPointType>,
619 access: Option<RemuBreakPointAccessMode>,
620 run: Option<RemuBreakPointRunMode>,
621 mask: Option<Expr>,
622 size: Option<Expr>,
623 value: Option<Expr>,
624 value_mask: Option<Expr>,
625 condition: Option<Expr>,
626 name: Option<Expr>,
627 step: Option<Expr>
628 },
629 BuildCpr,
630 BuildSna(Option<SnapshotVersion>),
631 Charset(CharsetFormat),
632 Comment(String),
633 CrunchedBinary(CrunchType, SmolStr),
634 CrunchedSection(CrunchType, Listing),
635 Defb(Vec<Expr>),
636 Defs(Vec<(Expr, Option<Expr>)>),
637 Defw(Vec<Expr>),
638
639 End,
640 Equ {
641 label: SmolStr,
642 expr: Expr
643 },
644 Export(Vec<SmolStr>),
645
646 Fail(Option<Vec<FormattedExpr>>),
647 Field {
648 label: SmolStr,
649 expr: Expr
650 },
651 For {
652 label: SmolStr,
653 start: Expr,
654 stop: Expr,
655 step: Option<Expr>,
656 listing: Listing
657 },
658
659 Function(SmolStr, Vec<SmolStr>, Listing),
661
662 If(Vec<(TestKind, Listing)>, Option<Listing>),
664
665 Incbin {
667 fname: Expr,
668 offset: Option<Expr>,
669 length: Option<Expr>,
670 extended_offset: Option<Expr>,
671 off: bool,
672 transformation: BinaryTransformation
673 },
674 Include(Expr, Option<SmolStr>, bool),
676 Iterate(SmolStr, either::Either<Vec<Expr>, Expr>, Listing),
677
678 Label(SmolStr),
679 Let(SmolStr, Expr),
680 Limit(Expr),
681 List,
682
683 Macro {
684 name: SmolStr,
685 params: Vec<SmolStr>,
686 content: String,
687 flavor: AssemblerFlavor
688 }, MacroCall(SmolStr, Vec<MacroParam>), Map(Expr),
692 Module(SmolStr, Listing),
693 MultiPop(Vec<DataAccess>),
695 MultiPush(Vec<DataAccess>),
697
698 Next {
699 label: SmolStr,
700 source: SmolStr,
701 expr: Option<Expr>
702 },
703 NoExport(Vec<SmolStr>),
704 NoList,
705
706 OpCode(
708 Mnemonic,
709 Option<DataAccess>,
710 Option<DataAccess>,
711 Option<Register8>
712 ),
713 Org {
714 val1: Expr,
715 val2: Option<Expr>
716 },
717 Pause,
718 Print(Vec<FormattedExpr>),
719 Protect(Expr, Expr),
720 Range(String, Expr, Expr),
722 Repeat(
724 Expr,
726 Listing,
728 Option<SmolStr>,
730 Option<Expr>
732 ),
733 RepeatToken {
734 token: Box<Self>,
735 repeat: Expr
736 },
737 RepeatUntil(Expr, Listing),
738 Return(Expr),
740 Rorg(Expr, Listing),
742 Run(Expr, Option<Expr>),
743
744 Save {
745 filename: Expr,
746 address: Option<Expr>,
747 size: Option<Expr>,
748 save_type: Option<SaveType>,
749 dsk_filename: Option<Expr>,
750 side: Option<Expr>
751 },
752 Section(SmolStr),
753 SetCPC(Expr),
754 SetCrtc(Expr),
755 SetN {
756 label: SmolStr,
757 source: SmolStr,
758 expr: Option<Expr>
759 },
760 Skip(Expr),
761 SnaInit(Expr),
763 SnaSet(
764 cpclib_sna::flags::SnapshotFlag,
765 cpclib_sna::flags::FlagValue
766 ),
767 StableTicker(StableTickerAction<SmolStr>),
768 StartingIndex {
769 start: Option<Expr>,
770 step: Option<Expr>
771 },
772 Str(Vec<Expr>),
773 Struct(SmolStr, Vec<(SmolStr, Token)>),
774 Switch(Expr, Vec<(Expr, Listing, bool)>, Option<Listing>),
775
776 Undef(SmolStr),
777 WaitNops(Expr),
778 While(Expr, Listing)
779}
780impl Eq for Token {}
969
970impl fmt::Display for Token {
971 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
972 let expr_list_to_string = |exprs: &Vec<Expr>| {
973 exprs
974 .iter()
975 .map(|expr| expr.to_simplified_string())
976 .collect::<Vec<_>>()
977 .join(",")
978 };
979
980 let data_access_list_to_string = |data: &Vec<DataAccess>| {
981 data.iter()
982 .map(|d| format!("{d}"))
983 .collect::<Vec<_>>()
984 .join(",")
985 };
986
987 #[remain::sorted]
988 match self {
989
990 Token::Align( expr, None)
991 => write!(f, "ALIGN {}", expr.to_simplified_string()),
992 Token::Align( expr, Some( fill))
993 => write!(f, "ALIGN {}, {}", expr.to_simplified_string(), fill),
994 Token::Assert( expr, None)
995 => write!(f, "ASSERT {}", expr.to_simplified_string()),
996 Token::Assert( expr, Some( text))
997 => write!(f, "ASSERT {}, {}", expr.to_simplified_string(), text.iter().map(|e|e.to_string()).join(",")),
998
999 Token::Breakpoint{address, ..} => {
1000 write!(f, "BREAKPOINT")?;
1001 if let Some(address) = address {
1002 write!(f, " {}", address.to_simplified_string())?;
1003 }
1004 unimplemented!();
1005 Ok(())
1006 }
1007 Token::Comment( string)
1008 => write!(f, " ; {}", string.replace('\n',"\n;")),
1009
1010 Token::Defb( exprs)
1011 => write!(f, "DB {}", expr_list_to_string(exprs)),
1012 Token::Defs( vals)
1013 => write!(f, "DEFS {}", vals.iter()
1014 .map(|p| {
1015 match &p.1 {
1016 Some( v) => format!("{}, {}", p.0.to_simplified_string(), v.to_simplified_string()),
1017 None => p.0.to_simplified_string()
1018 }
1019 })
1020 .join(", ")
1021 ),
1022
1023 Token::Defw( exprs)
1024 => write!(f, "DW {}", expr_list_to_string(exprs)),
1025
1026 Token::Equ{label, expr}
1027 => write!(f, "{} EQU {}", label, expr.to_simplified_string()),
1028
1029 Token::Fail(msg) => {
1030 if let Some(msg) = msg {
1031 write!(f, "FAIL {}", msg.iter().map(|e| e.to_string()).join(", "))
1032 } else {
1033 write!(f, "FAIL")
1034 }
1035 }
1036
1037 Token::If(tests, default) => {
1038 let get_code_string = |tokens: &[Token]| {
1039 let mut code_part = String::new();
1040 for token in tokens.iter() {
1041 if !token.starts_with_label() {
1042 code_part.push('\t');
1043 }
1044 code_part += &token.to_string();
1045 code_part += "\n";
1046 }
1047 code_part
1048 };
1049
1050 let mut first = true;
1051 for (test, code) in tests {
1052 let test_part = match test {
1053 TestKind::True(e) => format!("IF {e}"),
1054 TestKind::False(e) => format!("IFNOT {e}"),
1055 TestKind::LabelExists(l) => format!("IFDEF {l}"),
1056 TestKind::LabelDoesNotExist(l) => format!("IFNDEF {l}"),
1057 TestKind::LabelUsed(l) => format!("IFUSED {l}"),
1058 TestKind::LabelNused(l) => format!("IFNUSED {l}"),
1059 };
1060
1061 let code_part = get_code_string(code);
1062 write!(f, "\t{}{}\n{}", if first {""} else {"ELSE "},test_part, code_part)?;
1063 first = false;
1064 }
1065
1066 if let Some(code) = default {
1067 let code_part = get_code_string(code);
1068 write!(f, "{code_part}")?;
1069 }
1070
1071 write!(f, "\n\tENDIF\n")
1072 }
1073
1074 Token::Incbin{
1075 fname,
1076 offset,
1077 length,
1078 extended_offset,
1079 off,
1080 transformation
1081 }
1082 => {
1083
1084 let directive = match transformation {
1085 BinaryTransformation::None => "INCBIN",
1086 BinaryTransformation::Crunch(crunch) => {
1087 match crunch {
1088 CrunchType::LZ48 =>"INCL48",
1089 CrunchType::LZ49 => "INCL49",
1090 #[cfg(not(target_arch = "wasm32"))]
1091 CrunchType::LZ4 =>"INCLZ4",
1092 CrunchType::LZX7 =>"INCZX7",
1093 #[cfg(not(target_arch = "wasm32"))]
1094 CrunchType::LZX0 => "INCZX0",
1095 #[cfg(not(target_arch = "wasm32"))]
1096 CrunchType::LZEXO => "INCEXO",
1097 #[cfg(not(target_arch = "wasm32"))]
1098 CrunchType::LZAPU => "INCAPU",
1099 CrunchType::LZSA1 => "INCLZSA1",
1100 CrunchType::LZSA2 => "INCLZSA2",
1101 #[cfg(not(target_arch = "wasm32"))]
1102 CrunchType::Shrinkler => "INCSHRINKLER",
1103 #[cfg(not(target_arch = "wasm32"))]
1104 CrunchType::Upkr => "INCUPKR",
1105 }
1106 }
1107 };
1108
1109 write!(f, "{directive} {fname}")?;
1110 if offset.is_some() {
1111 write!(f, ", {}", offset.as_ref().unwrap())?;
1112
1113 if length.is_some() {
1114 write!(f, ", {}", length.as_ref().unwrap())?;
1115
1116 if extended_offset.is_some() {
1117 write!(f, ", {}", extended_offset.as_ref().unwrap())?;
1118
1119 if *off {
1120 write!(f, ", OFF")?;
1121
1122 }
1123 }
1124 }
1125 }
1126 Ok(())
1127
1128 }
1129
1130
1131 Token::Include( fname, Some(module), once)
1132 => write!(f, "INCLUDE {}\"{}\" namespace {}", fname, module.as_str(), if *once {"ONCE "} else {""}),
1133
1134 Token::Include( fname, None, once)
1135 => write!(f, "INCLUDE {}\"{}\"", fname, if *once {"ONCE "} else {""}),
1136
1137 Token::Label( string)
1138 => write!(f, "{string}"),
1139
1140
1141 Token::MacroCall( name, args)
1142 => {use cpclib_common::itertools::Itertools;
1143 let args = args.clone()
1144 .iter()
1145 .map(|a|{a.to_string()})
1146 .join(", ");
1147 let args = if args.is_empty() {
1148 "(void)".to_owned()
1149 } else {
1150 args
1151 };
1152 write!(f, "{name} {args}")?;
1153 Ok(())
1154 },
1155
1156 Token::MultiPop( regs) => {
1157 write!(f, "POP {}", data_access_list_to_string(regs))
1158 },
1159
1160 Token::MultiPush( regs) => {
1161 write!(f, "PUSH {}", data_access_list_to_string(regs))
1162 },
1163
1164
1165 Token::OpCode( mne, Some(DataAccess::Register8(_)), Some( arg2), None) if &Mnemonic::Out == mne
1167 => write!(f, "{mne} (C), {arg2}"),
1168 Token::OpCode( mne, None, None, None)
1169 => write!(f, "{mne}"),
1170 Token::OpCode( mne, Some( arg1), None, None)
1171 => write!(f, "{mne} {arg1}"),
1172 Token::OpCode( mne, None, Some( arg2), None) => write!(f, "{mne} {arg2}"),
1174 Token::OpCode( mne, Some( arg1), Some( arg2), None)
1175 => write!(f, "{mne} {arg1}, {arg2}"),
1176
1177 Token::OpCode( mne, Some( arg1), Some( arg2), Some(arg3))
1178 => write!(f, "{mne} {arg1}, {arg2}, {arg3}"),
1179
1180 Token::Org{val1, val2:None}
1181 => write!(f, "ORG {val1}"),
1182 Token::Org{val1, val2: Some( expr2)}
1183 => write!(f, "ORG {val1}, {expr2}"),
1184
1185
1186 Token::Print( exp)
1187 => write!(f, "PRINT {}", exp.iter().map(|e|e.to_string()).join(",")),
1188
1189 Token::Protect( exp1, exp2)
1190 => write!(f, "PROTECT {exp1}, {exp2}"),
1191
1192 Token::Repeat( exp, code, label, start) => {
1193
1194 write!(f, "REPEAT {exp}")?;
1195 if label.is_some() {
1196 write!(f, " {}", label.as_ref().unwrap())?;
1197 }
1198 if start.is_some() {
1199 write!(f, ", {}", start.as_ref().unwrap())?;
1200 }
1201 writeln!(f)?;
1202
1203 for token in code.iter() {
1204 writeln!(f, "\t{token}")?;
1205 }
1206 write!(f, "\tENDREPEAT")
1207 },
1208
1209 Token::Section(sec) => {
1210 write!(f, "SECTION {sec}")
1211 }
1212
1213 Token::StableTicker( ticker)
1214 => {
1215 match ticker {
1216 StableTickerAction::Start( label) => {
1217 write!(f, "STABLETICKER START, {label}")
1218 },
1219 StableTickerAction::Stop(Some( label)) => {
1220 write!(f, "STABLETICKER STOP, {label}")
1221 },
1222 StableTickerAction::Stop(None) => {
1223 write!(f, "STABLETICKER STOP")
1224 }
1225 }
1226 },
1227
1228
1229
1230
1231 _ => unimplemented!("{:?}", self)
1232
1233 }
1234 }
1235}
1236
1237impl From<u8> for Token {
1238 fn from(byte: u8) -> Self {
1239 Self::Defb(vec![byte.into()])
1240 }
1241}
1242
1243#[allow(missing_docs)]
1244impl Token {
1245 pub fn new_opcode(mne: Mnemonic, arg1: Option<DataAccess>, arg2: Option<DataAccess>) -> Self {
1246 Token::OpCode(mne, arg1, arg2, None)
1247 }
1248
1249 pub fn fix_relative_jumps_after_disassembling(&mut self) {
1251 panic!("I plan to remove this code, it sould not be called");
1252 dbg!("before", &self);
1253
1254 if self.is_opcode() {
1255 let expression = match self {
1256 Self::OpCode(Mnemonic::Jr, _, Some(DataAccess::Expression(exp)), _) => Some(exp),
1257 Self::OpCode(Mnemonic::Djnz, Some(DataAccess::Expression(exp)), ..) => Some(exp),
1258 _ => None
1261 };
1262
1263 if let Some(expr) = expression {
1264 expr.fix_relative_value();
1265 };
1266 }
1267
1268 dbg!("after", &self);
1269 }
1270
1271 pub fn is_opcode(&self) -> bool {
1272 self.mnemonic().is_some()
1273 }
1274
1275 pub fn is_output_opcode(&self) -> bool {
1276 match self {
1277 Token::OpCode(Mnemonic::Out, ..)
1278 | Token::OpCode(Mnemonic::Outd, ..)
1279 | Token::OpCode(Mnemonic::Outi, ..)
1280 | Token::OpCode(Mnemonic::Otdr, ..)
1281 | Token::OpCode(Mnemonic::Otir, ..) => true,
1282 _ => false
1283 }
1284 }
1285
1286 pub fn is_input_opcode(&self) -> bool {
1287 match self {
1288 Token::OpCode(Mnemonic::In, ..)
1289 | Token::OpCode(Mnemonic::Ind, ..)
1290 | Token::OpCode(Mnemonic::Ini, ..)
1291 | Token::OpCode(Mnemonic::Indr, ..)
1292 | Token::OpCode(Mnemonic::Inir, ..) => true,
1293 _ => false
1294 }
1295 }
1296
1297 pub fn is_retlike_opcode(&self) -> bool {
1298 match self {
1299 Token::OpCode(Mnemonic::Ret, ..)
1300 | Token::OpCode(Mnemonic::Reti, ..)
1301 | Token::OpCode(Mnemonic::Retn, ..) => true,
1302 _ => false
1303 }
1304 }
1305
1306 pub fn is_autocopy_opcode(&self) -> bool {
1308 matches!(
1309 self,
1310 Self::OpCode(
1311 Mnemonic::Rlc
1312 | Mnemonic::Rrc
1313 | Mnemonic::Rl
1314 | Mnemonic::Rr
1315 | Mnemonic::Sla
1316 | Mnemonic::Sra
1317 | Mnemonic::Sl1
1318 | Mnemonic::Srl,
1319 Some(DataAccess::IndexRegister16WithIndex(_, _, _)),
1320 Some(DataAccess::Register8(_)),
1321 None
1322 ) | Self::OpCode(
1323 Mnemonic::Set | Mnemonic::Res,
1324 Some(DataAccess::Expression(_)),
1325 Some(DataAccess::IndexRegister16WithIndex(_, _, _)),
1326 Some(_)
1327 )
1328 )
1329 }
1330
1331 pub fn label(&self) -> Option<&str> {
1332 match self {
1333 Token::Label(label) | Token::Equ { label, .. } => Some(label),
1334 _ => None
1335 }
1336 }
1337
1338 pub fn is_label(&self) -> bool {
1339 match self {
1340 Self::Label(_) => true,
1341 _ => false
1342 }
1343 }
1344
1345 pub fn macro_name(&self) -> Option<&str> {
1346 match self {
1347 Self::Macro { name, .. } => Some(name),
1348 Self::MacroCall(name, _params) => Some(name),
1349 _ => None
1350 }
1351 }
1352
1353 pub fn macro_arguments(&self) -> Option<&[SmolStr]> {
1354 match self {
1355 Self::Macro { params, .. } => Some(params.as_ref()),
1356 _ => None
1357 }
1358 }
1359
1360 pub fn macro_content(&self) -> Option<&str> {
1361 match self {
1362 Self::Macro { content, .. } => Some(content),
1363 _ => None
1364 }
1365 }
1366
1367 #[deprecated(
1495 since = "0.1.1",
1496 note = "please use `expr` instead as other token need it"
1497 )]
1498 pub fn org_expr(&self) -> Option<&Expr> {
1499 self.expr()
1500 }
1501
1502 pub fn expr(&self) -> Option<&Expr> {
1503 match self {
1504 Token::Org { val1: expr, .. } | Token::Equ { expr, .. } => Some(expr),
1505 _ => None
1506 }
1507 }
1508
1509 pub fn has_at_least_one_listing(&self) -> bool {
1511 match self {
1512 Self::CrunchedSection(..)
1513 | Self::Include(..)
1514 | Self::If(..)
1515 | Self::Repeat(..)
1516 | Self::RepeatUntil(..)
1517 | Self::Rorg(..)
1518 | Self::Switch(..)
1519 | Self::While(..) => true,
1520 _ => false
1521 }
1522 }
1523}