UP | HOME

Testes

Arquivo: tests.rs.

A seguir, enumero alguns testes unitários para Majestic Lisp. Estes testes tentam seguir as orientações e exemplos da especificação ao máximo.

1. Importações

use regex::Regex;
use crate::{ maj_list, maj_dotted_list };
use crate::printing::{ maj_format, maj_format_raw };
use crate::core::{ MajState, Maj };
use crate::axioms::predicates::maj_errorp;
use crate::evaluator::maj_eval;
use crate::reader::tokenizer::maj_tokenize;
use crate::reader::parser::maj_parse;
use crate::axioms::primitives::{ maj_car, maj_macroexpand_1 };

2. Expressões regulares

const RE_IN_STREAM:  &'static str =
    // #<stream (in) {0x...}>
    r"(?u)^#<stream \(in\) \{0x[0-9a-z]*}>$";
const RE_OUT_STREAM: &'static str =
    // #<stream (out) {0x...}>
    r"(?u)^#<stream \(out\) \{0x[0-9a-z]*}>$";
const RE_ENVIRONMENT: &'static str =
    // #<environment {0x...}>
    r"^(?u)#<environment \{0x[0-9a-z]*\}>$";
const RE_CLOSURE: &'static str =
    // #<function (fn (x...)) {0x...}>
    // #<function (fn nil) {0x...}>
    // #<function (fn (x... . blah)) {0x...}>
    r"(?u)^#<function \(fn (nil|\((\w+\s*)+(\. \w+)?\))\) \{0x[0-9a-z]*\}>$";
const RE_MACRO: &'static str =
    // #<macro (mac (x...)) {0x...}>
    // #<macro (mac nil) {0x...}>
    // #<macro (mac (x... . blah)) {0x...}>
    r"(?u)^#<macro \(mac (nil|\((\w+\s*)+(\. \w+)?\))\) \{0x[0-9a-z]*\}>$";
const RE_PRIMITIVE: &'static str =
    // #<function (prim fn-name (arity (required X)))>
    // #<function (prim fn-name (arity (required 0)))>
    // #<function (prim fn-name (arity (variadic X)))>
    // #<function (prim fn-name (arity (variadic 0)))>
    r"(?u)^#<function \(prim ((\w|\W)+) \(arity \((required|variadic) [0-9]*\)\)\)>$";

3. Macros de teste

3.1. Comparação direta de formatações

macro_rules! test_format {
    ($state:ident, $x:expr, $y:tt) => {
        let ex = $x;
        let fmt = maj_format(&$state, ex);
        //println!("fmt = {}", fmt);
        assert_eq!(fmt, $y);
    };
}
macro_rules! multi_test {
    ($state:ident; $(($x:expr, $y:tt);)+) => {
        $(test_format!($state, $x, $y);)*
    }
}

3.2. Comparação de interpretações de AST

macro_rules! test_eval_ast {
    ($state:ident, $x:expr, $env:expr, $y:tt) => {
        let ex = $x;
        let result = maj_eval(&mut $state, ex, $env);
        let fmt = maj_format(&$state, result);
        assert_eq!(fmt, $y);
    };
}
macro_rules! multi_eval_ast_test {
    ($state:ident; $(($x:expr, $env:expr, $y:tt);)+) => {
        $(test_eval_ast!($state, $x, $env, $y);)*
    }
}

3.3. Comparação de parsing

macro_rules! test_parser {
    ($state:ident, $expr:tt, $toks:expr, $y:tt) => {
        let tokens = maj_tokenize($expr).unwrap();
        let expected_tokens: Vec<&str> = $toks;
        assert_eq!(tokens.len(), expected_tokens.len());
        for n in 0..tokens.len() {
            assert_eq!(tokens[n], expected_tokens[n]);
        }
        let parsed = maj_parse(&mut $state, tokens).unwrap();
        let fmt    = maj_format_raw(&$state, parsed, false);
        assert_eq!(fmt, $y);
    }
}
macro_rules! multi_parser_test {
    ($state:ident; $(($expr:tt, $toks:expr, $y:tt);)+) => {
        $(test_parser!($state, $expr, $toks, $y);)*
    }
}

3.4. Comparação de falha de parsing

macro_rules! test_parser_fail {
    ($state:ident, $expr:tt) => {
        let tokens = maj_tokenize($expr).unwrap();
        assert!(maj_parse(&mut $state, tokens).is_err());
    }
}
macro_rules! multi_parser_fail_test {
    ($state:ident; $($expr:tt;)+) => {
        $(test_parser_fail!($state, $expr);)*
    }
}

3.5. Comparação de interpretação

macro_rules! test_eval {
    ($state:ident, $expr:tt, $y:tt) => {
        let tokens = maj_tokenize($expr).unwrap();
        let parsed = maj_parse(&mut $state, tokens).unwrap();
        let result = maj_eval(
            &mut $state,
            Maj::cons(Maj::do_sym(), parsed),
            Maj::nil());
        assert!(!maj_errorp(result.clone()).to_bool());
        let fmt    = maj_format_raw(&$state, result, false);
        assert_eq!(fmt, $y);
    }
}
macro_rules! multi_eval_test {
    ($state:ident; $(($expr:tt, $y:tt);)+) => {
        $(test_eval!($state, $expr, $y);)*
    }
}

3.6. Comparação com falha de interpretação

macro_rules! test_eval_fail {
    ($state:ident, $expr:tt) => {
        let tokens = maj_tokenize($expr).unwrap();
        let parsed = maj_parse(&mut $state, tokens).unwrap();
        let result = maj_eval(
            &mut $state,
            Maj::cons(Maj::do_sym(), parsed),
            Maj::nil());
        assert!(maj_errorp(result).to_bool());
    }
}
macro_rules! multi_eval_fail_test {
    ($state:ident; $($expr:tt;)+) => {
        $(test_eval_fail!($state, $expr);)*
    }
}

3.7. Comparação com expansão de macro (uma vez)

macro_rules! test_macroexpand_1 {
    ($state:ident, $expr:tt, $y:tt) => {
        let tokens = maj_tokenize($expr).unwrap();
        let parsed = maj_parse(&mut $state, tokens).unwrap();
        let parsed = maj_car(parsed);
        let (expanded, worked) =
            maj_macroexpand_1(&mut $state, parsed, Maj::nil());
        if !worked {
            panic!("Failed expansion: {}\nExpected: {}",
                   maj_format_raw(&$state, expanded, false),
                   $y);
        }
        let fmt = maj_format_raw(&$state, expanded, false);
        assert_eq!(fmt, $y);
    }
}
macro_rules! multi_macroexpand_1_test {
    ($state:ident; $(($expr:tt, $y:tt);)+) => {
        $(test_macroexpand_1!($state, $expr, $y);)*
    }
}

3.8. Comparação por expressão regular

macro_rules! test_regex {
    ($state:ident, $x:expr, $re:tt) => {
        let ex  = $x;
        let fmt = maj_format(&$state, ex);
        let re  = Regex::new($re).unwrap();
        assert!(re.is_match(&fmt));
    };
}
macro_rules! test_fail_regex {
    ($state:ident, $x:expr, $re:tt) => {
        let ex  = $x;
        let fmt = maj_format(&$state, ex);
        let re  = Regex::new($re).unwrap();
        assert!(!re.is_match(&fmt));
    };
}
macro_rules! multi_regex_test {
    ($state:ident; $($pair:expr;)+) => {
        $(
            let (x, y) = $pair;
            test_regex!($state, x, y);
        )*
    }
}

3.9. Comparação com expressão de falha ou não-falha

macro_rules! test_fail {
    ($x:expr) => {
        assert!(maj_errorp($x).to_bool());
    };
}
macro_rules! test_dont_fail {
    ($x:expr) => {
        assert!(!maj_errorp($x).to_bool());
    };
}
macro_rules! multi_fail_test {
    ($($x:expr;)+) => {
        $(test_fail!($x);)*
    }
}

3.10. Arquivos para uso em streams

3.10.1. Leitura

Hello world

3.10.2. Escrita


3.11. Comparação de resultados de predicados

macro_rules! test_boolean {
    ($x:expr, $v:literal) => {
        let res = $x;
        if maj_errorp(res.clone()).to_bool() {
            panic!("Error raised during assertion");
        }
        assert_eq!(res.to_bool(), $v);
    }
}
macro_rules! multi_boolean_test {
    ($(($x:expr, $v:literal);)+) => {
        $(test_boolean!($x, $v);)*
    }
}

4. Formatação

4.1. Símbolos

#[test]
fn formatter_symbol() {
    let mut state = MajState::new();
    multi_test!(
        state;
        (Maj::symbol(&mut state, "foo"),   "foo");
        (Maj::symbol(&mut state, "bar"),   "bar");
        (Maj::symbol(&mut state, "baz"),   "baz");
        (Maj::symbol(&mut state, "t"),     "t");
        (Maj::t(),                         "t");
        (Maj::symbol(&mut state, "nil"),   "nil");
        (Maj::nil(),                       "nil");
        (Maj::symbol(&mut state, "&"),     "&");
        (Maj::symbol(&mut state, "apply"), "apply");
    );
}

4.2. Cons

#[test]
fn formatter_cons_cell() {
    let mut state = MajState::new();
    let foo = Maj::symbol(&mut state, "foo");
    let bar = Maj::symbol(&mut state, "bar");
    let baz = Maj::symbol(&mut state, "baz");

    multi_test!(
        state;
        (Maj::cons(foo.clone(), bar.clone()),
         "(foo . bar)");
        (Maj::cons(foo.clone(),
                   Maj::cons(bar.clone(), baz.clone())),
         "(foo bar . baz)");
    );
}

4.3. Caracteres

#[test]
fn formatter_character() {
    let state = MajState::new();
    multi_test!(
        state;
        (Maj::character('a'),    "#\\a");
        (Maj::character('\x07'), "#\\␇");
        (Maj::character('\t'),   "#\\tab");
        (Maj::character(' '),    "#\\space");
        (Maj::character('\n'),   "#\\newline");
    );
}

4.4. Streams

#[test]
#[ignore]
fn formatter_stream() {
    use crate::core::types::MajStreamDirection;
    let mut state = MajState::new();
    let stdin  = state.make_stream_stdin();
    let stdout = state.make_stream_stdout();
    let istream = Maj::stream(
        &mut state,
        "test-streams-in.txt",
        MajStreamDirection::In).unwrap();
    let ostream = Maj::stream(
        &mut state,
        "test-streams-out.txt",
        MajStreamDirection::Out).unwrap();

    multi_regex_test!(
        state;
        (stdin,           RE_IN_STREAM);
        (stdout,          RE_OUT_STREAM);
        (istream.clone(), RE_IN_STREAM);
        (ostream.clone(), RE_OUT_STREAM);
    );

    state.close_stream(istream);
    state.close_stream(ostream);
}

4.5. Números

4.5.1. Inteiros

#[test]
fn formatter_number_integer() {
    let state = MajState::new();
    multi_test!(
        state;
        (Maj::integer(1), "1");
        (Maj::integer(0), "0");
        (Maj::integer(-1), "-1");
        (Maj::integer(50), "50");
        (Maj::integer(295), "295");
    );
}

4.5.2. Frações

Frações não sofrem simplificação em sua criação para que não haja complicações em tipos esperados. Então, ignoramos simplificações.

#[test]
fn formatter_number_fraction() {
    let state = MajState::new();
    multi_test!(
        state;
        (Maj::fraction(2, 3),    "2/3");
        (Maj::fraction(3, 4),    "3/4");
        (Maj::fraction(5, 8),    "5/8");
        (Maj::fraction(99, 100), "99/100");
        (Maj::fraction(5, 2),    "5/2");
        (Maj::fraction(-10, 3),  "-10/3");

        // (Maj::fraction(2, 4),    "1/2");
        // (Maj::fraction(5, 1),    "5");
        // (Maj::fraction(4, -9),   "-4/9");
        // (Maj::fraction(-4, -9),  "4/9");
    );
}

4.5.3. Floats

#[test]
fn formatter_number_float() {
    let state = MajState::new();
    multi_test!(
        state;
        (Maj::float(2.0), "2.0");
        (Maj::float(0.5), "0.5");
        (Maj::float(20.2), "20.2");
        (Maj::float(-16.3), "-16.3");
        (Maj::float(-9.0), "-9.0");
        (Maj::float(-7.0), "-7.0");
    );
}

4.5.4. Complexos

#[test]
fn formatter_number_complex() {
    let state = MajState::new();
    multi_test!(
        state;
        (Maj::complex(Maj::integer(0),
                      Maj::integer(5)),
         "0J5");
        (Maj::complex(Maj::integer(3),
                      Maj::integer(1)),
         "3J1");
        (Maj::complex(Maj::fraction(2, 3),
                      Maj::float(0.5)),
         "2/3J0.5");
        (Maj::complex(Maj::integer(-2),
                      Maj::integer(-1)),
         "-2J-1");
        (Maj::complex(Maj::float(35.0),
                      Maj::fraction(-2, 9)),
         "35.0J-2/9");
    );
}

4.6. Listas

4.6.1. Listas pontuadas

#[test]
fn formatter_dotted_list() {
    let mut state = MajState::new();
    let foo  = Maj::symbol(&mut state, "foo");
    let bar  = Maj::symbol(&mut state, "bar");
    let baz  = Maj::symbol(&mut state, "baz");
    let quux = Maj::symbol(&mut state, "quux");

    multi_test!(
        state;
        (maj_dotted_list!(foo.clone(), bar.clone()),
         "(foo . bar)");
        (maj_dotted_list!(foo.clone(), bar.clone(),
                          baz.clone()),
         "(foo bar . baz)");
        (maj_dotted_list!(foo.clone(), bar.clone(),
                          baz.clone(), quux.clone()),
         "(foo bar baz . quux)");
    );
}

4.6.2. Listas adequadas

#[test]
fn formatter_proper_list() {
    let mut state = MajState::new();
    let foo  = Maj::symbol(&mut state, "foo");
    let bar  = Maj::symbol(&mut state, "bar");
    let baz  = Maj::symbol(&mut state, "baz");
    let quux = Maj::symbol(&mut state, "quux");

    multi_test!(
        state;
        (maj_list!(foo.clone()), "(foo)");
        (maj_list!(foo.clone(), bar.clone()),
         "(foo bar)");
        (maj_list!(foo.clone(), bar.clone(),
                   baz.clone()),
         "(foo bar baz)");
        (maj_list!(foo.clone(), bar.clone(),
                   baz.clone(), quux.clone()),
         "(foo bar baz quux)");
        (maj_list!(Maj::quote(), foo.clone()),
         "'foo");
        (maj_list!(Maj::quasiquote(),
                   maj_list!(
                       foo.clone(),
                       maj_list!(
                           Maj::unquote(),
                           bar.clone()),
                       maj_list!(
                           Maj::unquote_splice(),
                           baz.clone()))),
         "`(foo ,bar ,@baz)");
    );
}

4.7. Vetores

4.7.1. Vetores de números inteiros

