cpclib_asm/assembler/
mod.rs

1pub mod control;
2pub mod delayed_command;
3pub mod file;
4pub mod function;
5pub mod list;
6pub mod listing_output;
7pub mod r#macro;
8pub mod matrix;
9pub mod page_info;
10pub mod report;
11pub mod save_command;
12pub mod section;
13pub mod stable_ticker;
14pub mod string;
15pub mod support;
16pub mod symbols_output;
17
18pub mod embedded;
19pub mod processed_token;
20
21use std::borrow::BorrowMut;
22use std::collections::{BTreeMap, HashMap, HashSet};
23use std::fmt;
24use std::fmt::{Debug, Display};
25use std::io::Write;
26use std::ops::{Deref, Neg};
27use std::sync::{Arc, RwLock};
28use std::time::Instant;
29
30use cpclib_basic::*;
31use cpclib_common::bitvec::prelude::BitVec;
32use cpclib_common::camino::{Utf8Path, Utf8PathBuf};
33use cpclib_common::chars::{Charset, char_to_amscii};
34use cpclib_common::event::EventObserver;
35use cpclib_common::itertools::Itertools;
36use cpclib_common::smallvec::SmallVec;
37use cpclib_common::smol_str::SmolStr;
38use cpclib_common::winnow::stream::UpdateSlice;
39use cpclib_disc::built_info;
40use cpclib_files::{FileType, StorageSupport};
41use cpclib_sna::*;
42use cpclib_tokens::ToSimpleToken;
43use file::AnyFileNameOwned;
44use processed_token::build_processed_token;
45use support::banks::DecoratedPages;
46use support::cpr::CprAssembler;
47use support::sna::SnaAssembler;
48#[cfg(all(not(target_arch = "wasm32"), feature = "rayon"))]
49use {cpclib_common::rayon::prelude::*, rayon_cond::CondIterator};
50
51use self::control::ControlOutputStore;
52use self::function::{Function, FunctionBuilder, HardCodedFunction};
53use self::listing_output::*;
54use self::processed_token::ProcessedToken;
55use self::report::SavedFile;
56use self::string::PreprocessedFormattedString;
57use self::symbols_output::{SymbolOutputFormat, SymbolOutputGenerator};
58use crate::assembler::processed_token::visit_processed_tokens;
59use crate::delayed_command::*;
60use crate::page_info::PageInformation;
61use crate::preamble::*;
62#[cfg(not(target_arch = "wasm32"))]
63use crate::progress::Progress;
64use crate::report::Report;
65use crate::save_command::*;
66use crate::section::Section;
67use crate::stable_ticker::*;
68use crate::{AssemblingOptions, MemoryPhysicalAddress};
69
70#[derive(Clone, Copy, PartialEq)]
71enum OutputKind {
72    Snapshot,
73    Cpr,
74    FreeBank
75}
76
77/// Use smallvec to put stuff on the stack not the heap and (hope so) speed up assembling
78const MAX_SIZE: usize = 4;
79const MMR_PAGES_SELECTION: [u8; 9] = [
80    0xC0,
81    0b1100_0001,
82    0b1100_1001,
83    0b1101_0001,
84    0b1101_1001,
85    0b1110_0001,
86    0b1110_1001,
87    0b1111_0001,
88    0b1111_1001
89];
90
91#[allow(missing_docs)]
92pub type Bytes = SmallVec<[u8; MAX_SIZE]>;
93
94#[derive(Clone, Debug)]
95pub struct EnvOptions {
96    parse: ParserOptions,
97    assemble: AssemblingOptions,
98    observer: Arc<dyn EnvEventObserver>
99}
100
101impl Default for EnvOptions {
102    fn default() -> Self {
103        Self {
104            parse: Default::default(),
105            assemble: Default::default(),
106            observer: Arc::new(())
107        }
108    }
109}
110
111impl From<AssemblingOptions> for EnvOptions {
112    fn from(ass: AssemblingOptions) -> EnvOptions {
113        let mut opt = Self::default();
114        opt.assemble = ass;
115        opt
116    }
117}
118
119impl EnvOptions {
120    delegate::delegate! {
121        to self.parse {
122            pub fn context_builder(self) -> ParserContextBuilder;
123        }
124
125        to self.assemble {
126            pub fn case_sensitive(&self) -> bool;
127            pub fn symbols(&self) -> &cpclib_tokens::symbols::SymbolsTable;
128            pub fn symbols_mut(&mut self) -> &mut cpclib_tokens::symbols::SymbolsTable;
129            pub fn save_behavior(&self) -> cpclib_disc::amsdos::AmsdosAddBehavior;
130
131            pub fn write_listing_output<W: 'static + Write + Send + Sync>(
132                &mut self,
133                writer: W
134            ) -> &mut AssemblingOptions;
135
136        }
137    }
138
139    pub fn new(
140        parse: ParserOptions,
141        assemble: AssemblingOptions,
142        observer: Arc<dyn EnvEventObserver>
143    ) -> Self {
144        Self {
145            parse,
146            assemble,
147            observer
148        }
149    }
150
151    pub fn parse_options(&self) -> &ParserOptions {
152        &self.parse
153    }
154
155    pub fn assemble_options(&self) -> &AssemblingOptions {
156        &self.assemble
157    }
158
159    #[cfg(not(target_arch = "wasm32"))]
160    pub fn show_progress(&self) -> bool {
161        self.parse.show_progress
162    }
163
164    #[cfg(target_arch = "wasm32")]
165    pub fn show_progress(&self) -> bool {
166        false
167    }
168}
169
170/// Add the encoding of an indexed structure
171fn add_index(m: &mut Bytes, idx: i32) -> Result<(), AssemblerError> {
172    //  if idx < -127 || idx > 128 {
173    if !(-128..=127).contains(&idx) {
174        // TODO raise a warning to get the line/file
175        eprintln!("Index error {}", idx);
176    }
177    let val = (idx & 0xFF) as u8;
178    add_byte(m, val);
179    Ok(())
180}
181
182fn add_byte(m: &mut Bytes, b: u8) {
183    m.push(b);
184}
185
186fn add_word(m: &mut Bytes, w: u16) {
187    m.push((w % 256) as u8);
188    m.push((w / 256) as u8);
189}
190
191fn add_index_register_code(m: &mut Bytes, r: IndexRegister16) {
192    add_byte(m, indexed_register16_to_code(r));
193}
194
195const DD: u8 = 0xDD;
196const FD: u8 = 0xFD;
197
198pub trait MyDefault {
199    fn default() -> Self;
200}
201
202/// Several passes are needed to properly assemble a source file.
203///
204/// This structure allows to code which pass is going to be analysed.
205/// First pass consists in collecting the various labels to manipulate and so on. Some labels stay unknown at this moment.
206/// Second pass serves to get the final values
207#[derive(Clone, Copy, Debug, PartialEq, Eq)]
208pub enum AssemblingPass {
209    Uninitialized,
210    FirstPass,
211    SecondPass, // and subsequent
212    Finished,
213    ListingPass // pass dedicated to the listing production
214}
215impl fmt::Display for AssemblingPass {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        let content = match self {
218            AssemblingPass::Uninitialized => "Uninitialized",
219            AssemblingPass::FirstPass => "1",
220            AssemblingPass::SecondPass => "2",
221            AssemblingPass::Finished => "Finished",
222            AssemblingPass::ListingPass => "Listing"
223        };
224        write!(f, "{}", content)
225    }
226}
227
228#[allow(missing_docs)]
229#[allow(unused)]
230impl AssemblingPass {
231    fn is_uninitialized(self) -> bool {
232        match self {
233            AssemblingPass::Uninitialized => true,
234            _ => false
235        }
236    }
237
238    pub fn is_finished(self) -> bool {
239        match self {
240            AssemblingPass::Finished => true,
241            _ => false
242        }
243    }
244
245    pub fn is_first_pass(self) -> bool {
246        match self {
247            AssemblingPass::FirstPass => true,
248            _ => false
249        }
250    }
251
252    pub fn is_second_pass(self) -> bool {
253        match self {
254            AssemblingPass::SecondPass => true,
255            _ => false
256        }
257    }
258
259    pub fn is_listing_pass(self) -> bool {
260        match self {
261            AssemblingPass::ListingPass => true,
262            _ => false
263        }
264    }
265
266    fn next_pass(self) -> Self {
267        match self {
268            AssemblingPass::Uninitialized => AssemblingPass::FirstPass,
269            AssemblingPass::FirstPass => AssemblingPass::SecondPass,
270            AssemblingPass::SecondPass => AssemblingPass::Finished,
271            AssemblingPass::Finished | AssemblingPass::ListingPass => panic!()
272        }
273    }
274}
275
276/// Trait to implement for each type of token.
277/// it allows to drive the appropriate data vonversion
278pub trait Visited {
279    /// Make all the necessary for the given token
280    fn visited(&self, env: &mut Env) -> Result<(), AssemblerError>;
281}
282
283impl Visited for Token {
284    fn visited(&self, env: &mut Env) -> Result<(), AssemblerError> {
285        visit_token(self, env)
286    }
287}
288
289impl Visited for LocatedToken {
290    fn visited(&self, env: &mut Env) -> Result<(), AssemblerError> {
291        // dbg!(env.output_address, self.as_token());
292        visit_located_token(self, env).map_err(|e| e.locate(self.span().clone()))
293    }
294}
295
296type AssemblerWarning = AssemblerError;
297
298/// Store all the necessary information when handling a crunched section
299#[derive(Clone)]
300struct CrunchedSectionState {
301    /// Start of the crunched section for code assembled from the sources.
302    /// None for code assembled from tokens
303    // mainly usefull for error messages; nothing more
304    crunched_section_start: Option<Z80Span>
305}
306
307impl CrunchedSectionState {
308    pub fn new(span: Option<Z80Span>) -> Self {
309        CrunchedSectionState {
310            crunched_section_start: span
311        }
312    }
313}
314
315#[derive(Clone)]
316pub struct CharsetEncoding {
317    lut: std::collections::HashMap<char, i32>
318}
319
320impl Default for CharsetEncoding {
321    fn default() -> Self {
322        Self::new()
323    }
324}
325
326impl CharsetEncoding {
327    pub fn new() -> Self {
328        let mut enc = Self {
329            lut: Default::default()
330        };
331        enc.reset();
332        enc
333    }
334
335    pub fn reset(&mut self) {
336        self.lut.clear()
337    }
338
339    pub fn update(&mut self, spec: &CharsetFormat, env: &mut Env) -> Result<(), AssemblerError> {
340        match spec {
341            CharsetFormat::Reset => self.reset(),
342            CharsetFormat::CharsList(l, s) => {
343                let mut s = env.resolve_expr_must_never_fail(s)?.int()?;
344                for c in l.iter() {
345                    self.lut.insert(*c, s);
346                    s += 1;
347                }
348            },
349            CharsetFormat::Char(c, i) => {
350                let c = env.resolve_expr_must_never_fail(c)?.char()?;
351                let i = env.resolve_expr_must_never_fail(i)?.int()?;
352                self.lut.insert(c, i);
353            },
354            CharsetFormat::Interval(a, b, s) => {
355                let a = env.resolve_expr_must_never_fail(a)?.char()?;
356                let b = env.resolve_expr_must_never_fail(b)?.char()?;
357                let mut s = env.resolve_expr_must_never_fail(s)?.int()?;
358                for c in a..=b {
359                    self.lut.insert(c, s);
360                    s += 1;
361                }
362            }
363        }
364
365        Ok(())
366    }
367
368    pub fn transform_char(&self, c: char) -> u8 {
369        self.lut
370            .get(&c)
371            .cloned()
372            .unwrap_or_else(|| char_to_amscii(c, Charset::English).unwrap_or(c as _) as i32)
373            as _
374    }
375
376    pub fn transform_string(&self, s: &str) -> Vec<u8> {
377        s.chars().map(|c| self.transform_char(c)).collect_vec()
378    }
379}
380
381pub trait EnvEventObserver: EventObserver {}
382
383impl<T> EnvEventObserver for T where T: EventObserver {}
384
385/// Environment of the assembly
386#[allow(missing_docs)]
387pub struct Env {
388    /// Lookup directory when searching for a file. Must be pushed at each import directive and pop after
389    lookup_directory_stack: Vec<Utf8PathBuf>,
390
391    /// Current pass
392    pass: AssemblingPass,
393    options: EnvOptions,
394    real_nb_passes: usize,
395    /// If true at the end of the pass, can prematurely stop the assembling
396    /// Hidden in a rwlock to allow a modification even in non mutable state
397    can_skip_next_passes: RwLock<bool>,
398    /// An issue in a crunched section requires an additional pass
399    request_additional_pass: RwLock<bool>,
400    /// true when it is an additional pass
401    requested_additional_pass: bool,
402
403    /// Check if we are assembling a crunched section as there are some limitations
404    crunched_section_state: Option<CrunchedSectionState>,
405
406    /// Stable counter of nops
407    stable_counters: StableTickerCounters,
408
409    /// gate array configuration
410    ga_mmr: u8,
411    /// duplicate of the output address to be sure to select the appropriate page info
412    output_address: u16,
413
414    /// Ensemble of pages (2 for a stock CPC) for the snapshot
415
416    /// Memory configuration is controlled by the underlying snapshot.
417    /// It will ease the generation of snapshots but may complexity the generation of files
418    sna: SnaAssembler,
419    // TODO remove it as it is store within the sna
420    sna_version: cpclib_sna::SnapshotVersion,
421
422    /// If buildcpr is used, we work within a Cpr
423    cpr: Option<CprAssembler>,
424
425    /// List of banks (temporary memory)
426    free_banks: DecoratedPages,
427
428    /// Counter for the unique labels within macros
429    macro_seed: usize,
430
431    charset_encoding: CharsetEncoding,
432
433    /// Track where bytes has been written to forbid overriding them when generating data
434    /// BUG: should be stored individually in each bank ?
435    byte_written: bool,
436
437    symbols: SymbolsTableCaseDependent,
438
439    /// Return value of the currently executed function. Is almost always None
440    return_value: Option<ExprResult>,
441    functions: BTreeMap<String, Arc<Function>>,
442
443    /// Set only if the run instruction has been used
444    run_options: Option<(u16, Option<u16>)>,
445
446    /// optional object that manages the listing output
447    output_trigger: Option<ListingOutputTrigger>,
448    /// Listing of symbols generator
449    symbols_output: SymbolOutputGenerator,
450
451    warnings: Vec<AssemblerWarning>,
452
453    /// Counter to disable some instruction in rorg stuff
454    nested_rorg: usize,
455
456    /// List of all sections
457    sections: HashMap<String, Arc<RwLock<Section>>>,
458    /// Current section if any
459    current_section: Option<Arc<RwLock<Section>>>,
460
461    saved_files: Option<Vec<SavedFile>>,
462
463    // Store the error that has been temporarily discarded at previous pass, by expecting they will be not be raised at current pass
464    previous_pass_discarded_errors: HashSet<String>,
465    // Store the error that has been temporarily discarded, by expecting they will be fixed at next pass
466    current_pass_discarded_errors: HashSet<String>,
467
468    if_token_adr_to_used_decision: HashMap<usize, bool>,
469    if_token_adr_to_unused_decision: HashMap<usize, bool>,
470
471    included_paths: HashSet<Utf8PathBuf>,
472
473    map_counter: i32,
474
475    // repeat conf
476    repeat_start: ExprResult,
477    repeat_step: ExprResult,
478
479    // temporary stuff
480    extra_print_from_function: RwLock<Vec<PrintOrPauseCommand>>,
481    extra_failed_assert_from_function: RwLock<Vec<FailedAssertCommand>>,
482
483    // list of output commands that are generated in a restricted assembling env
484    pub(crate) assembling_control_current_output_commands: Vec<ControlOutputStore>
485}
486
487impl Default for Env {
488    fn default() -> Self {
489        Env::new(Default::default())
490    }
491}
492
493impl Clone for Env {
494    fn clone(&self) -> Self {
495        Self {
496            lookup_directory_stack: self.lookup_directory_stack.clone(),
497            options: self.options.clone(),
498            can_skip_next_passes: (*self.can_skip_next_passes.read().unwrap().deref()).into(),
499            request_additional_pass: (*self.request_additional_pass.read().unwrap().deref()).into(),
500            pass: self.pass,
501            real_nb_passes: self.real_nb_passes,
502            crunched_section_state: self.crunched_section_state.clone(),
503            stable_counters: self.stable_counters.clone(),
504            ga_mmr: self.ga_mmr,
505            output_address: self.output_address,
506            sna: self.sna.clone(),
507            sna_version: self.sna_version,
508            free_banks: self.free_banks.clone(),
509            macro_seed: self.macro_seed,
510            charset_encoding: self.charset_encoding.clone(),
511            byte_written: self.byte_written,
512            symbols: self.symbols.clone(),
513            run_options: self.run_options,
514            output_trigger: self.output_trigger.clone(),
515            symbols_output: self.symbols_output.clone(),
516            warnings: self.warnings.clone(),
517            nested_rorg: self.nested_rorg,
518            sections: self.sections.clone(),
519            current_section: self.current_section.clone(),
520            saved_files: self.saved_files.clone(),
521
522            if_token_adr_to_used_decision: self.if_token_adr_to_used_decision.clone(),
523            if_token_adr_to_unused_decision: self.if_token_adr_to_unused_decision.clone(),
524            requested_additional_pass: self.requested_additional_pass,
525
526            functions: self.functions.clone(),
527            return_value: self.return_value.clone(),
528
529            current_pass_discarded_errors: self.current_pass_discarded_errors.clone(),
530            previous_pass_discarded_errors: self.previous_pass_discarded_errors.clone(),
531
532            included_paths: self.included_paths.clone(),
533            extra_print_from_function: self
534                .extra_print_from_function
535                .read()
536                .unwrap()
537                .clone()
538                .into(),
539            extra_failed_assert_from_function: self
540                .extra_failed_assert_from_function
541                .read()
542                .unwrap()
543                .clone()
544                .into(),
545
546            map_counter: self.map_counter,
547
548            cpr: self.cpr.clone(),
549
550            repeat_start: self.repeat_start.clone(),
551            repeat_step: self.repeat_step.clone(),
552
553            assembling_control_current_output_commands: self
554                .assembling_control_current_output_commands
555                .clone()
556        }
557    }
558}
559impl fmt::Debug for Env {
560    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561        write!(
562            f,
563            "Env{{ pass: {:?}, symbols {:?} }}",
564            self.pass,
565            self.symbols()
566        )
567    }
568}
569
570/// Symbols handling
571impl Env {
572    pub fn options(&self) -> &EnvOptions {
573        &self.options
574    }
575
576    pub fn symbols(&self) -> &SymbolsTableCaseDependent {
577        &self.symbols
578    }
579
580    pub fn symbols_mut(&mut self) -> &mut SymbolsTableCaseDependent {
581        &mut self.symbols
582    }
583
584    pub fn build_fname<E: ExprEvaluationExt + Debug>(
585        &mut self,
586        exp: &E
587    ) -> Result<String, AssemblerError> {
588        let fname = match self.resolve_expr_must_never_fail(exp) {
589            Ok(fname) => Ok(fname),
590            Err(e) => {
591                match &e {
592                    // the parser consider file.ext to be a label ... because it could ! So if it is not the case we need to fallback
593                    AssemblerError::UnknownSymbol { symbol, .. }
594                    | AssemblerError::RelocatedError {
595                        error: box AssemblerError::UnknownSymbol { symbol, .. },
596                        ..
597                    } => {
598                        let exp_str = exp.to_string();
599                        if exp_str.as_str() == symbol.as_str() {
600                            Ok(exp_str.into())
601                        }
602                        else {
603                            Err(e)
604                        }
605                    },
606                    _ => Err(e)
607                }
608            }
609        }?;
610        let fname = if fname.is_string() {
611            fname.string()?.to_owned()
612        }
613        else {
614            fname.to_string()
615        };
616        Ok(fname)
617    }
618
619    /// Compute the expression thanks to the symbol table of the environment.
620    /// If the expression is not solvable in first pass, 0 is returned.
621    /// If the expression is not solvable in second pass, an error is returned
622    ///
623    /// However, when assembling in a crunched section, the expression MUST NOT fail. edit: why ? I do not get it now and I have removed this limitation
624    pub fn resolve_expr_may_fail_in_first_pass<E: ExprEvaluationExt>(
625        &mut self,
626        exp: &E
627    ) -> Result<ExprResult, AssemblerError> {
628        self.resolve_expr_may_fail_in_first_pass_with_default(exp, 0)
629    }
630
631    pub fn resolve_index_may_fail_in_first_pass<E: ExprEvaluationExt>(
632        &mut self,
633        (op, exp): (BinaryOperation, &E)
634    ) -> Result<ExprResult, AssemblerError> {
635        let res = self.resolve_expr_may_fail_in_first_pass(exp)?;
636        let res = if op == BinaryOperation::Sub {
637            res.neg()?
638        }
639        else {
640            res
641        };
642        Ok(res)
643    }
644
645    pub fn resolve_expr_may_fail_in_first_pass_with_default<
646        E: ExprEvaluationExt,
647        R: Into<ExprResult>
648    >(
649        &mut self,
650        exp: &E,
651        r: R
652    ) -> Result<ExprResult, AssemblerError> {
653        self.track_used_symbols(exp);
654
655        match exp.resolve(self) {
656            Ok(value) => Ok(value),
657            Err(e) => {
658                // if we have no more remaining passes, we fail !
659                if let Some(commands) = self.assembling_control_current_output_commands.last() {
660                    if !commands.has_remaining_passes() {
661                        return Err(e);
662                    }
663                }
664
665                if self.pass.is_first_pass() {
666                    *self.can_skip_next_passes.write().unwrap() = false;
667                    Ok(r.into())
668                }
669                else {
670                    Err(e)
671                }
672            }
673        }
674    }
675
676    /// Compute the expression thanks to the symbol table of the environment.
677    /// An error is systematically raised if the expression is not solvable (i.e., labels are unknown)
678    fn resolve_expr_must_never_fail<E: ExprEvaluationExt>(
679        &mut self,
680        exp: &E
681    ) -> Result<ExprResult, AssemblerError> {
682        match exp.resolve(self) {
683            Ok(value) => Ok(value),
684            Err(e) => {
685                if self.pass.is_first_pass() {
686                    *self.can_skip_next_passes.write().unwrap() = false;
687                    Err(e)
688                }
689                else {
690                    Err(e)
691                }
692            },
693        }
694    }
695
696    pub(crate) fn add_function_parameter_to_symbols_table<S: Into<Symbol>, V: Into<Value>>(
697        &mut self,
698        symbol: S,
699        value: V
700    ) -> Result<(), AssemblerError> {
701        let symbol = symbol.into();
702        // // we do not test that, otherwise it is impossible to do recursive functions
703        // if self.symbols().contains_symbol(symbol.clone())? {
704        // return Err(AssemblerError::IncoherentCode{msg: format!("Function parameter {} already present", symbol)})
705        // }
706        self.symbols
707            .set_symbol_to_value(symbol, ValueAndSource::new_unlocated(value))?;
708        Ok(())
709    }
710
711    /// Add a symbol to the symbol table.
712    /// In pass 1: the label MUST be absent
713    /// In pass 2: the label MUST be present and of the same value
714    fn add_symbol_to_symbol_table<E: Into<Value>>(
715        &mut self,
716        label: &str,
717        value: E,
718        location: Option<Source>
719    ) -> Result<(), AssemblerError> {
720        let already_present = self.symbols().contains_symbol(label)?;
721        let value = value.into();
722        let value = ValueAndSource::new(value, location);
723
724        match (already_present, self.pass) {
725            (true, AssemblingPass::FirstPass) => {
726                Err(AssemblerError::SymbolAlreadyExists {
727                    symbol: label.to_string()
728                })
729            },
730            (false, AssemblingPass::SecondPass) => {
731                // here we weaken the test to allow multipass stuff
732                if !self.requested_additional_pass && !*self.request_additional_pass.read().unwrap()
733                {
734                    Err(AssemblerError::IncoherentCode {
735                        msg: format!(
736                            "Label {} is not present in the symbol table in pass {}. There is an issue with some  conditional code.",
737                            label, self.pass
738                        )
739                    })
740                }
741                else {
742                    self.symbols_mut().set_symbol_to_value(label, value)?;
743                    Ok(())
744                }
745            },
746            (false, AssemblingPass::ListingPass) => {
747                panic!();
748                Err(AssemblerError::IncoherentCode {
749                    msg: format!(
750                        "Label {} is not present in the symbol table in pass {}. There is an issue with some  conditional code.",
751                        label, self.pass
752                    )
753                })
754            },
755            (false, AssemblingPass::FirstPass) | (false, AssemblingPass::Uninitialized) => {
756                self.symbols_mut().set_symbol_to_value(label, value)?;
757                Ok(())
758            },
759            (true, AssemblingPass::SecondPass | AssemblingPass::ListingPass) => {
760                self.symbols_mut().update_symbol_to_value(label, value)?;
761                Ok(())
762            },
763            (..) => {
764                panic!(
765                    "add_symbol_to_symbol_table / unmanaged case {}, {}, {} {:#?}",
766                    self.pass, label, already_present, value
767                )
768            }
769        }
770    }
771
772    /// Track the symbols for an expression that has been properly executed
773    fn track_used_symbols<E: ExprEvaluationExt>(&mut self, e: &E) {
774        e.symbols_used()
775            .into_iter()
776            .for_each(|symbol| self.symbols.use_symbol(symbol))
777    }
778}
779/// Report handling
780impl Env {
781    pub fn report(&self, start: &Instant) -> Report {
782        Report::from((self, start))
783    }
784}
785
786/// Include once handling {
787impl Env {
788    #[inline]
789    fn included_marks_reset(&mut self) {
790        self.included_paths.clear();
791    }
792
793    #[inline]
794    fn included_marks_includes(&self, path: &Utf8PathBuf) -> bool {
795        self.included_paths.contains(path)
796    }
797
798    #[inline]
799    fn included_marks_add(&mut self, path: Utf8PathBuf) {
800        self.included_paths.insert(path);
801    }
802}
803
804/// Handle the file search relatively to the current file
805impl Env {
806    fn set_current_working_directory<P: Into<Utf8PathBuf>>(&mut self, p: P) {
807        self.lookup_directory_stack.push(p.into())
808    }
809
810    pub fn enter_current_working_file<P: AsRef<Utf8Path>>(&mut self, f: P) {
811        let f = f.as_ref();
812        debug_assert!(f.is_file() || f.starts_with("inner://"));
813        self.set_current_working_directory(f.parent().unwrap());
814    }
815
816    pub fn leave_current_working_file(&mut self) -> Option<Utf8PathBuf> {
817        self.lookup_directory_stack.pop()
818    }
819
820    pub fn get_current_working_directory(&self) -> Option<&Utf8Path> {
821        self.lookup_directory_stack.last().map(|p| p.as_path())
822    }
823
824    pub fn has_current_working_directory(&self) -> bool {
825        !self.lookup_directory_stack.is_empty()
826    }
827}
828
829/// Error handling
830impl Env {
831    /// If the error has not been raised at the previous pass, store it and do not propagate it. Otherwise, propagate it
832    pub fn add_error_discardable_one_pass(
833        &mut self,
834        e: AssemblerError
835    ) -> Result<(), AssemblerError> {
836        let repr = SimplerAssemblerError(&e).to_string();
837        if self.previous_pass_discarded_errors.contains(&repr) {
838            Err(e)
839        }
840        else {
841            self.current_pass_discarded_errors.insert(repr);
842            Ok(())
843        }
844    }
845}
846/// Namespace handling
847impl Env {
848    fn enter_namespace(&mut self, namespace: &str) -> Result<(), AssemblerError> {
849        if namespace.contains(".") {
850            return Err(AssemblerError::AssemblingError {
851                msg: format!("Invalid namespace \"{}\"", namespace)
852            });
853        }
854        self.symbols_mut().enter_namespace(namespace);
855        Ok(())
856    }
857
858    fn leave_namespace(&mut self) -> Result<Symbol, AssemblerError> {
859        self.symbols_mut().leave_namespace().map_err(|e| e.into())
860    }
861}
862
863impl Env {
864    /// Return the current state of writting of the assembler
865    fn output_kind(&self) -> OutputKind {
866        if self.cpr.is_some() {
867            OutputKind::Cpr
868        }
869        else if self.free_banks.selected_index.is_some() {
870            OutputKind::FreeBank
871        }
872        else {
873            OutputKind::Snapshot
874        }
875    }
876}
877
878#[allow(missing_docs)]
879impl Env {
880    /// Create an environment that embeds a copy of the given table and is configured to be in the latest pass.
881    /// Mainly used for tests.
882    /// TODO use bon here
883    pub fn with_table(symbols: &SymbolsTable) -> Self {
884        let mut env = Self::new(Default::default());
885        env.symbols.set_table(symbols.clone());
886        env.pass = AssemblingPass::SecondPass;
887        env
888    }
889
890    /// TODO use bon here
891    pub fn with_table_case_dependent(symbols: &SymbolsTableCaseDependent) -> Self {
892        let mut env = Self::new(Default::default());
893        env.symbols = symbols.clone();
894        env.pass = AssemblingPass::SecondPass;
895        env
896    }
897
898    pub fn warnings(&self) -> &[AssemblerWarning] {
899        &self.warnings
900    }
901
902    /// Manage the play with data for the output listing
903    fn handle_output_trigger(&mut self, new: &LocatedToken) {
904        if self.pass.is_listing_pass() && self.output_trigger.is_some() {
905            let code_addr = self.logical_code_address();
906            let phy_addr = self.logical_to_physical_address(self.logical_output_address());
907
908            let kind = if self.crunched_section_state.is_some() {
909                AddressKind::CrunchedArea
910            }
911            else {
912                AddressKind::Address
913            };
914
915            let trig = self.output_trigger.as_mut().unwrap();
916
917            trig.new_token(new, code_addr as _, kind, phy_addr);
918        }
919    }
920
921    fn retrieve_options_symbols(&mut self) {
922        let symbols = self
923            .options()
924            .symbols()
925            .available_symbols()
926            .cloned()
927            .collect_vec();
928        for symbol in symbols {
929            let value = self
930                .options()
931                .symbols()
932                .any_value(symbol.clone())
933                .unwrap()
934                .unwrap()
935                .clone();
936
937            self.symbols_mut().set_symbol_to_value(symbol, value);
938        }
939    }
940
941    /// Start a new pass by cleaning up datastructures.
942    /// The only thing to keep is the symbol table
943    pub(crate) fn start_new_pass(&mut self) {
944        if self.options().assemble_options().debug() {
945            eprintln!("Start a new pass {}", self.pass());
946            self.handle_print();
947            self.generate_symbols_output(
948                std::io::stderr().borrow_mut(),
949                SymbolOutputFormat::Winape
950            );
951        }
952
953        self.included_marks_reset();
954        self.requested_additional_pass |= !self.current_pass_discarded_errors.is_empty();
955
956        let mut can_change_request = true;
957        if !self.pass.is_listing_pass() {
958            self.pass = if self.real_nb_passes == 0
959                || !*self.can_skip_next_passes.read().unwrap().deref()
960            {
961                if *self.request_additional_pass.read().unwrap() {
962                    if self.pass.is_first_pass() {
963                        can_change_request = false;
964                    }
965                    AssemblingPass::SecondPass
966                }
967                else {
968                    self.pass.next_pass()
969                }
970            }
971            else if !*self.request_additional_pass.read().unwrap() {
972                AssemblingPass::Finished
973            }
974            else {
975                AssemblingPass::SecondPass
976            };
977        }
978
979        if !self.pass.is_finished() || self.pass.is_listing_pass() {
980            if !self.pass.is_listing_pass() {
981                self.real_nb_passes += 1;
982            }
983
984            std::mem::swap(
985                &mut self.current_pass_discarded_errors,
986                &mut self.previous_pass_discarded_errors
987            );
988            self.current_pass_discarded_errors.clear();
989
990            self.stable_counters.new_pass();
991            self.run_options = None;
992
993            self.sna.reset_written_bytes();
994            if let Some(cpr) = self.cpr.as_mut() {
995                cpr.reset_written_bytes()
996            }
997            self.free_banks.reset_written_bytes();
998
999            self.warnings.retain(|elem| !elem.is_override_memory());
1000            self.sna.pages_info.iter_mut().for_each(|p| p.new_pass());
1001
1002            self.sections
1003                .iter_mut()
1004                .for_each(|s| s.1.write().unwrap().new_pass());
1005            self.current_section = None;
1006
1007            self.free_banks.pages.iter_mut().for_each(|bank| {
1008                bank.1.new_pass();
1009                bank.2.fill(false);
1010            });
1011            self.free_banks.selected_index = None;
1012
1013            // environnement is not reset when assembling is finished
1014            self.output_address = 0;
1015            let page_info = self.active_page_info_mut();
1016            page_info.logical_outputadr = 0;
1017            page_info.logical_codeadr = 0;
1018            self.update_dollar();
1019
1020            self.ga_mmr = 0xC0;
1021            self.macro_seed = 0;
1022            self.charset_encoding.reset();
1023            // self.sna = Default::default(); // We finally keep the snapshot for the memory function
1024            // self.sna_version = cpclib_sna::SnapshotVersion::V3; // why changing it ?
1025
1026            self.can_skip_next_passes = true.into();
1027            if can_change_request {
1028                self.request_additional_pass = false.into();
1029            }
1030
1031            // reset the symbol table
1032            self.symbols.new_pass();
1033            self.retrieve_options_symbols();
1034
1035            if self.options.show_progress() {
1036                #[cfg(not(target_arch = "wasm32"))]
1037                Progress::progress().new_pass();
1038            }
1039        }
1040
1041        if AssemblingPass::FirstPass == self.pass {
1042            self.add_symbol_to_symbol_table(
1043                "BASM_VERSION",
1044                built_info::PKG_VERSION.to_owned(),
1045                None
1046            );
1047            self.add_symbol_to_symbol_table("BASM", 1, None);
1048            self.add_symbol_to_symbol_table("BASM_FEATURE_HFE", cfg!(feature = "hfe"), None);
1049        }
1050    }
1051
1052    /// Handle the actions to do after assembling.
1053    /// ATM it is only the save of data for each page
1054    pub fn handle_post_actions<'token, T>(
1055        &mut self,
1056        tokens: &'token [T]
1057    ) -> Result<(Option<RemuChunk>, Option<WabpChunk>), AssemblerError>
1058    where
1059        T: Visited + ToSimpleToken + Debug + Sync + ListingElement + MayHaveSpan,
1060        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
1061        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
1062            ExprEvaluationExt + ExprElement,
1063        ProcessedToken<'token, T>: FunctionBuilder
1064    {
1065        self.handle_print()?;
1066        self.handle_assert()?;
1067
1068        let remu_in_sna = self
1069            .options()
1070            .assemble_options()
1071            .get_flag(crate::AssemblingOptionFlags::SnaRemu);
1072        let remu_in_file = self
1073            .options()
1074            .assemble_options()
1075            .get_flag(crate::AssemblingOptionFlags::RemuInFile);
1076        let wabp_in_file = self
1077            .options()
1078            .assemble_options()
1079            .get_flag(crate::AssemblingOptionFlags::WabpInFile);
1080
1081        let mut remu = if remu_in_file || remu_in_sna {
1082            Some(RemuChunk::empty())
1083        }
1084        else {
1085            None
1086        };
1087
1088        let mut wabp = if wabp_in_file {
1089            Some(WabpChunk::empty())
1090        }
1091        else {
1092            None
1093        };
1094
1095        self.handle_breakpoints(&mut remu.as_mut(), &mut wabp.as_mut())?;
1096        self.handle_sna_symbols(&mut remu.as_mut())?;
1097
1098        if let Some(remu) = &remu
1099            && remu_in_sna
1100        {
1101            self.sna.add_chunk(remu.clone());
1102        }
1103
1104        // Add an additional pass to build the listing (this way it is built only one time)
1105        if self.options().assemble_options().output_builder.is_some() {
1106            let mut tokens = processed_token::build_processed_tokens_list(tokens, self)
1107                .expect("No errors must occur here");
1108            self.pass = AssemblingPass::ListingPass;
1109            self.start_new_pass();
1110            processed_token::visit_processed_tokens(&mut tokens, self)
1111                .map_err(|e| eprintln!("{}", e))
1112                .expect("No error can arise in listing output mode; there is a bug somewhere");
1113        }
1114
1115        // BUG this is definitevely a bug
1116        // - I have moved file saving here because output was wrong when done before listing
1117        // - Ther eis no reason to do that. it should even be the opposite
1118        self.saved_files = Some(self.handle_file_save()?);
1119
1120        Ok((remu, wabp))
1121    }
1122
1123    // Add the symbols in the snapshot
1124    fn handle_sna_symbols(
1125        &mut self,
1126        remu: &mut Option<&mut RemuChunk>
1127    ) -> Result<(), AssemblerError> {
1128        let options = self.options().assemble_options().clone();
1129        if options.get_flag(crate::AssemblingOptionFlags::SnaSymb) {
1130            let ace_chunk = self.symbols_output.build_ace_snapshot_chunk(self.symbols());
1131            self.sna.add_chunk(ace_chunk);
1132        }
1133
1134        if options.get_flag(crate::AssemblingOptionFlags::SnaRemu) {
1135            self.symbols_output
1136                .fill_remu_snapshot_chunk(self.symbols(), remu.as_mut().unwrap());
1137        }
1138
1139        Ok(())
1140    }
1141
1142    /// We handle breakpoint ONLY for the pages stored in the snapshot
1143    /// as they are stored inside a chunk of the snapshot:
1144    /// If one day another export is coded, we could export the others too.
1145    fn handle_breakpoints(
1146        &mut self,
1147        remu: &mut Option<&mut RemuChunk>,
1148        wabp: &mut Option<&mut WabpChunk>
1149    ) -> Result<(), AssemblerError> {
1150        let mut winape_chunk = if self
1151            .options()
1152            .assemble_options()
1153            .get_flag(crate::AssemblingOptionFlags::SnaBrks)
1154        {
1155            Some(WinapeBreakPointChunk::empty())
1156        }
1157        else {
1158            None
1159        };
1160        let mut ace_chunk = if self
1161            .options()
1162            .assemble_options()
1163            .get_flag(crate::AssemblingOptionFlags::SnaBrkc)
1164        {
1165            Some(AceBreakPointChunk::empty())
1166        }
1167        else {
1168            None
1169        };
1170
1171        let pages_mmr = MMR_PAGES_SELECTION;
1172        for (activepage, _page) in pages_mmr[0..self.sna.pages_info.len()].iter().enumerate() {
1173            for brk in self.sna.pages_info[activepage].collect_breakpoints() {
1174                let info = AssemblerError::RelocatedInfo {
1175                    info: Box::new(AssemblerError::AssemblingError {
1176                        msg: format!("Add a breakpoint: {} ", brk.info_repr())
1177                    }),
1178                    span: brk.span.as_ref().unwrap().clone()
1179                };
1180                eprint!("{}", info);
1181
1182                if let Some(chunk) = winape_chunk.as_mut() {
1183                    if let Some(brk) = brk.winape() {
1184                        chunk.add_breakpoint(brk);
1185                    }
1186                }
1187                if let Some(chunk) = ace_chunk.as_mut() {
1188                    if let Some(brk) = brk.ace() {
1189                        chunk.add_breakpoint(brk);
1190                    }
1191                }
1192
1193                if let Some(chunk) = remu.as_mut() {
1194                    chunk.add_entry(&brk.remu().into());
1195                }
1196
1197                if let Some(chunk) = wabp.as_mut() {
1198                    chunk.add_breakpoint(brk.wabp());
1199                }
1200            }
1201        }
1202
1203        if let Some(chunk) = winape_chunk
1204            && chunk.nb_breakpoints() > 0
1205        {
1206            self.sna.add_chunk(chunk);
1207        }
1208
1209        if let Some(chunk) = ace_chunk
1210            && chunk.nb_breakpoints() > 0
1211        {
1212            self.sna.add_chunk(chunk);
1213        }
1214
1215        Ok(())
1216    }
1217
1218    fn handle_assert(&mut self) -> Result<(), AssemblerError> {
1219        let backup = self.ga_mmr;
1220
1221        // ga values to properly switch the pages
1222        let pages_mmr = MMR_PAGES_SELECTION;
1223
1224        let mut assert_failures: Option<AssemblerError> = None;
1225
1226        let mut handle_page = |page: &PageInformation| {
1227            let mut l_errors = page.collect_assert_failure();
1228            match (&mut assert_failures, &mut l_errors) {
1229                (_, Ok(_)) => {
1230                    // nothing to do
1231                },
1232                (
1233                    Some(AssemblerError::MultipleErrors { errors: e1 }),
1234                    Err(AssemblerError::MultipleErrors { errors: e2 })
1235                ) => {
1236                    e1.append(e2);
1237                },
1238                (None, Err(l_errors)) => {
1239                    assert_failures = Some(l_errors.clone());
1240                },
1241                _ => unreachable!()
1242            }
1243        };
1244
1245        for (activepage, page) in pages_mmr[0..self.sna.pages_info.len()].iter().enumerate() {
1246            self.ga_mmr = *page;
1247            let page = &self.sna.pages_info[activepage];
1248            handle_page(page);
1249        }
1250
1251        for page in self.free_banks.page_infos() {
1252            handle_page(page);
1253        }
1254
1255        if let Some(cpr) = self.cpr.as_ref() {
1256            for page in cpr.page_infos() {
1257                handle_page(page)
1258            }
1259        }
1260
1261        self.ga_mmr = backup;
1262
1263        // All possible messages have been printed.
1264        // Errors are generated for the others
1265        if let Some(errors) = assert_failures {
1266            Err(errors)
1267        }
1268        else {
1269            Ok(())
1270        }
1271    }
1272
1273    pub fn observer(&self) -> Arc<dyn EnvEventObserver> {
1274        Arc::clone(&self.options().observer)
1275    }
1276
1277    pub fn handle_print(&mut self) -> Result<(), AssemblerError> {
1278        let backup = self.ga_mmr;
1279
1280        // ga values to properly switch the pages
1281        let pages_mmr = MMR_PAGES_SELECTION;
1282
1283        let mut print_errors: Option<AssemblerError> = None;
1284        let observer = self.observer();
1285
1286        let mut handle_page_info = |page: &PageInformation| {
1287            let mut l_errors = page.execute_print_or_pause(observer.deref());
1288            match (&mut print_errors, &mut l_errors) {
1289                (_, Ok(_)) => {
1290                    // nothing to do
1291                },
1292                (
1293                    Some(AssemblerError::MultipleErrors { errors: e1 }),
1294                    Err(AssemblerError::MultipleErrors { errors: e2 })
1295                ) => {
1296                    e1.append(e2);
1297                },
1298                (None, Err(l_errors)) => {
1299                    print_errors = Some(l_errors.clone());
1300                },
1301                _ => unreachable!()
1302            }
1303        };
1304
1305        // Print from the snapshot
1306        for (activepage, page) in pages_mmr[0..self.sna.pages_info.len()].iter().enumerate() {
1307            self.ga_mmr = *page;
1308            let page_info = &self.sna.pages_info[activepage];
1309
1310            handle_page_info(page_info);
1311        }
1312        self.ga_mmr = backup;
1313
1314        // Print free banks
1315        for page in self.free_banks.page_infos() {
1316            handle_page_info(page);
1317        }
1318
1319        // Print from CPR
1320        if let Some(cpr) = self.cpr.as_ref() {
1321            for page in cpr.page_infos() {
1322                handle_page_info(page);
1323            }
1324        }
1325
1326        // All possible messages have been printed.
1327        // Errors are generated for the others
1328        if let Some(errors) = print_errors {
1329            Err(errors)
1330        }
1331        else {
1332            Ok(())
1333        }
1334    }
1335
1336    fn handle_file_save(&mut self) -> Result<Vec<SavedFile>, AssemblerError> {
1337        let backup = self.ga_mmr;
1338
1339        // ga values to properly switch the pages
1340        let pages_mmr = MMR_PAGES_SELECTION;
1341
1342        let mut saved_files = Vec::new();
1343
1344        // count the number of files to save to build the process bar
1345        let nb_files_to_save = {
1346            let mut nb_files_to_save: u64 = 0;
1347            nb_files_to_save += pages_mmr[0..self.sna.pages_info.len()]
1348                .iter()
1349                .enumerate()
1350                .map(|(activepage, page)| {
1351                    self.ga_mmr = *page;
1352                    self.sna.pages_info[activepage].nb_files_to_save() as u64
1353                })
1354                .sum::<u64>();
1355            nb_files_to_save += self
1356                .free_banks
1357                .pages
1358                .iter()
1359                .map(|b| b.1.nb_files_to_save() as u64)
1360                .sum::<u64>();
1361
1362            nb_files_to_save
1363        };
1364
1365        if self.options.show_progress() {
1366            #[cfg(not(target_arch = "wasm32"))]
1367            Progress::progress().create_save_bar(nb_files_to_save);
1368        }
1369
1370        // save from snapshot. cannot be done in parallel
1371        for (activepage, _page) in pages_mmr[0..self.sna.pages_info.len()].iter().enumerate() {
1372            //  eprintln!("ACTIVEPAGE. {:x}", &activepage);
1373            //  eprintln!("PAGE. {:x}", &page);
1374
1375            for mma in self.sna.pages_info[activepage].get_save_mmrs() {
1376                self.ga_mmr = mma;
1377                let mut saved = self.sna.pages_info[activepage].execute_save(self, mma)?;
1378                saved_files.append(&mut saved);
1379            }
1380        }
1381
1382        // save from extra memory / can be done in parallel as it does not concerns memory
1383        self.ga_mmr = 0xC0;
1384
1385        #[cfg(all(not(target_arch = "wasm32"), feature = "rayon"))]
1386        let iter = {
1387            let can_save_in_parallel = self.banks.iter().all(|b| b.1.can_save_in_parallel());
1388            CondIterator::new(&self.banks, can_save_in_parallel)
1389        };
1390        #[cfg(any(target_arch = "wasm32", not(feature = "rayon")))]
1391        let iter = self.free_banks.pages.iter();
1392        let mut saved = iter
1393            .map(|bank| bank.1.execute_save(self, self.ga_mmr))
1394            .collect::<Result<Vec<_>, AssemblerError>>()?;
1395        for s in &mut saved {
1396            saved_files.append(s);
1397        }
1398
1399        if self.options().show_progress() {
1400            #[cfg(not(target_arch = "wasm32"))]
1401            Progress::progress().finish_save();
1402        }
1403        // restor memory conf
1404        self.ga_mmr = backup;
1405        Ok(saved_files)
1406    }
1407}
1408
1409/// Output handling
1410impl Env {
1411    /// TODO
1412    fn active_page_info(&self) -> &PageInformation {
1413        match self.output_kind() {
1414            OutputKind::Snapshot => {
1415                let active_page = self
1416                    .logical_to_physical_address(self.output_address)
1417                    .to_memory()
1418                    .page() as usize;
1419                &self.sna.pages_info[active_page]
1420            },
1421            OutputKind::Cpr => {
1422                self.cpr
1423                    .as_ref()
1424                    .unwrap()
1425                    .selected_active_page_info()
1426                    .unwrap()
1427            },
1428            OutputKind::FreeBank => self.free_banks.selected_active_page_info().unwrap()
1429        }
1430    }
1431
1432    fn active_page_info_mut(&mut self) -> &mut PageInformation {
1433        match self.output_kind() {
1434            OutputKind::Snapshot => {
1435                let active_page = self
1436                    .logical_to_physical_address(self.output_address)
1437                    .to_memory()
1438                    .page() as usize;
1439                &mut self.sna.pages_info[active_page]
1440            },
1441            OutputKind::Cpr => {
1442                let cpr = self.cpr.as_mut().unwrap();
1443                cpr.selected_active_page_info_mut().unwrap()
1444            },
1445            OutputKind::FreeBank => self.free_banks.selected_active_page_info_mut().unwrap()
1446        }
1447    }
1448
1449    fn page_info_for_logical_address_mut(&mut self, address: u16) -> &mut PageInformation {
1450        match self.output_kind() {
1451            OutputKind::Snapshot => {
1452                let active_page =
1453                    self.logical_to_physical_address(address).to_memory().page() as usize;
1454                &mut self.sna.pages_info[active_page]
1455            },
1456            OutputKind::Cpr => {
1457                self.cpr
1458                    .as_mut()
1459                    .unwrap()
1460                    .selected_active_page_info_mut()
1461                    .unwrap()
1462            },
1463            OutputKind::FreeBank => self.free_banks.selected_active_page_info_mut().unwrap()
1464        }
1465    }
1466
1467    fn written_bytes(&self) -> &BitVec {
1468        match self.output_kind() {
1469            OutputKind::Snapshot => &self.sna.written_bytes,
1470            OutputKind::Cpr => {
1471                self.cpr
1472                    .as_ref()
1473                    .unwrap()
1474                    .selected_written_bytes()
1475                    .expect("No bank selected")
1476            },
1477            OutputKind::FreeBank => {
1478                self.free_banks
1479                    .selected_written_bytes()
1480                    .expect("No bank selected")
1481            },
1482        }
1483    }
1484
1485    /// Return the address where the next byte will be written
1486    pub fn logical_output_address(&self) -> u16 {
1487        self.active_page_info().logical_outputadr
1488    }
1489
1490    pub fn physical_output_address(&self) -> PhysicalAddress {
1491        self.logical_to_physical_address(self.logical_output_address())
1492    }
1493
1494    pub fn physical_code_address(&self) -> PhysicalAddress {
1495        self.logical_to_physical_address(self.logical_code_address())
1496    }
1497
1498    /// Return the address of dollar
1499    pub fn logical_code_address(&self) -> u16 {
1500        self.active_page_info().logical_codeadr
1501    }
1502
1503    pub fn output_limit_address(&self) -> u16 {
1504        self.active_page_info().output_limit
1505    }
1506
1507    pub fn code_limit_address(&self) -> u16 {
1508        self.active_page_info().code_limit
1509    }
1510
1511    pub fn start_address(&self) -> Option<u16> {
1512        self.active_page_info().startadr
1513    }
1514
1515    pub fn maximum_address(&self) -> u16 {
1516        self.active_page_info().maxadr
1517    }
1518
1519    /// . Update the value of $ in the symbol table in order to take the current  output address
1520    pub fn update_dollar(&mut self) {
1521        if let Some(cpr) = &self.cpr {
1522            if cpr.is_empty() {
1523                return;
1524            }
1525        }
1526
1527        let code_addr = self.logical_to_physical_address(self.logical_code_address());
1528        let output_addr = self.logical_to_physical_address(self.logical_output_address());
1529
1530        self.symbols.set_current_address(code_addr);
1531        self.symbols.set_current_output_address(output_addr);
1532    }
1533
1534    /// Produce the memory for the required limits
1535    /// TODO check that the implementation is still correct with snapshot inclusion
1536    /// BUG  does not take into account extra bank configuration
1537    pub fn get_memory(&self, start: u16, size: u16) -> Vec<u8> {
1538        //     dbg!(self.ga_mmr);
1539        let mut mem = Vec::new();
1540        let start = start as u32;
1541        let size = size as u32;
1542        for pos in start..(start + size) {
1543            let address = self.logical_to_physical_address(pos as _);
1544            mem.push(self.peek(&address));
1545        }
1546        mem
1547    }
1548
1549    /// Returns the stream of bytes produced for a 64k compilation
1550    pub fn produced_bytes(&self) -> Vec<u8> {
1551        let (start, length) = match self.start_address() {
1552            Some(start) => {
1553                if start > self.maximum_address() {
1554                    (0, 0)
1555                }
1556                else {
1557                    (start, self.maximum_address() as usize - start as usize + 1)
1558                }
1559            },
1560            None => (0, 0)
1561        };
1562
1563        self.get_memory(start, length as _)
1564    }
1565
1566    /// Returns the address of the 1st written byte
1567    pub fn loading_address(&self) -> Option<u16> {
1568        self.start_address()
1569    }
1570
1571    /// Returns the address from when to start the program
1572    /// TODO really configure this address
1573    pub fn execution_address(&self) -> Option<u16> {
1574        self.start_address()
1575    }
1576
1577    /// Output one byte either in the appropriate bank of the snapshot or in the termporary bank
1578    /// return true if it raised an override warning
1579    pub fn output_byte(&mut self, v: u8) -> Result<bool, AssemblerError> {
1580        //   dbg!(self.logical_output_address(), self.output_address);
1581        if self.logical_output_address() != self.output_address {
1582            return Err(AssemblerError::BugInAssembler {
1583                file: file!(),
1584                line: line!(),
1585                msg: format!(
1586                    "Sync issue with output address (0x{:x} != 0x{:x})",
1587                    self.logical_output_address(),
1588                    self.output_address
1589                )
1590            });
1591        }
1592
1593        // dbg!(self.output_address(), &v);
1594        let physical_output_address: PhysicalAddress = self.physical_output_address();
1595        let physical_code_address: PhysicalAddress = self.physical_code_address();
1596
1597        // Check if it is legal to output the value
1598        // if self.logical_code_address() > self.limit_address() || (self.active_page_info().fail_next_write_if_zero && self.logical_code_address() == 0)
1599        if self.physical_output_address().address() > self.output_limit_address()
1600            || (self.active_page_info().fail_next_write_if_zero && self.logical_code_address() == 0)
1601        {
1602            return Err(AssemblerError::OutputExceedsLimits(
1603                physical_output_address,
1604                self.output_limit_address() as _
1605            ));
1606        }
1607
1608        if self.logical_code_address() > self.code_limit_address()
1609            || (self.active_page_info().fail_next_write_if_zero && self.logical_code_address() == 0)
1610        {
1611            return Err(AssemblerError::OutputExceedsLimits(
1612                physical_code_address,
1613                self.code_limit_address() as _
1614            ));
1615        }
1616        for protected_area in &self.active_page_info().protected_areas {
1617            if protected_area.contains(&{ self.logical_code_address() }) {
1618                return Err(AssemblerError::OutputProtected {
1619                    area: protected_area.clone(),
1620                    address: self.logical_code_address() as _
1621                });
1622            }
1623        }
1624
1625        self.byte_written = true;
1626        if let Some(commands) = self.assembling_control_current_output_commands.last_mut() {
1627            commands.store_byte(v);
1628        }
1629
1630        // TODO move the next in a function to reuse when executing the command
1631        // update the maximm 64k position
1632        self.active_page_info_mut().maxadr =
1633            self.maximum_address().max(self.logical_output_address());
1634        if self.active_page_info_mut().startadr.is_none() {
1635            self.active_page_info_mut().startadr = Some(self.logical_output_address());
1636        };
1637
1638        let abstract_address = physical_output_address.offset_in_cpc();
1639        let already_used = if let Some(access) = self.written_bytes().get(abstract_address as usize)
1640        {
1641            *access
1642        }
1643        else {
1644            return Err(AssemblerError::BugInAssembler {
1645                file: file!(),
1646                line: line!(),
1647                msg: format!(
1648                    "Wrong size of memory access {} > {}",
1649                    abstract_address,
1650                    self.written_bytes().len()
1651                )
1652            });
1653        };
1654
1655        let r#override = if already_used {
1656            let r#override = AssemblerWarning::OverrideMemory(physical_output_address, 1);
1657            if self.allow_memory_override() {
1658                self.add_warning(r#override);
1659                true
1660            }
1661            else {
1662                return Err(r#override);
1663            }
1664        }
1665        else {
1666            false
1667        };
1668
1669        if self.free_banks.selected_index.is_none() {
1670            if let Some(section) = &self.current_section {
1671                let section = section.read().unwrap();
1672                if !section.contains(physical_output_address.address()) {
1673                    return Err(AssemblerError::AssemblingError {
1674                        msg: format!(
1675                            "SECTION error: write address 0x{:x} out of range [Ox{:}-Ox{:}]",
1676                            physical_output_address.address(),
1677                            section.start,
1678                            section.stop
1679                        )
1680                    });
1681                }
1682            }
1683        }
1684
1685        match self.output_kind() {
1686            OutputKind::Snapshot => {
1687                self.sna.set_byte(abstract_address, v);
1688            },
1689            OutputKind::Cpr => {
1690                self.cpr
1691                    .as_mut()
1692                    .unwrap()
1693                    .set_byte(self.output_address, v)?;
1694            },
1695            OutputKind::FreeBank => {
1696                self.free_banks.set_byte(self.output_address, v);
1697            }
1698        }
1699
1700        // Add the byte to the listing space
1701        if self.pass.is_listing_pass() && self.output_trigger.is_some() {
1702            self.output_trigger.as_mut().unwrap().write_byte(v);
1703        }
1704
1705        self.active_page_info_mut().logical_outputadr =
1706            self.logical_output_address().wrapping_add(1);
1707        self.output_address = self.logical_output_address();
1708        self.active_page_info_mut().logical_codeadr = self.logical_code_address().wrapping_add(1);
1709
1710        // we have written all memory and are trying to restart
1711        if self.logical_output_address() == 0 {
1712            self.active_page_info_mut().fail_next_write_if_zero = true;
1713        }
1714
1715        {
1716            let (output, code) = (
1717                self.active_page_info().logical_outputadr,
1718                self.active_page_info().logical_codeadr
1719            );
1720
1721            if let Some(section) = &mut self.current_section {
1722                let mut section = section.write().unwrap();
1723                section.output_adr = output;
1724                section.code_adr = code;
1725                section.max_output_adr = section.max_output_adr.max(output);
1726            }
1727        }
1728
1729        self.update_dollar();
1730
1731        Ok(r#override)
1732    }
1733
1734    pub fn allow_memory_override(&self) -> bool {
1735        true // TODO parametrize it in the options (and set false by default)
1736    }
1737
1738    /// Write consecutives bytes
1739    pub fn output_bytes(&mut self, bytes: &[u8]) -> Result<(), AssemblerError> {
1740        //        dbg!(self.logical_output_address(), bytes);
1741
1742        let mut previously_overrided = false;
1743        for b in bytes.iter() {
1744            let currently_overrided = self.output_byte(*b)?;
1745
1746            if self.options().assemble_options().enable_warnings {
1747                match (previously_overrided, currently_overrided) {
1748                    (true, true) => {
1749                        // remove the latestwarning as it is a duplicate
1750                        let extra_override_idx = self
1751                            .warnings
1752                            .iter_mut()
1753                            .rev()
1754                            .position(|w| {
1755                                if let AssemblerError::OverrideMemory(..) = w {
1756                                    true
1757                                }
1758                                else {
1759                                    false
1760                                }
1761                            })
1762                            .unwrap(); // cannot fail by construction
1763                        self.warnings
1764                            .remove(self.warnings.len() - 1 - extra_override_idx); // rev impose to change index order
1765
1766                        // get the last override warning and update it
1767                        let r#override = self
1768                            .warnings
1769                            .iter_mut()
1770                            .rev()
1771                            .find(|w| {
1772                                if let AssemblerError::OverrideMemory(..) = w {
1773                                    true
1774                                }
1775                                else {
1776                                    false
1777                                }
1778                            })
1779                            .unwrap(); // cannot fail by construction
1780
1781                        // increase its size
1782                        match r#override {
1783                            AssemblerError::OverrideMemory(_, size) => {
1784                                *size += 1;
1785                            },
1786                            _ => unreachable!()
1787                        };
1788                    },
1789                    _ => {
1790                        // nothing to do
1791                    }
1792                }
1793            }
1794
1795            previously_overrided = currently_overrided;
1796        }
1797
1798        Ok(())
1799    }
1800
1801    pub fn peek(&self, address: &PhysicalAddress) -> u8 {
1802        // we assume that the physical address in argument matches the current configuration
1803        match self.output_kind() {
1804            OutputKind::Snapshot => {
1805                let address = address.to_memory().offset_in_cpc();
1806                self.sna.get_byte(address)
1807            },
1808            OutputKind::Cpr => {
1809                let address = address.to_cpr().address();
1810                self.cpr.as_ref().unwrap().get_byte(address as _).unwrap()
1811            },
1812            OutputKind::FreeBank => {
1813                let address = address.to_bank().address();
1814                self.free_banks.get_byte(address as _).unwrap()
1815            }
1816        }
1817    }
1818
1819    pub fn poke(&mut self, byte: u8, address: &PhysicalAddress) -> Result<(), AssemblerError> {
1820        // need modification to work when the physical address is different
1821        match self.output_kind() {
1822            OutputKind::Snapshot => {
1823                let address = address.to_memory().offset_in_cpc();
1824                self.sna.set_byte(address, byte)
1825            },
1826            OutputKind::Cpr => {
1827                let address = address.to_cpr().address();
1828                self.cpr.as_mut().unwrap().set_byte(address as _, byte)?
1829            },
1830            OutputKind::FreeBank => {
1831                let address = address.to_bank().address();
1832                self.free_banks.set_byte(address as _, byte)
1833            }
1834        }
1835
1836        Ok(())
1837    }
1838
1839    /// Get the size of the generated binary.
1840    /// ATTENTION it can only work when geneating 0x10000 files
1841    pub fn size(&self) -> u16 {
1842        if self.start_address().is_none() {
1843            panic!("Unable to compute size now");
1844        }
1845        else {
1846            self.logical_output_address() - self.start_address().unwrap()
1847        }
1848    }
1849
1850    /// Evaluate the expression according to the current state of the environment
1851    pub fn eval(&mut self, expr: &Expr) -> Result<ExprResult, AssemblerError> {
1852        expr.resolve(self)
1853    }
1854
1855    pub fn sna(&self) -> &cpclib_sna::Snapshot {
1856        &self.sna
1857    }
1858
1859    pub fn sna_version(&self) -> cpclib_sna::SnapshotVersion {
1860        self.sna_version
1861    }
1862
1863    pub fn save_sna<P: AsRef<Utf8Path>>(&self, fname: P) -> Result<(), std::io::Error> {
1864        self.sna().save(fname, self.sna_version())
1865    }
1866
1867    pub fn save_cpr<P: AsRef<Utf8Path>>(&self, fname: P) -> Result<(), AssemblerError> {
1868        let cpr_asm = self.cpr.as_ref().unwrap();
1869        let cpr = cpr_asm.build_cpr()?;
1870        cpr.save(fname)
1871            .map_err(|e| AssemblerError::IOError { msg: e.to_string() })
1872    }
1873
1874    /// Compute the relative address. Is authorized to fail at first pass
1875    fn absolute_to_relative_may_fail_in_first_pass(
1876        &self,
1877        address: i32,
1878        opcode_delta: i32
1879    ) -> Result<u8, AssemblerError> {
1880        match absolute_to_relative(address, opcode_delta, self.symbols()) {
1881            Ok(value) => Ok(value),
1882            Err(error) => {
1883                if self.pass.is_first_pass() {
1884                    Ok(0)
1885                }
1886                else {
1887                    Err(AssemblerError::RelativeAddressUncomputable {
1888                        address,
1889                        pass: self.pass,
1890                        error: Box::new(error)
1891                    })
1892                }
1893            },
1894        }
1895    }
1896}
1897
1898impl Env {
1899    #[inline(always)]
1900    pub fn add_warning(&mut self, warning: AssemblerWarning) {
1901        if self.options().assemble_options().enable_warnings {
1902            self.warnings.push(warning);
1903        }
1904    }
1905}
1906
1907/// Visit directives
1908impl Env {
1909    fn visit_org<E: ExprElement + ExprEvaluationExt + Debug>(
1910        &mut self,
1911        address: &E,
1912        address2: Option<&E>
1913    ) -> Result<(), AssemblerError> {
1914        // org $ set org to the output address (cf. rasm)
1915        let code_adr = if address2.is_none() && address.is_label_value("$") {
1916            if self.start_address().is_none() {
1917                return Err(AssemblerError::InvalidArgument {
1918                    msg: "ORG: $ cannot be used now".into()
1919                });
1920            }
1921            self.logical_output_address() as i32
1922        }
1923        else {
1924            self.resolve_expr_must_never_fail(address)?.int()?
1925        };
1926
1927        let output_adr = if let Some(address2) = address2 {
1928            if address2.is_label_value("$") {
1929                self.logical_output_address() as i32 // XXX here is must be code not output. I do not understand ...
1930            }
1931            else {
1932                self.resolve_expr_must_never_fail(address2)?.int()?
1933            }
1934        }
1935        else {
1936            code_adr
1937        };
1938
1939        if let Some(commands) = self.assembling_control_current_output_commands.last_mut() {
1940            commands.store_org(code_adr as _, output_adr as _);
1941        }
1942
1943        self.visit_org_set_arguments(code_adr as _, output_adr as _)
1944    }
1945
1946    pub fn visit_org_set_arguments(
1947        &mut self,
1948        code_adr: u16,
1949        output_adr: u16
1950    ) -> Result<(), AssemblerError> {
1951        // TODO move following code in a new method
1952
1953        // TODO Check overlapping region
1954        {
1955            let page_info = self.page_info_for_logical_address_mut(output_adr as _);
1956            page_info.logical_outputadr = output_adr as _;
1957            page_info.logical_codeadr = code_adr as _;
1958            page_info.fail_next_write_if_zero = false;
1959        }
1960
1961        // Specify start address at first use
1962        self.page_info_for_logical_address_mut(output_adr as _)
1963            .startadr = match self.start_address() {
1964            Some(val) => val.min(self.logical_output_address()),
1965            None => self.logical_output_address()
1966        }
1967        .into();
1968
1969        self.output_address = output_adr as _;
1970        self.update_dollar();
1971
1972        // update the erroneous information for the listing
1973        if self.pass.is_listing_pass() && self.output_trigger.is_some() {
1974            let output_adr = self.logical_to_physical_address(output_adr as _);
1975            let trigger = self.output_trigger.as_mut().unwrap();
1976
1977            trigger.replace_code_address(&code_adr.into());
1978            trigger.replace_physical_address(output_adr);
1979        }
1980
1981        if self.logical_output_address() != self.output_address {
1982            return Err(AssemblerError::BugInAssembler {
1983                file: file!(),
1984                line: line!(),
1985                msg: format!(
1986                    "BUG in assembler: 0x{:x}!=0x{:x} in pass {:?}",
1987                    self.logical_output_address(),
1988                    self.output_address,
1989                    self.pass
1990                )
1991            });
1992        }
1993
1994        Ok(())
1995    }
1996
1997    fn visit_breakpoint<E: ExprEvaluationExt + ExprElement + MayHaveSpan>(
1998        &mut self,
1999        address: Option<&E>,
2000        r#type: Option<&RemuBreakPointType>,
2001        access: Option<&RemuBreakPointAccessMode>,
2002        run: Option<&RemuBreakPointRunMode>,
2003        mask: Option<&E>,
2004        size: Option<&E>,
2005        value: Option<&E>,
2006        value_mask: Option<&E>,
2007        condition: Option<&E>,
2008        name: Option<&E>,
2009        step: Option<&E>,
2010        span: Option<&Z80Span>
2011    ) -> Result<(), AssemblerError> {
2012        let brk = if r#type.is_none()
2013            && access.is_none()
2014            && run.is_none()
2015            && mask.is_none()
2016            && size.is_none()
2017            && value.is_none()
2018            && value_mask.is_none()
2019            && condition.is_none()
2020            && name.is_none()
2021            && step.is_none()
2022        {
2023            // here we manipulate a very simple breakpoint
2024            let (current_address, page): (u16, u8) = if let Some(exp) = address {
2025                if exp.is_label() {
2026                    let label = exp.label();
2027                    let symbols = self.symbols();
2028                    let value: &Value = symbols.any_value(label)?.unwrap();
2029                    match value {
2030                        Value::Expr(expr_result) => (expr_result.int()? as _, 0),
2031                        Value::Address(physical_address) => {
2032                            (
2033                                physical_address.address(),
2034                                physical_address.remu_bank() as _
2035                            )
2036                        }, /* BUG we lost the differentiation between the different kind of addresses, */
2037                        _ => todo!()
2038                    }
2039                }
2040                else {
2041                    let current_address = self.resolve_expr_must_never_fail(exp)?.int()?;
2042                    let page = 0; // BUG should be dynamic and not hard coded !
2043                    (current_address as _, page)
2044                }
2045            }
2046            else {
2047                let current_address = self.logical_code_address();
2048                // ATM the breakpoints only work in SNA
2049                // To allow them in CPR there is a bit of work to do
2050                let page = match self
2051                    .logical_to_physical_address(current_address)
2052                    .to_memory()
2053                    .page()
2054                {
2055                    0 => 0,
2056                    1 => 1,
2057                    _ => {
2058                        return Err(AssemblerError::BugInAssembler {
2059                            file: file!(),
2060                            line: line!(),
2061                            msg: format!(
2062                                "Page selection not handled 0x{:x}",
2063                                self.logical_to_physical_address(current_address)
2064                                    .to_memory()
2065                                    .page()
2066                            )
2067                        });
2068                    }
2069                };
2070
2071                (current_address, page)
2072            };
2073
2074            BreakpointCommand::new_simple(current_address, page, span.cloned())
2075        }
2076        else {
2077            // here we manipulate an advanced breakpoint of Ace
2078
2079            let mut brk = AdvancedRemuBreakPoint::default();
2080            brk.addr = if let Some(address) = address {
2081                self.resolve_expr_must_never_fail(address)?.int()? as u16
2082            }
2083            else {
2084                self.logical_code_address()
2085            };
2086            if let Some(r#type) = r#type {
2087                brk.brk_type = r#type.clone();
2088            }
2089            if let Some(access) = access {
2090                brk.access_mode = access.clone();
2091            }
2092            if let Some(run) = run {
2093                brk.run_mode = run.clone();
2094            }
2095            if let Some(mask) = mask {
2096                brk.mask = self.resolve_expr_may_fail_in_first_pass(mask)?.int()? as u16;
2097            }
2098            if let Some(size) = size {
2099                brk.size = self.resolve_expr_may_fail_in_first_pass(size)?.int()? as u16;
2100            }
2101            if let Some(value) = value {
2102                brk.value = self.resolve_expr_may_fail_in_first_pass(value)?.int()? as u8;
2103            }
2104            if let Some(value_mask) = value_mask {
2105                brk.val_mask = self
2106                    .resolve_expr_may_fail_in_first_pass(value_mask)?
2107                    .int()? as u8;
2108            }
2109            if let Some(step) = step {
2110                brk.step = Some(self.resolve_expr_may_fail_in_first_pass(step)?.int()? as _);
2111            }
2112            if let Some(condition) = condition {
2113                let cond = self.resolve_expr_may_fail_in_first_pass(condition)?;
2114                let cond = cond.string()?;
2115                brk.condition.replace(String127::try_new(cond).map_err(|e| {
2116                    let e = AssemblerError::AssemblingError {
2117                        msg: "Condition is too long".to_owned()
2118                    };
2119                    if condition.has_span() {
2120                        e.locate(condition.span().clone())
2121                    }
2122                    else {
2123                        e
2124                    }
2125                })?);
2126            }
2127            if let Some(name) = name {
2128                let n = self.resolve_expr_may_fail_in_first_pass(name)?;
2129                let n = n.string()?;
2130                brk.name.replace(String127::try_new(n).map_err(|e| {
2131                    let e = AssemblerError::AssemblingError {
2132                        msg: "Name is too long".to_owned()
2133                    };
2134                    if name.has_span() {
2135                        e.locate(name.span().clone())
2136                    }
2137                    else {
2138                        e
2139                    }
2140                })?);
2141            }
2142
2143            BreakpointCommand::from((brk, span.cloned()))
2144        };
2145
2146        if self
2147            .options()
2148            .assemble_options()
2149            .get_flag(crate::AssemblingOptionFlags::BreakpointAsOpcode)
2150        {
2151            // XXX here we are dumb and add breakpoints unconditionnaly
2152            // TODO do it only for exec ones
2153            self.output_byte(0xED)?;
2154            self.output_byte(0xFF)?;
2155        }
2156        else {
2157            self.active_page_info_mut().add_breakpoint_command(brk);
2158        }
2159
2160        Ok(())
2161    }
2162}
2163
2164#[allow(missing_docs)]
2165impl Env {
2166    /// Write in w the list of symbols
2167    pub fn generate_symbols_output<W: Write>(
2168        &self,
2169        w: &mut W,
2170        fmt: SymbolOutputFormat
2171    ) -> std::io::Result<()> {
2172        self.symbols_output.generate(w, self.symbols(), fmt)
2173    }
2174
2175    /// Visit all the tokens of the slice of tokens.
2176    /// Return true if an additional pass is requested
2177    pub fn visit_listing<T: ListingElement + Visited + MayHaveSpan>(
2178        &mut self,
2179        listing: &[T]
2180    ) -> Result<(), AssemblerError> {
2181        for token in listing.iter() {
2182            token.visited(self)?;
2183        }
2184
2185        Ok(())
2186    }
2187
2188    /// TODO set the limit for the current page
2189    fn visit_limit<E: ExprEvaluationExt>(&mut self, exp: &E) -> Result<(), AssemblerError> {
2190        let value = self.resolve_expr_must_never_fail(exp)?.int()?;
2191        let in_crunched_section = self.crunched_section_state.is_some();
2192
2193        if value <= 0 {
2194            return Err(AssemblerError::AssemblingError {
2195                msg: format!("It is a nonsense to define a limit of {value}")
2196            });
2197        }
2198
2199        if value > 0xFFFF {
2200            return Err(AssemblerError::AssemblingError {
2201                msg: format!(
2202                    "It is a nonsense to define a limit of {value} that exceeds hardware limitations."
2203                )
2204            });
2205        }
2206
2207        if in_crunched_section {
2208            self.active_page_info_mut().code_limit = value as _;
2209            if self.code_limit_address() <= self.maximum_address() {
2210                return Err(AssemblerError::OutputAlreadyExceedsLimits(
2211                    self.code_limit_address() as _
2212                ));
2213            }
2214            if self.code_limit_address() == 0 {
2215                eprintln!("[WARNING] Do you really want to set a limit of 0 ?");
2216            }
2217        }
2218        else {
2219            self.active_page_info_mut().output_limit = value as _;
2220            if self.output_limit_address() <= self.maximum_address() {
2221                return Err(AssemblerError::OutputAlreadyExceedsLimits(
2222                    self.output_limit_address() as _
2223                ));
2224            }
2225            if self.output_limit_address() == 0 {
2226                eprintln!("[WARNING] Do you really want to set a limit of 0 ?");
2227            }
2228        }
2229
2230        Ok(())
2231    }
2232
2233    fn visit_map<E: ExprEvaluationExt>(&mut self, exp: &E) -> Result<(), AssemblerError> {
2234        let value = self.resolve_expr_must_never_fail(exp)?.int()?;
2235        self.map_counter = value;
2236
2237        Ok(())
2238    }
2239
2240    // Remove the global part if needed and change if if needed
2241    fn handle_global_and_local_labels<'s>(
2242        &mut self,
2243        label: &'s str
2244    ) -> Result<&'s str, AssemblerError> {
2245        let label = if let Some(dot_pos) = label[1..].find(".") {
2246            let global = &label[0..(dot_pos + 1)];
2247            let local = &label[(dot_pos + 1)..label.len()];
2248            let current = self.symbols().get_current_label().as_ref();
2249            if global != current {
2250                self.symbols_mut().set_current_label(global)?;
2251            }
2252            local
2253        }
2254        else {
2255            label
2256        };
2257
2258        Ok(label)
2259    }
2260
2261    fn visit_label<S: SourceString + MayHaveSpan>(
2262        &mut self,
2263        label_span: S
2264    ) -> Result<(), AssemblerError> {
2265        let label = self.symbols().normalize_symbol(label_span.as_str());
2266        let label = label.value();
2267
2268        // A label cannot be defined multiple times
2269        let res = if self.symbols().contains_symbol(label)?
2270            && (self.pass.is_first_pass()
2271                || !(self.symbols().kind(label)? == "address"
2272                    || self.symbols().kind(label)? == "any"))
2273        {
2274            Err(AssemblerError::AlreadyDefinedSymbol {
2275                symbol: self
2276                    .symbols()
2277                    .extend_local_and_patterns_for_symbol(label)
2278                    .map(std::convert::Into::<SmolStr>::into)
2279                    .unwrap_or_else(|_| SmolStr::from(label)),
2280                kind: self.symbols().kind(label)?.into(),
2281                here: self
2282                    .symbols()
2283                    .any_value(label)
2284                    .unwrap()
2285                    .unwrap()
2286                    .location()
2287                    .cloned()
2288            })
2289        }
2290        else {
2291            // TODO we should make the expansion right now because it is fucked up otherwise
2292
2293            let label = self.handle_global_and_local_labels(label)?;
2294            // XXX limit: should not be done here as it may start by {...} that contains when interpreted.}
2295            if !label.starts_with('.') {
2296                self.symbols_mut().set_current_label(label);
2297            }
2298
2299            // If the current address is not set up, we force it to be 0
2300            let value = self.symbols().current_address().unwrap_or_default();
2301            let addr = self.logical_to_physical_address(value);
2302
2303            self.add_symbol_to_symbol_table(
2304                label,
2305                addr,
2306                label_span.possible_span().map(|s| s.into())
2307            )
2308        };
2309
2310        // Try to fallback on a macro call - parser is not that much great
2311        if let Err(AssemblerError::AlreadyDefinedSymbol {
2312            symbol: _,
2313            kind,
2314            here: _
2315        }) = &res
2316        {
2317            if kind == "macro" || kind == "struct" {
2318                let message = AssemblerError::AssemblingError {
2319                    msg:
2320                        "Use (void) for macros or structs with no parameters to disambiguate them with labels"
2321                            .to_owned()
2322                };
2323                if self.options().assemble_options().force_void() {
2324                    return Err(message);
2325                }
2326                else {
2327                    // self.add_warning(message);
2328                }
2329
2330                // I'm really unsure of memory safety in case of bugs
2331                let macro_token = Token::MacroCall(label.into(), Default::default());
2332                let mut processed_token = build_processed_token(&macro_token, self)?;
2333                processed_token.visited(self)
2334            }
2335            else {
2336                res
2337            }
2338        }
2339        else {
2340            res
2341        }
2342    }
2343
2344    fn visit_noexport<S: AsRef<str> + Display>(
2345        &mut self,
2346        labels: &[S]
2347    ) -> Result<(), AssemblerError> {
2348        if labels.is_empty() {
2349            self.symbols_output.forbid_all_symbols();
2350        }
2351        else {
2352            labels
2353                .iter()
2354                .for_each(|l| self.symbols_output.forbid_symbol(l.as_ref()));
2355        }
2356
2357        Ok(())
2358    }
2359
2360    fn visit_export<S: AsRef<str> + Display>(
2361        &mut self,
2362        labels: &[S]
2363    ) -> Result<(), AssemblerError> {
2364        if labels.is_empty() {
2365            self.symbols_output.allow_all_symbols();
2366        }
2367        else {
2368            labels
2369                .iter()
2370                .for_each(|l| self.symbols_output.allow_symbol(l.as_ref()));
2371        }
2372
2373        Ok(())
2374    }
2375
2376    fn visit_multi_pushes<D: DataAccessElem>(&mut self, regs: &[D]) -> Result<(), AssemblerError> {
2377        let result = regs
2378            .iter()
2379            .map(|reg| assemble_push(reg))
2380            .collect::<Result<Vec<_>, AssemblerError>>()?;
2381        let result = result.into_iter().flatten().collect_vec();
2382        self.output_bytes(&result)
2383    }
2384
2385    fn visit_multi_pops<D: DataAccessElem>(&mut self, regs: &[D]) -> Result<(), AssemblerError> {
2386        let result = regs
2387            .iter()
2388            .map(|reg| assemble_pop(reg))
2389            .collect::<Result<Vec<_>, AssemblerError>>()?;
2390        let result = result.into_iter().flatten().collect_vec();
2391        self.output_bytes(&result)
2392    }
2393
2394    // TODO move that part n processed_tokens ?
2395    pub fn visit_macro_definition(
2396        &mut self,
2397        name: &str,
2398        arguments: &[&str],
2399        code: &str,
2400        source: Option<&Z80Span>,
2401        flavor: AssemblerFlavor
2402    ) -> Result<(), AssemblerError> {
2403        // ignore if it is the very same macro. That can happen with orgams
2404        if let Some(r#macro) = self.symbols().macro_value(name)? {
2405            if r#macro.code().trim() == code.trim() {
2406                return Ok(());
2407            }
2408            else {
2409                let diff = prettydiff::diff_lines(r#macro.code().trim(), code.trim())
2410                    .names("Previous macro", "Current macro")
2411                    .set_show_lines(true)
2412                    .set_diff_only(true)
2413                    .format();
2414                let msg = format!("Macro name `{name}` already exists. {}", diff);
2415                return Err(AssemblerError::AlreadyRenderedError(msg));
2416            }
2417        }
2418
2419        // raise an error if already exists
2420        if self.pass.is_first_pass() && self.symbols().contains_symbol(name)? {
2421            return Err(AssemblerError::SymbolAlreadyExists {
2422                symbol: name.to_owned()
2423            });
2424        }
2425
2426        let location: Option<Source> = source.map(|s| s.into());
2427        let source = source.map(|s| s.into());
2428
2429        let r#macro = Macro::new(name.into(), arguments, code.to_owned(), source, flavor);
2430        self.symbols_mut()
2431            .set_symbol_to_value(name, ValueAndSource::new(r#macro, location))?;
2432        Ok(())
2433    }
2434
2435    pub fn visit_waitnops<E: ExprEvaluationExt>(
2436        &mut self,
2437        count: &E
2438    ) -> Result<(), AssemblerError> {
2439        // TODO really use a clever way
2440        let bytes = self.assemble_nop(Mnemonic::Nop, Some(count))?;
2441        self.output_bytes(&bytes)?;
2442
2443        let count = self.resolve_expr_may_fail_in_first_pass(count)?.int()? as _;
2444        self.stable_counters.update_counters(count);
2445        Ok(())
2446    }
2447
2448    pub fn visit_struct_definition<
2449        T: ListingElement + ToSimpleToken,
2450        S1: SourceString,
2451        S2: AsRef<str>
2452    >(
2453        &mut self,
2454        name: S1,
2455        content: &[(S2, T)],
2456        span: Option<&Z80Span>
2457    ) -> Result<(), AssemblerError> {
2458        if self.pass.is_first_pass() && self.symbols().contains_symbol(name.as_str())? {
2459            return Err(AssemblerError::SymbolAlreadyExists {
2460                symbol: name.as_str().to_owned()
2461            });
2462        }
2463
2464        let r#struct = Struct::new(name.as_str(), content, span.map(|s| s.into()));
2465        // add inner index BEFORE the structure. It should reduce infinite loops
2466        let mut index = 0;
2467
2468        for (f, s) in r#struct.fields_size(self.symbols()) {
2469            self.symbols_mut()
2470                .set_symbol_to_value(format!("{}.{}", name, f), ValueAndSource::new(index, span))?;
2471            index += s;
2472        }
2473
2474        self.symbols_mut()
2475            .set_symbol_to_value(name.as_str(), ValueAndSource::new(r#struct, span))?;
2476
2477        Ok(())
2478    }
2479
2480    pub fn visit_buildcpr(&mut self) -> Result<(), AssemblerError> {
2481        if self.pass.is_first_pass() {
2482            self.cpr = Some(CprAssembler::default());
2483        }
2484        else {
2485            self.cpr.as_mut().unwrap().select(0);
2486        }
2487
2488        self.free_banks.selected_index = None; // be sure free banks is not selected
2489        self.ga_mmr = 0xC0;
2490
2491        Ok(())
2492    }
2493
2494    pub fn visit_buildsna(
2495        &mut self,
2496        version: Option<&SnapshotVersion>
2497    ) -> Result<(), AssemblerError> {
2498        self.sna_version = version.cloned().unwrap_or(SnapshotVersion::V3);
2499        self.free_banks.selected_index = None;
2500        Ok(())
2501    }
2502
2503    pub fn visit_assembler_control<C: AssemblerControlCommand>(
2504        &mut self,
2505        cmd: &C,
2506        span: Option<&Z80Span>
2507    ) -> Result<(), AssemblerError> {
2508        if cmd.is_restricted_assembling_environment() {
2509            return Err(AssemblerError::BugInAssembler {
2510                file: file!(),
2511                line: line!(),
2512                msg: "BUG in assembler. This has to be handled in processed_tokens".to_string()
2513            });
2514        }
2515        else if cmd.is_print_at_parse_state() {
2516            // nothing to do here because printing as alrady been done
2517        }
2518        else {
2519            assert!(cmd.is_print_at_assembling_state());
2520            let print_or_error =
2521                match self.prepropress_string_formatted_expression(cmd.get_formatted_expr()) {
2522                    Ok(msg) => either::Either::Left(msg),
2523                    Err(error) => either::Either::Right(error)
2524                };
2525
2526            PrintCommand {
2527                prefix: Some(format!("[PASS{}] ", self.pass)),
2528                span: span.cloned(),
2529                print_or_error
2530            }
2531            .execute(self.observer().deref()); // TODO use the true one
2532        }
2533        Ok(())
2534    }
2535
2536    pub fn visit_align<E: ExprEvaluationExt>(
2537        &mut self,
2538        boundary: &E,
2539        fill: Option<&E>
2540    ) -> Result<(), AssemblerError> {
2541        let boundary = self.resolve_expr_must_never_fail(boundary)?.int()? as u16;
2542        let fill = match fill {
2543            Some(fill) => self.resolve_expr_may_fail_in_first_pass(fill)?.int()? as u8,
2544            None => 0
2545        };
2546
2547        const OUTPUT_ALIGN: bool = false; // TODO programmaticall change it
2548
2549        while if OUTPUT_ALIGN {
2550            self.logical_output_address()
2551        }
2552        else {
2553            self.logical_code_address()
2554        } % boundary
2555            != 0
2556        {
2557            self.output_byte(fill)?;
2558        }
2559
2560        Ok(())
2561    }
2562
2563    fn get_section_description(&self, name: &str) -> Result<Section, AssemblerError> {
2564        match self.sections.get(name) {
2565            Some(section) => Ok(section.read().unwrap().clone()),
2566            None => {
2567                Err(AssemblerError::AssemblingError {
2568                    msg: format!("Section '{}' does not exists", name)
2569                })
2570            },
2571        }
2572    }
2573
2574    fn visit_section<S: SourceString>(&mut self, name: S) -> Result<(), AssemblerError> {
2575        let section = match self.sections.get(name.as_str()) {
2576            Some(section) => section,
2577            None => {
2578                return Err(AssemblerError::AssemblingError {
2579                    msg: format!("Section '{}' does not exists", name)
2580                });
2581            }
2582        };
2583
2584        let (output_adr, code_adr, mmr, warning) = {
2585            let section = section.read().unwrap();
2586
2587            let warning = if section.mmr != self.ga_mmr {
2588                Some(AssemblerError::AssemblingError {
2589                    msg: format!(
2590                        "Gate Array configuration is not coherent with the section. We  manually set it (0x{:x} expected instead of 0x{:x})",
2591                        section.mmr, self.ga_mmr
2592                    )
2593                })
2594            }
2595            else {
2596                None
2597            };
2598
2599            (section.output_adr, section.code_adr, section.mmr, warning)
2600        };
2601
2602        self.current_section = Some(Arc::clone(section));
2603
2604        self.ga_mmr = mmr;
2605        self.output_address = output_adr;
2606
2607        self.active_page_info_mut().logical_outputadr = output_adr;
2608        self.active_page_info_mut().logical_codeadr = code_adr;
2609
2610        self.update_dollar();
2611        if let Some(o) = self.output_trigger.as_mut() {
2612            o.replace_code_address(&code_adr.into())
2613        }
2614
2615        if let Some(warning) = warning {
2616            self.add_warning(warning);
2617        }
2618
2619        Ok(())
2620    }
2621
2622    fn visit_range<E: ExprEvaluationExt, S: SourceString>(
2623        &mut self,
2624        name: S,
2625        start: &E,
2626        stop: &E
2627    ) -> Result<(), AssemblerError> {
2628        let start = self.resolve_expr_must_never_fail(start)?.int()? as u16;
2629        let stop = self.resolve_expr_must_never_fail(stop)?.int()? as u16;
2630        let mmr = self.ga_mmr;
2631
2632        if let Some(section) = self.sections.get(name.as_str()) {
2633            let section = section.read().unwrap();
2634            if start != section.start
2635                || stop != section.stop
2636                || name.as_str() != section.name
2637                || mmr != section.mmr
2638            {
2639                return Err(AssemblerError::AssemblingError {
2640                    msg: format!(
2641                        "Section '{}' is already defined from 0x{:x} to 0x{:x} in 0x{:x}",
2642                        section.name, section.start, section.stop, section.mmr
2643                    )
2644                });
2645            }
2646        }
2647        else {
2648            let section = Arc::new(RwLock::new(Section::new(name.as_str(), start, stop, mmr)));
2649
2650            self.sections.insert(name.as_str().to_owned(), section);
2651        }
2652
2653        Ok(())
2654    }
2655
2656    fn visit_next_and_co<
2657        E: ExprElement + ExprEvaluationExt,
2658        S1: SourceString + MayHaveSpan,
2659        S2: SourceString
2660    >(
2661        &mut self,
2662        destination: S1,
2663        source: S2,
2664        delta: Option<&E>,
2665        can_override: bool
2666    ) -> Result<(), AssemblerError> {
2667        if !can_override
2668            && self.symbols.contains_symbol(destination.as_str())?
2669            && self.pass.is_first_pass()
2670        {
2671            let kind = self.symbols().kind(Symbol::from(destination.as_str()))?;
2672            return Err(AssemblerError::AlreadyDefinedSymbol {
2673                symbol: destination.as_str().into(),
2674                kind: kind.into(),
2675                here: None
2676            });
2677        }
2678
2679        // setup the value
2680        let value = self.resolve_expr_must_never_fail(&Expr::Label(source.as_str().into()))?;
2681        if can_override {
2682            self.symbols_mut()
2683                .assign_symbol_to_value(destination.as_str(), value.clone())?;
2684        }
2685        else {
2686            self.add_symbol_to_symbol_table(
2687                destination.as_str(),
2688                value.clone(),
2689                destination.possible_span().map(|s| s.into())
2690            )?;
2691        }
2692        if let Some(o) = self.output_trigger.as_mut() {
2693            o.replace_code_address(&value)
2694        }
2695
2696        // increase next one
2697        let delta = match delta {
2698            Some(delta) => self.resolve_expr_must_never_fail(delta)?,
2699            None => 1.into()
2700        };
2701        let value = (value + delta)?;
2702
2703        self.symbols_mut()
2704            .assign_symbol_to_value(source.as_str(), value)?;
2705
2706        Ok(())
2707    }
2708
2709    /// return the page and bank configuration for the given address at the current mmr configuration
2710    /// https://grimware.org/doku.php/documentations/devices/gatearray#mmr
2711    pub fn logical_to_physical_address(&self, address: u16) -> PhysicalAddress {
2712        match self.output_kind() {
2713            OutputKind::Snapshot => MemoryPhysicalAddress::new(address, self.ga_mmr).into(),
2714            OutputKind::Cpr => {
2715                CprPhysicalAddress::new(
2716                    address,
2717                    self.cpr.as_ref().unwrap().selected_bloc().unwrap()
2718                )
2719                .into()
2720            },
2721            OutputKind::FreeBank => {
2722                BankPhysicalAddress::new(address, self.free_banks.selected_index().unwrap()).into()
2723            },
2724        }
2725    }
2726
2727    fn visit_skip<E: ExprEvaluationExt>(&mut self, exp: &E) -> Result<(), AssemblerError> {
2728        let amount = self.resolve_expr_must_never_fail(exp)?.int()?;
2729
2730        // if amount < 0 {
2731        // return Err(AssemblerError::AlreadyRenderedError(format!("SKIP accept only positive values. {amount} is invalid")));
2732        // }
2733
2734        let amount = amount as u16;
2735
2736        let codeaddr = self
2737            .active_page_info()
2738            .logical_codeadr
2739            .wrapping_add(amount as _);
2740        let outputadr = self
2741            .active_page_info()
2742            .logical_outputadr
2743            .wrapping_add(amount as _);
2744
2745        self.active_page_info_mut().logical_codeadr = codeaddr;
2746        self.active_page_info_mut().logical_outputadr = outputadr;
2747
2748        self.update_dollar();
2749        self.output_address = outputadr;
2750        Ok(())
2751    }
2752
2753    /// The keyword is named BANK, but in fact, it is a PAGE ...
2754    fn visit_page_or_bank<E: ExprEvaluationExt>(
2755        &mut self,
2756        exp: Option<&E>
2757    ) -> Result<(), AssemblerError> {
2758        if self.nested_rorg > 0 {
2759            return Err(AssemblerError::NotAllowed);
2760        }
2761
2762        let output_kind = self.output_kind();
2763
2764        match exp {
2765            Some(exp) => {
2766                // prefix provided, we explicitely want one configuration
2767                let exp = self.resolve_expr_must_never_fail(exp)?.int()?;
2768                self.free_banks.selected_index = None;
2769
2770                if output_kind == OutputKind::Cpr {
2771                    if !(0..=31).contains(&exp) {
2772                        return Err(AssemblerError::AssemblingError {
2773                            msg: format!("Value {exp} is not compatible. [0-31]")
2774                        });
2775                    }
2776
2777                    if let Some(cpr) = &mut self.cpr {
2778                        cpr.select(exp as u8);
2779
2780                        let page_info = self.active_page_info_mut();
2781                        page_info.logical_outputadr = 0;
2782                        page_info.logical_codeadr = 0;
2783                        self.ga_mmr = 0xC0;
2784                        self.output_address = 0
2785                    }
2786                }
2787                else {
2788                    // Snapshot output
2789
2790                    let mmr = exp;
2791                    if !(0xC0..=0xC7).contains(&mmr) {
2792                        return Err(AssemblerError::MMRError { value: mmr });
2793                    }
2794
2795                    let mmr = mmr as u8;
2796                    self.ga_mmr = mmr;
2797
2798                    // ensure the page are present in the snapshot
2799                    if mmr >= 0xC4 && self.sna.pages_info.len() < 2 {
2800                        self.sna.resize(2.max(self.sna.pages_info.len()));
2801                    }
2802
2803                    // we do not change the output address (there is no reason to do that)
2804                }
2805            },
2806            None => {
2807                if output_kind == OutputKind::Cpr {
2808                    todo!("Need to implement this behavior")
2809                }
2810
2811                // nothing provided, we write in a temporary area
2812                if self.pass.is_first_pass() {
2813                    self.free_banks.add_new_and_select();
2814                }
2815                else {
2816                    self.free_banks.select_next()?;
2817                }
2818
2819                self.ga_mmr = 0xC0;
2820                self.output_address = 0;
2821                let page_info = self.active_page_info_mut();
2822                page_info.logical_outputadr = 0;
2823                page_info.logical_codeadr = 0;
2824            }
2825        }
2826
2827        Ok(())
2828    }
2829
2830    // total switch of page
2831    fn visit_pageset<E: ExprEvaluationExt>(&mut self, exp: &E) -> Result<(), AssemblerError> {
2832        if self.nested_rorg > 0 {
2833            return Err(AssemblerError::NotAllowed);
2834        }
2835
2836        let page = self.resolve_expr_must_never_fail(exp)?.int()? as u8; // This value MUST be interpretable once executed
2837
2838        //       eprintln!("Warning need to code sna memory extension if needed");
2839        self.select_page(page)?;
2840        Ok(())
2841    }
2842
2843    fn select_page(&mut self, page: u8) -> Result<(), AssemblerError> {
2844        if self.nested_rorg > 0 {
2845            return Err(AssemblerError::NotAllowed);
2846        }
2847
2848        if
2849        // page < 0 ||
2850        page >= 8 {
2851            return Err(AssemblerError::InvalidArgument {
2852                msg: format!(
2853                    "{} is invalid. BANKSET only accept values from 0 to 7",
2854                    page
2855                )
2856            });
2857        }
2858
2859        if page == 0 {
2860            self.ga_mmr = 0b1100_0000;
2861        }
2862        else {
2863            self.ga_mmr = 0b1100_0010 + ((page - 1) << 3);
2864        }
2865
2866        let page = page as usize;
2867        let expected_nb_pages = self.sna.pages_info.len().max(page + 1);
2868        if expected_nb_pages > self.sna.pages_info.len() {
2869            self.sna.resize(expected_nb_pages);
2870        }
2871        debug_assert_eq!(self.sna.pages_info.len(), expected_nb_pages);
2872
2873        self.output_address = self.logical_output_address();
2874        self.update_dollar();
2875        Ok(())
2876    }
2877
2878    /// Remove the given variable from the table of symbols
2879    pub fn visit_undef<S: SourceString>(&mut self, label: S) -> Result<(), AssemblerError> {
2880        match self.symbols_mut().remove_symbol(label.as_str())? {
2881            Some(_) => Ok(()),
2882            None => {
2883                Err(AssemblerError::UnknownSymbol {
2884                    symbol: label.as_str().into(),
2885                    closest: self
2886                        .symbols()
2887                        .closest_symbol(label.as_str(), SymbolFor::Number)?
2888                })
2889            },
2890        }
2891    }
2892
2893    pub fn visit_protect<E: ExprEvaluationExt>(
2894        &mut self,
2895        start: &E,
2896        stop: &E
2897    ) -> Result<(), AssemblerError> {
2898        if self.pass.is_first_pass() {
2899            let start = self.resolve_expr_must_never_fail(start)?.int()? as u16;
2900            let stop = self.resolve_expr_must_never_fail(stop)?.int()? as u16;
2901
2902            self.active_page_info_mut()
2903                .protected_areas
2904                .push(start..=stop);
2905        }
2906
2907        Ok(())
2908    }
2909
2910    #[inline]
2911    fn prepropress_string_formatted_expression(
2912        &mut self,
2913        info: &[FormattedExpr]
2914    ) -> Result<PreprocessedFormattedString, AssemblerError> {
2915        PreprocessedFormattedString::try_new(info, self)
2916    }
2917
2918    /// Print the evaluation of the expression in the 2nd pass
2919    pub fn visit_print(&mut self, info: &[FormattedExpr], span: Option<&Z80Span>) {
2920        let print_or_error = match self.prepropress_string_formatted_expression(info) {
2921            Ok(msg) => either::Either::Left(msg),
2922            Err(error) => either::Either::Right(error)
2923        };
2924
2925        self.active_page_info_mut().add_print_command(PrintCommand {
2926            prefix: None,
2927            span: span.cloned(),
2928            print_or_error
2929        })
2930    }
2931
2932    pub fn visit_pause(&mut self, span: Option<&Z80Span>) {
2933        self.active_page_info_mut()
2934            .add_pause_command(span.cloned().into());
2935    }
2936
2937    pub fn visit_fail(&mut self, info: Option<&[FormattedExpr]>) -> Result<(), AssemblerError> {
2938        let repr = info
2939            .map(|info| self.prepropress_string_formatted_expression(info))
2940            .unwrap_or_else(|| Ok(Default::default()))?;
2941        Err(AssemblerError::Fail {
2942            msg: repr.to_string()
2943        })
2944    }
2945
2946    // TODO better design the token to simplify this code and remove all ambigous cases
2947    pub fn visit_save<E: ExprEvaluationExt + Debug>(
2948        &mut self,
2949        amsdos_fname: &E,
2950        address: Option<&E>,
2951        size: Option<&E>,
2952        save_type: Option<&SaveType>,
2953        dsk_fname: Option<&E>,
2954        _side: Option<&E>
2955    ) -> Result<(), AssemblerError> {
2956        if cfg!(target_arch = "wasm32") {
2957            return Err(AssemblerError::AssemblingError {
2958                msg: "SAVE directive is not allowed in a web-based assembling.".to_owned()
2959            });
2960        }
2961
2962        let from = match address {
2963            Some(address) => {
2964                let address = self.resolve_expr_must_never_fail(address)?.int()?;
2965                if address < 0 {
2966                    return Err(AssemblerError::AssemblingError {
2967                        msg: format!(
2968                            "Cannot SAVE {amsdos_fname} as the address ({address}) is invalid."
2969                        )
2970                    });
2971                }
2972                Some(address)
2973            },
2974            None => None
2975        };
2976
2977        let size = match size {
2978            Some(size) => {
2979                let size = self.resolve_expr_must_never_fail(size)?.int()?;
2980                if size < 0 {
2981                    return Err(AssemblerError::AssemblingError {
2982                        msg: format!("Cannot SAVE {amsdos_fname} as the size ({size}) is invalid.")
2983                    });
2984                }
2985                Some(size)
2986            },
2987            None => None
2988        };
2989
2990        if let Some(from) = &from {
2991            if let Some(size) = &size {
2992                if 0x10000 - *from < *size {
2993                    return Err(AssemblerError::AssemblingError {
2994                        msg: format!(
2995                            "Cannot SAVE {amsdos_fname} as the address+size ({}) is out of bounds.",
2996                            *from + *size
2997                        )
2998                    });
2999                }
3000            }
3001        }
3002
3003        let amsdos_fname = self.build_fname(amsdos_fname)?;
3004        let any_fname: AnyFileNameOwned = match dsk_fname {
3005            Some(dsk_fname) => {
3006                AnyFileNameOwned::new_in_image(self.build_fname(dsk_fname)?, amsdos_fname)
3007            },
3008            None => AnyFileNameOwned::from(amsdos_fname.as_str())
3009        };
3010        let any_fname = any_fname.as_any_filename();
3011
3012        let (amsdos_fname, dsk_fname) = (any_fname.content_filename(), any_fname.image_filename());
3013
3014        let amsdos_fname = Utf8PathBuf::from(amsdos_fname);
3015        let dsk_fname = dsk_fname.map(Utf8PathBuf::from);
3016
3017        // Check filename validity
3018        if let Some(SaveType::Disc(disc)) = &save_type {
3019            let dsk_fname = dsk_fname.as_ref().unwrap();
3020            let lower_fname = dsk_fname.as_str().to_ascii_lowercase();
3021            match disc {
3022                DiscType::Dsk => {
3023                    if !(lower_fname.ends_with(".dsk") || lower_fname.ends_with(".edsk")) {
3024                        return Err(AssemblerError::InvalidArgument {
3025                            msg: format!("{dsk_fname} has not a DSK compatible extension")
3026                        });
3027                    }
3028                },
3029                DiscType::Hfe => {
3030                    if !lower_fname.ends_with(".hfe") {
3031                        return Err(AssemblerError::InvalidArgument {
3032                            msg: format!("{dsk_fname} has not a HFE compatible extension")
3033                        });
3034                    }
3035
3036                    #[cfg(not(feature = "hfe"))]
3037                    Err(AssemblerError::InvalidArgument {
3038                        msg: format!(
3039                            "{dsk_fname} cannot be saved. No HFE support is included with this version of basm"
3040                        )
3041                    })?
3042                },
3043                DiscType::Auto => {
3044                    if !(lower_fname.ends_with(".dsk")
3045                        || lower_fname.ends_with(".edsk")
3046                        || lower_fname.ends_with(".hfe"))
3047                    {
3048                        return Err(AssemblerError::InvalidArgument {
3049                            msg: format!("{dsk_fname} has not a DSK or HFE compatible extension")
3050                        });
3051                    }
3052
3053                    #[cfg(not(feature = "hfe"))]
3054                    if lower_fname.ends_with(".hfe") {
3055                        Err(AssemblerError::InvalidArgument {
3056                            msg: format!(
3057                                "{dsk_fname} cannot be saved. No HFE support is included with this version of basm"
3058                            )
3059                        })?
3060                    }
3061                }
3062            }
3063        }
3064
3065        let file = match (save_type, dsk_fname, amsdos_fname) {
3066            (Some(save_type), Some(dsk_fname), amsdos_fname) => {
3067                let support = match save_type {
3068                    SaveType::Disc(_) => StorageSupport::Disc(dsk_fname),
3069                    SaveType::Tape => StorageSupport::Tape(dsk_fname),
3070                    _ => StorageSupport::Disc(dsk_fname)
3071                };
3072                let file_type = match save_type {
3073                    SaveType::AmsdosBas => FileType::AmsdosBas,
3074                    SaveType::AmsdosBin => FileType::AmsdosBin,
3075                    SaveType::Ascii => FileType::Ascii,
3076                    SaveType::Disc(_) | SaveType::Tape => FileType::Auto /* TODO handle vases based on file names */
3077                };
3078                SaveFile::new(support, (file_type, amsdos_fname))
3079            },
3080            (None, Some(dsk_fname), amsdos_fname) => {
3081                SaveFile::new(
3082                    StorageSupport::Disc(dsk_fname),
3083                    (FileType::Auto, amsdos_fname)
3084                )
3085            },
3086            (Some(save_type), None, amsdos_fname) => {
3087                let file_type = match save_type {
3088                    SaveType::AmsdosBas => FileType::AmsdosBas,
3089                    SaveType::AmsdosBin => FileType::AmsdosBin,
3090                    SaveType::Ascii => FileType::Ascii,
3091                    SaveType::Disc(_) | SaveType::Tape => {
3092                        unimplemented!("Handle the error message");
3093                    }
3094                };
3095                SaveFile::new(StorageSupport::Host, (file_type, amsdos_fname))
3096            },
3097            (None, None, amsdos_fname) => {
3098                SaveFile::new(StorageSupport::Host, (FileType::Ascii, amsdos_fname))
3099            },
3100            (a, b, c) => unimplemented!("{a:?} {b:?} {c:?}")
3101        };
3102
3103        //       eprintln!("MMR at save=0x{:x}", self.ga_mmr);
3104        let mmr = self.ga_mmr;
3105        let page_info = self.active_page_info_mut();
3106        page_info.add_save_command(SaveCommand::new(from, size, file, mmr));
3107
3108        Ok(())
3109    }
3110
3111    pub fn visit_charset(&mut self, format: &CharsetFormat) -> Result<(), AssemblerError> {
3112        let mut new_charset = CharsetEncoding::new();
3113        std::mem::swap(&mut new_charset, &mut self.charset_encoding);
3114        new_charset.update(format, self)?;
3115        std::mem::swap(&mut new_charset, &mut self.charset_encoding); // XXX lost in case of error
3116        Ok(())
3117    }
3118
3119    pub fn visit_snainit<E: ExprEvaluationExt + Debug>(
3120        &mut self,
3121        fname: &E
3122    ) -> Result<(), AssemblerError> {
3123        let fname = self.build_fname(fname)?;
3124
3125        if !self.pass.is_first_pass() {
3126            return Ok(());
3127        }
3128
3129        if self.byte_written {
3130            return Err(AssemblerError::AssemblingError {
3131                msg: format!(
3132                    "Some bytes has already been produced; you cannot import the snapshot {}.",
3133                    fname
3134                )
3135            });
3136        }
3137        self.sna.sna = Snapshot::load(fname).map_err(|e| {
3138            AssemblerError::AssemblingError {
3139                msg: format!("Error while loading snapshot. {}", e)
3140            }
3141        })?;
3142
3143        self.sna.unwrap_memory_chunks();
3144
3145        Ok(())
3146    }
3147
3148    pub fn visit_snaset(
3149        &mut self,
3150        flag: &cpclib_sna::SnapshotFlag,
3151        value: &cpclib_sna::FlagValue
3152    ) -> Result<(), AssemblerError> {
3153        self.sna
3154            .set_value(*flag, value.as_u16().unwrap())
3155            .map_err(|e| e.into())
3156    }
3157
3158    pub fn visit_incbin(&mut self, data: &[u8]) -> Result<(), AssemblerError> {
3159        self.output_bytes(data)
3160    }
3161
3162    fn build_crunched_section_env(&mut self, span: Option<&Z80Span>) -> Self {
3163        let mut crunched_env = self.clone();
3164        crunched_env.crunched_section_state = CrunchedSectionState::new(span.cloned()).into();
3165        // codeadr stays the same
3166        crunched_env.active_page_info_mut().logical_outputadr = 0;
3167        crunched_env.active_page_info_mut().startadr = None; // reset the counter to obtain the bytes
3168        crunched_env.active_page_info_mut().maxadr = 0;
3169        crunched_env.active_page_info_mut().output_limit = 0xFFFF; // disable limit (to be redone in the area)
3170        crunched_env.active_page_info_mut().protected_areas.clear(); // remove protected areas
3171        crunched_env.output_address = 0;
3172
3173        crunched_env
3174    }
3175
3176    /// Handle a crunched section.
3177    /// bytes generated during previous pass or previous loop are provided TO NOT crunched them an additional time if they are similar
3178    pub fn visit_crunched_section<'tokens, T: Visited + ListingElement + MayHaveSpan + Sync>(
3179        &mut self,
3180        kind: &CrunchType,
3181        lst: &mut [ProcessedToken<'tokens, T>],
3182        previous_bytes: &mut Option<Vec<u8>>,
3183        previous_crunched_bytes: &mut Option<Vec<u8>>,
3184        span: Option<&Z80Span>
3185    ) -> Result<(), AssemblerError>
3186    where
3187        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3188        ProcessedToken<'tokens, T>: FunctionBuilder,
3189        <<T as cpclib_tokens::ListingElement>::TestKind as cpclib_tokens::TestKindElement>::Expr:
3190            ExprEvaluationExt
3191    {
3192        // deactivated because there is no reason to do such thing
3193        // crunched section is disabled inside crunched section
3194        // if let Some(state) = & self.crunched_section_state {
3195        // let base = AssemblerError::AlreadyInCrunchedSection(state.crunched_section_start);
3196        // if let Some(span) = span {
3197        // return Err(AssemblerError::RelocatedError{error:base, span});
3198        // } else {
3199        // return Err(base);
3200        // }
3201        // }
3202
3203        let could_display_warning_message = self.active_page_info().output_limit != 0xFFFF
3204            || !self.active_page_info().protected_areas.is_empty();
3205
3206        // from here, the modifications to the memory will be forgotten afterwise.
3207        // for this reason everything is done in a cloned environnement
3208        // TODO to have a more stable memory function, see if we can keep some steps between the passes
3209        // TODO OR play all the passes directly now
3210        let mut crunched_env = self.build_crunched_section_env(span);
3211
3212        if let Some(t) = self.output_trigger.as_mut() {
3213            t.enter_crunched_section()
3214        }
3215
3216        visit_processed_tokens(lst, &mut crunched_env).map_err(|e| {
3217            let e = AssemblerError::CrunchedSectionError { error: e.into() };
3218            match span {
3219                Some(span) => {
3220                    AssemblerError::RelocatedError {
3221                        error: e.into(),
3222                        span: span.clone()
3223                    }
3224                },
3225                None => e
3226            }
3227        })?;
3228
3229        if let Some(t) = self.output_trigger.as_mut() {
3230            t.leave_crunched_section()
3231        }
3232
3233        // get the new data and crunch it if needed
3234        let bytes = crunched_env.produced_bytes();
3235
3236        let must_crunch = previous_bytes
3237            .as_ref()
3238            .map(|b| b.as_slice() != bytes.as_slice())
3239            .unwrap_or(true);
3240        if must_crunch {
3241            let crunched: Vec<u8> = if bytes.is_empty() {
3242                Vec::new()
3243            }
3244            else {
3245                kind.crunch(&bytes).map_err(|e| {
3246                    match span {
3247                        Some(span) => {
3248                            AssemblerError::RelocatedError {
3249                                error: e.into(),
3250                                span: span.clone()
3251                            }
3252                        },
3253                        None => e
3254                    }
3255                })?
3256            };
3257            previous_crunched_bytes.replace(crunched);
3258            previous_bytes.replace(bytes);
3259        }
3260
3261        let _bytes = previous_bytes.as_ref().unwrap();
3262        let crunched = previous_crunched_bytes.as_ref().unwrap();
3263
3264        // inject the crunched data
3265        self.visit_incbin(crunched).map_err(|e| {
3266            match span {
3267                Some(span) => {
3268                    AssemblerError::RelocatedError {
3269                        error: e.into(),
3270                        span: span.clone()
3271                    }
3272                },
3273                None => e
3274            }
3275        })?;
3276
3277        // update the symbol table with the new symbols obtained in the crunched section
3278        std::mem::swap(self.symbols_mut(), crunched_env.symbols_mut());
3279        let can_skip_next_passes = *self.can_skip_next_passes.read().unwrap().deref()
3280            & *crunched_env.can_skip_next_passes.read().unwrap(); // report missing symbols from the crunched area to the current area
3281        let request_additional_pass = *self.request_additional_pass.read().unwrap().deref()
3282            | *crunched_env.request_additional_pass.read().unwrap();
3283        *self.can_skip_next_passes.write().unwrap() = can_skip_next_passes;
3284        *self.request_additional_pass.write().unwrap() = request_additional_pass;
3285
3286        self.macro_seed = crunched_env.macro_seed;
3287
3288        // TODO display ONLY if:
3289        // - no LIMIT/PROTECT has been used in the crunched area
3290        // - a possible forbidden write has been done (maybe too complex to implement)
3291        if could_display_warning_message {
3292            self.add_warning(
3293                AssemblerWarning::AssemblingError{
3294                    msg: "Memory protection systems are disabled in crunched section. If you want to keep them, explicitely use LIMIT or PROTECT directives in the crunched section.".to_owned()
3295                }
3296            );
3297        }
3298
3299        Ok(())
3300    }
3301}
3302
3303impl Env {
3304    fn assemble_nop<E: ExprEvaluationExt>(
3305        &mut self,
3306        kind: Mnemonic,
3307        count: Option<&E>
3308    ) -> Result<Bytes, AssemblerError> {
3309        let count = match count {
3310            Some(count) => self.resolve_expr_must_never_fail(count)?.int()?,
3311            None => 1
3312        };
3313        let mut bytes = Bytes::new();
3314        for _i in 0..count {
3315            match kind {
3316                Mnemonic::Nop => {
3317                    bytes.push(0);
3318                },
3319                Mnemonic::Nop2 => {
3320                    bytes.push(0xED);
3321                    bytes.push(0xFF);
3322                },
3323                _ => unreachable!()
3324            }
3325        }
3326        Ok(bytes)
3327    }
3328}
3329/// Visit the tokens during several passes without providing a specific symbol table.
3330// pub fn visit_tokens_all_passes<
3331// 'token,
3332// T: 'token + Visited + ToSimpleToken + Debug + Sync + ListingElement + MayHaveSpan
3333// >(
3334// tokens: &'token [T]
3335// ) -> Result<Env, AssemblerError>
3336// where
3337// <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3338// <<T as cpclib_tokens::ListingElement>::TestKind as cpclib_tokens::TestKindElement>::Expr:
3339// ExprEvaluationExt,
3340// ProcessedToken<'token, T>: FunctionBuilder
3341// {
3342// let options = EnvOptions::default();
3343// visit_tokens_all_passes_with_options(tokens, options).map(|r| r.1) // TODO really return both
3344// }
3345//
3346
3347impl Env {
3348    pub fn new(options: EnvOptions) -> Self {
3349        let mut env = Self {
3350            lookup_directory_stack: Vec::with_capacity(3),
3351            pass: AssemblingPass::Uninitialized,
3352            options: EnvOptions::default(),
3353            stable_counters: StableTickerCounters::default(),
3354            ga_mmr: 0xC0, // standard memory configuration
3355
3356            macro_seed: 0,
3357            charset_encoding: CharsetEncoding::new(),
3358            sna: SnaAssembler::default(),
3359            sna_version: cpclib_sna::SnapshotVersion::V3,
3360
3361            cpr: None,
3362
3363            symbols: SymbolsTableCaseDependent::default(),
3364            run_options: None,
3365            byte_written: false,
3366            output_trigger: None,
3367            symbols_output: Default::default(),
3368
3369            crunched_section_state: None,
3370
3371            warnings: Vec::new(),
3372            nested_rorg: 0,
3373
3374            sections: HashMap::<String, Arc<RwLock<Section>>>::default(),
3375            current_section: None,
3376            output_address: 0,
3377            free_banks: DecoratedPages::default(),
3378
3379            real_nb_passes: 0,
3380            saved_files: None,
3381            can_skip_next_passes: true.into(),
3382            request_additional_pass: false.into(),
3383
3384            if_token_adr_to_used_decision: HashMap::default(),
3385            if_token_adr_to_unused_decision: HashMap::default(),
3386            requested_additional_pass: false,
3387
3388            functions: Default::default(),
3389            return_value: None,
3390
3391            current_pass_discarded_errors: HashSet::default(),
3392            previous_pass_discarded_errors: HashSet::default(),
3393
3394            included_paths: HashSet::default(),
3395
3396            extra_print_from_function: Vec::new().into(),
3397            extra_failed_assert_from_function: Vec::new().into(),
3398            map_counter: 0,
3399
3400            repeat_start: 1.into(),
3401            repeat_step: 1.into(),
3402
3403            assembling_control_current_output_commands: Vec::new()
3404        };
3405
3406        env.options = options;
3407
3408        // prefill the snapshot representation with something else than the default
3409        if let Some(sna) = env.options.assemble_options().snapshot_model() {
3410            env.sna.sna = sna.clone();
3411            env.sna_version = env.sna.version();
3412        }
3413
3414        env.symbols = SymbolsTableCaseDependent::new(
3415            env.options().symbols().clone(),
3416            env.options().case_sensitive()
3417        );
3418        env.retrieve_options_symbols();
3419
3420        if let Some(builder) = &env.options().assemble_options().output_builder {
3421            env.output_trigger = ListingOutputTrigger {
3422                token: None,
3423                bytes: Vec::new(),
3424                builder: builder.clone(),
3425                start: 0,
3426                physical_address: MemoryPhysicalAddress::new(0, 0).into()
3427            }
3428            .into();
3429        }
3430        env
3431    }
3432
3433    pub fn pass(&self) -> &AssemblingPass {
3434        &self.pass
3435    }
3436}
3437
3438// Functions related
3439impl Env {
3440    pub fn visit_return<E: ExprEvaluationExt>(&mut self, e: &E) -> Result<(), AssemblerError> {
3441        debug_assert!(self.return_value.is_none());
3442        self.return_value = Some(self.resolve_expr_must_never_fail(e)?);
3443        Ok(())
3444    }
3445
3446    pub fn user_defined_function(&self, name: &str) -> Result<&Function, AssemblerError> {
3447        match self.functions.get(name) {
3448            Some(f) => Ok(f),
3449            None => Err(AssemblerError::FunctionUnknown(name.to_owned()))
3450        }
3451    }
3452
3453    pub fn any_function<'res>(
3454        &'res self,
3455        name: &'res str
3456    ) -> Result<&'res Function, AssemblerError> {
3457        match HardCodedFunction::by_name(name) {
3458            Some(f) => Ok(f),
3459            None => self.user_defined_function(name)
3460        }
3461    }
3462}
3463
3464/// Visit the tokens during several passes by providing a specific symbol table.
3465/// Warning Listing output is only possible for LocatedToken
3466pub fn visit_tokens_all_passes_with_options<'token, T>(
3467    tokens: &'token [T],
3468    options: EnvOptions
3469) -> Result<
3470    (Vec<ProcessedToken<'token, T>>, Env),
3471    (Option<Vec<ProcessedToken<'token, T>>>, Env, AssemblerError)
3472>
3473where
3474    T: Visited + ToSimpleToken + Debug + Sync + ListingElement + MayHaveSpan,
3475    <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3476    <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
3477        ExprEvaluationExt + ExprElement,
3478    ProcessedToken<'token, T>: FunctionBuilder
3479{
3480    let mut env = Env::new(options);
3481
3482    let mut tokens = match processed_token::build_processed_tokens_list(tokens, &mut env) {
3483        Ok(tokens) => tokens,
3484        Err(e) => return Err((None, env, e))
3485    };
3486    loop {
3487        env.start_new_pass();
3488        // println!("[pass] {:?}", env.pass);
3489
3490        if env.pass.is_finished() {
3491            break;
3492        }
3493
3494        let res = processed_token::visit_processed_tokens(&mut tokens, &mut env);
3495        if let Err(e) = res {
3496            return Err((Some(tokens), env, e));
3497        }
3498    }
3499
3500    env.cleanup_warnings();
3501
3502    if let Some(trigger) = env.output_trigger.as_mut() {
3503        trigger.finish()
3504    }
3505
3506    Ok((tokens, env))
3507}
3508
3509/// Visit the tokens during a single pass. Is deprecated in favor to the mulitpass version
3510#[deprecated(note = "use visit_tokens_one_pass")]
3511pub fn visit_tokens<T: Visited>(
3512    tokens: &[T],
3513    o: Arc<dyn EnvEventObserver>
3514) -> Result<Env, AssemblerError> {
3515    visit_tokens_one_pass(tokens, o)
3516}
3517
3518/// Assemble the tokens doing one pass only (so symbols are not properly treated)
3519pub fn visit_tokens_one_pass<T: Visited>(
3520    tokens: &[T],
3521    o: Arc<dyn EnvEventObserver>
3522) -> Result<Env, AssemblerError> {
3523    let mut opt = EnvOptions::default();
3524    opt.observer = o;
3525    let mut env = Env::new(opt);
3526
3527    for token in tokens.iter() {
3528        token.visited(&mut env)?;
3529    }
3530
3531    Ok(env)
3532}
3533
3534macro_rules! visit_token_impl {
3535    ($token:ident, $env:ident, $span:ident, $cls:tt) => {{
3536        $env.update_dollar();
3537        match &$token {
3538            $cls::Abyte(d, l) => $env.visit_abyte(d, l.as_ref()),
3539            $cls::Align(boundary, fill) => $env.visit_align(boundary, fill.as_ref()),
3540            $cls::Assert(exp, txt) => {
3541                visit_assert(exp, txt.as_ref(), $env, $span)?;
3542                Ok(())
3543            },
3544            $cls::AssemblerControl(cmd) => $env.visit_assembler_control(cmd, $span),
3545            $cls::Assign { label, expr, op } => $env.visit_assign(label, expr, op.as_ref()),
3546
3547            $cls::Basic(variables, hidden_lines, code) => {
3548                $env.visit_basic(
3549                    variables
3550                        .as_ref()
3551                        .map(|l| l.iter().map(|i| i).collect_vec()),
3552                    hidden_lines.as_ref(),
3553                    code
3554                )
3555            }, // TODO move in the processed tokens stuff
3556            $cls::Bank(exp) => $env.visit_page_or_bank(exp.as_ref()),
3557            $cls::Bankset(v) => $env.visit_pageset(v),
3558            $cls::Breakpoint {
3559                address,
3560                r#type,
3561                access,
3562                run,
3563                mask,
3564                size,
3565                value,
3566                value_mask,
3567                condition,
3568                name,
3569                step
3570            } => {
3571                $env.visit_breakpoint(
3572                    address.as_ref(),
3573                    r#type.as_ref(),
3574                    access.as_ref(),
3575                    run.as_ref(),
3576                    mask.as_ref(),
3577                    size.as_ref(),
3578                    value.as_ref(),
3579                    value_mask.as_ref(),
3580                    condition.as_ref(),
3581                    name.as_ref(),
3582                    step.as_ref(),
3583                    $span
3584                )
3585            },
3586            $cls::BuildCpr => $env.visit_buildcpr(),
3587            $cls::BuildSna(v) => $env.visit_buildsna(v.as_ref()),
3588
3589            $cls::Charset(format) => $env.visit_charset(format),
3590
3591            $cls::Comment(_) => Ok(()), // Nothing to do for a comment
3592
3593            $cls::Defb(l) => $env.visit_db_or_dw_or_str(DbLikeKind::Defb, l.as_ref(), 0.into()),
3594            $cls::Defw(l) => $env.visit_db_or_dw_or_str(DbLikeKind::Defw, l.as_ref(), 0.into()),
3595            $cls::Defs(l) => visit_defs(l, $env),
3596
3597            $cls::End => visit_end($env),
3598            $cls::Export(labels) => $env.visit_export(labels.as_slice()),
3599            $cls::Equ { label, expr } => $env.visit_equ(&label, expr),
3600
3601            $cls::Fail(exp) => $env.visit_fail(exp.as_ref().map(|v| v.as_slice())),
3602            $cls::Field { label, expr, .. } => $env.visit_field(label, expr),
3603
3604            $cls::Label(label) => $env.visit_label(label),
3605            $cls::Limit(exp) => $env.visit_limit(exp),
3606            $cls::List => {
3607                $env.output_trigger.as_mut().map(|l| {
3608                    l.on();
3609                });
3610                Ok(())
3611            },
3612
3613            $cls::Map(exp) => $env.visit_map(exp),
3614            $cls::MultiPush(regs) => $env.visit_multi_pushes(regs),
3615            $cls::MultiPop(regs) => $env.visit_multi_pops(regs),
3616
3617            $cls::Next {
3618                label,
3619                source,
3620                expr
3621            } => $env.visit_next_and_co(label, source, expr.as_ref(), false),
3622            $cls::NoExport(labels) => $env.visit_noexport(labels.as_slice()),
3623            $cls::NoList => {
3624                $env.output_trigger.as_mut().map(|l| {
3625                    l.off();
3626                });
3627                Ok(())
3628            },
3629
3630            $cls::Org { val1, val2 } => $env.visit_org(val1, val2.as_ref()),
3631            $cls::OpCode(mnemonic, arg1, arg2, arg3) => {
3632                visit_opcode(*mnemonic, &arg1, &arg2, &arg3, $env)?;
3633                // Compute duration only if it is necessary
3634                if !$env.stable_counters.is_empty() {
3635                    let duration = $token.to_token().estimated_duration()?;
3636                    $env.stable_counters.update_counters(duration);
3637                }
3638                Ok(())
3639            },
3640
3641            $cls::Pause => {
3642                $env.visit_pause($span);
3643                Ok(())
3644            },
3645            $cls::Protect(start, end) => $env.visit_protect(start, end),
3646            $cls::Print(exp) => {
3647                $env.visit_print(exp.as_ref(), $span);
3648                Ok(())
3649            },
3650
3651            $cls::Range(name, start, stop) => $env.visit_range(name, start, stop),
3652            $cls::Return(exp) => $env.visit_return(exp),
3653
3654            $cls::Rorg(_exp, _code) => panic!("Is delegated to ProcessedToken"),
3655            $cls::Run(address, gate_array) => $env.visit_run(address, gate_array.as_ref()),
3656
3657            $cls::SetN {
3658                label,
3659                source,
3660                expr
3661            } => $env.visit_next_and_co(label, source, expr.as_ref(), true),
3662            $cls::Save {
3663                filename,
3664                address,
3665                size,
3666                save_type,
3667                dsk_filename,
3668                side
3669            } => {
3670                $env.visit_save(
3671                    filename,
3672                    address.as_ref(),
3673                    size.as_ref(),
3674                    save_type.as_ref(),
3675                    dsk_filename.as_ref(),
3676                    side.as_ref()
3677                )
3678            },
3679            $cls::Section(name) => $env.visit_section(name),
3680            $cls::Skip(amount) => $env.visit_skip(amount),
3681            $cls::SnaInit(fname) => $env.visit_snainit(fname),
3682            $cls::SnaSet(flag, value) => $env.visit_snaset(flag, value),
3683            $cls::StableTicker(ticker) => visit_stableticker(ticker, $env),
3684            $cls::StartingIndex { start, step } => {
3685                $env.visit_starting_index(start.as_ref(), step.as_ref())
3686            },
3687            $cls::Str(l) => $env.visit_db_or_dw_or_str(DbLikeKind::Str, l.as_ref(), 0.into()),
3688            $cls::Struct(name, content) => {
3689                $env.visit_struct_definition(name, content.as_slice(), $span)
3690            },
3691
3692            $cls::Undef(label) => $env.visit_undef(label),
3693            $cls::WaitNops(count) => $env.visit_waitnops(count),
3694
3695            $cls::Include(..)
3696            | $cls::Incbin { .. }
3697            | $cls::If(..)
3698            | $cls::Repeat(..)
3699            | $cls::Macro { .. } => panic!("Should be handled by ProcessedToken"),
3700
3701            _ => {
3702                Err(AssemblerError::BugInAssembler {
3703                    file: file!(),
3704                    line: line!(),
3705                    msg: format!("Directive not handled: {:?}", $token)
3706                })
3707            },
3708        }
3709    }};
3710}
3711
3712/// Apply the effect of the localized token. Most of the action is delegated to visit_token.
3713/// The difference with the standard token is the ability to embed listing
3714pub fn visit_located_token(
3715    outer_token: &LocatedToken,
3716    env: &mut Env
3717) -> Result<(), AssemblerError> {
3718    let nb_warnings = env.warnings.len();
3719
3720    // cheat on the lifetime of tokens
3721    let outer_token = unsafe { (outer_token as *const LocatedToken).as_ref().unwrap() };
3722
3723    // XXX Maybe we have to uncomment it if some tokens are not included within the listing
3724    // env.handle_output_trigger(outer_token);
3725
3726    let span = Some(outer_token.span());
3727
3728    // handle warning if any
3729    if outer_token.is_warning() {
3730        let warning = AssemblerWarning::AlreadyRenderedError(outer_token.warning_message().into());
3731        let warning = warning.locate(outer_token.span().clone());
3732        env.add_warning(warning);
3733    }
3734
3735    // get the token to handle (after remobing handling wrapping)
3736    let token = outer_token.deref();
3737
3738    visit_token_impl!(token, env, span, LocatedTokenInner)
3739        .map_err(|e| e.locate(span.unwrap().clone()))?;
3740
3741    let span = outer_token.span();
3742
3743    // Patch the warnings to inject them a location
3744    let nb_additional_warnings = env.warnings.len() - nb_warnings;
3745    for i in 0..nb_additional_warnings {
3746        let warning = &mut env.warnings[i + nb_warnings];
3747        *warning = warning.clone().locate_warning(span.clone());
3748
3749        // TODO check why it has been done this way
3750        //      maybe source code is not retrained and there are random crashes ?
3751        //     anyway I comment it now because it breaks warning merge
3752        //
3753        //    *warning = AssemblerError::AssemblingError {
3754        //        msg: (*warning).to_string()
3755        //    }
3756    }
3757
3758    env.move_delayed_commands_of_functions();
3759
3760    Ok(())
3761}
3762
3763/// Apply the effect of the token
3764fn visit_token(token: &Token, env: &mut Env) -> Result<(), AssemblerError> {
3765    let span = None;
3766    let _res = visit_token_impl!(token, env, span, Token);
3767
3768    env.move_delayed_commands_of_functions();
3769    Ok(())
3770}
3771
3772/// No error is generated here; everything is delayed at the end of assembling.
3773/// Returns false in case of assert failure
3774fn visit_assert<E: ExprEvaluationExt + ExprElement>(
3775    exp: &E,
3776    txt: Option<&Vec<FormattedExpr>>,
3777    env: &mut Env,
3778    span: Option<&Z80Span>
3779) -> Result<bool, AssemblerError> {
3780    if let Some(commands) = env.assembling_control_current_output_commands.last_mut() {
3781        commands.store_assert(exp.to_expr().into_owned(), txt.cloned(), span.cloned());
3782    }
3783
3784    let res = match env.resolve_expr_must_never_fail(exp) {
3785        Err(e) => Err(e),
3786
3787        Ok(value) => {
3788            if !value.bool()? {
3789                Err(AssemblerError::AssertionFailed {
3790                    msg: /*prefix
3791                        +*/ (if txt.is_some() {
3792                            env.prepropress_string_formatted_expression(txt.unwrap())?.to_string()
3793                        }
3794                        else {
3795                            "".to_owned()
3796                        })
3797                        /* .as_str()*/,
3798                    test: exp.to_string(),
3799                    guidance: env.to_assert_string(exp)
3800                })
3801            }
3802            else {
3803                Ok(())
3804            }
3805        }
3806    };
3807
3808    if let Err(assert_error) = res {
3809        let assert_error = if let Some(span) = span {
3810            assert_error.locate(span.clone())
3811        }
3812        else {
3813            assert_error
3814        };
3815        env.active_page_info_mut()
3816            .add_failed_assert_command(assert_error.into());
3817        Ok(false)
3818    }
3819    else {
3820        Ok(true)
3821    }
3822}
3823
3824impl Env {
3825    pub fn visit_while<'token, E, T>(
3826        &mut self,
3827        cond: &E,
3828        code: &mut [ProcessedToken<'token, T>],
3829        span: Option<&Z80Span>
3830    ) -> Result<(), AssemblerError>
3831    where
3832        T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
3833        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3834        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
3835            ExprEvaluationExt,
3836        ProcessedToken<'token, T>: FunctionBuilder
3837    {
3838        while self.resolve_expr_must_never_fail(cond)?.bool()? {
3839            // generate the bytes
3840            visit_processed_tokens(code, self).map_err(|e| {
3841                AssemblerError::WhileIssue {
3842                    error: Box::new(e),
3843                    span: span.cloned()
3844                }
3845            })?;
3846        }
3847
3848        Ok(())
3849    }
3850
3851    /// Handle the iterate repetition directive
3852    /// Values is either a list of values or a Expression that represents a list
3853    pub fn visit_iterate<
3854        'token,
3855        E: ExprEvaluationExt,
3856        T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync
3857    >(
3858        &mut self,
3859        counter_name: &str,
3860        values: either::Either<&Vec<E>, &E>,
3861        code: &mut [ProcessedToken<'token, T>],
3862        span: Option<&Z80Span>
3863    ) -> Result<(), AssemblerError>
3864    where
3865        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3866        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
3867            ExprEvaluationExt,
3868        ProcessedToken<'token, T>: FunctionBuilder
3869    {
3870        let counter_name = format!("{{{}}}", counter_name);
3871        let counter_name = counter_name.as_str();
3872        if self.symbols().contains_symbol(counter_name)? {
3873            return Err(AssemblerError::RepeatIssue {
3874                error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
3875                    AssemblerError::AssemblingError {
3876                        msg: format!("Counter {} already exists", counter_name)
3877                    }
3878                )))
3879                .into(),
3880                span: span.cloned(),
3881                repetition: 0
3882            });
3883        }
3884
3885        // Get the values (all args or list explosion)
3886        // BUG: iteration over values make the expressions progressively evaluated, while iteration over a list make its expressions evaluated at first loop
3887        match values {
3888            either::Either::Left(values) => {
3889                for (i, value) in values.iter().enumerate() {
3890                    let counter_value = self.resolve_expr_must_never_fail(value).map_err(|e| {
3891                        AssemblerError::RepeatIssue {
3892                            error: Box::new(e),
3893                            span: span.cloned(),
3894                            repetition: i as _
3895                        }
3896                    })?;
3897                    self.inner_visit_repeat(
3898                        Some(counter_name),
3899                        Some(counter_value),
3900                        i as _,
3901                        code,
3902                        span
3903                    )?;
3904                }
3905            },
3906            either::Either::Right(values) => {
3907                match self.resolve_expr_must_never_fail(values)? {
3908                    ExprResult::List(values) => {
3909                        for (i, counter_value) in values.into_iter().enumerate() {
3910                            self.inner_visit_repeat(
3911                                Some(counter_name),
3912                                Some(counter_value),
3913                                i as _,
3914                                code,
3915                                span
3916                            )?;
3917                        }
3918                    },
3919                    _ => {
3920                        return Err(AssemblerError::AssemblingError {
3921                            msg: format!("REPEAT issue: {} is not a list", values)
3922                        });
3923                    }
3924                }
3925            },
3926        }
3927
3928        // Apply the iteration
3929
3930        // TODO restore a previous value if any
3931        self.symbols_mut().remove_symbol(counter_name)?;
3932
3933        Ok(())
3934    }
3935
3936    pub fn visit_rorg<'token, T, E>(
3937        &mut self,
3938        address: &E,
3939        code: &mut [ProcessedToken<'token, T>],
3940        span: Option<&Z80Span>
3941    ) -> Result<(), AssemblerError>
3942    where
3943        E: ExprEvaluationExt,
3944        T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
3945        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3946        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
3947            ExprEvaluationExt,
3948        ProcessedToken<'token, T>: FunctionBuilder
3949    {
3950        // Get the next code address
3951        let address = self
3952            .resolve_expr_must_never_fail(address)
3953            .map_err(|error| {
3954                match span {
3955                    Some(span) => {
3956                        AssemblerError::RelocatedError {
3957                            error: Box::new(error),
3958                            span: span.clone()
3959                        }
3960                    },
3961                    None => error
3962                }
3963            })?
3964            .int()?;
3965
3966        // do not change the output address
3967        {
3968            let page_info = self.active_page_info_mut();
3969            page_info.logical_codeadr = address as _;
3970        }
3971
3972        self.update_dollar();
3973        let value = self.active_page_info_mut().logical_codeadr;
3974
3975        if let Some(o) = self.output_trigger.as_mut() {
3976            o.replace_code_address(&value.into())
3977        }
3978
3979        // execute the listing
3980        self.nested_rorg += 1; // used to disable page functionalities
3981        visit_processed_tokens(code, self)?;
3982        self.nested_rorg -= 1;
3983
3984        // restore the appropriate  address
3985        let page_info = self.active_page_info_mut();
3986        page_info.logical_codeadr = page_info.logical_outputadr;
3987
3988        Ok(())
3989    }
3990
3991    pub fn visit_confined<'token, E: ExprEvaluationExt, T>(
3992        &mut self,
3993        lst: &mut [ProcessedToken<'token, T>],
3994        span: Option<&Z80Span>
3995    ) -> Result<(), AssemblerError>
3996    where
3997        T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
3998        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3999        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4000            ExprEvaluationExt,
4001        ProcessedToken<'token, T>: FunctionBuilder
4002    {
4003        // Visit the confined section a first time
4004        // TODO: refactor this code with visit_crunched_section
4005        let mut confined_env = self.clone();
4006        confined_env.active_page_info_mut().logical_outputadr = 0;
4007        confined_env.active_page_info_mut().startadr = None; // reset the counter to obtain the bytes
4008        confined_env.active_page_info_mut().maxadr = 0;
4009        confined_env.active_page_info_mut().output_limit = 0xFFFF; // disable limit (to be redone in the area)
4010        confined_env.active_page_info_mut().protected_areas.clear(); // remove protected areas
4011        confined_env.output_address = 0;
4012        // TODO: forbid a subset of instructions to ensure it works properly
4013        visit_processed_tokens(lst, &mut confined_env).map_err(|e| {
4014            panic!("{:?}", e);
4015            match span {
4016                Some(span) => e.locate(span.clone()),
4017                None => e
4018            }
4019        })?;
4020
4021        // compute its size
4022        let bytes = confined_env.produced_bytes();
4023        let bytes_len = bytes.len() as u16;
4024
4025        if bytes_len > 256 {
4026            let e = AssemblerError::AssemblingError {
4027                msg: format!(
4028                    "CONFINED error: content uses {} bytes instead of a maximum of 256.",
4029                    bytes.len()
4030                )
4031            };
4032            match span {
4033                Some(span) => return Err(e.locate(span.clone())),
4034                None => return Err(e)
4035            }
4036        }
4037
4038        // Add the delta if needed and recompute the confined section a second time to properly setup the side effects
4039        if ((self.logical_code_address().wrapping_add(bytes_len)) & 0xFF00)
4040            != self.logical_code_address() & 0xFF00
4041        {
4042            while (self.logical_code_address() & 0x00FF) != 0x0000 {
4043                self.output_byte(0)?;
4044                self.update_dollar();
4045            }
4046        }
4047
4048        visit_processed_tokens(lst, self)
4049    }
4050
4051    /// Handle the for directive
4052    pub fn visit_for<'token, E: ExprEvaluationExt, T>(
4053        &mut self,
4054        label: &str,
4055        start: &E,
4056        stop: &E,
4057        step: Option<&E>,
4058        code: &mut [ProcessedToken<'token, T>],
4059        span: Option<&Z80Span>
4060    ) -> Result<(), AssemblerError>
4061    where
4062        T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
4063        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4064        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4065            ExprEvaluationExt,
4066        ProcessedToken<'token, T>: FunctionBuilder
4067    {
4068        let counter_name = format!("{{{}}}", label);
4069        if self.symbols().contains_symbol(&counter_name)? {
4070            return Err(AssemblerError::ForIssue {
4071                error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
4072                    AssemblerError::AssemblingError {
4073                        msg: format!("Counter {} already exists", &counter_name)
4074                    }
4075                )))
4076                .into(),
4077                span: span.cloned()
4078            });
4079        }
4080
4081        let mut counter_value = self.resolve_expr_must_never_fail(start)?;
4082        let stop = self.resolve_expr_must_never_fail(stop)?;
4083        let step = match step {
4084            Some(step) => self.resolve_expr_must_never_fail(step)?,
4085            None => 1i32.into()
4086        };
4087
4088        let zero = ExprResult::from(0i32);
4089
4090        if step == zero {
4091            return Err(AssemblerError::ForIssue {
4092                error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
4093                    AssemblerError::AssemblingError {
4094                        msg: "Infinite loop".to_string()
4095                    }
4096                )))
4097                .into(),
4098                span: span.cloned()
4099            });
4100        }
4101
4102        if step < zero {
4103            return Err(AssemblerError::ForIssue {
4104                error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
4105                    AssemblerError::AssemblingError {
4106                        msg: "Negative step is not yet handled".to_string()
4107                    }
4108                )))
4109                .into(),
4110                span: span.cloned()
4111            });
4112        }
4113
4114        let mut i = 1;
4115        while counter_value <= stop {
4116            self.inner_visit_repeat(
4117                Some(counter_name.as_str()),
4118                Some(counter_value.clone()),
4119                i as _,
4120                code,
4121                span
4122            )?;
4123            counter_value = (counter_value + &step)?;
4124            i += 1;
4125        }
4126
4127        self.symbols_mut().remove_symbol(counter_name)?;
4128
4129        Ok(())
4130    }
4131
4132    /// Handle the standard repetition directive
4133    pub fn visit_repeat_until<'token, E, T>(
4134        &mut self,
4135        cond: &E,
4136        code: &mut [ProcessedToken<'token, T>],
4137        span: Option<&Z80Span>
4138    ) -> Result<(), AssemblerError>
4139    where
4140        E: ExprEvaluationExt,
4141        T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
4142        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4143        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4144            ExprEvaluationExt,
4145        ProcessedToken<'token, T>: FunctionBuilder
4146    {
4147        let mut i = 0;
4148        loop {
4149            i += 1;
4150            self.inner_visit_repeat(None, None, i as _, code, span)?;
4151            let res = self.resolve_expr_must_never_fail(cond)?;
4152            if res.bool()? {
4153                break;
4154            }
4155        }
4156
4157        Ok(())
4158    }
4159
4160    pub fn visit_starting_index<E>(
4161        &mut self,
4162        start: Option<&E>,
4163        step: Option<&E>
4164    ) -> Result<(), AssemblerError>
4165    where
4166        E: ExprEvaluationExt
4167    {
4168        let start_value = start
4169            .map(|start| self.resolve_expr_must_never_fail(start))
4170            .unwrap_or(Ok(ExprResult::from(1)))?;
4171        let step_value = step
4172            .map(|step| self.resolve_expr_must_never_fail(step))
4173            .unwrap_or(Ok(ExprResult::from(1)))?;
4174
4175        self.repeat_start = start_value;
4176        self.repeat_step = step_value;
4177        Ok(())
4178    }
4179
4180    /// Handle the repetition of single opcode
4181    pub fn visit_repeat_token<'token, T, E>(
4182        &mut self,
4183        opcode: &mut ProcessedToken<'token, T>,
4184        count: &E
4185    ) -> Result<(), AssemblerError>
4186    where
4187        E: ExprEvaluationExt,
4188        T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
4189        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4190        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4191            ExprEvaluationExt,
4192        ProcessedToken<'token, T>: FunctionBuilder
4193    {
4194        let repeat = self.resolve_expr_must_never_fail(count)?;
4195        let repeat = repeat.int()?;
4196        for _ in 0..repeat {
4197            opcode.visited(self)?;
4198        }
4199        Ok(())
4200    }
4201
4202    /// Handle the standard repetition directive
4203    pub fn visit_repeat<'token, T, E>(
4204        &mut self,
4205        count: &E,
4206        code: &mut [ProcessedToken<'token, T>],
4207        counter_name: Option<&str>,
4208        counter_start: Option<&E>,
4209        counter_step: Option<&E>,
4210        span: Option<&Z80Span>
4211    ) -> Result<(), AssemblerError>
4212    where
4213        E: ExprEvaluationExt,
4214        T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
4215        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4216        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4217            ExprEvaluationExt,
4218        ProcessedToken<'token, T>: FunctionBuilder
4219    {
4220        // get the number of loops
4221        let count = self.resolve_expr_must_never_fail(count)?.int()?;
4222
4223        // get the counter name of any
4224        let counter_name = counter_name
4225            .as_ref()
4226            .map(|counter| format!("{{{}}}", counter));
4227        let counter_name = counter_name.as_deref();
4228        if let Some(counter_name) = counter_name {
4229            if self.symbols().contains_symbol(counter_name)? {
4230                return Err(AssemblerError::RepeatIssue {
4231                    error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
4232                        AssemblerError::AssemblingError {
4233                            msg: format!("Counter {} already exists", counter_name)
4234                        }
4235                    )))
4236                    .into(),
4237                    span: span.cloned(),
4238                    repetition: 0
4239                });
4240            }
4241        }
4242
4243        // get the first value
4244        let mut counter_value = counter_start
4245            .map(|start| self.resolve_expr_must_never_fail(start))
4246            .unwrap_or(Ok(self.repeat_start.clone()))?; // TODO use the one setup by STARTINGINDEX
4247        let step_value = counter_step
4248            .map(|step| self.resolve_expr_must_never_fail(step))
4249            .unwrap_or(Ok(self.repeat_step.clone()))?; // TODO use the one steup by STARTINGINDEX
4250
4251        for i in 0..count {
4252            self.inner_visit_repeat(
4253                counter_name,
4254                Some(counter_value.clone()),
4255                i as _,
4256                code,
4257                span
4258            )?;
4259            // handle the counter update
4260            counter_value += step_value.clone();
4261        }
4262
4263        if let Some(counter_name) = counter_name {
4264            self.symbols_mut().remove_symbol(counter_name)?;
4265        }
4266        Ok(())
4267    }
4268
4269    /// Handle the code generation for all the repetition variants
4270    fn inner_visit_repeat<'token, T: ListingElement + Visited + MayHaveSpan + Sync>(
4271        &mut self,
4272        counter_name: Option<&str>,
4273        counter_value: Option<ExprResult>,
4274        iteration: i32,
4275        code: &mut [ProcessedToken<'token, T>],
4276        span: Option<&Z80Span>
4277    ) -> Result<(), AssemblerError>
4278    where
4279        <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4280        <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4281            ExprEvaluationExt,
4282        ProcessedToken<'token, T>: FunctionBuilder
4283    {
4284        // handle symbols unicity
4285        {
4286            self.macro_seed += 1;
4287            let seed = self.macro_seed;
4288            self.symbols_mut().push_seed(seed);
4289        }
4290
4291        // handle counter value update
4292        if let Some(counter_name) = counter_name {
4293            self.symbols_mut()
4294                .set_symbol_to_value(counter_name, counter_value.clone().unwrap())?;
4295
4296            if self.pass.is_listing_pass() {
4297                if let Some(trigger) = self.output_trigger.as_mut() {
4298                    trigger.repeat_iteration(counter_name, counter_value.as_ref())
4299                }
4300            }
4301        }
4302        else if self.pass.is_listing_pass() {
4303            if let Some(trigger) = self.output_trigger.as_mut() {
4304                trigger.repeat_iteration("<new iteration>", counter_value.as_ref())
4305            }
4306        }
4307
4308        if let Some(counter_value) = &counter_value {
4309            self.symbols_mut().push_counter_value(counter_value.clone());
4310        }
4311
4312        // generate the bytes
4313        visit_processed_tokens(code, self).map_err(|e| {
4314            let e = if let AssemblerError::RelocatedError {
4315                error: box AssemblerError::UnknownSymbol { closest: _, symbol },
4316                span
4317            } = &e
4318            {
4319                if let Some(counter_name) = counter_name {
4320                    if counter_name == &format!("{{{}}}", symbol) {
4321                        AssemblerError::RelocatedError {
4322                            error: Box::new(AssemblerError::UnknownSymbol {
4323                                closest: Some(counter_name.into()),
4324                                symbol: symbol.clone()
4325                            }),
4326                            span: span.clone()
4327                        }
4328                    }
4329                    else {
4330                        e
4331                    }
4332                }
4333                else {
4334                    e
4335                }
4336            }
4337            else {
4338                e
4339            };
4340
4341            AssemblerError::RepeatIssue {
4342                error: Box::new(e),
4343                span: span.cloned(),
4344                repetition: iteration as _
4345            }
4346        })?;
4347
4348        // handle the end of visibility of unique labels
4349        self.symbols_mut().pop_seed();
4350        if let Some(counter_value) = &counter_value {
4351            self.symbols_mut().pop_counter_value();
4352        }
4353
4354        Ok(())
4355    }
4356
4357    /// Generate a string that is helpfull for assertion understanding (i.e. show the operation and evaluate the rest)
4358    /// Crash if expression cannot be computed
4359    fn to_assert_string<E: ExprEvaluationExt + ExprElement>(&mut self, exp: &E) -> String {
4360        let mut format = |oper, left, right| {
4361            format!(
4362                "0x{:x} {} 0x{:x}",
4363                self.resolve_expr_must_never_fail(left).unwrap(),
4364                oper,
4365                self.resolve_expr_must_never_fail(right).unwrap(),
4366            )
4367        };
4368
4369        if exp.is_binary_operation() {
4370            let code = match exp.binary_operation() {
4371                BinaryOperation::Equal => Some("=="),
4372                BinaryOperation::GreaterOrEqual => Some(">="),
4373                BinaryOperation::StrictlyGreater => Some(">"),
4374                BinaryOperation::StrictlyLower => Some("<"),
4375                BinaryOperation::LowerOrEqual => Some("<="),
4376                _ => None
4377            };
4378
4379            match code {
4380                Some(code) => {
4381                    let left = exp.arg1();
4382                    let right = exp.arg2();
4383                    format(code, left, right)
4384                },
4385
4386                None => {
4387                    let d = self.resolve_expr_must_never_fail(exp).unwrap();
4388                    format!("0x{:x}", d)
4389                }
4390            }
4391        }
4392        else {
4393            let d = self.resolve_expr_must_never_fail(exp).unwrap();
4394            format!("0x{:x}", d)
4395        }
4396    }
4397
4398    fn visit_run<E: ExprEvaluationExt>(
4399        &mut self,
4400        address: &E,
4401        ga: Option<&E>
4402    ) -> Result<(), AssemblerError> {
4403        let address = self.resolve_expr_may_fail_in_first_pass(address)?.int()?;
4404
4405        if let Some(o) = self.output_trigger.as_mut() {
4406            o.replace_code_address(&address.into())
4407        }
4408
4409        if self.run_options.is_some() {
4410            return Err(AssemblerError::RunAlreadySpecified);
4411        }
4412        self.sna
4413            .set_value(cpclib_sna::SnapshotFlag::Z80_PC, address as _)?;
4414
4415        match ga {
4416            None => {
4417                self.run_options = Some((address as _, None));
4418            },
4419            Some(ga_expr) => {
4420                let ga_expr = self.resolve_expr_may_fail_in_first_pass(ga_expr)?.int()?;
4421                self.sna.set_value(SnapshotFlag::GA_RAMCFG, address as _)?;
4422                self.run_options = Some((address as _, Some(ga_expr as _)));
4423            }
4424        }
4425        Ok(())
4426    }
4427}
4428
4429/// Macro related code
4430impl Env {
4431    pub fn inc_macro_seed(&mut self) {
4432        self.macro_seed += 1;
4433    }
4434
4435    pub fn macro_seed(&self) -> usize {
4436        self.macro_seed
4437    }
4438}
4439
4440/// Warnings related code
4441impl Env {
4442    fn merge_overriding_warnings(&mut self) {
4443        // Filter the warnings to merge overriding
4444        let mut current_warning_idx = 1; // index to the last warning to treat
4445        let mut previous_warning_idx = 0; // index to the previous warning treated (diff with current_warning_idx can be higher than 1 when there are several consecutive warnings for OverrideMemory)
4446
4447        while current_warning_idx < self.warnings.len() {
4448            // Check if we need to fuse successive override memory warnings
4449            let (new_size, new_span) = match (
4450                &self.warnings[previous_warning_idx],
4451                &self.warnings[current_warning_idx]
4452            ) {
4453                // we fuse two consecutive override memory warnings
4454                (
4455                    AssemblerWarning::OverrideMemory(prev_addr, prev_size),
4456                    AssemblerWarning::OverrideMemory(curr_addr, curr_size)
4457                ) => {
4458                    if (prev_addr.offset_in_cpc() + *prev_size as u32) == curr_addr.offset_in_cpc()
4459                    {
4460                        (Some(*prev_size + *curr_size), None)
4461                    }
4462                    else {
4463                        (None, None)
4464                    }
4465                },
4466
4467                (
4468                    AssemblerError::RelocatedWarning {
4469                        warning: box AssemblerWarning::OverrideMemory(prev_addr, prev_size),
4470                        span: prev_span
4471                    },
4472                    AssemblerError::RelocatedWarning {
4473                        warning: box AssemblerWarning::OverrideMemory(curr_addr, curr_size),
4474                        span: curr_span
4475                    }
4476                ) => {
4477                    if (prev_addr.offset_in_cpc() + *prev_size as u32 == curr_addr.offset_in_cpc())
4478                        && std::ptr::eq(
4479                            prev_span.complete_source().as_ptr(),
4480                            curr_span.complete_source().as_ptr()
4481                        )
4482                    {
4483                        let new_size = *prev_size + *curr_size;
4484
4485                        let start_str = prev_span.as_str();
4486                        let end_str = curr_span.as_str();
4487                        let start_str = start_str.as_bytes();
4488                        let end_str = end_str.as_bytes();
4489
4490                        let start_ptr = &start_str[0] as *const u8;
4491                        let end_last_ptr = &end_str[end_str.len() - 1] as *const u8;
4492                        assert!(end_last_ptr > start_ptr);
4493                        let txt = unsafe {
4494                            let slice = std::slice::from_raw_parts(
4495                                start_ptr,
4496                                end_last_ptr.offset_from(start_ptr) as _
4497                            );
4498                            std::str::from_utf8(slice).unwrap()
4499                        };
4500
4501                        let new_span = Z80Span::from(prev_span.0.update_slice(txt.as_bytes()));
4502
4503                        (Some(new_size), Some(new_span))
4504                    }
4505                    else {
4506                        (None, None)
4507                    }
4508                },
4509
4510                _ => {
4511                    // nothing to do ATM
4512                    (None, None)
4513                }
4514            };
4515
4516            if let Some(new_size) = new_size {
4517                if let Some(new_span) = new_span {
4518                    if let AssemblerError::RelocatedWarning {
4519                        warning: box AssemblerWarning::OverrideMemory(_prev_addr, prev_size),
4520                        span
4521                    } = &mut self.warnings[previous_warning_idx]
4522                    {
4523                        *prev_size = new_size;
4524                        *span = new_span;
4525                    }
4526                }
4527                else if let AssemblerWarning::OverrideMemory(_prev_addr, prev_size) =
4528                    &mut self.warnings[previous_warning_idx]
4529                {
4530                    *prev_size = new_size;
4531                }
4532            }
4533            else {
4534                previous_warning_idx += 1;
4535                if previous_warning_idx != current_warning_idx {
4536                    self.warnings
4537                        .swap(previous_warning_idx, current_warning_idx);
4538                }
4539            }
4540
4541            current_warning_idx += 1;
4542        }
4543        // change the length  of the vector to remove all eated ones
4544        self.warnings.truncate(previous_warning_idx + 1);
4545    }
4546
4547    fn render_warnings(&mut self) {
4548        // transform the warnings as strings
4549        self.warnings.iter_mut().for_each(|w| {
4550            if let AssemblerError::AssemblingError { .. } = w {
4551                // nothing to do
4552            }
4553            else {
4554                *w = AssemblerWarning::AssemblingError {
4555                    msg: (*w).to_string()
4556                }
4557            }
4558        });
4559    }
4560
4561    pub fn cleanup_warnings(&mut self) {
4562        if !self.options().assemble_options().enable_warnings {
4563            debug_assert!(self.warnings.is_empty());
4564            return;
4565        }
4566
4567        self.merge_overriding_warnings();
4568        self.render_warnings();
4569    }
4570}
4571
4572impl Env {
4573    fn visit_equ<E: ExprEvaluationExt + ExprElement + Debug, S: SourceString + MayHaveSpan>(
4574        &mut self,
4575        label_span: &S,
4576        exp: &E
4577    ) -> Result<(), AssemblerError> {
4578        if self.symbols().contains_symbol(label_span.as_str())? && self.pass.is_first_pass() {
4579            Err(AssemblerError::AlreadyDefinedSymbol {
4580                symbol: label_span.as_str().into(),
4581                kind: self.symbols().kind(label_span.as_str())?.into(),
4582                here: label_span.possible_span().map(|s| s.into())
4583            })
4584        }
4585        else {
4586            let label = self.handle_global_and_local_labels(label_span.as_str())?;
4587
4588            if label.starts_with(".") {
4589                let warning = AssemblerError::AssemblingError {
4590                    msg: format!(
4591                        "{} is not a local label. A better name without the dot would be better",
4592                        &label
4593                    )
4594                };
4595                let warning = AssemblerWarning::AssemblingError {
4596                    msg: warning.to_string()
4597                };
4598                self.add_warning(warning);
4599            }
4600
4601            // XXX Disabled behavior the 12/01/2024
4602            // if !label.starts_with('.') {
4603            // self.symbols_mut().set_current_label(label)?;
4604            // }
4605            let value = self.resolve_expr_may_fail_in_first_pass(exp)?;
4606            if let Some(o) = self.output_trigger.as_mut() {
4607                o.replace_code_address(&value)
4608            }
4609            self.add_symbol_to_symbol_table(
4610                label,
4611                value,
4612                label_span.possible_span().map(|s| s.into())
4613            )
4614        }
4615    }
4616
4617    fn visit_field<
4618        E: ExprEvaluationExt + ExprElement + Debug + MayHaveSpan,
4619        S: SourceString + MayHaveSpan
4620    >(
4621        &mut self,
4622        label_span: S,
4623        exp: &E
4624    ) -> Result<(), AssemblerError> {
4625        if self.symbols().contains_symbol(label_span.as_str())? && self.pass.is_first_pass() {
4626            Err(AssemblerError::AlreadyDefinedSymbol {
4627                symbol: label_span.as_str().into(),
4628                kind: self.symbols().kind(label_span.as_str())?.into(),
4629                here: None
4630            })
4631        }
4632        else {
4633            let delta = self.resolve_expr_may_fail_in_first_pass(exp)?.int()?;
4634            if delta < 0 {
4635                let mut e = AssemblerError::AlreadyRenderedError(format!(
4636                    "FIELD argument must be positive ({delta} is a wrong value)."
4637                ));
4638                if let Some(span) = exp.possible_span() {
4639                    e = e.locate(span.clone());
4640                }
4641                return Err(e);
4642            }
4643
4644            let label = self.handle_global_and_local_labels(label_span.as_str())?;
4645            if !label.starts_with('.') {
4646                self.symbols_mut().set_current_label(label)?;
4647            }
4648
4649            let value: ExprResult = self.map_counter.into();
4650            if let Some(o) = self.output_trigger.as_mut() {
4651                o.replace_code_address(&value)
4652            }
4653            self.add_symbol_to_symbol_table(
4654                label,
4655                value,
4656                label_span.possible_span().map(|l| l.into())
4657            )?;
4658
4659            self.map_counter = self.map_counter.wrapping_add(delta);
4660
4661            Ok(())
4662        }
4663    }
4664
4665    fn visit_assign<'e, E: ExprEvaluationExt + ExprElement + Clone, S: AsRef<str>>(
4666        &mut self,
4667        label: S,
4668        exp: &E,
4669        op: Option<&BinaryOperation>
4670    ) -> Result<(), AssemblerError> {
4671        let label = label.as_ref();
4672        let value = if let Some(op) = op {
4673            let new_exp = Expr::BinaryOperation(
4674                *op,
4675                Box::new(Expr::Label(label.into())),
4676                Box::new(exp.to_expr().into_owned())
4677            );
4678            self.resolve_expr_must_never_fail(&new_exp)?
4679        }
4680        else {
4681            self.resolve_expr_may_fail_in_first_pass(exp)?
4682        };
4683
4684        if let Some(o) = self.output_trigger.as_mut() {
4685            o.replace_code_address(&value)
4686        }
4687
4688        let label = self.handle_global_and_local_labels(label)?;
4689        // XXX Disabled behavior the 12/01/2024
4690        // if !label.starts_with('.') {
4691        // self.symbols_mut().set_current_label(label)?;
4692        // }
4693        self.symbols_mut().assign_symbol_to_value(label, value)?;
4694        Ok(())
4695    }
4696}
4697
4698fn visit_defs<E: ExprEvaluationExt>(
4699    l: &[(E, Option<E>)],
4700    env: &mut Env
4701) -> Result<(), AssemblerError> {
4702    for (e, f) in l.iter() {
4703        let bytes = assemble_defs_item(e, f.as_ref(), env)?;
4704        env.output_bytes(&bytes)?;
4705    }
4706    Ok(())
4707}
4708
4709fn visit_end(_env: &mut Env) -> Result<(), AssemblerError> {
4710    eprintln!("END directive is not implemented");
4711    Ok(())
4712}
4713
4714pub enum DbLikeKind {
4715    Defb,
4716    Defw,
4717    Str
4718}
4719
4720impl From<&Token> for DbLikeKind {
4721    fn from(token: &Token) -> Self {
4722        match token {
4723            Token::Defb(..) => Self::Defb,
4724            Token::Defw(..) => Self::Defw,
4725            Token::Str(..) => Self::Str,
4726            _ => unreachable!()
4727        }
4728    }
4729}
4730
4731impl DbLikeKind {
4732    fn mask(&self) -> u16 {
4733        match self {
4734            DbLikeKind::Defb => 0xFF,
4735            DbLikeKind::Defw => 0xFFFF,
4736            DbLikeKind::Str => 0xFF
4737        }
4738    }
4739}
4740
4741impl Env {
4742    pub fn visit_abyte<
4743        E1: ExprEvaluationExt + ExprElement + Debug,
4744        E2: ExprEvaluationExt + ExprElement + Debug
4745    >(
4746        &mut self,
4747        delta: &E1,
4748        exprs: &[E2]
4749    ) -> Result<(), AssemblerError> {
4750        let delta = self.resolve_expr_may_fail_in_first_pass(delta)?;
4751        self.visit_db_or_dw_or_str(DbLikeKind::Defb, exprs, delta)
4752    }
4753
4754    // TODO refactor code with assemble_opcode or other functions manipulating bytes
4755    pub fn visit_db_or_dw_or_str<E: ExprEvaluationExt + ExprElement + Debug>(
4756        &mut self,
4757        kind: DbLikeKind,
4758        exprs: &[E],
4759        delta: ExprResult
4760    ) -> Result<(), AssemblerError> {
4761        let env = self;
4762
4763        let delta = delta.int()?;
4764
4765        let mask = kind.mask();
4766
4767        let output = |env: &mut Env, val: i32, mask: u16| -> Result<(), AssemblerError> {
4768            let val = val + delta;
4769
4770            if mask == 0xFF {
4771                env.output_byte(val as u8)?;
4772            }
4773            else {
4774                let high = ((val & 0xFF00) >> 8) as u8;
4775                let low = (val & 0xFF) as u8;
4776                env.output_byte(low)?;
4777                env.output_byte(high)?;
4778            }
4779            Ok(())
4780        };
4781
4782        let output_expr_result = |env: &mut Env, expr: ExprResult, mask: u16| {
4783            match &expr {
4784                ExprResult::Float(_) | ExprResult::Value(_) | ExprResult::Bool(_) => {
4785                    output(env, expr.int()?, mask)
4786                },
4787                ExprResult::Char(c) => {
4788                    // XXX here it is problematci c shold be a char and not a byte
4789                    let c = env.charset_encoding.transform_char(*c as char);
4790                    output(env, expr.int()?, mask)
4791                },
4792                ExprResult::String(s) => {
4793                    let bytes = env.charset_encoding.transform_string(s);
4794
4795                    for c in bytes {
4796                        output(env, c as _, mask)?;
4797                    }
4798                    Ok(())
4799                },
4800                ExprResult::List(l) => {
4801                    for c in l {
4802                        output(env, c.int()?, mask)?;
4803                    }
4804                    Ok(())
4805                },
4806                ExprResult::Matrix { .. } => {
4807                    for row in expr.matrix_rows() {
4808                        for c in row.list_content() {
4809                            output(env, c.int()?, mask)?;
4810                        }
4811                    }
4812                    Ok(())
4813                }
4814            }
4815        };
4816
4817        let backup_address = env.logical_output_address();
4818        for exp in exprs.iter() {
4819            if exp.is_string() {
4820                let s = exp.string();
4821                let bytes = env.charset_encoding.transform_string(s);
4822                for b in &bytes {
4823                    output(env, *b as _, mask)?
4824                }
4825                env.update_dollar();
4826            }
4827            else if exp.is_char() {
4828                let c = exp.char();
4829                let b = env.charset_encoding.transform_char(c);
4830                output(env, b as _, mask)?;
4831                env.update_dollar();
4832            }
4833            else {
4834                let val = env.resolve_expr_may_fail_in_first_pass(exp)?;
4835                output_expr_result(env, val, mask)?;
4836                env.update_dollar();
4837            }
4838        }
4839
4840        // Patch the last char of a str
4841        if matches!(kind, DbLikeKind::Str) && backup_address < env.logical_output_address() {
4842            let last_address = env.logical_output_address() - 1;
4843            let last_address = env.logical_to_physical_address(last_address as _);
4844            let last_value = env.peek(&last_address);
4845            env.poke(last_value | 0x80, &last_address);
4846        }
4847
4848        Ok(())
4849    }
4850}
4851
4852impl Env {
4853    // TODO find a more efficient way; there a tons of copies there...
4854    fn move_delayed_commands_of_functions(&mut self) {
4855        {
4856            let prints = self.extra_print_from_function.read().unwrap().clone();
4857            for print in prints.into_iter() {
4858                self.active_page_info_mut()
4859                    .add_print_or_pause_command(print);
4860            }
4861            self.extra_print_from_function.write().unwrap().clear();
4862        }
4863
4864        {
4865            let asserts = self
4866                .extra_failed_assert_from_function
4867                .read()
4868                .unwrap()
4869                .clone();
4870            for assert in asserts.into_iter() {
4871                self.active_page_info_mut()
4872                    .add_failed_assert_command(assert);
4873            }
4874            self.extra_failed_assert_from_function
4875                .write()
4876                .unwrap()
4877                .clear();
4878        }
4879    }
4880}
4881
4882#[allow(missing_docs)]
4883impl Env {
4884    pub fn visit_basic<S: SourceString, S2: SourceString, E: ExprEvaluationExt>(
4885        &mut self,
4886        variables: Option<Vec<S>>,
4887        hidden_lines: Option<&Vec<E>>,
4888        code: S2
4889    ) -> Result<(), AssemblerError> {
4890        let bytes = self.assemble_basic(variables, hidden_lines, code)?;
4891
4892        // If the basic directive is the VERY first thing to output,
4893        // we assume startadr is 0x170 as for any basic program
4894        if self.start_address().is_none() {
4895            self.active_page_info_mut().logical_outputadr = 0x170;
4896            self.active_page_info_mut().logical_codeadr = self.logical_output_address();
4897            self.active_page_info_mut().startadr = Some(self.logical_output_address());
4898            self.output_address = 0x170;
4899        }
4900
4901        self.output_bytes(&bytes)
4902    }
4903
4904    pub fn assemble_basic<S: SourceString, S2: SourceString, E: ExprEvaluationExt>(
4905        &mut self,
4906        variables: Option<Vec<S>>,
4907        hidden_lines: Option<&Vec<E>>,
4908        code: S2
4909    ) -> Result<Vec<u8>, AssemblerError> {
4910        let hidden_lines = hidden_lines.map(|h| {
4911            h.iter()
4912                .map(|e| self.resolve_expr_must_never_fail(e))
4913                .collect::<Result<Vec<_>, AssemblerError>>()
4914        });
4915        if let Some(Err(e)) = hidden_lines {
4916            return Err(e);
4917        }
4918
4919        let hidden_lines = hidden_lines.map(|r| {
4920            r.unwrap()
4921                .into_iter()
4922                .map(|e| e.int())
4923                .collect::<Result<Vec<_>, ExpressionTypeError>>()
4924        });
4925        if let Some(Err(e)) = hidden_lines {
4926            return Err(e.into());
4927        }
4928
4929        let hidden_lines =
4930            hidden_lines.map(|r| r.unwrap().into_iter().map(|e| e as u16).collect_vec());
4931
4932        // Build the final basic code by replacing variables by value
4933        // Hexadecimal is used to ensure a consistent 2 bytes representation
4934        let basic_src = {
4935            let mut basic = code.as_str().to_owned();
4936            match variables {
4937                None => {},
4938                Some(arguments) => {
4939                    for argument in arguments {
4940                        let key = format!("{{{}}}", argument.as_str());
4941                        let value = format!(
4942                            "&{:X}",
4943                            self.resolve_expr_may_fail_in_first_pass(&Expr::from(
4944                                argument.as_str()
4945                            ))?
4946                        );
4947                        basic = basic.replace(&key, &value);
4948                    }
4949                },
4950            }
4951            basic
4952        };
4953
4954        // build the basic tokens
4955        let mut basic = BasicProgram::parse(basic_src)?;
4956        if let Some(hidden_lines) = hidden_lines {
4957            basic.hide_lines(&hidden_lines)?;
4958        }
4959        Ok(basic.as_bytes())
4960    }
4961}
4962
4963/// When visiting a repetition, we unroll the loop and stream the tokens
4964/// TODO reimplement it in a similar way that the LocatedToken version that is better
4965pub fn visit_repeat(rept: &Token, env: &mut Env) -> Result<(), AssemblerError> {
4966    let tokens = rept.unroll(env).unwrap()?;
4967
4968    for token in &tokens {
4969        visit_token(token, env)?;
4970    }
4971
4972    Ok(())
4973}
4974
4975/// Manage the stable ticker stuff.
4976/// - Start: register a counter
4977/// - Stop: store counter count
4978#[allow(clippy::cast_possible_wrap)]
4979pub fn visit_stableticker<S: AsRef<str>>(
4980    ticker: &StableTickerAction<S>,
4981    env: &mut Env
4982) -> Result<(), AssemblerError> {
4983    match ticker {
4984        StableTickerAction::Start(name) => {
4985            env.stable_counters.add_counter(name)?;
4986            Ok(())
4987        },
4988        StableTickerAction::Stop(stop) => {
4989            if let Some((label, count)) = stop
4990                .as_ref()
4991                .map(|stop| env.stable_counters.release_counter(stop.as_ref()))
4992                .unwrap_or_else(|| env.stable_counters.release_last_counter())
4993            {
4994                if !env.pass.is_listing_pass() && env.symbols().contains_symbol(&label)? {
4995                    env.add_warning(AssemblerWarning::AlreadyRenderedError(format!(
4996                        "Symbol {label} has been overwritten"
4997                    )));
4998                }
4999
5000                // force the injection of the value
5001                env.symbols_mut()
5002                    .set_symbol_to_value(label, Value::from(count))?;
5003                Ok(())
5004            }
5005            else {
5006                Err(AssemblerError::NoActiveCounter)
5007            }
5008        }
5009    }
5010}
5011
5012/// Assemble DEFS directive
5013pub fn assemble_defs_item<E: ExprEvaluationExt>(
5014    expr: &E,
5015    fill: Option<&E>,
5016    env: &mut Env
5017) -> Result<Bytes, AssemblerError> {
5018    let count = match env.resolve_expr_must_never_fail(expr) {
5019        Ok(amount) => amount.int()?,
5020        Err(e) => {
5021            env.add_error_discardable_one_pass(e)?;
5022            *env.request_additional_pass.write().unwrap() = true; // we expect to obtain this value later
5023            0
5024        }
5025    };
5026
5027    if count < 0 {
5028        return Err(AssemblerError::AssemblingError {
5029            msg: format!("{count} is an invalid value")
5030        });
5031    }
5032
5033    let value = if fill.is_none() {
5034        0
5035    }
5036    else {
5037        let value = env
5038            .resolve_expr_may_fail_in_first_pass(fill.unwrap())?
5039            .int()?;
5040        (value & 0xFF) as u8
5041    };
5042
5043    let mut bytes = Bytes::with_capacity(count as usize);
5044    bytes.resize_with(count as _, || value);
5045
5046    Ok(bytes)
5047}
5048
5049/// Assemble align directive. It can only work if current address is known...
5050pub fn assemble_align(
5051    expr: &Expr,
5052    fill: Option<&Expr>,
5053    env: &mut Env
5054) -> Result<Bytes, AssemblerError> {
5055    let expression = env.resolve_expr_must_never_fail(expr)?.int()? as u16;
5056    let current = env.symbols().current_address()?;
5057    let value = if fill.is_none() {
5058        0
5059    }
5060    else {
5061        let value = env
5062            .resolve_expr_may_fail_in_first_pass(fill.unwrap())?
5063            .int()?;
5064        (value & 0xFF) as u8
5065    };
5066
5067    // compute the number of 0 to put
5068    let mut until = current;
5069    while until % expression != 0 {
5070        until += 1;
5071    }
5072
5073    // Create the vector
5074    let hole = (until - current) as usize;
5075    let mut bytes = Bytes::with_capacity(hole);
5076    for _i in 0..hole {
5077        bytes.push(value);
5078    }
5079
5080    // and return it
5081    Ok(bytes)
5082}
5083
5084/// Assemble the opcode and inject in the environement
5085pub(crate) fn visit_opcode<D: DataAccessElem>(
5086    mnemonic: Mnemonic,
5087    arg1: &Option<D>,
5088    arg2: &Option<D>,
5089    arg3: &Option<Register8>,
5090    env: &mut Env
5091) -> Result<(), AssemblerError>
5092where
5093    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5094{
5095    // TODO update $ in the symbol table
5096    let bytes = assemble_opcode(mnemonic, arg1, arg2, arg3, env)?;
5097    for b in bytes.iter() {
5098        env.output_byte(*b)?;
5099    }
5100
5101    Ok(())
5102}
5103
5104/// Assemble an opcode and returns the generated bytes or the error message if it is impossible to
5105/// assemblea.
5106/// We assume the opcode is properlt coded. Panic occurs if it is not the case
5107pub fn assemble_opcode<D: DataAccessElem>(
5108    mnemonic: Mnemonic,
5109    arg1: &Option<D>,
5110    arg2: &Option<D>,
5111    arg3: &Option<Register8>,
5112    env: &mut Env
5113) -> Result<Bytes, AssemblerError>
5114where
5115    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5116{
5117    match mnemonic {
5118        Mnemonic::And | Mnemonic::Or | Mnemonic::Xor => {
5119            assemble_logical_operator(mnemonic, arg1.as_ref().unwrap(), env)
5120        },
5121        Mnemonic::Add | Mnemonic::Adc => {
5122            assemble_add_or_adc(mnemonic, arg1.as_ref(), arg2.as_ref().unwrap(), env)
5123        },
5124        Mnemonic::Cp => env.assemble_cp(arg1.as_ref().unwrap()),
5125        Mnemonic::ExMemSp => assemble_ex_memsp(arg1.as_ref().unwrap()),
5126        Mnemonic::Dec | Mnemonic::Inc => assemble_inc_dec(mnemonic, arg1.as_ref().unwrap(), env),
5127        Mnemonic::Djnz => assemble_djnz(arg1.as_ref().unwrap(), env),
5128        Mnemonic::In => assemble_in(arg1.as_ref().unwrap(), arg2.as_ref().unwrap(), env),
5129        Mnemonic::Ld => assemble_ld(arg1.as_ref().unwrap(), arg2.as_ref().unwrap(), env),
5130        Mnemonic::Ldi
5131        | Mnemonic::Ldd
5132        | Mnemonic::Ldir
5133        | Mnemonic::Lddr
5134        | Mnemonic::Outi
5135        | Mnemonic::Outd
5136        | Mnemonic::Ei
5137        | Mnemonic::Di
5138        | Mnemonic::ExAf
5139        | Mnemonic::ExHlDe
5140        | Mnemonic::Exx
5141        | Mnemonic::Halt
5142        | Mnemonic::Ind
5143        | Mnemonic::Indr
5144        | Mnemonic::Ini
5145        | Mnemonic::Inir
5146        | Mnemonic::Rla
5147        | Mnemonic::Rlca
5148        | Mnemonic::Rrca
5149        | Mnemonic::Rra
5150        | Mnemonic::Reti
5151        | Mnemonic::Retn
5152        | Mnemonic::Scf
5153        | Mnemonic::Ccf
5154        | Mnemonic::Cpd
5155        | Mnemonic::Cpdr
5156        | Mnemonic::Cpi
5157        | Mnemonic::Cpir
5158        | Mnemonic::Cpl
5159        | Mnemonic::Daa
5160        | Mnemonic::Neg
5161        | Mnemonic::Otdr
5162        | Mnemonic::Otir
5163        | Mnemonic::Rld
5164        | Mnemonic::Rrd => assemble_no_arg(mnemonic),
5165        Mnemonic::Out => assemble_out(arg1.as_ref().unwrap(), arg2.as_ref().unwrap(), env),
5166        Mnemonic::Jr | Mnemonic::Jp | Mnemonic::Call => {
5167            assemble_call_jr_or_jp(mnemonic, arg1.as_ref(), arg2.as_ref().unwrap(), env)
5168        },
5169        Mnemonic::Pop => assemble_pop(arg1.as_ref().unwrap()),
5170        Mnemonic::Push => assemble_push(arg1.as_ref().unwrap()),
5171        Mnemonic::Bit | Mnemonic::Res | Mnemonic::Set => {
5172            assemble_bit_res_or_set(
5173                mnemonic,
5174                arg1.as_ref().unwrap(),
5175                arg2.as_ref().unwrap(),
5176                arg3.as_ref(),
5177                env
5178            )
5179        },
5180        Mnemonic::Ret => assemble_ret(arg1.as_ref()),
5181        Mnemonic::Rst => {
5182            if let Some(arg2) = arg2.as_ref() {
5183                assemble_rst_fake(arg1.as_ref().unwrap(), arg2, env)
5184            }
5185            else {
5186                // normal RST
5187                assemble_rst(arg1.as_ref().unwrap(), env)
5188            }
5189        },
5190        Mnemonic::Im => assemble_im(arg1.as_ref().unwrap(), env),
5191        Mnemonic::Nop => {
5192            env.assemble_nop(
5193                Mnemonic::Nop,
5194                arg1.as_ref().map(|v| v.get_expression().unwrap())
5195            )
5196        },
5197        Mnemonic::Nop2 => env.assemble_nop::<Expr>(Mnemonic::Nop2, None),
5198
5199        Mnemonic::Sub => env.assemble_sub(arg1.as_ref().unwrap()),
5200        Mnemonic::Sbc => env.assemble_sbc(arg1.as_ref(), arg2.as_ref().unwrap()),
5201        Mnemonic::Sla
5202        | Mnemonic::Sra
5203        | Mnemonic::Srl
5204        | Mnemonic::Sl1
5205        | Mnemonic::Rl
5206        | Mnemonic::Rr
5207        | Mnemonic::Rlc
5208        | Mnemonic::Rrc => env.assemble_shift(mnemonic, arg1.as_ref().unwrap(), arg2.as_ref())
5209    }
5210}
5211
5212fn assemble_no_arg(mnemonic: Mnemonic) -> Result<Bytes, AssemblerError> {
5213    let bytes: &[u8] = match mnemonic {
5214        Mnemonic::Ldi => &[0xED, 0xA0],
5215        Mnemonic::Ldd => &[0xED, 0xA8],
5216        Mnemonic::Lddr => &[0xED, 0xB8],
5217        Mnemonic::Ldir => &[0xED, 0xB0],
5218        Mnemonic::Di => &[0xF3],
5219        Mnemonic::ExAf => &[0x08],
5220        Mnemonic::ExHlDe => &[0xEB],
5221        Mnemonic::Exx => &[0xD9],
5222        Mnemonic::Ei => &[0xFB],
5223        Mnemonic::Halt => &[0x76],
5224        Mnemonic::Ind => &[0xED, 0xAA],
5225        Mnemonic::Indr => &[0xED, 0xBA],
5226        Mnemonic::Ini => &[0xED, 0xA2],
5227        Mnemonic::Inir => &[0xED, 0xB2],
5228        Mnemonic::Outd => &[0xED, 0xAB],
5229        Mnemonic::Outi => &[0xED, 0xA3],
5230        Mnemonic::Rla => &[0x17],
5231        Mnemonic::Rlca => &[0x07],
5232        Mnemonic::Rrca => &[0x0F],
5233        Mnemonic::Rra => &[0x1F],
5234        Mnemonic::Reti => &[0xED, 0x4D],
5235        Mnemonic::Retn => &[0xED, 0x45],
5236        Mnemonic::Scf => &[0x37],
5237        Mnemonic::Ccf => &[0x3F],
5238        // added
5239        Mnemonic::Cpd => &[0xED, 0xA9],
5240        Mnemonic::Cpdr => &[0xED, 0xB9],
5241        Mnemonic::Cpi => &[0xED, 0xA1],
5242        Mnemonic::Cpir => &[0xED, 0xB1],
5243        Mnemonic::Cpl => &[0x2F],
5244        Mnemonic::Daa => &[0x27],
5245        Mnemonic::Neg => &[0xED, 0x44],
5246        Mnemonic::Otdr => &[0xED, 0xBB],
5247        Mnemonic::Otir => &[0xED, 0xB3],
5248        Mnemonic::Rld => &[0xED, 0x6F],
5249        Mnemonic::Rrd => &[0xED, 0x67],
5250        _ => {
5251            return Err(AssemblerError::BugInAssembler {
5252                file: file!(),
5253                line: line!(),
5254                msg: format!("{} not treated", mnemonic)
5255            });
5256        }
5257    };
5258
5259    Ok(Bytes::from_slice(bytes))
5260}
5261
5262fn assemble_inc_dec<D: DataAccessElem>(
5263    mne: Mnemonic,
5264    arg1: &D,
5265    env: &mut Env
5266) -> Result<Bytes, AssemblerError>
5267where
5268    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5269{
5270    let mut bytes = Bytes::new();
5271
5272    let is_inc = match mne {
5273        Mnemonic::Inc => true,
5274        Mnemonic::Dec => false,
5275        _ => panic!("Impossible case")
5276    };
5277
5278    if arg1.is_register16() {
5279        let reg = arg1.get_register16().unwrap();
5280        {
5281            let base = if is_inc { 0b0000_0011 } else { 0b0000_1011 };
5282            let byte = base | (register16_to_code_with_sp(reg) << 4);
5283            bytes.push(byte);
5284        }
5285    }
5286    else if arg1.is_indexregister16() {
5287        let reg = arg1.get_indexregister16().unwrap();
5288        {
5289            bytes.push(indexed_register16_to_code(reg));
5290            bytes.push(if is_inc { 0x23 } else { 0x2B });
5291        }
5292    }
5293    else if arg1.is_register8() {
5294        let reg = arg1.get_register8().unwrap();
5295        {
5296            bytes.push(
5297                if is_inc { 0b0000_0100 } else { 0b0000_0101 } | (register8_to_code(reg) << 3)
5298            );
5299        }
5300    }
5301    else if arg1.is_indexregister8() {
5302        let reg = arg1.get_indexregister8().unwrap();
5303        {
5304            bytes.push(indexed_register16_to_code(reg.complete()));
5305            bytes.push(
5306                if is_inc { 0b0000_0100 } else { 0b0000_0101 } | (indexregister8_to_code(reg) << 3)
5307            );
5308        }
5309    }
5310    else if arg1.is_address_in_register16() && arg1.get_register16().unwrap() == Register16::Hl {
5311        {
5312            bytes.push(if is_inc { 0x34 } else { 0x35 });
5313        }
5314    }
5315    else if arg1.is_indexregister_with_index() {
5316        let reg = arg1.get_indexregister16().unwrap();
5317        let idx = arg1.get_index().unwrap();
5318        {
5319            let res = env.resolve_index_may_fail_in_first_pass(idx)?;
5320            let val = (res.int()? & 0xFF) as u8;
5321
5322            bytes.push(indexed_register16_to_code(reg));
5323            bytes.push(if is_inc { 0x34 } else { 0x35 });
5324            bytes.push(val);
5325        }
5326    }
5327    else {
5328        return Err(AssemblerError::BugInAssembler {
5329            file: file!(),
5330            line: line!(),
5331            msg: format!(
5332                "{}: not implemented for {:?}",
5333                mne.to_string().to_owned(),
5334                arg1
5335            )
5336        });
5337    }
5338    Ok(bytes)
5339}
5340
5341/// Converts an absolute address to a relative one (relative to $)
5342pub fn absolute_to_relative<T: AsRef<SymbolsTable>>(
5343    address: i32,
5344    opcode_delta: i32,
5345    sym: T
5346) -> Result<u8, AssemblerError> {
5347    match sym.as_ref().current_address() {
5348        Err(_msg) => Err(AssemblerError::UnknownAssemblingAddress),
5349        Ok(root) => {
5350            let delta = (address - i32::from(root)) - opcode_delta;
5351            if !(-128..=127).contains(&delta) {
5352                Err(AssemblerError::InvalidArgument {
5353                    msg: format!(
5354                        "Address 0x{:x} relative to 0x{:x} is too far {}",
5355                        address, root, delta
5356                    )
5357                })
5358            }
5359            else {
5360                let res = (delta & 0xFF) as u8;
5361                Ok(res)
5362            }
5363        }
5364    }
5365}
5366
5367fn assemble_ret<D: DataAccessElem>(arg1: Option<&D>) -> Result<Bytes, AssemblerError> {
5368    let mut bytes = Bytes::new();
5369
5370    if let Some(arg1) = arg1 {
5371        if let Some(test) = arg1.get_flag_test() {
5372            let flag = flag_test_to_code(test);
5373            bytes.push(0b1100_0000 | (flag << 3));
5374        }
5375        else {
5376            return Err(AssemblerError::InvalidArgument {
5377                msg: "RET: wrong argument for ret".to_string()
5378            });
5379        }
5380    }
5381    else {
5382        bytes.push(0xC9);
5383    }
5384
5385    Ok(bytes)
5386}
5387
5388fn assemble_rst_fake<D: DataAccessElem>(
5389    arg1: &D,
5390    arg2: &D,
5391    env: &mut Env
5392) -> Result<Bytes, AssemblerError>
5393where
5394    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5395{
5396    let val = env
5397        .resolve_expr_may_fail_in_first_pass(arg2.get_expression().unwrap())?
5398        .int()?;
5399
5400    let _p = match val {
5401        0x38 | 7 | 38 => 0b111,
5402        _ => {
5403            return Err(AssemblerError::InvalidArgument {
5404                msg: format!(
5405                    "Conditionnal RST cannot take {} as argument. Expected values are 0x38|7|38.",
5406                    val
5407                )
5408            });
5409        }
5410    };
5411
5412    let flag = arg1.get_flag_test().unwrap();
5413    if flag != FlagTest::NZ && flag != FlagTest::Z && flag != FlagTest::NC && flag != FlagTest::C {
5414        return Err(AssemblerError::InvalidArgument {
5415            msg: format!(
5416                "Conditionnal RST cannot take {} as flag. Expected values are C|NC|Z|NZ.",
5417                flag
5418            )
5419        });
5420    }
5421
5422    assemble_opcode(
5423        Mnemonic::Jr,
5424        &Some(DataAccess::from(flag)),
5425        &Some(DataAccess::from(
5426            Expr::Label("$".into()).add(Expr::Value(1))
5427        )),
5428        &None,
5429        env
5430    )
5431}
5432
5433fn assemble_rst<D: DataAccessElem>(arg1: &D, env: &mut Env) -> Result<Bytes, AssemblerError>
5434where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5435    let mut bytes = Bytes::new();
5436    let val = env
5437        .resolve_expr_may_fail_in_first_pass(arg1.get_expression().unwrap())?
5438        .int()?;
5439
5440    let p = match val {
5441        0x00 => 0b000,
5442        0x08 | 1 => 0b001,
5443        0x10 | 2 | 10 => 0b010,
5444        0x18 | 3 | 18 => 0b011,
5445        0x20 | 4 | 20 => 0b100,
5446        0x28 | 5 | 28 => 0b101,
5447        0x30 | 6 | 30 => 0b110,
5448        0x38 | 7 | 38 => 0b111,
5449        _ => {
5450            return Err(AssemblerError::InvalidArgument {
5451                msg: format!(
5452                    "RST cannot take {} as argument. Expected values are 0x00, 0x08|1, 0x10|2|10, 0x18|3|18, 0x20|4|20, 0x28|5|28, 0x30|6|30, 0x38|7|38.",
5453                    val
5454                )
5455            });
5456        }
5457    };
5458
5459    bytes.push(0b11000111 | (p << 3));
5460    Ok(bytes)
5461}
5462
5463fn assemble_im<D: DataAccessElem>(arg1: &D, env: &mut Env) -> Result<Bytes, AssemblerError>
5464where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5465    let mut bytes = Bytes::new();
5466    let val = env
5467        .resolve_expr_may_fail_in_first_pass(arg1.get_expression().unwrap())?
5468        .int()?;
5469
5470    let code = match val {
5471        0x00 => 0x46,
5472        0x01 => 0x56,
5473        0x02 => 0x5E,
5474        _ => {
5475            return Err(AssemblerError::InvalidArgument {
5476                msg: format!("IM cannot take {} as argument.", val)
5477            });
5478        }
5479    };
5480
5481    bytes.push(0xED);
5482    bytes.push(code);
5483    Ok(bytes)
5484}
5485
5486/// arg1 contains the tests
5487/// arg2 contains the information
5488pub fn assemble_call_jr_or_jp<D: DataAccessElem>(
5489    mne: Mnemonic,
5490    arg1: Option<&D>,
5491    arg2: &D,
5492    env: &mut Env
5493) -> Result<Bytes, AssemblerError>
5494where
5495    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5496{
5497    let mut bytes = Bytes::new();
5498
5499    let is_jr = match mne {
5500        Mnemonic::Jr => true,
5501        Mnemonic::Jp | Mnemonic::Call => false,
5502        _ => unreachable!()
5503    };
5504
5505    let is_call = match mne {
5506        Mnemonic::Call => true,
5507        Mnemonic::Jp | Mnemonic::Jr => false,
5508        _ => unreachable!()
5509    };
5510
5511    let is_jp = !(is_call || is_jr);
5512
5513    // compute the flag code if any
5514    // TODO raise an error if the flag test for jr is wrong
5515    let flag_code = if let Some(arg1) = arg1 {
5516        match arg1.get_flag_test() {
5517            Some(test) => Some(flag_test_to_code(test)),
5518            _ => {
5519                return Err(AssemblerError::InvalidArgument {
5520                    msg: format!(
5521                        "{}: wrong flag argument",
5522                        mne.to_string().to_ascii_uppercase()
5523                    )
5524                });
5525            }
5526        }
5527    }
5528    else {
5529        None
5530    };
5531
5532    // Treat address
5533    if arg2.is_expression() {
5534        let e = arg2.get_expression().unwrap();
5535        let address = env.resolve_expr_may_fail_in_first_pass(e)?.int()?;
5536        if is_jr {
5537            let relative = if e.is_relative() {
5538                address as u8
5539            }
5540            else {
5541                env.absolute_to_relative_may_fail_in_first_pass(address, 2)?
5542            };
5543            if flag_code.is_some() {
5544                // jr - flag
5545                add_byte(&mut bytes, 0b0010_0000 | (flag_code.unwrap() << 3));
5546            }
5547            else {
5548                // jr - no flag
5549                add_byte(&mut bytes, 0b0001_1000);
5550            }
5551            add_byte(&mut bytes, relative);
5552        }
5553        else if is_call {
5554            match flag_code {
5555                Some(flag) => add_byte(&mut bytes, 0b1100_0100 | (flag << 3)),
5556                None => add_byte(&mut bytes, 0xCD)
5557            }
5558            add_word(&mut bytes, address as u16);
5559        }
5560        else {
5561            if flag_code.is_some() {
5562                // jp - flag
5563                add_byte(&mut bytes, 0b1100_0010 | (flag_code.unwrap() << 3))
5564            }
5565            else {
5566                // jp - no flag
5567                add_byte(&mut bytes, 0xC3);
5568            }
5569            add_word(&mut bytes, address as u16);
5570        }
5571    }
5572    else if arg2.is_address_in_register16() {
5573        assert_eq!(arg2.get_register16(), Some(Register16::Hl));
5574        assert!(is_jp);
5575        add_byte(&mut bytes, 0xE9);
5576    }
5577    else if arg2.is_address_in_indexregister16() {
5578        assert!(is_jp);
5579        let reg = arg2.get_indexregister16().unwrap();
5580        add_byte(&mut bytes, indexed_register16_to_code(reg));
5581        add_byte(&mut bytes, 0xE9);
5582    }
5583    else {
5584        return Err(AssemblerError::BugInAssembler {
5585            file: file!(),
5586            line: line!(),
5587            msg: format!("{}: parameter {:?} not treated", mne, arg2)
5588        });
5589    }
5590
5591    Ok(bytes)
5592}
5593
5594fn assemble_djnz<D: DataAccessElem>(arg1: &D, env: &mut Env) -> Result<Bytes, AssemblerError>
5595where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5596    if let Some(expr) = arg1.get_expression() {
5597        let mut bytes = Bytes::new();
5598        let address = env.resolve_expr_may_fail_in_first_pass(expr)?.int()?;
5599        let relative = if expr.is_relative() {
5600            address as u8
5601        }
5602        else {
5603            env.absolute_to_relative_may_fail_in_first_pass(address, 1 + 1)?
5604        };
5605        bytes.push(0x10);
5606        bytes.push(relative);
5607
5608        Ok(bytes)
5609    }
5610    else {
5611        unreachable!()
5612    }
5613}
5614
5615#[allow(missing_docs)]
5616impl Env {
5617    pub fn assemble_cp<D: DataAccessElem>(&mut self, arg: &D) -> Result<Bytes, AssemblerError>
5618    where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5619        let mut bytes = Bytes::new();
5620
5621        if arg.is_register8() {
5622            let reg = arg.get_register8().unwrap();
5623            {
5624                add_byte(&mut bytes, 0b1011_1000 + register8_to_code(reg));
5625            }
5626        }
5627        else if arg.is_indexregister8() {
5628            let reg = arg.get_indexregister8().unwrap();
5629            {
5630                add_byte(&mut bytes, indexed_register16_to_code(reg.complete()));
5631                add_byte(&mut bytes, 0b1011_1000 + indexregister8_to_code(reg));
5632            }
5633        }
5634        else if arg.is_expression() {
5635            let exp = arg.get_expression().unwrap();
5636            {
5637                add_byte(&mut bytes, 0xFE);
5638                add_byte(
5639                    &mut bytes,
5640                    self.resolve_expr_may_fail_in_first_pass(exp)?.int()? as _
5641                );
5642            }
5643        }
5644        else if arg.is_address_in_register16() && arg.get_register16().unwrap() == Register16::Hl
5645        {
5646            {
5647                add_byte(&mut bytes, 0xBE);
5648            }
5649        }
5650        else if arg.is_indexregister_with_index() {
5651            let reg = arg.get_indexregister16().unwrap();
5652            let idx = arg.get_index().unwrap();
5653            {
5654                add_byte(&mut bytes, indexed_register16_to_code(reg));
5655                add_byte(&mut bytes, 0xBE);
5656                add_byte(
5657                    &mut bytes,
5658                    self.resolve_index_may_fail_in_first_pass(idx)?.int()? as _
5659                );
5660            }
5661        }
5662        else {
5663            unreachable!()
5664        }
5665
5666        Ok(bytes)
5667    }
5668
5669    pub fn assemble_sub<D: DataAccessElem>(&mut self, arg: &D) -> Result<Bytes, AssemblerError>
5670    where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5671        let mut bytes = Bytes::new();
5672
5673        if arg.is_expression() {
5674            let exp = arg.get_expression().unwrap();
5675            {
5676                let val = (self.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
5677                bytes.push(0xD6);
5678                bytes.push(val);
5679            }
5680        }
5681        else if arg.is_register8() {
5682            let reg = arg.get_register8().unwrap();
5683            {
5684                bytes.push(0b10010000 + (register8_to_code(reg)));
5685            }
5686        }
5687        else if arg.is_indexregister8() {
5688            let reg = arg.get_indexregister8().unwrap();
5689            {
5690                bytes.push(indexed_register16_to_code(reg.complete()));
5691                bytes.push(0b10010000 + (indexregister8_to_code(reg)));
5692            }
5693        }
5694        else if arg.is_address_in_register16() {
5695            assert_eq!(arg.get_register16().unwrap(), Register16::Hl);
5696            {
5697                bytes.push(0x96);
5698            }
5699        }
5700        else if arg.is_indexregister_with_index() {
5701            let reg = arg.get_indexregister16().unwrap();
5702            let idx = arg.get_index().unwrap();
5703
5704            {
5705                let val = (self.resolve_index_may_fail_in_first_pass(idx)?.int()? & 0xFF) as u8;
5706
5707                bytes.push(indexed_register16_to_code(reg));
5708                bytes.push(0x96);
5709                bytes.push(val);
5710            }
5711        }
5712        else {
5713            unreachable!();
5714        }
5715
5716        Ok(bytes)
5717    }
5718
5719    pub fn assemble_sbc<D: DataAccessElem>(
5720        &mut self,
5721        arg1: Option<&D>,
5722        arg2: &D
5723    ) -> Result<Bytes, AssemblerError>
5724    where
5725        <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5726    {
5727        let mut bytes = Bytes::new();
5728
5729        if arg1.as_ref().map(|arg| arg.is_register_a()).unwrap_or(true) {
5730            if arg2.is_register8() {
5731                let reg = arg2.get_register8().unwrap();
5732                {
5733                    bytes.push(0b10011000 + register8_to_code(reg));
5734                }
5735            }
5736            else if arg2.is_indexregister8() {
5737                let reg = arg2.get_indexregister8().unwrap();
5738                {
5739                    bytes.push(indexed_register16_to_code(reg.complete()));
5740                    bytes.push(0b10011000 + indexregister8_to_code(reg));
5741                }
5742            }
5743            else if arg2.is_expression() {
5744                let exp = arg2.get_expression().unwrap();
5745                {
5746                    let val = self.resolve_expr_may_fail_in_first_pass(exp)?.int()? as u8;
5747                    bytes.push(0xDE);
5748                    bytes.push(val);
5749                }
5750            }
5751            else if arg2.is_address_in_register16() {
5752                assert_eq!(arg2.get_register16().unwrap(), Register16::Hl);
5753                {
5754                    bytes.push(0x9E);
5755                }
5756            }
5757            else if arg2.is_indexregister_with_index() {
5758                let reg = arg2.get_indexregister16().unwrap();
5759                let idx = arg2.get_index().unwrap();
5760                {
5761                    bytes.push(indexed_register16_to_code(reg));
5762                    bytes.push(0x9E);
5763                    let val = self.resolve_index_may_fail_in_first_pass(idx)?.int()? as u8;
5764                    bytes.push(val);
5765                }
5766            }
5767            else {
5768                unreachable!()
5769            }
5770        }
5771        else {
5772            assert!(arg1.unwrap().is_register_hl());
5773            assert!(arg2.is_register16());
5774            let reg = arg2.get_register16().unwrap();
5775            bytes.push(0xED);
5776            bytes.push(0b0100_0010 | (register16_to_code_with_sp(reg) << 4));
5777        }
5778
5779        Ok(bytes)
5780    }
5781
5782    pub fn assemble_shift<D: DataAccessElem>(
5783        &mut self,
5784        mne: Mnemonic,
5785        target: &D,
5786        hidden: Option<&D>
5787    ) -> Result<Bytes, AssemblerError>
5788    where
5789        <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5790    {
5791        let mut bytes = Bytes::new();
5792
5793        if target.is_register8() {
5794            let reg = target.get_register8().unwrap();
5795            add_byte(&mut bytes, 0xCB);
5796            let byte = if mne.is_sla() {
5797                0b0010_0000
5798            }
5799            else if mne.is_sra() {
5800                0b0010_1000
5801            }
5802            else if mne.is_srl() {
5803                0b0011_1000
5804            }
5805            else if mne.is_rlc() {
5806                0b0000_0000
5807            }
5808            else if mne.is_rrc() {
5809                0b0000_1000
5810            }
5811            else if mne.is_rl() {
5812                0b0001_0000
5813            }
5814            else if mne.is_rr() {
5815                0b0001_1000
5816            }
5817            else if mne.is_sl1() {
5818                0b0011_0000
5819            }
5820            else {
5821                unreachable!()
5822            } + register8_to_code(reg);
5823            add_byte(&mut bytes, byte);
5824        }
5825        else if target.is_register16() {
5826            // here we handle a fake instruction
5827            let reg16 = target.get_register16().unwrap();
5828            let opcodes: &[(Mnemonic, Option<Register8>)] = match mne {
5829                Mnemonic::Srl => &[(Mnemonic::Srl, reg16.high()), (Mnemonic::Rr, reg16.low())],
5830                Mnemonic::Sra => &[(Mnemonic::Sra, reg16.high()), (Mnemonic::Rr, reg16.low())],
5831                Mnemonic::Sl1 => &[(Mnemonic::Sl1, reg16.low()), (Mnemonic::Rl, reg16.high())],
5832                Mnemonic::Sla => &[(Mnemonic::Sla, reg16.low()), (Mnemonic::Rl, reg16.high())],
5833                Mnemonic::Rr => &[(Mnemonic::Rr, reg16.high()), (Mnemonic::Rr, reg16.low())],
5834                Mnemonic::Rl => &[(Mnemonic::Rl, reg16.low()), (Mnemonic::Rl, reg16.high())],
5835                Mnemonic::Rlc => {
5836                    &[
5837                        (Mnemonic::Sla, reg16.high()),
5838                        (Mnemonic::Rl, reg16.low()),
5839                        (Mnemonic::Rr, reg16.high()),
5840                        (Mnemonic::Rlc, reg16.high())
5841                    ]
5842                },
5843                Mnemonic::Rrc => {
5844                    &[
5845                        (Mnemonic::Srl, reg16.high()),
5846                        (Mnemonic::Rr, reg16.low()),
5847                        (Mnemonic::Rl, reg16.high()),
5848                        (Mnemonic::Rrc, reg16.high())
5849                    ]
5850                },
5851
5852                _ => unreachable!()
5853            };
5854
5855            for instruction in opcodes
5856                .iter()
5857                .map(|op| Token::OpCode(op.0, Some(op.1.unwrap().into()), None, None))
5858            {
5859                instruction.visited(self)?;
5860            }
5861        }
5862        else {
5863            assert!(target.is_address_in_register16() || target.is_indexregister_with_index());
5864
5865            // add prefix for ix/iy
5866            if target.is_indexregister_with_index() {
5867                let reg = target.get_indexregister16().unwrap();
5868                let idx = target.get_index().unwrap();
5869
5870                {
5871                    let val = self.resolve_index_may_fail_in_first_pass(idx)?.int()? as u8;
5872                    bytes.push(indexed_register16_to_code(reg));
5873                    add_byte(&mut bytes, 0xCB);
5874                    bytes.push(val);
5875                }
5876            }
5877            else if target.is_address_in_register16() {
5878                assert_eq!(target.get_register16().unwrap(), Register16::Hl);
5879                {
5880                    add_byte(&mut bytes, 0xCB);
5881                }
5882            }
5883            else {
5884                return Err(AssemblerError::InvalidArgument {
5885                    msg: format!("{} cannot take {} as argument", mne, target)
5886                });
5887            };
5888
5889            // some hidden opcode modify this byte
5890            let mut byte: u8 = if mne.is_sla() {
5891                0x26
5892            }
5893            else if mne.is_sra() {
5894                0x2E
5895            }
5896            else if mne.is_srl() {
5897                0x3E
5898            }
5899            else if mne.is_rlc() {
5900                0x06
5901            }
5902            else if mne.is_rrc() {
5903                0x0E
5904            }
5905            else if mne.is_rl() {
5906                0x16
5907            }
5908            else if mne.is_rr() {
5909                0x1E
5910            }
5911            else if mne.is_sl1() {
5912                0x36
5913            }
5914            else {
5915                unreachable!()
5916            };
5917
5918            if hidden.is_some() {
5919                let delta: i8 = match hidden.unwrap().get_register8().unwrap() {
5920                    Register8::A => 1,
5921                    Register8::L => -1,
5922                    Register8::H => -2,
5923                    Register8::E => -3,
5924                    Register8::D => -4,
5925                    Register8::C => -5,
5926                    Register8::B => -6
5927                };
5928                if delta < 0 {
5929                    byte -= delta.unsigned_abs();
5930                }
5931                else {
5932                    byte += delta as u8;
5933                }
5934            }
5935            bytes.push(byte);
5936        }
5937
5938        Ok(bytes)
5939    }
5940}
5941
5942fn assemble_ld<D: DataAccessElem + Debug>(
5943    arg1: &D,
5944    arg2: &D,
5945    env: &mut Env
5946) -> Result<Bytes, AssemblerError>
5947where
5948    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5949{
5950    let mut bytes = Bytes::new();
5951
5952    // Destination is 8bits register
5953    if arg1.is_register8() {
5954        let dst = register8_to_code(arg1.get_register8().unwrap());
5955        if arg2.is_register8() {
5956            let src = arg2.get_register8().unwrap();
5957            {
5958                // R. Zaks p 297
5959                let src = register8_to_code(src);
5960
5961                let code = 0b0100_0000 + (dst << 3) + src;
5962                bytes.push(code);
5963            }
5964        }
5965        else if arg2.is_indexregister8() {
5966            let src = arg2.get_indexregister8().unwrap();
5967            {
5968                bytes.push(indexed_register16_to_code(src.complete()));
5969                let src = indexregister8_to_code(src);
5970                let code = 0b0100_0000 + (dst << 3) + src;
5971                bytes.push(code);
5972            }
5973        }
5974        else if arg2.is_expression() {
5975            let exp = arg2.get_expression().unwrap();
5976            {
5977                let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
5978
5979                bytes.push(0b0000_0110 | (dst << 3));
5980                bytes.push(val);
5981            }
5982        }
5983        else if arg2.is_indexregister_with_index() {
5984            let reg = arg2.get_indexregister16().unwrap();
5985            let idx = arg2.get_index().unwrap();
5986            {
5987                let val = env.resolve_index_may_fail_in_first_pass(idx)?.int()?;
5988
5989                add_index_register_code(&mut bytes, reg);
5990                add_byte(&mut bytes, 0b0100_0110 | (dst << 3));
5991                add_index(&mut bytes, val)?;
5992            }
5993        }
5994        else if arg2.is_address_in_register16() {
5995            match arg2.get_register16().unwrap() {
5996                Register16::Hl => {
5997                    add_byte(&mut bytes, 0b0100_0110 | (dst << 3));
5998                },
5999                memreg => {
6000                    assert!(arg1.is_register_a());
6001                    let byte = match memreg {
6002                        Register16::Bc => 0x0A,
6003                        Register16::De => 0x1A,
6004                        _ => unreachable!()
6005                    };
6006                    add_byte(&mut bytes, byte);
6007                }
6008            }
6009        }
6010        else if arg2.is_address_in_indexregister16() {
6011            let reg = arg2.get_indexregister16().unwrap();
6012            {
6013                add_index_register_code(&mut bytes, reg);
6014                add_byte(&mut bytes, 0b0100_0110 | (dst << 3));
6015            }
6016        }
6017        else if arg2.is_memory() {
6018            let expr = arg2.get_expression().unwrap();
6019
6020            {
6021                // dst is A
6022                let val = env.resolve_expr_may_fail_in_first_pass(expr)?.int()?;
6023                add_byte(&mut bytes, 0x3A);
6024                add_word(&mut bytes, val as _);
6025            }
6026        }
6027        else if arg2.is_register_i() {
6028            {
6029                assert!(arg1.is_register_a());
6030                bytes.push(0xED);
6031                bytes.push(0x57);
6032            }
6033        }
6034        else if arg2.is_register_r() {
6035            {
6036                assert!(arg1.is_register_a());
6037                bytes.push(0xED);
6038                bytes.push(0x5F);
6039            }
6040        }
6041        else {
6042            return Err(AssemblerError::BugInAssembler {
6043                file: file!(),
6044                line: line!(),
6045                msg: format!("LD: not properly implemented for '{:?}, {:?}'", arg1, arg2)
6046            });
6047        }
6048    }
6049    // Destination is 16 bits register
6050    else if arg1.is_register16() {
6051        let dst = arg1.get_register16().unwrap();
6052        let dst_code = register16_to_code_with_sp(dst);
6053
6054        if arg2.is_expression() {
6055            let exp = arg2.get_expression().unwrap();
6056            {
6057                let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFFFF) as u16;
6058
6059                add_byte(&mut bytes, 0b0000_0001 | (dst_code << 4));
6060                add_word(&mut bytes, val);
6061            }
6062        }
6063        else if arg2.is_register_hl() && dst.is_sp() {
6064            add_byte(&mut bytes, 0xF9);
6065        }
6066        else if arg2.is_indexregister16() && dst.is_sp() {
6067            let reg = arg2.get_indexregister16().unwrap();
6068            {
6069                add_byte(&mut bytes, indexed_register16_to_code(reg));
6070                add_byte(&mut bytes, 0xF9);
6071            }
6072        }
6073        else if arg2.is_register16() {
6074            let src = arg2.get_register16().unwrap();
6075            // Fake instruction splitted in 2 bits operations
6076            {
6077                let bytes_high = assemble_ld(
6078                    &DataAccess::Register8(dst.high().unwrap()),
6079                    &DataAccess::Register8(src.high().unwrap()),
6080                    env
6081                )
6082                .unwrap();
6083                let bytes_low = assemble_ld(
6084                    &DataAccess::Register8(dst.low().unwrap()),
6085                    &DataAccess::Register8(src.low().unwrap()),
6086                    env
6087                )
6088                .unwrap();
6089
6090                bytes.extend_from_slice(&bytes_low);
6091                bytes.extend_from_slice(&bytes_high);
6092            }
6093        }
6094        else if arg2.is_memory() {
6095            let expr = arg2.get_expression().unwrap();
6096            {
6097                let val = (env.resolve_expr_may_fail_in_first_pass(expr)?.int()? & 0xFFFF) as u16;
6098
6099                if let Register16::Hl = dst {
6100                    add_byte(&mut bytes, 0x2A);
6101                    add_word(&mut bytes, val);
6102                }
6103                else {
6104                    add_byte(&mut bytes, 0xED);
6105                    add_byte(
6106                        &mut bytes,
6107                        (register16_to_code_with_sp(dst) << 4) + 0b0100_1011
6108                    );
6109                    add_word(&mut bytes, val);
6110                }
6111            }
6112        }
6113    }
6114    else if arg1.is_indexregister8() {
6115        let dst = arg1.get_indexregister8().unwrap();
6116        add_byte(&mut bytes, indexed_register16_to_code(dst.complete()));
6117
6118        if arg2.is_expression() {
6119            let exp = arg2.get_expression().unwrap();
6120            {
6121                let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6122                bytes.push(0b0000_0110 | (indexregister8_to_code(dst) << 3));
6123                bytes.push(val);
6124            }
6125        }
6126        else if arg2.is_register8() {
6127            let src = arg2.get_register8().unwrap();
6128
6129            {
6130                let code = register8_to_code(src);
6131
6132                let code = if dst.is_high() {
6133                    0b0110_0000 + code
6134                }
6135                else {
6136                    0x68 + code
6137                };
6138                bytes.push(code);
6139            }
6140        }
6141        else if arg2.is_indexregister8() {
6142            let src = arg2.get_indexregister8().unwrap();
6143            {
6144                assert_eq!(dst.complete(), src.complete());
6145
6146                let byte = match (dst.is_low(), src.is_low()) {
6147                    (false, false) => 0x64,
6148                    (false, true) => 0x65,
6149                    (true, false) => 0x6C,
6150                    (true, true) => 0x6D
6151                };
6152                bytes.push(byte)
6153            }
6154        }
6155        else {
6156            unreachable!()
6157        }
6158    }
6159    // Destination  is 16 bits indexed register
6160    else if arg1.is_indexregister16() {
6161        let dst = arg1.get_indexregister16().unwrap();
6162        let code = indexed_register16_to_code(dst);
6163
6164        if arg2.is_expression() {
6165            let exp = arg2.get_expression().unwrap();
6166            {
6167                let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFFFF) as u16;
6168
6169                add_byte(&mut bytes, code);
6170                add_byte(&mut bytes, 0x21);
6171                add_word(&mut bytes, val);
6172            }
6173        }
6174        else if arg2.is_memory() {
6175            let exp = arg2.get_expression().unwrap();
6176
6177            {
6178                let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFFFF) as u16;
6179
6180                add_byte(&mut bytes, code);
6181                add_byte(&mut bytes, 0x2A);
6182                add_word(&mut bytes, val);
6183            }
6184        }
6185    }
6186    // Destination is memory indexed by register
6187    else if arg1.is_address_in_register16() {
6188        let dst = arg1.get_register16().unwrap();
6189        // Want to store in memory pointed by register
6190        match dst {
6191            Register16::Hl => {
6192                if arg2.is_register8() {
6193                    let src = arg2.get_register8().unwrap();
6194                    let src = register8_to_code(src);
6195                    let code = 0b0111_0000 | src;
6196                    bytes.push(code);
6197                }
6198                else if arg2.is_expression() {
6199                    let exp = arg2.get_expression().unwrap();
6200                    let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6201                    bytes.push(0x36);
6202                    bytes.push(val);
6203                }
6204            },
6205
6206            Register16::De if arg2.is_register_a() => {
6207                bytes.push(0b0001_0010);
6208            },
6209
6210            Register16::Bc if arg2.is_register_a() => {
6211                bytes.push(0b0000_0010);
6212            },
6213
6214            _ => {}
6215        }
6216    }
6217    else if arg1.is_address_in_indexregister16() {
6218        let dst = arg1.get_indexregister16().unwrap();
6219        add_index_register_code(&mut bytes, dst);
6220
6221        if arg2.is_register8() {
6222            let src = arg2.get_register8().unwrap();
6223            let src = register8_to_code(src);
6224            let code = 0b0111_0000 | src;
6225            bytes.push(code);
6226            bytes.push(0);
6227        }
6228        else if arg2.is_expression() {
6229            let exp = arg2.get_expression().unwrap();
6230            let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6231            bytes.push(0x36);
6232            bytes.push(val);
6233        }
6234    }
6235    // Destination is memory form ix/iy + n
6236    else if arg1.is_indexregister_with_index() {
6237        let reg = arg1.get_indexregister16().unwrap();
6238        let idx = arg1.get_index().unwrap();
6239        add_byte(&mut bytes, indexed_register16_to_code(reg));
6240        let delta = (env.resolve_index_may_fail_in_first_pass(idx)?.int()? & 0xFF) as u8;
6241
6242        if arg2.is_expression() {
6243            let exp = arg2.get_expression().unwrap();
6244            {
6245                let value = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6246                add_byte(&mut bytes, 0x36);
6247                add_byte(&mut bytes, delta);
6248                add_byte(&mut bytes, value);
6249            }
6250        }
6251        else if arg2.is_register8() {
6252            let src = arg2.get_register8().unwrap();
6253
6254            {
6255                add_byte(&mut bytes, 0x70 + register8_to_code(src));
6256                add_byte(&mut bytes, delta);
6257            }
6258        }
6259        else {
6260            // possible fake instruction
6261            bytes.clear();
6262        }
6263    }
6264    // Destination is memory
6265    else if arg1.is_memory() {
6266        let exp = arg1.get_expression().unwrap();
6267        let address = env.resolve_expr_may_fail_in_first_pass(exp)?.int()?;
6268
6269        if arg2.is_indexregister16() {
6270            match arg2.get_indexregister16().unwrap() {
6271                IndexRegister16::Ix => {
6272                    bytes.push(DD);
6273                    bytes.push(0b0010_0010);
6274                    add_word(&mut bytes, address as _);
6275                },
6276                IndexRegister16::Iy => {
6277                    bytes.push(FD);
6278                    bytes.push(0b0010_0010);
6279                    add_word(&mut bytes, address as _);
6280                }
6281            }
6282        }
6283        else if arg2.is_register_hl() {
6284            bytes.push(0b0010_0010);
6285            add_word(&mut bytes, address as _);
6286        }
6287        else if arg2.is_register16() {
6288            let reg = arg2.get_register16().unwrap();
6289            {
6290                bytes.push(0xED);
6291                bytes.push(0b0100_0011 | (register16_to_code_with_sp(reg) << 4));
6292                add_word(&mut bytes, address as _);
6293            }
6294        }
6295        else if arg2.is_register_a() {
6296            bytes.push(0x32);
6297            add_word(&mut bytes, address as _);
6298        }
6299    }
6300    else if arg1.is_register_i() {
6301        assert!(arg2.is_register_a());
6302        {
6303            bytes.push(0xED);
6304            bytes.push(0x47)
6305        }
6306    }
6307    else if arg1.is_register_r() {
6308        assert!(arg2.is_register_a());
6309        {
6310            bytes.push(0xED);
6311            bytes.push(0x4F)
6312        }
6313    }
6314
6315    // handle fake instructions
6316    if bytes.is_empty() {
6317        if arg1.is_register16() && arg2.is_register16() {
6318            let dst = arg1.get_register16().unwrap();
6319            let src = arg2.get_register16().unwrap();
6320            {
6321                bytes.extend(assemble_ld(
6322                    &DataAccess::Register8(dst.low().unwrap()),
6323                    &DataAccess::Register8(src.low().unwrap()),
6324                    env
6325                )?);
6326                bytes.extend(assemble_ld(
6327                    &DataAccess::Register8(dst.high().unwrap()),
6328                    &DataAccess::Register8(src.high().unwrap()),
6329                    env
6330                )?);
6331            }
6332        }
6333        else if (arg1.is_register_hl() && arg2.is_indexregister16())
6334            || (arg1.is_indexregister16() && arg2.is_register_hl())
6335            || (arg1.is_indexregister16() && arg2.is_indexregister16())
6336        {
6337            bytes.extend(assemble_push(arg2)?);
6338            bytes.extend(assemble_pop(arg1)?);
6339        }
6340        else if arg1.is_register16() && arg2.is_indexregister16() {
6341            let dst = arg1.get_register16().unwrap();
6342            let src = arg2.get_indexregister16().unwrap();
6343
6344            bytes.extend(
6345                assemble_ld(
6346                    &DataAccess::Register8(dst.low().unwrap()),
6347                    &DataAccess::IndexRegister8(src.low()),
6348                    env
6349                )?
6350                .iter()
6351                .cloned()
6352            );
6353            bytes.extend(
6354                assemble_ld(
6355                    &DataAccess::Register8(dst.high().unwrap()),
6356                    &DataAccess::IndexRegister8(src.high()),
6357                    env
6358                )?
6359                .iter()
6360                .cloned()
6361            );
6362        }
6363        else if arg1.is_indexregister16() && arg2.is_register16() {
6364            let dst = arg1.get_indexregister16().unwrap();
6365            let _res = arg2.get_register16().unwrap();
6366            let src = arg2.get_register16().unwrap();
6367
6368            // general > indexed
6369            {
6370                bytes.extend(assemble_ld(
6371                    &DataAccess::IndexRegister8(dst.low()),
6372                    &DataAccess::Register8(src.low().unwrap()),
6373                    env
6374                )?);
6375                bytes.extend(assemble_ld(
6376                    &DataAccess::IndexRegister8(dst.high()),
6377                    &DataAccess::Register8(src.high().unwrap()),
6378                    env
6379                )?);
6380            }
6381        }
6382        else if arg1.is_register16() && arg2.is_indexregister_with_index() {
6383            let dst = arg1.get_register16().unwrap();
6384            let src = arg2.get_indexregister16().unwrap();
6385            let idx = arg2.get_index().unwrap();
6386
6387            {
6388                bytes.extend(assemble_ld(
6389                    &DataAccess::Register8(dst.low().unwrap()),
6390                    &DataAccess::IndexRegister16WithIndex(src, idx.0, idx.1.to_expr().into_owned()),
6391                    env
6392                )?);
6393                bytes.extend(assemble_ld(
6394                    &DataAccess::Register8(dst.high().unwrap()),
6395                    &DataAccess::IndexRegister16WithIndex(
6396                        src,
6397                        idx.0,
6398                        idx.1.to_expr().into_owned().add(1)
6399                    ),
6400                    env
6401                )?);
6402            }
6403        }
6404        else if arg1.is_indexregister_with_index() && arg2.is_register16() {
6405            let dst = arg1.get_indexregister16().unwrap();
6406            let index = arg1.get_index().unwrap();
6407            let src = arg2.get_register16().unwrap();
6408            {
6409                bytes.extend(assemble_ld(
6410                    &DataAccess::IndexRegister16WithIndex(
6411                        dst,
6412                        index.0,
6413                        index.1.to_expr().into_owned()
6414                    ),
6415                    &DataAccess::Register8(src.low().unwrap()),
6416                    env
6417                )?);
6418                bytes.extend(assemble_ld(
6419                    &DataAccess::IndexRegister16WithIndex(
6420                        dst,
6421                        index.0,
6422                        index.1.to_expr().into_owned().add(1)
6423                    ),
6424                    &DataAccess::Register8(src.high().unwrap()),
6425                    env
6426                )?);
6427            }
6428        }
6429        else if arg1.is_register16()
6430            && arg2.is_address_in_indexregister16()
6431            && arg2.get_register16().unwrap() == Register16::Hl
6432        {
6433            let dst = arg1.get_register16().unwrap();
6434            {
6435                bytes.extend(
6436                    assemble_ld(
6437                        &DataAccess::Register8(dst.low().unwrap()),
6438                        &DataAccess::MemoryRegister16(Register16::Hl),
6439                        env
6440                    )?
6441                    .iter()
6442                    .cloned()
6443                );
6444                bytes.extend(assemble_inc_dec(
6445                    Mnemonic::Inc,
6446                    &DataAccess::Register16(Register16::Hl),
6447                    env
6448                )?);
6449                bytes.extend(
6450                    assemble_ld(
6451                        &DataAccess::Register8(dst.high().unwrap()),
6452                        &DataAccess::MemoryRegister16(Register16::Hl),
6453                        env
6454                    )?
6455                    .iter()
6456                    .cloned()
6457                );
6458                bytes.extend(assemble_inc_dec(
6459                    Mnemonic::Dec,
6460                    &DataAccess::Register16(Register16::Hl),
6461                    env
6462                )?);
6463            }
6464        }
6465        else if arg2.is_register16()
6466            && arg1.is_address_in_indexregister16()
6467            && arg1.get_register16().unwrap() == Register16::Hl
6468        {
6469            let src = arg2.get_register16().unwrap();
6470            bytes.extend(
6471                assemble_ld(
6472                    &DataAccess::MemoryRegister16(Register16::Hl),
6473                    &DataAccess::Register8(src.low().unwrap()),
6474                    env
6475                )?
6476                .iter()
6477                .cloned()
6478            );
6479            bytes.extend(assemble_inc_dec(
6480                Mnemonic::Inc,
6481                &DataAccess::Register16(Register16::Hl),
6482                env
6483            )?);
6484            bytes.extend(
6485                assemble_ld(
6486                    &DataAccess::MemoryRegister16(Register16::Hl),
6487                    &DataAccess::Register8(src.high().unwrap()),
6488                    env
6489                )?
6490                .iter()
6491                .cloned()
6492            );
6493            bytes.extend(assemble_inc_dec(
6494                Mnemonic::Dec,
6495                &DataAccess::Register16(Register16::Hl),
6496                env
6497            )?);
6498        }
6499    }
6500
6501    if bytes.is_empty() {
6502        Err(AssemblerError::BugInAssembler {
6503            file: file!(),
6504            line: line!(),
6505            msg: format!("LD: not properly implemented for '{:?}, {:?}'", arg1, arg2)
6506        })
6507    }
6508    else {
6509        Ok(bytes)
6510    }
6511}
6512
6513fn assemble_in<D: DataAccessElem>(
6514    arg1: &D,
6515    arg2: &D,
6516    env: &mut Env
6517) -> Result<Bytes, AssemblerError>
6518where
6519    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
6520{
6521    let mut bytes = Bytes::new();
6522
6523    if arg1.is_expression() {
6524        assert_eq!(
6525            env.resolve_expr_must_never_fail(arg1.get_expression().unwrap())?,
6526            ExprResult::from(0)
6527        );
6528        assert!(arg2.is_port_c());
6529        bytes.push(0xED);
6530        bytes.push(0x70);
6531    }
6532    else if arg2.is_port_c() && arg1.is_register8() {
6533        let reg = arg1.get_register8().unwrap();
6534        {
6535            bytes.push(0xED);
6536            bytes.push(0b0100_0000 | (register8_to_code(reg) << 3))
6537        }
6538    }
6539    else if arg2.is_port_n() {
6540        let exp = arg2.get_expression().unwrap();
6541        {
6542            if arg1.is_register_a() {
6543                let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6544                bytes.push(0xDB);
6545                bytes.push(val);
6546            }
6547        }
6548    }
6549
6550    if bytes.is_empty() {
6551        Err(AssemblerError::BugInAssembler {
6552            file: file!(),
6553            line: line!(),
6554            msg: format!("IN: not properly implemented for '{:?}, {:?}'", arg1, arg2)
6555        })
6556    }
6557    else {
6558        Ok(bytes)
6559    }
6560}
6561
6562fn assemble_out<D: DataAccessElem>(
6563    arg1: &D,
6564    arg2: &D,
6565    env: &mut Env
6566) -> Result<Bytes, AssemblerError>
6567where
6568    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
6569{
6570    let mut bytes = Bytes::new();
6571
6572    if arg2.is_expression() {
6573        assert_eq!(
6574            env.resolve_expr_must_never_fail(arg2.get_expression().unwrap())?,
6575            0.into()
6576        );
6577        assert!(arg1.is_port_c());
6578        bytes.push(0xED);
6579        bytes.push(0x71);
6580    }
6581    else if arg1.is_port_c() {
6582        if arg2.is_register8() {
6583            let reg = arg2.get_register8().unwrap();
6584            bytes.push(0xED);
6585            bytes.push(0b0100_0001 | (register8_to_code(reg) << 3))
6586        }
6587    }
6588    else if arg1.is_port_n() {
6589        let exp = arg1.get_expression().unwrap();
6590        {
6591            if arg2.is_register_a() {
6592                let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6593                bytes.push(0xD3);
6594                bytes.push(val);
6595            }
6596        }
6597    }
6598
6599    if bytes.is_empty() {
6600        Err(AssemblerError::BugInAssembler {
6601            file: file!(),
6602            line: line!(),
6603            msg: format!("OUT: not properly implemented for '{:?}, {:?}'", arg1, arg2)
6604        })
6605    }
6606    else {
6607        Ok(bytes)
6608    }
6609}
6610
6611fn assemble_pop<D: DataAccessElem>(arg1: &D) -> Result<Bytes, AssemblerError> {
6612    let mut bytes = Bytes::new();
6613
6614    if arg1.is_register16() {
6615        let reg = arg1.get_register16().unwrap();
6616        let byte = 0b1100_0001 | (register16_to_code_with_af(reg) << 4);
6617        bytes.push(byte);
6618    }
6619    else if arg1.is_indexregister16() {
6620        let reg = arg1.get_indexregister16().unwrap();
6621        bytes.push(indexed_register16_to_code(reg));
6622        bytes.push(0xE1);
6623    }
6624    else {
6625        return Err(AssemblerError::InvalidArgument {
6626            msg: format!("POP: not implemented for {:?}", arg1)
6627        });
6628    }
6629
6630    Ok(bytes)
6631}
6632
6633fn assemble_push<D: DataAccessElem>(arg1: &D) -> Result<Bytes, AssemblerError> {
6634    let mut bytes = Bytes::new();
6635
6636    if arg1.is_register16() {
6637        let reg = arg1.get_register16().unwrap();
6638        let byte = 0b1100_0101 | (register16_to_code_with_af(reg) << 4);
6639        bytes.push(byte);
6640    }
6641    else if arg1.is_indexregister16() {
6642        let reg = arg1.get_indexregister16().unwrap();
6643        bytes.push(indexed_register16_to_code(reg));
6644        bytes.push(0xE5);
6645    }
6646    else {
6647        return Err(AssemblerError::InvalidArgument {
6648            msg: format!("PUSH: not implemented for {:?}", arg1)
6649        });
6650    }
6651
6652    Ok(bytes)
6653}
6654
6655fn assemble_logical_operator<D: DataAccessElem>(
6656    mnemonic: Mnemonic,
6657    arg1: &D,
6658    env: &mut Env
6659) -> Result<Bytes, AssemblerError>
6660where
6661    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
6662{
6663    let mut bytes = Bytes::new();
6664
6665    let memory_code = || {
6666        match mnemonic {
6667            Mnemonic::And => 0xA6,
6668            Mnemonic::Or => 0xB6,
6669            Mnemonic::Xor => 0xAE,
6670            _ => unreachable!()
6671        }
6672    };
6673
6674    if arg1.is_register8() {
6675        let reg = arg1.get_register8().unwrap();
6676        {
6677            let base = match mnemonic {
6678                Mnemonic::And => 0b1010_0000,
6679                Mnemonic::Or => 0b1011_0000,
6680                Mnemonic::Xor => 0b1010_1000,
6681                _ => unreachable!()
6682            };
6683            bytes.push(base + register8_to_code(reg));
6684        }
6685    }
6686    else if arg1.is_indexregister8() {
6687        let reg = arg1.get_indexregister8().unwrap();
6688        {
6689            bytes.push(indexed_register16_to_code(reg.complete()));
6690            let base = match mnemonic {
6691                Mnemonic::And => 0b1010_0000,
6692                Mnemonic::Or => 0b1011_0000,
6693                Mnemonic::Xor => 0b1010_1000,
6694                _ => unreachable!()
6695            };
6696            bytes.push(base + indexregister8_to_code(reg));
6697        }
6698    }
6699    else if arg1.is_expression() {
6700        let exp = arg1.get_expression().unwrap();
6701
6702        {
6703            let base = match mnemonic {
6704                Mnemonic::And => 0xE6,
6705                Mnemonic::Or => 0xF6,
6706                Mnemonic::Xor => 0xEE,
6707                _ => unreachable!()
6708            };
6709            let value = env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF;
6710            bytes.push(base);
6711            bytes.push(value as u8);
6712        }
6713    }
6714    else if arg1.is_address_in_register16() {
6715        assert_eq!(arg1.get_register16(), Some(Register16::Hl));
6716
6717        {
6718            bytes.push(memory_code());
6719        }
6720    }
6721    else if arg1.is_indexregister_with_index() {
6722        let reg = arg1.get_indexregister16().unwrap();
6723        let idx = arg1.get_index().unwrap();
6724
6725        {
6726            let value = env.resolve_index_may_fail_in_first_pass(idx)?.int()? & 0xFF;
6727            bytes.push(indexed_register16_to_code(reg));
6728            bytes.push(memory_code());
6729            bytes.push(value as u8);
6730        }
6731    }
6732    else {
6733        unreachable!()
6734    }
6735
6736    Ok(bytes)
6737}
6738
6739fn assemble_ex_memsp<D: DataAccessElem>(arg1: &D) -> Result<Bytes, AssemblerError> {
6740    let mut bytes = Bytes::new();
6741
6742    if let Some(reg) = arg1.get_indexregister16() {
6743        bytes.push(indexed_register16_to_code(reg));
6744    }
6745
6746    bytes.push(0xE3);
6747    Ok(bytes)
6748}
6749
6750fn assemble_add_or_adc<D: DataAccessElem>(
6751    mnemonic: Mnemonic,
6752    arg1: Option<&D>,
6753    arg2: &D,
6754    env: &mut Env
6755) -> Result<Bytes, AssemblerError>
6756where
6757    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
6758{
6759    let mut bytes = Bytes::new();
6760    let is_add = match mnemonic {
6761        Mnemonic::Add => true,
6762        Mnemonic::Adc => false,
6763        _ => panic!("Impossible case")
6764    };
6765
6766    if arg1.is_none() || arg1.as_ref().map(|arg1| arg1.is_register_a()).unwrap() {
6767        if arg2.is_address_in_hl() {
6768            if is_add {
6769                bytes.push(0b1000_0110);
6770            }
6771            else {
6772                bytes.push(0b1000_1110);
6773            }
6774        }
6775        else if arg2.is_indexregister_with_index() {
6776            let reg = arg2.get_indexregister16().unwrap();
6777            let idx = arg2.get_index().unwrap();
6778
6779            {
6780                let val = env.resolve_index_may_fail_in_first_pass(idx)?.int()?;
6781
6782                // TODO check if the code is ok
6783                bytes.push(indexed_register16_to_code(reg));
6784                if is_add {
6785                    bytes.push(0b1000_0110);
6786                }
6787                else {
6788                    bytes.push(0x8E);
6789                }
6790                add_index(&mut bytes, val)?;
6791            }
6792        }
6793        else if arg2.is_expression() {
6794            let exp = arg2.get_expression().unwrap();
6795            {
6796                let val = env.resolve_expr_may_fail_in_first_pass(exp)?.int()? as u8;
6797                if is_add {
6798                    bytes.push(0b1100_0110);
6799                }
6800                else {
6801                    bytes.push(0xCE);
6802                }
6803                bytes.push(val);
6804            }
6805        }
6806        else if arg2.is_register8() {
6807            let reg = arg2.get_register8().unwrap();
6808            {
6809                let base = if is_add { 0b1000_0000 } else { 0b1000_1000 };
6810                bytes.push(base | register8_to_code(reg));
6811            }
6812        }
6813        else if arg2.is_indexregister8() {
6814            let reg = arg2.get_indexregister8().unwrap();
6815
6816            {
6817                bytes.push(indexed_register16_to_code(reg.complete()));
6818                let base = if is_add { 0b1000_0000 } else { 0b1000_1000 };
6819                bytes.push(base | indexregister8_to_code(reg));
6820            }
6821        }
6822    }
6823    else if arg1.as_ref().unwrap().is_register_hl() {
6824        if arg2.is_register16() {
6825            let reg = arg2.get_register16().unwrap();
6826            let base = if is_add {
6827                0b0000_1001
6828            }
6829            else {
6830                bytes.push(0xED);
6831                0b0100_1010
6832            };
6833
6834            bytes.push(base | (register16_to_code_with_sp(reg) << 4));
6835        }
6836    }
6837    else if arg1.as_ref().unwrap().is_indexregister16() {
6838        let reg1 = arg1.as_ref().unwrap().get_indexregister16().unwrap();
6839        {
6840            if arg2.is_register16() {
6841                let reg2 = arg2.get_register16().unwrap();
6842                {
6843                    // TODO Error if reg2 = HL
6844                    bytes.push(indexed_register16_to_code(reg1));
6845                    let base = if is_add {
6846                        0b0000_1001
6847                    }
6848                    else {
6849                        panic!();
6850                    };
6851                    bytes.push(
6852                        base | (register16_to_code_with_indexed(&DataAccess::Register16(reg2))
6853                            << 4)
6854                    )
6855                }
6856            }
6857            else if arg2.is_indexregister16() {
6858                let reg2 = arg2.get_indexregister16().unwrap();
6859
6860                {
6861                    if reg1 != reg2 {
6862                        return Err(AssemblerError::InvalidArgument {
6863                            msg: "Unable to add different indexed registers".to_owned()
6864                        });
6865                    }
6866
6867                    bytes.push(indexed_register16_to_code(reg1));
6868                    let base = if is_add {
6869                        0b0000_1001
6870                    }
6871                    else {
6872                        panic!();
6873                    };
6874                    bytes.push(
6875                        base | (register16_to_code_with_indexed(&DataAccess::IndexRegister16(
6876                            reg2
6877                        )) << 4)
6878                    )
6879                }
6880            }
6881        }
6882    }
6883
6884    if bytes.is_empty() {
6885        Err(AssemblerError::BugInAssembler {
6886            file: file!(),
6887            line: line!(),
6888            msg: format!("{:?} not implemented for {:?} {:?}", mnemonic, arg1, arg2)
6889        })
6890    }
6891    else {
6892        Ok(bytes)
6893    }
6894}
6895
6896fn assemble_bit_res_or_set<D: DataAccessElem>(
6897    mnemonic: Mnemonic,
6898    arg1: &D,
6899    arg2: &D,
6900    hidden: Option<&Register8>,
6901    env: &mut Env
6902) -> Result<Bytes, AssemblerError>
6903where
6904    <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt
6905{
6906    let mut bytes = Bytes::new();
6907
6908    // Get the bit of interest
6909    let bit = match arg1.get_expression() {
6910        Some(e) => {
6911            let bit = (env.resolve_expr_may_fail_in_first_pass(e)?.int()? & 0xFF) as u8;
6912            if bit > 7 {
6913                return Err(AssemblerError::InvalidArgument {
6914                    msg: format!("{}: {} is an invalid value", mnemonic, bit)
6915                });
6916            }
6917            bit
6918        },
6919        _ => unreachable!()
6920    };
6921
6922    // Get the code to differentiate the instructions
6923    // the value can be modified by some hidden instructions
6924    let code = match mnemonic {
6925        Mnemonic::Res => 0b1000_0000,
6926        Mnemonic::Set => 0b1100_0000,
6927        Mnemonic::Bit => 0b0100_0000,
6928        _ => unreachable!()
6929    };
6930
6931    // Apply it to the right thing
6932    if let Some(ref reg) = arg2.get_register8() {
6933        //    let mut code = code + 0b0110;
6934
6935        bytes.push(0xCB);
6936        bytes.push(code | (bit << 3) | register8_to_code(*reg))
6937    }
6938    else {
6939        assert!(arg2.is_address_in_register16() || arg2.is_indexregister_with_index());
6940        let mut code = code + 0b0110;
6941
6942        if arg2.is_indexregister_with_index() {
6943            let reg = arg2.get_indexregister16().unwrap();
6944            let idx = arg2.get_index().unwrap();
6945
6946            bytes.push(indexed_register16_to_code(reg));
6947            add_byte(&mut bytes, 0xCB);
6948            let delta = (env.resolve_index_may_fail_in_first_pass(idx)?.int()? & 0xFF) as u8;
6949            add_byte(&mut bytes, delta);
6950
6951            // patch the code for hidden opcode
6952            if hidden.is_some() {
6953                let fix: i8 = match hidden.unwrap() {
6954                    Register8::A => 1,
6955                    Register8::L => -1,
6956                    Register8::H => -2,
6957                    Register8::E => -3,
6958                    Register8::D => -4,
6959                    Register8::C => -5,
6960                    Register8::B => -6
6961                };
6962                if fix < 0 {
6963                    code -= fix.unsigned_abs();
6964                }
6965                else {
6966                    code += fix as u8;
6967                }
6968            }
6969        }
6970        else {
6971            bytes.push(0xCB);
6972        }
6973
6974        bytes.push(code | (bit << 3));
6975    }
6976
6977    Ok(bytes)
6978}
6979
6980fn indexed_register16_to_code(reg: IndexRegister16) -> u8 {
6981    match reg {
6982        IndexRegister16::Ix => DD,
6983        IndexRegister16::Iy => FD
6984    }
6985}
6986
6987/// Return the code that represents a 8bits register.
6988/// A: 0b111
6989/// B: 0b000
6990/// C: 0b001
6991/// D: 0b010
6992/// E: 0b011
6993/// H: 0b100
6994/// L: 0b101
6995#[inline]
6996fn register8_to_code(reg: Register8) -> u8 {
6997    match reg {
6998        Register8::A => 0b111,
6999        Register8::B => 0b000,
7000        Register8::C => 0b001,
7001        Register8::D => 0b010,
7002        Register8::E => 0b011,
7003        Register8::H => 0b100,
7004        Register8::L => 0b101
7005    }
7006}
7007
7008#[inline]
7009fn indexregister8_to_code(reg: IndexRegister8) -> u8 {
7010    match reg {
7011        IndexRegister8::Ixh | IndexRegister8::Iyh => register8_to_code(Register8::H),
7012        IndexRegister8::Ixl | IndexRegister8::Iyl => register8_to_code(Register8::L)
7013    }
7014}
7015
7016/// Return the code that represents a 16 bits register
7017fn register16_to_code_with_af(reg: Register16) -> u8 {
7018    match reg {
7019        Register16::Bc => 0b00,
7020        Register16::De => 0b01,
7021        Register16::Hl => 0b10,
7022        Register16::Af => 0b11,
7023        _ => panic!("no mapping for {:?}", reg)
7024    }
7025}
7026
7027fn register16_to_code_with_sp(reg: Register16) -> u8 {
7028    match reg {
7029        Register16::Bc => 0b00,
7030        Register16::De => 0b01,
7031        Register16::Hl => 0b10,
7032        Register16::Sp => 0b11,
7033        _ => panic!("no mapping for {:?}", reg)
7034    }
7035}
7036
7037fn register16_to_code_with_indexed<D: DataAccessElem>(reg: &D) -> u8 {
7038    if reg.is_register_bc() {
7039        0b00
7040    }
7041    else if reg.is_register_de() {
7042        0b01
7043    }
7044    else if reg.is_indexregister16() {
7045        0b10
7046    }
7047    else if reg.is_register_sp() {
7048        0b11
7049    }
7050    else {
7051        panic!("no mapping for {:?}", reg)
7052    }
7053}
7054
7055fn flag_test_to_code(flag: FlagTest) -> u8 {
7056    match flag {
7057        FlagTest::NZ => 0b000,
7058        FlagTest::Z => 0b001,
7059        FlagTest::NC => 0b010,
7060        FlagTest::C => 0b011,
7061
7062        // the following flags are not used for jr
7063        FlagTest::PO => 0b100,
7064        FlagTest::PE => 0b101,
7065        FlagTest::P => 0b110,
7066        FlagTest::M => 0b111
7067    }
7068}
7069
7070// All these tests are deactivated because there are too many compilation issues at the moment
7071#[cfg(test_to_clean)]
7072#[allow(deprecated)]
7073mod test {
7074
7075    use super::processed_token::build_processed_token;
7076    use super::*;
7077
7078    fn visit_token(token: &Token, env: &mut Env) -> Result<(), AssemblerError> {
7079        let mut processed = build_processed_token(token, env);
7080        processed.visited(env)
7081    }
7082
7083    fn visit_tokens(tokens: &[Token]) -> Result<Env, AssemblerError> {
7084        let mut env = Env::default();
7085        for t in tokens {
7086            visit_token(t, &mut env)?;
7087        }
7088        Ok(env)
7089    }
7090
7091    #[test]
7092    pub fn test_inc_b() {
7093        let mut env = Env::default();
7094        let res = assemble_inc_dec(
7095            Mnemonic::Inc,
7096            &DataAccess::Register8(Register8::B),
7097            &mut env
7098        )
7099        .unwrap();
7100        assert_eq!(res.len(), 1);
7101        assert_eq!(res[0], 0x04);
7102    }
7103
7104    #[test]
7105    pub fn test_pop() {
7106        let res = assemble_pop(&DataAccess::Register16(Register16::Af)).unwrap();
7107        assert_eq!(res.len(), 1);
7108        assert_eq!(res[0], 0b1111_0001);
7109    }
7110
7111    #[test]
7112    fn test_jump() {
7113        let res = assemble_call_jr_or_jp(
7114            Mnemonic::Jp,
7115            Some(&DataAccess::FlagTest(FlagTest::Z)),
7116            &DataAccess::Expression(Expr::Value(0x1234)),
7117            &mut Env::default()
7118        )
7119        .unwrap();
7120        assert_eq!(res.len(), 3);
7121        assert_eq!(res[0], 0b1100_1010);
7122        assert_eq!(res[1], 0x34);
7123        assert_eq!(res[2], 0x12);
7124    }
7125
7126    #[test]
7127    pub fn test_assert() {
7128        let mut env = Env::default();
7129        env.start_new_pass();
7130
7131        assert!(
7132            visit_assert(
7133                &Expr::BinaryOperation(
7134                    BinaryOperation::Equal,
7135                    Box::new(0i32.into()),
7136                    Box::new(0i32.into())
7137                ),
7138                None,
7139                &mut env,
7140                None
7141            )
7142            .unwrap()
7143        );
7144        assert!(
7145            !visit_assert(
7146                &Expr::BinaryOperation(
7147                    BinaryOperation::Equal,
7148                    Box::new(1i32.into()),
7149                    Box::new(0i32.into())
7150                ),
7151                None,
7152                &mut env,
7153                None
7154            )
7155            .unwrap()
7156        );
7157    }
7158
7159    #[test]
7160    pub fn test_undef() {
7161        let mut env = Env::default();
7162        env.start_new_pass();
7163
7164        env.visit_label("toto").unwrap();
7165        assert!(env.symbols().contains_symbol("toto").unwrap());
7166        env.visit_undef("toto").unwrap();
7167        assert!(!env.symbols().contains_symbol("toto").unwrap());
7168        assert!(env.visit_undef("toto").is_err());
7169    }
7170
7171    #[test]
7172    pub fn test_inc_dec() {
7173        let env = Env::default();
7174        let res =
7175            assemble_inc_dec(Mnemonic::Inc, &DataAccess::Register16(Register16::De), &env).unwrap();
7176        assert_eq!(res.len(), 1);
7177        assert_eq!(res[0], 0x13);
7178
7179        let res =
7180            assemble_inc_dec(Mnemonic::Dec, &DataAccess::Register8(Register8::B), &env).unwrap();
7181        assert_eq!(res.len(), 1);
7182        assert_eq!(res[0], 0x05);
7183    }
7184
7185    #[test]
7186    pub fn test_res() {
7187        let env = Env::default();
7188        let res = assemble_bit_res_or_set(
7189            Mnemonic::Res,
7190            &DataAccess::Expression(0.into()),
7191            &DataAccess::Register8(Register8::B),
7192            None,
7193            &env
7194        )
7195        .unwrap();
7196
7197        assert_eq!(res.as_ref(), &[0xCB, 0b10000000]);
7198
7199        let env = Env::default();
7200        let res = assemble_bit_res_or_set(
7201            Mnemonic::Res,
7202            &DataAccess::Expression(2.into()),
7203            &DataAccess::Register8(Register8::C),
7204            None,
7205            &env
7206        )
7207        .unwrap();
7208
7209        assert_eq!(res.as_ref(), &[0xCB, 0b10010001]);
7210
7211        let env = Env::default();
7212        let res = assemble_bit_res_or_set(
7213            Mnemonic::Res,
7214            &DataAccess::Expression(2.into()),
7215            &DataAccess::MemoryRegister16(Register16::Hl),
7216            None,
7217            &env
7218        )
7219        .unwrap();
7220
7221        assert_eq!(res.as_ref(), &[0xCB, 0b10010110]);
7222
7223        let env = Env::default();
7224        let res = assemble_bit_res_or_set(
7225            Mnemonic::Res,
7226            &DataAccess::Expression(2.into()),
7227            &DataAccess::IndexRegister16WithIndex(IndexRegister16::Ix, 3.into()),
7228            None,
7229            &env
7230        )
7231        .unwrap();
7232
7233        assert_eq!(res.as_ref(), &[DD, 0xCB, 3, 0b10010110]);
7234
7235        let env = Env::default();
7236        let res = assemble_bit_res_or_set(
7237            Mnemonic::Res,
7238            &DataAccess::Expression(2.into()),
7239            &DataAccess::IndexRegister16WithIndex(IndexRegister16::Ix, 3.into()),
7240            Some(&Register8::B),
7241            &env
7242        )
7243        .unwrap();
7244
7245        assert_eq!(res.as_ref(), &[DD, 0xCB, 3, 0b10010000]);
7246    }
7247
7248    #[test]
7249    pub fn test_ld() {
7250        let res = assemble_ld(
7251            &DataAccess::Register16(Register16::De),
7252            &DataAccess::Expression(Expr::Value(0x1234)),
7253            &Env::default()
7254        )
7255        .unwrap();
7256        assert_eq!(res.len(), 3);
7257        assert_eq!(res[0], 0x11);
7258        assert_eq!(res[1], 0x34);
7259        assert_eq!(res[2], 0x12);
7260    }
7261
7262    #[test]
7263    #[should_panic]
7264    pub fn test_ld_fail() {
7265        let _res = assemble_ld(
7266            &DataAccess::Register16(Register16::Af),
7267            &DataAccess::Expression(Expr::Value(0x1234)),
7268            &Env::default()
7269        )
7270        .unwrap();
7271    }
7272
7273    #[test]
7274    pub fn test_ld_r16_r16() {
7275        let res = assemble_ld(
7276            &DataAccess::Register16(Register16::De),
7277            &DataAccess::Register16(Register16::Hl),
7278            &Env::default()
7279        )
7280        .unwrap();
7281        assert_eq!(res.len(), 2);
7282    }
7283
7284    #[test]
7285    pub fn test_repeat() {
7286        let tokens = vec![
7287            Token::Org(0.into(), None),
7288            Token::Repeat(
7289                10.into(),
7290                vec![Token::OpCode(Mnemonic::Nop, None, None, None)].into(),
7291                None,
7292                None
7293            ),
7294        ];
7295
7296        let count = visit_tokens(&tokens).unwrap().size();
7297        assert_eq!(count, 10);
7298    }
7299
7300    #[test]
7301    pub fn test_double_repeat() {
7302        let tokens = vec![
7303            Token::Org(0.into(), None),
7304            Token::Repeat(
7305                10.into(),
7306                vec![Token::Repeat(
7307                    10.into(),
7308                    vec![Token::OpCode(Mnemonic::Nop, None, None, None)].into(),
7309                    None,
7310                    None
7311                )]
7312                .into(),
7313                None,
7314                None
7315            ),
7316        ];
7317
7318        let count = visit_tokens(&tokens).unwrap().size();
7319        assert_eq!(count, 100);
7320    }
7321
7322    #[test]
7323    pub fn test_assemble_logical_operator() {
7324        let operators = [Mnemonic::And, Mnemonic::Or, Mnemonic::Xor];
7325        let operands = [
7326            DataAccess::Register8(Register8::A),
7327            DataAccess::Expression(0.into()),
7328            DataAccess::MemoryRegister16(Register16::Hl),
7329            DataAccess::IndexRegister16WithIndex(IndexRegister16::Ix, 2.into())
7330        ];
7331
7332        for operator in &operators {
7333            for operand in &operands {
7334                let token = Token::OpCode(*operator, Some(operand.clone()), None, None);
7335                visit_tokens(&[token]).unwrap();
7336            }
7337        }
7338    }
7339
7340    #[test]
7341    pub fn test_count() {
7342        let tokens = vec![
7343            Token::Org(0.into(), None),
7344            Token::OpCode(Mnemonic::Nop, None, None, None),
7345            Token::OpCode(Mnemonic::Nop, None, None, None),
7346            Token::OpCode(Mnemonic::Nop, None, None, None),
7347            Token::OpCode(Mnemonic::Nop, None, None, None),
7348            Token::OpCode(Mnemonic::Nop, None, None, None),
7349            Token::OpCode(Mnemonic::Nop, None, None, None),
7350            Token::OpCode(Mnemonic::Nop, None, None, None),
7351            Token::OpCode(Mnemonic::Nop, None, None, None),
7352            Token::OpCode(Mnemonic::Nop, None, None, None),
7353            Token::OpCode(Mnemonic::Nop, None, None, None),
7354        ];
7355
7356        let count = visit_tokens(&tokens).unwrap().size();
7357        assert_eq!(count, 10);
7358    }
7359
7360    #[test]
7361    pub fn test_stableticker() {
7362        let tokens = vec![
7363            Token::StableTicker(StableTickerAction::Start("myticker".into())),
7364            Token::OpCode(
7365                Mnemonic::Inc,
7366                Some(DataAccess::Register16(Register16::Hl)),
7367                None,
7368                None
7369            ),
7370            Token::StableTicker(StableTickerAction::Stop),
7371        ];
7372
7373        let env = visit_tokens(&tokens);
7374        assert!(env.is_ok());
7375        let env = env.unwrap();
7376
7377        let val = env.symbols().int_value("myticker");
7378        assert_eq!(val.unwrap().unwrap(), 2);
7379    }
7380
7381    #[test]
7382    pub fn basic_no_variable() {
7383        let tokens = vec![Token::Basic(None, None, "10 PRINT &DEAD".to_owned())];
7384
7385        let env = visit_tokens(&tokens);
7386        println!("{:?}", env);
7387        assert!(env.is_ok());
7388    }
7389
7390    #[test]
7391    pub fn basic_variable_unset() {
7392        let tokens = vec![Token::Basic(
7393            Some(vec!["STUFF".into()]),
7394            None,
7395            "10 PRINT {STUFF}".to_owned()
7396        )];
7397
7398        let env = visit_tokens(&tokens);
7399        println!("{:?}", env);
7400        assert!(env.is_err());
7401    }
7402
7403    #[test]
7404    pub fn basic_variable_set() {
7405        let tokens = vec![
7406            Token::Label("STUFF".into()),
7407            Token::Basic(Some(vec!["STUFF".into()]), None, "10 PRINT {STUFF}".into()),
7408        ];
7409
7410        let env = visit_tokens(&tokens);
7411        println!("{:?}", env);
7412        assert!(env.is_ok());
7413    }
7414
7415    #[test]
7416    pub fn test_duration() {
7417        let tokens = vec![Token::OpCode(
7418            Mnemonic::Ld,
7419            Some(DataAccess::Register8(Register8::A)),
7420            Some(DataAccess::Expression(Expr::UnaryTokenOperation(
7421                UnaryTokenOperation::Duration,
7422                Box::new(Token::OpCode(
7423                    Mnemonic::Inc,
7424                    Some(DataAccess::Register16(Register16::Hl)),
7425                    None,
7426                    None
7427                ))
7428            ))),
7429            None
7430        )];
7431
7432        let env = visit_tokens(&tokens);
7433        assert!(env.is_ok());
7434        let env = env.unwrap();
7435        let bytes = env.memory(0, 2);
7436        assert_eq!(bytes[1], 2);
7437    }
7438
7439    #[test]
7440    pub fn test_opcode() {
7441        let tokens = vec![Token::OpCode(
7442            Mnemonic::Ld,
7443            Some(DataAccess::Register8(Register8::A)),
7444            Some(DataAccess::Expression(Expr::UnaryTokenOperation(
7445                UnaryTokenOperation::Opcode,
7446                Box::new(Token::OpCode(
7447                    Mnemonic::Inc,
7448                    Some(DataAccess::Register16(Register16::Hl)),
7449                    None,
7450                    None
7451                ))
7452            ))),
7453            None
7454        )];
7455
7456        let env = visit_tokens(&tokens);
7457        assert!(env.is_ok());
7458        let env = env.unwrap();
7459        let bytes = env.memory(0, 2);
7460        assert_eq!(
7461            bytes[1],
7462            assemble_inc_dec(Mnemonic::Inc, &DataAccess::Register16(Register16::Hl), &env).unwrap()
7463                [0]
7464        );
7465    }
7466
7467    #[test]
7468    pub fn test_bytes() {
7469        let mut m = Bytes::new();
7470
7471        add_byte(&mut m, 2);
7472        assert_eq!(m.len(), 1);
7473        assert_eq!(m[0], 2);
7474
7475        add_word(&mut m, 0x1234);
7476        assert_eq!(m.len(), 3);
7477        assert_eq!(m[1], 0x34);
7478        assert_eq!(m[2], 0x12);
7479    }
7480
7481    #[test]
7482    pub fn test_labels() {
7483        let mut env = Env::default();
7484        let res = visit_token(&Token::Org(0x4000.into(), None), &mut env);
7485        assert!(res.is_ok());
7486        assert!(!env.symbols().contains_symbol("hello").unwrap());
7487        let res = visit_token(&Token::Label("hello".into()), &mut env);
7488        assert!(res.is_ok());
7489        assert!(env.symbols().contains_symbol("hello").unwrap());
7490        assert_eq!(env.symbols().int_value("hello").unwrap(), 0x4000.into());
7491    }
7492
7493    #[test]
7494    pub fn test_jr() {
7495        let res = dbg!(visit_tokens_all_passes(
7496            &[
7497                Token::Org(0x4000.into(), None),
7498                Token::OpCode(
7499                    Mnemonic::Jr,
7500                    None,
7501                    Some(DataAccess::Expression(Expr::Label("$".into()))),
7502                    None,
7503                ),
7504            ],
7505            ctx()
7506        ));
7507
7508        assert!(res.is_ok());
7509        let env = res.unwrap();
7510
7511        assert_eq!(
7512            env.memory(0x4000, 2),
7513            &[0x18, 0u8.wrapping_sub(1).wrapping_sub(1)]
7514        );
7515    }
7516
7517    /// Check if  label already exists
7518    #[test]
7519    pub fn label_exists() {
7520        let res = visit_tokens_all_passes(
7521            &[
7522                Token::Org(0x4000.into(), None),
7523                Token::Label("hello".into()),
7524                Token::Label("hello".into())
7525            ],
7526            ctx()
7527        );
7528        assert!(res.is_err());
7529    }
7530
7531    #[test]
7532    pub fn test_rorg() {
7533        let res = visit_tokens_all_passes(
7534            &[
7535                Token::Org(0x4000i32.into(), None),
7536                Token::Rorg(
7537                    0x8000i32.into(),
7538                    vec![Token::Defb(vec![Expr::Label("$".into())])].into()
7539                )
7540            ],
7541            ctx()
7542        );
7543        assert!(res.is_ok());
7544    }
7545
7546    #[test]
7547    pub fn test_two_passes() {
7548        let tokens = vec![
7549            Token::Org(0x123i32.into(), None),
7550            Token::OpCode(
7551                Mnemonic::Ld,
7552                Some(DataAccess::Register16(Register16::Hl)),
7553                Some(DataAccess::Expression(Expr::Label("test".into()))),
7554                None
7555            ),
7556            Token::Label("test".into()),
7557        ];
7558        let env = visit_tokens(&tokens);
7559        assert!(env.is_err());
7560
7561        let env = visit_tokens_all_passes(&tokens, ctx());
7562        assert!(env.is_ok());
7563        let env = env.ok().unwrap();
7564
7565        let count = env.size();
7566        assert_eq!(count, 3);
7567
7568        assert_eq!(
7569            env.symbols()
7570                .int_value(&"test".to_owned())
7571                .unwrap()
7572                .unwrap(),
7573            0x123 + 3
7574        );
7575        let buffer = env.memory(0x123, 3);
7576        assert_eq!(buffer[1], 0x23 + 3);
7577        assert_eq!(buffer[2], 0x1);
7578    }
7579
7580    #[test]
7581    fn test_read_bytes() {
7582        let tokens = vec![
7583            Token::Org(0x100.into(), None),
7584            Token::Defb(vec![1.into(), 2.into()]),
7585            Token::Defb(vec![3.into(), 4.into()]),
7586        ];
7587
7588        let env = visit_tokens(&tokens).unwrap();
7589        let bytes = env.memory(0x100, 4);
7590        assert_eq!(bytes, vec![1, 2, 3, 4]);
7591    }
7592
7593    #[test]
7594    pub fn test_undocumented_rlc() {
7595        let res = visit_tokens_all_passes(
7596            &[
7597                Token::Org(0x100.into(), None),
7598                Token::OpCode(
7599                    Mnemonic::Rlc,
7600                    Some(DataAccess::IndexRegister16WithIndex(
7601                        IndexRegister16::Iy,
7602                        2.into()
7603                    )),
7604                    Some(DataAccess::Register8(Register8::C)),
7605                    None
7606                )
7607            ],
7608            ctx()
7609        );
7610        assert!(res.is_ok());
7611        let env = res.unwrap();
7612        let bytes = env.memory(0x100, 4);
7613        assert_eq!(bytes, vec![0xFD, 0xCB, 0x2, 0x1]);
7614    }
7615
7616    #[test]
7617    pub fn test_undocumented_res() {
7618        // normal case
7619        let res = visit_tokens_all_passes(
7620            &[
7621                Token::Org(0x100.into(), None),
7622                Token::OpCode(
7623                    Mnemonic::Res,
7624                    Some(DataAccess::Expression(4.into())),
7625                    Some(DataAccess::MemoryRegister16(Register16::Hl)),
7626                    None
7627                )
7628            ],
7629            ctx()
7630        );
7631        assert!(res.is_ok());
7632        let env = res.unwrap();
7633        let bytes = env.memory(0x100, 2);
7634        assert_eq!(bytes, vec![0xCB, 0xA6]);
7635
7636        let res = visit_tokens_one_pass(
7637            &[
7638                Token::Org(0x100.into(), None),
7639                Token::OpCode(
7640                    Mnemonic::Res,
7641                    Some(DataAccess::Expression(4.into())),
7642                    Some(DataAccess::IndexRegister16WithIndex(
7643                        IndexRegister16::Iy,
7644                        2.into()
7645                    )),
7646                    Some(Register8::A)
7647                )
7648            ],
7649            ctx()
7650        );
7651        assert!(res.is_ok());
7652        let env = res.unwrap();
7653        let bytes = env.memory(0x100, 4);
7654        assert_eq!(bytes, vec![0xFD, 0xCB, 0x2, 0xA7]);
7655    }
7656}