wgsl_parser/scopes/
mod.rs1use std::{
28 collections::HashMap,
29 fmt::{self, Write},
30 sync::{Arc, Weak},
31};
32
33use gramatika::{Span, Spanned, Substr, Token as _};
34use parking_lot::RwLock;
35
36use crate::{decl::Decl, traversal::Walk, SyntaxTree, Token, TokenKind};
37
38mod builder;
39use builder::ScopeBuilder;
40
41pub type Bindings = HashMap<(Substr, TokenKind), Arc<Decl>>;
43
44pub struct Scope {
45 span: Span,
46 parent: Option<Weak<Scope>>,
47 children: RwLock<Vec<Arc<Scope>>>,
48 bindings: Arc<RwLock<Bindings>>,
49}
50
51impl Spanned for Scope {
52 fn span(&self) -> Span {
53 self.span
54 }
55}
56
57trait PrintKeys {
58 fn print_keys(&self, indent: usize) -> Result<String, fmt::Error>;
59}
60
61impl PrintKeys for Bindings {
62 fn print_keys(&self, indent: usize) -> Result<String, fmt::Error> {
63 let spacing = " ".repeat(indent);
64
65 let mut out = String::new();
66 let f = &mut out;
67
68 for (lexeme, kind) in self.keys() {
69 write!(f, "`{}` ({:?}), ", lexeme, kind)?;
70 }
71 out.pop();
72 out.pop();
73
74 if out.is_empty() {
75 return Ok(out);
76 }
77
78 out = out.replace(", ", &format!("\n {spacing}"));
79 out = std::format!("\n {spacing}{out}");
80
81 Ok(out)
82 }
83}
84
85impl fmt::Debug for Scope {
86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87 write!(f, "{}", self.print(0)?)
88 }
89}
90
91pub fn build(syntax_tree: &SyntaxTree) -> Arc<Scope> {
92 let span = syntax_tree.span();
93 let mut builder = ScopeBuilder::new(span);
94
95 syntax_tree.walk(&mut builder);
96 builder.build()
97}
98
99impl Scope {
100 pub fn new(span: Span) -> Self {
101 Self {
102 span,
103 parent: None,
104 children: RwLock::new(vec![]),
105 bindings: Arc::new(RwLock::new(HashMap::default())),
106 }
107 }
108
109 pub fn with_parent(span: Span, parent: Arc<Scope>) -> Arc<Self> {
110 let mut this = Self::new(span);
111 this.parent = Some(Arc::downgrade(&parent));
112
113 let arc_this = Arc::new(this);
114 parent.children.write().push(Arc::clone(&arc_this));
115
116 arc_this
117 }
118
119 pub fn parent(&self) -> Option<Arc<Scope>> {
120 self.parent.as_ref().and_then(|env| env.upgrade())
121 }
122
123 pub fn find_decl(
124 &self,
125 token: &Token,
126 debug: bool, ) -> Option<Arc<Decl>> {
128 let (lexeme, span) = token.as_inner();
129 let kind = token.kind();
130
131 if !self.span.contains(span) {
132 None
133 } else {
134 if debug {
135 eprintln!(
136 "Looking for `{lexeme}` ({kind:?}) ({span:?}) in scope:\n ({:?}){}",
137 self.span(),
138 self.bindings.read().print_keys(1).unwrap(),
139 );
140 }
141
142 if self.bindings.read().contains_key(&(lexeme.clone(), kind)) {
143 self.bindings.read().get(&(lexeme, kind)).cloned()
144 } else {
145 self.children
146 .read()
147 .iter()
148 .find_map(|env| env.find_decl(token, debug))
149 .clone()
150 }
151 }
152 }
153
154 pub fn find_field_decl(&self, token: &Token, struct_name: &Token) -> Option<Arc<Decl>> {
155 let (lexeme, span) = token.as_inner();
156 let field_key = &(lexeme, token.kind());
157 let struct_key = &(struct_name.lexeme(), TokenKind::Ident);
158
159 if !self.span.contains(span) {
160 None
161 } else if self.bindings.read().contains_key(field_key)
162 && self.bindings.read().contains_key(struct_key)
163 {
164 self.bindings.read().get(field_key).cloned()
165 } else {
166 self.children
167 .read()
168 .iter()
169 .find_map(|env| env.find_field_decl(token, struct_name))
170 .clone()
171 }
172 }
173
174 pub fn find(&self, token: &Token) -> Option<Arc<Scope>> {
175 let (lexeme, span) = token.as_inner();
176 let kind = token.kind();
177
178 if !self.span.contains(span) {
179 return None;
180 }
181
182 self.children
183 .read()
184 .iter()
185 .find_map(|scope| {
186 if scope.span.contains(span)
187 && scope.bindings.read().contains_key(&(lexeme.clone(), kind))
188 {
189 Some(Arc::clone(scope))
190 } else {
191 None
192 }
193 })
194 .or_else(|| {
195 self.children
196 .read()
197 .iter()
198 .find_map(|scope| scope.find(token))
199 })
200 }
201
202 fn define(&self, ident: (Substr, TokenKind), decl: Decl) {
203 self.bindings.write().insert(ident, Arc::new(decl));
204 }
205
206 fn print(&self, indent: usize) -> Result<String, fmt::Error> {
207 let mut out = String::new();
208 let spacing = " ".repeat(indent);
209
210 writeln!(
211 &mut out,
212 "{spacing}({:?}) {}",
213 self.span,
214 self.bindings.read().print_keys(indent)?
215 )?;
216
217 for child in self.children.read().iter() {
218 write!(&mut out, "{}", child.print(indent + 1)?)?;
219 }
220
221 Ok(out)
222 }
223}