#[test]
fn formatter_vector_integers() {
    let state = MajState::new();
    multi_test!(
        state;
        (Maj::vector_integer(vec![]), "[]");
        (Maj::vector_integer(vec![1, 2, 3, 4]),
         "[1 2 3 4]");
        (Maj::vector_integer(vec![-10, 2, 5, 93]),
         "[-10 2 5 93]");
    );
}

4.7.2. Vetores de pontos flutuantes

#[test]
fn formatter_vector_float() {
    let state = MajState::new();
    multi_test!(
        state;
        (Maj::vector_float(vec![]), "[]");
        (Maj::vector_float(vec![1.0, 2.0, 3.0, 4.0]),
         "[1.0 2.0 3.0 4.0]");
        (Maj::vector_float(vec![-10.0, 2.0, 5.0, 93.0]),
         "[-10.0 2.0 5.0 93.0]");
    );
}

4.7.3. Strings

#[test]
fn formatter_string() {
    let state = MajState::new();
    multi_test!(
        state;
        (Maj::string(""), "\"\"");
        (Maj::string("abc"), "\"abc\"");
    );
}

4.7.4. Vetores de tipos quaisquer

#[test]
fn formatter_vector_any() {
    let mut state = MajState::new();
    multi_test!(
        state;
        (Maj::vector_any(vec![]), "[]");
        (Maj::vector_any(vec![
            Maj::integer(1),
            Maj::fraction(2, 3),
            Maj::complex(Maj::integer(2),
                         Maj::integer(5)),
            Maj::integer(6),
            maj_list!(Maj::symbol(&mut state, "a"),
                      Maj::symbol(&mut state, "b"),
                      Maj::symbol(&mut state, "c"))]),
         "[1 2/3 2J5 6 (a b c)]");
        (Maj::vector_any(
            vec![Maj::vector_any(vec![]),
                 Maj::vector_any(vec![]),
                 Maj::vector_any(vec![])]),
         "[[] [] []]");
        (Maj::vector_any(
            vec![Maj::character('H'),
                 Maj::character('e'),
                 Maj::character('l'),
                 Maj::character('l'),
                 Maj::character('o')]),
         "[#\\H #\\e #\\l #\\l #\\o]");
    );
}

4.8. Clausuras

#[test]
fn formatter_closure() {
    let mut state = MajState::new();
    let x = Maj::symbol(&mut state, "x");
    let fst = Maj::symbol(&mut state, "fst");
    let snd = Maj::symbol(&mut state, "snd");
    let rest = Maj::symbol(&mut state, "rest");
    multi_regex_test!(
        state;
        // (lit closure nil (x) ((* x x)))
        // #<function (fn (x)) {0x...}>
        (maj_list!(Maj::lit(), Maj::closure(), Maj::nil(),
                   maj_list!(x.clone()),
                   maj_list!(
                       maj_list!(Maj::symbol(&mut state, "*"),
                                 x.clone(), x.clone()))),
         RE_CLOSURE);
        // (lit closure nil nil (2))
        // #<function (fn nil) {0x...}>
        (maj_list!(Maj::lit(), Maj::closure(), Maj::nil(),
                   Maj::nil(),
                   maj_list!(Maj::integer(2))),
         RE_CLOSURE);
        // (lit closure nil (x . rest) ((x)))
        // #<function (fn (x . rest)) {0x...}>
        (maj_list!(Maj::lit(), Maj::closure(), Maj::nil(),
                   maj_dotted_list!(x.clone(),
                                    rest.clone()),
                   maj_list!(maj_list!(x.clone()))),
         RE_CLOSURE);
        // (lit closure nil (fst snd . rest) ((fst)))
        // #<function (fn (fst snd . rest)) {0x...}>
        (maj_list!(Maj::lit(), Maj::closure(), Maj::nil(),
                   maj_dotted_list!(fst.clone(),
                                    snd.clone(),
                                    rest.clone()),
                   maj_list!(maj_list!(fst.clone()))),
         RE_CLOSURE);
    );
    test_fail_regex!(state,
                     // (lit 2)
                     maj_list!(Maj::lit(), Maj::integer(2)),
                     RE_CLOSURE);
}

4.9. Primitivas

#[test]
fn formatter_primitive() {
    let mut state = MajState::new();

    let prim_fetch = |mut state: &mut MajState, name| {
        let sym = Maj::symbol(&mut state, name);
        let result =
            maj_eval(&mut state, sym, Maj::nil());
        assert!(!maj_errorp(result.clone()).to_bool());
        result
    };
    
    multi_regex_test! {
        state;
        // (lit prim cons required 2) => (defn cons (a b) ...)
        (prim_fetch(&mut state, "cons"), RE_PRIMITIVE);
        // (lit prim coin nil nil) => (defn coin () ...)
        (prim_fetch(&mut state, "coin"), RE_PRIMITIVE);
        // (lit prim print variadic 1) => (defn print (fmt . rest) ...)
        (prim_fetch(&mut state, "print"), RE_PRIMITIVE);
        // (lit prim list variadic 0) => (defn list rest ...)
        (prim_fetch(&mut state, "list"), RE_PRIMITIVE);
    }
}

4.10. Macros

Isso aqui acaba sendo um quase um copypaste descarado do teste de clausuras, mas com algumas modificações.

#[test]
fn formatter_macro() {
    let mut state = MajState::new();

    let x = Maj::symbol(&mut state, "x");
    let fst = Maj::symbol(&mut state, "fst");
    let snd = Maj::symbol(&mut state, "snd");
    let rest = Maj::symbol(&mut state, "rest");
    
    let macro_writer = |lambda_list, body| {
        // (lit macro (lit closure nil <lambda-list> <body>))
        // where <body> is also a list of many expressions
        maj_list!(Maj::lit(), Maj::macro_sym(),
                  maj_list!(
                      Maj::lit(),
                      Maj::closure(),
                      Maj::nil(),
                      lambda_list, body))
    };

    multi_regex_test!(
        state;
        // #<macro (mac (x)) {0x...}>
        // (mac (x) x)
        (macro_writer(
            maj_list!(x.clone()),
            maj_list!(x.clone())),
         RE_MACRO);
        // #<macro (mac nil) {0x...}>
        // (mac () x)
        (macro_writer(
            Maj::nil(),
            maj_list!(x.clone())),
         RE_MACRO);
        
        // #<macro (mac (x . rest)) {0x...}>
        // (mac (x . rest) (x rest))
        (macro_writer(
            maj_dotted_list!(x.clone(), rest.clone()),
            maj_list!(x.clone(), rest.clone())),
         RE_MACRO);
        
        // #<macro (mac (fst snd . rest)) {0x...}>
        // (mac (fst snd . rest) (fst snd rest))
        (macro_writer(
            maj_dotted_list!(fst.clone(), snd.clone(),
                             rest.clone()),
            maj_list!(fst.clone(), snd.clone(), rest.clone())),
         RE_MACRO);
    );
}

4.11. Erros

#[test]
fn formatter_error() {
    let state = MajState::new();

    let error_writer = |format, args| {
        maj_dotted_list!(
            Maj::lit(), Maj::error(),
            format, args)
    };
    
    multi_test!(
        state;
        (error_writer(Maj::string("Hello"),
                      Maj::nil()),
         "Hello");
        (error_writer(Maj::string("Hello, {}"),
                      maj_list!(
                          Maj::string("world"))),
         "Hello, world");
        (error_writer(Maj::string("{} + {} = {}"),
                      maj_list!(
                          Maj::integer(1),
                          Maj::integer(2),
                          Maj::integer(3))),
         "1 + 2 = 3");
        (error_writer(Maj::string("{} is not a list such as {}"),
                      maj_list!(
                          Maj::cons(Maj::integer(1),
                                    Maj::integer(2)),
                          maj_list!(Maj::integer(1),
                                    Maj::integer(2)))),
         "(1 . 2) is not a list such as (1 2)");
    );
}

4.12. TODO Pretty-printing

#[test]
#[ignore]
fn formatter_prettyprinting() {
    unimplemented!();
}

5. Coerções numéricas

#[test]
fn number_coercion() {
    use crate::axioms::primitives::maj_number_coerce;
    let mut state = MajState::new();
    let integer  = Maj::symbol(&mut state, "integer");
    let fraction = Maj::symbol(&mut state, "fraction");
    let float    = Maj::symbol(&mut state, "float");
    let complex  = Maj::symbol(&mut state, "complex");

    multi_test!(
        state;
        
        // Integer coercion
        (maj_number_coerce(&mut state, integer.clone(),
                           Maj::integer(5)),
         "5");
        (maj_number_coerce(&mut state, float.clone(),
                           Maj::integer(5)),
         "5.0");
        (maj_number_coerce(&mut state, fraction.clone(),
                           Maj::integer(5)),
         "5/1");
        (maj_number_coerce(&mut state, complex.clone(),
                           Maj::integer(5)),
         "5J0.0");

        // Float coercion
        (maj_number_coerce(&mut state, integer.clone(),
                           Maj::float(5.3)),
         "5");
        (maj_number_coerce(&mut state, float.clone(),
                           Maj::float(5.3)),
         "5.3");
        (maj_number_coerce(&mut state, fraction.clone(),
                           Maj::float(5.3)),
         "53/10");
        (maj_number_coerce(&mut state, complex.clone(),
                           Maj::float(5.3)),
         "5.3J0.0");

        // Fraction coercion
        (maj_number_coerce(&mut state, integer.clone(),
                           Maj::fraction(3, 2)),
         "1");
        (maj_number_coerce(&mut state, float.clone(),
                           Maj::fraction(3, 2)),
         "1.5");
        (maj_number_coerce(&mut state, fraction.clone(),
                           Maj::fraction(3, 2)),
         "3/2");
        (maj_number_coerce(&mut state, complex.clone(),
                           Maj::fraction(3, 2)),
         "3/2J0.0");

        // Complex coercion
        (maj_number_coerce(&mut state, integer.clone(),
                           Maj::complex(
                               Maj::integer(3),
                               Maj::integer(2))),
         "3");
        (maj_number_coerce(&mut state, float.clone(),
                           Maj::complex(
                               Maj::integer(3),
                               Maj::integer(2))),
         "3.0");
        (maj_number_coerce(&mut state, fraction.clone(),
                           Maj::complex(
                               Maj::integer(3),
                               Maj::integer(2))),
         "3/1");
        (maj_number_coerce(&mut state, complex.clone(),
                           Maj::complex(
                               Maj::integer(3),
                               Maj::integer(2))),
         "3J2");
    );
}

6. Funções

6.1. Predicados

6.1.1. symbolp

#[test]
fn predicates_symbolp() {
    use crate::axioms::predicates::maj_symbolp;
    multi_boolean_test!(
        (maj_symbolp(Maj::t()), true);
        (maj_symbolp(Maj::fraction(2, 3)), false);
    );
}

6.1.2. eq

#[test]
fn predicates_eq() {
    use crate::axioms::predicates::maj_eq;
    multi_boolean_test!(
        (maj_eq(Maj::t(), Maj::t()), true);
        (maj_eq(Maj::nil(), Maj::nil()), true);
        (maj_eq(Maj::t(), Maj::nil()), false);
        (maj_eq(Maj::integer(20), Maj::t()), false);
    );
}

6.1.3. nilp

#[test]
fn predicates_nilp() {
    use crate::axioms::predicates::maj_nilp;
    multi_boolean_test!(
        (maj_nilp(Maj::nil()), true);
        (maj_nilp(Maj::integer(5)), false);
    );
}

6.1.4. consp

#[test]
fn predicates_consp() {
    use crate::axioms::predicates::maj_consp;
    let mut state = MajState::new();
    multi_boolean_test!(
        (maj_consp(Maj::cons(Maj::integer(2),
                             Maj::integer(3))),
         true);
        (maj_consp(Maj::cons(Maj::symbol(&mut state, "a"),
                             Maj::symbol(&mut state, "b"))),
         true);
        (maj_consp(Maj::integer(10)), false);
    );
}

6.1.5. atomp

#[test]
fn predicates_atomp() {
    use crate::axioms::predicates::maj_atomp;
    let mut state = MajState::new();
    multi_boolean_test!(
        (maj_atomp(Maj::integer(1)), true);
        (maj_atomp(Maj::symbol(&mut state, "a")), true);
        (maj_atomp(maj_list!(Maj::integer(1),
                             Maj::integer(2),
                             Maj::integer(3))),
         false);
    );
}

6.1.6. charp

#[test]
fn predicates_charp() {
    use crate::axioms::predicates::maj_charp;
    multi_boolean_test!(
        (maj_charp(Maj::character('a')), true);
        (maj_charp(Maj::t()), false);
    );
}

6.1.7. char=

#[test]
fn predicates_char_equals() {
    use crate::axioms::predicates::maj_char_equals;
    let small_a = Maj::character('a');
    let big_a   = Maj::character('A');
    let bel     = Maj::character('\x07');
    multi_boolean_test!(
        (maj_char_equals(small_a.clone(), small_a.clone()),
         true);
        (maj_char_equals(small_a.clone(), big_a.clone()),
         false);
    );
    multi_fail_test!(
        maj_char_equals(small_a.clone(), Maj::t());
        maj_char_equals(Maj::nil(), bel);
    );
}

6.1.8. streamp

#[test]
fn predicates_streamp() {
    use crate::axioms::predicates::maj_streamp;
    use crate::core::types::MajStreamDirection;
    let mut state = MajState::new();
    let ostream = Maj::stream(
        &mut state,
        "test-streams-out.txt",
        MajStreamDirection::Out).unwrap();
    let stdout = state.make_stream_stdout();
    multi_boolean_test!(
        (maj_streamp(ostream.clone()), true);
        (maj_streamp(stdout), true);
        (maj_streamp(Maj::t()), false);
    );
    state.close_stream(ostream);
}

6.1.9. numberp

#[test]
fn predicates_numberp() {
    use crate::axioms::predicates::maj_numberp;
    multi_boolean_test!(
        (maj_numberp(Maj::integer(2)), true);
        (maj_numberp(Maj::float(0.5)), true);
        (maj_numberp(Maj::fraction(2, 3)), true);
        (maj_numberp(Maj::complex(Maj::integer(0),
                                  Maj::float(2.0))),
         true);
        (maj_numberp(Maj::t()), false);
    );
}

6.1.10. integerp

#[test]
fn predicates_integerp() {
    use crate::axioms::predicates::maj_integerp;
    multi_boolean_test!(
        (maj_integerp(Maj::integer(2)), true);
        (maj_integerp(Maj::fraction(2, 3)), false);
    );
}

6.1.11. floatp

#[test]
fn predicates_floatp() {
    use crate::axioms::predicates::maj_floatp;
    multi_boolean_test!(
        (maj_floatp(Maj::float(2.5)), true);
        (maj_floatp(Maj::float(2.0)), true);
        (maj_floatp(Maj::float(0.5)), true);
        (maj_floatp(Maj::integer(3)), false);
    );
}

6.1.12. fractionp

#[test]
fn predicates_fractionp() {
    use crate::axioms::predicates::maj_fractionp;
    multi_boolean_test!(
        (maj_fractionp(Maj::fraction(2, 3)), true);
        (maj_fractionp(Maj::fraction(5, 8)), true);
        (maj_fractionp(Maj::integer(8)), false);
    );
}

6.1.13. complexp

