diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 2 | ||||
| -rw-r--r-- | src/macro_processor/macro_processor.rs | 130 | ||||
| -rw-r--r-- | src/macro_processor/main.rs | 4 | ||||
| -rw-r--r-- | src/skaldpress/main.rs | 18 | ||||
| -rw-r--r-- | src/skaldpress/mod.rs | 1 | 
5 files changed, 105 insertions, 50 deletions
@@ -1,2 +1,2 @@ -pub mod skaldpress;  pub mod macro_processor; +pub mod skaldpress; 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); diff --git a/src/skaldpress/main.rs b/src/skaldpress/main.rs index de6088f..56abf70 100644 --- a/src/skaldpress/main.rs +++ b/src/skaldpress/main.rs @@ -92,17 +92,13 @@ fn compile_file(file_path: &Path) -> Result<String, Box<dyn std::error::Error>>          return Ok(file_content);      }; -    let template_file = format!( -        "{}{}.html", -        TEMPLATES_DIR, -        template -    ); +    let template_file = format!("{}{}.html", TEMPLATES_DIR, template);      //println!(      //    "Processing template {} for content file {:?}",      //    template_file, file_path      //);      let template = fs::read_to_string(template_file).expect("Failed to read template"); -     +      let mut macro_processor = MacroProcessor::new();      for (key, value) in map {          macro_processor.define_macro(format!("METADATA_{}", key), value.to_string()); @@ -114,7 +110,9 @@ fn compile_file(file_path: &Path) -> Result<String, Box<dyn std::error::Error>>  }  fn compile_file_and_write(source_file_path: &Path) -> Result<(), Box<dyn std::error::Error>> { -    let dest_file_path = Path::new(BUILD_DIR).join(source_file_path.strip_prefix(CONTENT_DIR).expect("SP14")).with_extension("html"); +    let dest_file_path = Path::new(BUILD_DIR) +        .join(source_file_path.strip_prefix(CONTENT_DIR).expect("SP14")) +        .with_extension("html");      std::fs::create_dir_all(&dest_file_path.parent().expect("SP19")).expect("SP10"); @@ -130,16 +128,12 @@ fn compile_files_in_directory(directory: &Path) {          let metadata = fs::metadata(&path).expect("SP6");          if metadata.is_file() { -            println!( -                "Compiling {:#?}", -                path.as_path() -            ); +            println!("Compiling {:#?}", path.as_path());              compile_file_and_write(path.as_path()).expect("SP12");          } else if metadata.is_dir() {              compile_files_in_directory(path.as_path());          }      } -  }  fn main() { diff --git a/src/skaldpress/mod.rs b/src/skaldpress/mod.rs index e69de29..8b13789 100644 --- a/src/skaldpress/mod.rs +++ b/src/skaldpress/mod.rs @@ -0,0 +1 @@ +  | 
