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 active(&self) -> bool {
24 matches!(self, Self::Active { .. })
25 }
26
27 pub fn activate(self) -> Self {
28 match self {
29 Self::None => Self::Active { else_seen: false },
30 Self::Active { else_seen } | Self::One { else_seen } => Self::Active { else_seen },
31 }
32 }
33
34 pub fn deactivate(self) -> Self {
35 match self {
36 Self::Active { else_seen } => Self::One { else_seen },
37 other => other,
38 }
39 }
40
41 pub fn with_else_seen(self, active: bool) -> Self {
42 if active {
43 match self {
44 Self::None => Self::Active { else_seen: true },
45 Self::Active { .. } | Self::One { .. } => Self::One { else_seen: true },
46 }
47 } else {
48 Self::One { else_seen: true }
49 }
50 }
51}
52
53#[derive(Debug, Error)]
54#[allow(clippy::enum_variant_names)]
55pub enum IfError {
56 #[error("unmatched #elif directive")]
57 ExtraElif,
58 #[error("unmatched #else directive")]
59 ExtraElse,
60 #[error("unmatched #endif directive")]
61 ExtraEndIf,
62}
63
64impl From<IfError> for ProcessingErrorKind {
65 fn from(value: IfError) -> Self {
66 match value {
67 IfError::ExtraElif => ProcessingErrorKind::ExtraElif,
68 IfError::ExtraElse => ProcessingErrorKind::ExtraElse,
69 IfError::ExtraEndIf => ProcessingErrorKind::ExtraEndIf,
70 }
71 }
72}
73
74pub struct IfStack {
75 stack: Vec<IfState>,
76}
77
78impl IfStack {
79 pub fn new() -> Self {
80 Self {
81 stack: Vec::with_capacity(4),
82 }
83 }
84
85 pub fn if_group_active(&self) -> bool {
86 let len = self.stack.len();
87 if len >= 2 {
88 unsafe { self.stack.get_unchecked(len - 2) }.active()
89 } else {
90 true
91 }
92 }
93
94 pub fn active(&self) -> bool {
95 self.stack.last().map(|top| top.active()).unwrap_or(true)
96 }
97
98 pub fn on_if_like(&mut self, expr: bool) {
99 if self.active() && expr {
100 self.stack.push(IfState::Active { else_seen: false });
101 } else {
102 self.stack.push(IfState::None);
103 }
104 }
105
106 pub fn on_elif(&mut self, expr: bool) -> Result<(), IfError> {
107 let top = if let Some(top) = self.stack.pop() {
109 top
110 } else {
111 return Err(IfError::ExtraElif);
112 };
113
114 if top.else_seen() {
116 self.stack.push(IfState::One { else_seen: true });
118 return Err(IfError::ExtraElif);
119 }
120
121 if self.active() && expr {
124 self.stack.push(top.activate());
125 } else {
126 self.stack.push(top.deactivate());
127 }
128
129 Ok(())
130 }
131
132 pub fn on_else(&mut self) -> Result<(), IfError> {
133 let top = if let Some(top) = self.stack.pop() {
135 top
136 } else {
137 return Err(IfError::ExtraElse);
138 };
139
140 if top.else_seen() {
142 self.stack.push(IfState::One { else_seen: true });
144 return Err(IfError::ExtraElif);
145 }
146
147 self.stack.push(top.with_else_seen(self.active()));
149
150 Ok(())
151 }
152
153 pub fn on_endif(&mut self) -> Result<(), IfError> {
154 let _top = if let Some(top) = self.stack.pop() {
156 top
157 } else {
158 return Err(IfError::ExtraEndIf);
159 };
160
161 Ok(())
164 }
165}