#[test]
fn predicates_complexp() {
    use crate::axioms::predicates::maj_complexp;
    multi_boolean_test!(
        (maj_complexp(Maj::complex(Maj::float(0.5),
                                   Maj::integer(1))),
         true);
        (maj_complexp(Maj::complex(Maj::integer(-10),
                                   Maj::integer(-3))),
         true);
        (maj_complexp(Maj::integer(5)), false);
        // (maj_complexp(Maj::complex(Maj::integer(5),
        //                            Maj::integer(0))),
        //  false);
        (maj_complexp(Maj::complex(Maj::integer(5),
                                   Maj::float(0.0))),
         true);
    );
}

6.1.14. vectorp

#[test]
fn predicates_vectorp() {
    use crate::axioms::predicates::maj_vectorp;
    multi_boolean_test!(
        (maj_vectorp(
            Maj::vector_integer(vec![1, 2, 3])), true);
        (maj_vectorp(Maj::t()), false);
    );
}

6.1.15. id

#[test]
fn predicates_id() {
    use crate::axioms::predicates::maj_id;
    let mut state = MajState::new();
    multi_boolean_test!(
        (maj_id(Maj::symbol(&mut state, "a"),
                Maj::symbol(&mut state, "a")),
         true);
        (maj_id(Maj::character('c'),
                Maj::character('c')),
         true);
        (maj_id(maj_list!(Maj::symbol(&mut state, "a"),
                          Maj::symbol(&mut state, "b")),
                maj_list!(Maj::symbol(&mut state, "a"),
                          Maj::symbol(&mut state, "b"))),
         false);
        (maj_id(Maj::integer(5), Maj::integer(5)),
         false);
    );
}

6.1.16. proper-list-p

#[test]
fn predicates_proper_list_p() {
    use crate::axioms::predicates::maj_proper_list_p;
    let mut state = MajState::new();
    let a = Maj::symbol(&mut state, "a");
    let b = Maj::symbol(&mut state, "b");
    let c = Maj::symbol(&mut state, "c");
    let d = Maj::symbol(&mut state, "d");
    multi_boolean_test!(
        (maj_proper_list_p(
            maj_list!(a.clone(),
                      b.clone(),
                      c.clone(),
                      d.clone())),
         true);
        (maj_proper_list_p(
            maj_dotted_list!(a, b, c, d)),
         false);
    );
}

6.1.17. stringp

#[test]
fn predicates_stringp() {
    use crate::axioms::predicates::maj_stringp;
    use crate::axioms::primitives::maj_vector;
    let mut state = MajState::new();
    let a = Maj::character('a');
    let b = Maj::character('b');
    let c = Maj::character('c');
    let charlist = maj_list!(a.clone(), b.clone(), c.clone());
    let charvec = maj_vector(&mut state, charlist.clone());
    let charvec2 = Maj::vector_any(vec![a, b, c]);
    multi_boolean_test!(
        (maj_stringp(Maj::string("abc")), true);
        (maj_stringp(charvec), true);
        (maj_stringp(charlist), false);
        (maj_stringp(charvec2), false);
        (maj_stringp(Maj::t()), false);
    );  
}

6.1.18. literalp

#[test]
fn predicates_literalp() {
    use crate::axioms::predicates::maj_literalp;
    let mut state = MajState::new();
    let x = Maj::symbol(&mut state, "x");
    let a = Maj::symbol(&mut state, "a");
    let b = Maj::symbol(&mut state, "b");
    let c = Maj::symbol(&mut state, "c");
    multi_boolean_test!(
        (maj_literalp(
            // (lit closure nil (x) ((* x x)))
            maj_list!(Maj::lit(),
                      Maj::closure(),
                      Maj::nil(),
                      maj_list!(x.clone()),
                      maj_list!(maj_list!(
                          Maj::symbol(&mut state, "*"),
                          x.clone(), x)))),
         true);
        (maj_literalp(maj_list!(a, b, c)), false);
        (maj_literalp(maj_list!(
            Maj::lit(),
            Maj::symbol(&mut state, "blah"))),
         true);       
    );
}

6.1.19. primitivep

#[test]
fn predicates_primitivep() {
    use crate::axioms::predicates::maj_primitivep;
    let mut state = MajState::new();
    let x = Maj::symbol(&mut state, "x");
    // Emulate internal definitions of primitivep and +
    // (lit prim primitivep required 1)
    let primitivep = maj_list!(
        Maj::lit(),
        Maj::prim(),
        Maj::symbol(&mut state, "primitivep"),
        Maj::symbol(&mut state, "required"),
        Maj::integer(1));
    // (lit prim + variadic 0)
    let plus = maj_list!(
        Maj::lit(),
        Maj::prim(),
        Maj::symbol(&mut state, "+"),
        Maj::symbol(&mut state, "variadic"),
        Maj::integer(0));
    // Emulate closure definition on top-level
    // (lit closure nil (x) ((+ x x)))
    let closure = maj_list!(
        Maj::lit(),
        Maj::closure(),
        Maj::nil(),
        maj_list!(x.clone()),
        maj_list!(maj_list!(
            Maj::symbol(&mut state, "+"),
            x.clone(), x)));
    multi_boolean_test!(
        (maj_primitivep(primitivep), true);
        (maj_primitivep(closure), false);
        (maj_primitivep(plus), true);
    );
}

6.1.20. closurep

#[test]
fn predicates_closurep() {
    use crate::axioms::predicates::maj_closurep;
    let mut state = MajState::new();
    let x = Maj::symbol(&mut state, "x");
    // Emulate closure definition on top-level
    // (lit closure nil (x) ((* x x)))
    let closure = maj_list!(
        Maj::lit(),
        Maj::closure(),
        Maj::nil(),
        maj_list!(x.clone()),
        maj_list!(maj_list!(
            Maj::symbol(&mut state, "*"),
            x.clone(), x)));
    // Emulate internal definitions of cons and +
    // (lit prim cons required 2)
    let cons = maj_list!(
        Maj::lit(),
        Maj::prim(),
        Maj::symbol(&mut state, "cons"),
        Maj::symbol(&mut state, "required"),
        Maj::integer(2));
    // (lit prim + variadic 0)
    let plus = maj_list!(
        Maj::lit(),
        Maj::prim(),
        Maj::symbol(&mut state, "+"),
        Maj::symbol(&mut state, "variadic"),
        Maj::integer(0));
    multi_boolean_test!(
        (maj_closurep(closure), true);
        (maj_closurep(
            maj_list!(Maj::lit(),
                      Maj::symbol(&mut state, "blah"))),
         false);
        (maj_closurep(cons), false);
        (maj_closurep(plus), false);
    );
}

6.1.21. functionp

#[test]
fn predicates_functionp() {
    use crate::axioms::predicates::maj_functionp;
    let mut state = MajState::new();
    let x = Maj::symbol(&mut state, "x");
    // Emulate closure definition on top-level
    // (lit closure nil (x) ((* x x)))
    let closure = maj_list!(
        Maj::lit(),
        Maj::closure(),
        Maj::nil(),
        maj_list!(x.clone()),
        maj_list!(maj_list!(
            Maj::symbol(&mut state, "*"),
            x.clone(), x)));
    // Emulate internal definitions of cons and +
    // (lit prim cons required 2)
    let cons = maj_list!(
        Maj::lit(),
        Maj::prim(),
        Maj::symbol(&mut state, "cons"),
        Maj::symbol(&mut state, "required"),
        Maj::integer(2));
    // (lit prim + variadic 0)
    let plus = maj_list!(
        Maj::lit(),
        Maj::prim(),
        Maj::symbol(&mut state, "+"),
        Maj::symbol(&mut state, "variadic"),
        Maj::integer(0));
    multi_boolean_test!(
        (maj_functionp(closure), true);
        (maj_functionp(plus), true);
        (maj_functionp(cons), true);
        (maj_functionp(maj_list!(
            Maj::lit(),
            Maj::symbol(&mut state, "blah"))),
         false);
    );
}

6.1.22. macrop

#[test]
fn predicates_macrop() {
    use crate::axioms::predicates::maj_macrop;
    let mut state = MajState::new();
    
    let x         = Maj::symbol(&mut state, "x");
    // Emulate definition of (mac (x) `(list ,x)) on top level
    // (lit macro (lit closure nil (x) ((quasiquote (list (unquote x))))))
    let themacro = maj_list!(
        Maj::lit(),
        Maj::symbol(&mut state, "macro"),
        maj_list!(
            Maj::lit(),
            Maj::closure(),
            Maj::nil(),
            maj_list!(x.clone()),
            maj_list!(
                maj_list!(
                    Maj::quasiquote(),
                    maj_list!(
                        Maj::symbol(&mut state, "list"),
                        maj_list!(
                            Maj::unquote(),
                            x.clone()))))));
    // Emulate internal definitions of cons and +
    // (lit prim cons required 2)
    let cons = maj_list!(
        Maj::lit(),
        Maj::prim(),
        Maj::symbol(&mut state, "cons"),
        Maj::symbol(&mut state, "required"),
        Maj::integer(2));
    // (lit prim + variadic 0)
    let plus = maj_list!(
        Maj::lit(),
        Maj::prim(),
        Maj::symbol(&mut state, "+"),
        Maj::symbol(&mut state, "variadic"),
        Maj::integer(0));
    multi_boolean_test!(
        (maj_macrop(themacro), true);
        (maj_macrop(maj_list!(Maj::lit(),
                              Maj::symbol(&mut state, "blah"))),
         false);
        (maj_macrop(cons), false);
        (maj_macrop(plus), false);
    );
}

6.1.23. errorp

#[test]
fn predicates_errorp() {
    use crate::axioms::predicates::maj_errorp;
    use crate::axioms::primitives::maj_err;
    multi_boolean_test!(
        (maj_errorp(maj_err(Maj::string("Some error"),
                            Maj::nil())),
         true);
        (maj_errorp(maj_err(Maj::string("Some other error"),
                            Maj::nil())),
         true);
        (maj_errorp(Maj::integer(2)), false);
    );
}

6.1.24. zerop

#[test]
fn predicates_zerop() {
    use crate::axioms::predicates::maj_zerop;
    let mut state = MajState::new();
    multi_boolean_test!(
        (maj_zerop(&mut state, Maj::nil(), Maj::float(0.0)), true);
        (maj_zerop(&mut state, Maj::nil(), Maj::fraction(0, 1)), true);
        (maj_zerop(&mut state, Maj::nil(), Maj::integer(0)), true);
        (maj_zerop(&mut state, Maj::nil(), Maj::integer(5)), false);
    );
    test_fail!(
        maj_zerop(&mut state, Maj::nil(), Maj::t()));
}

6.2. Outras funções primitivas

6.2.1. cons

#[test]
fn primitives_cons() {
    use crate::axioms::primitives::{ maj_cons, maj_err };
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_cons(Maj::symbol(&mut state, "a"),
                  Maj::symbol(&mut state, "b")),
         "(a . b)");
        (maj_cons(Maj::integer(1), Maj::integer(2)),
         "(1 . 2)");
    );
    multi_fail_test!(
        maj_cons(maj_err(Maj::string("Some error"),
                         Maj::nil()),
                 Maj::t());
    );
}

6.2.2. car

#[test]
fn primitives_car() {
    use crate::axioms::primitives::{
        maj_cons
    };
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_car(Maj::cons(Maj::symbol(&mut state, "a"),
                           Maj::symbol(&mut state, "b"))),
         "a");
        (maj_car(maj_cons(Maj::symbol(&mut state, "c"),
                          Maj::symbol(&mut state, "d"))),
         "c");
        (maj_car(Maj::nil()), "nil");
    );
}

6.2.3. cdr

#[test]
fn primitives_cdr() {
    use crate::axioms::primitives::{
        maj_cdr, maj_cons
    };
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_cdr(Maj::cons(Maj::symbol(&mut state, "a"),
                           Maj::symbol(&mut state, "b"))),
         "b");
        (maj_cdr(maj_cons(Maj::symbol(&mut state, "c"),
                          Maj::symbol(&mut state, "d"))),
         "d");
        (maj_cdr(Maj::nil()), "nil");
    );
}

6.2.4. copy

#[test]
fn primitives_copy() {
    use crate::axioms::{
        primitives::{
            maj_copy, maj_cons, maj_cdr
        },
        predicates::maj_id
    };
    let mut state = MajState::new();
    let x = maj_cons(Maj::symbol(&mut state, "a"),
                     Maj::symbol(&mut state, "b"));
    let y = maj_copy(x.clone());

    multi_test!(
        state;
        (x.clone(), "(a . b)");
        (y.clone(), "(a . b)");
    );
    multi_boolean_test!(
        (maj_id(x.clone(), y.clone()), false);
        (maj_id(maj_car(x.clone()), maj_car(y.clone())),
         true);
        (maj_id(maj_cdr(x.clone()), maj_cdr(y.clone())),
         true);
    );
    test_fail!(maj_copy(Maj::t()));
}

6.2.5. length

#[test]
fn primitives_length() {
    use crate::axioms::primitives::maj_length;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_length(maj_list!(Maj::integer(1),
                              Maj::integer(2),
                              Maj::integer(3),
                              Maj::integer(4))),
         "4");
        (maj_length(maj_list!(Maj::symbol(&mut state, "a"),
                              Maj::symbol(&mut state, "b"),
                              Maj::symbol(&mut state, "c"))),
         "3");
        (maj_length(Maj::nil()), "0");
        (maj_length(maj_dotted_list!(Maj::integer(1),
                                     Maj::integer(2),
                                     Maj::integer(3))),
         "2");
    );
    test_fail!(maj_length(Maj::symbol(&mut state, "a")));
}

6.2.6. depth

#[test]
fn primitives_depth() {
    use crate::axioms::primitives::maj_depth;
    let state = MajState::new();
    multi_test!(
        state;
        (maj_depth(Maj::nil()), "0");
        (maj_depth(maj_list!(Maj::nil())), "1");
        (maj_depth(maj_list!(maj_list!(Maj::integer(1)))),
         "2");
        (maj_depth(maj_list!(Maj::integer(1),
                             Maj::integer(2),
                             Maj::integer(3),
                             Maj::integer(4),
                             Maj::integer(5))),
         "5");
        (maj_depth(maj_list!(Maj::integer(1),
                             Maj::integer(2),
                             Maj::integer(3),
                             Maj::integer(4),
                             Maj::integer(5),
                             Maj::integer(6))),
         "6");
        (maj_depth(maj_dotted_list!(Maj::integer(1),
                                    Maj::integer(2),
                                    Maj::integer(3),
                                    Maj::integer(4),
                                    Maj::integer(5),
                                    Maj::integer(6))),
         "5");
    );
    test_fail!(maj_depth(Maj::integer(1)));
}

6.2.7. type

