glsl_lang_pp/processor/expand/
if_stack.rs1use thiserror::Error;
2
3use crate::processor::event::ProcessingErrorKind;
4
5#[derive(Clone, Copy, PartialEq, Eq)]
6enum IfState {
7 None,
9 Active { else_seen: bool },
11 One { else_seen: bool },
13}
14
15impl IfState {
16 pub fn else_seen(&self) -> bool {
17 match self {
18 Self::None => false,
19 Self::Active { else_seen } | Self::One { else_seen } => *else_seen,
20 }
21 }
22
23 pub fn none(&self) -> bool {
24 matches!(self, Self::None)
25 }
26
27 pub fn active(&self) -> bool {
28 matches!(self, Self::Active { .. })
29 }
30
31 pub fn activate(self) -> Self {
32 match self {
33 Self::None => Self::Active { else_seen: false },
34 Self::Active { else_seen } | Self::One { else_seen } => Self::Active { else_seen },
35 }
36 }
37
38 pub fn deactivate(self) -> Self {
39 match self {
40 Self::Active { else_seen } => Self::One { else_seen },
41 other => other,
42 }
43 }
44
45 pub fn with_else_seen(self, active: bool) -> Self {
46 if active {
47 match self {
48 Self::None => Self::Active { else_seen: true },
49 Self::Active { .. } | Self::One { .. } => Self::One { else_seen: true },
50 }
51 } else {
52 Self::One { else_seen: true }
53 }
54 }
55}
56
57#[derive(Debug, Error)]
58#[allow(clippy::enum_variant_names)]
59pub enum IfError {
60 #[error("unmatched #elif directive")]
61 ExtraElif,
62 #[error("unmatched #else directive")]
63 ExtraElse,
64 #[error("unmatched #endif directive")]
65 ExtraEndIf,
66}
67
68impl From<IfError> for ProcessingErrorKind {
69 fn from(value: IfError) -> Self {
70 match value {
71 IfError::ExtraElif => ProcessingErrorKind::ExtraElif,
72 IfError::ExtraElse => ProcessingErrorKind::ExtraElse,
73 IfError::ExtraEndIf => ProcessingErrorKind::ExtraEndIf,
74 }
75 }
76}
77
78pub struct IfStack {
79 stack: Vec<IfState>,
80}
81
82impl IfStack {
83 pub fn new() -> Self {
84 Self {
85 stack: Vec::with_capacity(4),
86 }
87 }
88
89 pub fn if_group_active(&self) -> bool {
90 let len = self.stack.len();
91 if len >= 2 {
92 unsafe { self.stack.get_unchecked(len - 2) }.active()
93 } else {
94 true
95 }
96 }
97
98 pub fn active(&self) -> bool {
99 self.stack.last().map(|top| top.active()).unwrap_or(true)
100 }
101
102 pub fn none(&self) -> bool {
103 self.stack.last().map(|top| top.none()).unwrap_or(false)
104 }
105
106 pub fn on_if_like(&mut self, expr: bool) {
107 if self.active() && expr {
108 self.stack.push(IfState::Active { else_seen: false });
109 } else {
110 self.stack.push(IfState::None);
111 }
112 }
113
114 pub fn on_elif(&mut self, expr: bool) -> Result<(), IfError> {
115 let top = if let Some(top) = self.stack.pop() {
117 top
118 } else {
119 return Err(IfError::ExtraElif);
120 };
121
122 if top.else_seen() {
124 self.stack.push(IfState::One { else_seen: true });
126 return Err(IfError::ExtraElif);
127 }
128
129 if self.active() && expr {
132 self.stack.push(top.activate());
133 } else {
134 self.stack.push(top.deactivate());
135 }
136
137 Ok(())
138 }
139
140 pub fn on_else(&mut self) -> Result<(), IfError> {
141 let top = if let Some(top) = self.stack.pop() {
143 top
144 } else {
145 return Err(IfError::ExtraElse);
146 };
147
148 if top.else_seen() {
150 self.stack.push(IfState::One { else_seen: true });
152 return Err(IfError::ExtraElif);
153 }
154
155 self.stack.push(top.with_else_seen(self.active()));
157
158 Ok(())
159 }
160
161 pub fn on_endif(&mut self) -> Result<(), IfError> {
162 let _top = if let Some(top) = self.stack.pop() {
164 top
165 } else {
166 return Err(IfError::ExtraEndIf);
167 };
168
169 Ok(())
172 }
173}