diff --git a/cpclib-asm/src/assembler/mod.rs b/cpclib-asm/src/assembler/mod.rs index 24281598..ec028fec 100644 --- a/cpclib-asm/src/assembler/mod.rs +++ b/cpclib-asm/src/assembler/mod.rs @@ -24,7 +24,7 @@ use std::fmt; use std::fmt::{Debug, Display}; use std::io::{stdout, Write}; use std::ops::Neg; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::{Arc, RwLock}; use std::time::Instant; @@ -351,6 +351,10 @@ impl CharsetEncoding { /// Environment of the assembly #[allow(missing_docs)] pub struct Env { + /// Lookup directory when searching for a file. Must be pushed at each import directive and pop after + lookup_directory_stack: Vec, + + /// Current pass pass: AssemblingPass, options: EnvOptions, @@ -451,6 +455,7 @@ pub struct Env { impl Clone for Env { fn clone(&self) -> Self { Self { + lookup_directory_stack: self.lookup_directory_stack.clone(), options: self.options.clone(), can_skip_next_passes: (*self.can_skip_next_passes.read().unwrap().deref()).into(), request_additional_pass: (*self.request_additional_pass.read().unwrap().deref()).into(), @@ -528,6 +533,7 @@ impl fmt::Debug for Env { impl Default for Env { fn default() -> Self { Self { + lookup_directory_stack: Vec::with_capacity(3), pass: AssemblingPass::Uninitialized, options: EnvOptions::default(), stable_counters: StableTickerCounters::default(), @@ -770,6 +776,33 @@ impl Env { } } + +/// Handle the file search relatively to the current file +impl Env { + fn set_current_working_directory>(&mut self, p: P) { + self.lookup_directory_stack.push(p.into()) + } + + pub fn enter_current_working_file>(&mut self, f: P) { + let f = f.as_ref(); + debug_assert!(f.is_file() || f.starts_with("inner://")); + self.set_current_working_directory(f.parent().unwrap()); + } + + pub fn leave_current_working_file(&mut self) -> Option { + self.lookup_directory_stack.pop() + } + + pub fn get_current_working_directory(&self) -> Option<&Path> { + self.lookup_directory_stack.last() + .map(|p| p.as_path()) + } + + pub fn has_current_working_directory(&self) -> bool { + !self.lookup_directory_stack.is_empty() + } +} + /// Error handling impl Env { /// If the error has not been raised at the previous pass, store it and do not propagate it. Otherwise, propagate it @@ -4086,6 +4119,11 @@ impl Env { else { let label = self.handle_global_and_local_labels(label.as_str())?; + if label.starts_with(".") { + let warning = AssemblerError::AssemblingError { msg: format!("{} is not a local label. A better name without the dot would be better", &label) }; + self.warnings.push(warning); + } + // XXX Disabled behavior the 12/01/2024 // if !label.starts_with('.') { // self.symbols_mut().set_current_label(label)?; diff --git a/cpclib-asm/src/assembler/processed_token.rs b/cpclib-asm/src/assembler/processed_token.rs index 403437a4..804b270a 100644 --- a/cpclib-asm/src/assembler/processed_token.rs +++ b/cpclib-asm/src/assembler/processed_token.rs @@ -122,6 +122,8 @@ struct SwitchState<'token, T: Visited + ListingElement + Debug + Sync> { struct IncludeState(BTreeMap); impl IncludeState { + /// By constructon fname exists and is correct + /// fn retreive_listing( &mut self, env: &mut Env, @@ -170,6 +172,8 @@ impl IncludeState { self.0.get_mut(fname).unwrap() }; + + // handle the listing env.mark_included(fname.clone()); @@ -198,10 +202,13 @@ impl IncludeState { } // Visit the included listing - state.with_processed_tokens_mut(|tokens| { + env.enter_current_working_file(fname); + let res = state.with_processed_tokens_mut(|tokens| { let tokens: &mut [ProcessedToken<'_, LocatedToken>] = &mut tokens[..]; visit_processed_tokens::<'_, LocatedToken>(tokens, env) - })?; + }); + env.leave_current_working_file(); + res?; // Remove module if necessary if namespace.is_some() { diff --git a/cpclib-asm/src/parser/context.rs b/cpclib-asm/src/parser/context.rs index f818141a..18d3e9d2 100644 --- a/cpclib-asm/src/parser/context.rs +++ b/cpclib-asm/src/parser/context.rs @@ -327,16 +327,26 @@ impl ParserOptions { let fname = std::path::Path::new(fname); - // We expect the file to exists if no search_path is provided - if self.search_path.is_empty() { - if fname.is_file() { - return Ok(fname.into()); - } - else { - does_not_exists.push(fname.to_str().unwrap().to_owned()); + // check if file exists + if fname.is_file() { + return Ok(fname.into()); + } + does_not_exists.push(fname.to_str().unwrap().to_owned()); + + // otherwhise, try with the current directory of the environment + if let Some(env) = env.as_ref() { + if let Some(search) = env.get_current_working_directory() { + let current_path = search.join(fname); + if current_path.is_file() { + return Ok(current_path); + } else { + does_not_exists.push(current_path.to_str().unwrap().to_owned()); + } } } - else { + + // otherwhise try with the folder set up at the beginning + { // loop over all possibilities for search in &self.search_path { assert!(std::path::Path::new(&search).is_dir()); diff --git a/cpclib-asm/src/parser/parser.rs b/cpclib-asm/src/parser/parser.rs index 27727448..55066fb5 100644 --- a/cpclib-asm/src/parser/parser.rs +++ b/cpclib-asm/src/parser/parser.rs @@ -2605,7 +2605,7 @@ pub fn parse_conditional(input: &mut InnerZ80Span) -> PResult PResult