#[test]
fn primitives_type() {
    use crate::axioms::primitives::maj_type;
    let mut state = MajState::new();
    let a = Maj::symbol(&mut state, "a");
    let b = Maj::symbol(&mut state, "b");
    let c = Maj::symbol(&mut state, "c");
    let stdout = state.make_stream_stdout();
    multi_test!(
        state;
        (maj_type(&mut state, Maj::integer(1)),
         "integer");
        (maj_type(&mut state, Maj::float(2.0)),
         "float");
        (maj_type(&mut state, a.clone()),
         "symbol");
        (maj_type(&mut state, Maj::nil()),
         "symbol");
        (maj_type(&mut state, Maj::fraction(2, 3)),
         "fraction");
        (maj_type(&mut state, maj_list!(a, b, c)),
         "cons");
        (maj_type(&mut state, Maj::character('L')),
         "char");
        (maj_type(&mut state, stdout), "stream");
        (maj_type(&mut state, Maj::complex(Maj::integer(1),
                                           Maj::integer(5))),
         "complex");
        (maj_type(&mut state, Maj::vector_integer(vec![1, 2, 3])),
         "vector");
    );
}

6.2.8. intern

#[test]
fn primitives_intern() {
    use crate::axioms::primitives::maj_intern;
    let mut state = MajState::new();
    let a = Maj::symbol(&mut state, "a");
    multi_test!(
        state;
        (maj_intern(&mut state, Maj::string("blah")),
         "blah");
        (maj_intern(&mut state, Maj::string("foo")),
         "foo");
        (maj_intern(&mut state, Maj::string("")),
         "nil");
    );
    test_fail!(maj_intern(&mut state, a));
}

6.2.9. name

#[test]
fn primitives_name() {
    use crate::axioms::primitives::maj_name;
    let mut state = MajState::new();
    let foo = Maj::symbol(&mut state, "foo");
    let thing = Maj::symbol(&mut state, "thing");
    multi_test!(
        state;
        (maj_name(&state, Maj::t()), "\"t\"");
        (maj_name(&state, foo), "\"foo\"");
        (maj_name(&state, thing), "\"thing\"");
        (maj_name(&state, Maj::nil()), "\"nil\"");
    );
    test_fail!(maj_name(&state, Maj::string("Blah")));
}

6.2.10. TODO get-environment

#[test]
#[ignore]
fn primitives_get_environment() {
    use crate::core::environment::maj_env_push;
    use crate::axioms::primitives::maj_get_environment;
    let mut state = MajState::new();
    let x = Maj::symbol(&mut state, "x");
    let y = Maj::symbol(&mut state, "y");
    let plus = Maj::symbol(&mut state, "+");
    let sum_test = Maj::symbol(&mut state, "sum-test");
    let global = Maj::symbol(&mut state, "global");
    let lexical = Maj::symbol(&mut state, "lexical");
    let blah = Maj::symbol(&mut state, "blah");
    let mut env = Maj::nil();
    env = maj_env_push(env, x.clone(), Maj::integer(5));
    env = maj_env_push(env, y.clone(), Maj::integer(6));
    multi_regex_test!(
        state;
        (maj_get_environment(&mut state, global, env.clone()),
         RE_ENVIRONMENT);
        (maj_get_environment(&mut state, lexical.clone(), env.clone()),
         RE_ENVIRONMENT);
    );
    test_fail!(maj_get_environment(&mut state, blah, env.clone()));
    test_format!(
        state,
        {
            let lexenv = maj_get_environment(
                &mut state, lexical, env.clone());
            let newenv = maj_env_push(
                env.clone(),
                Maj::symbol(&mut state, "env"),
                lexenv);
            state.push(sum_test.clone(),
                       maj_list!(
                           maj_list!(
                               Maj::quasiquote(),
                               maj_list!(
                                   Maj::lit(),
                                   Maj::closure(),
                                   newenv.clone(),
                                   Maj::nil(),
                                   maj_list!(
                                       maj_list!(
                                           plus, x, y))))));
            sum_test.clone() // TODO: Replace with lookup
        }, "sum-test"); // TODO: Return a closure here and check
    // TODO: Add application (sum-test)
}

6.2.11. coin

#[test]
fn primitives_coin() {
    use crate::axioms::primitives::maj_coin;
    let state = MajState::new();
    // No better way to test this... just toss a coin
    // for a few times and check whether the output
    // is either t or nil.
    // In the future, we might want to test the distribution
    // of these values.
    let n = 100;
    for _ in 0..n {
        test_regex!(state, maj_coin(), r"^t|nil$");
    }
}

6.2.12. sys

#[test]
fn primitives_sys() {
    use crate::axioms::primitives::maj_sys;
    let state = MajState::new();
    multi_test!(
        state;
        (maj_sys(Maj::string("true"), Maj::nil()),  "0");
        (maj_sys(Maj::string("false"), Maj::nil()), "1");
    );
}

6.2.13. format

#[test]
fn primitives_format() {
    use crate::axioms::primitives::{
        maj_format_prim,
        maj_type
    };
    let mut state = MajState::new();
    let x = Maj::fraction(1, 2);
    let xtype = maj_type(&mut state, x.clone());
    multi_test!(
        state;
        (maj_format_prim(&state, Maj::string("Hello world"),
                         Maj::nil()),
         "\"Hello world\"");
        (maj_format_prim(&state, Maj::string("The number five: {}"),
                         maj_list!(Maj::integer(5))),
         "\"The number five: 5\"");
        (maj_format_prim(
            &state, Maj::string("The floating point {} is nice"),
            maj_list!(Maj::float(2.0))),
         "\"The floating point 2.0 is nice\"");
        (maj_format_prim(
            &state, Maj::string("The number {} has a subtype {}"),
            maj_list!(x, xtype)),
         "\"The number 1/2 has a subtype fraction\"");
    );
    multi_fail_test!(
        maj_format_prim(&state, Maj::string("Hello {}"),
                        Maj::nil());
        maj_format_prim(&state, Maj::string("Hello {"),
                        maj_list!(Maj::string("World")));
        maj_format_prim(&state, Maj::string("Hello }"),
                        maj_list!(Maj::string("World")));
    );
}

6.2.14. err

#[test]
fn primitives_err() {
    use crate::axioms::primitives::maj_err;
    // Should any error creation fail here, the
    // function will panic.
    multi_fail_test!(
        maj_err(Maj::string("{} is not a number"),
                maj_list!(Maj::t()));
        maj_err(
            Maj::string("This is an error, numbers are {} and {}"),
            maj_list!(Maj::integer(2), Maj::integer(3)));
    );
}

6.2.15. TODO warn

#[test]
#[ignore]
fn primitives_warn() {
    unimplemented!();
}

6.2.16. list

#[test]
fn primitives_list() {
    use crate::axioms::primitives::maj_list;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_list(maj_list!(Maj::integer(1),
                            Maj::integer(2),
                            Maj::integer(3))),
         "(1 2 3)");
        (maj_list(maj_list!(
            Maj::symbol(&mut state, "a"),
            Maj::integer(6),
            Maj::symbol(&mut state, "b"))),
         "(a 6 b)");
        (maj_list(Maj::nil()), "nil");
    );
}

6.2.17. append

#[test]
fn primitives_append() {
    use crate::axioms::primitives::maj_append;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_append(maj_list!(
            maj_list!(Maj::integer(1),
                      Maj::integer(2),
                      Maj::integer(3)),
            maj_list!(Maj::integer(4),
                      Maj::integer(5),
                      Maj::integer(6)))),
         "(1 2 3 4 5 6)");
        (maj_append(maj_list!(
            maj_list!(
                Maj::symbol(&mut state, "a"),
                maj_list!(
                    Maj::symbol(&mut state, "b"),
                    Maj::symbol(&mut state, "c")),
                Maj::symbol(&mut state, "d"),
                maj_list!(
                    Maj::symbol(&mut state, "e"))),
            maj_list!(
                Maj::symbol(&mut state, "f"),
                maj_list!(
                    Maj::symbol(&mut state, "g"),
                    Maj::symbol(&mut state, "h"))))),
         "(a (b c) d (e) f (g h))");
        (maj_append(maj_list!(
            maj_list!(
                Maj::symbol(&mut state, "a"),
                Maj::symbol(&mut state, "b"),
                Maj::symbol(&mut state, "c")),
            Maj::symbol(&mut state, "d"))),
         "(a b c . d)");
    );
}

6.2.18. last

#[test]
fn primitives_last() {
    use crate::axioms::primitives::maj_last;
    let mut state = MajState::new();
    let a = Maj::symbol(&mut state, "a");
    let b = Maj::symbol(&mut state, "b");
    let c = Maj::symbol(&mut state, "c");
    let d = Maj::symbol(&mut state, "d");
    multi_test!(
        state;
        (maj_last(maj_list!(a.clone(),
                            b.clone(),
                            c.clone(),
                            d.clone())),
         "(d)");
        (maj_last(maj_dotted_list!(
            a.clone(), b, c, d)),
         "(c . d)");
    );
    test_fail!(maj_last(a));
}

6.2.19. reverse

#[test]
fn primitives_reverse() {
    use crate::axioms::primitives::maj_reverse;
    let mut state = MajState::new();
    let a = Maj::symbol(&mut state, "a");
    let b = Maj::symbol(&mut state, "b");
    let c = Maj::symbol(&mut state, "c");
    let d = Maj::symbol(&mut state, "d");
    test_format!(
        state,
        maj_reverse(maj_list!(
            a.clone(), b.clone(), c.clone(), d.clone())),
        "(d c b a)");
    multi_fail_test!(
        maj_reverse(a.clone());
        maj_reverse(maj_dotted_list!(a, b, c, d));
    );
}

6.2.20. nthcdr

#[test]
fn primitives_nthcdr() {
    use crate::axioms::primitives::maj_nthcdr;
    let state = MajState::new();
    let list = maj_list!(Maj::integer(1),
                         Maj::integer(2),
                         Maj::integer(3),
                         Maj::integer(4));
    let dlist = maj_dotted_list!(Maj::integer(1),
                                 Maj::integer(2),
                                 Maj::integer(3),
                                 Maj::integer(4));
    multi_test!(
        state;
        (maj_nthcdr(Maj::integer(0), list.clone()),
         "(1 2 3 4)");
        (maj_nthcdr(Maj::integer(1), list.clone()),
         "(2 3 4)");
        (maj_nthcdr(Maj::integer(3), list.clone()),
         "(4)");
    );
    multi_fail_test!(
        maj_nthcdr(Maj::integer(3), dlist);
        maj_nthcdr(Maj::integer(-1), list.clone());
        maj_nthcdr(Maj::fraction(3, 4), list.clone());
    );
    multi_test!(
        state;
        (maj_nthcdr(Maj::integer(4), list.clone()),
         "nil");
        (maj_nthcdr(Maj::integer(5), list), "nil");
        (maj_nthcdr(Maj::integer(50), Maj::nil()), "nil");
    );
}

6.2.21. nth

#[test]
fn primitives_nth() {
    use crate::axioms::primitives::maj_nth;
    let state = MajState::new();
    let list = maj_list!(Maj::integer(1),
                         Maj::integer(2),
                         Maj::integer(3),
                         Maj::integer(4));
    let dlist = maj_dotted_list!(Maj::integer(1),
                                 Maj::integer(2),
                                 Maj::integer(3),
                                 Maj::integer(4));
    multi_test!(
        state;
        (maj_nth(Maj::integer(0), list.clone()),
         "1");
        (maj_nth(Maj::integer(3), list.clone()),
         "4");
    );
    multi_fail_test!(
        maj_nth(Maj::integer(3), dlist);
        maj_nth(Maj::integer(-1), list.clone());
        maj_nth(Maj::fraction(3, 4), list.clone());
    );
    multi_test!(
        state;
        (maj_nth(Maj::integer(4), list.clone()),
         "nil");
        (maj_nth(Maj::integer(5), list), "nil");
        (maj_nth(Maj::integer(50), Maj::nil()), "nil");
    );
}

6.2.22. TODO macroexpand-1

#[test]
#[ignore]
fn primitives_macroexpand_1() {
    unimplemented!();
}

6.2.23. TODO macroexpand

#[test]
#[ignore]
fn primitives_macroexpand() {
    unimplemented!();
}

6.2.24. not

#[test]
fn primitives_not() {
    use crate::axioms::primitives::maj_not;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_not(Maj::integer(1)), "nil");
        (maj_not(maj_list!(Maj::symbol(&mut state, "a"),
                           Maj::symbol(&mut state, "b"),
                           Maj::symbol(&mut state, "c"))),
         "nil");
        (maj_not(Maj::t()), "nil");
        (maj_not(Maj::nil()), "t");
    );
}

6.2.25. gensym

#[test]
fn primitives_gensym() {
    use crate::axioms::primitives::maj_gensym;
    // Generate a few symbols and that's it.
    let mut state = MajState::new();
    let n = 100;
    for _ in 0..n {
        test_regex!(state, maj_gensym(&mut state), r"^:G[0-9]*$");
    }
}

6.3. Funções para vetores

6.3.1. vector e vec-type

#[test]
fn primitives_vector_vec_type() {
    use crate::axioms::primitives::{
        maj_vector,
        maj_vec_type
    };
    let mut state = MajState::new();
    let v1 = maj_vector(&mut state, Maj::nil());
    let v2 = maj_vector(&mut state, maj_list!(Maj::integer(1),
                                              Maj::integer(2),
                                              Maj::integer(3),
                                              Maj::integer(4)));
    let v3 = maj_vector(&mut state, maj_list!(Maj::float(1.0),
                                              Maj::float(3.0),
                                              Maj::float(2.5)));
    let v4 = maj_vector(&mut state, maj_list!(Maj::character('H'),
                                              Maj::character('e'),
                                              Maj::character('l'),
                                              Maj::character('l'),
                                              Maj::character('o')));
    let blah = Maj::symbol(&mut state, "blah");
    let v5 = maj_vector(&mut state, maj_list!(Maj::float(1.0),
                                              Maj::integer(3),
                                              Maj::fraction(2, 5),
                                              Maj::complex(
                                                  Maj::integer(2),
                                                  Maj::integer(6)),
                                              blah));
    multi_test!(
        state;
        (v1.clone(), "[]");
        (maj_vec_type(&mut state, v1), "any");
        (v2.clone(), "[1 2 3 4]");
        (maj_vec_type(&mut state, v2), "integer");
        (v3.clone(), "[1.0 3.0 2.5]");
        (maj_vec_type(&mut state, v3), "float");
        (v4.clone(), "\"Hello\"");
        (maj_vec_type(&mut state, v4), "char");
        (v5.clone(), "[1.0 3 2/5 2J6 blah]");
        (maj_vec_type(&mut state, v5), "any");
    );
}

6.3.2. vec-coerce

#[test]
fn primitive_vec_coerce() {
    use crate::axioms::primitives::{
        maj_vector,
        maj_vec_push,
        maj_vec_type,
        maj_vec_coerce
    };
    let mut state = MajState::new();
    let integer = Maj::symbol(&mut state, "integer");
    let any = Maj::symbol(&mut state, "any");
    let v = maj_vector(&mut state, Maj::nil());
    test_format!(state, maj_vec_type(&mut state, v.clone()), "any");
    
    let _ = maj_vec_push(&mut state, v.clone(), Maj::integer(2));
    let _ = maj_vec_push(&mut state, v.clone(), Maj::integer(3));
    test_format!(state, maj_vec_type(&mut state, v.clone()), "any");
    
    let v2 = maj_vec_coerce(&mut state, integer, v);
    test_format!(state, maj_vec_type(&mut state, v2), "integer");

    test_format!(state, maj_vec_coerce(&mut state, any, Maj::string("Hello")),
                 "[#\\H #\\e #\\l #\\l #\\o]");
}

