diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/macro_processor/macro_processor.rs | 275 | 
1 files changed, 160 insertions, 115 deletions
diff --git a/src/macro_processor/macro_processor.rs b/src/macro_processor/macro_processor.rs index 306aa04..0d931f9 100644 --- a/src/macro_processor/macro_processor.rs +++ b/src/macro_processor/macro_processor.rs @@ -1,5 +1,6 @@  use std::collections::HashMap;  use std::fs; +use std::process::Command;  // print only with debug_assertions  macro_rules! dprint { @@ -37,143 +38,191 @@ macro_rules! highlight_debug {      };  } -#[derive(Debug)] +pub enum MacroType { +    Function(fn(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String), +    String(String) +} +  pub struct MacroProcessor { -    macros: HashMap<String, String>, +    macros: HashMap<String, MacroType>,  } -impl MacroProcessor { -    pub fn new() -> Self { -        Self { -            macros: HashMap::new(), -        } +fn smp_builtin_define(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String { +    if args.len() < 1 { +        return macro_name.to_string(); +    } +    let arg0 = smp.process_input(&args[0]); +    if args.len() > 1 { +        let arg1 = smp.process_input(&args[1]); +        smp.define_macro(arg0, arg1); +    } else { +        smp.define_macro(arg0, String::new());      } +    String::new() +} -    pub fn define_macro(&mut self, name: String, body: String) { -        self.macros.insert(name, body); +fn smp_builtin_ifdef(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String { +    if args.len() < 2 { +        return macro_name.to_string(); +    } +    // We need to expand the first argument here as well, but we need to make the parser +    // support literal, and phrase strings +    if smp.macros.contains_key(&args[0]) { +        return smp.process_input(&args[1]);      } +    if args.len() > 2 { +        return smp.process_input(&args[2]); +    } +    String::new() +} -    /// This expands a macro definition, and it executes builtin functions, like define -    /// Currently, you cannot overwrite builtin's. -    /// This is partly by design, and I don't currently see why I would want that. -    /// In the future, this may change -    /// -    /// (The HashMap might become a HashMap<String, Box<dyn FnMut>> or something similar. -    ///  Then, all builtins would also be functions, and "normal" macros, would simply -    ///  be closures returning the string) -    fn expand_macro(&mut self, macro_name: &str, args: &mut [String]) -> String { -        if macro_name == "define" { -            if args.len() < 1 { -                println!("Missing argument(s) to `define`, found {} but expected 1 or 2", args.len()); -                return String::new(); -            } -            let arg0 = self.process_input(&args[0]); -            if args.len() > 1 { -                let arg1 = self.process_input(&args[1]); -                self.define_macro(arg0, arg1); -            } else { -                self.define_macro(arg0, String::new()); -            } -            return String::new(); -        } +fn smp_builtin_ifndef(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String { +    if args.len() < 2 { +        return macro_name.to_string(); +    } +    // We need to expand the first argument here as well, but we need to make the parser +    // support literal, and phrase strings +    if !smp.macros.contains_key(&args[0]) { +        return smp.process_input(&args[1]); +    } +    if args.len() > 2 { +        return smp.process_input(&args[2]); +    } +    String::new() +} -        if macro_name == "ifdef" { -            if args.len() < 2 { -                println!("Missing argument(s) to `ifdef`, found {} but expected 2 or 3", args.len()); -                return String::new(); -            } -            // We need to expand the first argument here as well, but we need to make the parser -            // support literal, and phrase strings -            if self.macros.contains_key(&args[0]) { -                return self.process_input(&args[1]); -            } -            if args.len() > 2 { -                return self.process_input(&args[2]); -            } -            return String::new(); -        } +fn smp_builtin_ifeq(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String { +    if args.len() < 3 { +        return macro_name.to_string(); +    } +    let arg0 = smp.process_input(&args[0]); +    let arg1 = smp.process_input(&args[1]); +    if arg0 == arg1 { +        return smp.process_input(&args[2]); +    } +    if args.len() > 3 { +        return smp.process_input(&args[3]); +    } +    String::new() +} -        if macro_name == "ifndef" { -            if args.len() < 2 { -                println!("Missing argument(s) to `ifndef`, found {} but expected 2 or 3", args.len()); -                return String::new(); -            } -            // We need to expand the first argument here as well, but we need to make the parser -            // support literal, and phrase strings -            if !self.macros.contains_key(&args[0]) { -                return self.process_input(&args[1]); -            } -            if args.len() > 2 { -                return self.process_input(&args[2]); -            } -            return String::new(); -        } +fn smp_builtin_ifneq(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String { +    if args.len() < 3 { +        return macro_name.to_string(); +    } +    let arg0 = smp.process_input(&args[0]); +    let arg1 = smp.process_input(&args[1]); +    if arg0 != arg1 { +        return smp.process_input(&args[2]); +    } +    if args.len() > 3 { +        return smp.process_input(&args[3]); +    } +    return String::new(); +} -        if macro_name == "ifeq" { -            if args.len() < 3 { -                println!("Missing argument(s) to `ifeq`, found {} but expected 3 or 4", args.len()); -                return String::new(); -            } -            let arg0 = self.process_input(&args[0]); -            let arg1 = self.process_input(&args[1]); -            if arg0 == arg1 { -                return self.process_input(&args[2]); -            } -            if args.len() > 3 { -                return self.process_input(&args[3]); -            } -            return String::new(); -        } +fn smp_builtin_include(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String { +    if args.len() < 1 { +        return macro_name.to_string(); +    } +    let arg0 = smp.process_input(&args[0]); +    let input_file = fs::read_to_string(&arg0).expect("Failed to read input file"); +    return smp.process_input(&input_file); +} -        if macro_name == "ifneq" { -            if args.len() < 3 { -                println!("Missing argument(s) to `ifneq`, found {} but expected 3 or 4", args.len()); -                return String::new(); -            } -            let arg0 = self.process_input(&args[0]); -            let arg1 = self.process_input(&args[1]); -            if arg0 != arg1 { -                return self.process_input(&args[2]); -            } -            if args.len() > 3 { -                return self.process_input(&args[3]); -            } -            return String::new(); -        } -         -        if macro_name == "include" { -            if args.len() < 1 { -                println!("Missing argument(s) to `include`, found {} but expected 1", args.len()); -                return String::new(); -            } -            let arg0 = self.process_input(&args[0]); -            let input_file = fs::read_to_string(&arg0).expect("Failed to read input file"); -            return self.process_input(&input_file); -        } +fn smp_builtin_shell(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String { +    if args.len() < 1 { +        return macro_name.to_string(); +    } +    let arg0 = smp.process_input(&args[0]); +    let res = Command::new("sh") +        .arg("-c") +        .arg(arg0) +        .output(); +    match res { +        Ok(output) => String::from_utf8(output.stdout).expect("SMP1"), +        Err(_) => String::new() +    } +} -        //Expand macro name? somwhat unsure on how to do this safely -        //let macro_name = self.process_input(macro_name); +/// Would like one that is better than this tbh +fn smp_builtin_expr(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String { +    if args.len() < 1 { +        return macro_name.to_string(); +    } + +    for arg in args.iter_mut() { +        *arg = smp.process_input(&arg); +    } +    let res = Command::new("expr") +        .args(args) +        .output(); +    match res { +        Ok(output) => String::from_utf8(output.stdout).expect("SMP1"), +        Err(_) => String::new() +    } +} + +impl MacroProcessor { +    pub fn new() -> Self { +        let mut smp = Self { +            macros: HashMap::new(), +        }; +        smp.define_builtins(); +        smp +    } + +    fn define_builtins(&mut self) { +        self.define_macro_fn(String::from("define"), MacroType::Function(smp_builtin_define)); +        self.define_macro_fn(String::from("ifdef"), MacroType::Function(smp_builtin_ifdef)); +        self.define_macro_fn(String::from("ifndef"), MacroType::Function(smp_builtin_ifndef)); +        self.define_macro_fn(String::from("ifeq"), MacroType::Function(smp_builtin_ifeq)); +        self.define_macro_fn(String::from("ifneq"), MacroType::Function(smp_builtin_ifneq)); +        self.define_macro_fn(String::from("include"), MacroType::Function(smp_builtin_include)); +        self.define_macro_fn(String::from("shell"), MacroType::Function(smp_builtin_shell)); +        self.define_macro_fn(String::from("expr"), MacroType::Function(smp_builtin_expr)); +        // TODO +        // format('Result id %d', 3282) +    } + +    pub fn define_macro(&mut self, name: String, body: String) { +        self.macros.insert(name, MacroType::String(body)); +    } + +    pub fn define_macro_fn(&mut self, name: String, macro_expansion: MacroType) { +        self.macros.insert(name, macro_expansion); +    } +     +    /// This expands a macro definition, and it executes builtin functions, like define +    fn expand_macro(&mut self, macro_name: &str, args: &mut [String]) -> String {          let Some(macro_body) = self.macros.get(macro_name) else {              return format!("{}", macro_name);          }; -        let mut expanded = macro_body.clone(); -        for (i, arg) in args.iter().enumerate() { -            let placeholder = format!("${}", i + 1); -            expanded = expanded.replace(&placeholder, arg); +        match macro_body { +            MacroType::String(body) => { +                let mut expanded = body.clone(); +                for (i, arg) in args.iter().enumerate() { +                    let placeholder = format!("${}", i + 1); +                    expanded = expanded.replace(&placeholder, arg); +                } +                return expanded; +            }, +            MacroType::Function(func) => { +                return func(self, macro_name, args); +            },          } -        expanded      }      pub fn process_input(&mut self, input: &str) -> String {          let mut output = String::new();          let mut state = ParserState::Normal; -        let mut state_previous = ParserState::Normal;          let mut macro_name = String::new();          let mut macro_args = Vec::new();          let mut argument = String::new();          let mut macro_name_start = 0; +          let mut skip_next_line_ending = false;          let mut in_quote_single = false; @@ -193,7 +242,6 @@ impl MacroProcessor {                      if c.is_alphanumeric() {                          state = ParserState::InMacro; -                        state_previous = ParserState::Normal;                          macro_name.push(c);                      } else {                          output.push(c); @@ -204,12 +252,11 @@ impl MacroProcessor {                          macro_name.push(c);                      } else if c == '(' {                          state = ParserState::InMacroArgs; -                        state_previous = ParserState::InMacro;                      } else {                          if self.macros.contains_key(¯o_name) {                              highlight_debug!("\x1b[32m\x1b[7m", input, (macro_name_start -> i));                          } -                        if macro_name == "DNL" { +                        if macro_name == "SNNL" {                              skip_next_line_ending = c != '\n';                          } else {                              let expanded = self.expand_macro(¯o_name, &mut []); @@ -218,7 +265,6 @@ impl MacroProcessor {                          }                          macro_name.clear();                          state = ParserState::Normal; -                        state_previous = ParserState::InMacro;                      }                  }                  ParserState::InMacroArgs => { @@ -229,7 +275,6 @@ impl MacroProcessor {                          let expanded = self.expand_macro(¯o_name, &mut macro_args);                          output.push_str(&expanded);                          state = ParserState::Normal; -                        state_previous = ParserState::InMacroArgs;                          macro_name.clear();                          macro_args.clear();                          argument.clear();  | 
