1 use std::fmt;
2 
3 use super::{builtins::MacroCall, context::ExprPos, Span};
4 use crate::{
5     BinaryOperator, Binding, Constant, Expression, Function, GlobalVariable, Handle, Interpolation,
6     Sampling, StorageAccess, StorageClass, Type, UnaryOperator,
7 };
8 
9 #[derive(Debug, Clone, Copy)]
10 pub enum GlobalLookupKind {
11     Variable(Handle<GlobalVariable>),
12     Constant(Handle<Constant>, Handle<Type>),
13     BlockSelect(Handle<GlobalVariable>, u32),
14 }
15 
16 #[derive(Debug, Clone, Copy)]
17 pub struct GlobalLookup {
18     pub kind: GlobalLookupKind,
19     pub entry_arg: Option<usize>,
20     pub mutable: bool,
21 }
22 
23 #[derive(Debug, Clone)]
24 pub struct ParameterInfo {
25     pub qualifier: ParameterQualifier,
26     /// Wether the parameter should be treated as a depth image instead of a
27     /// sampled image
28     pub depth: bool,
29 }
30 
31 /// How the function is implemented
32 #[derive(Clone, Copy)]
33 pub enum FunctionKind {
34     /// The function is user defined
35     Call(Handle<Function>),
36     /// The function is a buitin
37     Macro(MacroCall),
38 }
39 
40 impl fmt::Debug for FunctionKind {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result41     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42         match *self {
43             Self::Call(_) => write!(f, "Call"),
44             Self::Macro(_) => write!(f, "Macro"),
45         }
46     }
47 }
48 
49 #[derive(Debug)]
50 pub struct Overload {
51     /// Normalized function parameters, modifiers are not applied
52     pub parameters: Vec<Handle<Type>>,
53     pub parameters_info: Vec<ParameterInfo>,
54     /// How the function is implemented
55     pub kind: FunctionKind,
56     /// Wheter this function was already defined or is just a prototype
57     pub defined: bool,
58     /// Wheter or not this function returns void (nothing)
59     pub void: bool,
60 }
61 
62 #[derive(Debug, Default)]
63 pub struct FunctionDeclaration {
64     pub overloads: Vec<Overload>,
65     /// Wether or not this function has the name of a builtin
66     pub builtin: bool,
67     /// In case [`builtin`](Self::builtin) is true, this field indicates wether
68     /// this function already has double overloads added or not, otherwise is unused
69     pub double: bool,
70 }
71 
72 #[derive(Debug)]
73 pub struct EntryArg {
74     pub name: Option<String>,
75     pub binding: Binding,
76     pub handle: Handle<GlobalVariable>,
77     pub storage: StorageQualifier,
78 }
79 
80 #[derive(Debug, Clone)]
81 pub struct VariableReference {
82     pub expr: Handle<Expression>,
83     pub load: bool,
84     pub mutable: bool,
85     pub constant: Option<(Handle<Constant>, Handle<Type>)>,
86     pub entry_arg: Option<usize>,
87 }
88 
89 #[derive(Debug, Clone)]
90 pub struct HirExpr {
91     pub kind: HirExprKind,
92     pub meta: Span,
93 }
94 
95 #[derive(Debug, Clone)]
96 pub enum HirExprKind {
97     Access {
98         base: Handle<HirExpr>,
99         index: Handle<HirExpr>,
100     },
101     Select {
102         base: Handle<HirExpr>,
103         field: String,
104     },
105     Constant(Handle<Constant>),
106     Binary {
107         left: Handle<HirExpr>,
108         op: BinaryOperator,
109         right: Handle<HirExpr>,
110     },
111     Unary {
112         op: UnaryOperator,
113         expr: Handle<HirExpr>,
114     },
115     Variable(VariableReference),
116     Call(FunctionCall),
117     Conditional {
118         condition: Handle<HirExpr>,
119         accept: Handle<HirExpr>,
120         reject: Handle<HirExpr>,
121     },
122     Assign {
123         tgt: Handle<HirExpr>,
124         value: Handle<HirExpr>,
125     },
126     /// A prefix/postfix operator like `++`
127     PrePostfix {
128         /// The operation to be performed
129         op: BinaryOperator,
130         /// Whether this is a postfix or a prefix
131         postfix: bool,
132         /// The target expression
133         expr: Handle<HirExpr>,
134     },
135 }
136 
137 #[derive(Debug)]
138 pub enum TypeQualifier {
139     StorageQualifier(StorageQualifier),
140     Interpolation(Interpolation),
141     Set(u32),
142     Binding(u32),
143     Location(u32),
144     WorkGroupSize(usize, u32),
145     Sampling(Sampling),
146     Layout(StructLayout),
147     Precision(Precision),
148     EarlyFragmentTests,
149     StorageAccess(StorageAccess),
150 }
151 
152 #[derive(Debug, Clone)]
153 pub enum FunctionCallKind {
154     TypeConstructor(Handle<Type>),
155     Function(String),
156 }
157 
158 #[derive(Debug, Clone)]
159 pub struct FunctionCall {
160     pub kind: FunctionCallKind,
161     pub args: Vec<Handle<HirExpr>>,
162 }
163 
164 #[derive(Debug, Clone, Copy, PartialEq)]
165 pub enum StorageQualifier {
166     StorageClass(StorageClass),
167     Input,
168     Output,
169     Const,
170 }
171 
172 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
173 pub enum StructLayout {
174     Std140,
175     Std430,
176 }
177 
178 // TODO: Encode precision hints in the IR
179 /// A precision hint used in glsl declarations
180 ///
181 /// Precision hints can be used to either speed up shader execution or control
182 /// the precision of arithmetic operations.
183 ///
184 /// To use a precision hint simply add it before the type in the declaration.
185 /// ```glsl
186 /// mediump float a;
187 /// ```
188 ///
189 /// The default when no precision is declared is `highp` which means that all
190 /// operations operate with the type defined width.
191 ///
192 /// For `mediump` and `lowp` operations follow the spir-v
193 /// [`RelaxedPrecision`][RelaxedPrecision] decoration semantics.
194 ///
195 /// [RelaxedPrecision]: https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#_a_id_relaxedprecisionsection_a_relaxed_precision
196 #[derive(Debug, Clone, PartialEq, Copy)]
197 pub enum Precision {
198     /// `lowp` precision
199     Low,
200     /// `mediump` precision
201     Medium,
202     /// `highp` precision
203     High,
204 }
205 
206 #[derive(Debug, Clone, PartialEq, Copy)]
207 pub enum ParameterQualifier {
208     In,
209     Out,
210     InOut,
211     Const,
212 }
213 
214 impl ParameterQualifier {
215     /// Returns true if the argument should be passed as a lhs expression
is_lhs(&self) -> bool216     pub fn is_lhs(&self) -> bool {
217         match *self {
218             ParameterQualifier::Out | ParameterQualifier::InOut => true,
219             _ => false,
220         }
221     }
222 
223     /// Converts from a parameter qualifier into a [`ExprPos`](ExprPos)
as_pos(&self) -> ExprPos224     pub fn as_pos(&self) -> ExprPos {
225         match *self {
226             ParameterQualifier::Out | ParameterQualifier::InOut => ExprPos::Lhs,
227             _ => ExprPos::Rhs,
228         }
229     }
230 }
231 
232 /// The glsl profile used by a shader
233 #[derive(Debug, Clone, Copy, PartialEq)]
234 pub enum Profile {
235     /// The `core` profile, default when no profile is specified.
236     Core,
237 }
238