summaryrefslogtreecommitdiff
path: root/src/macro_processor/macro_processor.rs
diff options
context:
space:
mode:
authorQrius <[email protected]>2024-09-26 00:11:05 +0200
committerQrius <[email protected]>2024-09-26 00:11:05 +0200
commite6ab276a4d5daaf0dd40eed5e2ff477b48187f77 (patch)
treed9394d87b428d15e45706b7f3de0eda4cbddeb0e /src/macro_processor/macro_processor.rs
parente489f7d9f8b799ee1605b4d5cb65fe7adf24ea22 (diff)
downloadskaldpress-e6ab276a4d5daaf0dd40eed5e2ff477b48187f77.tar.gz
skaldpress-e6ab276a4d5daaf0dd40eed5e2ff477b48187f77.zip
Change return of MacroProcessor to Result
Diffstat (limited to 'src/macro_processor/macro_processor.rs')
-rw-r--r--src/macro_processor/macro_processor.rs129
1 files changed, 85 insertions, 44 deletions
diff --git a/src/macro_processor/macro_processor.rs b/src/macro_processor/macro_processor.rs
index 0f8b217..f26780e 100644
--- a/src/macro_processor/macro_processor.rs
+++ b/src/macro_processor/macro_processor.rs
@@ -1,3 +1,4 @@
+use crate::macro_processor::error::SMPError;
use std::collections::HashMap;
use std::fs;
use std::process::Command;
@@ -39,24 +40,32 @@ macro_rules! highlight_debug {
}
/// Builtin for defining a new macro
-fn smp_builtin_define(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String {
+fn smp_builtin_define(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+) -> Result<String, SMPError> {
if args.len() < 1 {
- return macro_name.to_string();
+ return Ok(macro_name.to_string());
}
- let arg0 = smp.process_input(&args[0]);
+ let arg0 = smp.process_input(&args[0])?;
if args.len() > 1 {
- let arg1 = smp.process_input(&args[1]);
+ let arg1 = smp.process_input(&args[1])?;
smp.define_macro(arg0, arg1);
} else {
smp.define_macro(arg0, String::new());
}
- String::new()
+ Ok(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 {
+fn smp_builtin_ifdef(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+) -> Result<String, SMPError> {
if args.len() < 2 {
- return macro_name.to_string();
+ return Ok(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
@@ -66,13 +75,17 @@ fn smp_builtin_ifdef(smp: &mut MacroProcessor, macro_name: &str, args: &mut [Str
if args.len() > 2 {
return smp.process_input(&args[2]);
}
- String::new()
+ Ok(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 {
+fn smp_builtin_ifndef(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+) -> Result<String, SMPError> {
if args.len() < 2 {
- return macro_name.to_string();
+ return Ok(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
@@ -82,85 +95,113 @@ fn smp_builtin_ifndef(smp: &mut MacroProcessor, macro_name: &str, args: &mut [St
if args.len() > 2 {
return smp.process_input(&args[2]);
}
- String::new()
+ Ok(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 {
+fn smp_builtin_ifeq(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+) -> Result<String, SMPError> {
if args.len() < 3 {
- return macro_name.to_string();
+ return Ok(macro_name.to_string());
}
- let arg0 = smp.process_input(&args[0]);
- let arg1 = smp.process_input(&args[1]);
+ 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()
+ Ok(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 {
+fn smp_builtin_ifneq(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+) -> Result<String, SMPError> {
if args.len() < 3 {
- return macro_name.to_string();
+ return Ok(macro_name.to_string());
}
- let arg0 = smp.process_input(&args[0]);
- let arg1 = smp.process_input(&args[1]);
+ 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();
+ return Ok(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 {
+fn smp_builtin_include(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+) -> Result<String, SMPError> {
if args.len() < 1 {
- return macro_name.to_string();
+ return Ok(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");
+ let arg0 = smp.process_input(&args[0])?;
+ let input_file = fs::read_to_string(&arg0).map_err(|e| SMPError::IncludeError(2, e, arg0))?;
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 {
+fn smp_builtin_shell(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+) -> Result<String, SMPError> {
if args.len() < 1 {
- return macro_name.to_string();
+ return Ok(macro_name.to_string());
}
- let arg0 = smp.process_input(&args[0]);
+ 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(),
+ Ok(output) => String::from_utf8(output.stdout)
+ .map_err(|e| SMPError::ShellCommandError(1, Box::new(e))),
+ Err(_) => Ok(String::new()),
}
}
/// Would like one that is better than this tbh
-fn smp_builtin_expr(smp: &mut MacroProcessor, macro_name: &str, args: &mut [String]) -> String {
+fn smp_builtin_expr(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+) -> Result<String, SMPError> {
if args.len() < 1 {
- return macro_name.to_string();
+ return Ok(macro_name.to_string());
}
for arg in args.iter_mut() {
- *arg = smp.process_input(&arg);
+ *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(),
+ Ok(output) => String::from_utf8(output.stdout)
+ .map_err(|e| SMPError::ShellCommandError(1, Box::new(e))),
+ Err(_) => Ok(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),
+ Function(
+ fn(
+ smp: &mut MacroProcessor,
+ macro_name: &str,
+ args: &mut [String],
+ ) -> Result<String, SMPError>,
+ ),
/// Will be expanded in-place to the String
String(String),
}
@@ -247,9 +288,9 @@ impl MacroProcessor {
///
/// * `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 {
+ fn expand_macro(&mut self, macro_name: &str, args: &mut [String]) -> Result<String, SMPError> {
let Some(macro_body) = self.macros.get(macro_name) else {
- return format!("{}", macro_name);
+ return Ok(format!("{}", macro_name));
};
match macro_body {
@@ -262,7 +303,7 @@ impl MacroProcessor {
let placeholder = format!("${}", i + 1);
expanded = expanded.replace(&placeholder, arg);
}
- return expanded;
+ return Ok(expanded);
}
MacroType::Function(func) => {
return func(self, macro_name, args);
@@ -281,7 +322,7 @@ impl MacroProcessor {
/// # Arguments
///
/// * `input` - The text to process
- pub fn process_input(&mut self, input: &str) -> String {
+ pub fn process_input(&mut self, input: &str) -> Result<String, SMPError> {
let mut output = String::new();
let mut state = ParserState::Normal;
let mut macro_name = String::new();
@@ -325,7 +366,7 @@ impl MacroProcessor {
if macro_name == "SNNL" {
skip_next_line_ending = c != '\n';
} else {
- let expanded = self.expand_macro(&macro_name, &mut []);
+ let expanded = self.expand_macro(&macro_name, &mut [])?;
output.push_str(&expanded);
output.push(c);
}
@@ -338,7 +379,7 @@ impl MacroProcessor {
highlight_debug!("\x1b[32m\x1b[7m", input, (macro_name_start -> i));
macro_args.push(argument.trim().to_string());
- let expanded = self.expand_macro(&macro_name, &mut macro_args);
+ let expanded = self.expand_macro(&macro_name, &mut macro_args)?;
output.push_str(&expanded);
state = ParserState::Normal;
macro_name.clear();
@@ -356,9 +397,9 @@ impl MacroProcessor {
// Handle cases where the text ends with a macro without arguments
if !macro_name.is_empty() {
- output.push_str(&self.expand_macro(&macro_name, &mut []));
+ output.push_str(&self.expand_macro(&macro_name, &mut [])?);
}
- output
+ Ok(output)
}
}