1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
/// This is an implementation of a very simple (read very-bad) C pre-processor
/// it doesn't do true tokenization and it doesn't support many features.
///
/// It does support the following:
///    * Logical line concatenation
///    * Comments (Line and block)
///    * `define` for constant strings
///    * `undef`
///    * `ifdef` and `ifndef`
///
/// It does not support the following:
///    * Macro functions
///    * Symbol concatenation
///    * Generalized `if`
pub mod lexer;

use lexer::OwningTokenizer;
use regex::Regex;
use std::path::PathBuf;

// Reference:
//     * https://www.lysator.liu.se/c/ANSI-C-grammar-l.html
//     * https://github.com/bagder/fcpp
//     * https://github.com/danmar/simplecpp

pub fn splice_lines<S: AsRef<str>>(input: S) -> String {
    let line_regex = Regex::new("\r\n|\n\r|\r").unwrap();

    line_regex.replace_all(input.as_ref(), "\n").into()
}

#[cfg(test)]
mod splice_tests {
    use crate::splice_lines;
    #[test]
    fn nothing_to_do() {
        assert_eq!(splice_lines("a\nb"), "a\nb")
    }

    #[test]
    fn windows_line_ending() {
        assert_eq!(splice_lines("a\r\nb"), "a\nb")
    }

    #[test]
    fn reverse_windows_line_ending() {
        assert_eq!(splice_lines("a\n\rb"), "a\nb")
    }

    #[test]
    fn longest_sequence_first() {
        assert_eq!(splice_lines("a\r\n\rb"), "a\n\nb")
    }

    #[test]
    fn non_greedy() {
        assert_eq!(splice_lines("a\n\r\nb"), "a\n\nb")
    }
}

pub fn preprocess(_input: String) -> String {
    // let stream = TokenStream {
    //     path: "/".into(),
    //     tokenizer: OwningTokenizer::new(input),
    // };
    // let mut file_stack = vec![Tokenizer::new(&input)];
    // let mut current_token_stream = file_stack.last_mut().unwrap();

    // //let ouput_token_stream = Vec::new();
    // let current_row = Vec::new();

    // let mut in_directive = false;

    // while file_stack.len() > 0 {

    //     // Grab a single line of nput off the currently active token stream
    //     loop {
    //         match current_token_stream.get_next_token() {
    //             Ok(tok) => {
    //                 match tok.token_type {
    //                     TokenType::Punctuator if tok.text == "#" => {
    //                         in_directive = true;
    //                     }
    //                     TokenType::EOL => {
    //                         current_row.push(tok);
    //                         break;
    //                     }
    //                     TokenType::EOF => break,
    //                     _ => current_row.push(tok),
    //                 }
    //             }
    //             Err(err) => {
    //                 unimplemented!();
    //             }
    //         }
    //     }

    //     //Process the current line
    // }

    "".into()
}

struct TokenStream {
    path: PathBuf,
    tokenizer: OwningTokenizer,
}