diff options
Diffstat (limited to 'src/macro_processor')
| -rw-r--r-- | src/macro_processor/macro_processor.rs | 130 | ||||
| -rw-r--r-- | src/macro_processor/main.rs | 4 | 
2 files changed, 97 insertions, 37 deletions
diff --git a/src/macro_processor/macro_processor.rs b/src/macro_processor/macro_processor.rs index 0d931f9..4a46a62 100644 --- a/src/macro_processor/macro_processor.rs +++ b/src/macro_processor/macro_processor.rs @@ -38,15 +38,7 @@ macro_rules! highlight_debug {      };  } -pub enum MacroType { -    Function(fn(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String), -    String(String) -} - -pub struct MacroProcessor { -    macros: HashMap<String, MacroType>, -} - +/// Builtin for defining a new macro  fn smp_builtin_define(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String {      if args.len() < 1 {          return macro_name.to_string(); @@ -61,6 +53,7 @@ fn smp_builtin_define(smp: &mut MacroProcessor, macro_name: &str, args: &mut [St      String::new()  } +/// If macro is defined, return second argument, else return third argument if provided  fn smp_builtin_ifdef(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String {      if args.len() < 2 {          return macro_name.to_string(); @@ -76,6 +69,7 @@ fn smp_builtin_ifdef(smp: &mut MacroProcessor, macro_name: &str, args: &mut [Str      String::new()  } +/// If macro is not defined, return second argument, else return third argument if provided  fn smp_builtin_ifndef(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String {      if args.len() < 2 {          return macro_name.to_string(); @@ -91,6 +85,7 @@ fn smp_builtin_ifndef(smp: &mut MacroProcessor, macro_name: &str, args: &mut [St      String::new()  } +/// If arguments are equal, return third argument, else return fourth argument if provided  fn smp_builtin_ifeq(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String {      if args.len() < 3 {          return macro_name.to_string(); @@ -106,6 +101,7 @@ fn smp_builtin_ifeq(smp: &mut MacroProcessor, macro_name: &str, args: &mut [Stri      String::new()  } +/// If arguments are not equal, return third argument, else return fourth argument if provided  fn smp_builtin_ifneq(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String {      if args.len() < 3 {          return macro_name.to_string(); @@ -121,6 +117,7 @@ fn smp_builtin_ifneq(smp: &mut MacroProcessor, macro_name: &str, args: &mut [Str      return String::new();  } +/// Include a new file, and process it normally. There is no loop protection here!  fn smp_builtin_include(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String {      if args.len() < 1 {          return macro_name.to_string(); @@ -130,18 +127,16 @@ fn smp_builtin_include(smp: &mut MacroProcessor, macro_name: &str, args: &mut [S      return smp.process_input(&input_file);  } +/// Simply execute argument as shell command  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(); +    let res = Command::new("sh").arg("-c").arg(arg0).output();      match res {          Ok(output) => String::from_utf8(output.stdout).expect("SMP1"), -        Err(_) => String::new() +        Err(_) => String::new(),      }  } @@ -155,16 +150,38 @@ fn smp_builtin_expr(smp: &mut MacroProcessor, macro_name: &str, args: &mut [Stri          *arg = smp.process_input(&arg);      } -    let res = Command::new("expr") -        .args(args) -        .output(); +    let res = Command::new("expr").args(args).output();      match res {          Ok(output) => String::from_utf8(output.stdout).expect("SMP1"), -        Err(_) => String::new() +        Err(_) => String::new(),      }  } +/// Types of macros, this is to make it easy to store both functions and strings +pub enum MacroType { +    /// When expanded, the associated function will be expanded +    Function(fn(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String), +    /// Will be expanded in-place to the String +    String(String), +} + +/// Possible parser states +#[derive(Debug, PartialEq)] +enum ParserState { +    Normal, +    InMacro, +    InMacroArgs, +} + +/// Defines a MacroProcessor object, with it's associated state +/// the state mostly includes the defined macros +pub struct MacroProcessor { +    /// All currently defined macros in this MacroProcessor +    macros: HashMap<String, MacroType>, +} +  impl MacroProcessor { +      pub fn new() -> Self {          let mut smp = Self {              macros: HashMap::new(), @@ -173,28 +190,64 @@ impl MacroProcessor {          smp      } +    /// Bootstrapping-function for defining all builtins, +    /// the same way all other macros might be defined      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("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("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)      } +    /// Define a new macro as a string that will be expanded in-place +    /// +    /// # Arguments +    /// +    /// * `name` - The name of the new macro +    /// * `body` - The body of the new macro, this will be expanded when macro is executed      pub fn define_macro(&mut self, name: String, body: String) {          self.macros.insert(name, MacroType::String(body));      } +    /// Define a new macro as any MacroType +    /// +    /// # Arguments +    /// +    /// * `name` - The name of the new macro +    /// * `macro_expansion` - The MacroType struct to use.      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 +    /// +    /// # Arguments +    /// +    /// * `macro_name` - Name of macro to expand if it exists +    /// * `args` - List of arguments parsed along with macro invokation (empty list if no arguments were parsed)      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); @@ -203,18 +256,32 @@ impl MacroProcessor {          match macro_body {              MacroType::String(body) => {                  let mut expanded = body.clone(); +                // The expanded macro, should _probably_ be expanded again +                // The below is a okay _idea_, but I am not sure if I want to have this syntax for +                // functions defined in normal smp code                  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); -            }, +            }          }      } +    /// Do macro processing of a input string +    /// +    /// This is the main function used for processing a input string, +    /// will return the processed string. +    /// Will be called recursively if needed. +    /// Subsequent calls will keep the state from the previous call. +    /// This includes macro definitions. +    /// +    /// # Arguments +    /// +    /// * `input` - The text to process      pub fn process_input(&mut self, input: &str) -> String {          let mut output = String::new();          let mut state = ParserState::Normal; @@ -296,10 +363,3 @@ impl MacroProcessor {          output      }  } - -#[derive(Debug, PartialEq)] -enum ParserState { -    Normal, -    InMacro, -    InMacroArgs, -} diff --git a/src/macro_processor/main.rs b/src/macro_processor/main.rs index 5575aa6..247fc85 100644 --- a/src/macro_processor/main.rs +++ b/src/macro_processor/main.rs @@ -1,11 +1,11 @@ +use skaldpress::macro_processor::MacroProcessor;  use std::env;  use std::fs; -use skaldpress::macro_processor::MacroProcessor;  fn main() {      let args: Vec<String> = env::args().collect();      let input_file = fs::read_to_string(&args[1]).expect("Failed to read input file"); -     +      let mut macro_processor = MacroProcessor::new();      let final_output = macro_processor.process_input(&input_file);      println!("{}", final_output);  | 
