summaryrefslogtreecommitdiff
path: root/src/macro_processor
diff options
context:
space:
mode:
Diffstat (limited to 'src/macro_processor')
-rw-r--r--src/macro_processor/macro_processor.rs130
-rw-r--r--src/macro_processor/main.rs4
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);