///|
fn wgsl_shader_def_value_cache_text(value : ShaderDefValue) -> String {
match value {
Bool(flag) => "b:\{flag}"
Int(value) => "i:\{value}"
UInt(value) => "u:\{value}"
Raw(value) => "r:\{value.length()}:\{value}"
}
}
///|
fn wgsl_active_defs_cache_key(
rel_path : String,
active_defs : WgslActiveComposeDefs,
) -> String {
"\{normalize_shader_rel_path(rel_path)}|\{active_defs.cache_text()}"
}
///|
fn wgsl_redirects_cache_text(redirects : Array[WgslSymbolRedirect]) -> String {
if redirects.length() == 0 {
return ""
}
let entries : Array[String] = []
for redirect in redirects {
let from_name = redirect.from_name.trim().to_owned()
let to_name = redirect.to_name.trim().to_owned()
entries.push(
"\{from_name.length()}:\{from_name}->\{to_name.length()}:\{to_name}",
)
}
entries.join("|")
}
///|
fn wgsl_processed_module_cache_key(
rel_path : String,
active_defs : WgslActiveComposeDefs,
session : WgslComposeSession,
) -> String {
"\{wgsl_active_defs_cache_key(rel_path, active_defs)}|redirects:\{wgsl_redirects_cache_text(session.redirects)}|immediates:\{wgsl_immediate_specializations_cache_text(rel_path, session)}"
}
///|
fn wgsl_immediate_specializations_cache_text(
rel_path : String,
session : WgslComposeSession,
) -> String {
let normalized_rel_path = normalize_shader_rel_path(rel_path)
let entries : Array[String] = []
for specialization in session.immediate_specializations {
if normalize_shader_rel_path(specialization.rel_path) != normalized_rel_path {
continue
}
let fields : Array[String] = []
for entry in specialization.field_values.iter() {
let (field_name, value) = entry
fields.push("\{field_name}=\{wgsl_shader_def_value_cache_text(value)}")
}
fields.sort()
entries.push("\{specialization.global_name}{\{fields.join("|")}}")
}
entries.sort()
entries.join("|")
}
///|
fn WgslActiveComposeDefs::cache_text(self : WgslActiveComposeDefs) -> String {
match self.cache_text {
Some(text) => text
None => {
let text = self.compute_cache_text()
self.cache_text = Some(text)
text
}
}
}
///|
fn WgslActiveComposeDefs::compute_cache_text(
self : WgslActiveComposeDefs,
) -> String {
let entries : Array[String] = []
for entry in self.shader_defs.iter() {
let (name, value) = entry
entries.push("\{name}=\{wgsl_shader_def_value_cache_text(value)}")
}
entries.sort()
entries.join("|")
}
///|
fn collect_wgsl_naga_pull_ranks(
origins : Array[WgslModuleItemOrigin],
) -> Map[String, Int32] {
let ranks : Map[String, Int32] = Map([])
for origin in origins {
if origin.name() != "" && !ranks.contains(origin.name()) {
ranks.set(origin.name(), origin.source_start())
}
}
ranks
}
///|
fn collect_wgsl_source_decl_ranks(
extraction : WgslModuleItemExtraction,
) -> Map[String, Int32] {
let ranks : Map[String, Int32] = Map([])
let origins = extraction.origins()
for i in 0.. String {
let items : Array[String] = []
for item in requested_items {
items.push(item)
}
items.sort()
items.join("|")
}
///|
fn WgslProcessedComposeModule::translation_unit(
self : WgslProcessedComposeModule,
) -> WgslTranslationUnit raise ComposerError {
match self.unit {
Some(unit) => unit
None => {
let unit = self.prepared.translation_unit()
self.unit = Some(unit)
unit
}
}
}
///|
fn WgslProcessedComposeModule::declaration_map(
self : WgslProcessedComposeModule,
) -> Map[String, WgslGlobalDecl] raise ComposerError {
match self.declarations_by_name {
Some(declarations) => declarations
None => {
let declarations : Map[String, WgslGlobalDecl] = Map([])
for declaration in self.translation_unit().declarations() {
let name = declaration.name()
if name != "" && !declarations.contains(name) {
declarations.set(name, declaration)
}
}
self.declarations_by_name = Some(declarations)
declarations
}
}
}
///|
fn wgsl_processed_name_after_keyword(
tokens : Array[WgslToken],
start : Int32,
) -> String? {
let mut index = start
let mut angle_depth = 0
while index < tokens.length() {
let token = tokens[index]
if token.is_punctuation(59) || token.is_punctuation(123) {
return None
}
if token.is_punctuation(60) {
angle_depth = angle_depth + 1
} else if token.is_punctuation(62) {
if angle_depth > 0 {
angle_depth = angle_depth - 1
}
} else if angle_depth == 0 {
match token.identifier_text() {
Some(name) => return Some(name)
None => ()
}
}
index = index + 1
}
None
}
///|
fn wgsl_processed_summary_insert(
summaries : Map[String, WgslProcessedDeclarationSummary],
name : String?,
kind : WgslProcessedDeclarationKind,
has_resource_binding : Bool,
) -> Unit {
match name {
Some(name) if name != "" && !summaries.contains(name) =>
summaries.set(name, { kind, has_resource_binding, })
_ => ()
}
}
///|
fn WgslProcessedComposeModule::scan_declaration_summaries(
self : WgslProcessedComposeModule,
) -> Map[String, WgslProcessedDeclarationSummary] {
let summaries : Map[String, WgslProcessedDeclarationSummary] = Map([])
let source = self.prepared.active_source
let tokens = tokenize_wgsl(replace_comments(source), false)
let mut brace_depth = 0
let mut pending_group = false
let mut pending_binding = false
let mut index = 0
while index < tokens.length() {
let token = tokens[index]
if token.is_punctuation(35) {
let line_end = wgsl_line_end(source, token.pos())
while index < tokens.length() && tokens[index].pos() < line_end {
index = index + 1
}
continue
}
if token.is_punctuation(123) {
brace_depth = brace_depth + 1
index = index + 1
continue
}
if token.is_punctuation(125) {
if brace_depth > 0 {
brace_depth = brace_depth - 1
}
index = index + 1
continue
}
if brace_depth != 0 {
index = index + 1
continue
}
if token.is_punctuation(64) && index + 1 < tokens.length() {
let attr = tokens[index + 1]
if attr.is_identifier("group") {
pending_group = true
} else if attr.is_identifier("binding") {
pending_binding = true
}
index = index + 1
continue
}
if token.is_punctuation(59) {
pending_group = false
pending_binding = false
index = index + 1
continue
}
match token.identifier_text() {
Some("struct") => {
wgsl_processed_summary_insert(
summaries,
wgsl_processed_name_after_keyword(tokens, index + 1),
SummaryType,
false,
)
pending_group = false
pending_binding = false
}
Some("alias") | Some("type") => {
wgsl_processed_summary_insert(
summaries,
wgsl_processed_name_after_keyword(tokens, index + 1),
SummaryType,
false,
)
pending_group = false
pending_binding = false
}
Some("const") => {
wgsl_processed_summary_insert(
summaries,
wgsl_processed_name_after_keyword(tokens, index + 1),
SummaryConstant,
false,
)
pending_group = false
pending_binding = false
}
Some("override") =>
if index + 1 < tokens.length() && tokens[index + 1].is_identifier("fn") {
wgsl_processed_summary_insert(
summaries,
wgsl_processed_name_after_keyword(tokens, index + 2),
SummaryFunction,
false,
)
pending_group = false
pending_binding = false
} else {
wgsl_processed_summary_insert(
summaries,
wgsl_processed_name_after_keyword(tokens, index + 1),
SummaryOverride,
false,
)
pending_group = false
pending_binding = false
}
Some("virtual") =>
if index + 1 < tokens.length() && tokens[index + 1].is_identifier("fn") {
wgsl_processed_summary_insert(
summaries,
wgsl_processed_name_after_keyword(tokens, index + 2),
SummaryFunction,
false,
)
pending_group = false
pending_binding = false
}
Some("fn") => {
wgsl_processed_summary_insert(
summaries,
wgsl_processed_name_after_keyword(tokens, index + 1),
SummaryFunction,
false,
)
pending_group = false
pending_binding = false
}
Some("var") => {
wgsl_processed_summary_insert(
summaries,
wgsl_processed_name_after_keyword(tokens, index + 1),
SummaryGlobalVariable,
pending_group && pending_binding,
)
pending_group = false
pending_binding = false
}
_ => ()
}
index = index + 1
}
summaries
}
///|
fn WgslProcessedComposeModule::declaration_summary_map(
self : WgslProcessedComposeModule,
) -> Map[String, WgslProcessedDeclarationSummary] {
match self.declaration_summaries {
Some(summaries) => summaries
None => {
let summaries = self.scan_declaration_summaries()
self.declaration_summaries = Some(summaries)
summaries
}
}
}
///|
fn WgslProcessedComposeModule::declaration_summary(
self : WgslProcessedComposeModule,
name : String,
) -> WgslProcessedDeclarationSummary? {
self.declaration_summary_map().get(name)
}
///|
fn WgslProcessedComposeModule::module_item_extractor(
self : WgslProcessedComposeModule,
) -> WgslModuleItemExtractor raise ComposerError {
match self.item_extractor {
Some(extractor) => extractor
None => {
let extractor = new_wgsl_module_item_extractor_from_unit(
self.prepared.active_source,
self.translation_unit(),
)
self.item_extractor = Some(extractor)
extractor
}
}
}
///|
fn WgslProcessedComposeModule::declares_all_items(
self : WgslProcessedComposeModule,
requested_items : Array[String],
) -> Bool raise ComposerError {
let declarations = self.declaration_map()
for item in requested_items {
if !declarations.contains(item) {
return false
}
}
true
}
///|
fn WgslProcessedComposeModule::declares_non_resource_dependency_item(
self : WgslProcessedComposeModule,
item_name : String,
referenced : Bool,
) -> Bool {
if !referenced {
return false
}
match self.declaration_summary(item_name) {
Some(summary) =>
match summary.kind {
SummaryType | SummaryConstant | SummaryOverride | SummaryFunction =>
true
SummaryGlobalVariable => false
}
None => false
}
}
///|
fn WgslProcessedComposeModule::declares_const_side_effect_item(
self : WgslProcessedComposeModule,
item_name : String,
) -> Bool {
match self.declaration_summary(item_name) {
Some(summary) =>
match summary.kind {
SummaryConstant | SummaryOverride => true
_ => false
}
None => false
}
}
///|
fn WgslProcessedComposeModule::resource_side_effect_items(
self : WgslProcessedComposeModule,
candidate_items : Array[String],
) -> Array[String] {
let items : Array[String] = []
for candidate_item in candidate_items {
match self.declaration_summary(candidate_item) {
Some(summary) =>
if summary.kind == SummaryGlobalVariable && summary.has_resource_binding {
composer_string_list_push_unique(items, candidate_item)
}
None => ()
}
}
items
}
///|
fn WgslProcessedComposeModule::const_side_effect_items(
self : WgslProcessedComposeModule,
candidate_items : Array[String],
) -> Array[String] {
let items : Array[String] = []
for candidate_item in candidate_items {
if self.declares_const_side_effect_item(candidate_item) {
composer_string_list_push_unique(items, candidate_item)
}
}
items
}
///|
fn WgslProcessedComposeModule::imports_for_override_side_effect(
self : WgslProcessedComposeModule,
) -> Bool {
match self.has_override_function {
Some(found) => found
None => {
self.scan_function_qualifier_flags()
match self.has_override_function {
Some(found) => found
None => false
}
}
}
}
///|
fn WgslProcessedComposeModule::imports_for_virtual_side_effect(
self : WgslProcessedComposeModule,
) -> Bool {
match self.has_virtual_function {
Some(found) => found
None => {
self.scan_function_qualifier_flags()
match self.has_virtual_function {
Some(found) => found
None => false
}
}
}
}
///|
fn WgslProcessedComposeModule::scan_function_qualifier_flags(
self : WgslProcessedComposeModule,
) -> Unit {
let may_have_override = self.prepared.active_source.contains("override")
let may_have_virtual = self.prepared.active_source.contains("virtual")
if !may_have_override && !may_have_virtual {
self.has_override_function = Some(false)
self.has_virtual_function = Some(false)
return
}
let tokens = tokenize_wgsl(
replace_comments(self.prepared.active_source),
false,
)
let mut has_override = false
let mut has_virtual = false
let mut depth = 0
let mut index = 0
while index < tokens.length() {
let token = tokens[index]
if token.is_punctuation(123) {
depth = depth + 1
index = index + 1
continue
}
if token.is_punctuation(125) {
if depth > 0 {
depth = depth - 1
}
index = index + 1
continue
}
if depth == 0 && index + 1 < tokens.length() {
let next = tokens[index + 1]
if next.is_identifier("fn") {
if may_have_override && token.is_identifier("override") {
has_override = true
} else if may_have_virtual && token.is_identifier("virtual") {
has_virtual = true
}
if (!may_have_override || has_override) &&
(!may_have_virtual || has_virtual) {
break
}
}
}
index = index + 1
}
self.has_override_function = Some(has_override)
self.has_virtual_function = Some(has_virtual)
}
///|
fn WgslProcessedComposeModule::virtual_override_target_names(
self : WgslProcessedComposeModule,
) -> Array[String] raise ComposerError {
match self.virtual_override_targets {
Some(targets) => targets.copy()
None => {
let targets : Array[String] = []
for declaration in self.translation_unit().declarations() {
match declaration.data() {
Function(function) if function.qualifier() == Some(Override) => {
let name = function.name().name()
if name != "" {
targets.push(name)
}
}
_ => ()
}
}
self.virtual_override_targets = Some(targets.copy())
targets
}
}
}
///|
fn WgslProcessedComposeModule::item_extraction(
self : WgslProcessedComposeModule,
requested_items : Array[String],
) -> WgslModuleItemExtraction raise ComposerError {
let key = wgsl_item_extraction_cache_key(requested_items)
match self.item_extractions.get(key) {
Some(extraction) => extraction
None => {
let extraction = self.module_item_extractor().extract(requested_items)
self.item_extractions.set(key, extraction)
extraction
}
}
}
///|
fn WgslProcessedComposeModule::semantic_declaration_names(
self : WgslProcessedComposeModule,
) -> Array[String] raise ComposerError {
match self.declaration_names {
Some(names) => names
None => {
let names = collect_wgsl_semantic_declaration_names_from_unit(
self.translation_unit(),
)
self.declaration_names = Some(names)
names
}
}
}
///|
fn WgslComposeSession::record_processed_semantic_facts(
self : WgslComposeSession,
processed : WgslProcessedComposeModule,
) -> Unit raise ComposerError {
let active_source = processed.prepared.active_source
match self.semantic_facts.get(active_source) {
Some(_) => ()
None =>
self.semantic_facts.set(
active_source,
processed.prepared.active_semantic_facts(self),
)
}
let importless_source = processed.prepared.importless_source
if importless_source != active_source {
match self.semantic_facts.get(importless_source) {
Some(_) => ()
None =>
self.semantic_facts.set(
importless_source,
processed.prepared.reference_scan_semantic_facts(self),
)
}
}
}
///|
fn WgslProcessedComposeModule::naga_dependency_pull_ranks(
self : WgslProcessedComposeModule,
) -> Map[String, Int32] raise ComposerError {
match self.naga_pull_ranks {
Some(ranks) => ranks
None => {
let ranks = collect_wgsl_naga_pull_ranks(
self.module_item_extractor().naga_dependency_pulled_item_origins(),
)
self.naga_pull_ranks = Some(ranks)
ranks
}
}
}
///|
fn WgslProcessedComposeModule::declaration_source_ranks(
self : WgslProcessedComposeModule,
) -> Map[String, Int32] raise ComposerError {
match self.source_decl_ranks {
Some(ranks) => ranks
None => {
let ranks = collect_wgsl_source_decl_ranks(self.item_extraction([]))
self.source_decl_ranks = Some(ranks)
ranks
}
}
}
///|
fn Composer::processed_wgsl_compose_module(
self : Composer,
rel_path : String,
raw_source : String,
session : WgslComposeSession,
inherited_defs : WgslActiveComposeDefs?,
) -> WgslProcessedComposeModule raise ComposerError {
let active_defs = self.active_compose_defs_for_rel_path(
rel_path, session, inherited_defs,
)
merge_wgsl_source_local_shader_defs(
active_defs,
raw_source,
session,
normalize_shader_rel_path(rel_path),
)
let cache_key = wgsl_processed_module_cache_key(
rel_path, active_defs, session,
)
match session.processed_modules.get(cache_key) {
Some(processed) => processed
None =>
match self.processed_module_cache.get(cache_key) {
Some(processed) => {
session.processed_modules.set(cache_key, processed)
processed
}
None => {
let prepared = prepare_wgsl_compose_source(
raw_source, rel_path, session, active_defs,
)
let processed = WgslProcessedComposeModule::{
raw_source,
active_defs,
prepared,
unit: None,
declarations_by_name: None,
declaration_summaries: None,
declaration_names: None,
item_extractor: None,
item_extractions: Map([]),
naga_pull_ranks: None,
source_decl_ranks: None,
virtual_override_targets: None,
has_override_function: None,
has_virtual_function: None,
}
session.processed_modules.set(cache_key, processed)
self.processed_module_cache.set(cache_key, processed)
processed
}
}
}
}
///|
fn Composer::processed_registered_wgsl_compose_module(
self : Composer,
rel_path : String,
session : WgslComposeSession,
inherited_defs : WgslActiveComposeDefs?,
) -> WgslProcessedComposeModule raise ComposerError {
let raw_source = match self.registry.registered_source(rel_path) {
Some(source) => source
None => raise MissingRegisteredSource(rel_path)
}
self.processed_wgsl_compose_module(
rel_path, raw_source, session, inherited_defs,
)
}