diff options
| -rw-r--r-- | Cargo.lock | 2 | ||||
| -rw-r--r-- | Cargo.toml | 6 | ||||
| -rw-r--r-- | build.rs | 1 | ||||
| -rw-r--r-- | src/guile/guile.rs | 76 | ||||
| -rw-r--r-- | src/guile/guiledefs.c | 9 | ||||
| -rw-r--r-- | src/guile/main.rs | 5 | ||||
| -rw-r--r-- | src/macro_processor/macro_processor.rs | 47 | 
7 files changed, 92 insertions, 54 deletions
| @@ -236,7 +236,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"  [[package]]  name = "skaldpress" -version = "2.0.0" +version = "2.1.0"  dependencies = [   "chrono",   "markdown", @@ -1,6 +1,6 @@  [package]  name = "skaldpress" -version = "2.0.0" +version = "2.1.0"  edition = "2021"  default-run = "skaldpress" @@ -27,7 +27,3 @@ path = "src/skaldpress/main.rs"  [[bin]]  name = "smp"  path = "src/macro_processor/main.rs" - -[[bin]] -name = "guiletest" -path = "src/guile/main.rs" @@ -4,6 +4,7 @@ use std::env;  use std::process::Command;  // cargo build has to be run twice for some reason. +#[cfg(feature = "guile")]  fn build_guile() {      const LIBGUILE_INCLUDE_PATH: &str = "/usr/include/guile/3.0/";      const GUILEDEFS_SRC: &str = "src/guile/guiledefs.c"; diff --git a/src/guile/guile.rs b/src/guile/guile.rs index 4a0e25b..36df62a 100644 --- a/src/guile/guile.rs +++ b/src/guile/guile.rs @@ -2,34 +2,20 @@ use std::ffi::{CStr, CString};  use std::os::raw::{c_char, c_int, c_void};  #[link(name = "guile-3.0")] -#[allow(dead_code)]  extern "C" {      fn scm_init_guile(); -    fn scm_c_define_gsubr( -        name: *const c_char, -        req: c_int, -        opt: c_int, -        rst: c_int, -        func: extern "C" fn() -> *mut c_void, -    );      fn scm_c_eval_string(expr: *const c_char) -> *mut c_void;      fn scm_to_locale_string(scm_obj: *mut c_void) -> *const c_char; -    fn scm_c_write(scm_obj: *mut c_void, port: *mut c_void); -    fn scm_open_output_string() -> *mut c_void; -    fn scm_get_output_string(port: *mut c_void) -> *mut c_void;      fn scm_is_string(scm_obj: *mut c_void) -> c_int; -    fn scm_is_number(scm_obj: *mut c_void) -> c_int;      fn scm_object_to_string(scm_obj: *mut c_void, printer: *mut c_void) -> *mut c_void;  }  #[link(name = "guiledefs")]  extern "C" {      pub static scm_undefined: *mut c_void; -} - -extern "C" fn my_rust_function() -> *mut c_void { -    println!("Hello from Rust!"); -    unsafe { scm_undefined } +    pub static scm_unspecified: *mut c_void; +    fn defs_scm_is_eq(x: *mut c_void, y: *mut c_void) -> c_int; +    fn defs_scm_define_string(name: *const c_char, value: *const c_char);  }  /// Convert a scm object into a string using Guile-builtins @@ -38,16 +24,14 @@ fn string_from_scm(scm_obj: *mut c_void) -> Result<String, ()> {          if scm_obj.is_null() {              return Err(());          } -        if scm_is_string(scm_obj) != 0 { +        if defs_scm_is_eq(scm_obj, scm_unspecified) != 0 { +            return Ok(String::new()); +        } else if scm_is_string(scm_obj) != 0 {              let res_str = CStr::from_ptr(scm_to_locale_string(scm_obj))                  .to_string_lossy()                  .into_owned();              return Ok(res_str);          } else { -            let port = scm_open_output_string(); -            if port.is_null() { -                return Err(()); -            }              let res = scm_object_to_string(scm_obj, scm_undefined);              if res.is_null() {                  return Err(()); @@ -60,27 +44,39 @@ fn string_from_scm(scm_obj: *mut c_void) -> Result<String, ()> {      }  } -pub fn smp_guile_init() {} +#[derive(Clone)] +pub struct Guile {} -pub fn testguile() { -    unsafe { -        scm_init_guile(); +impl Guile { +    pub fn new() -> Self { +        unsafe { +            scm_init_guile(); +        } +        Guile {} +    } -        let func_name = CString::new("my-rust-function").unwrap(); -        scm_c_define_gsubr( -            func_name.as_ptr(), -            0, // required arguments -            0, // optional arguments -            0, // rest arguments -            my_rust_function, -        ); +    pub fn evaluate_expression(&self, expr: &str) -> Result<String, ()> { +        unsafe { +            let c_expr = CString::new(expr).map_err(|_| ())?; +            let result = scm_c_eval_string(c_expr.as_ptr()); +            string_from_scm(result) +        } +    } -        let expr = CString::new("(+ 2 3)").unwrap(); -        let result = scm_c_eval_string(expr.as_ptr()); -        println!("{:?}", string_from_scm(result)); +    pub fn define_string(&self, name: &str, value: &str) { +        let c_name = CString::new(name).expect("CString::new failed"); +        let c_value = CString::new(value).expect("CString::new failed"); +        unsafe { +            defs_scm_define_string(c_name.as_ptr(), c_value.as_ptr()); +        } +    } +} -        let expr = CString::new("(my-rust-function)").unwrap(); -        let result = scm_c_eval_string(expr.as_ptr()); -        println!("{:?}", string_from_scm(result)); +impl Drop for Guile { +    fn drop(&mut self) { +        if let Err(e) = self.evaluate_expression("(exit)") { +            panic!("Error while exiting {:#?}", e); +        }      }  } + diff --git a/src/guile/guiledefs.c b/src/guile/guiledefs.c index 9f52c43..a0e9bd2 100644 --- a/src/guile/guiledefs.c +++ b/src/guile/guiledefs.c @@ -1,3 +1,12 @@  #include <libguile.h>  struct scm_unused_struct * scm_undefined = SCM_UNDEFINED; +struct scm_unused_struct * scm_unspecified = SCM_UNSPECIFIED; + +int defs_scm_is_eq(SCM x, SCM y) { +    return scm_is_eq(x, y); +} + +void defs_scm_define_string(const char* name, const char* value) { +    scm_c_define(name, scm_from_utf8_string(value)); +} diff --git a/src/guile/main.rs b/src/guile/main.rs deleted file mode 100644 index 6957c8c..0000000 --- a/src/guile/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -use skaldpress::guile::guile::testguile; - -fn main() { -    testguile(); -} diff --git a/src/macro_processor/macro_processor.rs b/src/macro_processor/macro_processor.rs index 0b714f0..306c8da 100644 --- a/src/macro_processor/macro_processor.rs +++ b/src/macro_processor/macro_processor.rs @@ -1,10 +1,12 @@ +#[cfg(feature = "guile")] +use crate::guile::guile::Guile; +#[cfg(feature = "deadlinks")] +use crate::macro_processor::deadlinks::smp_builtin_wodl;  use crate::macro_processor::error::SMPError;  use std::collections::HashMap;  use std::fs;  use std::process::Command; -#[cfg(feature = "deadlinks")] -use crate::macro_processor::deadlinks::smp_builtin_wodl;  // print only with debug_assertions  macro_rules! dprint {      ($($x:tt)*) => { @@ -591,6 +593,8 @@ enum ParserState {      InQuotes,      InMacro,      InMacroArgs, +    #[cfg(feature = "guile")] +    InGuile,      DNL,  } @@ -627,6 +631,8 @@ pub struct MacroProcessor {      pub macro_invocations: Vec<(String, Vec<String>)>,      /// Emitted warnings      pub warnings: Vec<MacroProcessorWarning>, +    #[cfg(feature = "guile")] +    pub guile: Guile,  }  impl MacroProcessor { @@ -635,6 +641,8 @@ impl MacroProcessor {              macros: HashMap::new(),              macro_invocations: Vec::new(),              warnings: Vec::new(), +            #[cfg(feature = "guile")] +            guile: Guile::new(),          };          smp.define_builtins();          smp @@ -729,7 +737,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_string(&mut self, name: String, body: String) { -        self.macros.insert(name, MacroType::String(body)); +        self.define_macro(name, MacroType::String(body));      }      /// Define a new macro as any MacroType @@ -739,6 +747,13 @@ impl MacroProcessor {      /// * `name` - The name of the new macro      /// * `macro_expansion` - The MacroType struct to use.      pub fn define_macro(&mut self, name: String, macro_expansion: MacroType) { +        #[cfg(feature = "guile")] +        { +            match ¯o_expansion { +                MacroType::String(s) => self.guile.define_string(&(name.clone()), s), +                _ => (), +            } +        }          self.macros.insert(name, macro_expansion);      } @@ -836,6 +851,9 @@ impl MacroProcessor {          let mut quote_level = 0;          let mut parens_level = 0; +        #[cfg(feature = "guile")] +        let mut guile_expr = String::new(); +          let mut chars = input.char_indices().peekable();          while let Some((i, c)) = chars.next() {              highlight_debug!(input, macro_name_start, i); @@ -858,6 +876,13 @@ impl MacroProcessor {                          continue;                      } +                    #[cfg(feature = "guile")] +                    if c == '%' && peek == Some(&'(') { +                        state = ParserState::InGuile; +                        chars.next(); +                        continue; +                    } +                      if c == '%' && peek == Some(&'"') {                          state = ParserState::InQuotes;                          quote_level += 1; @@ -888,6 +913,22 @@ impl MacroProcessor {                          output.push(c);                      }                  }, +                #[cfg(feature = "guile")] +                ParserState::InGuile => match c { +                    ')' if peek == Some(&'%') => { +                        let r = self +                            .guile +                            .evaluate_expression(&guile_expr) +                            .expect("fatal guile error"); +                        output.push_str(&r); +                        guile_expr.clear(); +                        state = ParserState::Normal; +                        chars.next(); +                    } +                    _ => { +                        guile_expr.push(c); +                    } +                },                  ParserState::InMacro => {                      if c.is_alphanumeric() || c == '_' {                          macro_name.push(c); | 
