Lines
98.96 %
Functions
100 %
Branches
use nms::interpreter::Interpreter;
use scripting::nomiscript::{Fraction, Value};
#[test]
fn test_eval_defun_sum() {
let mut interp = Interpreter::new(false).unwrap();
let results = interp
.eval("(defun sum (a b c) \"Sums A, B, C\" (+ a b c))\n(sum 1 2 3)")
.unwrap();
assert_eq!(results, vec![Value::Number(Fraction::from_integer(6))]);
}
fn test_eval_defun_add() {
.eval("(defun add (a b) (+ a b))\n(add 10 20)")
assert_eq!(results, vec![Value::Number(Fraction::from_integer(30))]);
fn test_eval_defun_only() {
let results = interp.eval("(defun foo (x) (+ x 1))").unwrap();
assert_eq!(results, vec![Value::Symbol("FOO".to_string())]);
fn test_eval_defun_arity_error() {
let result = interp.eval("(defun add (a b) (+ a b))\n(add 1)");
assert!(result.is_err());
fn test_eval_defun_persistence() {
interp.eval("(defun add (a b) (+ a b))").unwrap();
let results = interp.eval("(add 3 4)").unwrap();
assert_eq!(results, vec![Value::Number(Fraction::from_integer(7))]);
fn test_eval_funcall_native() {
let results = interp.eval("(funcall + 1 2 3)").unwrap();
fn test_eval_funcall_user() {
.eval("(defun add (a b) (+ a b))\n(funcall add 10 20)")
fn test_eval_apply_quoted_list() {
let results = interp.eval("(apply + '(1 2 3))").unwrap();
fn test_eval_apply_mixed_args() {
let results = interp.eval("(apply + 1 2 '(3 4))").unwrap();
assert_eq!(results, vec![Value::Number(Fraction::from_integer(10))]);
fn test_eval_compile() {
.eval("(defun add (a b) (+ a b))\n(compile 'add)")
assert_eq!(results, vec![Value::Symbol("ADD".to_string())]);
fn test_eval_eval() {
let results = interp.eval("(eval '(+ 1 2))").unwrap();
assert_eq!(results, vec![Value::Number(Fraction::from_integer(3))]);
fn test_eval_eval_defun() {
let results = interp.eval("(eval '(defun x (a) (+ 1 a)))\n(x 5)").unwrap();
fn test_eval_eval_self_evaluating() {
assert_eq!(
interp.eval("(eval 42)").unwrap(),
vec![Value::Number(Fraction::from_integer(42))]
);
interp.eval("(eval \"hello\")").unwrap(),
vec![Value::String("hello".to_string())]
assert_eq!(interp.eval("(eval nil)").unwrap(), vec![Value::Nil]);
fn test_eval_eval_symbol() {
let results = interp.eval("(eval 'revision)").unwrap();
match &results[0] {
Value::String(s) => assert!(s.chars().all(|c| c.is_ascii_hexdigit())),
_ => panic!("expected string, got {:?}", results[0]),
fn test_eval_lambda_literal() {
let results = interp.eval("(lambda (x) (* x 2))").unwrap();
results,
vec![Value::String("(LAMBDA (X) (* X 2))".to_string())]
fn test_eval_defun_then_call() {
.eval("(defun double (x) (* x 2)) (double 5)")
fn test_eval_eval_defun_dynamic() {
.eval("(eval '(defun sum (a) (+ a 1))) (sum 5)")
fn test_eval_funcall_lambda() {
let results = interp.eval("(funcall (lambda (x y) (+ x y)) 3 4)").unwrap();
fn test_eval_function_form() {
.eval("(defun f (x) (* x 2)) (funcall (function f) 5)")
fn test_bare_operator_error() {
let err = interp.eval("+").unwrap_err();
assert!(
err.to_string().contains("is a function"),
"expected function error, got: {err}"
fn test_bare_special_form_error() {
let err = interp.eval("quote").unwrap_err();
err.to_string().contains("is a special form"),
"expected special form error, got: {err}"
fn test_bare_native_function_error() {
let err = interp.eval("debug").unwrap_err();
fn test_labels_simple() {
.eval("(labels ((double (x) (* x 2))) (double 5))")
fn test_labels_factorial() {
.eval(
"(defun fact (n)
(labels ((go (i acc)
(if (<= i 1) acc (go (- i 1) (* acc i)))))
(go n 1)))
(fact 5)",
)
assert_eq!(results, vec![Value::Number(Fraction::from_integer(120))]);
fn test_labels_mutual_recursion() {
"(labels ((is-even (n) (if (= n 0) t (is-odd (- n 1))))
(is-odd (n) (if (= n 0) nil (is-even (- n 1)))))
(is-even 4))",
assert_eq!(results, vec![Value::Bool(true)]);
fn test_labels_no_body_error() {
let err = interp.eval("(labels ((f (x) x)))").unwrap_err();
err.to_string().contains("LABELS requires"),
"expected labels error, got: {err}"
fn test_labels_scope() {
interp
.eval("(labels ((local-fn (x) (+ x 1))) (local-fn 5))")
let err = interp.eval("(local-fn 5)").unwrap_err();
err.to_string().contains("undefined")
|| err.to_string().contains("Undefined")
|| err.to_string().contains("not defined"),
"expected undefined error, got: {err}"
fn test_1_plus() {
let results = interp.eval("(1+ 5)").unwrap();
fn test_1_minus() {
let results = interp.eval("(1- 5)").unwrap();
assert_eq!(results, vec![Value::Number(Fraction::from_integer(4))]);