diff options
author | Qrius <[email protected]> | 2024-09-26 00:11:05 +0200 |
---|---|---|
committer | Qrius <[email protected]> | 2024-09-26 00:11:05 +0200 |
commit | ca6571d9d3f1d1961e23691837feb430cbbd0e24 (patch) | |
tree | ea3a2607dc42e55b1117807075785890ed3d1974 | |
parent | e6ab276a4d5daaf0dd40eed5e2ff477b48187f77 (diff) | |
download | skaldpress-ca6571d9d3f1d1961e23691837feb430cbbd0e24.tar.gz skaldpress-ca6571d9d3f1d1961e23691837feb430cbbd0e24.zip |
Add special DNL macro, do a bunch of skaldpress-stuff
-rw-r--r-- | src/macro_processor/macro_processor.rs | 39 | ||||
-rw-r--r-- | src/skaldpress/error.rs | 3 | ||||
-rw-r--r-- | src/skaldpress/main.rs | 66 | ||||
-rw-r--r-- | tests/macro_processor.rs | 52 |
4 files changed, 124 insertions, 36 deletions
diff --git a/src/macro_processor/macro_processor.rs b/src/macro_processor/macro_processor.rs index f26780e..82a94ef 100644 --- a/src/macro_processor/macro_processor.rs +++ b/src/macro_processor/macro_processor.rs @@ -51,9 +51,9 @@ fn smp_builtin_define( let arg0 = smp.process_input(&args[0])?; if args.len() > 1 { let arg1 = smp.process_input(&args[1])?; - smp.define_macro(arg0, arg1); + smp.define_macro(arg0, MacroType::String(arg1)); } else { - smp.define_macro(arg0, String::new()); + smp.define_macro(arg0, MacroType::String(String::new())); } Ok(String::new()) } @@ -212,6 +212,7 @@ enum ParserState { Normal, InMacro, InMacroArgs, + DNL, } /// Defines a MacroProcessor object, with it's associated state @@ -233,32 +234,32 @@ impl MacroProcessor { /// Bootstrapping-function for defining all builtins, /// the same way all other macros might be defined fn define_builtins(&mut self) { - self.define_macro_fn( + self.define_macro( String::from("define"), MacroType::Function(smp_builtin_define), ); - self.define_macro_fn( + self.define_macro( String::from("ifdef"), MacroType::Function(smp_builtin_ifdef), ); - self.define_macro_fn( + self.define_macro( String::from("ifndef"), MacroType::Function(smp_builtin_ifndef), ); - self.define_macro_fn(String::from("ifeq"), MacroType::Function(smp_builtin_ifeq)); - self.define_macro_fn( + self.define_macro(String::from("ifeq"), MacroType::Function(smp_builtin_ifeq)); + self.define_macro( String::from("ifneq"), MacroType::Function(smp_builtin_ifneq), ); - self.define_macro_fn( + self.define_macro( String::from("include"), MacroType::Function(smp_builtin_include), ); - self.define_macro_fn( + self.define_macro( String::from("shell"), MacroType::Function(smp_builtin_shell), ); - self.define_macro_fn(String::from("expr"), MacroType::Function(smp_builtin_expr)); + self.define_macro(String::from("expr"), MacroType::Function(smp_builtin_expr)); // format('Result id %d', 3282) } @@ -268,7 +269,7 @@ impl MacroProcessor { /// /// * `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) { + pub fn define_macro_string(&mut self, name: String, body: String) { self.macros.insert(name, MacroType::String(body)); } @@ -278,7 +279,7 @@ impl MacroProcessor { /// /// * `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) { + pub fn define_macro(&mut self, name: String, macro_expansion: MacroType) { self.macros.insert(name, macro_expansion); } @@ -303,11 +304,12 @@ impl MacroProcessor { let placeholder = format!("${}", i + 1); expanded = expanded.replace(&placeholder, arg); } - return Ok(expanded); + self.process_input(&expanded) } MacroType::Function(func) => { return func(self, macro_name, args); } + MacroType::Array(vec) => return Ok(format!("Array[{}]", vec.len())), } } @@ -339,6 +341,11 @@ impl MacroProcessor { highlight_debug!(input, macro_name_start, i); match state { + ParserState::DNL => { + if c == '\n' { + state = ParserState::Normal; + } + } ParserState::Normal => { macro_name_start = i; @@ -365,6 +372,12 @@ impl MacroProcessor { } if macro_name == "SNNL" { skip_next_line_ending = c != '\n'; + } else if macro_name == "DNL" { + if c != '\n' { + state = ParserState::DNL; + } + macro_name.clear(); + continue; } else { let expanded = self.expand_macro(¯o_name, &mut [])?; output.push_str(&expanded); diff --git a/src/skaldpress/error.rs b/src/skaldpress/error.rs index 65a89ab..ae769a5 100644 --- a/src/skaldpress/error.rs +++ b/src/skaldpress/error.rs @@ -6,7 +6,8 @@ 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; +pub const SP_COMPILE_TEMPLATE_MACRO_PROCESS_ERROR: u8 = 9; +pub const SP_COMPILE_FILE_MACRO_PROCESS_ERROR: u8 = 10; #[derive(Debug)] pub enum SkaldpressError { diff --git a/src/skaldpress/main.rs b/src/skaldpress/main.rs index 3563bf7..c1b2006 100644 --- a/src/skaldpress/main.rs +++ b/src/skaldpress/main.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fs; use std::path::Path; @@ -6,15 +7,22 @@ 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, + SP_COMPILE_TEMPLATE_MACRO_PROCESS_ERROR, SP_GEN_DEST_STRIP_PREFIX_ERROR, }; use skaldpress::skaldpress::metadata_parser::extract_parse_yaml_metadata; +use skaldpress::skaldpress::metadata_parser::YamlValue; const TEMPLATES_DIR: &str = "templates/"; const CONTENT_DIR: &str = "content/"; const BUILD_DIR: &str = "build/"; -fn compile_file(file_path: &Path) -> Result<String, SkaldpressError> { +struct CompiledFile { + content: String, + metadata: HashMap<String, YamlValue>, +} + +/// Will attempt to compile a specific file, potentially storing some state about the file +fn compile_file(file_path: &Path) -> Result<CompiledFile, SkaldpressError> { let extension = file_path .extension() .ok_or(SkaldpressError::PathOperationError( @@ -40,33 +48,54 @@ fn compile_file(file_path: &Path) -> Result<String, SkaldpressError> { _ => file_content.to_string(), }; - let Some(template) = map.get("template") else { - return Ok(file_content); + let mut macro_processor = MacroProcessor::new(); + for (key, value) in &map { + macro_processor.define_macro_string(format!("METADATA_{}", key), value.to_string()); + } + + let Some(template) = &map.get("template") else { + let file_content = macro_processor + .process_input(&file_content) + .map_err(|e| SkaldpressError::SMPError(SP_COMPILE_FILE_MACRO_PROCESS_ERROR, e))?; + return Ok(CompiledFile { + content: file_content, + metadata: map, + }); }; - let template_file = format!("{}{}.html", TEMPLATES_DIR, template); + let template_file = format!("{}{}", TEMPLATES_DIR, template); 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); - macro_processor + macro_processor.define_macro_string(String::from("CONTENT"), file_content); + let content = macro_processor .process_input(&template) - .map_err(|e| SkaldpressError::SMPError(SP_COMPILE_FILE_MACRO_PROCESS_ERROR, e)) + .map_err(|e| SkaldpressError::SMPError(SP_COMPILE_TEMPLATE_MACRO_PROCESS_ERROR, e))?; + Ok(CompiledFile { + content, + metadata: map, + }) } fn compile_file_and_write(source_file_path: &Path) -> Result<(), Box<dyn std::error::Error>> { + let cfile = compile_file(&source_file_path)?; + + if let Some(skip_build) = cfile.metadata.get("skip_build") { + if let YamlValue::Scalar(skip_build) = skip_build { + if skip_build.to_lowercase() == "true" { + return Ok(()); + } + } + } + let dest_file_path = Path::new(BUILD_DIR) - .join( - source_file_path - .strip_prefix(CONTENT_DIR) - .map_err(|e| SkaldpressError::PathOperationError(SP_GEN_DEST_STRIP_PREFIX_ERROR, Some(Box::new(e))))?, - ) + .join(source_file_path.strip_prefix(CONTENT_DIR).map_err(|e| { + SkaldpressError::PathOperationError(SP_GEN_DEST_STRIP_PREFIX_ERROR, Some(Box::new(e))) + })?) .with_extension("html"); + // Here we need to do something about the extension, read it from the metadata of the template, + // or the main file let dest_dir = &dest_file_path .parent() @@ -79,8 +108,7 @@ fn compile_file_and_write(source_file_path: &Path) -> Result<(), Box<dyn std::er ) })?; - let file_content = compile_file(&source_file_path)?; - fs::write(&dest_file_path, file_content)?; + fs::write(&dest_file_path, cfile.content)?; Ok(()) } diff --git a/tests/macro_processor.rs b/tests/macro_processor.rs index 95edfeb..cb21df5 100644 --- a/tests/macro_processor.rs +++ b/tests/macro_processor.rs @@ -2,7 +2,9 @@ use skaldpress::macro_processor::MacroProcessor; fn run_macro_processor(input: &str) -> String { let mut macro_processor = MacroProcessor::new(); - macro_processor.process_input(&input) + macro_processor + .process_input(&input) + .expect("macro processing failed") } #[test] @@ -48,7 +50,7 @@ fn test_smp_define_2() { fn test_smp_dnl_1() { assert_eq!( run_macro_processor( - "SNNL + "DNL test" ), "test", @@ -59,7 +61,7 @@ test" fn test_smp_dnl_2() { assert_eq!( run_macro_processor( - "SNNL + "DNL this is some random text that should not be included test" ), "test", @@ -70,6 +72,50 @@ test" fn test_smp_dnl_3() { assert_eq!( run_macro_processor( + "DNL ifdef(a, b, c) +test" + ), + "test", + ); +} + +#[test] +fn test_smp_dnl_4() { + assert_eq!( + run_macro_processor( + "DNL +test" + ), + "test", + ); +} + +#[test] +fn test_smp_snnl_1() { + assert_eq!( + run_macro_processor( + "SNNL +test" + ), + "test", + ); +} + +#[test] +fn test_smp_snnl_2() { + assert_eq!( + run_macro_processor( + "SNNL +test" + ), + "test", + ); +} + +#[test] +fn test_smp_snnl_3() { + assert_eq!( + run_macro_processor( "define(MAC1, test)SNNL MAC1 SNNL test" |