1use crate::lexer::lex_file;
2use std::fs;
3use std::path::Path;
4use std::process::exit;
5
6use crate::prelude::*;
8
9#[derive(Debug, Clone)]
10pub struct Macro {
11 pub name: String,
12 pub tokens: Vec<Token>,
13}
14
15#[must_use]
16pub fn is_macro(name: String, macros: &[Macro]) -> Option<Macro> {
17 let mut macroms: Option<Macro> = None;
18 for macrom in macros {
19 if name == macrom.name {
20 macroms = Some(macrom.clone());
21 break;
22 }
23 }
24 macroms
25}
26
27fn unwrap_macro(uno_macro: Macro, macros: &Vec<Macro>) -> Vec<Token> {
28 let mut unwrap_token: Vec<Token> = Vec::new();
29 for token in &uno_macro.tokens {
30 if token.token_type != TokenType::Ident {
31 unwrap_token.push(token.clone());
32 } else {
33 let name = token.value.clone();
34 let nmacro = is_macro(name, macros);
35 if let Some(nmacro) = nmacro {
36 let mut tokens = unwrap_macro(nmacro, macros);
39 unwrap_token.append(&mut tokens);
40 } else {
41 println!("{}:{}:{} Unwrap Macros: Undentifier Not defined {}", token.filename, token.row, token.col +1, token.value);
42 exit(1);
43 }
44 }
45 }
46 unwrap_token
47}
48
49fn unwrap_macros(tokens: Vec<Token>, macros: Vec<Macro>) -> Vec<Token> {
50 let mut next_tokens: Vec<Token> = Vec::new();
51 let mut i: usize = 0;
52 let len: usize = tokens.len();
53 while i < len {
54 let token = tokens[i].clone();
55
56 if !(token.token_type == TokenType::Ident) {
57 next_tokens.push(token);
58 } else {
59 let name = token.value.clone();
60 let macrom = is_macro(name.clone(), ¯os);
61 if let Some(macrom) = macrom {
62 let mut macro_tokens = unwrap_macro(macrom, ¯os);
63 next_tokens.append(&mut macro_tokens);
64 } else {
65 println!("{}:{}:{} Undentifier Not defined: {}",tokens[i].filename,
66 tokens[i].row,
67 tokens[i].col + 1,name);
68 exit(1);
69 }
70 }
71
72 i += 1;
73 }
74
75 next_tokens
76}
77
78fn is_macro_token(token_type: TokenType) -> bool {
79 token_type == TokenType::MacroDecl
80 || token_type == TokenType::IfdefMacro
81 || token_type == TokenType::IfNdefMacro
82 || token_type == TokenType::ElseMacro
83 || token_type == TokenType::EndifMacro
84 || token_type == TokenType::TapeDecl
85}
86
87fn preprocess_macro_decl(i: &mut usize, tokens: &[Token], macros: &mut Vec<Macro>) {
88 let mut macrom: Macro = Macro {
89 name: String::new(),
90 tokens: Vec::new(),
91 };
92
93 *i += 1; let macro_name: Token = tokens[*i].clone();
96
97 if macro_name.token_type != TokenType::Ident {
98 println!("{}:{}:{} MacroDecl: Expected identifier", tokens[*i].filename,
99 tokens[*i].row,
100 tokens[*i].col + 1);
101 exit(1);
102 }
103
104 for macron in &*macros {
105 if macro_name.value == macron.name {
106 println!("{}:{}:{} Macro already defined: #define {}", tokens[*i].filename,
107 tokens[*i].row,
108 tokens[*i].col + 1, macro_name.value);
109 exit(1);
110 }
111 }
112
113 *i += 1; macrom.name = macro_name.value;
116
117 let mut terms: Vec<Token> = Vec::new();
118
119 while tokens[*i].token_type != TokenType::NewLine {
120 let token = tokens[*i].clone();
121
122 if is_macro_token(token.token_type.clone()) {
123 println!("{}:{}:{} Cannot Put Macro inside #define", tokens[*i].filename,
124 tokens[*i].row,
125 tokens[*i].col + 1);
126 exit(1);
127 } else {
128 terms.push(token);
129 }
130
131 *i += 1;
132 }
133
134 macrom.tokens = terms;
135
136 macros.push(macrom);
137}
138
139fn preprocess_ifdef_macro(
140 i: &mut usize,
141 tokens: &[Token],
142 new_tokens: &mut Vec<Token>,
143 macros: &mut Vec<Macro>,
144 tapes: &mut Vec<Tape>,
145) {
146 *i += 1;
147
148 let macro_name: Token = tokens[*i].clone();
149
150 if macro_name.token_type != TokenType::Ident {
151 println!("{}:{}:{} Ifdef Macro: Expected identifier", tokens[*i].filename,
152 tokens[*i].row,
153 tokens[*i].col + 1);
154 exit(1);
155 }
156
157 *i += 1; let is_defined = {
160 let mut answ: bool = false;
161 for macrom in &*macros {
162 if macro_name.value == macrom.name {
163 answ = true;
164 break;
165 }
166 }
167
168 answ
169 };
170
171 if is_defined {
172 while tokens[*i].token_type != TokenType::ElseMacro
173 && tokens[*i].token_type != TokenType::EndifMacro
174 {
175 let token: Token = tokens[*i].clone();
176
177 if is_macro_token(token.token_type.clone()) {
178 preprocess_macro(i, tokens, new_tokens, macros, tapes);
179 } else {
180 new_tokens.push(token);
181 *i += 1;
182 }
183 }
184
185 if tokens[*i].token_type == TokenType::ElseMacro {
186 while tokens[*i].token_type != TokenType::EndifMacro {
187 *i += 1;
188 }
189 }
190
191 *i += 1; } else {
193 while tokens[*i].token_type != TokenType::ElseMacro
194 && tokens[*i].token_type != TokenType::EndifMacro
195 {
196 *i += 1;
197 }
198
199 if tokens[*i].token_type == TokenType::ElseMacro {
200 *i += 1;
201 while tokens[*i].token_type != TokenType::EndifMacro {
202 let token: Token = tokens[*i].clone();
203
204 if is_macro_token(token.token_type.clone()) {
205 preprocess_macro(i, tokens, new_tokens, macros, tapes);
206 } else {
207 new_tokens.push(token);
208 *i += 1;
209 }
210 }
211 }
212 *i += 1; }
214}
215fn preprocess_ifndef_macro(
216 i: &mut usize,
217 tokens: &[Token],
218 new_tokens: &mut Vec<Token>,
219 macros: &mut Vec<Macro>,
220 tapes: &mut Vec<Tape>,
221) {
222 *i += 1;
223
224 let macro_name: Token = tokens[*i].clone();
225
226 if macro_name.token_type != TokenType::Ident {
227 println!("{}:{}:{} Ifdef Macro: Expected identifier", tokens[*i].filename,
228 tokens[*i].row,
229 tokens[*i].col + 1);
230 exit(1);
231 }
232
233 *i += 1; let is_defined = {
236 let mut answ: bool = false;
237 for macrom in &*macros {
238 if macro_name.value == macrom.name {
239 answ = true;
240 break;
241 }
242 }
243
244 answ
245 };
246
247 if !is_defined {
248 while tokens[*i].token_type != TokenType::ElseMacro
249 && tokens[*i].token_type != TokenType::EndifMacro
250 {
251 let token: Token = tokens[*i].clone();
252
253 if is_macro_token(token.token_type.clone()) {
254 preprocess_macro(i, tokens, new_tokens, macros, tapes);
255 } else {
256 new_tokens.push(token);
257 *i += 1;
258 }
259 }
260
261 if tokens[*i].token_type == TokenType::ElseMacro {
262 while tokens[*i].token_type != TokenType::EndifMacro {
263 *i += 1;
264 }
265 }
266
267 *i += 1; } else {
269 while tokens[*i].token_type != TokenType::ElseMacro
270 && tokens[*i].token_type != TokenType::EndifMacro
271 {
272 *i += 1;
273 }
274
275 if tokens[*i].token_type == TokenType::ElseMacro {
276 *i += 1;
277 while tokens[*i].token_type != TokenType::EndifMacro {
278 let token: Token = tokens[*i].clone();
279
280 if is_macro_token(token.token_type.clone()) {
281 preprocess_macro(i, tokens, new_tokens, macros, tapes);
282 } else {
283 new_tokens.push(token);
284 *i += 1;
285 }
286 }
287 }
288 *i += 1; }
290}
291
292fn preprocess_tape_decl(
293 i: &mut usize,
294 tokens: &[Token],
295 tapes: &mut Vec<Tape>,
296 macros: &Vec<Macro>,
297) {
298 let mut tape = Tape {
299 name: String::new(),
300 size: Size::Byte,
301 cell_count: 0,
302 };
303
304 *i += 1;
305
306 let name = tokens[*i].clone();
307
308 if name.token_type != TokenType::Ident {
309 println!("{}:{}:{} TapeDecl: Expected identifier", tokens[*i].filename,
310 tokens[*i].row,
311 tokens[*i].col + 1);
312 exit(1);
313 }
314
315 *i += 1;
316
317 tape.name = name.value;
318
319 let size = tokens[*i].clone();
320
321 if size.token_type != TokenType::CellSize {
322 println!(
323 "{}:{}:{} TapeDecl({}): Expected CellSize (byte, word, dword, qword) got {}",
324 tokens[*i].filename,
325 tokens[*i].row,
326 tokens[*i].col + 1,tape.name, size.value
327 );
328 exit(1);
329 }
330
331 tape.size = match size.value.as_str() {
332 "byte" => Size::Byte,
333
334 "word" => Size::Word,
335
336 "dword" => Size::Dword,
337
338 "qword" => Size::Qword,
339
340 _ => {
341 println!("{}:{}:{} TapeDecl: Unreachable", tokens[*i].filename,
342 tokens[*i].row,
343 tokens[*i].col + 1);
344 exit(1);
345 }
346 };
347
348 *i += 1;
349
350 let mut cell_count = tokens[*i].clone();
351
352 if cell_count.token_type == TokenType::Ident {
353 let mut is_macro: bool = false;
354 let mut macro_id: usize = 0;
355
356 for (n, macrom) in macros.iter().enumerate() {
357 if macrom.name == cell_count.value {
358 is_macro = true;
359 macro_id = n;
360 }
361 }
362
363 if !is_macro {
364 println!("{}:{}:{} TapeDecl: Identifier {} not defined", tokens[*i].filename,
365 tokens[*i].row,
366 tokens[*i].col + 1, cell_count.value);
367 exit(1);
368 }
369
370 let macrom = macros[macro_id].clone();
371
372 let macro_tokens = unwrap_macro(macrom, macros);
373
374 if macro_tokens.len() > 1 {
375 println!("{}:{}:{} TapeDecl: Expected IntLit", tokens[*i].filename,
376 tokens[*i].row,
377 tokens[*i].col + 1);
378 exit(1);
379 }
380
381 if macro_tokens[0].token_type != TokenType::IntLit {
382 println!("{}:{}:{} TapeDecl: Expected IntLit", tokens[*i].filename,
383 tokens[*i].row,
384 tokens[*i].col + 1);
385 exit(1);
386 }
387
388 cell_count = macro_tokens[0].clone();
389 }
390
391 if cell_count.token_type != TokenType::IntLit {
392 println!(
393 "{}:{}:{} TapeDecl({}): Expected IntLit got {}",tokens[*i].filename,
394 tokens[*i].row,
395 tokens[*i].col + 1,
396 tape.name, size.value
397 );
398 exit(1);
399 }
400
401 tape.cell_count = cell_count.value.parse().unwrap();
402
403 *i += 1;
404
405 if tokens[*i].token_type != TokenType::NewLine {
406 println!(
407 "{}:{}:{} TapeDecl({}): Expected a new line got {}",
408 tokens[*i].filename,
409 tokens[*i].row,
410 tokens[*i].col + 1,
411 tape.name, size.value
412 );
413 exit(1);
414 }
415
416 tapes.push(tape);
417}
418
419fn preprocess_macro(
420 i: &mut usize,
421 tokens: &[Token],
422 new_tokens: &mut Vec<Token>,
423 macros: &mut Vec<Macro>,
424 tapes: &mut Vec<Tape>,
425) {
426 let token: Token = tokens[*i].clone();
428
429 match token.token_type {
430 TokenType::MacroDecl => {
431 preprocess_macro_decl(i, tokens, macros);
432 }
433
434 TokenType::IfdefMacro => {
435 preprocess_ifdef_macro(i, tokens, new_tokens, macros, tapes);
436 }
437
438 TokenType::IfNdefMacro => {
439 preprocess_ifndef_macro(i, tokens, new_tokens, macros, tapes);
440 }
441
442 TokenType::EndifMacro => {
443 println!("{}:{}:{} EndifMacro: You need to declare contition", token.filename,
444 token.row,
445 token.col + 1);
446 exit(1);
447 }
448
449 TokenType::ElseMacro => {
450 println!("{}:{}:{} ElseMacro: You need to declare contition", token.filename,
451 token.row,
452 token.col + 1);
453 exit(1);
454 }
455
456 TokenType::TapeDecl => {
457 preprocess_tape_decl(i, tokens, tapes, macros);
458 }
459
460 _ => {
461 println!(
462 "{}:{}:{} Unreachable, there are only macro tokens got {}",
463 token.filename,
464 token.row,
465 token.col + 1
466 ,
467 token.value
468 );
469 exit(1);
470 }
471 }
472}
473
474fn preprocess_macros(tokens: Vec<Token>, tapes: &mut Vec<Tape>) -> (Vec<Token>, Vec<Macro>) {
475 let mut new_tokens: Vec<Token> = Vec::new();
476 let mut macros: Vec<Macro> = Vec::new();
477 let mut i: usize = 0;
478 let len: usize = tokens.len();
479
480 while i < len {
481 let token: Token = tokens[i].clone();
482
483 if is_macro_token(token.token_type.clone()) {
484 preprocess_macro(&mut i, &tokens, &mut new_tokens, &mut macros, tapes);
485 } else {
486 new_tokens.push(token);
487 }
488
489 i += 1;
490 }
491
492 (new_tokens, macros)
493}
494
495fn preprocess_include(
496 i: &mut usize,
497 tokens: &[Token],
498 current_path: String,
499 path: &String,
500 new_tokens: &mut Vec<Token>,
501 includes: &Vec<String>,
502 _tapes: &mut Vec<Tape>,
503) {
504 let token = tokens[*i].clone();
505
506 if token.token_type != TokenType::IncludeMacro {
507 new_tokens.push(token);
508 *i += 1;
509 } else {
510 *i += 1;
511 let file_name: Token = tokens[*i].clone();
512
513 if file_name.token_type != TokenType::StringLit
514 && file_name.token_type != TokenType::IncludePath
515 {
516 println!("{}:{}:{} IncludeDecl: Expected String Literal or Include Path", token.filename,
517 token.row,
518 token.col + 1);
519 exit(1);
520 }
521
522 *i += 1;
523
524 let filename: String = {
525 if file_name.token_type == TokenType::StringLit {
526 path.clone() + file_name.value.as_str()
527 } else {
528 let include_path: Vec<&str> = file_name.value.split('/').collect::<Vec<&str>>();
529 let len: usize = include_path.len() - 1;
530 let mut exists: Option<String> = None;
531 for path in includes {
532 let path_arr = path.split('/').collect::<Vec<&str>>();
533 let path_len = path_arr.len();
534 let mut path_str = {
535 let mut path = String::new();
536 for folder in path_arr.iter().take(path_len - len) {
537 path += folder;
538 path += "/";
539 }
540 path
541 };
542 path_str += file_name.value.as_str();
543 let path_path = Path::new(path_str.as_str());
544 if path_path.exists() {
545 exists = Some(path_str);
546 break;
547 }
548
549 dbg!(&path_str);
550 }
551 let out;
552 if let Some(exists) = exists {
553 out = exists;
554 } else {
555 println!("{}:{}:{} Could not find include: {}",token.filename,
556 token.row,
557 token.col + 1, file_name.value);
558 exit(1);
559 }
560
561 out
562 }
563 };
564
565 if filename == current_path {
570 println!(
571 "{}:{}:{} IncludeDecl: Cannot include file in itself file: {filename}",
572 token.filename,
573 token.row,
574 token.col + 1
575 );
576 exit(1);
577 }
578
579 if !filename.ends_with(".bf") {
580 println!(
581 "{}:{}:{} IncludeDecl: Brain fuck plus files must have .bf extension",
582 token.filename,
583 token.row,
584 token.col + 1
585 );
586 exit(1);
587 }
588
589 let contents =
590 fs::read_to_string(filename.clone()).expect("Something went wrong reading the file");
591
592 let file_tokens = lex_file(contents, filename.clone());
593
594 let mut file_i: usize = 0;
595 let file_len: usize = file_tokens.len();
596
597 while file_i < file_len {
598 if token.token_type.clone() != TokenType::IncludeMacro {
599 new_tokens.push(token.clone());
600 file_i += 1;
601 } else {
602 preprocess_include(
603 &mut file_i,
604 &file_tokens,
605 filename.clone(),
606 path,
607 new_tokens,
608 includes,
609 _tapes,
610 );
611 }
612 }
613
614 }
620}
621
622fn include_includes(
623 tokens: Vec<Token>,
624 current_path: String,
625 path: String,
626 includes: Vec<String>,
627 tapes: &mut Vec<Tape>,
628) -> Vec<Token> {
629 let mut i: usize = 0;
630 let len: usize = tokens.len();
631 let mut new_tokens: Vec<Token> = Vec::new();
632
633 while i < len {
634 preprocess_include(
635 &mut i,
636 &tokens,
637 current_path.clone(),
638 &path,
639 &mut new_tokens,
640 &includes,
641 tapes,
642 );
643 }
644
645 new_tokens
648}
649
650fn discover_extern_funcs(tokens: &[Token]) -> (Vec<String>, Vec<Token>){
651 let mut i: usize = 0;
652 let len: usize = tokens.len();
653
654 let mut extern_funcs: Vec<String> = Vec::new();
655 let mut new_tokens: Vec<Token> = Vec::new();
656
657 while i < len{
658
659 let token: Token = tokens[i].clone();
660
661 if token.token_type == TokenType::ExternFuncDecl{
662 i+=1;
663 let ident = tokens[i].clone();
664 if ident.token_type != TokenType::Ident{
665 println!(
666 "{}:{}:{} ExternFuncDecl: Expected Identifier got {:?}",
667 token.filename,
668 token.row,
669 token.col + 1,
670 token.token_type
671 );
672 exit(1);
673 }
674
675 i+=1;
676
677 if tokens[i].token_type != TokenType::NewLine{
678 println!(
679 "{}:{}:{} ExternFuncDecl: Expected NewLine got {:?}",
680 token.filename,
681 token.row,
682 token.col + 1,
683 token.token_type
684 );
685 exit(1);
686 }
687
688 extern_funcs.push(ident.value);
689
690 }else{
691 new_tokens.push(token);
692 }
693
694 i+=1;
695 }
696
697 (extern_funcs, new_tokens)
698}
699
700pub fn preprocess_tokens(
701 tokens: Vec<Token>,
702 current_path: String,
703 path: String,
704 includes: Vec<String>,
705 tapes: &mut Vec<Tape>,
706) -> (Vec<Token>, Vec<String>) {
707
708
709 let new_tokens = include_includes(tokens, current_path, path, includes, tapes);
710
711 let (extern_funcs, new_tokens) = discover_extern_funcs(new_tokens.as_slice());
712
713 let (new_tokens, macros) = preprocess_macros(new_tokens, tapes);
714
715 (unwrap_macros(new_tokens, macros), extern_funcs)
716}