1use std::{
2 collections::HashMap,
3 sync::{atomic::AtomicUsize, Arc},
4};
5
6use hemtt_tokens::{Symbol, Token};
7
8use crate::{defines::Defines, ifstate::IfStates, Error};
9
10const BUILTIN: [&str; 37] = [
11 "__LINE__",
12 "__FILE__",
13 "__DATE_ARR__",
14 "__DATE_STR__",
15 "__DATE_STR_ISO8601__",
16 "__TIME__",
17 "__TIME_UTC__",
18 "__TIMESTAMP_UTC__",
19 "__COUNTER__",
20 "__COUNTER_RESET__",
21 "__RAND_INT8__",
22 "__RAND_INT16__",
23 "__RAND_INT32__",
24 "__RAND_INT64__",
25 "__RAND_UINT8__",
26 "__RAND_UINT16__",
27 "__RAND_UINT32__",
28 "__RAND_UINT64__",
29 "__ARMA__",
30 "__ARMA3__",
31 "__A3_DEBUG__",
32 "__HEMTT__",
33 "__HEMTT_DEBUG__",
34 "__HEMTT_VERSION__",
35 "__HEMTT_VERSION_MAJ__",
36 "__HEMTT_VERSION_MIN__",
37 "__HEMTT_VERSION_REV__",
38 "__HEMTT_VERSION_BUILD__",
39 "__HEMTT_PROJECT_NAME__",
40 "__HEMTT_PROJECT_VERSION__",
41 "__HEMTT_PROJECT_VERSION_MAJ__",
42 "__HEMTT_PROJECT_VERSION_MIN__",
43 "__HEMTT_PROJECT_VERSION_REV__",
44 "__HEMTT_PROJECT_VERSION_BUILD__",
45 "__HEMTT_PROJECT_MAINPREFIX__",
46 "__HEMTT_PROJECT_PREFIX__",
47 "__HEMTT_PROJECT_AUTHOR__",
48];
49
50#[derive(Clone, Debug)]
51pub struct Context<'a> {
53 ifstates: IfStates,
54 definitions: Defines,
55 entry: String,
56 current_file: String,
57 counter: Arc<AtomicUsize>,
58 trace: Vec<Token>,
59 parent: Option<&'a Self>,
60}
61
62impl<'a> Context<'a> {
63 #[must_use]
64 pub fn new(entry: String) -> Self {
66 Self {
67 ifstates: IfStates::new(),
68 definitions: HashMap::new(),
69 current_file: entry.clone(),
70 entry,
71 counter: Arc::new(AtomicUsize::new(0)),
72 trace: Vec::new(),
73 parent: None,
74 }
75 }
76
77 #[must_use]
78 pub fn stack(&'a self, source: Token) -> Context<'a> {
80 Self {
81 ifstates: self.ifstates.clone(),
82 definitions: HashMap::new(),
83 current_file: self.current_file.clone(),
84 entry: self.entry.clone(),
85 counter: self.counter.clone(),
86 trace: {
87 let mut trace = self.trace.clone();
88 trace.push(source);
89 trace
90 },
91 parent: Some(self),
92 }
93 }
94
95 pub fn push(&mut self, source: Token) {
97 self.trace.push(source);
98 }
99
100 pub fn pop(&mut self) -> Option<Token> {
102 self.trace.pop()
103 }
104
105 #[must_use]
106 pub fn trace(&self) -> Vec<Token> {
108 self.trace.clone()
109 }
110
111 #[must_use]
112 pub const fn ifstates(&self) -> &IfStates {
114 &self.ifstates
115 }
116
117 pub fn ifstates_mut(&mut self) -> &mut IfStates {
119 &mut self.ifstates
120 }
121
122 #[must_use]
123 pub const fn definitions(&self) -> &Defines {
125 &self.definitions
126 }
127
128 pub fn definitions_mut(&mut self) -> &mut Defines {
130 &mut self.definitions
131 }
132
133 #[must_use]
134 pub const fn entry(&self) -> &String {
136 &self.entry
137 }
138
139 #[must_use]
140 pub const fn current_file(&self) -> &String {
142 &self.current_file
143 }
144
145 pub fn set_current_file(&mut self, file: String) {
147 self.current_file = file;
148 }
149
150 pub fn define(
155 &mut self,
156 ident: String,
157 source: Token,
158 definition: Definition,
159 ) -> Result<(), Error> {
160 if BUILTIN.contains(&ident.as_str()) {
161 return Err(Error::ChangeBuiltin {
162 token: Box::new(source),
163 trace: self.trace(),
164 });
165 }
166 self.definitions.insert(ident, (source, definition));
167 Ok(())
168 }
169
170 pub fn undefine(
175 &mut self,
176 ident: &str,
177 source: &Token,
178 ) -> Result<Option<(Token, Definition)>, Error> {
179 if BUILTIN.contains(&ident) {
180 return Err(Error::ChangeBuiltin {
181 token: Box::new(source.clone()),
182 trace: self.trace(),
183 });
184 }
185 Ok(self.definitions.remove(ident))
186 }
187
188 #[must_use]
189 pub fn has(&self, ident: &str) -> bool {
191 self.definitions.contains_key(ident)
192 }
193
194 #[must_use]
195 pub fn get(&self, ident: &str, token: &Token) -> Option<(Token, Definition)> {
197 match ident {
198 "__LINE__" => Some((
199 Token::builtin(Some(Box::new(token.clone()))),
200 Definition::Value(vec![Token::new(
201 Symbol::Word(token.source().start().1 .0.to_string()),
202 token.source().clone(),
203 Some(Box::new(token.clone())),
204 )]),
205 )),
206 "__FILE__" => Some((
207 Token::builtin(Some(Box::new(token.clone()))),
208 Definition::Value(vec![Token::new(
209 Symbol::Word(token.source().path().to_string().replace('\\', "/")),
210 token.source().clone(),
211 Some(Box::new(token.clone())),
212 )]),
213 )),
214 "__COUNTER__" => Some((
215 Token::builtin(Some(Box::new(token.clone()))),
216 Definition::Value(vec![Token::new(
217 Symbol::Word(
218 self.counter
219 .fetch_add(1, std::sync::atomic::Ordering::SeqCst)
220 .to_string(),
221 ),
222 token.source().clone(),
223 Some(Box::new(token.clone())),
224 )]),
225 )),
226 "__COUNTER_RESET__" => {
227 self.counter.store(0, std::sync::atomic::Ordering::SeqCst);
228 Some((
229 Token::builtin(Some(Box::new(token.clone()))),
230 Definition::Value(vec![Token::new(
231 Symbol::Void,
232 token.source().clone(),
233 Some(Box::new(token.clone())),
234 )]),
235 ))
236 }
237 "__ARMA__" | "__ARMA3__" | "__HEMTT__" => Some((
238 Token::builtin(Some(Box::new(token.clone()))),
239 Definition::Value(vec![Token::new(
240 Symbol::Digit(1),
241 token.source().clone(),
242 Some(Box::new(token.clone())),
243 )]),
244 )),
245 _ => {
246 let mut context = self;
248 loop {
249 if let Some((source, definition)) = context.definitions.get(ident) {
250 return Some((source.clone(), definition.clone()));
251 }
252 if let Some(parent) = &context.parent {
253 context = parent;
254 } else {
255 break;
256 }
257 }
258 None
259 }
260 }
261 }
262}
263
264#[derive(Clone, Debug, PartialEq, Eq)]
265pub enum Definition {
267 Function(FunctionDefinition),
269 Value(Vec<Token>),
271 Unit(Vec<Token>),
274}
275
276impl Definition {
277 #[must_use]
278 pub const fn is_function(&self) -> bool {
280 matches!(self, Self::Function(_))
281 }
282
283 #[must_use]
284 pub const fn is_value(&self) -> bool {
286 matches!(self, Self::Value(_))
287 }
288
289 #[must_use]
290 pub const fn is_unit(&self) -> bool {
292 matches!(self, Self::Unit(_))
293 }
294}
295
296#[derive(Clone, Debug, PartialEq, Eq)]
297pub struct FunctionDefinition {
307 parameters: Vec<Token>,
308 body: Vec<Token>,
309}
310
311impl FunctionDefinition {
312 #[must_use]
313 pub fn new(parameters: Vec<Token>, body: Vec<Token>) -> Self {
315 Self { parameters, body }
316 }
317
318 #[must_use]
319 pub fn parameters(&self) -> &[Token] {
321 &self.parameters
322 }
323
324 #[must_use]
325 pub fn body(&self) -> &[Token] {
327 &self.body
328 }
329}