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, Override, 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 Override(Handle<Override>, Handle<Type>),
15 BlockSelect(Handle<GlobalVariable>, u32),
16}
17
18#[derive(Debug, Clone, Copy)]
19pub struct GlobalLookup {
20 pub kind: GlobalLookupKind,
21 pub entry_arg: Option<usize>,
22 pub mutable: bool,
23}
24
25#[derive(Debug, Clone)]
26pub struct ParameterInfo {
27 pub qualifier: ParameterQualifier,
28 pub depth: bool,
31}
32
33#[derive(Clone, Copy)]
35pub enum FunctionKind {
36 Call(Handle<Function>),
38 Macro(MacroCall),
40}
41
42impl fmt::Debug for FunctionKind {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match *self {
45 Self::Call(_) => write!(f, "Call"),
46 Self::Macro(_) => write!(f, "Macro"),
47 }
48 }
49}
50
51#[derive(Debug)]
52pub struct Overload {
53 pub parameters: Vec<Handle<Type>>,
55 pub parameters_info: Vec<ParameterInfo>,
56 pub kind: FunctionKind,
58 pub defined: bool,
60 pub internal: bool,
63 pub void: bool,
65}
66
67bitflags::bitflags! {
68 #[derive(Default)]
72 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
73 pub struct BuiltinVariations: u32 {
74 const STANDARD = 1 << 0;
76 const DOUBLE = 1 << 1;
78 const CUBE_TEXTURES_ARRAY = 1 << 2;
80 const D2_MULTI_TEXTURES_ARRAY = 1 << 3;
82 }
83}
84
85#[derive(Debug, Default)]
86pub struct FunctionDeclaration {
87 pub overloads: Vec<Overload>,
88 pub variations: BuiltinVariations,
90}
91
92#[derive(Debug)]
93pub struct EntryArg {
94 pub name: Option<String>,
95 pub binding: Binding,
96 pub handle: Handle<GlobalVariable>,
97 pub storage: StorageQualifier,
98}
99
100#[derive(Debug, Clone)]
101pub struct VariableReference {
102 pub expr: Handle<Expression>,
103 pub load: bool,
105 pub mutable: bool,
107 pub constant: Option<(Handle<Constant>, Handle<Type>)>,
108 pub entry_arg: Option<usize>,
109}
110
111#[derive(Debug, Clone)]
112pub struct HirExpr {
113 pub kind: HirExprKind,
114 pub meta: Span,
115}
116
117#[derive(Debug, Clone)]
118pub enum HirExprKind {
119 Sequence {
121 exprs: Vec<Handle<HirExpr>>,
122 },
123 Access {
124 base: Handle<HirExpr>,
125 index: Handle<HirExpr>,
126 },
127 Select {
128 base: Handle<HirExpr>,
129 field: String,
130 },
131 Literal(Literal),
132 Binary {
133 left: Handle<HirExpr>,
134 op: BinaryOperator,
135 right: Handle<HirExpr>,
136 },
137 Unary {
138 op: UnaryOperator,
139 expr: Handle<HirExpr>,
140 },
141 Variable(VariableReference),
142 Call(FunctionCall),
143 Conditional {
145 condition: Handle<HirExpr>,
147 accept: Handle<HirExpr>,
151 reject: Handle<HirExpr>,
155 },
156 Assign {
157 tgt: Handle<HirExpr>,
158 value: Handle<HirExpr>,
159 },
160 PrePostfix {
162 op: BinaryOperator,
164 postfix: bool,
166 expr: Handle<HirExpr>,
168 },
169 Method {
171 expr: Handle<HirExpr>,
173 name: String,
175 args: Vec<Handle<HirExpr>>,
177 },
178}
179
180#[derive(Debug, Hash, PartialEq, Eq)]
181pub enum QualifierKey<'a> {
182 String(Cow<'a, str>),
183 Layout,
185 Format,
187 Index,
189}
190
191#[derive(Debug)]
192pub enum QualifierValue {
193 None,
194 Uint(u32),
195 Layout(StructLayout),
196 Format(crate::StorageFormat),
197}
198
199#[derive(Debug, Default)]
200pub struct TypeQualifiers<'a> {
201 pub span: Span,
202 pub storage: (StorageQualifier, Span),
203 pub invariant: Option<Span>,
204 pub interpolation: Option<(Interpolation, Span)>,
205 pub precision: Option<(Precision, Span)>,
206 pub sampling: Option<(Sampling, Span)>,
207 pub storage_access: Option<(StorageAccess, Span)>,
210 pub layout_qualifiers: crate::FastHashMap<QualifierKey<'a>, (QualifierValue, Span)>,
211}
212
213impl<'a> TypeQualifiers<'a> {
214 pub fn unused_errors(&self, errors: &mut Vec<super::Error>) {
216 if let Some(meta) = self.invariant {
217 errors.push(super::Error {
218 kind: super::ErrorKind::SemanticError(
219 "Invariant qualifier can only be used in in/out variables".into(),
220 ),
221 meta,
222 });
223 }
224
225 if let Some((_, meta)) = self.interpolation {
226 errors.push(super::Error {
227 kind: super::ErrorKind::SemanticError(
228 "Interpolation qualifiers can only be used in in/out variables".into(),
229 ),
230 meta,
231 });
232 }
233
234 if let Some((_, meta)) = self.sampling {
235 errors.push(super::Error {
236 kind: super::ErrorKind::SemanticError(
237 "Sampling qualifiers can only be used in in/out variables".into(),
238 ),
239 meta,
240 });
241 }
242
243 if let Some((_, meta)) = self.storage_access {
244 errors.push(super::Error {
245 kind: super::ErrorKind::SemanticError(
246 "Memory qualifiers can only be used in storage variables".into(),
247 ),
248 meta,
249 });
250 }
251
252 for &(_, meta) in self.layout_qualifiers.values() {
253 errors.push(super::Error {
254 kind: super::ErrorKind::SemanticError("Unexpected qualifier".into()),
255 meta,
256 });
257 }
258 }
259
260 pub fn uint_layout_qualifier(
263 &mut self,
264 name: &'a str,
265 errors: &mut Vec<super::Error>,
266 ) -> Option<u32> {
267 match self
268 .layout_qualifiers
269 .remove(&QualifierKey::String(name.into()))
270 {
271 Some((QualifierValue::Uint(v), _)) => Some(v),
272 Some((_, meta)) => {
273 errors.push(super::Error {
274 kind: super::ErrorKind::SemanticError("Qualifier expects a uint value".into()),
275 meta,
276 });
277 Some(0)
282 }
283 _ => None,
284 }
285 }
286
287 pub fn none_layout_qualifier(&mut self, name: &'a str, errors: &mut Vec<super::Error>) -> bool {
290 match self
291 .layout_qualifiers
292 .remove(&QualifierKey::String(name.into()))
293 {
294 Some((QualifierValue::None, _)) => true,
295 Some((_, meta)) => {
296 errors.push(super::Error {
297 kind: super::ErrorKind::SemanticError(
298 "Qualifier doesn't expect a value".into(),
299 ),
300 meta,
301 });
302 true
305 }
306 _ => false,
307 }
308 }
309}
310
311#[derive(Debug, Clone)]
312pub enum FunctionCallKind {
313 TypeConstructor(Handle<Type>),
314 Function(String),
315}
316
317#[derive(Debug, Clone)]
318pub struct FunctionCall {
319 pub kind: FunctionCallKind,
320 pub args: Vec<Handle<HirExpr>>,
321}
322
323#[derive(Debug, Clone, Copy, PartialEq)]
324pub enum StorageQualifier {
325 AddressSpace(AddressSpace),
326 Input,
327 Output,
328 Const,
329}
330
331impl Default for StorageQualifier {
332 fn default() -> Self {
333 StorageQualifier::AddressSpace(AddressSpace::Function)
334 }
335}
336
337#[derive(Debug, Clone, Copy, PartialEq, Eq)]
338pub enum StructLayout {
339 Std140,
340 Std430,
341}
342
343#[derive(Debug, Clone, PartialEq, Copy)]
362pub enum Precision {
363 Low,
365 Medium,
367 High,
369}
370
371#[derive(Debug, Clone, PartialEq, Copy)]
372pub enum ParameterQualifier {
373 In,
374 Out,
375 InOut,
376 Const,
377}
378
379impl ParameterQualifier {
380 pub const fn is_lhs(&self) -> bool {
382 match *self {
383 ParameterQualifier::Out | ParameterQualifier::InOut => true,
384 _ => false,
385 }
386 }
387}
388
389#[derive(Debug, Clone, Copy, PartialEq)]
391pub enum Profile {
392 Core,
394}