///|
priv struct WgslPreparedComposeSource {
active_source : String
directive_scan_items : Array[WgslDirectiveScanItem]
importless_source : String
cache_id : Int32
mut unit : WgslTranslationUnit?
mut semantic_facts : WgslComposeSemanticFacts?
mut importless_semantic_facts : WgslComposeSemanticFacts?
}
///|
fn wgsl_redirect_direct_target(
redirects : Array[WgslSymbolRedirect],
name : String,
) -> String? {
let mut target : String? = None
for redirect in redirects {
let from_name = redirect.from_name.trim().to_owned()
let to_name = redirect.to_name.trim().to_owned()
if from_name == name && to_name != "" && from_name != to_name {
target = Some(to_name)
}
}
target
}
///|
fn wgsl_redirect_final_target(
redirects : Array[WgslSymbolRedirect],
from_name : String,
) -> String? {
let seen : Array[String] = []
let mut current = from_name
let mut target : String? = None
while true {
if seen.contains(current) {
break
}
seen.push(current)
match wgsl_redirect_direct_target(redirects, current) {
Some(next) => {
target = Some(next)
current = next
}
None => break
}
}
target
}
///|
fn build_wgsl_redirect_reference_plan(
redirects : Array[WgslSymbolRedirect],
) -> WgslReferenceRewritePlan {
let plan = WgslReferenceRewritePlan()
for redirect in redirects {
let from_name = redirect.from_name.trim().to_owned()
if from_name == "" {
continue
}
match wgsl_redirect_final_target(redirects, from_name) {
Some(to_name) =>
if to_name != "" && to_name != from_name {
match WgslReferencePath::from_text(from_name) {
Some(reference_path) =>
plan.add_symbol_reference_binding(
WgslComposeSymbolIdentity("", from_name),
reference_path,
to_name,
)
None => ()
}
}
None => ()
}
}
plan
}
///|
fn prepare_wgsl_compose_source(
source : String,
rel_path : String,
session : WgslComposeSession,
active_defs : WgslActiveComposeDefs,
) -> WgslPreparedComposeSource raise ComposerError {
if session.redirects.length() > 0 {
let source_facts = collect_wgsl_compose_semantic_facts(session, source)
record_wgsl_redirect_matches(source_facts, session)
}
let redirect_plan = build_wgsl_redirect_reference_plan(session.redirects)
let redirected_source = rewrite_wgsl_references_with_binding_plan(
source, redirect_plan,
) catch {
error => raise composer_error_from_wgsl_parse_error(error)
}
let preprocessed_source = apply_wgsl_template_consts(
apply_wgsl_ifdefs_strict_for_compose(redirected_source, active_defs),
active_defs.value_defines,
)
let relevant_specializations : Array[WgslImmediateSpecialization] = []
let normalized_rel_path = normalize_shader_rel_path(rel_path)
for specialization in session.immediate_specializations {
if normalize_shader_rel_path(specialization.rel_path) == normalized_rel_path {
relevant_specializations.push(specialization)
}
}
let active_source = specialize_wgsl_immediate_globals(
preprocessed_source, relevant_specializations,
) catch {
error => raise ImmediateSpecializationFailed(error.message())
}
ignore(get_preprocessor_metadata(active_source, collect_import_uses=false)) catch {
error => raise composer_error_from_metadata_error(error)
}
prepare_active_wgsl_compose_source(active_source, session)
}
///|
fn parse_wgsl_compose_translation_unit(
source : String,
) -> WgslTranslationUnit raise ComposerError {
parse_wgsl_translation_unit_strict(mask_naga_oil_directives_for_wgsl(source)) catch {
error => raise composer_error_from_wgsl_parse_error(error)
}
}
///|
fn wgsl_compose_semantic_facts_from_unit(
unit : WgslTranslationUnit,
) -> WgslComposeSemanticFacts {
let declarations = collect_wgsl_semantic_declaration_names_from_unit(unit)
let global_variables = collect_wgsl_semantic_global_variable_names_from_unit(
unit,
)
let references : Array[WgslReferencePath] = []
collect_wgsl_semantic_reference_paths_from_unit(unit, references)
WgslComposeSemanticFacts(declarations, global_variables, references)
}
///|
fn prepare_active_wgsl_compose_source(
active_source : String,
session : WgslComposeSession,
) -> WgslPreparedComposeSource {
let directive_scan_items = parse_wgsl_directive_scan_items(
active_source,
include_glsl_version=false,
)
let importless_source = drop_wgsl_import_directives_from_scan_items(
directive_scan_items, active_source,
)
let cache_id = session.source_cache_id(active_source)
ignore(session.source_cache_id(importless_source))
session.directive_scans.set(active_source, directive_scan_items)
session.importless_sources.set(active_source, importless_source)
{
active_source,
directive_scan_items,
importless_source,
cache_id,
unit: None,
semantic_facts: None,
importless_semantic_facts: None,
}
}
///|
fn WgslPreparedComposeSource::translation_unit(
self : WgslPreparedComposeSource,
) -> WgslTranslationUnit raise ComposerError {
match self.unit {
Some(unit) => unit
None => {
let unit = parse_wgsl_compose_translation_unit(self.active_source)
self.unit = Some(unit)
unit
}
}
}
///|
fn WgslPreparedComposeSource::active_semantic_facts(
self : WgslPreparedComposeSource,
session : WgslComposeSession,
) -> WgslComposeSemanticFacts raise ComposerError {
match self.semantic_facts {
Some(facts) => facts
None =>
match session.semantic_facts.get(self.active_source) {
Some(facts) => {
self.semantic_facts = Some(facts)
facts
}
None => {
let facts = wgsl_compose_semantic_facts_from_unit(
self.translation_unit(),
)
self.semantic_facts = Some(facts)
session.semantic_facts.set(self.active_source, facts)
facts
}
}
}
}
///|
fn WgslPreparedComposeSource::reference_scan_semantic_facts(
self : WgslPreparedComposeSource,
session : WgslComposeSession,
) -> WgslComposeSemanticFacts raise ComposerError {
match self.importless_semantic_facts {
Some(facts) => facts
None =>
match session.semantic_facts.get(self.importless_source) {
Some(facts) => {
self.importless_semantic_facts = Some(facts)
facts
}
None =>
if self.importless_source == self.active_source {
let facts = self.active_semantic_facts(session)
self.importless_semantic_facts = Some(facts)
facts
} else {
let unit = parse_wgsl_compose_translation_unit(
self.importless_source,
)
let facts = wgsl_compose_semantic_facts_from_unit(unit)
self.importless_semantic_facts = Some(facts)
session.semantic_facts.set(self.importless_source, facts)
facts
}
}
}
}
///|
fn collect_wgsl_compose_semantic_facts(
session : WgslComposeSession,
source : String,
) -> WgslComposeSemanticFacts raise ComposerError {
match session.semantic_facts.get(source) {
Some(facts) => facts
None => {
let facts = wgsl_compose_semantic_facts_from_unit(
parse_wgsl_compose_translation_unit(source),
)
session.semantic_facts.set(source, facts)
facts
}
}
}
///|
fn WgslComposeSession::directive_scan_items(
self : WgslComposeSession,
source : String,
) -> Array[WgslDirectiveScanItem] {
match self.directive_scans.get(source) {
Some(items) => items
None => {
let items = parse_wgsl_directive_scan_items(
source,
include_glsl_version=false,
)
self.directive_scans.set(source, items)
items
}
}
}