6.3.3. vec-push

#[test]
fn primitives_vec_push() {
    use crate::axioms::primitives::maj_vec_push;
    let mut state = MajState::new();
    
    let v = Maj::vector_integer(vec![]);
    multi_test!(
        state;
        (v.clone(), "[]");
        (maj_vec_push(&mut state, Maj::integer(5), v.clone()), "[5]");
        (maj_vec_push(&mut state, Maj::integer(6), v.clone()), "[5 6]");
    );

    let a = Maj::symbol(&mut state, "a");
    test_fail!(maj_vec_push(&mut state, a.clone(), v.clone()));

    let myvec = Maj::vector_any(vec![]);
    let elements = vec![
        Maj::integer(5), Maj::integer(6), a,
        Maj::fraction(2, 3)
    ];
    for elt in &elements {
        test_dont_fail!(
            maj_vec_push(&mut state, elt.clone(), myvec.clone()));
    }
    test_format!(state, myvec, "[5 6 a 2/3]");
}

6.3.4. vec-set

#[test]
fn primitives_vec_set() {
    use crate::axioms::primitives::maj_vec_set;
    let state = MajState::new();
    let v = Maj::vector_integer(vec![1, 2, 3, 4, 5]);
    multi_test!(
        state;
        (maj_vec_set(Maj::integer(2), Maj::integer(50), v.clone()),
         "[1 2 50 4 5]");
        (maj_vec_set(Maj::integer(4), Maj::integer(10), v.clone()),
         "[1 2 50 4 10]");
    );
    test_fail!(
        maj_vec_set(Maj::integer(5), Maj::integer(90), v.clone()));
}

6.3.5. vec-pop

#[test]
fn primitives_vec_pop() {
    use crate::axioms::primitives::maj_vec_pop;
    let state = MajState::new();
    let v = Maj::vector_integer(vec![1, 2, 3]);
    multi_test!(
        state;
        (v.clone(), "[1 2 3]");
        (maj_vec_pop(v.clone()), "3");
        (maj_vec_pop(v.clone()), "2");
        (maj_vec_pop(v.clone()), "1");
        (maj_vec_pop(v.clone()), "nil");
        (v, "[]");
    );
    test_fail!(maj_vec_pop(Maj::fraction(2, 3)));
}

6.3.6. vec-deq

#[test]
fn primitives_vec_deq() {
    use crate::axioms::primitives::maj_vec_deq;
    let state = MajState::new();
    let v = Maj::vector_integer(vec![0, 1, 2]);
    multi_test!(
        state;
        (v.clone(), "[0 1 2]");
        (maj_vec_deq(v.clone()), "0");
        (maj_vec_deq(v.clone()), "1");
        (maj_vec_deq(v.clone()), "2");
        (maj_vec_deq(v.clone()), "nil");
        (v, "[]");
    );
    test_fail!(maj_vec_deq(Maj::fraction(2, 3)));
}

6.3.7. vec-length

#[test]
fn primitives_vec_length() {
    use crate::axioms::primitives::{
        maj_vec_length,
        maj_iota,
        maj_reverse,
        maj_vector
    };
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_vec_length(Maj::vector_any(vec![])), "0");
        (maj_vec_length(Maj::vector_integer(vec![1, 2, 3, 4])), "4");
        ({
            let iota50 = maj_iota(Maj::integer(50));
            let reviota = maj_reverse(iota50);
            let v = maj_vector(&mut state, reviota);
            maj_vec_length(v)
        }, "50");
    );
    test_fail!(maj_vec_length(state.make_stream_stdin()));
}

6.3.8. vec-at

#[test]
fn primitives_vec_at() {
    use crate::axioms::primitives::maj_vec_at;
    let state = MajState::new();
    multi_test!(
        state;
        (maj_vec_at(Maj::integer(1),
                    Maj::vector_integer(vec![1, 2, 3])),
         "2");
        (maj_vec_at(Maj::integer(0), Maj::string("Hello")),
         "#\\H");
    );
    multi_fail_test!(
        maj_vec_at(Maj::integer(5), Maj::string("Hello"));
        maj_vec_at(Maj::integer(5),
                   maj_list!(Maj::integer(1),
                             Maj::integer(2),
                             Maj::integer(3)));
    );
}

6.3.9. vec-remove

#[test]
fn primitives_vec_remove() {
    use crate::axioms::primitives::maj_vec_remove;
    let vec = Maj::vector_integer(vec![1, 2, 3, 4, 5]);
    let state = MajState::new();
    multi_test!(
        state;
        (maj_vec_remove(Maj::integer(2), vec.clone()), "3");
        (maj_vec_remove(Maj::integer(2), vec.clone()), "4");
        (vec.clone(), "[1 2 5]");
        (maj_vec_remove(Maj::integer(2), vec.clone()), "5");
    );
    multi_fail_test!(
        maj_vec_remove(Maj::integer(2), vec);
        maj_vec_remove(Maj::integer(0), Maj::integer(2));
    );
}

6.3.10. vec-insert

#[test]
fn primitives_vec_insert() {
    use crate::axioms::primitives::maj_vec_insert;
    let mut state = MajState::new();
    let v = Maj::vector_integer(vec![1, 2, 3]);
    
    multi_test!(
        state;
        (v.clone(), "[1 2 3]");
        (maj_vec_insert(
            &mut state, Maj::integer(3), Maj::integer(5), v.clone()),
         "[1 2 3 5]");
        (maj_vec_insert(
            &mut state, Maj::integer(0), Maj::integer(5), v.clone()),
         "[5 1 2 3 5]");
        (maj_vec_insert(
            &mut state, Maj::integer(0), Maj::integer(5), v.clone()),
         "[5 5 1 2 3 5]");
        (maj_vec_insert(
            &mut state, Maj::integer(0), Maj::integer(5), v.clone()),
         "[5 5 5 1 2 3 5]");
        (maj_vec_insert(
            &mut state, Maj::integer(1), Maj::integer(7), v.clone()),
         "[5 7 5 5 1 2 3 5]");
        (maj_vec_insert(
            &mut state, Maj::integer(3), Maj::integer(8), v.clone()),
         "[5 7 5 8 5 1 2 3 5]");
    );

    let a = Maj::symbol(&mut state, "a");
    multi_fail_test!(
        maj_vec_insert(&mut state,
                       Maj::integer(20),
                       Maj::integer(8),
                       Maj::vector_integer(vec![1, 2, 3]));
        maj_vec_insert(&mut state,
                       Maj::integer(2),
                       a,
                       Maj::vector_integer(vec![1, 2, 3]));
    );
}

6.4. Funções numéricas

6.4.1. number-coerce

#[test]
fn primitives_number_coerce() {
    use crate::axioms::primitives::maj_number_coerce;
    let mut state = MajState::new();

    let float = Maj::symbol(&mut state, "float");
    let integer = Maj::symbol(&mut state, "integer");

    multi_test!(
        state;
        (maj_number_coerce(
            &mut state, float.clone(), Maj::integer(1)), "1.0");
        (maj_number_coerce(
            &mut state, integer.clone(), Maj::complex(
                Maj::integer(1), Maj::integer(3))), "1");
        (maj_number_coerce(
            &mut state, integer.clone(), Maj::float(2.3)), "2");
        (maj_number_coerce(
            &mut state, float, Maj::fraction(2, 5)), "0.4");
    );
    test_fail!(maj_number_coerce(&mut state, integer, Maj::t()));
}

6.4.2. real-part e imag-part

#[test]
fn primitives_real_part_imag_part() {
    use crate::axioms::primitives::{
        maj_real_part,
        maj_imag_part
    };
    let state = MajState::new();
    multi_test!(
        state;
        (maj_real_part(Maj::complex(Maj::integer(2),
                                    Maj::integer(5))), "2");
        (maj_real_part(Maj::complex(Maj::fraction(3, 2),
                                    Maj::integer(7))), "3/2");
        (maj_imag_part(Maj::complex(Maj::integer(2),
                                    Maj::integer(5))), "5");
        (maj_imag_part(Maj::complex(Maj::integer(7),
                                    Maj::fraction(3, 2))), "3/2");
    );
    multi_fail_test!(
        maj_real_part(Maj::fraction(1, 2));
        maj_real_part(Maj::nil());
        maj_imag_part(Maj::fraction(1, 2));
        maj_imag_part(Maj::nil());
    );
}

6.4.3. numer e denom

#[test]
fn primitives_numer_denom() {
    use crate::axioms::primitives::{
        maj_numer,
        maj_denom
    };
    let state = MajState::new();
    multi_test!(
        state;
        (maj_numer(Maj::fraction(1, 2)), "1");
        (maj_numer(Maj::fraction(3, 2)), "3");
        (maj_denom(Maj::fraction(1, 2)), "2");
        (maj_denom(Maj::fraction(3, 2)), "2");
    );
    multi_fail_test!(
        maj_numer(Maj::integer(2));
        maj_numer(Maj::nil());
        maj_denom(Maj::integer(2));
        maj_denom(Maj::nil());
    );
}

6.4.4. richest-number-type

#[test]
fn primitives_richest_number_type() {
    use crate::axioms::primitives::maj_richest_number_type;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_richest_number_type(
            &mut state, Maj::integer(2), Maj::float(2.0)),
         "float");
        (maj_richest_number_type(
            &mut state, Maj::integer(2), Maj::fraction(2, 3)),
         "fraction");
        (maj_richest_number_type(
            &mut state, Maj::complex(Maj::integer(2),
                                     Maj::integer(3)),
            Maj::integer(9)),
         "complex");
        (maj_richest_number_type(
            &mut state, Maj::complex(Maj::fraction(2, 3),
                                     Maj::integer(-9)),
            Maj::float(2.0)),
         "complex");
    );
    test_fail!(maj_richest_number_type(
        &mut state, Maj::complex(Maj::fraction(2, 3),
                                 Maj::integer(-9)),
        Maj::t()));
}

6.4.5. rich-number-coerce

#[test]
fn primitives_rich_number_coerce() {
    use crate::axioms::primitives::maj_rich_number_coerce;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_rich_number_coerce(&mut state,
                                Maj::complex(Maj::integer(2),
                                             Maj::integer(3)),
                                Maj::fraction(2, 5)),
         "(2J3 2/5J0.0)");
        (maj_rich_number_coerce(&mut state,
                                Maj::float(1.5),
                                Maj::fraction(5, 2)),
         "(3/2 5/2)");
    );
    test_fail!(maj_rich_number_coerce(
        &mut state, Maj::integer(2), Maj::t()));
}

6.4.6. + (arithmetic plus)

#[test]
fn primitives_arithm_plus() {
    use crate::axioms::primitives::maj_arithm_plus;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_arithm_plus(&mut state, Maj::nil(), Maj::nil()), "1");
        (maj_arithm_plus(
            &mut state, Maj::nil(),
            maj_list!(Maj::complex(Maj::integer(2),
                                   Maj::integer(3)))), "2J-3");
        (maj_arithm_plus(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(1),
                      Maj::integer(2),
                      Maj::integer(3))),
         "6");
    );
    let a = Maj::symbol(&mut state, "a");
    test_fail!(maj_arithm_plus(
        &mut state, Maj::nil(), maj_list!(a)));
}

6.4.7. - (arithmetic minus)

#[test]
fn primitives_arithm_minus() {
    use crate::axioms::primitives::maj_arithm_minus;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_arithm_minus(&mut state, Maj::nil(), Maj::nil()), "0");
        (maj_arithm_minus(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(1))), "-1");
        (maj_arithm_minus(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(1),
                      Maj::integer(2),
                      Maj::integer(3))),
         "-4");
    );
    let a = Maj::symbol(&mut state, "a");
    test_fail!(maj_arithm_minus(
        &mut state, Maj::nil(), maj_list!(a)));
}

6.4.8. * (arithmetic times)

#[test]
fn primitives_arithm_times() {
    use crate::axioms::primitives::maj_arithm_times;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_arithm_times(&mut state, Maj::nil(), Maj::nil()), "1");
        (maj_arithm_times(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(-50))), "-1");
        (maj_arithm_times(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(1),
                      Maj::integer(2),
                      Maj::integer(3))),
         "6");
        (maj_arithm_times(
            &mut state, Maj::nil(),
            maj_list!(Maj::complex(Maj::integer(3),
                                   Maj::integer(2)),
                      Maj::complex(Maj::integer(1),
                                   Maj::integer(7)))),
         "-11J23.0");
    );
    let a = Maj::symbol(&mut state, "a");
    test_fail!(maj_arithm_times(
        &mut state, Maj::nil(), maj_list!(a)));
}

6.4.9. / (arithmetic divide)

#[test]
fn primitives_arithm_divide() {
    use crate::axioms::primitives::maj_arithm_divide;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_arithm_divide(&mut state, Maj::nil(), Maj::nil()), "1");
        (maj_arithm_divide(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(3))), "1/3");
        (maj_arithm_divide(
            &mut state, Maj::nil(),
            maj_list!(Maj::float(0.5))), "2");
        (maj_arithm_divide(
            &mut state, Maj::nil(),
            maj_list!(Maj::fraction(1, 2),
                      Maj::complex(
                          Maj::integer(0),
                          Maj::integer(1)))),
         "0.0J-1/2");
        (maj_arithm_divide(
            &mut state, Maj::nil(),
            maj_list!(Maj::fraction(1, 2))), "2");
        (maj_arithm_divide(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(3),
                      Maj::integer(4))),
         "3/4");
    );
    let a = Maj::symbol(&mut state, "a");
    multi_fail_test!(
        maj_arithm_divide(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(2),
                      Maj::integer(3),
                      Maj::integer(0)));
        maj_arithm_divide(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(0)));
        maj_arithm_divide(
            &mut state, Maj::nil(),
            maj_list!(Maj::integer(2), a));
    );
}

6.4.10. iota

#[test]
fn primitives_iota() {
    use crate::axioms::primitives::maj_iota;
    let mut state = MajState::new();
    multi_test!(
        state;
        (maj_iota(Maj::integer(0)), "nil");
        (maj_iota(Maj::integer(5)), "(0 1 2 3 4)");
    );
    multi_fail_test!(
        maj_iota(Maj::integer(-1));
        maj_iota(Maj::fraction(2, 3));
        maj_iota(Maj::symbol(&mut state, "a"));
    );
}

6.5. Funções de comparações

6.5.1. = (numeric equality)

