1use alloc::{borrow::Cow, string::String, vec::Vec};
2use core::fmt;
3
4use super::{builtins::MacroCall, Span};
5use crate::{
6 AddressSpace, BinaryOperator, Binding, Constant, Expression, Function, GlobalVariable, Handle,
7 Interpolation, Literal, Sampling, StorageAccess, Type, UnaryOperator,
8};
9
10#[derive(Debug, Clone, Copy)]
11pub enum GlobalLookupKind {
12 Variable(Handle<GlobalVariable>),
13 Constant(Handle<Constant>, Handle<Type>),
14 BlockSelect(Handle<GlobalVariable>, u32),
15}
16
17#[derive(Debug, Clone, Copy)]
18pub struct GlobalLookup {
19 pub kind: GlobalLookupKind,
20 pub entry_arg: Option<usize>,
21 pub mutable: bool,
22}
23
24#[derive(Debug, Clone)]
25pub struct ParameterInfo {
26 pub qualifier: ParameterQualifier,
27 pub depth: bool,
30}
31
32#[derive(Clone, Copy)]
34pub enum FunctionKind {
35 Call(Handle<Function>),
37 Macro(MacroCall),
39}
40
41impl fmt::Debug for FunctionKind {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match *self {
44 Self::Call(_) => write!(f, "Call"),
45 Self::Macro(_) => write!(f, "Macro"),
46 }
47 }
48}
49
50#[derive(Debug)]
51pub struct Overload {
52 pub parameters: Vec<Handle<Type>>,
54 pub parameters_info: Vec<ParameterInfo>,
55 pub kind: FunctionKind,
57 pub defined: bool,
59 pub internal: bool,
62 pub void: bool,
64}
65
66bitflags::bitflags! {
67 #[derive(Default)]
71 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
72 pub struct BuiltinVariations: u32 {
73 const STANDARD = 1 << 0;
75 const DOUBLE = 1 << 1;
77 const CUBE_TEXTURES_ARRAY = 1 << 2;
79 const D2_MULTI_TEXTURES_ARRAY = 1 << 3;
81 }
82}
83
84#[derive(Debug, Default)]
85pub struct FunctionDeclaration {
86 pub overloads: Vec<Overload>,
87 pub variations: BuiltinVariations,
89}
90
91#[derive(Debug)]
92pub struct EntryArg {
93 pub name: Option<String>,
94 pub binding: Binding,
95 pub handle: Handle<GlobalVariable>,
96 pub storage: StorageQualifier,
97}
98
99#[derive(Debug, Clone)]
100pub struct VariableReference {
101 pub expr: Handle<Expression>,
102 pub load: bool,
104 pub mutable: bool,
106 pub constant: Option<(Handle<Constant>, Handle<Type>)>,
107 pub entry_arg: Option<usize>,
108}
109
110#[derive(Debug, Clone)]
111pub struct HirExpr {
112 pub kind: HirExprKind,
113 pub meta: Span,
114}
115
116#[derive(Debug, Clone)]
117pub enum HirExprKind {
118 Access {
119 base: Handle<HirExpr>,
120 index: Handle<HirExpr>,
121 },
122 Select {
123 base: Handle<HirExpr>,
124 field: String,
125 },
126 Literal(Literal),
127 Binary {
128 left: Handle<HirExpr>,
129 op: BinaryOperator,
130 right: Handle<HirExpr>,
131 },
132 Unary {
133 op: UnaryOperator,
134 expr: Handle<HirExpr>,
135 },
136 Variable(VariableReference),
137 Call(FunctionCall),
138 Conditional {
140 condition: Handle<HirExpr>,
142 accept: Handle<HirExpr>,
146 reject: Handle<HirExpr>,
150 },
151 Assign {
152 tgt: Handle<HirExpr>,
153 value: Handle<HirExpr>,
154 },
155 PrePostfix {
157 op: BinaryOperator,
159 postfix: bool,
161 expr: Handle<HirExpr>,
163 },
164 Method {
166 expr: Handle<HirExpr>,
168 name: String,
170 args: Vec<Handle<HirExpr>>,
172 },
173}
174
175#[derive(Debug, Hash, PartialEq, Eq)]
176pub enum QualifierKey<'a> {
177 String(Cow<'a, str>),
178 Layout,
180 Format,
182 Index,
184}
185
186#[derive(Debug)]
187pub enum QualifierValue {
188 None,
189 Uint(u32),
190 Layout(StructLayout),
191 Format(crate::StorageFormat),
192}
193
194#[derive(Debug, Default)]
195pub struct TypeQualifiers<'a> {
196 pub span: Span,
197 pub storage: (StorageQualifier, Span),
198 pub invariant: Option<Span>,
199 pub interpolation: Option<(Interpolation, Span)>,
200 pub precision: Option<(Precision, Span)>,
201 pub sampling: Option<(Sampling, Span)>,
202 pub storage_access: Option<(StorageAccess, Span)>,
205 pub layout_qualifiers: crate::FastHashMap<QualifierKey<'a>, (QualifierValue, Span)>,
206}
207
208impl<'a> TypeQualifiers<'a> {
209 pub fn unused_errors(&self, errors: &mut Vec<super::Error>) {
211 if let Some(meta) = self.invariant {
212 errors.push(super::Error {
213 kind: super::ErrorKind::SemanticError(
214 "Invariant qualifier can only be used in in/out variables".into(),
215 ),
216 meta,
217 });
218 }
219
220 if let Some((_, meta)) = self.interpolation {
221 errors.push(super::Error {
222 kind: super::ErrorKind::SemanticError(
223 "Interpolation qualifiers can only be used in in/out variables".into(),
224 ),
225 meta,
226 });
227 }
228
229 if let Some((_, meta)) = self.sampling {
230 errors.push(super::Error {
231 kind: super::ErrorKind::SemanticError(
232 "Sampling qualifiers can only be used in in/out variables".into(),
233 ),
234 meta,
235 });
236 }
237
238 if let Some((_, meta)) = self.storage_access {
239 errors.push(super::Error {
240 kind: super::ErrorKind::SemanticError(
241 "Memory qualifiers can only be used in storage variables".into(),
242 ),
243 meta,
244 });
245 }
246
247 for &(_, meta) in self.layout_qualifiers.values() {
248 errors.push(super::Error {
249 kind: super::ErrorKind::SemanticError("Unexpected qualifier".into()),
250 meta,
251 });
252 }
253 }
254
255 pub fn uint_layout_qualifier(
258 &mut self,
259 name: &'a str,
260 errors: &mut Vec<super::Error>,
261 ) -> Option<u32> {
262 match self
263 .layout_qualifiers
264 .remove(&QualifierKey::String(name.into()))
265 {
266 Some((QualifierValue::Uint(v), _)) => Some(v),
267 Some((_, meta)) => {
268 errors.push(super::Error {
269 kind: super::ErrorKind::SemanticError("Qualifier expects a uint value".into()),
270 meta,
271 });
272 Some(0)
277 }
278 _ => None,
279 }
280 }
281
282 pub fn none_layout_qualifier(&mut self, name: &'a str, errors: &mut Vec<super::Error>) -> bool {
285 match self
286 .layout_qualifiers
287 .remove(&QualifierKey::String(name.into()))
288 {
289 Some((QualifierValue::None, _)) => true,
290 Some((_, meta)) => {
291 errors.push(super::Error {
292 kind: super::ErrorKind::SemanticError(
293 "Qualifier doesn't expect a value".into(),
294 ),
295 meta,
296 });
297 true
300 }
301 _ => false,
302 }
303 }
304}
305
306#[derive(Debug, Clone)]
307pub enum FunctionCallKind {
308 TypeConstructor(Handle<Type>),
309 Function(String),
310}
311
312#[derive(Debug, Clone)]
313pub struct FunctionCall {
314 pub kind: FunctionCallKind,
315 pub args: Vec<Handle<HirExpr>>,
316}
317
318#[derive(Debug, Clone, Copy, PartialEq)]
319pub enum StorageQualifier {
320 AddressSpace(AddressSpace),
321 Input,
322 Output,
323 Const,
324}
325
326impl Default for StorageQualifier {
327 fn default() -> Self {
328 StorageQualifier::AddressSpace(AddressSpace::Function)
329 }
330}
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq)]
333pub enum StructLayout {
334 Std140,
335 Std430,
336}
337
338#[derive(Debug, Clone, PartialEq, Copy)]
357pub enum Precision {
358 Low,
360 Medium,
362 High,
364}
365
366#[derive(Debug, Clone, PartialEq, Copy)]
367pub enum ParameterQualifier {
368 In,
369 Out,
370 InOut,
371 Const,
372}
373
374impl ParameterQualifier {
375 pub const fn is_lhs(&self) -> bool {
377 match *self {
378 ParameterQualifier::Out | ParameterQualifier::InOut => true,
379 _ => false,
380 }
381 }
382}
383
384#[derive(Debug, Clone, Copy, PartialEq)]
386pub enum Profile {
387 Core,
389}