shader_sense/symbols/
shader_module.rs

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    // TODO: should abstract this.
62    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    // Dump AST from tree
184    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}