#[test]
fn primitives_arithm_equal() {
    use crate::axioms::primitives::maj_arithm_eq;
    use crate::core::environment::maj_env_push;
    
    let mut state = MajState::new();
    let test_env = maj_env_push(Maj::nil(),
                                Maj::symbol(&mut state, "*ulps*"),
                                Maj::integer(3));
    
    multi_boolean_test!(
        (maj_arithm_eq(&mut state, test_env.clone(),
                       Maj::fraction(2, 1), Maj::integer(2),
                       Maj::nil()), true);
        (maj_arithm_eq(&mut state, test_env.clone(),
                       Maj::integer(1), Maj::integer(1),
                       Maj::nil()), true);
        (maj_arithm_eq(&mut state, test_env.clone(),
                       Maj::complex(Maj::integer(2),
                                    Maj::integer(3)),
                       Maj::fraction(2, 3),
                       Maj::nil()), false);
        (maj_arithm_eq(&mut state, test_env.clone(),
                       Maj::float(2.0), Maj::integer(2),
                       Maj::nil()), true);
        (maj_arithm_eq(&mut state, test_env.clone(),
                       Maj::integer(2), Maj::fraction(4, 2),
                       maj_list!(
                           Maj::integer(2),
                           Maj::integer(3),
                           Maj::integer(5))), false);
    );
    test_fail!(maj_arithm_eq(&mut state, test_env,
                             Maj::t(), Maj::fraction(2, 3),
                             Maj::nil()));
}

6.5.2. float= (floating point equality)

#[test]
fn primitives_arithm_float_eq() {
    use crate::axioms::primitives::{
        maj_arithm_floateq,
        maj_arithm_times,
        maj_arithm_plus
    };
    use crate::core::environment::maj_env_push;
    
    let mut state = MajState::new();
    let test_env = maj_env_push(Maj::nil(),
                                Maj::symbol(&mut state, "*ulps*"),
                                Maj::integer(3));

    
    let f = Maj::float(0.1);
    let mut sum = Maj::float(0.0);

    // (repeat 10 (set sum (+ sum f)))
    for _ in 0..10 {
        sum = maj_arithm_plus(&mut state, test_env.clone(),
                              maj_list!(sum.clone(), f.clone()));
    }

    // (def product (* f 10))
    let product =
        maj_arithm_times(&mut state, test_env.clone(),
                         maj_list!(f.clone(), Maj::float(10.0)));
    
    test_boolean!(maj_arithm_floateq(&mut state, test_env.clone(),
                                     sum, product),
                  true);
}

6.5.3. > (greater than)

#[test]
fn primitives_arithm_greater() {
    use crate::axioms::primitives::maj_arithm_greater;
    let mut state = MajState::new();

    let one = Maj::integer(1);
    
    multi_boolean_test!(
        (maj_arithm_greater(&mut state,
                            Maj::fraction(5, 2), Maj::integer(2),
                            Maj::nil()), true);
        (maj_arithm_greater(&mut state,
                            Maj::integer(1), one, Maj::nil()),
         false);
        (maj_arithm_greater(&mut state,
                            Maj::integer(10), Maj::integer(5),
                            maj_list!(Maj::integer(3), Maj::integer(1))),
         true);
        (maj_arithm_greater(&mut state,
                            Maj::integer(1), Maj::integer(2),
                            maj_list!(Maj::integer(3))), false);
    );

    multi_fail_test!(
        maj_arithm_greater(&mut state, Maj::complex(Maj::integer(2),
                                                    Maj::integer(3)),
                           Maj::fraction(2, 3), Maj::nil());
        maj_arithm_greater(&mut state, Maj::integer(3), Maj::t(),
                           Maj::nil());
    );
}

6.5.4. < (lesser than)

#[test]
fn primitives_arithm_lesser() {
    use crate::axioms::primitives::maj_arithm_lesser;
    let mut state = MajState::new();

    let one = Maj::integer(1);
    
    multi_boolean_test!(
        (maj_arithm_lesser(&mut state,
                           Maj::integer(2), Maj::fraction(5, 2),
                           Maj::nil()), true);
        (maj_arithm_lesser(&mut state,
                            Maj::integer(1), one, Maj::nil()),
         false);
        (maj_arithm_lesser(&mut state,
                           Maj::integer(1), Maj::integer(3),
                           maj_list!(Maj::integer(5),
                                     Maj::integer(10))),
         true);
        (maj_arithm_lesser(&mut state,
                           Maj::integer(3), Maj::integer(2),
                           maj_list!(Maj::integer(1))), false);
    );

    multi_fail_test!(
        maj_arithm_lesser(&mut state, Maj::complex(Maj::integer(2),
                                                   Maj::integer(3)),
                          Maj::fraction(2, 3), Maj::nil());
        maj_arithm_lesser(&mut state, Maj::integer(3), Maj::t(),
                          Maj::nil());
    );
}

6.5.5. >= (greater or equal)

#[test]
fn primitives_arithm_geq() {
    use crate::axioms::primitives::maj_arithm_geq;
    use crate::core::environment::maj_env_push;
    let mut state = MajState::new();
    let env = maj_env_push(Maj::nil(),
                           Maj::symbol(&mut state, "*ulps*"),
                           Maj::integer(3));
    
    multi_boolean_test!(
        (maj_arithm_geq(&mut state, env.clone(),
                        Maj::fraction(5, 2), Maj::integer(2),
                        Maj::nil()), true);
        (maj_arithm_geq(&mut state, env.clone(),
                        Maj::float(2.0), Maj::integer(2),
                        Maj::nil()), true);
        (maj_arithm_geq(&mut state, env.clone(),
                        Maj::integer(1), Maj::integer(2),
                        maj_list!(Maj::integer(3))), false);
        (maj_arithm_geq(&mut state, env.clone(),
                        Maj::integer(3), Maj::integer(3),
                        maj_list!(Maj::integer(1))), true);
    );
    multi_fail_test!(
        maj_arithm_geq(&mut state, env.clone(),
                       Maj::complex(Maj::integer(5),
                                    Maj::integer(9)),
                       Maj::complex(Maj::integer(6),
                                    Maj::integer(9)),
                       Maj::nil());
        maj_arithm_geq(&mut state, env,
                       Maj::integer(3), Maj::t(), Maj::nil());
    );
}

6.5.6. <= (lesser or equal)

#[test]
fn primitives_arithm_leq() {
    use crate::axioms::primitives::maj_arithm_leq;
    use crate::core::environment::maj_env_push;
    let mut state = MajState::new();
    let env = maj_env_push(Maj::nil(),
                           Maj::symbol(&mut state, "*ulps*"),
                           Maj::integer(3));
    
    multi_boolean_test!(
        (maj_arithm_leq(&mut state, env.clone(),
                        Maj::fraction(5, 2), Maj::integer(2),
                        Maj::nil()), false);
        (maj_arithm_leq(&mut state, env.clone(),
                        Maj::float(2.0), Maj::integer(2),
                        Maj::nil()), true);
        (maj_arithm_leq(&mut state, env.clone(),
                        Maj::integer(1), Maj::integer(2),
                        maj_list!(Maj::integer(3))), true);
        (maj_arithm_leq(&mut state, env.clone(),
                        Maj::integer(3), Maj::integer(3),
                        maj_list!(Maj::integer(1))), false);
    );
    multi_fail_test!(
        maj_arithm_leq(&mut state, env.clone(),
                       Maj::complex(Maj::integer(5),
                                    Maj::integer(9)),
                       Maj::complex(Maj::integer(6),
                                    Maj::integer(9)),
                       Maj::nil());
        maj_arithm_leq(&mut state, env,
                       Maj::integer(3), Maj::t(), Maj::nil());
    );
}

6.6. Funções de streams

6.6.1. open-stream e close-stream

#[test]
fn primitives_open_stream_close_stream() {
    use crate::axioms::primitives::{
        maj_open_stream,
        maj_close_stream
    };
    let mut state = MajState::new();
    let out_sym = Maj::symbol(&mut state, "out");
    let outstream;
    
    multi_regex_test!(
        state;
        ({
            outstream =
                maj_open_stream(&mut state, out_sym.clone(),
                                Maj::string("test-streams-out.txt"));
            outstream.clone()
        }, RE_OUT_STREAM);
    );
    multi_boolean_test!(
        (maj_close_stream(&mut state, outstream.clone()), true);
        (maj_close_stream(&mut state, outstream.clone()), false);
    );
    multi_fail_test!(
        maj_open_stream(&mut state, out_sym.clone(), Maj::string("/"));
        maj_close_stream(&mut state, out_sym.clone());
    );
}

6.6.2. stat

#[test]
fn primitives_stat() {
    use crate::axioms::primitives::{
        maj_stat,
        maj_open_stream,
        maj_close_stream
    };
    let mut state = MajState::new();
    let outsym = Maj::symbol(&mut state, "out");
    let outstream =
        maj_open_stream(&mut state, outsym,
                        Maj::string("test-streams-out.txt"));

    if maj_errorp(outstream.clone()).to_bool() {
        panic!("Cannot open output stream");
    }
    
    multi_test!(
        state;
        (maj_stat(&mut state, outstream.clone()), "open");
        ({
            maj_close_stream(&mut state, outstream.clone());
            maj_stat(&mut state, outstream)
        }, "closed");
    );
    test_fail!(maj_stat(&mut state, Maj::integer(3)));
}

6.6.3. write

#[test]
fn primitives_write() {
    use crate::axioms::primitives::maj_write;
    let mut state = MajState::new();
    let outstream = state.make_stream_stdout();
    let instream  = state.make_stream_stdin();
    let x = Maj::symbol(&mut state, "x");
    let closure =
        // (lit closure nil (x) ((* x x)))
        maj_list!(Maj::lit(), Maj::closure(), Maj::nil(),
                  maj_list!(x.clone()),
                  maj_list!(
                      maj_list!(Maj::symbol(&mut state, "*"),
                                x.clone(), x)));
    test_boolean!(maj_write(&mut state, closure.clone(), outstream),
                  false);
    multi_fail_test!(
        maj_write(&mut state, closure.clone(), instream);
        maj_write(&mut state, closure.clone(), Maj::integer(5));
    );
}

6.6.4. TODO read

#[test]
#[ignore]
fn primitives_read() {
    unimplemented!();
}

6.6.5. read-char e peek-char

#[test]
#[ignore]
fn primitives_read_char_peek_char() {
    use crate::core::types::MajStreamDirection;
    use crate::axioms::primitives::{
        maj_peek_char,
        maj_read_char,
        maj_close_stream
    };
    use crate::axioms::predicates::maj_eq;
    let mut state = MajState::new();
    let eof = Maj::symbol(&mut state, "eof");
    let istream = Maj::stream(
        &mut state,
        "test-streams-in.txt",
        MajStreamDirection::In).unwrap();
    let stdout = state.make_stream_stdout();

    multi_test!(
        state;
        (maj_peek_char(&mut state, istream.clone()), "#\\H");
        (maj_peek_char(&mut state, istream.clone()), "#\\H");
        (maj_read_char(&mut state, istream.clone()), "#\\H");
        (maj_read_char(&mut state, istream.clone()), "#\\e");
        ({
            while !maj_eq(maj_read_char(&mut state, istream.clone()),
                          eof.clone()).to_bool() {}
            maj_peek_char(&mut state, istream.clone())
        }, "eof");
        (maj_read_char(&mut state, istream.clone()), "eof");
    );

    test_boolean!(maj_close_stream(&mut state, istream.clone()),
                  true);
    
    multi_fail_test!(
        maj_read_char(&mut state, stdout.clone());
        maj_peek_char(&mut state, stdout);
        maj_read_char(&mut state, istream.clone());
        maj_peek_char(&mut state, istream.clone());
        maj_read_char(&mut state, Maj::fraction(2, 3));
        maj_peek_char(&mut state, Maj::fraction(2, 3));
    );
}

6.6.6. write-char e write-string

#[test]
fn primitives_write_char_write_string() {
    use crate::axioms::primitives::{
        maj_write_char,
        maj_write_string,
        maj_close_stream
    };
    use crate::core::types::MajStreamDirection;
    let mut state = MajState::new();
    let ostream = Maj::stream(
        &mut state,
        "test-streams-out.txt",
        MajStreamDirection::Out).unwrap();
    let stdin  = state.make_stream_stdin();
    let stdout = state.make_stream_stdout();

    multi_test!(
        state;
        (maj_write_char(
            &mut state, Maj::character('a'), ostream.clone()),
         "nil");
        (maj_write_string(
            &mut state, Maj::string("Hello"), ostream.clone()),
         "nil");
    );

    test_boolean!(
        maj_close_stream(&mut state, ostream.clone()), true);
    
    multi_fail_test!(
        maj_write_char(
            &mut state, Maj::character('a'), ostream.clone());
        maj_write_string(
            &mut state, Maj::string("Hello"), ostream.clone());
        maj_write_char(
            &mut state, Maj::character('a'), stdin.clone());
        maj_write_string(
            &mut state, Maj::string("Hello"), stdin.clone());
        maj_write_char(
            &mut state, Maj::character('a'), Maj::integer(5));
        maj_write_string(
            &mut state, Maj::string("Hello"), Maj::integer(5));
        maj_write_char(
            &mut state, Maj::integer(5), stdout.clone());
        maj_write_string(
            &mut state, Maj::integer(5), stdout.clone());
    );
}

7. Ligações e Contextos

7.1. Ligações globais

#[test]
fn environments_global_bindings() {
    // use crate::axioms::MajRawSym;
    // use crate::axioms::utils::sym_from_raw;
    let mut state = MajState::new();
    let my_value = Maj::symbol(&mut state, "my-value");

    multi_eval_ast_test!(
        state;
        // (def my-value 5)
        (maj_list!(Maj::symbol(&mut state, "def"),
                   my_value.clone(),
                   Maj::integer(5)),
         Maj::nil(),
         "my-value");
        // my-value
        (my_value.clone(), Maj::nil(), "5");
    );
}

7.2. Ligações léxicas/estáticas

#[test]
fn environments_lexical_bindings() {
    use crate::axioms::MajRawSym;
    use crate::axioms::utils::sym_from_raw;
    let mut state = MajState::new();
    let f = Maj::symbol(&mut state, "f");
    let def = Maj::symbol(&mut state, "def");
    let x = Maj::symbol(&mut state, "x");
    let g = Maj::symbol(&mut state, "g");
    let y = Maj::symbol(&mut state, "y");
    let plussym = Maj::symbol(&mut state, "+");
    let fnsym = sym_from_raw(MajRawSym::Fn);
    multi_eval_ast_test!(
        state;
        // (def f (fn (x) (+ x 1)))
        (maj_list!(def.clone(), f.clone(),
                   maj_list!(fnsym.clone(),
                             maj_list!(x.clone()),
                             maj_list!(
                                 plussym.clone(),
                                 x.clone(),
                                 Maj::integer(1)))),
         Maj::nil(),
         "f");
        // (f 5)
        (maj_list!(f.clone(), Maj::integer(5)),
         Maj::nil(),
         "6");
        // (def g ((fn (x) (fn (y) (+ x y))) 9))
        (maj_list!(def.clone(), g.clone(),
                   maj_list!(
                       maj_list!(fnsym.clone(),
                                 maj_list!(x.clone()),
                                 maj_list!(fnsym.clone(),
                                           maj_list!(y.clone()),
                                           maj_list!(
                                               plussym.clone(),
                                               x.clone(),
                                               y.clone()))),
                       Maj::integer(9))),
         Maj::nil(),
         "g");
        // (g 4)
        (maj_list!(g.clone(), Maj::integer(4)),
         Maj::nil(),
         "13");
    );
}

7.3. Ligações dinâmicas

