summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/macro_processor/error.rs23
-rw-r--r--src/macro_processor/macro_processor.rs129
-rw-r--r--src/macro_processor/main.rs14
-rw-r--r--src/macro_processor/mod.rs1
-rw-r--r--src/skaldpress/error.rs11
-rw-r--r--src/skaldpress/main.rs29
6 files changed, 151 insertions, 56 deletions
diff --git a/src/macro_processor/error.rs b/src/macro_processor/error.rs
new file mode 100644
index 0000000..074a8ef
--- /dev/null
+++ b/src/macro_processor/error.rs
@@ -0,0 +1,23 @@
+use std::error::Error;
+use std::fmt;
+
+#[derive(Debug)]
+pub enum SMPError {
+ IncludeError(u8, std::io::Error, String),
+ ShellCommandError(u8, Box<dyn Error>),
+}
+
+impl fmt::Display for SMPError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ SMPError::IncludeError(code, _, file) => {
+ write!(f, "[SMP{}] Error reading file \"{}\"", code, file)
+ }
+ SMPError::ShellCommandError(code, e) => {
+ write!(f, "[SMP{}] Error running shell command \"{:#?}\"", code, e)
+ }
+ }
+ }
+}
+
+impl std::error::Error for SMPError {}
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)
}
}
diff --git a/src/macro_processor/main.rs b/src/macro_processor/main.rs
index 247fc85..2d34952 100644
--- a/src/macro_processor/main.rs
+++ b/src/macro_processor/main.rs
@@ -4,9 +4,17 @@ use std::fs;
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 input_file = match fs::read_to_string(&args[1]) {
+ Ok(x) => x,
+ Err(e) => {
+ println!("Could not read input-file \"{}\": {}", args[1], e);
+ std::process::exit(1);
+ }
+ };
let mut macro_processor = MacroProcessor::new();
- let final_output = macro_processor.process_input(&input_file);
- println!("{}", final_output);
+ match macro_processor.process_input(&input_file) {
+ Ok(out) => println!("{}", out),
+ Err(e) => println!("Error {}", e),
+ }
}
diff --git a/src/macro_processor/mod.rs b/src/macro_processor/mod.rs
index 2fccbda..ffc2144 100644
--- a/src/macro_processor/mod.rs
+++ b/src/macro_processor/mod.rs
@@ -1,2 +1,3 @@
+pub mod error;
pub mod macro_processor;
pub use macro_processor::MacroProcessor;
diff --git a/src/skaldpress/error.rs b/src/skaldpress/error.rs
index f8639b6..65a89ab 100644
--- a/src/skaldpress/error.rs
+++ b/src/skaldpress/error.rs
@@ -1,6 +1,13 @@
+use crate::macro_processor::error::SMPError;
use std::error::Error;
use std::fmt;
+pub const SP_COMPILE_FILE_TEMPLATE_READ_ERROR: u8 = 2;
+pub const SP_COMPILE_FILE_EXTENSION_ERROR_2: u8 = 3;
+pub const SP_GEN_DEST_STRIP_PREFIX_ERROR: u8 = 4;
+pub const SP_COMPILE_FILE_EXTENSION_ERROR: u8 = 7;
+pub const SP_COMPILE_FILE_MACRO_PROCESS_ERROR: u8 = 9;
+
#[derive(Debug)]
pub enum SkaldpressError {
TemplateReadError(u8, std::io::Error, String),
@@ -8,6 +15,7 @@ pub enum SkaldpressError {
DirectoryReadError(u8, std::io::Error, String),
PathOperationError(u8, Option<Box<dyn Error>>),
DirectoryCreateError(u8, std::io::Error, String),
+ SMPError(u8, SMPError),
}
impl fmt::Display for SkaldpressError {
@@ -28,6 +36,9 @@ impl fmt::Display for SkaldpressError {
SkaldpressError::DirectoryCreateError(code, _, dir) => {
write!(f, "[SP{}] Directory create error \"{}\"", code, dir)
}
+ SkaldpressError::SMPError(code, e) => {
+ write!(f, "[SP{}] Macro processing error \"{:#?}\"", code, e)
+ }
}
}
}
diff --git a/src/skaldpress/main.rs b/src/skaldpress/main.rs
index 79ea7ab..3563bf7 100644
--- a/src/skaldpress/main.rs
+++ b/src/skaldpress/main.rs
@@ -3,6 +3,11 @@ use std::path::Path;
use skaldpress::macro_processor::MacroProcessor;
use skaldpress::skaldpress::error::SkaldpressError;
+use skaldpress::skaldpress::error::{
+ SP_COMPILE_FILE_EXTENSION_ERROR, SP_COMPILE_FILE_EXTENSION_ERROR_2,
+ SP_COMPILE_FILE_MACRO_PROCESS_ERROR, SP_COMPILE_FILE_TEMPLATE_READ_ERROR,
+ SP_GEN_DEST_STRIP_PREFIX_ERROR,
+};
use skaldpress::skaldpress::metadata_parser::extract_parse_yaml_metadata;
const TEMPLATES_DIR: &str = "templates/";
@@ -12,7 +17,10 @@ const BUILD_DIR: &str = "build/";
fn compile_file(file_path: &Path) -> Result<String, SkaldpressError> {
let extension = file_path
.extension()
- .ok_or(SkaldpressError::PathOperationError(7, None))?;
+ .ok_or(SkaldpressError::PathOperationError(
+ SP_COMPILE_FILE_EXTENSION_ERROR,
+ None,
+ ))?;
let file_content = fs::read_to_string(file_path).map_err(|e| {
SkaldpressError::FileReadError(
@@ -24,8 +32,10 @@ fn compile_file(file_path: &Path) -> Result<String, SkaldpressError> {
let (map, file_content) = extract_parse_yaml_metadata(&file_content);
let file_content = match extension
.to_str()
- .ok_or(SkaldpressError::PathOperationError(3, None))?
- {
+ .ok_or(SkaldpressError::PathOperationError(
+ SP_COMPILE_FILE_EXTENSION_ERROR_2,
+ None,
+ ))? {
"md" => markdown::to_html(file_content),
_ => file_content.to_string(),
};
@@ -35,17 +45,18 @@ fn compile_file(file_path: &Path) -> Result<String, SkaldpressError> {
};
let template_file = format!("{}{}.html", TEMPLATES_DIR, template);
- let template = fs::read_to_string(&template_file)
- .map_err(|e| SkaldpressError::TemplateReadError(2, e, template_file))?;
+ let template = fs::read_to_string(&template_file).map_err(|e| {
+ SkaldpressError::TemplateReadError(SP_COMPILE_FILE_TEMPLATE_READ_ERROR, e, template_file)
+ })?;
let mut macro_processor = MacroProcessor::new();
for (key, value) in map {
macro_processor.define_macro(format!("METADATA_{}", key), value.to_string());
}
macro_processor.define_macro(String::from("CONTENT"), file_content);
- let final_output = macro_processor.process_input(&template);
-
- Ok(final_output)
+ macro_processor
+ .process_input(&template)
+ .map_err(|e| SkaldpressError::SMPError(SP_COMPILE_FILE_MACRO_PROCESS_ERROR, e))
}
fn compile_file_and_write(source_file_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
@@ -53,7 +64,7 @@ fn compile_file_and_write(source_file_path: &Path) -> Result<(), Box<dyn std::er
.join(
source_file_path
.strip_prefix(CONTENT_DIR)
- .map_err(|e| SkaldpressError::PathOperationError(4, Some(Box::new(e))))?,
+ .map_err(|e| SkaldpressError::PathOperationError(SP_GEN_DEST_STRIP_PREFIX_ERROR, Some(Box::new(e))))?,
)
.with_extension("html");