diff options
author | Qrius <[email protected]> | 2024-12-19 14:35:56 +0100 |
---|---|---|
committer | Qrius <[email protected]> | 2024-12-19 14:36:07 +0100 |
commit | b84765abc10598c3c808ea207ba89be40211189b (patch) | |
tree | e5e13ac52367904b30c0dbea8782ff03b8665d32 | |
parent | 861779e4c6b82f9f4bf09fd7e714ac5106b4455d (diff) | |
download | skaldpress-b84765abc10598c3c808ea207ba89be40211189b.tar.gz skaldpress-b84765abc10598c3c808ea207ba89be40211189b.zip |
Try to make a macro to get guile things instead
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | Cargo.toml | 5 | ||||
-rwxr-xr-x | packaging/package_debian.sh | 1 | ||||
-rw-r--r-- | src/guile/guile.rs | 75 | ||||
-rw-r--r-- | src/guile/guiledefs.c | 1 | ||||
-rw-r--r-- | src/macro_processor/macro_processor.rs | 32 | ||||
-rw-r--r-- | src/macro_processor/main.rs | 44 |
7 files changed, 133 insertions, 27 deletions
@@ -236,7 +236,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "skaldpress" -version = "2.1.0" +version = "2.2.0" dependencies = [ "chrono", "markdown", @@ -1,16 +1,17 @@ [package] name = "skaldpress" -version = "2.1.0" +version = "2.2.0" edition = "2021" default-run = "skaldpress" [features] -default = ["time", "markdown", "deadlinks", "guile"] +default = ["time", "markdown", "deadlinks", "guile", "readline"] time = ["dep:chrono"] markdown = ["dep:markdown"] deadlinks = ["dep:minreq"] webring = [] guile = [] +readline = [] [dependencies] markdown = { version = "1.0.0-alpha.20", optional = true } diff --git a/packaging/package_debian.sh b/packaging/package_debian.sh index 2c147e6..6549717 100755 --- a/packaging/package_debian.sh +++ b/packaging/package_debian.sh @@ -1,5 +1,6 @@ #!/bin/bash set -x +set -o pipefail tmpdir=$(mktemp -d) diff --git a/src/guile/guile.rs b/src/guile/guile.rs index 36df62a..a459a64 100644 --- a/src/guile/guile.rs +++ b/src/guile/guile.rs @@ -1,13 +1,41 @@ +use crate::macro_processor::macro_processor::MacroProcessor; use std::ffi::{CStr, CString}; use std::os::raw::{c_char, c_int, c_void}; +use std::sync::mpsc; +use std::thread; + +macro_rules! dprint { + ($($x:tt)*) => { + #[cfg(debug_assertions)] + print!($($x)*) + } +} + #[link(name = "guile-3.0")] extern "C" { fn scm_init_guile(); fn scm_c_eval_string(expr: *const c_char) -> *mut c_void; + fn scm_from_utf8_string(expr: *const c_char) -> *mut c_void; fn scm_to_locale_string(scm_obj: *mut c_void) -> *const c_char; fn scm_is_string(scm_obj: *mut c_void) -> c_int; fn scm_object_to_string(scm_obj: *mut c_void, printer: *mut c_void) -> *mut c_void; + fn scm_to_pointer(scm_obj: *mut c_void) -> *mut c_void; + fn scm_c_define_gsubr( + name: *const c_char, + req: c_int, + opt: c_int, + rst: c_int, + func: extern "C" fn(scm_obj: *mut c_void) -> *mut c_void, + ); + fn scm_c_define(name: *const c_char, value: *mut c_void); + fn scm_from_pointer(value: *mut c_void) -> *mut c_void; + //fn scm_with_guile(func: extern "C" fn(data: *mut c_void) -> *mut c_void, data: *mut c_void) -> *mut c_void; + //fn scm_is_number(scm_obj: *mut c_void) -> c_int; + //fn scm_without_guile(func: extern "C" fn(data: *mut c_void) -> *mut c_void, data: *mut c_void) -> *mut c_void; + //fn scm_c_write(scm_obj: *mut c_void, port: *mut c_void); + //fn scm_get_output_string(port: *mut c_void) -> *mut c_void; + //fn scm_open_output_string() -> *mut c_void; } #[link(name = "guiledefs")] @@ -44,7 +72,30 @@ fn string_from_scm(scm_obj: *mut c_void) -> Result<String, ()> { } } -#[derive(Clone)] +extern "C" fn scm_smp_macro(arg: *mut c_void) -> *mut c_void { + let arg_str; + unsafe { + arg_str = CStr::from_ptr(scm_to_locale_string(arg)) + .to_string_lossy() + .into_owned(); + } + dprint!("ARG {:#?}\n", arg_str); + let c_smp_state_ptr = CString::new("smp_state_ptr").expect("CString::new() failed"); + unsafe { + let smp_state_scm = scm_c_eval_string(c_smp_state_ptr.as_ptr()); + let smp_state_ptr = scm_to_pointer(smp_state_scm); + let smp: &mut MacroProcessor = &mut *(smp_state_ptr as *mut MacroProcessor); + if let Some(macro_value) = smp.macros.get(&arg_str) { + let r = CString::new(macro_value.to_string()).expect("CString::new() failed"); + scm_from_utf8_string(r.as_ptr()) + } else { + let r = CString::new("Macro not found").expect("CString::new() failed"); + scm_from_utf8_string(r.as_ptr()) + } + } +} + +#[derive(Debug)] pub struct Guile {} impl Guile { @@ -52,10 +103,16 @@ impl Guile { unsafe { scm_init_guile(); } - Guile {} + let guile = Guile {}; + let func_name = CString::new("smp_get").unwrap(); + unsafe { + scm_c_define_gsubr(func_name.as_ptr(), 1, 0, 0, scm_smp_macro); + } + guile } pub fn evaluate_expression(&self, expr: &str) -> Result<String, ()> { + dprint!("(eval \"{}\")\n", expr); unsafe { let c_expr = CString::new(expr).map_err(|_| ())?; let result = scm_c_eval_string(c_expr.as_ptr()); @@ -70,13 +127,19 @@ impl Guile { defs_scm_define_string(c_name.as_ptr(), c_value.as_ptr()); } } + + pub fn define(&self, name: &str, value: *mut c_void) { + let c_name = CString::new(name).expect("CString::new failed"); + unsafe { + scm_c_define(c_name.as_ptr(), scm_from_pointer(value)); + } + } } impl Drop for Guile { fn drop(&mut self) { - if let Err(e) = self.evaluate_expression("(exit)") { - panic!("Error while exiting {:#?}", e); - } + //if let Err(e) = self.evaluate_expression("(variable-unset! \"smp_state_ptr\")") { + // panic!("Error while exiting {:#?}", e); + //} } } - diff --git a/src/guile/guiledefs.c b/src/guile/guiledefs.c index a0e9bd2..bf050af 100644 --- a/src/guile/guiledefs.c +++ b/src/guile/guiledefs.c @@ -10,3 +10,4 @@ int defs_scm_is_eq(SCM x, SCM 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/macro_processor/macro_processor.rs b/src/macro_processor/macro_processor.rs index 306c8da..52fc581 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; +use crate::guile::guile::{scm_undefined, 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; +#[cfg(feature = "guile")] +use std::os::raw::c_void; use std::process::Command; // print only with debug_assertions @@ -537,6 +539,9 @@ fn smp_builtin_html_from_markdown( } fn macro_is_whitespace_deleting(s: &str) -> bool { + if s.len() == 0 { + return false; + } s.chars().nth(s.len() - 1) == Some('_') } @@ -623,7 +628,7 @@ impl MacroProcessorWarning { /// Defines a MacroProcessor object, with it's associated state /// the state mostly includes the defined macros -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct MacroProcessor { /// All currently defined macros in this MacroProcessor pub macros: HashMap<String, MacroType>, @@ -632,9 +637,11 @@ pub struct MacroProcessor { /// Emitted warnings pub warnings: Vec<MacroProcessorWarning>, #[cfg(feature = "guile")] - pub guile: Guile, + pub guile: std::rc::Rc<Guile>, } +pub static mut GLOBS: Option<&MacroProcessor> = None; + impl MacroProcessor { pub fn new() -> Self { let mut smp = Self { @@ -642,12 +649,21 @@ impl MacroProcessor { macro_invocations: Vec::new(), warnings: Vec::new(), #[cfg(feature = "guile")] - guile: Guile::new(), + guile: std::rc::Rc::new(Guile::new()), }; smp.define_builtins(); smp } + pub fn defself(&mut self) { + // Find a better way to do this Rc-stuff + let guile = std::rc::Rc::as_ptr(&self.guile); + unsafe { + let data_ptr: *mut c_void = self as *mut _ as *mut c_void; + (*guile).define("smp_state_ptr", data_ptr); + } + } + /// Bootstrapping-function for defining all builtins, /// the same way all other macros might be defined fn define_builtins(&mut self) { @@ -747,13 +763,6 @@ 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); } @@ -916,6 +925,7 @@ impl MacroProcessor { #[cfg(feature = "guile")] ParserState::InGuile => match c { ')' if peek == Some(&'%') => { + self.defself(); let r = self .guile .evaluate_expression(&guile_expr) diff --git a/src/macro_processor/main.rs b/src/macro_processor/main.rs index d8247d6..2435cf3 100644 --- a/src/macro_processor/main.rs +++ b/src/macro_processor/main.rs @@ -1,9 +1,31 @@ use skaldpress::macro_processor::MacroProcessor; use std::env; use std::fs; +#[cfg(not(feature = "readline"))] use std::io; +#[cfg(not(feature = "readline"))] use std::io::Write; +#[cfg(feature = "readline")] +use std::ffi::{CStr, CString}; +#[cfg(feature = "readline")] +use std::os::raw::c_char; + +#[cfg(feature = "readline")] +#[link(name = "readline")] +extern "C" { + fn readline(p: *const c_char) -> *const c_char; +} + +#[cfg(feature = "readline")] +fn readline_r(prompt: &str) -> String { + let c_prompt = CString::new(prompt).expect("Could not convert to c_string"); + unsafe { + let ret = readline(c_prompt.as_ptr()); + CStr::from_ptr(ret).to_string_lossy().into_owned() + } +} + fn repl() { println!("=Skaldpress Macro Processor (REPL)"); println!(" type \"quit\" to exit"); @@ -11,14 +33,22 @@ fn repl() { loop { let mut input = String::new(); loop { - print!("> "); - let _ = io::stdout().flush(); let mut _input = String::new(); - io::stdin() - .read_line(&mut _input) - .expect("error: unable to read user input"); - if _input == "\n" { - input.pop(); + + #[cfg(feature = "readline")] + { + _input = readline_r("> ") + } + #[cfg(not(feature = "readline"))] + { + print!("> "); + let _ = io::stdout().flush(); + io::stdin() + .read_line(&mut _input) + .expect("error: unable to read user input"); + } + + if _input == "" { break; } if _input == "quit\n" { |