1use std::{
2 cell::RefCell,
3 path::{Path, PathBuf},
4 rc::Rc,
5};
6
7use tree_sitter::{Tree, TreeCursor};
8
9use crate::{
10 shader::ShaderContextParams,
11 symbols::symbol_list::{ShaderSymbolList, ShaderSymbolListRef},
12};
13
14use super::prepocessor::{
15 ShaderPreprocessor, ShaderPreprocessorContext, ShaderPreprocessorInclude,
16};
17
18#[derive(Debug, Clone)]
19pub struct ShaderModule {
20 pub file_path: PathBuf,
21 pub content: String,
22 pub tree: Tree,
23}
24
25pub type ShaderModuleHandle = Rc<RefCell<ShaderModule>>;
26
27#[derive(Debug, Default, Clone)]
28pub struct ShaderSymbols {
29 pub(super) preprocessor: ShaderPreprocessor,
30 pub(super) symbol_list: ShaderSymbolList,
31}
32impl ShaderSymbols {
33 pub fn new(file_path: &Path, shader_params: ShaderContextParams) -> Self {
34 Self {
35 preprocessor: ShaderPreprocessor::new(ShaderPreprocessorContext::main(
36 file_path,
37 shader_params,
38 )),
39 symbol_list: ShaderSymbolList::default(),
40 }
41 }
42 pub fn get_all_symbols<'a>(&'a self) -> ShaderSymbolListRef<'a> {
43 let mut symbols = self.get_local_symbols();
44 for include in &self.preprocessor.includes {
45 assert!(
46 include.cache.is_some(),
47 "Include {} do not have cache, but is being queried.\n{}",
48 include.get_relative_path(),
49 self.dump_dependency_tree(&PathBuf::from("oui"))
50 );
51 symbols.append(include.get_cache().get_all_symbols());
52 }
53 symbols
54 }
55 pub fn get_local_symbols<'a>(&'a self) -> ShaderSymbolListRef<'a> {
56 self.preprocessor.preprocess_symbols(&self.symbol_list)
57 }
58 pub fn get_context(&self) -> &ShaderPreprocessorContext {
59 &self.preprocessor.context
60 }
61 pub fn get_preprocessor(&self) -> &ShaderPreprocessor {
63 &self.preprocessor
64 }
65 pub fn get_preprocessor_mut(&mut self) -> &mut ShaderPreprocessor {
66 &mut self.preprocessor
67 }
68 pub fn visit_includes<F: FnMut(&ShaderPreprocessorInclude)>(&self, callback: &mut F) {
69 for include in &self.preprocessor.includes {
70 callback(&include);
71 include.get_cache().visit_includes(callback);
72 }
73 }
74 pub fn visit_includes_mut<F: FnMut(&mut ShaderPreprocessorInclude)>(
75 &mut self,
76 callback: &mut F,
77 ) {
78 for include in &mut self.preprocessor.includes {
79 callback(include);
80 include.cache.as_mut().unwrap().visit_includes_mut(callback);
81 }
82 }
83 pub fn find_include_stack<F: FnMut(&ShaderPreprocessorInclude) -> bool>(
84 &self,
85 callback: &mut F,
86 ) -> Option<Vec<&ShaderPreprocessorInclude>> {
87 for include in &self.preprocessor.includes {
88 if callback(&include) {
89 return Some(vec![&include]);
90 } else {
91 match include.get_cache().find_include_stack(callback) {
92 Some(mut stack) => {
93 stack.insert(0, include);
94 return Some(stack);
95 }
96 None => {}
97 }
98 }
99 }
100 None
101 }
102 pub fn find_include<F: FnMut(&ShaderPreprocessorInclude) -> bool>(
103 &self,
104 callback: &mut F,
105 ) -> Option<&ShaderPreprocessorInclude> {
106 for include in &self.preprocessor.includes {
107 if callback(&include) {
108 return Some(&include);
109 } else {
110 match include.get_cache().find_include(callback) {
111 Some(include) => {
112 return Some(&include);
113 }
114 None => {}
115 }
116 }
117 }
118 None
119 }
120 pub fn find_direct_includer(&self, include_path: &Path) -> Option<&ShaderPreprocessorInclude> {
121 match self.find_include_stack(&mut |include| *include.get_absolute_path() == *include_path)
122 {
123 Some(stack) => {
124 assert!(!stack.is_empty());
125 Some(stack[0])
126 }
127 None => None,
128 }
129 }
130 pub fn has_dependency(&self, dependency_to_find_path: &Path) -> bool {
131 self.find_include(&mut |e| *e.get_absolute_path() == *dependency_to_find_path)
132 .is_some()
133 }
134 fn dump_dependency_node(
135 &self,
136 include: &ShaderPreprocessorInclude,
137 header: String,
138 is_last: bool,
139 ) -> String {
140 let mut dependency_tree = format!(
141 "{}{} {} ({})\n",
142 header,
143 if is_last { "└─" } else { "├─" },
144 include.get_absolute_path().display(),
145 match &include.cache {
146 Some(cache) => format!("Mode: {:?}", cache.preprocessor.mode),
147 None => "Missing cache".into(),
148 }
149 );
150 let childs_header = format!("{}{}", header, if is_last { " " } else { "| " });
151 let mut deps_iter = match &include.cache {
152 Some(data) => data.preprocessor.includes.iter().peekable(),
153 None => {
154 return dependency_tree;
155 }
156 };
157 while let Some(included_include) = deps_iter.next() {
158 dependency_tree.push_str(
159 self.dump_dependency_node(
160 included_include,
161 childs_header.clone(),
162 deps_iter.peek().is_none(),
163 )
164 .as_str(),
165 );
166 }
167 dependency_tree
168 }
169 pub fn dump_dependency_tree(&self, absolute_path: &PathBuf) -> String {
170 let mut dependency_tree = format!("{}\n", absolute_path.display());
171 let mut deps_iter = self.preprocessor.includes.iter().peekable();
172 while let Some(include) = deps_iter.next() {
173 dependency_tree.push_str(
174 self.dump_dependency_node(include, " ".into(), deps_iter.peek().is_none())
175 .as_str(),
176 );
177 }
178 dependency_tree
179 }
180}
181
182impl ShaderModule {
183 pub fn dump_ast(&self) -> String {
185 Self::dump_ast_node(self.tree.root_node())
186 }
187 pub fn dump_ast_node(node: tree_sitter::Node) -> String {
188 fn format_debug_cursor(cursor: &mut TreeCursor, depth: usize) -> String {
189 let mut debug_tree = String::new();
190 loop {
191 debug_tree.push_str(&match cursor.field_name() {
192 Some(field_name) => format!(
193 "{}{}: {} [{}, {}] - [{}, {}]\n",
194 " ".repeat(depth * 2),
195 field_name,
196 if cursor.node().is_named() {
197 cursor.node().kind().into()
198 } else {
199 format!("\"{}\"", cursor.node().kind())
200 },
201 cursor.node().range().start_point.row,
202 cursor.node().range().start_point.column,
203 cursor.node().range().end_point.row,
204 cursor.node().range().end_point.column,
205 ),
206 None => format!(
207 "{}{} [{}, {}] - [{}, {}]\n",
208 " ".repeat(depth * 2),
209 if cursor.node().is_named() {
210 cursor.node().kind().into()
211 } else {
212 format!("\"{}\"", cursor.node().kind())
213 },
214 cursor.node().range().start_point.row,
215 cursor.node().range().start_point.column,
216 cursor.node().range().end_point.row,
217 cursor.node().range().end_point.column,
218 ),
219 });
220 if cursor.goto_first_child() {
221 debug_tree.push_str(format_debug_cursor(cursor, depth + 1).as_str());
222 cursor.goto_parent();
223 }
224 if !cursor.goto_next_sibling() {
225 break;
226 }
227 }
228 debug_tree
229 }
230 format_debug_cursor(&mut node.walk(), 0)
231 }
232}