#[test]
fn environments_dynamic_bindings() {
    use crate::axioms::MajRawSym;
    use crate::axioms::utils::sym_from_raw;
    let mut state = MajState::new();
    let my_function = Maj::symbol(&mut state, "my-function");
    let def = Maj::symbol(&mut state, "def");
    let my_value = Maj::symbol(&mut state, "*my-value*");
    let fnsym = sym_from_raw(MajRawSym::Fn);
    
    multi_eval_ast_test!(
        state;
        // (def *my-value* 5)
        (maj_list!(def.clone(), my_value.clone(),
                   Maj::integer(5)),
         Maj::nil(),
         "*my-value*");
        // *my-value*
        (my_value.clone(), Maj::nil(), "5");
        // (def my-function (fn () *my-value*))
        (maj_list!(def.clone(), my_function.clone(),
                   maj_list!(
                       fnsym.clone(), Maj::nil(),
                       my_value.clone())),
         Maj::nil(),
         "my-function");
        (maj_list!(my_function.clone()),
         Maj::nil(),
         "5");
        // ((fn (*my-value*) (my-function)) 6)
        (maj_list!(
            maj_list!(fnsym.clone(),
                      maj_list!(my_value.clone()),
                      maj_list!(my_function.clone())),
            Maj::integer(6)),
         Maj::nil(),
         "6");
        // (let ((*my-value* 7))
        //   (my-function))
        (maj_list!(my_function.clone()),
         maj_list!(Maj::cons(my_value.clone(),
                             Maj::integer(7))),
         "7");
    );
}

7.4. Mutabilidade

#[test]
fn environment_mutability_set() {
    let mut state = MajState::new();
    let def = Maj::symbol(&mut state, "def");
    let set = Maj::symbol(&mut state, "set");
    let x   = Maj::symbol(&mut state, "x");
    let mutate_x = Maj::symbol(&mut state, "mutate-x");
    let mutate_x_local = Maj::symbol(&mut state, "mutate-x-local");
    multi_eval_ast_test!(
        state;
        // (def x 5)
        (maj_list!(def.clone(), x.clone(), Maj::integer(5)),
         Maj::nil(),
         "x");

        // x
        (x.clone(), Maj::nil(), "5");
        
        // (set x 9)
        (maj_list!(set.clone(), x.clone(), Maj::integer(9)),
         Maj::nil(),
         "x");
        
        // x
        (x.clone(), Maj::nil(), "9");

        // (do (set x (1+ x)) x)
        // context: ((x . 12))
        (maj_list!(
            Maj::do_sym(),
            maj_list!(
                set.clone(), x.clone(),
                maj_list!(Maj::symbol(&mut state, "1+"),
                          x.clone())),
            x.clone()),
         maj_list!(Maj::cons(x.clone(), Maj::integer(12))),
         "13");

        // (defn mutate-x () (set x (+ x 2)) x)
        (maj_list!(
            Maj::symbol(&mut state, "defn"),
            mutate_x.clone(), Maj::nil(),
            maj_list!(
                set.clone(), x.clone(),
                maj_list!(
                    Maj::symbol(&mut state, "+"),
                    x.clone(), Maj::integer(2))),
            x.clone()),
         Maj::nil(),
         "mutate-x");
        
        // (mutate-x) altering x globally
        (maj_list!(mutate_x.clone()), Maj::nil(), "11");
        
        // (mutate-x) altering x dynamically
        // context: ((x . 12))
        (maj_list!(mutate_x.clone()),
         maj_list!(Maj::cons(x.clone(), Maj::integer(12))),
         "14");

        // x, unchanged
        (x.clone(), Maj::nil(), "11");

        // (defn mutate-x-local () (set x (+ x 2)) x)
        // context: ((x . 12))
        (maj_list!(
            Maj::symbol(&mut state, "defn"),
            mutate_x_local.clone(), Maj::nil(),
            maj_list!(
                set.clone(), x.clone(),
                maj_list!(
                    Maj::symbol(&mut state, "+"),
                    x.clone(), Maj::integer(2))),
            x.clone()),
         maj_list!(Maj::cons(x.clone(), Maj::integer(12))),
         "mutate-x-local");

        // (mutate-x-local) changing captured environment
        (maj_list!(mutate_x_local.clone()), Maj::nil(), "14");
        
        // x, unchanged
        (x.clone(), Maj::nil(), "11");

        // (mutate-x-local) changing captured environment
        (maj_list!(mutate_x_local.clone()), Maj::nil(), "16");

        // x, unchanged
        (x.clone(), Maj::nil(), "11");
    );
}
#[test]
fn environment_mutability_set_car_set_cdr() {
    let mut state = MajState::new();
    let def     = Maj::symbol(&mut state, "def");
    let defn    = Maj::symbol(&mut state, "defn");
    let set_car = Maj::symbol(&mut state, "set-car");
    let set_cdr = Maj::symbol(&mut state, "set-cdr");
    let x       = Maj::symbol(&mut state, "x");
    let a       = Maj::symbol(&mut state, "a");
    let b       = Maj::symbol(&mut state, "b");
    let replace_x_elts = Maj::symbol(&mut state, "replace-x-elts");
    let replace_x_elts_local =
        Maj::symbol(&mut state, "replace-x-elts-local");
    multi_eval_ast_test!(
        state;
        // (def x '(1 . 2))
        (maj_list!(
            def.clone(), x.clone(),
            maj_list!(Maj::quote(), Maj::cons(Maj::integer(1),
                                              Maj::integer(2)))),
         Maj::nil(),
         "x");
        
        // x
        (x.clone(), Maj::nil(), "(1 . 2)");
        
        // (set-car x 5)
        (maj_list!(
            set_car.clone(), x.clone(), Maj::integer(5)),
         Maj::nil(),
         "(5 . 2)");
        
        // (set-cdr x 6)
        (maj_list!(
            set_cdr.clone(), x.clone(), Maj::integer(6)),
         Maj::nil(),
         "(5 . 6)");
        
        // x
        (x.clone(), Maj::nil(), "(5 . 6)");
        
        // defining replace-x-elts
        (maj_list!(
            defn.clone(), replace_x_elts.clone(),
            maj_list!(a.clone(), b.clone()),
            maj_list!(set_car.clone(), x.clone(), a.clone()),
            maj_list!(set_cdr.clone(), x.clone(), b.clone()),
            x.clone()),
         Maj::nil(),
         "replace-x-elts");

        // (replace-x-elts 20 90)
        // context: ((x . (9 . 10)))
        (maj_list!(
            replace_x_elts.clone(),
            Maj::integer(20), Maj::integer(90)),
         maj_list!(Maj::cons(x.clone(),
                             Maj::cons(Maj::integer(9),
                                       Maj::integer(10)))),
         "(20 . 90)");

        // x
        (x.clone(), Maj::nil(), "(5 . 6)");

        // (replace-x-elts 30 45)
        (maj_list!(replace_x_elts.clone(),
                   Maj::integer(30), Maj::integer(45)),
         Maj::nil(),
         "(30 . 45)");
        
        // x
        (x.clone(), Maj::nil(), "(30 . 45)");

        // defining replace-x-elts-local
        // context: ((x . (9 . 10)))
        (maj_list!(
            defn.clone(), replace_x_elts_local.clone(),
            maj_list!(a.clone(), b.clone()),
            maj_list!(set_car.clone(), x.clone(), a.clone()),
            maj_list!(set_cdr.clone(), x.clone(), b.clone()),
            x.clone()),
         maj_list!(Maj::cons(x.clone(),
                             Maj::cons(Maj::integer(9),
                                       Maj::integer(10)))),
         "replace-x-elts-local");

        // (replace-x-elts-local 13 50)
        (maj_list!(
            replace_x_elts_local.clone(),
            Maj::integer(13), Maj::integer(50)),
         Maj::nil(),
         "(13 . 50)");

        // x
        (x.clone(), Maj::nil(), "(30 . 45)");
    );
}

8. Leitor (Tokenizador e Parser)

8.1. Expressões simples

#[test]
fn reader_simple_expressions() {
    let mut state = MajState::new();
    multi_parser_test!(
        state;
        ("", vec![], "nil");
        ("test", vec!["test"], "(test)");
        ("(defn foo ()
            (print \"Hello world\"))",
         vec!["(", "defn", "foo", "(", ")",
              "(", "print", "\"Hello world\"", ")", ")"],
         "((defn foo nil (print \"Hello world\")))");
        ("foo (foo) 5",
         vec!["foo", "(", "foo", ")", "5"],
         "(foo (foo) 5)");
    );
    multi_parser_fail_test!(
        state;
        "(')";
        "(a . b c)";
        "(a .";
        "(a . ";
        "(a . b";
        "a b . c d e";
        "foo bar '";
        "foo bar ,";
        "foo bar ,@";
        "foo ',@";
        "#\\invalidchar";
    );
}

8.2. Números

#[test]
#[ignore]
fn reader_numbers() {
    let mut state = MajState::new();
    multi_parser_fail_test!(
        state;
        // These are supposed to be parser errors!
        // Fix the parser so that these produce proper errors.
        "J";
        "j";
        ".";
        "/";
        "1/0";
        "1/00";
    );
}

8.3. Strings

#[test]
fn reader_strings() {
    let mut state = MajState::new();
    multi_parser_test!(
        state;
        ("\"Hello\\nworld\"",
         vec!["\"Hello\\nworld\""],
         "(\"Hello\nworld\")");
        ("\"Hello\\tworld\"",
        vec!["\"Hello\\tworld\""],
        "(\"Hello       world\")");
    );
}

8.4. Read macros

8.4.1. Comentários

#[test]
fn reader_comments() {
    let mut state = MajState::new();
    multi_parser_test!(
        state;
        (";", vec![], "nil");
        ("; ", vec![], "nil");
        (";;", vec![], "nil");
        (";; ", vec![], "nil");
        (";;;", vec![], "nil");
        (";;; ", vec![], "nil");
        ("; Comentário", vec![], "nil");
        (";; Comentário", vec![], "nil");
        (";;; Comentário", vec![], "nil");
        (";; Comentários seguidos
          ;; Em várias linhas",
         vec![],
         "nil");
        (";; Comentário com tokens
          (+ 1 2)",
         vec!["(", "+", "1", "2", ")"],
         "((+ 1 2))");
        ("(+ 1 2) ; Comentário ao final",
         vec!["(", "+", "1", "2", ")"],
        "((+ 1 2))");
        ("(+ 1 2) ; Comentário ao final e continua
          (- 3 4)",
         vec!["(", "+", "1", "2", ")",
              "(", "-", "3", "4", ")"],
        "((+ 1 2) (- 3 4))");
    );
}

8.4.2. Quote

#[test]
fn reader_quote() {
    let mut state = MajState::new();
    multi_parser_test!(
        state;
        ("'foo", vec!["'", "foo"], "((quote foo))");
        ("'a 'b 'c", vec!["'", "a", "'", "b", "'", "c"],
         "((quote a) (quote b) (quote c))");
        ("'a", vec!["'", "a"], "((quote a))");
        ("'(1 2 3)", vec!["'", "(", "1", "2", "3", ")"],
         "((quote (1 2 3)))");
    );
}

8.4.3. Quasiquote, Unquote, Unquote-Splice

#[test]
fn reader_quasiquote_unquote_unquotesplice() {
    let mut state = MajState::new();
    multi_parser_test!(
        state;
        ("`(x)", vec!["`", "(", "x", ")"],
         "((quasiquote (x)))");
        ("`(+ ,x ,y)", vec!["`", "(", "+", ",", "x",
                            ",", "y", ")"],
         "((quasiquote (+ (unquote x) (unquote y))))");
        ("`,foo", vec!["`", ",", "foo"],
         "((quasiquote (unquote foo)))");
        ("`(,y ,@x)", vec!["`", "(", ",", "y", ",@", "x", ")"],
         "((quasiquote ((unquote y) (unquote-splice x))))");
    );
}

8.4.4. Sintaxe de vetores

#[test]
fn reader_vector_syntax() {
    let mut state = MajState::new();
    multi_parser_test!(
        state;
        ("[]", vec!["[", "]"], "((vector))");
        ("[1 2 'a 3 (+ 2 5)]",
         vec!["[", "1", "2", "'", "a", "3",
              "(", "+", "2", "5", ")", "]"],
         "((vector 1 2 (quote a) 3 (+ 2 5)))");
    );
    multi_parser_fail_test!(
        state;
        "[']";
        "[1 2 3";
    );
}

9. Interpretação

9.1. Formas especiais

9.1.1. quote

#[test]
fn evaluator_quote() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(quote x)", "x");
        ("(quote (1 2 3))", "(1 2 3)");
        ("(quote (+ 5 6))", "(+ 5 6)");
    );
}

9.1.2. def

#[test]
fn evaluator_def() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(def x 5)", "x");
    );
    multi_eval_fail_test!(
        state;
        "(def (foo bar) 5)";
        "(def y (length x))";
    );
}

9.1.3. set

#[test]
fn evaluator_set() {
    let mut state = MajState::new();
    multi_eval_fail_test!(
        state;
        "(set x 5)";
    );
    multi_eval_test!(
        state;
        ("(def x 1)", "x");
        ("x", "1");
        ("(set x 5)", "x");
        ("x", "5");
        ("(let ((x 6)) x)", "6");
        ("(let ((x 6))
            (set x 9)
            x)",
         "9");
        ("x", "5");
    );
}

9.1.4. set-car

#[test]
fn evaluator_set_car() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(def x (quote (1 . 2)))", "x");
        ("(set-car x 3)", "(3 . 2)");
        ("(set-car (quote (9 . 0)) (quote f))",
         "(f . 0)");
        ("(let ((x (quote (4 . 5))))
            (set-car x 9))",
         "(9 . 5)");
        ("x", "(3 . 2)");
        ("(let ((a x))
            (set-car a 4))",
         "(4 . 2)");
        ("x", "(4 . 2)");
        ("(let ((a (copy x)))
            (set-car a 5))",
         "(5 . 2)");
        ("x", "(4 . 2)");
    );
}

9.1.5. set-cdr

#[test]
fn evaluator_set_cdr() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(def x (quote (1 . 2)))", "x");
        ("(set-cdr x 3)", "(1 . 3)");
        ("(set-cdr (quote (9 . 0)) (quote f))",
         "(9 . f)");
        ("(let ((x (quote (4 . 5))))
            (set-cdr x 9))",
         "(4 . 9)");
        ("x", "(1 . 3)");
        ("(let ((a x))
            (set-cdr a 4))",
         "(1 . 4)");
        ("x", "(1 . 4)");
        ("(let ((a (copy x)))
            (set-cdr a 5))",
         "(1 . 5)");
        ("x", "(1 . 4)");
    );
}

9.1.6. if

#[test]
fn evaluator_if() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(if (nilp (quote a))
              (quote is-nil)
              (quote is-not-nil))",
         "is-not-nil");
        ("(if (nilp nil)
              (quote is-nil)
              (quote is-not-nil))",
         "is-nil");
    );
}

9.1.7. fn

#[test]
fn evaluator_fn() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(fn (x) (* x x))",
         "(lit closure nil (x) ((* x x)))");
        ("(fn (x . rest) (list x rest))",
         "(lit closure nil (x . rest) ((list x rest)))");
        ("((fn (x) (* x x)) 5)",
         "25");
        ("(def square (fn (x) (* x x)))",
         "square");
        ("(square 5)", "25");
    );
}

