Skip to main content

brainfuck_plus_core/
preprocess.rs

1use crate::lexer::lex_file;
2use std::fs;
3use std::path::Path;
4use std::process::exit;
5
6// use std::process::exit;
7use 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                // if nmacro.is_some(){
37                // let nmacro = nmacro.unwrap();
38                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(), &macros);
61            if let Some(macrom) = macrom {
62                let mut macro_tokens = unwrap_macro(macrom, &macros);
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; // move to indent
94
95    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; // move to terms
114
115    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; // skip to terms
158
159    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; // skip endif token
192    } 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; // skip endif token
213    }
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; // skip to terms
234
235    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; // skip endif token
268    } 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; // skip endif token
289    }
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 macrom: Macro = Macro{name: String::new(), tokens: Vec::new()};
427    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        // dbg!(&filename);
566
567        // exit(1);
568
569        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        // dbg!(file_tokens);
615
616        // dbg!(new_tokens);
617
618        // exit(1);
619    }
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    // dbg!(&new_tokens);
646
647    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}