CompileNode

This commit is contained in:
Quaternions 2024-07-01 12:39:13 -07:00
parent 581a0d6699
commit 43b5dfd0d5

View File

@ -186,7 +186,12 @@ struct ScriptWithOverrides{
source:String, source:String,
} }
fn extract_script_overrides(mut source:String)->AResult<ScriptWithOverrides>{ pub enum ScriptWithOverridesError{
UnimplementedProperty(String),
}
impl ScriptWithOverrides{
fn from_source(mut source:String)->Result<Self,ScriptWithOverridesError>{
let mut overrides=PropertiesOverride::default(); let mut overrides=PropertiesOverride::default();
let mut count=0; let mut count=0;
for line in source.lines(){ for line in source.lines(){
@ -197,7 +202,7 @@ fn extract_script_overrides(mut source:String)->AResult<ScriptWithOverrides>{
match &captures[1]{ match &captures[1]{
"Name"=>overrides.name=Some(captures[2].to_owned()), "Name"=>overrides.name=Some(captures[2].to_owned()),
"ClassName"=>overrides.class=Some(captures[2].to_owned()), "ClassName"=>overrides.class=Some(captures[2].to_owned()),
other=>Err(anyhow::Error::msg(format!("Unimplemented property {other}")))?, other=>Err(ScriptWithOverridesError::UnimplementedProperty(other.to_owned()))?,
} }
}else{ }else{
break; break;
@ -205,15 +210,50 @@ fn extract_script_overrides(mut source:String)->AResult<ScriptWithOverrides>{
} }
Ok(ScriptWithOverrides{overrides,source:source.split_off(count)}) Ok(ScriptWithOverrides{overrides,source:source.split_off(count)})
} }
}
async fn script_node(search_name:&str,mut file:FileWithName,hint:ScriptHint)->AResult<CompileNode>{ enum CompileClass{
Folder,
Script(String),
LocalScript(String),
ModuleScript(String),
Model(Vec<u8>),
}
struct CompileNode{
name:String,
blacklist:Option<String>,
class:CompileClass,
}
enum CompileNodeError{
IO(std::io::Error),
ScriptWithOverrides(ScriptWithOverridesError),
InvalidHintOrClass(Option<String>,ScriptHint),
QueryResolveError(QueryResolveError),
/// Conversion from OsString to String failed
FileName(std::ffi::OsString),
ExtensionNotSupportedInStyle{
extension:String,
style:Option<DecompileStyle>,
},
NoExtension,
}
enum FileDiscernment{
Model,
Script(ScriptHint),
}
impl CompileNode{
async fn script(search_name:&str,mut file:FileWithName,hint:ScriptHint)->Result<Self,CompileNodeError>{
//read entire file //read entire file
let mut buf=String::new(); let mut buf=String::new();
file.file.read_to_string(&mut buf).await?; file.file.read_to_string(&mut buf).await.map_err(CompileNodeError::IO)?;
//regex script according to Properties lines at the top //regex script according to Properties lines at the top
let script_with_overrides=extract_script_overrides(buf)?; let script_with_overrides=ScriptWithOverrides::from_source(buf).map_err(CompileNodeError::ScriptWithOverrides)?;
//script //script
Ok(CompileNode{ Ok(Self{
blacklist:Some(file.name), blacklist:Some(file.name),
name:script_with_overrides.overrides.name.unwrap_or_else(||search_name.to_owned()), name:script_with_overrides.overrides.name.unwrap_or_else(||search_name.to_owned()),
class:match (script_with_overrides.overrides.class.as_deref(),hint){ class:match (script_with_overrides.overrides.class.as_deref(),hint){
@ -223,24 +263,23 @@ async fn script_node(search_name:&str,mut file:FileWithName,hint:ScriptHint)->AR
|(None,ScriptHint::LocalScript)=>CompileClass::LocalScript(script_with_overrides.source), |(None,ScriptHint::LocalScript)=>CompileClass::LocalScript(script_with_overrides.source),
(Some("Script"),_) (Some("Script"),_)
|(None,ScriptHint::Script)=>CompileClass::Script(script_with_overrides.source), |(None,ScriptHint::Script)=>CompileClass::Script(script_with_overrides.source),
other=>Err(anyhow::Error::msg(format!("Invalid hint or class {other:?}")))?, other=>Err(CompileNodeError::InvalidHintOrClass(other.0.map(|s|s.to_owned()),other.1))?,
}, },
}) })
} }
async fn model(search_name:&str,mut file:FileWithName)->Result<Self,CompileNodeError>{
async fn model_node(search_name:&str,mut file:FileWithName)->AResult<CompileNode>{
//read entire file //read entire file
let mut buf=Vec::new(); let mut buf=Vec::new();
file.file.read_to_end(&mut buf).await?; file.file.read_to_end(&mut buf).await.map_err(CompileNodeError::IO)?;
//model //model
Ok(CompileNode{ Ok(Self{
blacklist:Some(file.name), blacklist:Some(file.name),
name:search_name.to_owned(),//wrong but gets overwritten by internal model name name:search_name.to_owned(),//wrong but gets overwritten by internal model name
class:CompileClass::Model(buf), class:CompileClass::Model(buf),
}) })
} }
async fn locate_override_file(entry:&tokio::fs::DirEntry,style:Option<DecompileStyle>)->AResult<CompileNode>{ async fn from_folder(entry:&tokio::fs::DirEntry,style:Option<DecompileStyle>)->Result<Self,CompileNodeError>{
let contents_folder=entry.path(); let contents_folder=entry.path();
let file_name=entry.file_name(); let file_name=entry.file_name();
let search_name=file_name.to_str().unwrap(); let search_name=file_name.to_str().unwrap();
@ -261,59 +300,47 @@ async fn locate_override_file(entry:&tokio::fs::DirEntry,style:Option<DecompileS
let model_query=get_file_async(contents_folder.clone(),format!("{}.rbxmx",search_name)); let model_query=get_file_async(contents_folder.clone(),format!("{}.rbxmx",search_name));
//model? script? both? //model? script? both?
Ok(match tokio::join!(script_query,model_query){ Ok(match tokio::join!(script_query,model_query){
(Ok(FileHint{file,hint}),Err(QueryResolveError::NotFound))=>script_node(search_name,file,hint).await?, (Ok(FileHint{file,hint}),Err(QueryResolveError::NotFound))=>Self::script(search_name,file,hint).await?,
(Err(QueryResolveError::NotFound),Ok(file))=>model_node(search_name,file).await?, (Err(QueryResolveError::NotFound),Ok(file))=>Self::model(search_name,file).await?,
(Ok(_),Ok(_))=>Err(QueryResolveError::Ambiguous)?, (Ok(_),Ok(_))=>Err(CompileNodeError::QueryResolveError(QueryResolveError::Ambiguous))?,
//neither //neither
(Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound))=>CompileNode{ (Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound))=>Self{
name:search_name.to_owned(), name:search_name.to_owned(),
blacklist:None, blacklist:None,
class:CompileClass::Folder, class:CompileClass::Folder,
}, },
//other error //other error
(Err(e),_) (Err(e),_)
|(_,Err(e))=>Err(e)? |(_,Err(e))=>Err(CompileNodeError::QueryResolveError(e))?
}) })
} }
async fn from_file(entry:&tokio::fs::DirEntry,style:Option<DecompileStyle>)->Result<Self,CompileNodeError>{
enum FileDiscernment{
Model,
Script(ScriptHint),
}
async fn discern_file(entry:&tokio::fs::DirEntry,style:Option<DecompileStyle>)->AResult<CompileNode>{
let mut file_name=entry let mut file_name=entry
.file_name() .file_name()
.into_string() .into_string()
.map_err(|e|anyhow::Error::msg(format!("insane file name {e:?}")))?; .map_err(CompileNodeError::FileName)?;
//reject goobers //reject goobers
let is_goober=match style{ let is_goober=match style{
Some(DecompileStyle::Rojo)=>true, Some(DecompileStyle::Rojo)=>true,
_=>false, _=>false,
}; };
let (ext_len,file_discernment)={ let (ext_len,file_discernment)={
if let Some(captures)=lazy_regex::regex!(r"^.*(.module.lua|.client.lua|.server.lua)$") if let Some(captures)=lazy_regex::regex!(r"^.*(.module.lua|.client.lua|.server.lua|.rbxmx|.lua)$")
.captures(file_name.as_str()){ .captures(file_name.as_str()){
let ext=&captures[1]; let ext=&captures[1];
(ext.len(),match ext{ (ext.len(),match ext{
".module.lua"=>{ ".module.lua"=>{
if is_goober{ if is_goober{
Err(anyhow::Error::msg(format!("File extension {ext} not supported in style {style:?}")))?; Err(CompileNodeError::ExtensionNotSupportedInStyle{extension:ext.to_owned(),style})?;
} }
FileDiscernment::Script(ScriptHint::ModuleScript) FileDiscernment::Script(ScriptHint::ModuleScript)
}, },
".client.lua"=>FileDiscernment::Script(ScriptHint::LocalScript), ".client.lua"=>FileDiscernment::Script(ScriptHint::LocalScript),
".server.lua"=>FileDiscernment::Script(ScriptHint::Script), ".server.lua"=>FileDiscernment::Script(ScriptHint::Script),
_=>panic!("Regex failed"),
})
}else if let Some(captures)=lazy_regex::regex!(r"^.*(.rbxmx|.lua)$")
.captures(file_name.as_str()){
let ext=&captures[1];
(ext.len(),match ext{
".rbxmx"=>{ ".rbxmx"=>{
if is_goober{ if is_goober{
Err(anyhow::Error::msg(format!("File extension {ext} not supported in style {style:?}")))?; Err(CompileNodeError::ExtensionNotSupportedInStyle{extension:ext.to_owned(),style})?;
} }
FileDiscernment::Model FileDiscernment::Model
}, },
@ -321,16 +348,17 @@ async fn discern_file(entry:&tokio::fs::DirEntry,style:Option<DecompileStyle>)->
_=>panic!("Regex failed"), _=>panic!("Regex failed"),
}) })
}else{ }else{
return Err(anyhow::Error::msg("No file extension")); return Err(CompileNodeError::NoExtension);
} }
}; };
file_name.truncate(file_name.len()-ext_len); file_name.truncate(file_name.len()-ext_len);
let file=tokio::fs::File::open(entry.path()).await?; let file=tokio::fs::File::open(entry.path()).await.map_err(CompileNodeError::IO)?;
Ok(match file_discernment{ Ok(match file_discernment{
FileDiscernment::Model=>model_node(file_name.as_str(),FileWithName{file,name:file_name.clone()}).await?, FileDiscernment::Model=>Self::model(file_name.as_str(),FileWithName{file,name:file_name.clone()}).await?,
FileDiscernment::Script(hint)=>script_node(file_name.as_str(),FileWithName{file,name:file_name.clone()},hint).await?, FileDiscernment::Script(hint)=>Self::script(file_name.as_str(),FileWithName{file,name:file_name.clone()},hint).await?,
}) })
} }
}
#[derive(Debug)] #[derive(Debug)]
enum ScriptHint{ enum ScriptHint{
@ -348,20 +376,6 @@ enum PreparedData{
Builder(rbx_dom_weak::InstanceBuilder), Builder(rbx_dom_weak::InstanceBuilder),
} }
enum CompileClass{
Folder,
Script(String),
LocalScript(String),
ModuleScript(String),
Model(Vec<u8>),
}
struct CompileNode{
name:String,
blacklist:Option<String>,
class:CompileClass,
}
enum CompileStackInstruction{ enum CompileStackInstruction{
TraverseReferent(rbx_dom_weak::types::Ref,Option<String>), TraverseReferent(rbx_dom_weak::types::Ref,Option<String>),
PopFolder, PopFolder,
@ -446,8 +460,8 @@ async fn compile(config:CompileConfig,&mut dom:rbx_dom_weak::WeakDom)->Result<()
let met=entry.metadata().await?; let met=entry.metadata().await?;
//discern that bad boy //discern that bad boy
let compile_class=match met.is_dir(){ let compile_class=match met.is_dir(){
true=>locate_override_file(&entry,style).await?, true=>CompileNode::from_folder(&entry,style).await?,
false=>discern_file(&entry,style).await?, false=>CompileNode::from_file(&entry,style).await?,
}; };
//prepare data structure //prepare data structure
Ok(Some((compile_class.blacklist,match compile_class.class{ Ok(Some((compile_class.blacklist,match compile_class.class{