use super::error::{EvalResult, Flow, signal};
use super::value::*;
use crate::emacs_core::value::ValueKind;
fn expect_args(name: &str, args: &[Value], n: usize) -> Result<(), Flow> {
if args.len() != n {
Err(signal(
"wrong-number-of-arguments",
vec![Value::symbol(name), Value::fixnum(args.len() as i64)],
))
} else {
Ok(())
}
}
fn expect_min_args(name: &str, args: &[Value], min: usize) -> Result<(), Flow> {
if args.len() < min {
Err(signal(
"wrong-number-of-arguments",
vec![Value::symbol(name), Value::fixnum(args.len() as i64)],
))
} else {
Ok(())
}
}
fn expect_max_args(name: &str, args: &[Value], max: usize) -> Result<(), Flow> {
if args.len() > max {
Err(signal(
"wrong-number-of-arguments",
vec![Value::symbol(name), Value::fixnum(args.len() as i64)],
))
} else {
Ok(())
}
}
fn expect_optional_string(_name: &str, value: &Value) -> Result<(), Flow> {
if value.is_nil() {
return Ok(());
}
if value.as_str().is_none() {
Err(signal(
"wrong-type-argument",
vec![Value::symbol("stringp"), *value],
))
} else {
Ok(())
}
}
fn html_parse_fallback(name: &str, args: &[Value]) -> Value {
let body = if args.len() <= 1 {
Value::string(format!("({name})"))
} else {
Value::string("(")
};
Value::list(vec![
Value::symbol("html"),
Value::NIL,
Value::list(vec![Value::symbol("body"), Value::NIL, body]),
])
}
fn expect_integer_or_marker(value: &Value) -> Result<i64, Flow> {
if let Some(n) = value.as_fixnum() {
return Ok(n);
}
if let Some(c) = value.as_char() {
return Ok(c as i64);
}
if super::marker::is_marker(value) {
return super::marker::marker_position_as_int(value);
}
Err(signal(
"wrong-type-argument",
vec![Value::symbol("integer-or-marker-p"), *value],
))
}
pub(crate) fn builtin_libxml_parse_html_region(args: Vec<Value>) -> EvalResult {
expect_min_args("libxml-parse-html-region", &args, 0)?;
expect_max_args("libxml-parse-html-region", &args, 4)?;
if args.len() >= 2 {
if args.first().is_some_and(|v| v.is_nil()) {
return Ok(Value::NIL);
}
let start_pos = expect_integer_or_marker(
args.first()
.expect("libxml-parse-html-region requires a start position here"),
)?;
if let Some(end) = args.get(1) {
if !end.is_nil() {
let end_pos = expect_integer_or_marker(end)?;
if start_pos == end_pos {
return Ok(Value::NIL);
}
}
}
}
if let Some(base_url) = args.get(2) {
expect_optional_string("libxml-parse-html-region", base_url)?;
}
Ok(html_parse_fallback("libxml-parse-html-region", &args))
}
pub(crate) fn builtin_libxml_parse_xml_region(args: Vec<Value>) -> EvalResult {
expect_min_args("libxml-parse-xml-region", &args, 0)?;
expect_max_args("libxml-parse-xml-region", &args, 4)?;
if let Some(start) = args.first() {
if !start.is_nil() {
let _ = expect_integer_or_marker(start)?;
}
}
if let Some(end) = args.get(1) {
if !end.is_nil() {
let _ = expect_integer_or_marker(end)?;
}
}
if let Some(base_url) = args.get(2) {
expect_optional_string("libxml-parse-xml-region", base_url)?;
}
Ok(Value::NIL)
}
pub(crate) fn builtin_libxml_available_p(args: Vec<Value>) -> EvalResult {
expect_args("libxml-available-p", &args, 0)?;
Ok(Value::T)
}
pub(crate) fn builtin_zlib_available_p(args: Vec<Value>) -> EvalResult {
expect_args("zlib-available-p", &args, 0)?;
Ok(Value::T)
}
pub(crate) fn builtin_zlib_decompress_region(args: Vec<Value>) -> EvalResult {
expect_min_args("zlib-decompress-region", &args, 2)?;
expect_max_args("zlib-decompress-region", &args, 3)?;
let _start = expect_integer_or_marker(&args[0])?;
let _end = expect_integer_or_marker(&args[1])?;
Err(signal(
"error",
vec![Value::string(
"This function can be called only in unibyte buffers",
)],
))
}
#[cfg(test)]
#[path = "xml_test.rs"]
mod tests;