9.1.8. mac

#[test]
fn evaluator_mac() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(mac (x) (quasiquote (list (unquote x))))",
         "(lit macro (lit closure nil (x) ((quasiquote (list (unquote x))))))");
        ("((mac (x) (quasiquote (list (unquote x)))) 5)",
         "(5)");
        ("(def encapsulate
            (mac (x) (quasiquote (list (unquote x)))))",
         "encapsulate");
        ("(macroexpand-1 (quote (encapsulate 5)))",
         "(list 5)");
        ("(encapsulate 5)", "(5)");
    );
}

9.1.9. quasiquote / unquote / unquote-splice

#[test]
fn evaluator_quasiquote_unquote_unquote_splice() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(quasiquote a)", "a");
        ("(let ((x 5)  (y 6))
            (quasiquote (1 (unquote x) (unquote y))))",
         "(1 5 6)");
        ("(let ((lst (list 1 2 3)))
            (quasiquote (0 (unquote lst))))",
         "(0 (1 2 3))");
        ("(let ((lst (list 1 2 3)))
            (quasiquote (0 (unquote-splice lst))))",
         "(0 1 2 3)");
    );
}

9.1.10. do

#[test]
fn evaluator_do() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(do (quote a)
              (quote b)
              (list (quote c)
                    (quote d)
                    (quote e)))",
         "(c d e)");
        ("(do)", "nil");
    );
}

9.1.11. TODO apply

#[test]
#[ignore]
fn evaluator_apply() {
    unimplemented!();
}

9.1.12. while

#[test]
fn evaluator_while() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(let ((x 0)  (lst nil))
            (while (< x 5)
              (set lst (cons x lst))
              (set x (1+ x)))
            (list x lst))",
         "(5 (4 3 2 1 0))");
        ("(let ((lst (quote (1 2 3 4 5)))
                (result nil))
            (while (not (nilp lst))
              (let (((num . rest) lst))
                (set result
                     (cons (= 2 num) result))
                (set lst rest)))
            result)",
         "(nil nil nil t nil)");
    );
    multi_eval_fail_test!(
        state;
        "(let ((lst (quote (1 2 3 a 5))))
           (while (not (nilp lst))
             (let (((num . rest) lst))
               (= 2 num))
             (set lst rest)))";
        "(let ((lst (quote (1 2 3 NaN 5))))
           (while (not (nilp lst))
             (let (((num . rest) lst))
               (= 2 num))
             (set lst rest)))";
    );
}

9.1.13. and

#[test]
fn evaluator_and() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(and (= 1 1) (= 0.5 1/2) (quote ok))",
         "ok");
        ("(and (= 1 1) (< 0.5 1/2) (quote ok))",
         "nil");
        ("(and)", "t");
    );
}

9.1.14. or

#[test]
fn evaluator_or() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(or (not (= 1 1))
              (< 0.5 1/2)
              (quote ok))",
         "ok");
        ("(or (= 1 1) (< 0.5 1/2))",
         "t");
        ("(or)", "nil");
    );
}

9.1.15. letrec

#[test]
fn evaluator_letrec() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(let ((results nil))
            (letrec ((foo ()
                       (set results
                         (cons (quote foo) results))
                       (bar))
                     (bar ()
                       (set results
                         (cons (quote bar) results))
                       (baz))
                     (baz ()
                       (set results
                         (cons (quote baz) results))
                       results))
              (foo)))",
         "(baz bar foo)");
        ("(letrec ((iter (x)
                     (if (> x 0)
                       (iter (1- x))
                       (quote finished))))
            (iter 5))",
         "finished");
        ("(def my-function
               (letrec ((foo () (bar))
                        (bar () (quote hello-from-bar)))
                 foo))",
         "my-function");
        ("(my-function)", "hello-from-bar");
    );
}

9.1.16. unwind-protect

#[test]
#[ignore]
fn evaluator_unwind_protect() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(def *my-stream* nil)", "*my-stream*");
        ("(unwind-protect
              (do (set *my-stream*
                       (open-stream 'in
                                    \"test-streams-in.txt\"))
                  (read-char *my-stream*))
            (do (close-stream *my-stream*)
                (set *my-stream* nil)))",
         "#\\H");
        ("*my-stream*", "nil");
        ("(and (set *my-stream*
                  (open-stream 'out \"test-streams-out.txt\"))
               t)",
         "t");
    );
    multi_eval_fail_test!(
        state;
        "(unwind-protect (read-char *my-stream*)
           (do (close-stream *my-stream*)
               (set *my-stream* nil)))";
             
    );
    multi_eval_test!(
        state;
        ("*my-stream*", "nil");
    );
}

9.2. Aplicação de clausuras

9.2.1. TODO Aplicação comum

#[test]
#[ignore]
fn evaluator_closure_application_default() {
    unimplemented!();
}

9.2.2. TODO Aplicação parcial

#[test]
#[ignore]
fn evaluator_closure_application_partial() {
    unimplemented!();
}

9.2.3. TODO Argumentos opcionais

#[test]
#[ignore]
fn evaluator_closure_application_optional_args() {
    unimplemented!();
}

9.2.4. TODO Aplicação parcial forçada

#[test]
#[ignore]
fn evaluator_closure_application_forced() {
    unimplemented!();
}

9.3. Bootstrap

9.3.1. Constantes

#[test]
fn evaluator_bootstrap_constants() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(type *stdin*)", "stream");
        ("(type *stdout*)", "stream");
        ("*ulps*", "3");
    );
}

9.3.2. map e mapc

#[test]
fn evaluator_bootstrap_map_mapc() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(map (fn (x) (* x x))
               (quote (1 2 3 4 5)))",
         "(1 4 9 16 25)");
        ("(map (fn (x) (* x x))
               (quote (1 2 3 4 . 5)))",
         "(1 4 9 16)");
        ("(mapc (fn (x) (* x x))
                (quote (1 2 3 4 5)))",
         "nil");
        ("(let ((results nil))
            (mapc (fn (x)
                    (set results
                         (cons (* x x) results)))
                  (quote (1 2 3 4 5)))
            results)",
         "(25 16 9 4 1)");
    );
}

9.3.3. vector=

#[test]
fn evaluator_bootstrap_vectorequal() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(vector= [1 2 3] [1 2 3])",     "t");
        ("(let ((v [5 6 7 8]))
            (vector= v [5 6 7 8]))",      "t");
        ("(vector= [1 2] [3 4 5])",       "nil");
        ("(vector= \"Hello\" \"Hello\")", "t");
        ("(vector= ['a 'b] [#\\a #\\b])", "nil");
    );
    multi_eval_fail_test!(
        state;
        "(vector= 'a ['a])";
        "(vector= [5] 5)";
    );
}

9.3.4. equal

#[test]
fn evaluator_bootstrap_equal() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(equal 0.5 1/2)",             "t");
        ("(equal [1 2 3] [1 2 3])",     "t");
        ("(equal 'a 'b)",               "nil");
        ("(equal '(a b c) '(a b c))",   "t");
        ("(equal #\\F #\\F)",           "t");
        ("(equal *stdin* *stdin*)",     "t");
        ("(equal *stdin* *stdout*)",    "nil");
        ("(equal 20 'a)",               "nil");
        ("(equal *stdout* '(a b c))",   "nil");
        ("(equal [6 5] '(6 5))",        "nil");
        ("(equal \"Teste\" \"Teste\")", "t");
    );
}

9.3.5. assp e assoc

#[test]
fn evaluator_bootstrap_assp_assoc() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(assp (fn (x) (eq (quote b) x))
                (quote ((a . 1) (b . 2) (c . 3))))",
         "(b . 2)");
        ("(assp (eq (quote b))
                (quote ((a . 1) (b . 2) (c . 3))))",
         "(b . 2)");
        ("(assp (eq (quote z))
                (quote ((a . 1) (b . 2) (c . 3))))",
         "nil");
        ("(assoc (quote b)
                 (quote ((a . 1) (b . 2) (c . 3))))",
         "(b . 2)");
        ("(assoc (quote a)
                 (quote ((a . 1) (b . 2) (c . 3))))",
         "(a . 1)");
        ("(letfn ((equal (x y)
                    (= x y)))
            (assoc 2 (quote ((1 . a) (2 . b) (3 . c)))))",
         "(2 . b)");
        ("(assoc (quote z)
                 (quote ((a . 1) (b . 2) (c . 3))))",
         "nil");
    );
}

9.3.6. member

#[test]
fn evaluator_bootstrap_member() {
    let mut state = MajState::new();
    multi_eval_test!(
        state;
        ("(member (quote a) (quote (x y z a b c)))",
         "(a b c)");
        ("(member (quote x) (quote (x y z a b c)))",
         "(x y z a b c)");
        ("(member (quote c) (quote (x y z a b c)))",
         "(c)");
        ("(letfn ((equal (x y)
                    (= x y)))
            (member 1 (quote (5 6 7 1 2 3))))",
         "(1 2 3)");
        ("(member (quote n) (quote (x y z a b c)))",
         "nil");
    );
}

9.4. TODO Aplicação de primitivas

#[test]
#[ignore]
fn evaluator_primitives_application() {
    unimplemented!();
}

9.5. TODO Expansão de macros

9.5.1. cond

#[test]
fn macros_cond() {
    let mut state = MajState::new();
    multi_macroexpand_1_test! {
        state;
        ("(cond (a b)
                (t c))",
         "(if a (do b) (cond (t c)))");
        ("(cond ((numberp x) x))",
         "(if (numberp x) (do x) nil)");
    };
    multi_eval_test! {
        state;
        ("(let ((x 1))
            (cond ((zerop x) 0)
                  ((< x 1) (- x))
                  (t x)))",
         "1");
        ("(let ((x 0))
            (cond ((zerop x) 0)
                  ((< x 1) (- x))
                  (t x)))",
         "0");
        ("(cond (t (quote a)))", "a");
        ("(cond ((eq (quote a)
                     (quote b))
                 (quote ok)))",
         "nil");
    };
}

9.5.2. defn

#[test]
fn macros_defn() {
    let mut state = MajState::new();
    multi_macroexpand_1_test! {
        state;
        ("(defn name lambda-list body1 body2)",
         "(def name (fn lambda-list body1 body2))");
        ("(defn identity (x) x)",
         "(def identity (fn (x) x))");
    }
    multi_eval_test! {
        state;
        ("(defn identity (x) x)", "identity");
        ("(closurep identity)",   "t");
        ("identity", "(lit closure nil (x) (x))");
    }
}

9.5.3. defmac

#[test]
fn macros_defmac() {
    let mut state = MajState::new();
    multi_macroexpand_1_test! {
        state;
        ("(defmac name lambda-list body1 body2)",
         "(def name (mac lambda-list body1 body2))");
        ("(defmac call (f) (quasiquote ((unquote f))))",
         "(def call (mac (f) (quasiquote ((unquote f)))))");
    }
    multi_eval_test! {
        state;
        ("(defmac call (f) (quasiquote ((unquote f))))",
         "call");
        ("(macrop call)",   "t");
        ("(defn foo () 1)", "foo");
        ("(call foo)", "1");
    }
}

9.5.4. let e let*

#[test]
fn macros_let_letstar() {
    let mut state = MajState::new();
    multi_macroexpand_1_test! {
        state;
        ("(let ((x 1)  (y 2))
            (+ x y))",
         "((fn (y x) (+ x y)) 2 1)");
        ("(let* ((x 1)  (y (1+ x)))
            (+ x y))",
         "(let ((x 1)) (let* ((y (1+ x))) (+ x y)))");
        ("(let* ((x (* 2 3))
                 (y (1+ x))
                 (z (+ y 3)))
            (+ x y z))",
         "(let ((x (* 2 3))) (let* ((y (1+ x)) (z (+ y 3))) (+ x y z)))");
    }
    multi_eval_test! {
        state;
        ("(let ((x 1)  (y 2))
            (+ x y))",
         "3");
        ("(let* ((x (* 2 3))
                 (y (1+ x))
                 (z (+ y 3)))
            (+ x y z))",
         "23");
    }
}

9.5.5. letfn e letfn*

#[test]
fn macros_letfn_letfnstar() {
    let mut state = MajState::new();
    multi_macroexpand_1_test! {
        state;
        ("(letfn ((foo (x) (+ 1 2 x))
                  (bar (x) x))
            (foo 5))",
         "((fn (bar foo) (foo 5)) (fn (x) x) (fn (x) (+ 1 2 x)))");
        ("(letfn* ((foo (x) (+ 1 2 x))
                   (bar (x) (foo x)))
            (bar 5))",
         "(letfn ((foo (x) (+ 1 2 x))) (letfn* ((bar (x) (foo x))) (bar 5)))");
    }
    multi_eval_test! {
        state;
        ("(letfn ((foo (x) (+ 1 2 x)))
            (foo 5))",
         "8");
        ("(letfn* ((foo (x) (+ 1 2 x))
                   (bar (x) (foo x)))
            (bar 5))",
         "8");
    };
}

9.5.6. when e unless

#[test]
fn macros_when_unless() {
    let mut state = MajState::new();
    multi_macroexpand_1_test! {
        state;
        ("(when t
            (print \"Hello\")
            (+ 2 3))",
         "(if t (do (print \"Hello\") (+ 2 3)) nil)");
        ("(unless t
            (print \"Hello\")
            (+ 2 3))",
         "(if (not t) (do (print \"Hello\") (+ 2 3)) nil)");
    }
    multi_eval_test! {
        state;
        ("(when t (+ 2 3))",         "5");
        ("(when (= 2 3) (+ 2 3))",   "nil");
        ("(unless t (+ 2 3))",       "nil");
        ("(unless (= 2 3) (+ 2 3))", "5");
    }
}

9.5.7. until

#[test]
fn macros_until() {
    let mut state = MajState::new();
    multi_macroexpand_1_test! {
        state;
        ("(until (>= x 5)
            (set x (1+ x)))",
         "(while (not (>= x 5)) (set x (1+ x)))");
    }
    multi_eval_test! {
        state;
        ("(let ((x 0))
            (until (>= x 5)
              (set x (1+ x)))
            x)",
         "5");
    }
}

9.5.8. TODO repeat

#[test]
#[ignore]
fn macros_repeat() {
    // Needs a macroexpand-1 macro which accepts
    // generated-symbol regex
    unimplemented!();
}

9.5.9. with-open-stream

#[test]
#[ignore]
fn macros_with_open_stream() {
    let mut state = MajState::new();
    multi_macroexpand_1_test! {
        state;
        ("(with-open-stream (s (quote in) \"test-streams-in.txt\")
            (read-char s))",
         "(let ((s (open-stream (quote in) \"test-streams-in.txt\"))) (unwind-protect (do (read-char s)) (close-stream s)))");
    }
    multi_eval_test! {
        state;
        ("(with-open-stream (s (quote in) \"test-streams-in.txt\")
            (read-char s))",
         "#\\H");
    }
}

Author: Lucas S. Vieira

Created: 2022-10-24 seg 09:58

Validate