cpclib_tokens/tokens/
instructions.rs

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)]
16/// This structures encode the parameters of macros.
17/// The usual parameter is a string.
18/// However, it can be a list of parameters to allows nested structs
19pub enum MacroParam {
20    /// Standard argument
21    RawArgument(String),
22    EvaluatedArgument(String),
23    /// A list of argument that will be provided in a nested macro call
24    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    /// Rename the arguments when they are a macro call
92    /// XXX I am pretty sure such implementation is faulty when there are nested calls !!! It needs to be checked (maybe nested stuff has to be removed)
93    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, // Fake instruction that generate a breakpoint on winape
150    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                /// Check if this DataAccess corresonds to $mnemonic
268                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/// Stable ticker serves to count nops with the assembler !
353#[derive(Debug, Clone, PartialEq, Eq, Hash)]
354#[allow(missing_docs)]
355pub enum StableTickerAction<S: AsRef<str>> {
356    /// Start of the ticker with its name that will contains its duration
357    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/// Encode the kind of test done in if/elif/else cases
402#[derive(Debug, Clone, PartialEq, Eq, Hash)]
403#[allow(missing_docs)]
404pub enum TestKind {
405    // Test succeed if it is an expression that returns True
406    True(Expr),
407    // Test succeed if it is an expression that returns False
408    False(Expr),
409    // Test succeed if it is an existing label
410    LabelExists(SmolStr),
411    // Test succeed if it is a missing label
412    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/// List of transformations that can be applied to an imported binary file
496#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
497#[allow(missing_docs)]
498pub enum BinaryTransformation {
499    // Raw include of the data
500    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/// Define characters encoding
514#[derive(Debug, Clone, PartialEq, Eq, Hash)]
515pub enum CharsetFormat {
516    /// Reset the encoding knowledge
517    Reset,
518    /// Specify all chars in a row
519    CharsList(Vec<char>, Expr),
520    /// Attribute the code to a single char
521    Char(Expr, Expr),
522    /// Specify for a given interval
523    Interval(Expr, Expr, Expr)
524}
525
526pub trait ToSimpleToken {
527    /// Convert the token in its simplest form
528    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>), // completely ignored during assembling
541    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    // mathematical expressions use []
590    Orgams
591}
592
593/// The embeded Listing can be of several kind (with the token or with decorated version of the token)
594#[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    /// Configure the bank - completely incompatible with rasm behavior
610    /// The expression corresponds to the GATE ARRAY value to select the bank of interest
611    Bank(Option<Expr>),
612    Bankset(Expr),
613    /// Basic code which tokens will be included in the code (imported variables, lines to hide,  code)
614    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 embeds a listing with a limited number of possible instructions and return a value
660    Function(SmolStr, Vec<SmolStr>, Listing),
661
662    /// Conditional expression. _0 contains all the expression and the appropriate code, _1 contains the else case
663    If(Vec<(TestKind, Listing)>, Option<Listing>),
664
665    /// Include of an asm file _0 contains the name of the file, _1 contains the content of the file. It is not loaded at the creation of the Token because there is not enough context to know where to load file
666    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    // file may or may not be read during parse. If not, it is read on demand when assembling
675    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    }, // Content of the macro is parsed on use
689    // macro call can be used for struct too
690    MacroCall(SmolStr, Vec<MacroParam>), /* String are used in order to not be limited to expression and allow opcode/registers use */
691    Map(Expr),
692    Module(SmolStr, Listing),
693    // Fake pop directive with several arguments
694    MultiPop(Vec<DataAccess>),
695    // Fake push directive with several arguments
696    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    /// Very last argument concerns only few undocumented instructions that save their results in a register
707    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    /// Define a named section in the current page
721    Range(String, Expr, Expr),
722    /// Duplicate the token stream
723    Repeat(
724        // number of loops
725        Expr,
726        // code to execute
727        Listing,
728        // name of the counter if any
729        Option<SmolStr>,
730        // start value
731        Option<Expr>
732    ),
733    RepeatToken {
734        token: Box<Self>,
735        repeat: Expr
736    },
737    RepeatUntil(Expr, Listing),
738    /// Return value from a function
739    Return(Expr),
740    /// Set the value of $ to Expr
741    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    /// This directive setup a value for a given flag of the snapshot
762    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}
780// impl Clone for Token {
781// fn clone(&self) -> Self {
782// match self {
783// Token::Align(a, b) => Token::Align(a.clone(), b.clone()),
784// Token::Assert(a, b) => Token::Assert(a.clone(), b.clone()),
785// Token::Assign { label, expr, op } => {
786// Token::Assign {
787// label: label.clone(),
788// expr: expr.clone(),
789// op: *op
790// }
791// },
792// Token::Bank(b) => Token::Bank(b.clone()),
793// Token::Bankset(b) => Token::Bankset(b.clone()),
794// Token::Basic(a, b, c) => Token::Basic(a.clone(), b.clone(), c.clone()),
795// Token::Break => Token::Break,
796// Token::Breakpoint(a) => Token::Breakpoint(a.clone()),
797// Token::BuildCpr => Token::BuildCpr,
798// Token::BuildSna(a) => Token::BuildSna(*a),
799// Token::Charset(a) => Token::Charset(a.clone()),
800// Token::Comment(c) => Token::Comment(c.clone()),
801// Token::CrunchedBinary(a, b) => Token::CrunchedBinary(*a, b.clone()),
802// Token::CrunchedSection(a, b) => Token::CrunchedSection(*a, b.clone()),
803// Token::Defb(l) => Token::Defb(l.clone()),
804// Token::Defs(l) => Token::Defs(l.clone()),
805// Token::Defw(l) => Token::Defw(l.clone()),
806// Token::Equ { label, expr } => {
807// Token::Equ {
808// label: label.clone(),
809// expr: expr.clone()
810// }
811// },
812// Token::End => Token::End,
813// Token::Export(a) => Token::Export(a.clone()),
814// Token::Fail(a) => Token::Fail(a.clone()),
815// Token::Function(a, b, c) => Token::Function(a.clone(), b.clone(), c.clone()),
816// Token::If(a, b) => Token::If(a.clone(), b.clone()),
817// Token::Incbin {
818// fname,
819// offset,
820// length,
821// extended_offset,
822// off,
823// transformation
824// } => {
825// Token::Incbin {
826// fname: fname.clone(),
827// offset: offset.clone(),
828// length: length.clone(),
829// extended_offset: extended_offset.clone(),
830// off: *off,
831// transformation: *transformation
832// }
833// },
834// Token::Include(a, b, c) => Token::Include(a.clone(), b.clone(), *c),
835// Token::Iterate(a, b, c) => Token::Iterate(a.clone(), b.clone(), c.clone()),
836// Token::Label(a) => Token::Label(a.clone()),
837// Token::Let(a, b) => Token::Let(a.clone(), b.clone()),
838// Token::Limit(a) => Token::Limit(a.clone()),
839// Token::List => Token::List,
840// Token::Macro {
841// name: a,
842// params: b,
843// content: c
844// } => {
845// Token::Macro {
846// name: a.clone(),
847// params: b.clone(),
848// content: c.clone()
849// }
850// },
851// Token::MacroCall(n, p) => Token::MacroCall(n.clone(), p.clone()),
852// Token::Module(a, b) => Token::Module(a.clone(), b.clone()),
853// Token::MultiPop(a) => Token::MultiPop(a.clone()),
854// Token::MultiPush(b) => Token::MultiPush(b.clone()),
855// Token::Next {
856// label,
857// source,
858// expr
859// } => {
860// Token::Next {
861// label: label.clone(),
862// source: source.clone(),
863// expr: expr.clone()
864// }
865// },
866// Token::NoExport(a) => Token::NoExport(a.clone()),
867// Token::NoList => Token::NoList,
868// Token::OpCode(mne, arg1, arg2, arg3) => {
869// Self::OpCode(*mne, arg1.clone(), arg2.clone(), *arg3)
870// },
871// Token::Org { val1, val2 } => {
872// Token::Org {
873// val1: val1.clone(),
874// val2: val2.clone()
875// }
876// },
877// Token::Pause => Token::Pause,
878// Token::Print(a) => Token::Print(a.clone()),
879// Token::Protect(a, b) => Token::Protect(a.clone(), b.clone()),
880// Token::Range(a, b, c) => Token::Range(a.clone(), b.clone(), c.clone()),
881// Token::Repeat(a, b, c, d) => Token::Repeat(a.clone(), b.clone(), c.clone(), d.clone()),
882// Token::RepeatUntil(a, b) => Token::RepeatUntil(a.clone(), b.clone()),
883// Token::Return(a) => Token::Return(a.clone()),
884// Token::Rorg(a, b) => Token::Rorg(a.clone(), b.clone()),
885// Token::Run(a, b) => Token::Run(a.clone(), b.clone()),
886// Token::Save {
887// filename,
888// address,
889// size,
890// save_type,
891// dsk_filename,
892// side
893// } => {
894// Token::Save {
895// filename: filename.clone(),
896// address: address.clone(),
897// size: size.clone(),
898// save_type: *save_type,
899// dsk_filename: dsk_filename.clone(),
900// side: side.clone()
901// }
902// },
903// Token::Section(a) => Token::Section(a.clone()),
904// Token::SetCPC(b) => Token::SetCPC(b.clone()),
905// Token::SetCrtc(c) => Token::SetCrtc(c.clone()),
906// Token::SetN {
907// label,
908// source,
909// expr
910// } => {
911// Token::SetN {
912// label: label.clone(),
913// source: source.clone(),
914// expr: expr.clone()
915// }
916// },
917// Token::SnaInit(a) => Token::SnaInit(a.clone()),
918// Token::SnaSet(a, b) => Token::SnaSet(*a, b.clone()),
919// Token::StableTicker(a) => Token::StableTicker(a.clone()),
920// Token::Str(a) => Token::Str(a.clone()),
921// Token::Struct(a, b) => Token::Struct(a.clone(), b.clone()),
922// Token::Switch(a, b, c) => Token::Switch(a.clone(), b.clone(), c.clone()),
923// Token::Undef(a) => Token::Undef(a.clone()),
924// Token::WaitNops(b) => Token::WaitNops(b.clone()),
925// Token::While(a, b) => Token::While(a.clone(), b.clone()),
926// Token::For {
927// label,
928// start,
929// stop,
930// step,
931// listing
932// } => {
933// Token::For {
934// label: label.clone(),
935// start: start.clone(),
936// stop: stop.clone(),
937// step: step.clone(),
938// listing: listing.clone()
939// }
940// },
941// Token::Map(e) => Token::Map(e.clone()),
942// Token::Field { label, expr } => {
943// Token::Field {
944// label: label.clone(),
945// expr: expr.clone()
946// }
947// },
948// Token::StartingIndex { .. } => todo!()
949// }
950// }
951// }
952// /
953// impl PartialEq for Token {
954// fn eq(&self, other: &Self) -> bool {
955// match (self, other) {
956// (Token::OpCode(a1, b1, c1, d1), Token::OpCode(a2, b2, c2, d2)) => {
957// a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2
958// },
959//
960// (Token::Print(a1), Token::Print(a2)) => a1 == a2,
961//
962// (Token::Defb(a), Token::Defb(b)) => a == b,
963//
964// _ => unimplemented!("{:?}, {:?}", self, other)
965// }
966// }
967// }
968impl 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                // TODO remove this one / it is not coherent as we have the PortC
1166            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) // JP/JR without flags
1173               => 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    /// When diassembling code, the token with relative information are not appropriate
1250    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                //          Self::OpCode(_, Some(DataAccess::IndexRegister16WithIndex(_, exp)), _) => Some(exp),
1259                //         Self::OpCode(_, _, Some(DataAccess::IndexRegister16WithIndex(_, exp))) => Some(exp),
1260                _ => 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    /// Check if it is an undocumented instruction that makes a copy of the data to save in an additional register
1307    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    /// Rename the @labels in macros
1368    /// XXX no more needed - to remove later
1369    // pub fn fix_local_macro_labels_with_seed(&mut self, seed: usize) {
1370    // match self {
1371    // Self::Align(a, b)  | Self::Org(a, b) | Self::Run(a, b) => {
1372    // a.fix_local_macro_labels_with_seed(seed);
1373    // b.as_mut().map(|b| b.fix_local_macro_labels_with_seed(seed));
1374    // }
1375    //
1376    // Self::Defs(a) => {
1377    // a.iter_mut()
1378    // .for_each(|p| {
1379    // match &mut p.1 {
1380    // Some( mut v) => {
1381    // p.0.fix_local_macro_labels_with_seed(seed);
1382    // v.fix_local_macro_labels_with_seed(seed);
1383    // },
1384    // None => {
1385    // p.0.fix_local_macro_labels_with_seed(seed);
1386    // }
1387    // }
1388    // })
1389    // }
1390    //
1391    // Self::Protect(a, b) => {
1392    // a.fix_local_macro_labels_with_seed(seed);
1393    // b.fix_local_macro_labels_with_seed(seed);
1394    // }
1395    //
1396    // Self::Assert(a, _)
1397    // | Self::Bank(a)
1398    // | Self::Bankset(a)
1399    // | Self::Breakpoint(Some(a))
1400    // | Self::Limit(a)
1401    // | Self::SetCPC(a)
1402    // | Self::SetCrtc(a) => {
1403    // a.fix_local_macro_labels_with_seed(seed);
1404    // }
1405    //
1406    // Self::Defb(v) | Self::Defw(v) => {
1407    // v.iter_mut()
1408    // .for_each(|e| e.fix_local_macro_labels_with_seed(seed));
1409    // }
1410    //
1411    // Self::Assign(a, b)  | Self::Equ(a, b) | Self::Let(a, b) => {
1412    // Expr::do_apply_macro_labels_modification(a, seed);
1413    // b.fix_local_macro_labels_with_seed(seed);
1414    // }
1415    //
1416    // Self::Save {
1417    // address,
1418    // size,
1419    // side,
1420    // ..
1421    // } => {
1422    // address.fix_local_macro_labels_with_seed(seed);
1423    // size.fix_local_macro_labels_with_seed(seed);
1424    // side.as_mut()
1425    // .map(|s| s.fix_local_macro_labels_with_seed(seed));
1426    // }
1427    //
1428    // Self::Basic(_, _, _)
1429    // | Self::Break
1430    // | Self::BuildCpr
1431    // | Self::BuildSna(_)
1432    // | Self::Comment(_)
1433    // | Self::CrunchedBinary(_, _)
1434    // | Self::CrunchedSection(_, _)
1435    // | Self::List
1436    // | Self::MultiPop(_)
1437    // | Self::MultiPush(_)
1438    // | Self::NoList
1439    // | Self::SnaSet(_, _)
1440    // | Self::StableTicker(_)
1441    // | Self::Str(_)
1442    // | Self::Struct(_, _) => {}
1443    //
1444    // Self::If(v, o) => {
1445    // v.iter_mut()
1446    // .map(|(t, l)| l)
1447    // .for_each(|l| l.fix_local_macro_labels_with_seed(seed));
1448    // o.as_mut().map(|l| l.fix_local_macro_labels_with_seed(seed));
1449    // }
1450    //
1451    // Self::Label(s) => {
1452    // Expr::do_apply_macro_labels_modification(s, seed);
1453    // }
1454    //
1455    // Self::MacroCall(_n, v) => {
1456    // v.iter_mut()
1457    // .for_each(|p| p.do_apply_macro_labels_modification(seed));
1458    // }
1459    //
1460    // Self::OpCode(_m, a, b, _) => {
1461    // a.as_mut().map(|d| d.fix_local_macro_labels_with_seed(seed));
1462    // b.as_mut().map(|d| d.fix_local_macro_labels_with_seed(seed));
1463    // }
1464    //
1465    //
1466    // Self::RepeatUntil(e, l)
1467    // | Self::Rorg(e, l)
1468    // | Self::While(e, l) => {
1469    // e.fix_local_macro_labels_with_seed(seed);
1470    // l.fix_local_macro_labels_with_seed(seed);
1471    // }
1472    //
1473    // Self::Repeat(e, l, _, s) => {
1474    //
1475    // e.fix_local_macro_labels_with_seed(seed);
1476    // l.fix_local_macro_labels_with_seed(seed);
1477    // s.as_mut().map(|e| e.fix_local_macro_labels_with_seed(seed));
1478    // }
1479    //
1480    // Self::Switch(l) => {
1481    // l.iter_mut().for_each(|(e, l)| {
1482    // e.fix_local_macro_labels_with_seed(seed);
1483    // l.fix_local_macro_labels_with_seed(seed);
1484    // });
1485    // }
1486    //
1487    // Self::Print( mut vec) => {
1488    // vec.iter_mut().for_each(|e| e.fix_local_macro_labels_with_seed(seed))
1489    // }
1490    // _ => unimplemented!("{:?}", self),
1491    // }
1492    // }
1493
1494    #[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    /// Return true for directives that can emebed some listing information
1510    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}