use lispexp::annotate::{annotate_form, bundled_registry, Role};
use lispexp::{parse, DatumKind, Dialect, Options};
fn annotate<'a>(
src: &'a str,
dialect: Dialect,
) -> (Vec<lispexp::Datum<'a>>, lispexp::annotate::Registry) {
let data = parse(src, &Options::for_dialect(dialect)).data;
(data, bundled_registry(dialect))
}
#[test]
fn cl_defmethod_with_qualifier_and_specializers() {
let (data, reg) = annotate(
"(cl-defmethod foo :around ((x integer) (y string)) (bar))",
Dialect::EmacsLisp,
);
let a = annotate_form(&data[0], ®).unwrap();
assert_eq!(a.first(Role::Name).unwrap().kind, DatumKind::Symbol("foo"));
let quals: Vec<_> = a.all(Role::Qualifier).collect();
assert_eq!(quals.len(), 1);
assert_eq!(quals[0].kind, DatumKind::Keyword(":around"));
let params = a.specialized_params();
assert_eq!(params.len(), 2);
assert_eq!(params[0].variable.kind, DatumKind::Symbol("x"));
assert_eq!(
params[0].specializer.unwrap().kind,
DatumKind::Symbol("integer")
);
assert_eq!(params[1].variable.kind, DatumKind::Symbol("y"));
assert_eq!(
params[1].specializer.unwrap().kind,
DatumKind::Symbol("string")
);
}
#[test]
fn cl_defmethod_zero_qualifiers() {
let (data, reg) = annotate(
"(cl-defmethod area ((s square)) (* (side s) (side s)))",
Dialect::EmacsLisp,
);
let a = annotate_form(&data[0], ®).unwrap();
assert_eq!(a.all(Role::Qualifier).count(), 0);
let params = a.specialized_params();
assert_eq!(params.len(), 1);
assert_eq!(params[0].variable.kind, DatumKind::Symbol("s"));
assert_eq!(
params[0].specializer.unwrap().kind,
DatumKind::Symbol("square")
);
}
#[test]
fn cl_defmethod_multiple_qualifiers() {
let (data, reg) = annotate(
"(defmethod foo :before :extra ((x t)) nil)",
Dialect::CommonLisp,
);
let a = annotate_form(&data[0], ®).unwrap();
let quals: Vec<_> = a.all(Role::Qualifier).map(|d| &d.kind).collect();
assert_eq!(quals.len(), 2);
}
#[test]
fn eql_specializer_is_verbatim_list() {
let (data, reg) = annotate("(cl-defmethod g ((x (eql 0))) x)", Dialect::EmacsLisp);
let a = annotate_form(&data[0], ®).unwrap();
let params = a.specialized_params();
assert_eq!(params[0].variable.kind, DatumKind::Symbol("x"));
assert!(matches!(
params[0].specializer.unwrap().kind,
DatumKind::List { .. }
));
}
#[test]
fn unspecialized_param_has_no_specializer() {
let (data, reg) = annotate("(cl-defmethod h ((x integer) y) x)", Dialect::EmacsLisp);
let a = annotate_form(&data[0], ®).unwrap();
let params = a.specialized_params();
assert_eq!(params.len(), 2);
assert!(params[1].specializer.is_none());
assert_eq!(params[1].variable.kind, DatumKind::Symbol("y"));
}
#[test]
fn cl_defmethod_docstring_is_tagged() {
let (data, reg) = annotate(
r#"(defmethod area ((s square)) "Compute the area." (* s s))"#,
Dialect::CommonLisp,
);
let a = annotate_form(&data[0], ®).unwrap();
assert_eq!(
a.first(Role::Docstring).unwrap().kind,
DatumKind::Str("\"Compute the area.\"")
);
}
#[test]
fn clojure_multi_arity_defmethod_clause_is_not_arglist() {
let (data, reg) = annotate("(defmethod f :x ([a] a) ([a b] b))", Dialect::Clojure);
let a = annotate_form(&data[0], ®).unwrap();
assert!(a.first(Role::Arglist).is_none());
assert_eq!(a.parts.iter().filter(|p| p.role == Role::Body).count(), 2);
}
#[test]
fn clojure_defmethod_uses_dispatch_value() {
let (data, reg) = annotate(
"(defmethod area :circle [shape] (* 3 (:r shape)))",
Dialect::Clojure,
);
let a = annotate_form(&data[0], ®).unwrap();
assert_eq!(a.first(Role::Name).unwrap().kind, DatumKind::Symbol("area"));
assert_eq!(
a.first(Role::DispatchValue).unwrap().kind,
DatumKind::Keyword(":circle")
);
assert_eq!(a.all(Role::Qualifier).count(), 0);
assert!(matches!(
a.first(Role::Arglist).unwrap().kind,
DatumKind::List { .. }
));
}