Skip to content

Commit

Permalink
[cpclib-asm] Rework # handling in filenames
Browse files Browse the repository at this point in the history
  • Loading branch information
Krusty/Benediction committed Nov 21, 2024
1 parent 4a4b2c0 commit 5ac62f5
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 59 deletions.
226 changes: 189 additions & 37 deletions cpclib-asm/src/assembler/file.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::{Borrow, Cow};
use std::collections::VecDeque;
use std::fs::File;
use std::io::Read;
Expand All @@ -16,7 +17,7 @@ use crate::error::AssemblerError;
use crate::preamble::ParserOptions;
use crate::progress::Progress;

struct Fname<'a, 'b>(Either<&'a Utf8Path, (&'a str, &'b Env)>);
pub struct Fname<'a, 'b>(Either<&'a Utf8Path, (&'a str, &'b Env)>);

impl<'a, 'b> Deref for Fname<'a, 'b> {
type Target = Either<&'a Utf8Path, (&'a str, &'b Env)>;
Expand Down Expand Up @@ -45,41 +46,191 @@ impl<'a, 'b> From<(&'a str, &'b Env)> for Fname<'a, 'b> {
}
}

/// Separator to split am image disc to a file
pub const DSK_SEPARATOR: char = '#';

pub fn get_filename<S: AsRef<str>>(
fname: S,
options: &ParserOptions,
env: Option<&Env>
) -> Result<Utf8PathBuf, AssemblerError> {
let fname = fname.as_ref();
pub enum AnyFileNameOwned {
InImage { image: String, content: String },
Standard(String)
}

let components = fname.split(DSK_SEPARATOR).collect_vec();
let real_fname = components.first().unwrap();
impl<'fname> From<&AnyFileName<'fname>> for AnyFileNameOwned {
fn from(value: &AnyFileName) -> Self {
match value {
AnyFileName::InImage { image, content } => Self::new_in_image(*image, *content),
AnyFileName::Standard(content) => Self::new_standard(*content),
}
}
}

let res = options.get_path_for(real_fname, env).map_err(|e| {
match e {
either::Either::Left(asm) => asm,
either::Either::Right(tested) => {
AssemblerError::AssemblingError {
msg: format!("{} not found. Tested {:?}", fname, tested)
impl<'fname> From<&'fname AnyFileNameOwned> for AnyFileName<'fname> {
fn from(value: &'fname AnyFileNameOwned) -> Self {
match value {
AnyFileNameOwned::InImage { image, content: amsdos } => {
AnyFileName::InImage {
image: image.as_str(),
content: amsdos.as_str()
}
},
AnyFileNameOwned::Standard(fname) => AnyFileName::Standard(fname.as_str())
}
})?;
}
}

let res = if components.len() == 2 {
let mut s = res.to_string();
s.push(DSK_SEPARATOR);
s.push_str(components.last().unwrap());
Utf8PathBuf::from(&s)
impl From<&str> for AnyFileNameOwned {
fn from(value: &str) -> Self {
let any = AnyFileName::from(value);
AnyFileNameOwned::from(&any)
}
else {
res
};
}


impl AnyFileNameOwned {
pub fn new_standard<S: Into<String>>(fname: S) -> Self {
Self::Standard(fname.into())
}

pub fn new_in_image<S1: Into<String>, S2: Into<String>>(image: S1, amsdos: S2) -> Self {
Self::InImage {
image: image.into(),
content: amsdos.into()
}
}

pub fn as_any_filename(&self) -> AnyFileName {
AnyFileName::from(self)
}
}


/// Helper to handler filenames that contains both a dsk name and a file
pub enum AnyFileName<'fname> {
InImage {
image: &'fname str,
content: &'fname str
},
Standard(&'fname str)
}

impl<'fname> AnyFileName<'fname> {
const DSK_SEPARATOR: char = '#';

pub fn new_standard(fname: &'fname str) -> Self {
Self::Standard(fname)
}

pub fn new_in_image(image: &'fname str, amsdos: &'fname str) -> Self {
Self::InImage { image, content: amsdos }
}

pub fn use_image(&self) -> bool {
match self {
AnyFileName::InImage { .. } => true,
_ => false
}
}


pub fn image_filename(&self) -> Option<&str> {
match self {
AnyFileName::InImage { image, ..} => Some(image),
AnyFileName::Standard(_) => None,
}
}

pub fn content_filename(&self) -> &str {
match self {
AnyFileName::InImage { image, content: amsdos } => amsdos,
AnyFileName::Standard(content) => content,
}
}

pub fn basm_fname(&self) -> Cow<str> {
match self {
AnyFileName::InImage { image, content } => Cow::Owned(format!("{}{}{}", image, Self::DSK_SEPARATOR, content)),
AnyFileName::Standard(content) => Cow::Borrowed(content),
}
}


fn base_filename(&self) -> &str {
match self {
AnyFileName::InImage { image, content: amsdos } => image,
AnyFileName::Standard(f) => f
}
}

pub fn path_for_base_filename(
&self,
options: &ParserOptions,
env: Option<&Env>
) -> Result<Utf8PathBuf, AssemblerError> {
let real_fname = self.base_filename();

let res = options.get_path_for(real_fname, env).map_err(|e| {
match e {
either::Either::Left(asm) => asm,
either::Either::Right(tested) => {
AssemblerError::AssemblingError {
msg: format!("{} not found. Tested {:?}", self.base_filename(), tested)
}
},
}
})?;

let res = if self.image_filename().is_some() {
let mut s = res.to_string();
s.push(Self::DSK_SEPARATOR);
s.push_str(self.content_filename());
Utf8PathBuf::from(&s)
}
else {
res
};

Ok(res)
}
}

impl<'fname> From<&'fname str> for AnyFileName<'fname> {
fn from(fname: &'fname str) -> Self {
const IMAGES_EXT: &[&str] = &[".dsk", ".edsk", ".hfe"];

let components = fname.split(Self::DSK_SEPARATOR).collect_vec();
match &components[..] {
&[fname] => AnyFileName::Standard(fname),
&[first, second] => {
let is_image = IMAGES_EXT
.iter()
.any(|ext| first.to_ascii_lowercase().ends_with(ext));
if is_image {
AnyFileName::InImage {
image: first,
content: second
}
}
else {
AnyFileName::Standard(fname)
}
},
_ => {
todo!(
"Need to handle case where fname as several {}",
Self::DSK_SEPARATOR
)
},
}
}
}

pub fn get_filename_to_read<S: AsRef<str>>(
fname: S,
options: &ParserOptions,
env: Option<&Env>
) -> Result<Utf8PathBuf, AssemblerError> {
let fname = fname.as_ref();

Ok(res)
AnyFileName::from(fname)
.path_for_base_filename(options, env)

}

/// Load a file and remove header if any
Expand All @@ -91,16 +242,17 @@ pub fn load_file<'a, 'b, F: Into<Fname<'a, 'b>>>(
) -> Result<(VecDeque<u8>, Option<AmsdosHeader>), AssemblerError> {
let fname = fname.into();
let true_fname = match &fname.deref() {
either::Either::Right((p, env)) => get_filename(p, options, Some(env))?,
either::Either::Right((p, env)) => get_filename_to_read(p, options, Some(env))?,
either::Either::Left(p) => p.into()
};

let mut parts = true_fname.as_str().split(DSK_SEPARATOR).rev().collect_vec();
let (data, header) = if parts.len() == 1 {
let true_name = true_fname.as_str();
let any_filename: AnyFileName<'_> = true_name.into();
let (data, header) = if !any_filename.use_image() {
// here we handle a standard file

// Get the file content
let data = load_file_raw(fname, options)?;
let data = load_file_raw(any_filename.content_filename(), options)?;
let mut data = VecDeque::from(data);

// get a slice on the data to ease its cut
Expand All @@ -124,14 +276,14 @@ pub fn load_file<'a, 'b, F: Into<Fname<'a, 'b>>>(
}
else {
// here we read from a dsk
let pc_fname = parts.pop().unwrap();
let amsdos_fname = parts.pop().unwrap();
let image_fname = any_filename.image_filename().unwrap();
let amsdos_fname = any_filename.content_filename();

let disc: Box<ExtendedDsk> /* we cannot use Disc ATM */ = if pc_fname.to_ascii_uppercase().ends_with(".DSK") {
Box::new(ExtendedDsk::open(pc_fname).map_err(|e| AssemblerError::AssemblingError { msg: e })?)
let disc: Box<ExtendedDsk> /* we cannot use Disc ATM */ = if image_fname.to_ascii_uppercase().ends_with(".DSK") {
Box::new(ExtendedDsk::open(image_fname).map_err(|e| AssemblerError::AssemblingError { msg: e })?)

} else {
unimplemented!("Need to code loading of {pc_fname}. Disc trait needs to be simplifed by removing all generic parameters :(");
unimplemented!("Need to code loading of {image_fname}. Disc trait needs to be simplifed by removing all generic parameters :(");
};

let manager = AmsdosManagerNonMut::new_from_disc(&disc, Head::A);
Expand Down Expand Up @@ -161,7 +313,7 @@ pub fn load_file_raw<'a, 'b, F: Into<Fname<'a, 'b>>>(

// Retreive fname
let fname = match &fname.deref() {
either::Either::Right((p, env)) => get_filename(p, options, Some(env))?,
either::Either::Right((p, env)) => get_filename_to_read(p, options, Some(env))?,
either::Either::Left(p) => p.into()
};

Expand Down
23 changes: 13 additions & 10 deletions cpclib-asm/src/assembler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use cpclib_common::winnow::stream::UpdateSlice;
use cpclib_disc::built_info;
use cpclib_sna::*;
use cpclib_tokens::ToSimpleToken;
use file::DSK_SEPARATOR;
use file::{AnyFileName, AnyFileNameOwned};
use processed_token::build_processed_token;
use support::banks::DecoratedPages;
use support::cpr::CprAssembler;
Expand Down Expand Up @@ -576,7 +576,7 @@ impl Env {
&mut self.symbols
}

pub fn get_fname<E: ExprEvaluationExt + Debug>(
pub fn build_fname<E: ExprEvaluationExt + Debug>(
&self,
exp: &E
) -> Result<String, AssemblerError> {
Expand Down Expand Up @@ -2905,16 +2905,19 @@ impl Env {
}
}

let amsdos_fname = self.get_fname(amsdos_fname)?;
let (amsdos_fname, dsk_fname) = match dsk_fname {
Some(fname) => (amsdos_fname, Some(self.get_fname(fname)?)),
let amsdos_fname = self.build_fname(amsdos_fname)?;
let any_fname: AnyFileNameOwned = match dsk_fname {
Some(dsk_fname) => AnyFileNameOwned::new_in_image(
self.build_fname(dsk_fname)?, amsdos_fname
),
None => {
let mut parts = amsdos_fname.as_str().split(DSK_SEPARATOR).collect_vec();
let amsdos_fname = parts.pop().unwrap().to_owned();
let dsk_fname = parts.pop().map(ToOwned::to_owned);
(amsdos_fname, dsk_fname)
AnyFileNameOwned::from(amsdos_fname.as_str())
}
};
let any_fname = any_fname.as_any_filename();


let (amsdos_fname, dsk_fname) = (any_fname.content_filename(), any_fname.image_filename());

let amsdos_fname = Utf8PathBuf::from(amsdos_fname);
let dsk_fname = dsk_fname.map(Utf8PathBuf::from);
Expand Down Expand Up @@ -3030,7 +3033,7 @@ impl Env {
&mut self,
fname: &E
) -> Result<(), AssemblerError> {
let fname = self.get_fname(fname)?;
let fname = self.build_fname(fname)?;

if !self.pass.is_first_pass() {
return Ok(());
Expand Down
18 changes: 9 additions & 9 deletions cpclib-asm/src/assembler/processed_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use cpclib_tokens::{
use ouroboros::*;

use super::control::ControlOutputStore;
use super::file::{get_filename, load_file, read_source};
use super::file::{get_filename_to_read, load_file, read_source};
use super::function::{Function, FunctionBuilder};
use super::r#macro::Expandable;
use super::AssemblerWarning;
Expand Down Expand Up @@ -184,7 +184,7 @@ impl IncludeState {
namespace: Option<&str>,
once: bool
) -> Result<(), AssemblerError> {
let fname = get_filename(fname, env.options().parse_options(), Some(env))?;
let fname = get_filename_to_read(fname, env.options().parse_options(), Some(env))?;

let need_to_include = !once || !env.included_marks_includes(&fname);

Expand Down Expand Up @@ -473,9 +473,9 @@ where
else if token.is_include() {
// we cannot use the real method onf IncludeState because it modifies env and here wa cannot
let fname = token.include_fname();
let fname = env.get_fname(fname)?;
let fname = env.build_fname(fname)?;
let options = env.options().parse_options();
match get_filename(fname, options, Some(env)) {
match get_filename_to_read(fname, options, Some(env)) {
Ok(fname) => {
match read_source(fname.clone(), options) {
Ok(content) => {
Expand Down Expand Up @@ -655,8 +655,8 @@ where
.filter(|t| t.include_is_standard_include())
.flat_map(|t| {
let fname = t.include_fname();
let fname = env.get_fname(fname)?;
get_filename(fname, options, Some(env))
let fname = env.build_fname(fname)?;
get_filename_to_read(fname, options, Some(env))
})
.collect::<Vec<_>>();
let include_fnames = include_fnames.iter().map(|t| progress::normalize(t));
Expand Down Expand Up @@ -978,8 +978,8 @@ where

// Handle file loading
let fname = self.token.incbin_fname();
let fname = env.get_fname(fname)?;
let fname = get_filename(fname, options.parse_options(), Some(env))?;
let fname = env.build_fname(fname)?;
let fname = get_filename_to_read(fname, options.parse_options(), Some(env))?;

// get the data for the given file
let data = if !contents.contains_key(&fname) {
Expand Down Expand Up @@ -1078,7 +1078,7 @@ where
},

Some(ProcessedTokenState::Include(ref mut state)) => {
let fname = env.get_fname(self.token.include_fname())?;
let fname = env.build_fname(self.token.include_fname())?;

state.handle(
env,
Expand Down
Loading

0 comments on commit 5ac62f5

Please sign in to comment.