Import type aliases
This commit is contained in:
parent
a9b0eb6abf
commit
b832c5249e
119
src/lib.rs
119
src/lib.rs
|
@ -25,7 +25,7 @@ pub struct Import {
|
|||
imports: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct DefRequirement {
|
||||
/// None if the requirement is local
|
||||
module: Option<String>,
|
||||
|
@ -34,6 +34,7 @@ pub struct DefRequirement {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Definition {
|
||||
#[allow(dead_code)]
|
||||
name: String,
|
||||
requirements: Vec<DefRequirement>,
|
||||
/// The start byte position as a `usize`.
|
||||
|
@ -51,6 +52,7 @@ pub struct Module {
|
|||
/// Constants that this module defines
|
||||
pub vars: HashMap<String, Definition>,
|
||||
pub structs: HashMap<String, Definition>,
|
||||
pub aliases: HashMap<String, Definition>,
|
||||
/// Functions that this module defines
|
||||
pub functions: HashMap<String, Definition>,
|
||||
/// Imports of things per module
|
||||
|
@ -62,6 +64,16 @@ pub struct Module {
|
|||
module_imports: HashSet<String>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
/// Get a definition of any type from this module.
|
||||
pub fn get_definition(&self, name: &str) -> Option<&Definition> {
|
||||
self.functions.get(name)
|
||||
.or_else(|| self.vars.get(name))
|
||||
.or_else(|| self.structs.get(name))
|
||||
.or_else(|| self.aliases.get(name))
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively find files in `path`.
|
||||
pub(crate) fn recurse_files(path: impl AsRef<Path>) -> std::io::Result<Vec<PathBuf>> {
|
||||
let mut buf = vec![];
|
||||
|
@ -138,6 +150,12 @@ fn main() -> vec4<f32> {
|
|||
/// i.e., `simple::some_const`.
|
||||
#[test]
|
||||
fn double_layer_import_indirect_imports() {
|
||||
/* tracing_subscriber::fmt()
|
||||
// enable everything
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
// sets this to be the default, global collector for this application.
|
||||
.init(); */
|
||||
|
||||
let mut p = Processor::new();
|
||||
p.parse_module(&INNER_MODULE).unwrap()
|
||||
.expect("failed to find module");
|
||||
|
@ -151,7 +169,7 @@ fn main() -> vec4<f32> {
|
|||
assert!(out.contains("const simple_scalar"), "definition of imported `const simple_scalar` is missing!");
|
||||
assert!(out.contains("fn do_something_cool("), "definition of imported `fn do_something_cool` is missing!");
|
||||
|
||||
assert!(out.contains("const scalar"), "definition of imported dependency, `const scalar` is missing!");
|
||||
assert!(out.contains("const scalar"), "definition of imported dependency, `const scalar` is missing! {}", out);
|
||||
assert!(out.contains("fn mult_some_nums("), "definition of imported dependency, `fn mult_some_nums` is missing!");
|
||||
|
||||
assert!(out.contains("fn do_something_cool("), "definition of imported `fn do_something_cool` is missing!");
|
||||
|
@ -181,11 +199,11 @@ fn main() -> vec4<f32> {
|
|||
return vec4<f32>(1.0);
|
||||
}"#;
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
/* tracing_subscriber::fmt()
|
||||
// enable everything
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
// sets this to be the default, global collector for this application.
|
||||
.init();
|
||||
.init(); */
|
||||
|
||||
let mut p = Processor::new();
|
||||
p.parse_module(BINDINGS_MODULE).unwrap()
|
||||
|
@ -222,11 +240,11 @@ fn main() -> vec4<f32> {
|
|||
return vec4<f32>(1.0);
|
||||
}"#;
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
/* tracing_subscriber::fmt()
|
||||
// enable everything
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
// sets this to be the default, global collector for this application.
|
||||
.init();
|
||||
.init(); */
|
||||
|
||||
let mut p = Processor::new();
|
||||
p.parse_module(BINDINGS_MODULE).unwrap()
|
||||
|
@ -272,11 +290,11 @@ fn main() -> vec4<f32> {
|
|||
return vec4<f32>(1.0);
|
||||
}"#;
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
/* tracing_subscriber::fmt()
|
||||
// enable everything
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
// sets this to be the default, global collector for this application.
|
||||
.init();
|
||||
.init(); */
|
||||
|
||||
let mut p = Processor::new();
|
||||
p.parse_module(BINDINGS_MODULE).unwrap()
|
||||
|
@ -315,11 +333,11 @@ fn main() -> vec4<f32> {
|
|||
return vec4<f32>(1.0);
|
||||
}"#;
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
/* tracing_subscriber::fmt()
|
||||
// enable everything
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
// sets this to be the default, global collector for this application.
|
||||
.init();
|
||||
.init(); */
|
||||
|
||||
let mut p = Processor::new();
|
||||
p.parse_module(BINDINGS_MODULE).unwrap()
|
||||
|
@ -363,11 +381,11 @@ fn main() -> vec4<f32> {
|
|||
return vec4<f32>(1.0);
|
||||
}"#;
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
/* tracing_subscriber::fmt()
|
||||
// enable everything
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
// sets this to be the default, global collector for this application.
|
||||
.init();
|
||||
.init(); */
|
||||
|
||||
let mut p = Processor::new();
|
||||
p.parse_module(TYPE_MODULE).unwrap()
|
||||
|
@ -384,4 +402,81 @@ fn main() -> vec4<f32> {
|
|||
assert!(out.contains("struct Light"), "missing `Light` struct definition: {}", out);
|
||||
assert!(out.contains("struct Something"), "missing `Something` struct definition: {}", out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_type_alias() {
|
||||
const TYPE_MODULE: &'static str =
|
||||
r#"#define_module engine::types
|
||||
|
||||
alias LightIntensity = f32;"#;
|
||||
|
||||
const IMPORTING_MODULE: &'static str =
|
||||
r#"#define_module engine::main
|
||||
#import engine::types::{LightIntensity}
|
||||
|
||||
fn main() -> vec4<f32> {
|
||||
// imports must be used to be generated
|
||||
let intensity: LightIntensity = 1.0;
|
||||
|
||||
return vec4<f32>(1.0);
|
||||
}"#;
|
||||
|
||||
/* tracing_subscriber::fmt()
|
||||
// enable everything
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
// sets this to be the default, global collector for this application.
|
||||
.init(); */
|
||||
|
||||
let mut p = Processor::new();
|
||||
p.parse_module(TYPE_MODULE).unwrap()
|
||||
.expect("failed to find bindings module def");
|
||||
let importing_mod = p.parse_module(IMPORTING_MODULE).unwrap()
|
||||
.expect("failed to find main module def");
|
||||
|
||||
let out = p.process_file(&importing_mod, &IMPORTING_MODULE).unwrap();
|
||||
assert!(out.contains("alias LightIntensity"), "missing `LightIntensity` type alias: {}", out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_type_alias_with_imports() {
|
||||
const TYPE_MODULE: &'static str =
|
||||
r#"#define_module engine::types
|
||||
|
||||
alias Number = f32;"#;
|
||||
|
||||
const LIGHT_MODULE: &'static str =
|
||||
r#"#define_module engine::light
|
||||
#import engine::types::{Number}
|
||||
|
||||
alias LightIntensity = Number;"#;
|
||||
|
||||
const IMPORTING_MODULE: &'static str =
|
||||
r#"#define_module engine::main
|
||||
#import engine::light::{LightIntensity}
|
||||
|
||||
fn main() -> vec4<f32> {
|
||||
// imports must be used to be generated
|
||||
let intensity: LightIntensity = 1.0;
|
||||
|
||||
return vec4<f32>(1.0);
|
||||
}"#;
|
||||
|
||||
/* tracing_subscriber::fmt()
|
||||
// enable everything
|
||||
.with_max_level(tracing::Level::TRACE)
|
||||
// sets this to be the default, global collector for this application.
|
||||
.init(); */
|
||||
|
||||
let mut p = Processor::new();
|
||||
p.parse_module(TYPE_MODULE).unwrap()
|
||||
.expect("failed to find bindings module def");
|
||||
p.parse_module(LIGHT_MODULE).unwrap()
|
||||
.expect("failed to find bindings module def");
|
||||
let importing_mod = p.parse_module(IMPORTING_MODULE).unwrap()
|
||||
.expect("failed to find main module def");
|
||||
|
||||
let out = p.process_file(&importing_mod, &IMPORTING_MODULE).unwrap();
|
||||
assert!(out.contains("alias LightIntensity"), "missing `LightIntensity` type alias: {}", out);
|
||||
assert!(out.contains("alias Number"), "missing `Number` type alias: {}", out);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,11 +427,11 @@ impl Processor {
|
|||
},
|
||||
Rule::shader_struct_def => {
|
||||
let mut struct_inner = line.clone().into_inner();
|
||||
|
||||
let struct_name = struct_inner.next().unwrap();
|
||||
|
||||
// iterate through fields in struct
|
||||
let mut requirements = vec![];
|
||||
while let (Some(ident), Some(field_ty)) = (struct_inner.next(), struct_inner.next()) {
|
||||
while let (Some(_), Some(field_ty)) = (struct_inner.next(), struct_inner.next()) {
|
||||
//panic!("got {} of type {}", ident.as_str(), field_ty.as_str());
|
||||
let mut ty_inner = field_ty.into_inner();
|
||||
let ty_inner = ty_inner.next().unwrap();
|
||||
|
@ -459,6 +459,33 @@ impl Processor {
|
|||
end_pos,
|
||||
});
|
||||
},
|
||||
Rule::shader_type_alias_def => {
|
||||
let mut inner = line.clone().into_inner();
|
||||
|
||||
// get rules
|
||||
let alias_name = inner.next().unwrap();
|
||||
let alias_to = inner.next().unwrap();
|
||||
|
||||
// get the requirements of the alias if there are any
|
||||
let requirements = if let Some(req) = get_external_var_requirement(&module, alias_to) {
|
||||
debug!("Type req: {}", req.name);
|
||||
vec![req]
|
||||
} else { vec![] };
|
||||
|
||||
let aname = alias_name.as_str().to_string();
|
||||
debug!("Type alias `{}`", aname);
|
||||
|
||||
let line_span = line.as_span();
|
||||
let start_pos = line_span.start();
|
||||
let end_pos = line_span.end();
|
||||
|
||||
module.aliases.insert(aname.clone(), Definition {
|
||||
name: aname,
|
||||
requirements,
|
||||
start_pos,
|
||||
end_pos,
|
||||
});
|
||||
},
|
||||
Rule::cws => (),
|
||||
Rule::newline => (),
|
||||
_ => unimplemented!("ran into unhandled rule: ({:?}) {:?}", line.as_rule(), line.as_span())
|
||||
|
@ -631,7 +658,7 @@ impl Processor {
|
|||
}
|
||||
|
||||
fn try_find_requirement_module(module: &Module, req_name: &str) -> Option<String> {
|
||||
//debug!("imports: {:?}", module.item_imports.values());
|
||||
debug!("looking for '{}' in module '{}' that imports: {:?}", req_name, module.name, module.item_imports.values());
|
||||
//debug!("Module: {}, req: {}", module.name, req_name);
|
||||
|
||||
for import in module.item_imports.values() {
|
||||
|
@ -647,10 +674,10 @@ fn try_find_requirement_module(module: &Module, req_name: &str) -> Option<String
|
|||
}
|
||||
|
||||
//#[instrument(fields(module = module.name, require=tracing::field::Empty), skip_all)]
|
||||
fn compile_definitions(modules: &HashMap<String, Module>, module: &Module, compiled_modules: &mut HashSet<String>, output: &mut String) -> Result<(), PreprocessorError> {
|
||||
let e = debug_span!("compile_definitions", module = module.name, require = tracing::field::Empty).entered();
|
||||
fn compile_definitions(modules: &HashMap<String, Module>, module: &Module, compiled_definitions: &mut HashSet<DefRequirement>, output: &mut String) -> Result<(), PreprocessorError> {
|
||||
let e = debug_span!("compile_definitions", module = module.name, require = tracing::field::Empty, sub_require = tracing::field::Empty).entered();
|
||||
|
||||
let defs = module.functions.iter().chain(module.vars.iter()).chain(module.structs.iter());
|
||||
let defs = module.functions.iter().chain(module.vars.iter()).chain(module.structs.iter()).chain(module.aliases.iter());
|
||||
for (_, funcs) in defs { //&module.functions {
|
||||
let mut requirements = VecDeque::from(funcs.requirements.clone());
|
||||
|
||||
|
@ -668,34 +695,43 @@ fn compile_definitions(modules: &HashMap<String, Module>, module: &Module, compi
|
|||
.unwrap_or_else(|| panic!("invalid module import: {}", module_name));
|
||||
|
||||
// get the definition from the module that defines the import
|
||||
let req_def = req_module.functions.get(&req.name)
|
||||
.or_else(|| req_module.vars.get(&req.name))
|
||||
.or_else(|| req_module.structs.get(&req.name))
|
||||
let req_def = req_module.get_definition(&req.name)
|
||||
.unwrap_or_else(|| panic!("invalid import: {} from {}", req.name, module_name));
|
||||
|
||||
|
||||
if !req_def.requirements.is_empty() {
|
||||
for sub in &req_def.requirements {
|
||||
let sub_module = sub.module.clone().or_else(|| try_find_requirement_module(&module, &req.name));
|
||||
for mut sub in req_def.requirements.clone() {
|
||||
e.record("sub_require", sub.name.clone());
|
||||
|
||||
if let Some(sub_mod) = &sub_module {
|
||||
if !compiled_modules.contains(sub_mod) {
|
||||
//panic!("NEED TO COMPILE");
|
||||
compiled_modules.insert(sub_mod.clone());
|
||||
println!("searching for sub requirement module in module: '{}'", req_module.name);
|
||||
|
||||
if sub.module.is_none() {
|
||||
sub.module = try_find_requirement_module(&req_module, &sub.name);
|
||||
}
|
||||
|
||||
if let Some(sub_mod) = &sub.module {
|
||||
if !compiled_definitions.contains(&sub) {
|
||||
compiled_definitions.insert(sub.clone());
|
||||
|
||||
let sub_mod = modules.get(sub_mod).expect("unknown module from import");
|
||||
debug!("found sub requirement module: {}", sub_mod.name);
|
||||
let module_name = &sub_mod.name;
|
||||
|
||||
/* let sub_req_names: Vec<String> = req_def.requirements.iter().map(|r| r.name.clone()).collect();
|
||||
debug!("Found requirement: {}, with the following sub-requirements: {:?} from {}", req_def.name, sub_req_names, req_module.name); */
|
||||
|
||||
let mut requirements_output = String::new();
|
||||
compile_definitions(modules, sub_mod, compiled_modules, &mut requirements_output)?;
|
||||
compile_definitions(modules, sub_mod, compiled_definitions, &mut requirements_output)?;
|
||||
|
||||
output.write_fmt(format_args!("\n// REQUIREMENTS OF {}::{}\n", module_name, req.name))?;
|
||||
output.push_str(&requirements_output);
|
||||
output.push_str("\n");
|
||||
|
||||
// find the definition of the sub requirement
|
||||
let sub_def = sub_mod.get_definition(&sub.name)
|
||||
.unwrap_or_else(|| panic!("invalid import: {} from {}", req.name, module_name));
|
||||
|
||||
// write the source of the sub requirement to the output
|
||||
let req_src = &sub_mod.src[sub_def.start_pos..sub_def.end_pos];
|
||||
output.write_fmt(format_args!("// SOURCE {}::{}\n", module_name, sub.name))?;
|
||||
output.push_str(req_src);
|
||||
output.push_str("\n");
|
||||
} else {
|
||||
debug!("Requirement module is already compiled, skipping...");
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ shader_value = { shader_value_bool | shader_value_num }
|
|||
|
||||
shader_var_type = { ":" ~ ws* ~ (shader_external_variable | shader_type) }
|
||||
shader_const_def = { "const" ~ ws ~ shader_ident ~ (ws* ~ shader_var_type)? ~ ws* ~ "=" ~ ws* ~ shader_value ~ ";" }
|
||||
shader_type_alias_def = { ("alias" | "type") ~ ws ~ shader_ident ~ ws* ~ "=" ~ ws* ~ (shader_external_variable | shader_type) ~ ";" }
|
||||
shader_struct_def = {
|
||||
"struct" ~ ws ~ shader_ident ~ ws* ~ "{" ~ NEWLINE ~
|
||||
ws* ~ shader_ident ~ shader_var_type ~
|
||||
|
@ -44,7 +45,6 @@ shader_struct_def = {
|
|||
","? ~ NEWLINE? ~
|
||||
"}"
|
||||
}
|
||||
shader_type_alias_def = { "alias" ~ ws ~ shader_ident ~ ws* ~ "=" ~ ws* ~ (shader_external_variable | shader_type) ~ ";" }
|
||||
|
||||
shader_group_binding = { "@group(" ~ NUMBER ~ ") @binding(" ~ NUMBER ~ ")" }
|
||||
shader_binding_var_constraint = {
|
||||
|
|
Loading…
Reference in New Issue