glsl_lang_lexer/
context.rs1use std::cell::RefCell;
2use std::collections::{BTreeMap, HashSet};
3use std::rc::Rc;
4
5use lang_util::{FileId, SmolStr};
6
7use glsl_lang_types::ast;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct ParseOptions {
12 pub default_version: u16,
14 pub target_vulkan: bool,
16 pub source_id: FileId,
18 pub allow_rs_ident: bool,
20}
21
22impl Default for ParseOptions {
23 fn default() -> Self {
24 Self {
25 default_version: 460,
26 target_vulkan: false,
27 source_id: FileId::new(0),
28 allow_rs_ident: false,
29 }
30 }
31}
32
33impl ParseOptions {
34 pub fn new() -> Self {
36 Self::default()
37 }
38}
39
40#[derive(Default, Debug, Clone, PartialEq)]
42pub struct ParseContext {
43 data: Rc<RefCell<ParseContextData>>,
45}
46
47impl ParseContext {
48 pub fn new() -> ParseContext {
50 Default::default()
51 }
52
53 pub fn new_with_comments() -> Self {
55 Self {
56 data: Rc::new(RefCell::new(ParseContextData::with_comments())),
57 }
58 }
59
60 pub fn new_with_policy(policy: impl TypeTablePolicy + 'static) -> Self {
62 Self {
63 data: Rc::new(RefCell::new(ParseContextData::with_policy(policy))),
64 }
65 }
66
67 pub fn new_with_comments_and_policy(policy: impl TypeTablePolicy + 'static) -> Self {
70 Self {
71 data: Rc::new(RefCell::new(ParseContextData::with_comments_and_policy(
72 policy,
73 ))),
74 }
75 }
76
77 pub fn new_with_context(context: ParseContextData) -> Self {
79 Self {
80 data: Rc::new(RefCell::new(context)),
81 }
82 }
83
84 pub fn clone_inner(&self) -> Self {
86 Self {
87 data: Rc::new(RefCell::new(self.data.borrow().clone())),
88 }
89 }
90
91 pub fn into_data(self) -> Option<ParseContextData> {
94 Rc::try_unwrap(self.data).ok().map(RefCell::into_inner)
95 }
96
97 pub fn data(&self) -> std::cell::Ref<'_, ParseContextData> {
99 self.data.borrow()
100 }
101
102 pub fn data_mut(&self) -> std::cell::RefMut<'_, ParseContextData> {
104 self.data.borrow_mut()
105 }
106
107 pub fn with_policy(&self, policy: impl TypeTablePolicy + 'static) -> ParseContext {
109 Self {
110 data: {
111 let mut data = self.data().clone();
112 data.policy = Rc::new(policy);
113 Rc::new(RefCell::new(data))
114 },
115 }
116 }
117}
118
119impl From<ParseContextData> for ParseContext {
120 fn from(data: ParseContextData) -> Self {
121 Self {
122 data: Rc::new(RefCell::new(data)),
123 }
124 }
125}
126
127#[derive(Debug, Clone)]
129pub struct ParseContextData {
130 names: Vec<HashSet<SmolStr>>,
132 comments: Option<CommentList>,
134
135 policy: Rc<dyn TypeTablePolicy>,
136}
137
138impl ParseContextData {
139 pub fn new() -> Self {
141 Self::default()
142 }
143
144 pub fn with_policy(policy: impl TypeTablePolicy + 'static) -> Self {
150 Self {
151 policy: Rc::new(policy),
152 ..Default::default()
153 }
154 }
155
156 pub fn with_comments() -> Self {
158 Self {
159 comments: Some(Default::default()),
160 ..Default::default()
161 }
162 }
163
164 pub fn with_comments_and_policy(policy: impl TypeTablePolicy + 'static) -> Self {
171 Self {
172 comments: Some(Default::default()),
173 policy: Rc::new(policy),
174 ..Default::default()
175 }
176 }
177
178 pub fn comments(&self) -> Option<&CommentList> {
180 self.comments.as_ref()
181 }
182}
183
184impl Default for ParseContextData {
185 fn default() -> Self {
186 Self {
187 names: vec![HashSet::new()],
188 comments: Default::default(),
189 policy: Rc::new(GlslTypeTablePolicy),
190 }
191 }
192}
193
194impl PartialEq for ParseContextData {
195 fn eq(&self, other: &Self) -> bool {
196 self.names.eq(&other.names)
197 }
198}
199
200#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204pub enum IdentifierContext {
205 FunctionPrototype,
207}
208
209pub trait TypeTablePolicy: std::fmt::Debug {
211 fn promote_to_type_name(&self, name: &ast::Identifier, ctx: IdentifierContext) -> bool;
214}
215
216#[derive(Debug, Clone, Copy)]
218pub struct GlslTypeTablePolicy;
219
220impl TypeTablePolicy for GlslTypeTablePolicy {
221 fn promote_to_type_name(&self, _: &ast::Identifier, _: IdentifierContext) -> bool {
222 false
223 }
224}
225
226impl ParseContext {
227 pub fn is_type_name(&self, name: &str) -> bool {
229 self.data.borrow().is_type_name(name)
230 }
231
232 pub fn add_type_name(&self, name: ast::Identifier) -> ast::TypeName {
234 self.data.borrow_mut().add_type_name(name)
235 }
236
237 pub fn push_scope(&self) {
239 self.data.borrow_mut().push_scope();
240 }
241
242 pub fn pop_scope(&self) {
244 self.data.borrow_mut().pop_scope();
245 }
246
247 pub fn new_identifier(&self, name: &ast::Identifier, ctx: IdentifierContext) {
249 self.data.borrow_mut().new_identifier(name, ctx)
250 }
251}
252
253impl ParseContextData {
254 pub fn is_type_name(&self, name: &str) -> bool {
256 self.names.iter().any(|level| level.contains(name))
257 }
258
259 pub fn add_type_name(&mut self, name: ast::Identifier) -> ast::TypeName {
261 let name_string = name.0.as_str();
262 self.names.last_mut().unwrap().insert(name_string.into());
263 name.map(ast::TypeNameData::from)
264 }
265
266 pub fn push_scope(&mut self) {
268 self.names.push(HashSet::new());
269 }
270
271 pub fn pop_scope(&mut self) {
273 if self.names.len() > 1 {
274 self.names.pop();
275 }
276 }
277
278 pub fn new_identifier(&mut self, name: &ast::Identifier, ctx: IdentifierContext) {
280 if self.policy.promote_to_type_name(name, ctx) {
281 self.add_type_name(name.clone());
282 }
283 }
284}
285
286pub type CommentList = BTreeMap<lang_util::position::NodeSpan, ast::Comment>;
292
293impl ParseContext {
294 pub fn has_comments(&self) -> bool {
296 self.data.borrow().comments.is_some()
297 }
298
299 pub fn add_comment(&self, comment: ast::Comment) {
301 self.data.borrow_mut().add_comment(comment)
302 }
303}
304
305impl ParseContextData {
306 pub fn add_comment(&mut self, comment: ast::Comment) {
308 if let Some(comments) = self.comments.as_mut() {
309 let span = comment.span;
310 comments.insert(span.unwrap(), comment);
311 }
312 }
313}